diff --git a/scripts/example.toy b/scripts/example.toy index 58f01e1..511acb8 100644 --- a/scripts/example.toy +++ b/scripts/example.toy @@ -1,3 +1,9 @@ +//single line comment + +/* +multi line comment +*/ + print "hello world"; print null; print true; @@ -6,3 +12,9 @@ print 42; print 3.14; print -69; print -4.20; +print 2 + (3 * 3); + +assert true, "This won't be seen"; + +assert false, "This is an error"; + diff --git a/source/compiler.c b/source/compiler.c index 8e4f492..84dccf9 100644 --- a/source/compiler.c +++ b/source/compiler.c @@ -66,6 +66,12 @@ void writeCompiler(Compiler* compiler, Node* node) { writeCompiler(compiler, node->binary.right); compiler->bytecode[compiler->count++] = (unsigned char)node->binary.opcode; //1 byte break; + + case NODE_GROUPING: + compiler->bytecode[compiler->count++] = OP_GROUPING_BEGIN; //1 byte + writeCompiler(compiler, node->grouping.child); + compiler->bytecode[compiler->count++] = OP_GROUPING_END; //1 byte + break; } } diff --git a/source/interpreter.c b/source/interpreter.c index c6026c7..0313ee2 100644 --- a/source/interpreter.c +++ b/source/interpreter.c @@ -199,7 +199,7 @@ static bool execArithmetic(Interpreter* interpreter, Opcode opcode) { //catch bad modulo if (opcode == OP_MODULO) { - printf("Bad arithmetic argument (modulo on floats not allowed)"); + printf("Bad arithmetic argument (modulo on floats not allowed)\n"); return false; } @@ -224,7 +224,7 @@ static bool execArithmetic(Interpreter* interpreter, Opcode opcode) { } //wrong types - printf("Bad arithmetic argument"); + printf("Bad arithmetic argument\n"); return false; } @@ -269,6 +269,13 @@ static void execInterpreter(Interpreter* interpreter) { } break; + case OP_GROUPING_BEGIN: + execInterpreter(interpreter); + break; + + case OP_GROUPING_END: + return; + default: printf("Unknown opcode found %d, terminating\n", opcode); printLiteralArray(&interpreter->stack, "\n"); diff --git a/source/lexer.c b/source/lexer.c index fc46508..38c4f54 100644 --- a/source/lexer.c +++ b/source/lexer.c @@ -289,8 +289,11 @@ Token scanLexer(Lexer* lexer) { return makeString(lexer, c); //TODO: possibly support interpolated strings - default: - return makeErrorToken(lexer, "Unexpected token"); + default: { + char buffer[128]; + snprintf(buffer, 128, "Unexpected token: %c", c); + return makeErrorToken(lexer, buffer); + } } } diff --git a/source/node.c b/source/node.c index 58692ed..2e658e9 100644 --- a/source/node.c +++ b/source/node.c @@ -5,6 +5,11 @@ #include void freeNode(Node* node) { + //don't free a NULL node + if (node == NULL) { + return; + } + switch(node->type) { case NODE_LITERAL: freeLiteral(node->atomic.literal); @@ -18,6 +23,10 @@ void freeNode(Node* node) { freeNode(node->binary.left); freeNode(node->binary.right); break; + + case NODE_GROUPING: + freeNode(node->grouping.child); + break; } FREE(Node, node); @@ -70,5 +79,11 @@ void printNode(Node* node) { printNode(node->binary.right); printf(";"); break; + + case NODE_GROUPING: + printf("("); + printNode(node->grouping.child); + printf(")"); + break; } } \ No newline at end of file diff --git a/source/node.h b/source/node.h index fd90115..0288b89 100644 --- a/source/node.h +++ b/source/node.h @@ -11,7 +11,7 @@ typedef enum NodeType { NODE_LITERAL, //a simple value NODE_UNARY, //one child NODE_BINARY, //two children, left and right - // NODE_GROUPING, + NODE_GROUPING, //one child } NodeType; typedef struct NodeLiteral { @@ -32,11 +32,17 @@ typedef struct NodeBinary { Node* right; } NodeBinary; +typedef struct NodeGrouping { + NodeType type; + Node* child; +} NodeGrouping; + union _node { NodeType type; NodeLiteral atomic; NodeUnary unary; NodeBinary binary; + NodeGrouping grouping; }; void freeNode(Node* node); diff --git a/source/opcodes.h b/source/opcodes.h index c16a42e..b9fa2d6 100644 --- a/source/opcodes.h +++ b/source/opcodes.h @@ -18,6 +18,8 @@ typedef enum Opcode { OP_MULTIPLICATION, OP_DIVISION, OP_MODULO, + OP_GROUPING_BEGIN, + OP_GROUPING_END, //meta OP_SECTION_END, diff --git a/source/parser.c b/source/parser.c index 04f1a52..7ca4805 100644 --- a/source/parser.c +++ b/source/parser.c @@ -128,6 +128,33 @@ static Opcode string(Parser* parser, Node** nodeHandle, bool canBeAssigned) { } } +static Opcode grouping(Parser* parser, Node** nodeHandle, bool canBeAssigned) { + //handle three diffent types of groupings: (), {}, [] + switch(parser->previous.type) { + case TOKEN_PAREN_LEFT: { + Node* tmpNode = NULL; + parsePrecedence(parser, &tmpNode, PREC_TERNARY); + consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of grouping"); + + //if it's just a literal, don't need a grouping + if (command.optimize >= 1 && tmpNode->type == NODE_LITERAL) { + (*nodeHandle) = tmpNode; + return OP_EOF; + } + + //process the result without optimisations + emitNodeUnary(nodeHandle, NODE_GROUPING); + nodeHandle = &((*nodeHandle)->unary.child); //re-align after append + (*nodeHandle) = tmpNode; + return OP_EOF; + } + + default: + error(parser, parser->previous, "Unexpected token passed to grouping precedence rule"); + return OP_EOF; + } +} + static Opcode binary(Parser* parser, Node** nodeHandle, bool canBeAssigned) { advance(parser); @@ -158,9 +185,9 @@ static Opcode binary(Parser* parser, Node** nodeHandle, bool canBeAssigned) { return OP_MODULO; } - default: - error(parser, parser->previous, "Unexpected token passed to binary precedence rule"); - return OP_EOF; + default: + error(parser, parser->previous, "Unexpected token passed to binary precedence rule"); + return OP_EOF; } } @@ -299,7 +326,7 @@ ParseRule parseRules[] = { //must match the token types {NULL, NULL, PREC_NONE},// TOKEN_MINUS_MINUS, //logical operators - {NULL, NULL, PREC_NONE},// TOKEN_PAREN_LEFT, + {grouping, NULL, PREC_CALL},// TOKEN_PAREN_LEFT, {NULL, NULL, PREC_NONE},// TOKEN_PAREN_RIGHT, {NULL, NULL, PREC_NONE},// TOKEN_BRACKET_LEFT, {NULL, NULL, PREC_NONE},// TOKEN_BRACKET_RIGHT, @@ -447,18 +474,20 @@ static void parsePrecedence(Parser* parser, Node** nodeHandle, PrecedenceRule ru ParseFn prefixRule = getRule(parser->previous.type)->prefix; if (prefixRule == NULL) { + *nodeHandle = NULL; //the handle's value MUST be set to null for error handling error(parser, parser->previous, "Expected expression"); return; } bool canBeAssigned = rule <= PREC_ASSIGNMENT; - prefixRule(parser, nodeHandle, canBeAssigned); + prefixRule(parser, nodeHandle, canBeAssigned); //ignore the returned opcode //infix rules are left-recursive while (rule <= getRule(parser->current.type)->precedence) { ParseFn infixRule = getRule(parser->current.type)->infix; if (infixRule == NULL) { + *nodeHandle = NULL; //the handle's value MUST be set to null for error handling error(parser, parser->current, "Expected operator"); return; } @@ -528,11 +557,14 @@ static void statement(Parser* parser, Node* node) { expressionStmt(parser, node); } -static void declaration(Parser* parser, Node* node) { - statement(parser, node); +static void declaration(Parser* parser, Node** nodeHandle) { + statement(parser, *nodeHandle); if (parser->panic) { synchronize(parser); + //return an error node for this iteration + *nodeHandle = ALLOCATE(Node, 1); + (*nodeHandle)->type = NODE_ERROR; } } @@ -564,10 +596,10 @@ Node* scanParser(Parser* parser) { //returns nodes on the heap Node* node = ALLOCATE(Node, 1); + node->type = NODE_ERROR; //BUGFIX: so freeing won't break the damn thing //process the grammar rule for this line - declaration(parser, node); + declaration(parser, &node); return node; } - diff --git a/source/repl_main.c b/source/repl_main.c index e558281..edf1a40 100644 --- a/source/repl_main.c +++ b/source/repl_main.c @@ -58,6 +58,14 @@ void runString(char* source) { //run the parser until the end of the source Node* node = scanParser(&parser); while(node != NULL) { + //pack up and leave + if (node->type == NODE_ERROR) { + freeNode(node); + freeCompiler(&compiler); + freeParser(&parser); + return; + } + writeCompiler(&compiler, node); freeNode(node); node = scanParser(&parser); @@ -84,6 +92,8 @@ void runFile(char* fname) { } void repl() { + bool error = false; + const int size = 2048; char input[size]; memset(input, 0, size); @@ -106,23 +116,33 @@ void repl() { //run this iteration Node* node = scanParser(&parser); while(node != NULL) { + //pack up and restart + if (node->type == NODE_ERROR) { + error = true; + freeNode(node); + break; + } + writeCompiler(&compiler, node); freeNode(node); node = scanParser(&parser); } - //get the bytecode dump - int size = 0; - char* tb = collateCompiler(&compiler, &size); + if (!error) { + //get the bytecode dump + int size = 0; + char* tb = collateCompiler(&compiler, &size); - //run the bytecode - initInterpreter(&interpreter, tb, size); - runInterpreter(&interpreter); - freeInterpreter(&interpreter); //TODO: option to retain the scopes + //run the bytecode + initInterpreter(&interpreter, tb, size); + runInterpreter(&interpreter); + freeInterpreter(&interpreter); //TODO: option to retain the scopes + } //clean up this iteration freeCompiler(&compiler); freeParser(&parser); + error = false; } freeInterpreter(&interpreter);