diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 4aa6975..ad88d18 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -2,7 +2,7 @@ name: Comprehensive Tests on: push: - branches: [ "main" ] + branches: [ "main", "dev" ] pull_request: branches: [ "main" ] diff --git a/docs/TODO.txt b/docs/TODO.txt deleted file mode 100644 index c5a1818..0000000 --- a/docs/TODO.txt +++ /dev/null @@ -1,51 +0,0 @@ -DONE: rework type system -DONE: var decl with a type, but no value -DONE: type casting -DONE: remove optimization option -DONE: conditionals -DONE: if-then-else -DONE: chained if-then-else -DONE: optional block around a path if it's only one statement -DONE: while-then -DONE: for-then -DONE: break and continue statements -DONE: truthiness rethink -DONE: string concat with the + operator -DONE: increment & decrement operators -DONE: store compound types in variables -DONE: += -= *= /= %= operators -DONE: && and || operators -DONE: functions are invoked by calling their names -DONE: function arguments can have specified types -DONE: function returns can have specified types -DONE: closures are explicitly supported -DONE: functions are first-class citizens -DONE: functions take a set number of parameters -DONE: functions last argument can be a rest parameter -DONE: assert needs to kill the whole script, not just functions -DONE: native functions -DONE: global functions _get, _set, _push, _pop, _length, clear available -DONE: change comma to colon in dictionary definition -DONE: Address circular references -DONE: are compounds shallow or deep copies? Deep copies -DONE: third output stream, for lexer/parser/compiler/interpreter errors -DONE: Assertion-based test scripts -DONE: Import/export keywords -DONE: A way to check the type of a variable (typeOf keyword) -DONE: slice and dot notation around the builtin _index and _dot functions -DONE: maximum recursion/function depth -DONE: better sugar for _push, _pop, _length -DONE: nested compound assignment bug -DONE: hooks on the external libraries, triggered on import - - -TODO: standard library -TODO: external script runner library -TODO: document how it all works -TODO: packaging for release? -TODO: test embedding in a game - -NOPE: a = b = c = 1; -NOPE: functions return a set number of values -NOPE: ternary operator? -NOPE: Nullish types? diff --git a/repl/lib_standard.c b/repl/lib_standard.c index 8061941..26debdb 100644 --- a/repl/lib_standard.c +++ b/repl/lib_standard.c @@ -18,7 +18,7 @@ static int nativeClock(Interpreter* interpreter, LiteralArray* arguments) { //push to the stack int len = strlen(timestr) - 1; //-1 for the newline - Literal timeLiteral = TO_STRING_LITERAL(copyString(timestr, len), len); + Literal timeLiteral = TO_STRING_LITERAL(createRefStringLength(timestr, len)); //push to the stack pushLiteralArray(&interpreter->stack, timeLiteral); @@ -57,7 +57,7 @@ int hookStandard(Interpreter* interpreter, Literal identifier, Literal alias) { //load the dict with functions for (int i = 0; natives[i].name; i++) { - Literal name = TO_STRING_LITERAL(copyString(natives[i].name, strlen(natives[i].name)), strlen(natives[i].name)); + Literal name = TO_STRING_LITERAL(createRefStringLength(natives[i].name, strlen(natives[i].name))); Literal func = TO_FUNCTION_LITERAL((void*)natives[i].fn, 0); func.type = LITERAL_FUNCTION_NATIVE; diff --git a/repl/lib_timer.c b/repl/lib_timer.c index efb2426..efa47ea 100644 --- a/repl/lib_timer.c +++ b/repl/lib_timer.c @@ -292,12 +292,12 @@ static int nativeTimerToString(Interpreter* interpreter, LiteralArray* arguments if (timer->tv_sec == 0 && timer->tv_usec < 0) { //special case, for when the negative sign is encoded in the usec char buffer[128]; snprintf(buffer, 128, "-%ld.%06ld", timer->tv_sec, -timer->tv_usec); - resultLiteral = TO_STRING_LITERAL( copyString(buffer, strlen(buffer)), strlen(buffer)); + resultLiteral = TO_STRING_LITERAL(createRefStringLength(buffer, strlen(buffer))); } else { //normal case char buffer[128]; snprintf(buffer, 128, "%ld.%06ld", timer->tv_sec, timer->tv_usec); - resultLiteral = TO_STRING_LITERAL( copyString(buffer, strlen(buffer)), strlen(buffer)); + resultLiteral = TO_STRING_LITERAL(createRefStringLength(buffer, strlen(buffer))); } pushLiteralArray(&interpreter->stack, resultLiteral); @@ -374,7 +374,7 @@ int hookTimer(Interpreter* interpreter, Literal identifier, Literal alias) { //load the dict with functions for (int i = 0; natives[i].name; i++) { - Literal name = TO_STRING_LITERAL(copyString(natives[i].name, strlen(natives[i].name)), strlen(natives[i].name)); + Literal name = TO_STRING_LITERAL(createRefStringLength(natives[i].name, strlen(natives[i].name))); Literal func = TO_FUNCTION_LITERAL((void*)natives[i].fn, 0); func.type = LITERAL_FUNCTION_NATIVE; diff --git a/repl/repl_main.c b/repl/repl_main.c index cf2b80d..998e611 100644 --- a/repl/repl_main.c +++ b/repl/repl_main.c @@ -50,15 +50,15 @@ void repl() { ASTNode* node = scanParser(&parser); while(node != NULL) { //pack up and restart - if (node->type == AST_NODEERROR) { + if (node->type == AST_NODE_ERROR) { printf(ERROR "error node detected\n" RESET); error = true; - freeNode(node); + freeASTNode(node); break; } writeCompiler(&compiler, node); - freeNode(node); + freeASTNode(node); node = scanParser(&parser); } diff --git a/repl/repl_tools.c b/repl/repl_tools.c index b9bf20d..df3fd2c 100644 --- a/repl/repl_tools.c +++ b/repl/repl_tools.c @@ -78,16 +78,16 @@ unsigned char* compileString(char* source, size_t* size) { ASTNode* node = scanParser(&parser); while(node != NULL) { //pack up and leave - if (node->type == AST_NODEERROR) { + if (node->type == AST_NODE_ERROR) { printf(ERROR "error node detected\n" RESET); - freeNode(node); + freeASTNode(node); freeCompiler(&compiler); freeParser(&parser); return NULL; } writeCompiler(&compiler, node); - freeNode(node); + freeASTNode(node); node = scanParser(&parser); } diff --git a/source/ast_node.c b/source/ast_node.c index d41922b..df23866 100644 --- a/source/ast_node.c +++ b/source/ast_node.c @@ -5,106 +5,134 @@ #include #include -void freeNodeCustom(ASTNode* node, bool freeSelf) { +void freeASTNodeCustom(ASTNode* node, bool freeSelf) { //don't free a NULL node if (node == NULL) { return; } switch(node->type) { - case AST_NODEERROR: + case AST_NODE_ERROR: //NO-OP break; - case AST_NODELITERAL: + case AST_NODE_LITERAL: freeLiteral(node->atomic.literal); break; - case AST_NODEUNARY: - freeNode(node->unary.child); + case AST_NODE_UNARY: + freeASTNode(node->unary.child); break; - case AST_NODEBINARY: - freeNode(node->binary.left); - freeNode(node->binary.right); + case AST_NODE_BINARY: + freeASTNode(node->binary.left); + freeASTNode(node->binary.right); break; - case AST_NODEGROUPING: - freeNode(node->grouping.child); + case AST_NODE_GROUPING: + freeASTNode(node->grouping.child); break; - case AST_NODEBLOCK: + case AST_NODE_BLOCK: for (int i = 0; i < node->block.count; i++) { - freeNodeCustom(node->block.nodes + i, false); + freeASTNodeCustom(node->block.nodes + i, false); } FREE_ARRAY(ASTNode, node->block.nodes, node->block.capacity); break; - case AST_NODECOMPOUND: + case AST_NODE_COMPOUND: for (int i = 0; i < node->compound.count; i++) { - freeNodeCustom(node->compound.nodes + i, false); + freeASTNodeCustom(node->compound.nodes + i, false); } FREE_ARRAY(ASTNode, node->compound.nodes, node->compound.capacity); break; - case AST_NODEPAIR: - freeNode(node->pair.left); - freeNode(node->pair.right); + case AST_NODE_PAIR: + freeASTNode(node->pair.left); + freeASTNode(node->pair.right); break; - case AST_NODEVAR_DECL: + case AST_NODE_INDEX: + freeASTNode(node->index.first); + freeASTNode(node->index.second); + freeASTNode(node->index.third); + break; + + case AST_NODE_VAR_DECL: freeLiteral(node->varDecl.identifier); freeLiteral(node->varDecl.typeLiteral); - freeNode(node->varDecl.expression); + freeASTNode(node->varDecl.expression); break; - case AST_NODEFN_DECL: - freeLiteral(node->fnDecl.identifier); - freeNode(node->fnDecl.arguments); - freeNode(node->fnDecl.returns); - freeNode(node->fnDecl.block); - break; - - case AST_NODEFN_COLLECTION: + case AST_NODE_FN_COLLECTION: for (int i = 0; i < node->fnCollection.count; i++) { - freeNodeCustom(node->fnCollection.nodes + i, false); + freeASTNodeCustom(node->fnCollection.nodes + i, false); } FREE_ARRAY(ASTNode, node->fnCollection.nodes, node->fnCollection.capacity); break; - case AST_NODEFN_CALL: - freeNode(node->fnCall.arguments); + case AST_NODE_FN_DECL: + freeLiteral(node->fnDecl.identifier); + freeASTNode(node->fnDecl.arguments); + freeASTNode(node->fnDecl.returns); + freeASTNode(node->fnDecl.block); break; - case AST_NODEPATH_IF: - case AST_NODEPATH_WHILE: - case AST_NODEPATH_FOR: - case AST_NODEPATH_BREAK: - case AST_NODEPATH_CONTINUE: - case AST_NODEPATH_RETURN: - freeNode(node->path.preClause); - freeNode(node->path.postClause); - freeNode(node->path.condition); - freeNode(node->path.thenPath); - freeNode(node->path.elsePath); + case AST_NODE_FN_CALL: + freeASTNode(node->fnCall.arguments); break; - case AST_NODEINCREMENT_PREFIX: - case AST_NODEINCREMENT_POSTFIX: - freeLiteral(node->increment.identifier); + case AST_NODE_FN_RETURN: + freeASTNode(node->returns.returns); break; - case AST_NODEIMPORT: - case AST_NODEEXPORT: + case AST_NODE_IF: + freeASTNode(node->pathIf.condition); + freeASTNode(node->pathIf.thenPath); + freeASTNode(node->pathIf.elsePath); + break; + + case AST_NODE_WHILE: + freeASTNode(node->pathWhile.condition); + freeASTNode(node->pathWhile.thenPath); + break; + + case AST_NODE_FOR: + freeASTNode(node->pathFor.preClause); + freeASTNode(node->pathFor.postClause); + freeASTNode(node->pathFor.condition); + freeASTNode(node->pathFor.thenPath); + break; + + case AST_NODE_BREAK: + //NO-OP + break; + + case AST_NODE_CONTINUE: + //NO-OP + break; + + case AST_NODE_PREFIX_INCREMENT: + freeLiteral(node->prefixIncrement.identifier); + break; + case AST_NODE_PREFIX_DECREMENT: + freeLiteral(node->prefixDecrement.identifier); + break; + case AST_NODE_POSTFIX_INCREMENT: + freeLiteral(node->postfixIncrement.identifier); + break; + case AST_NODE_POSTFIX_DECREMENT: + freeLiteral(node->postfixDecrement.identifier); + break; + + case AST_NODE_IMPORT: freeLiteral(node->import.identifier); freeLiteral(node->import.alias); break; - case AST_NODEINDEX: - case AST_NODEDOT: - freeNode(node->index.first); - freeNode(node->index.second); - freeNode(node->index.third); + case AST_NODE_EXPORT: + freeLiteral(node->export.identifier); + freeLiteral(node->export.alias); break; } @@ -113,15 +141,16 @@ void freeNodeCustom(ASTNode* node, bool freeSelf) { } } -void freeNode(ASTNode* node) { - freeNodeCustom(node, true); +void freeASTNode(ASTNode* node) { + freeASTNodeCustom(node, true); } +//various emitters void emitASTNodeLiteral(ASTNode** nodeHandle, Literal literal) { //allocate a new node *nodeHandle = ALLOCATE(ASTNode, 1); - (*nodeHandle)->type = AST_NODELITERAL; + (*nodeHandle)->type = AST_NODE_LITERAL; (*nodeHandle)->atomic.literal = copyLiteral(literal); } @@ -129,7 +158,7 @@ void emitASTNodeUnary(ASTNode** nodeHandle, Opcode opcode, ASTNode* child) { //allocate a new node *nodeHandle = ALLOCATE(ASTNode, 1); - (*nodeHandle)->type = AST_NODEUNARY; + (*nodeHandle)->type = AST_NODE_UNARY; (*nodeHandle)->unary.opcode = opcode; (*nodeHandle)->unary.child = child; } @@ -137,7 +166,7 @@ void emitASTNodeUnary(ASTNode** nodeHandle, Opcode opcode, ASTNode* child) { void emitASTNodeBinary(ASTNode** nodeHandle, ASTNode* rhs, Opcode opcode) { ASTNode* tmp = ALLOCATE(ASTNode, 1); - tmp->type = AST_NODEBINARY; + tmp->type = AST_NODE_BINARY; tmp->binary.opcode = opcode; tmp->binary.left = *nodeHandle; tmp->binary.right = rhs; @@ -148,7 +177,7 @@ void emitASTNodeBinary(ASTNode** nodeHandle, ASTNode* rhs, Opcode opcode) { void emitASTNodeGrouping(ASTNode** nodeHandle) { ASTNode* tmp = ALLOCATE(ASTNode, 1); - tmp->type = AST_NODEGROUPING; + tmp->type = AST_NODE_GROUPING; tmp->grouping.child = *nodeHandle; *nodeHandle = tmp; @@ -157,8 +186,8 @@ void emitASTNodeGrouping(ASTNode** nodeHandle) { void emitASTNodeBlock(ASTNode** nodeHandle) { ASTNode* tmp = ALLOCATE(ASTNode, 1); - tmp->type = AST_NODEBLOCK; - tmp->block.nodes = NULL; + tmp->type = AST_NODE_BLOCK; + tmp->block.nodes = NULL; //NOTE: appended by the parser tmp->block.capacity = 0; tmp->block.count = 0; @@ -168,7 +197,7 @@ void emitASTNodeBlock(ASTNode** nodeHandle) { void emitASTNodeCompound(ASTNode** nodeHandle, LiteralType literalType) { ASTNode* tmp = ALLOCATE(ASTNode, 1); - tmp->type = AST_NODECOMPOUND; + tmp->type = AST_NODE_COMPOUND; tmp->compound.literalType = literalType; tmp->compound.nodes = NULL; tmp->compound.capacity = 0; @@ -178,16 +207,27 @@ void emitASTNodeCompound(ASTNode** nodeHandle, LiteralType literalType) { } void setASTNodePair(ASTNode* node, ASTNode* left, ASTNode* right) { - //assume the node has already been allocated - node->type = AST_NODEPAIR; + //set - assume the node has already been allocated + node->type = AST_NODE_PAIR; node->pair.left = left; node->pair.right = right; } +void emitASTNodeIndex(ASTNode** nodeHandle, ASTNode* first, ASTNode* second, ASTNode* third) { + ASTNode* tmp = ALLOCATE(ASTNode, 1); + + tmp->type = AST_NODE_INDEX; + tmp->index.first = first; + tmp->index.second = second; + tmp->index.third = third; + + *nodeHandle = tmp; +} + void emitASTNodeVarDecl(ASTNode** nodeHandle, Literal identifier, Literal typeLiteral, ASTNode* expression) { ASTNode* tmp = ALLOCATE(ASTNode, 1); - tmp->type = AST_NODEVAR_DECL; + tmp->type = AST_NODE_VAR_DECL; tmp->varDecl.identifier = identifier; tmp->varDecl.typeLiteral = typeLiteral; tmp->varDecl.expression = expression; @@ -195,10 +235,21 @@ void emitASTNodeVarDecl(ASTNode** nodeHandle, Literal identifier, Literal typeLi *nodeHandle = tmp; } +void emitASTNodeFnCollection(ASTNode** nodeHandle) { //a collection of nodes, intended for use with functions + ASTNode* tmp = ALLOCATE(ASTNode, 1); + + tmp->type = AST_NODE_FN_COLLECTION; + tmp->fnCollection.nodes = NULL; + tmp->fnCollection.capacity = 0; + tmp->fnCollection.count = 0; + + *nodeHandle = tmp; +} + void emitASTNodeFnDecl(ASTNode** nodeHandle, Literal identifier, ASTNode* arguments, ASTNode* returns, ASTNode* block) { ASTNode* tmp = ALLOCATE(ASTNode, 1); - tmp->type = AST_NODEFN_DECL; + tmp->type = AST_NODE_FN_DECL; tmp->fnDecl.identifier = identifier; tmp->fnDecl.arguments = arguments; tmp->fnDecl.returns = returns; @@ -207,88 +258,126 @@ void emitASTNodeFnDecl(ASTNode** nodeHandle, Literal identifier, ASTNode* argume *nodeHandle = tmp; } -void emitASTFnCall(ASTNode** nodeHandle, ASTNode* arguments, int argumentCount) { +void emitASTNodeFnCall(ASTNode** nodeHandle, ASTNode* arguments) { ASTNode* tmp = ALLOCATE(ASTNode, 1); - tmp->type = AST_NODEFN_CALL; + tmp->type = AST_NODE_FN_CALL; tmp->fnCall.arguments = arguments; - tmp->fnCall.argumentCount = argumentCount; + tmp->fnCall.argumentCount = arguments->fnCollection.count; *nodeHandle = tmp; } -void emitASTNodeFnCollection(ASTNode** nodeHandle) { //a collection of nodes, intended for use with functions +void emitASTNodeFnReturn(ASTNode** nodeHandle, ASTNode* returns) { ASTNode* tmp = ALLOCATE(ASTNode, 1); - tmp->type = AST_NODEFN_COLLECTION; - tmp->fnCollection.nodes = NULL; - tmp->fnCollection.capacity = 0; - tmp->fnCollection.count = 0; + tmp->type = AST_NODE_FN_RETURN; + tmp->returns.returns = returns; *nodeHandle = tmp; } -void emitASTNodePath(ASTNode** nodeHandle, ASTNodeType type, ASTNode* preClause, ASTNode* postClause, ASTNode* condition, ASTNode* thenPath, ASTNode* elsePath) { +void emitASTNodeIf(ASTNode** nodeHandle, ASTNode* condition, ASTNode* thenPath, ASTNode* elsePath) { ASTNode* tmp = ALLOCATE(ASTNode, 1); - tmp->type = type; - tmp->path.preClause = preClause; - tmp->path.postClause = postClause; - tmp->path.condition = condition; - tmp->path.thenPath = thenPath; - tmp->path.elsePath = elsePath; + tmp->type = AST_NODE_IF; + tmp->pathIf.condition = condition; + tmp->pathIf.thenPath = thenPath; + tmp->pathIf.elsePath = elsePath; *nodeHandle = tmp; } -void emitASTNodePrefixIncrement(ASTNode** nodeHandle, Literal identifier, int increment) { +void emitASTNodeWhile(ASTNode** nodeHandle, ASTNode* condition, ASTNode* thenPath) { ASTNode* tmp = ALLOCATE(ASTNode, 1); - tmp->type = AST_NODEINCREMENT_PREFIX; - tmp->increment.identifier = copyLiteral(identifier); - tmp->increment.increment = increment; + tmp->type = AST_NODE_WHILE; + tmp->pathWhile.condition = condition; + tmp->pathWhile.thenPath = thenPath; *nodeHandle = tmp; } -void emitASTNodePostfixIncrement(ASTNode** nodeHandle, Literal identifier, int increment) { +void emitASTNodeFor(ASTNode** nodeHandle, ASTNode* preClause, ASTNode* condition, ASTNode* postClause, ASTNode* thenPath) { ASTNode* tmp = ALLOCATE(ASTNode, 1); - tmp->type = AST_NODEINCREMENT_POSTFIX; - tmp->increment.identifier = copyLiteral(identifier); - tmp->increment.increment = increment; + tmp->type = AST_NODE_FOR; + tmp->pathFor.preClause = preClause; + tmp->pathFor.condition = condition; + tmp->pathFor.postClause = postClause; + tmp->pathFor.thenPath = thenPath; *nodeHandle = tmp; } -void emitASTNodeImport(ASTNode** nodeHandle, ASTNodeType mode, Literal identifier, Literal alias) { +void emitASTNodeBreak(ASTNode** nodeHandle) { ASTNode* tmp = ALLOCATE(ASTNode, 1); - tmp->type = mode; + tmp->type = AST_NODE_BREAK; + + *nodeHandle = tmp; +} + +void emitASTNodeContinue(ASTNode** nodeHandle) { + ASTNode* tmp = ALLOCATE(ASTNode, 1); + + tmp->type = AST_NODE_CONTINUE; + + *nodeHandle = tmp; +} + +void emitASTNodePrefixIncrement(ASTNode** nodeHandle, Literal identifier) { + ASTNode* tmp = ALLOCATE(ASTNode, 1); + + tmp->type = AST_NODE_PREFIX_INCREMENT; + tmp->prefixIncrement.identifier = copyLiteral(identifier); + + *nodeHandle = tmp; +} + +void emitASTNodePrefixDecrement(ASTNode** nodeHandle, Literal identifier) { + ASTNode* tmp = ALLOCATE(ASTNode, 1); + + tmp->type = AST_NODE_PREFIX_DECREMENT; + tmp->prefixDecrement.identifier = copyLiteral(identifier); + + *nodeHandle = tmp; +} + +void emitASTNodePostfixIncrement(ASTNode** nodeHandle, Literal identifier) { + ASTNode* tmp = ALLOCATE(ASTNode, 1); + + tmp->type = AST_NODE_POSTFIX_INCREMENT; + tmp->postfixIncrement.identifier = copyLiteral(identifier); + + *nodeHandle = tmp; +} + +void emitASTNodePostfixDecrement(ASTNode** nodeHandle, Literal identifier) { + ASTNode* tmp = ALLOCATE(ASTNode, 1); + + tmp->type = AST_NODE_POSTFIX_DECREMENT; + tmp->postfixDecrement.identifier = copyLiteral(identifier); + + *nodeHandle = tmp; +} + +void emitASTNodeImport(ASTNode** nodeHandle, Literal identifier, Literal alias) { + ASTNode* tmp = ALLOCATE(ASTNode, 1); + + tmp->type = AST_NODE_IMPORT; tmp->import.identifier = copyLiteral(identifier); tmp->import.alias = copyLiteral(alias); *nodeHandle = tmp; } -void emitASTNodeIndex(ASTNode** nodeHandle, ASTNode* first, ASTNode* second, ASTNode* third) { +void emitASTNodeExport(ASTNode** nodeHandle, Literal identifier, Literal alias) { ASTNode* tmp = ALLOCATE(ASTNode, 1); - tmp->type = AST_NODEINDEX; - tmp->index.first = first; - tmp->index.second = second; - tmp->index.third = third; - - *nodeHandle = tmp; -} - -void emitASTNodeDot(ASTNode** nodeHandle, ASTNode* first) { - ASTNode* tmp = ALLOCATE(ASTNode, 1); - - tmp->type = AST_NODEDOT; - tmp->index.first = first; - tmp->index.second = NULL; - tmp->index.third = NULL; + tmp->type = AST_NODE_EXPORT; + tmp->export.identifier = copyLiteral(identifier); + tmp->export.alias = copyLiteral(alias); *nodeHandle = tmp; } diff --git a/source/ast_node.h b/source/ast_node.h index 9aef7ae..574807c 100644 --- a/source/ast_node.h +++ b/source/ast_node.h @@ -9,43 +9,53 @@ typedef union _node ASTNode; typedef enum ASTNodeType { - AST_NODEERROR, - AST_NODELITERAL, //a simple value - AST_NODEUNARY, //one child + opcode - AST_NODEBINARY, //two children, left and right + opcode - AST_NODEGROUPING, //one child - AST_NODEBLOCK, //contains a sub-node array - AST_NODECOMPOUND, //contains a sub-node array - AST_NODEPAIR, //contains a left and right - AST_NODEVAR_DECL, //contains identifier literal, typenode, expression definition - AST_NODEFN_DECL, //containd identifier literal, arguments node, returns node, block node - AST_NODEFN_COLLECTION, //parts of a function - AST_NODEFN_CALL, - AST_NODEPATH_IF, //for control flow - AST_NODEPATH_WHILE, //for control flow - AST_NODEPATH_FOR, //for control flow - AST_NODEPATH_BREAK, //for control flow - AST_NODEPATH_CONTINUE, //for control flow - AST_NODEPATH_RETURN, - AST_NODEINCREMENT_PREFIX, - AST_NODEINCREMENT_POSTFIX, - AST_NODEIMPORT, - AST_NODEEXPORT, - AST_NODEINDEX, - AST_NODEDOT, + AST_NODE_ERROR, + AST_NODE_LITERAL, //a simple value + AST_NODE_UNARY, //one child + opcode + AST_NODE_BINARY, //two children, left and right + opcode + AST_NODE_GROUPING, //one child + AST_NODE_BLOCK, //contains a sub-node array + AST_NODE_COMPOUND, //contains a sub-node array + AST_NODE_PAIR, //contains a left and right + AST_NODE_INDEX, //index a variable + AST_NODE_VAR_DECL, //contains identifier literal, typenode, expression definition + AST_NODE_FN_DECL, //containd identifier literal, arguments node, returns node, block node + AST_NODE_FN_COLLECTION, //parts of a function + AST_NODE_FN_CALL, //call a function + AST_NODE_FN_RETURN, //for control flow + AST_NODE_IF, //for control flow + AST_NODE_WHILE, //for control flow + AST_NODE_FOR, //for control flow + AST_NODE_BREAK, //for control flow + AST_NODE_CONTINUE, //for control flow + AST_NODE_PREFIX_INCREMENT, //increment a variable + AST_NODE_POSTFIX_INCREMENT, //increment a variable + AST_NODE_PREFIX_DECREMENT, //decrement a variable + AST_NODE_POSTFIX_DECREMENT, //decrement a variable + AST_NODE_IMPORT, //import a variable + AST_NODE_EXPORT, //export a variable } ASTNodeType; +//literals +void emitASTNodeLiteral(ASTNode** nodeHandle, Literal literal); + typedef struct NodeLiteral { ASTNodeType type; Literal literal; } NodeLiteral; +//unary operator +void emitASTNodeUnary(ASTNode** nodeHandle, Opcode opcode, ASTNode* child); + typedef struct NodeUnary { ASTNodeType type; Opcode opcode; ASTNode* child; } NodeUnary; +//binary operator +void emitASTNodeBinary(ASTNode** nodeHandle, ASTNode* rhs, Opcode opcode); //handled node becomes lhs + typedef struct NodeBinary { ASTNodeType type; Opcode opcode; @@ -53,11 +63,17 @@ typedef struct NodeBinary { ASTNode* right; } NodeBinary; +//grouping of other AST nodes +void emitASTNodeGrouping(ASTNode** nodeHandle); + typedef struct NodeGrouping { ASTNodeType type; ASTNode* child; } NodeGrouping; +//block of statement nodes +void emitASTNodeBlock(ASTNode** nodeHandle); + typedef struct NodeBlock { ASTNodeType type; ASTNode* nodes; @@ -65,6 +81,9 @@ typedef struct NodeBlock { int count; } NodeBlock; +//compound literals (array, dictionary) +void emitASTNodeCompound(ASTNode** nodeHandle, LiteralType literalType); + typedef struct NodeCompound { ASTNodeType type; LiteralType literalType; @@ -73,12 +92,26 @@ typedef struct NodeCompound { int count; } NodeCompound; +void setASTNodePair(ASTNode* node, ASTNode* left, ASTNode* right); //NOTE: this is a set function, not an emit function + typedef struct NodePair { ASTNodeType type; ASTNode* left; ASTNode* right; } NodePair; +void emitASTNodeIndex(ASTNode** nodeHandle, ASTNode* first, ASTNode* second, ASTNode* third); + +typedef struct NodeIndex { + ASTNodeType type; + ASTNode* first; + ASTNode* second; + ASTNode* third; +} NodeIndex; + +//variable declaration +void emitASTNodeVarDecl(ASTNode** nodeHandle, Literal identifier, Literal type, ASTNode* expression); + typedef struct NodeVarDecl { ASTNodeType type; Literal identifier; @@ -86,6 +119,19 @@ typedef struct NodeVarDecl { ASTNode* expression; } NodeVarDecl; +//NOTE: fnCollection is used by fnDecl, fnCall and fnReturn +void emitASTNodeFnCollection(ASTNode** nodeHandle); + +typedef struct NodeFnCollection { + ASTNodeType type; + ASTNode* nodes; + int capacity; + int count; +} NodeFnCollection; + +//function declaration +void emitASTNodeFnDecl(ASTNode** nodeHandle, Literal identifier, ASTNode* arguments, ASTNode* returns, ASTNode* block); + typedef struct NodeFnDecl { ASTNodeType type; Literal identifier; @@ -94,33 +140,88 @@ typedef struct NodeFnDecl { ASTNode* block; } NodeFnDecl; -typedef struct NodeFnCollection { - ASTNodeType type; - ASTNode* nodes; - int capacity; - int count; -} NodeFnCollection; +//function call +void emitASTNodeFnCall(ASTNode** nodeHandle, ASTNode* arguments); typedef struct NodeFnCall { ASTNodeType type; ASTNode* arguments; - int argumentCount; + int argumentCount; //NOTE: leave this, so it can be hacked by dottify() } NodeFnCall; -typedef struct NodePath { +//function return +void emitASTNodeFnReturn(ASTNode** nodeHandle, ASTNode* returns); + +typedef struct NodeFnReturn { + ASTNodeType type; + ASTNode* returns; +} NodeFnReturn; + +//control flow path - if-else, while, for, break, continue, return +void emitASTNodeIf(ASTNode** nodeHandle, ASTNode* condition, ASTNode* thenPath, ASTNode* elsePath); +void emitASTNodeWhile(ASTNode** nodeHandle, ASTNode* condition, ASTNode* thenPath); +void emitASTNodeFor(ASTNode** nodeHandle, ASTNode* preClause, ASTNode* condition, ASTNode* postClause, ASTNode* thenPath); +void emitASTNodeBreak(ASTNode** nodeHandle); +void emitASTNodeContinue(ASTNode** nodeHandle); + +typedef struct NodeIf { ASTNodeType type; - ASTNode* preClause; - ASTNode* postClause; ASTNode* condition; ASTNode* thenPath; ASTNode* elsePath; -} NodePath; +} NodeIf; -typedef struct NodeIncrement { +typedef struct NodeWhile { + ASTNodeType type; + ASTNode* condition; + ASTNode* thenPath; +} NodeWhile; + +typedef struct NodeFor { + ASTNodeType type; + ASTNode* preClause; + ASTNode* condition; + ASTNode* postClause; + ASTNode* thenPath; +} NodeFor; + +typedef struct NodeBreak { + ASTNodeType type; +} NodeBreak; + +typedef struct NodeContinue { + ASTNodeType type; +} NodeContinue; + +//pre-post increment/decrement +void emitASTNodePrefixIncrement(ASTNode** nodeHandle, Literal identifier); +void emitASTNodePrefixDecrement(ASTNode** nodeHandle, Literal identifier); +void emitASTNodePostfixIncrement(ASTNode** nodeHandle, Literal identifier); +void emitASTNodePostfixDecrement(ASTNode** nodeHandle, Literal identifier); + +typedef struct NodePrefixIncrement { ASTNodeType type; Literal identifier; - int increment; -} NodeIncrement; +} NodePrefixIncrement; + +typedef struct NodePrefixDecrement { + ASTNodeType type; + Literal identifier; +} NodePrefixDecrement; + +typedef struct NodePostfixIncrement { + ASTNodeType type; + Literal identifier; +} NodePostfixIncrement; + +typedef struct NodePostfixDecrement { + ASTNodeType type; + Literal identifier; +} NodePostfixDecrement; + +//import/export a variable +void emitASTNodeImport(ASTNode** nodeHandle, Literal identifier, Literal alias); +void emitASTNodeExport(ASTNode** nodeHandle, Literal identifier, Literal alias); typedef struct NodeImport { ASTNodeType type; @@ -128,12 +229,11 @@ typedef struct NodeImport { Literal alias; } NodeImport; -typedef struct NodeIndex { +typedef struct NodeExport { ASTNodeType type; - ASTNode* first; - ASTNode* second; - ASTNode* third; -} NodeIndex; + Literal identifier; + Literal alias; +} NodeExport; union _node { ASTNodeType type; @@ -144,32 +244,23 @@ union _node { NodeBlock block; NodeCompound compound; NodePair pair; - NodeVarDecl varDecl; - NodeFnDecl fnDecl; - NodeFnCollection fnCollection; - NodeFnCall fnCall; - NodePath path; - NodeIncrement increment; - NodeImport import; NodeIndex index; + NodeVarDecl varDecl; + NodeFnCollection fnCollection; + NodeFnDecl fnDecl; + NodeFnCall fnCall; + NodeFnReturn returns; + NodeIf pathIf; //TODO: rename these to ifStmt? + NodeWhile pathWhile; + NodeFor pathFor; + NodeBreak pathBreak; + NodeContinue pathContinue; + NodePrefixIncrement prefixIncrement; + NodePrefixDecrement prefixDecrement; + NodePostfixIncrement postfixIncrement; + NodePostfixDecrement postfixDecrement; + NodeImport import; + NodeExport export; }; -TOY_API void freeNode(ASTNode* node); - -void emitASTNodeLiteral(ASTNode** nodeHandle, Literal literal); -void emitASTNodeUnary(ASTNode** nodeHandle, Opcode opcode, ASTNode* child); -void emitASTNodeBinary(ASTNode** nodeHandle, ASTNode* rhs, Opcode opcode); //handled node becomes lhs -void emitASTNodeGrouping(ASTNode** nodeHandle); -void emitASTNodeBlock(ASTNode** nodeHandle); -void emitASTNodeCompound(ASTNode** nodeHandle, LiteralType literalType); -void setASTNodePair(ASTNode* node, ASTNode* left, ASTNode* right); -void emitASTNodeVarDecl(ASTNode** nodeHandle, Literal identifier, Literal type, ASTNode* expression); -void emitASTNodeFnDecl(ASTNode** nodeHandle, Literal identifier, ASTNode* arguments, ASTNode* returns, ASTNode* block); -void emitASTFnCall(ASTNode** nodeHandle, ASTNode* arguments, int argumentCount); -void emitASTNodeFnCollection(ASTNode** nodeHandle); -void emitASTNodePath(ASTNode** nodeHandle, ASTNodeType type, ASTNode* preClause, ASTNode* postClause, ASTNode* condition, ASTNode* thenPath, ASTNode* elsePath); -void emitASTNodePrefixIncrement(ASTNode** nodeHandle, Literal identifier, int increment); -void emitASTNodePostfixIncrement(ASTNode** nodeHandle, Literal identifier, int increment); -void emitASTNodeImport(ASTNode** nodeHandle, ASTNodeType mode, Literal identifier, Literal alias); -void emitASTNodeIndex(ASTNode** nodeHandle, ASTNode* first, ASTNode* second, ASTNode* third); -void emitASTNodeDot(ASTNode** nodeHandle, ASTNode* first); +TOY_API void freeASTNode(ASTNode* node); diff --git a/source/builtin.c b/source/builtin.c index b3e7141..15bd573 100644 --- a/source/builtin.c +++ b/source/builtin.c @@ -10,7 +10,7 @@ static Literal addition(Interpreter* interpreter, Literal lhs, Literal rhs) { //special case for string concatenation ONLY if (IS_STRING(lhs) && IS_STRING(rhs)) { //check for overflow - int totalLength = strlen(AS_STRING(lhs)) + strlen(AS_STRING(rhs)); + int totalLength = AS_STRING(lhs)->length + AS_STRING(rhs)->length; if (totalLength > MAX_STRING_LENGTH) { interpreter->errorOutput("Can't concatenate these strings (result is too long)\n"); return TO_NULL_LITERAL; @@ -18,8 +18,9 @@ static Literal addition(Interpreter* interpreter, Literal lhs, Literal rhs) { //concat the strings char buffer[MAX_STRING_LENGTH]; - snprintf(buffer, MAX_STRING_LENGTH, "%s%s", AS_STRING(lhs), AS_STRING(rhs)); - Literal literal = TO_STRING_LITERAL(copyString(buffer, totalLength), totalLength); + snprintf(buffer, MAX_STRING_LENGTH, "%s%s", toCString(AS_STRING(lhs)), toCString(AS_STRING(rhs))); + Literal literal = TO_STRING_LITERAL(createRefStringLength(buffer, totalLength)); + freeLiteral(lhs); freeLiteral(rhs); @@ -296,35 +297,35 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { return 1; } - else if (!strcmp( AS_STRING(op), "=")) { + else if (equalsRefStringCString(AS_STRING(op), "=")) { setLiteralDictionary(AS_DICTIONARY(compound), first, assign); } - else if (!strcmp( AS_STRING(op), "+=")) { + else if (equalsRefStringCString(AS_STRING(op), "+=")) { Literal lit = addition(interpreter, value, assign); setLiteralDictionary(AS_DICTIONARY(compound), first, lit); freeLiteral(lit); } - else if (!strcmp( AS_STRING(op), "-=")) { + else if (equalsRefStringCString(AS_STRING(op), "-=")) { Literal lit = subtraction(interpreter, value, assign); setLiteralDictionary(AS_DICTIONARY(compound), first, lit); freeLiteral(lit); } - else if (!strcmp( AS_STRING(op), "*=")) { + else if (equalsRefStringCString(AS_STRING(op), "*=")) { Literal lit = multiplication(interpreter, value, assign); setLiteralDictionary(AS_DICTIONARY(compound), first, lit); freeLiteral(lit); } - else if (!strcmp( AS_STRING(op), "/=")) { + else if (equalsRefStringCString(AS_STRING(op), "/=")) { Literal lit = division(interpreter, value, assign); setLiteralDictionary(AS_DICTIONARY(compound), first, lit); freeLiteral(lit); } - else if (!strcmp( AS_STRING(op), "%=")) { + else if (equalsRefStringCString(AS_STRING(op), "%=")) { Literal lit = modulo(interpreter, value, assign); setLiteralDictionary(AS_DICTIONARY(compound), first, lit); freeLiteral(lit); @@ -440,7 +441,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { } //array slice assignment - if (IS_STRING(op) && !strcmp( AS_STRING(op), "=")) { + if (IS_STRING(op) && equalsRefStringCString(AS_STRING(op), "=")) { //parse out the booleans & their defaults if (!IS_NULL(first)) { if (IS_BOOLEAN(first)) { @@ -620,31 +621,31 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { value = getLiteralArray(AS_ARRAY(compound), first); - if (IS_STRING(op) && !strcmp( AS_STRING(op), "+=")) { + if (IS_STRING(op) && equalsRefStringCString(AS_STRING(op), "+=")) { Literal lit = addition(interpreter, value, assign); setLiteralArray(AS_ARRAY(compound), first, lit); freeLiteral(lit); } - if (IS_STRING(op) && !strcmp( AS_STRING(op), "-=")) { + if (IS_STRING(op) && equalsRefStringCString(AS_STRING(op), "-=")) { Literal lit = subtraction(interpreter, value, assign); setLiteralArray(AS_ARRAY(compound), first, lit); freeLiteral(lit); } - if (IS_STRING(op) && !strcmp( AS_STRING(op), "*=")) { + if (IS_STRING(op) && equalsRefStringCString(AS_STRING(op), "*=")) { Literal lit = multiplication(interpreter, value, assign); setLiteralArray(AS_ARRAY(compound), first, lit); freeLiteral(lit); } - if (IS_STRING(op) && !strcmp( AS_STRING(op), "/=")) { + if (IS_STRING(op) && equalsRefStringCString(AS_STRING(op), "/=")) { Literal lit = division(interpreter, value, assign); setLiteralArray(AS_ARRAY(compound), first, lit); freeLiteral(lit); } - if (IS_STRING(op) && !strcmp( AS_STRING(op), "%=")) { + if (IS_STRING(op) && equalsRefStringCString(AS_STRING(op), "%=")) { Literal lit = modulo(interpreter, value, assign); setLiteralArray(AS_ARRAY(compound), first, lit); freeLiteral(lit); @@ -669,7 +670,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { } } - int compoundLength = strlen(AS_STRING(compound)); + int compoundLength = AS_STRING(compound)->length; if (!IS_NULL(second)) { if (IS_BOOLEAN(second)) { freeLiteral(second); @@ -709,14 +710,14 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { } if (IS_NULL(second)) { //assign only a single character - char c = AS_STRING(compound)[AS_INTEGER(first)]; + char c = toCString(AS_STRING(compound))[AS_INTEGER(first)]; char buffer[16]; snprintf(buffer, 16, "%c", c); freeLiteral(value); int totalLength = strlen(buffer); - value = TO_STRING_LITERAL(copyString(buffer, totalLength), totalLength); + value = TO_STRING_LITERAL(createRefStringLength(buffer, totalLength)); pushLiteralArray(&interpreter->stack, value); @@ -754,20 +755,20 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { //copy compound into result int resultIndex = 0; for (int i = min; i >= 0 && i >= lower && i <= max; i += AS_INTEGER(third)) { - result[ resultIndex++ ] = AS_STRING(compound)[ i ]; + result[ resultIndex++ ] = toCString(AS_STRING(compound))[ i ]; } result[ resultIndex ] = '\0'; //finally, swap out the compound for the result freeLiteral(compound); - compound = TO_STRING_LITERAL(copyString(result, resultIndex), resultIndex); + compound = TO_STRING_LITERAL(createRefStringLength(result, resultIndex)); FREE_ARRAY(char, result, MAX_STRING_LENGTH); } //string slice assignment - else if (IS_STRING(op) && !strcmp( AS_STRING(op), "=")) { + else if (IS_STRING(op) && equalsRefStringCString(AS_STRING(op), "=")) { //parse out the booleans & their defaults if (!IS_NULL(first)) { if (IS_BOOLEAN(first)) { @@ -782,7 +783,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { } } - int compoundLength = strlen(AS_STRING(compound)); + int compoundLength = AS_STRING(compound)->length; if (!IS_NULL(second)) { if (IS_BOOLEAN(second)) { freeLiteral(second); @@ -823,7 +824,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { if (IS_NULL(second)) { //assign only a single character //set the "first" within the array, then skip out - if (strlen( AS_STRING(assign) ) != 1) { + if (AS_STRING(assign)->length != 1) { //something is weird - skip out freeLiteral(op); freeLiteral(assign); @@ -836,9 +837,11 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { return -1; } - AS_STRING(compound)[AS_INTEGER(first)] = AS_STRING(assign)[0]; + Literal copiedCompound = TO_STRING_LITERAL(deepCopyRefString(AS_STRING(compound))); - pushLiteralArray(&interpreter->stack, compound); + AS_STRING(copiedCompound)->data[AS_INTEGER(first)] = toCString(AS_STRING(assign))[0]; + + pushLiteralArray(&interpreter->stack, copiedCompound); freeLiteral(op); freeLiteral(assign); @@ -871,18 +874,18 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { int resultIndex = 0; if (AS_INTEGER(third) == 1 || AS_INTEGER(third) == -1) { for (int i = 0; i < AS_INTEGER(first); i++) { - result[ resultIndex++ ] = AS_STRING(compound)[ i ]; + result[ resultIndex++ ] = toCString(AS_STRING(compound))[ i ]; } - int assignLength = strlen(AS_STRING(assign)); + int assignLength = AS_STRING(assign)->length; int min = AS_INTEGER(third) > 0 ? 0 : assignLength - 1; for (int i = min; i >= 0 && i < assignLength; i += AS_INTEGER(third)) { - result[ resultIndex++ ] = AS_STRING(assign)[ i ]; + result[ resultIndex++ ] = toCString(AS_STRING(assign))[ i ]; } for (int i = AS_INTEGER(second) + 1; i < compoundLength; i++) { - result[ resultIndex++ ] = AS_STRING(compound)[ i ]; + result[ resultIndex++ ] = toCString(AS_STRING(compound))[ i ]; } result[ resultIndex ] = '\0'; @@ -891,26 +894,26 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { //else override elements of the array instead else { //copy compound to result - snprintf(result, MAX_STRING_LENGTH, "%s", AS_STRING(compound)); + snprintf(result, MAX_STRING_LENGTH, "%s", toCString(AS_STRING(compound))); - int assignLength = strlen(AS_STRING(assign)); + int assignLength = AS_STRING(assign)->length; int min = AS_INTEGER(third) > 0 ? AS_INTEGER(first) : AS_INTEGER(second) - 1; int assignIndex = 0; for (int i = min; i >= AS_INTEGER(first) && i <= AS_INTEGER(second) && assignIndex < assignLength; i += AS_INTEGER(third)) { - result[ i ] = AS_STRING(assign)[ assignIndex++ ]; + result[ i ] = toCString(AS_STRING(assign))[ assignIndex++ ]; } resultIndex = strlen(result); } //finally, swap out the compound for the result freeLiteral(compound); - compound = TO_STRING_LITERAL(copyString(result, resultIndex), resultIndex); + compound = TO_STRING_LITERAL(createRefStringLength(result, resultIndex)); FREE_ARRAY(char, result, MAX_STRING_LENGTH); } - else if (IS_STRING(op) && !strcmp( AS_STRING(op), "+=")) { + else if (IS_STRING(op) && equalsRefStringCString(AS_STRING(op), "+=")) { Literal tmp = addition(interpreter, compound, assign); freeLiteral(compound); compound = tmp; //don't clear tmp @@ -1229,7 +1232,7 @@ int _pop(Interpreter* interpreter, LiteralArray* arguments) { int _length(Interpreter* interpreter, LiteralArray* arguments) { //if wrong number of arguments, fail if (arguments->count != 1) { - interpreter->errorOutput("Incorrect number of arguments to _get\n"); + interpreter->errorOutput("Incorrect number of arguments to _length\n"); return -1; } @@ -1257,7 +1260,7 @@ int _length(Interpreter* interpreter, LiteralArray* arguments) { } case LITERAL_STRING: { - Literal lit = TO_INTEGER_LITERAL( strlen(AS_STRING(obj)) ); + Literal lit = TO_INTEGER_LITERAL( AS_STRING(obj)->length ); pushLiteralArray(&interpreter->stack, lit); freeLiteral(lit); break; diff --git a/source/compiler.c b/source/compiler.c index d4537e7..d82fd12 100644 --- a/source/compiler.c +++ b/source/compiler.c @@ -83,7 +83,7 @@ static int writeNodeCompoundToCache(Compiler* compiler, ASTNode* node) { for (int i = 0; i < node->compound.count; i++) { //keys switch(node->compound.nodes[i].pair.left->type) { - case AST_NODELITERAL: { + case AST_NODE_LITERAL: { //keys are literals int key = findLiteralIndex(&compiler->literalCache, node->compound.nodes[i].pair.left->atomic.literal); if (key < 0) { @@ -96,7 +96,7 @@ static int writeNodeCompoundToCache(Compiler* compiler, ASTNode* node) { } break; - case AST_NODECOMPOUND: { + case AST_NODE_COMPOUND: { int key = writeNodeCompoundToCache(compiler, node->compound.nodes[i].pair.left); Literal literal = TO_INTEGER_LITERAL(key); @@ -112,7 +112,7 @@ static int writeNodeCompoundToCache(Compiler* compiler, ASTNode* node) { //values switch(node->compound.nodes[i].pair.right->type) { - case AST_NODELITERAL: { + case AST_NODE_LITERAL: { //values are literals int val = findLiteralIndex(&compiler->literalCache, node->compound.nodes[i].pair.right->atomic.literal); if (val < 0) { @@ -125,7 +125,7 @@ static int writeNodeCompoundToCache(Compiler* compiler, ASTNode* node) { } break; - case AST_NODECOMPOUND: { + case AST_NODE_COMPOUND: { int val = writeNodeCompoundToCache(compiler, node->compound.nodes[i].pair.right); Literal literal = TO_INTEGER_LITERAL(val); @@ -150,7 +150,7 @@ static int writeNodeCompoundToCache(Compiler* compiler, ASTNode* node) { //ensure each literal value is in the cache, individually for (int i = 0; i < node->compound.count; i++) { switch(node->compound.nodes[i].type) { - case AST_NODELITERAL: { + case AST_NODE_LITERAL: { //values int val = findLiteralIndex(&compiler->literalCache, node->compound.nodes[i].atomic.literal); if (val < 0) { @@ -163,7 +163,7 @@ static int writeNodeCompoundToCache(Compiler* compiler, ASTNode* node) { } break; - case AST_NODECOMPOUND: { + case AST_NODE_COMPOUND: { int val = writeNodeCompoundToCache(compiler, &node->compound.nodes[i]); Literal literal = TO_INTEGER_LITERAL(val); @@ -197,7 +197,7 @@ static int writeNodeCollectionToCache(Compiler* compiler, ASTNode* node) { //ensure each literal value is in the cache, individually for (int i = 0; i < node->fnCollection.count; i++) { switch(node->fnCollection.nodes[i].type) { - case AST_NODEVAR_DECL: { + case AST_NODE_VAR_DECL: { //write each piece of the declaration to the cache int identifierIndex = pushLiteralArray(&compiler->literalCache, node->fnCollection.nodes[i].varDecl.identifier); //store without duplication optimisation int typeIndex = writeLiteralTypeToCacheOpt(&compiler->literalCache, node->fnCollection.nodes[i].varDecl.typeLiteral, false); @@ -212,7 +212,7 @@ static int writeNodeCollectionToCache(Compiler* compiler, ASTNode* node) { } break; - case AST_NODELITERAL: { + case AST_NODE_LITERAL: { //write each piece of the declaration to the cache int typeIndex = writeLiteralTypeToCacheOpt(&compiler->literalCache, node->fnCollection.nodes[i].atomic.literal, false); @@ -267,8 +267,8 @@ static int writeLiteralToCompiler(Compiler* compiler, Literal literal) { return index; } -//NOTE: jumpOfsets are included, because function arg and return indexes are embedded in the code body i.e. need to include thier sizes in the jump -//NODE: rootNode should NOT include groupings and blocks +//NOTE: jumpOfsets are included, because function arg and return indexes are embedded in the code body i.e. need to include their sizes in the jump +//NOTE: rootNode should NOT include groupings and blocks static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* breakAddressesPtr, void* continueAddressesPtr, int jumpOffsets, ASTNode* rootNode) { //grow if the bytecode space is too small if (compiler->count + 32 > compiler->capacity) { @@ -280,18 +280,18 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br //determine node type switch(node->type) { - case AST_NODEERROR: { + case AST_NODE_ERROR: { fprintf(stderr, ERROR "[internal] AST_NODEERROR encountered in writeCompilerWithJumps()\n" RESET); compiler->bytecode[compiler->count++] = OP_EOF; //1 byte } break; - case AST_NODELITERAL: { + case AST_NODE_LITERAL: { writeLiteralToCompiler(compiler, node->atomic.literal); } break; - case AST_NODEUNARY: { + case AST_NODE_UNARY: { //pass to the child node, then embed the unary command (print, negate, etc.) Opcode override = writeCompilerWithJumps(compiler, node->unary.child, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); @@ -304,7 +304,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br break; //all infixes come here - case AST_NODEBINARY: { + case AST_NODE_BINARY: { //pass to the child nodes, then embed the binary command (math, etc.) Opcode override = writeCompilerWithJumps(compiler, node->binary.left, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); @@ -324,7 +324,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br //return this if... Opcode ret = writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); - if (node->binary.opcode == OP_INDEX && rootNode->type == AST_NODEBINARY && rootNode->binary.opcode == OP_VAR_ASSIGN) { //why var assign? + if (node->binary.opcode == OP_INDEX && rootNode->type == AST_NODE_BINARY && rootNode->binary.opcode == OP_VAR_ASSIGN) { //why var assign? return OP_INDEX_ASSIGN_INTERMEDIATE; } @@ -344,7 +344,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br } break; - case AST_NODEGROUPING: { + case AST_NODE_GROUPING: { compiler->bytecode[compiler->count++] = (unsigned char)OP_GROUPING_BEGIN; //1 byte Opcode override = writeCompilerWithJumps(compiler, node->grouping.child, breakAddressesPtr, continueAddressesPtr, jumpOffsets, node->grouping.child); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy @@ -354,7 +354,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br } break; - case AST_NODEBLOCK: { + case AST_NODE_BLOCK: { compiler->bytecode[compiler->count++] = (unsigned char)OP_SCOPE_BEGIN; //1 byte for (int i = 0; i < node->block.count; i++) { @@ -368,7 +368,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br } break; - case AST_NODECOMPOUND: { + case AST_NODE_COMPOUND: { int index = writeNodeCompoundToCache(compiler, node); //push the node opcode to the bytecode @@ -387,12 +387,12 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br } break; - case AST_NODEPAIR: + case AST_NODE_PAIR: fprintf(stderr, ERROR "[internal] AST_NODEPAIR encountered in writeCompilerWithJumps()\n" RESET); compiler->bytecode[compiler->count++] = OP_EOF; //1 byte break; - case AST_NODEVAR_DECL: { + case AST_NODE_VAR_DECL: { //first, embed the expression (leaves it on the stack) Opcode override = writeCompilerWithJumps(compiler, node->varDecl.expression, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy @@ -427,7 +427,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br } break; - case AST_NODEFN_DECL: { + case AST_NODE_FN_DECL: { //run a compiler over the function Compiler* fnCompiler = ALLOCATE(Compiler, 1); initCompiler(fnCompiler); @@ -471,7 +471,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br } break; - case AST_NODEFN_COLLECTION: { + case AST_NODE_FN_COLLECTION: { //embed these in the bytecode... int index = writeNodeCollectionToCache(compiler, node); @@ -480,12 +480,12 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br } break; - case AST_NODEFN_CALL: { + case AST_NODE_FN_CALL: { //NOTE: assume the function definition/name is above us for (int i = 0; i < node->fnCall.arguments->fnCollection.count; i++) { //reverse order, to count from the beginning in the interpreter //sub-calls - if (node->fnCall.arguments->fnCollection.nodes[i].type != AST_NODELITERAL) { + if (node->fnCall.arguments->fnCollection.nodes[i].type != AST_NODE_LITERAL) { Opcode override = writeCompilerWithJumps(compiler, &node->fnCall.arguments->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte @@ -540,9 +540,9 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br } break; - case AST_NODEPATH_IF: { + case AST_NODE_IF: { //process the condition - Opcode override = writeCompilerWithJumps(compiler, node->path.condition, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); + Opcode override = writeCompilerWithJumps(compiler, node->pathIf.condition, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -553,14 +553,14 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br compiler->count += sizeof(unsigned short); //2 bytes //write the then path - override = writeCompilerWithJumps(compiler, node->path.thenPath, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); + override = writeCompilerWithJumps(compiler, node->pathIf.thenPath, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } int jumpToEnd = 0; - if (node->path.elsePath) { + if (node->pathIf.elsePath) { //insert jump to end compiler->bytecode[compiler->count++] = OP_JUMP; //1 byte jumpToEnd = compiler->count; @@ -570,9 +570,9 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br //update the jumpToElse to point here AS_USHORT(compiler->bytecode[jumpToElse]) = compiler->count + jumpOffsets; //2 bytes - if (node->path.elsePath) { + if (node->pathIf.elsePath) { //if there's an else path, write it and - Opcode override = writeCompilerWithJumps(compiler, node->path.elsePath, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); + Opcode override = writeCompilerWithJumps(compiler, node->pathIf.elsePath, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -583,7 +583,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br } break; - case AST_NODEPATH_WHILE: { + case AST_NODE_WHILE: { //for breaks and continues LiteralArray breakAddresses; LiteralArray continueAddresses; @@ -595,7 +595,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br unsigned short jumpToStart = compiler->count; //process the condition - Opcode override = writeCompilerWithJumps(compiler, node->path.condition, &breakAddresses, &continueAddresses, jumpOffsets, rootNode); + Opcode override = writeCompilerWithJumps(compiler, node->pathWhile.condition, &breakAddresses, &continueAddresses, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -606,7 +606,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br compiler->count += sizeof(unsigned short); //2 bytes //write the body - override = writeCompilerWithJumps(compiler, node->path.thenPath, &breakAddresses, &continueAddresses, jumpOffsets, rootNode); + override = writeCompilerWithJumps(compiler, node->pathWhile.thenPath, &breakAddresses, &continueAddresses, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -639,7 +639,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br } break; - case AST_NODEPATH_FOR: { + case AST_NODE_FOR: { //for breaks and continues LiteralArray breakAddresses; LiteralArray continueAddresses; @@ -650,14 +650,14 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br compiler->bytecode[compiler->count++] = OP_SCOPE_BEGIN; //1 byte //initial setup - Opcode override = writeCompilerWithJumps(compiler, node->path.preClause, &breakAddresses, &continueAddresses, jumpOffsets, rootNode); + Opcode override = writeCompilerWithJumps(compiler, node->pathFor.preClause, &breakAddresses, &continueAddresses, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } //conditional unsigned short jumpToStart = compiler->count; - override = writeCompilerWithJumps(compiler, node->path.condition, &breakAddresses, &continueAddresses, jumpOffsets, rootNode); + override = writeCompilerWithJumps(compiler, node->pathFor.condition, &breakAddresses, &continueAddresses, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -669,7 +669,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br //write the body compiler->bytecode[compiler->count++] = OP_SCOPE_BEGIN; //1 byte - override = writeCompilerWithJumps(compiler, node->path.thenPath, &breakAddresses, &continueAddresses, jumpOffsets, rootNode); + override = writeCompilerWithJumps(compiler, node->pathFor.thenPath, &breakAddresses, &continueAddresses, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -679,7 +679,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br int jumpToIncrement = compiler->count; //evaluate third clause, restart - override = writeCompilerWithJumps(compiler, node->path.postClause, &breakAddresses, &continueAddresses, jumpOffsets, rootNode); + override = writeCompilerWithJumps(compiler, node->pathFor.postClause, &breakAddresses, &continueAddresses, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -712,7 +712,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br } break; - case AST_NODEPATH_BREAK: { + case AST_NODE_BREAK: { if (!breakAddressesPtr) { fprintf(stderr, ERROR "ERROR: Can't place a break statement here\n" RESET); break; @@ -730,7 +730,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br } break; - case AST_NODEPATH_CONTINUE: { + case AST_NODE_CONTINUE: { if (!continueAddressesPtr) { fprintf(stderr, ERROR "ERROR: Can't place a continue statement here\n" RESET); break; @@ -748,10 +748,10 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br } break; - case AST_NODEPATH_RETURN: { + case AST_NODE_FN_RETURN: { //read each returned literal onto the stack, and return the number of values to return - for (int i = 0; i < node->path.thenPath->fnCollection.count; i++) { - Opcode override = writeCompilerWithJumps(compiler, &node->path.thenPath->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); + for (int i = 0; i < node->returns.returns->fnCollection.count; i++) { + Opcode override = writeCompilerWithJumps(compiler, &node->returns.returns->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -760,18 +760,18 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br //push the return, with the number of literals compiler->bytecode[compiler->count++] = OP_FN_RETURN; //1 byte - *((unsigned short*)(compiler->bytecode + compiler->count)) = (unsigned short)(node->path.thenPath->fnCollection.count); //2 bytes + *((unsigned short*)(compiler->bytecode + compiler->count)) = (unsigned short)(node->returns.returns->fnCollection.count); //2 bytes compiler->count += sizeof(unsigned short); } break; - case AST_NODEINCREMENT_PREFIX: { - //push the literal to the stack (twice) - writeLiteralToCompiler(compiler, node->increment.identifier); - writeLiteralToCompiler(compiler, node->increment.identifier); + case AST_NODE_PREFIX_INCREMENT: { + //push the literal to the stack (twice: add + assign) + writeLiteralToCompiler(compiler, node->prefixIncrement.identifier); + writeLiteralToCompiler(compiler, node->prefixIncrement.identifier); //push the increment / decrement - Literal increment = TO_INTEGER_LITERAL(node->increment.increment); + Literal increment = TO_INTEGER_LITERAL(1); writeLiteralToCompiler(compiler, increment); //push the add opcode @@ -781,22 +781,43 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br compiler->bytecode[compiler->count++] = (unsigned char)OP_VAR_ASSIGN; //1 byte //leave the result on the stack - writeLiteralToCompiler(compiler, node->increment.identifier); + writeLiteralToCompiler(compiler, node->prefixIncrement.identifier); compiler->bytecode[compiler->count++] = (unsigned char)OP_LITERAL_RAW; //1 byte } break; - case AST_NODEINCREMENT_POSTFIX: { - //push the identifier's VALUE to the stack - writeLiteralToCompiler(compiler, node->increment.identifier); - compiler->bytecode[compiler->count++] = (unsigned char)OP_LITERAL_RAW; //1 byte - - //push the identifier (twice) - writeLiteralToCompiler(compiler, node->increment.identifier); - writeLiteralToCompiler(compiler, node->increment.identifier); + case AST_NODE_PREFIX_DECREMENT: { + //push the literal to the stack (twice: add + assign) + writeLiteralToCompiler(compiler, node->prefixDecrement.identifier); + writeLiteralToCompiler(compiler, node->prefixDecrement.identifier); //push the increment / decrement - Literal increment = TO_INTEGER_LITERAL(node->increment.increment); + Literal increment = TO_INTEGER_LITERAL(1); + writeLiteralToCompiler(compiler, increment); + + //push the subtract opcode + compiler->bytecode[compiler->count++] = (unsigned char)OP_SUBTRACTION; //1 byte + + //push the assign + compiler->bytecode[compiler->count++] = (unsigned char)OP_VAR_ASSIGN; //1 byte + + //leave the result on the stack + writeLiteralToCompiler(compiler, node->prefixDecrement.identifier); + compiler->bytecode[compiler->count++] = (unsigned char)OP_LITERAL_RAW; //1 byte + } + break; + + case AST_NODE_POSTFIX_INCREMENT: { + //push the identifier's VALUE to the stack + writeLiteralToCompiler(compiler, node->postfixIncrement.identifier); + compiler->bytecode[compiler->count++] = (unsigned char)OP_LITERAL_RAW; //1 byte + + //push the identifier (twice: add + assign) + writeLiteralToCompiler(compiler, node->postfixIncrement.identifier); + writeLiteralToCompiler(compiler, node->postfixIncrement.identifier); + + //push the increment / decrement + Literal increment = TO_INTEGER_LITERAL(1); writeLiteralToCompiler(compiler, increment); //push the add opcode @@ -807,7 +828,28 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br } break; - case AST_NODEIMPORT: { + case AST_NODE_POSTFIX_DECREMENT: { + //push the identifier's VALUE to the stack + writeLiteralToCompiler(compiler, node->postfixDecrement.identifier); + compiler->bytecode[compiler->count++] = (unsigned char)OP_LITERAL_RAW; //1 byte + + //push the identifier (twice: add + assign) + writeLiteralToCompiler(compiler, node->postfixDecrement.identifier); + writeLiteralToCompiler(compiler, node->postfixDecrement.identifier); + + //push the increment / decrement + Literal increment = TO_INTEGER_LITERAL(1); + writeLiteralToCompiler(compiler, increment); + + //push the subtract opcode + compiler->bytecode[compiler->count++] = (unsigned char)OP_SUBTRACTION; //1 byte + + //push the assign + compiler->bytecode[compiler->count++] = (unsigned char)OP_VAR_ASSIGN; //1 byte + } + break; + + case AST_NODE_IMPORT: { //push the identifier, and the alias writeLiteralToCompiler(compiler, node->import.identifier); writeLiteralToCompiler(compiler, node->import.alias); @@ -817,7 +859,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br } break; - case AST_NODEEXPORT: { + case AST_NODE_EXPORT: { //push the identifier, and the alias writeLiteralToCompiler(compiler, node->import.identifier); writeLiteralToCompiler(compiler, node->import.alias); @@ -827,7 +869,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br } break; - case AST_NODEINDEX: { + case AST_NODE_INDEX: { //pass to the child nodes, then embed the opcode //first @@ -868,12 +910,6 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br return OP_INDEX_ASSIGN; //override binary's instruction IF it is assign } break; - - case AST_NODEDOT: { - fprintf(stderr, ERROR "[internal] AST_NODEDOT encountered in writeCompilerWithJumps()\n" RESET); - compiler->bytecode[compiler->count++] = OP_EOF; //1 byte - } - break; } return OP_EOF; @@ -1006,8 +1042,8 @@ static unsigned char* collateCompilerHeaderOpt(Compiler* compiler, int* size, bo Literal str = compiler->literalCache.literals[i]; - for (int c = 0; c < (int)strlen(AS_STRING(str)); c++) { - emitByte(&collation, &capacity, &count, AS_STRING(str)[c]); + for (int c = 0; c < AS_STRING(str)->length; c++) { + emitByte(&collation, &capacity, &count, toCString(AS_STRING(str))[c]); } emitByte(&collation, &capacity, &count, '\0'); //terminate the string @@ -1078,8 +1114,8 @@ static unsigned char* collateCompilerHeaderOpt(Compiler* compiler, int* size, bo Literal identifier = compiler->literalCache.literals[i]; - for (int c = 0; c < (int)strlen(AS_IDENTIFIER(identifier)); c++) { - emitByte(&collation, &capacity, &count, AS_IDENTIFIER(identifier)[c]); + for (int c = 0; c < AS_IDENTIFIER(identifier)->length; c++) { + emitByte(&collation, &capacity, &count, toCString(AS_IDENTIFIER(identifier))[c]); } emitByte(&collation, &capacity, &count, '\0'); //terminate the string diff --git a/source/interpreter.c b/source/interpreter.c index 9a4cec1..1ca1425 100644 --- a/source/interpreter.c +++ b/source/interpreter.c @@ -34,7 +34,7 @@ bool injectNativeFn(Interpreter* interpreter, char* name, NativeFn func) { } int identifierLength = strlen(name); - Literal identifier = TO_IDENTIFIER_LITERAL(copyString(name, identifierLength), identifierLength); + Literal identifier = TO_IDENTIFIER_LITERAL(createRefStringLength(name, identifierLength)); //make sure the name isn't taken if (existsLiteralDictionary(&interpreter->scope->variables, identifier)) { @@ -64,7 +64,7 @@ bool injectNativeHook(Interpreter* interpreter, char* name, HookFn hook) { } int identifierLength = strlen(name); - Literal identifier = TO_IDENTIFIER_LITERAL(copyString(name, identifierLength), identifierLength); + Literal identifier = TO_IDENTIFIER_LITERAL(createRefStringLength(name, identifierLength)); //make sure the name isn't taken if (existsLiteralDictionary(interpreter->hooks, identifier)) { @@ -235,7 +235,7 @@ static bool execAssert(Interpreter* interpreter) { } if (IS_NULL(lhs) || !IS_TRUTHY(lhs)) { - (*interpreter->assertOutput)(AS_STRING(rhs)); + (*interpreter->assertOutput)(toCString(AS_STRING(rhs))); freeLiteral(rhs); interpreter->panic = true; return false; @@ -320,7 +320,7 @@ static bool execNegate(Interpreter* interpreter) { lit = TO_FLOAT_LITERAL(-AS_FLOAT(lit)); } else { - interpreter->errorOutput("[internal] The interpreter can't negate that literal: "); + interpreter->errorOutput("Can't negate that literal: "); printLiteralCustom(lit, interpreter->errorOutput); interpreter->errorOutput("\n"); @@ -352,7 +352,7 @@ static bool execInvert(Interpreter* interpreter) { lit = TO_BOOLEAN_LITERAL(!AS_BOOLEAN(lit)); } else { - interpreter->errorOutput("[internal] The interpreter can't invert that literal: "); + interpreter->errorOutput("Can't invert that literal: "); printLiteralCustom(lit, interpreter->errorOutput); interpreter->errorOutput("\n"); @@ -387,7 +387,7 @@ static bool execArithmetic(Interpreter* interpreter, Opcode opcode) { //special case for string concatenation ONLY if (IS_STRING(lhs) && IS_STRING(rhs)) { //check for overflow - int totalLength = strlen(AS_STRING(lhs)) + strlen(AS_STRING(rhs)); + int totalLength = AS_STRING(lhs)->length + AS_STRING(rhs)->length; if (totalLength > MAX_STRING_LENGTH) { interpreter->errorOutput("Can't concatenate these strings (result is too long)\n"); return false; @@ -395,9 +395,11 @@ static bool execArithmetic(Interpreter* interpreter, Opcode opcode) { //concat the strings char buffer[MAX_STRING_LENGTH]; - snprintf(buffer, MAX_STRING_LENGTH, "%s%s", AS_STRING(lhs), AS_STRING(rhs)); - Literal literal = TO_STRING_LITERAL( copyString(buffer, totalLength), totalLength); + snprintf(buffer, MAX_STRING_LENGTH, "%s%s", toCString(AS_STRING(lhs)), toCString(AS_STRING(rhs))); + Literal literal = TO_STRING_LITERAL(createRefStringLength(buffer, totalLength)); pushLiteralArray(&interpreter->stack, literal); + + //cleanup freeLiteral(literal); freeLiteral(lhs); freeLiteral(rhs); @@ -751,7 +753,7 @@ static bool execValCast(Interpreter* interpreter) { if (IS_STRING(value)) { int val = 0; - sscanf(AS_STRING(value), "%d", &val); + sscanf(toCString(AS_STRING(value)), "%d", &val); result = TO_INTEGER_LITERAL(val); } break; @@ -771,7 +773,7 @@ static bool execValCast(Interpreter* interpreter) { if (IS_STRING(value)) { float val = 0; - sscanf(AS_STRING(value), "%f", &val); + sscanf(toCString(AS_STRING(value)), "%f", &val); result = TO_FLOAT_LITERAL(val); } break; @@ -781,21 +783,21 @@ static bool execValCast(Interpreter* interpreter) { char* str = AS_BOOLEAN(value) ? "true" : "false"; int length = strlen(str); - result = TO_STRING_LITERAL(copyString(str, length), length); + result = TO_STRING_LITERAL(createRefStringLength(str, length)); //TODO: static reference optimisation? } if (IS_INTEGER(value)) { char buffer[128]; snprintf(buffer, 128, "%d", AS_INTEGER(value)); int length = strlen(buffer); - result = TO_STRING_LITERAL(copyString(buffer, length), length); + result = TO_STRING_LITERAL(createRefStringLength(buffer, length)); } if (IS_FLOAT(value)) { char buffer[128]; snprintf(buffer, 128, "%g", AS_FLOAT(value)); int length = strlen(buffer); - result = TO_STRING_LITERAL(copyString(buffer, length), length); + result = TO_STRING_LITERAL(createRefStringLength(buffer, length)); } if (IS_STRING(value)) { @@ -1143,12 +1145,12 @@ static bool execFnCall(Interpreter* interpreter, bool looseFirstArgument) { //let's screw with the fn name, too if (looseFirstArgument) { - int length = strlen(AS_IDENTIFIER(identifier)) + 1; + int length = AS_IDENTIFIER(identifier)->length + 1; char buffer[MAX_STRING_LENGTH]; - snprintf(buffer, MAX_STRING_LENGTH, "_%s", AS_IDENTIFIER(identifier)); //prepend an underscore + snprintf(buffer, MAX_STRING_LENGTH, "_%s", toCString(AS_IDENTIFIER(identifier))); //prepend an underscore freeLiteral(identifier); - identifier = TO_IDENTIFIER_LITERAL(copyString(buffer, length), length); + identifier = TO_IDENTIFIER_LITERAL(createRefStringLength(buffer, length)); } Literal func = identifier; @@ -1219,7 +1221,7 @@ bool callLiteralFn(Interpreter* interpreter, Literal func, LiteralArray* argumen initLiteralArray(&inner.literalCache); inner.scope = pushScope(func.as.function.scope); inner.bytecode = AS_FUNCTION(func).bytecode; - inner.length = func.as.function.length; + inner.length = AS_FUNCTION(func).length; inner.count = 0; inner.codeStart = -1; inner.depth = interpreter->depth + 1; @@ -1414,7 +1416,7 @@ bool callLiteralFn(Interpreter* interpreter, Literal func, LiteralArray* argumen } bool callFn(Interpreter* interpreter, char* name, LiteralArray* arguments, LiteralArray* returns) { - Literal key = TO_IDENTIFIER_LITERAL(copyString(name, strlen(name)), strlen(name)); + Literal key = TO_IDENTIFIER_LITERAL(createRefStringLength(name, strlen(name))); Literal val = TO_NULL_LITERAL; if (!isDelcaredScopeVariable(interpreter->scope, key)) { @@ -1605,7 +1607,7 @@ static bool execIndex(Interpreter* interpreter, bool assignIntermediate) { Literal func = TO_NULL_LITERAL; char* keyStr = "_index"; int keyStrLength = strlen(keyStr); - Literal key = TO_IDENTIFIER_LITERAL(copyString(keyStr, keyStrLength), keyStrLength); + Literal key = TO_IDENTIFIER_LITERAL(createRefStringLength(keyStr, keyStrLength)); if (!getScopeVariable(interpreter->scope, key, &func) || !IS_FUNCTION_NATIVE(func)) { interpreter->errorOutput("couldn't get the _index function\n"); @@ -1704,7 +1706,7 @@ static bool execIndexAssign(Interpreter* interpreter) { Literal func = TO_NULL_LITERAL; char* keyStr = "_index"; int keyStrLength = strlen(keyStr); - Literal key = TO_IDENTIFIER_LITERAL(copyString(keyStr, keyStrLength), keyStrLength); + Literal key = TO_IDENTIFIER_LITERAL(createRefStringLength(keyStr, keyStrLength)); if (!getScopeVariable(interpreter->scope, key, &func) || !IS_FUNCTION_NATIVE(func)) { interpreter->errorOutput("couldn't get the _index function\n"); @@ -1760,7 +1762,7 @@ static bool execIndexAssign(Interpreter* interpreter) { } int opLength = strlen(opStr); - Literal op = TO_STRING_LITERAL(copyString(opStr, opLength), opLength); + Literal op = TO_STRING_LITERAL(createRefStringLength(opStr, opLength)); //TODO: static reference optimisation? //build the argument list LiteralArray arguments; @@ -1815,7 +1817,7 @@ static bool execIndexAssign(Interpreter* interpreter) { char* opStr = "="; //shadow, but force assignment int opLength = strlen(opStr); - op = TO_STRING_LITERAL(copyString(opStr, opLength), opLength); + op = TO_STRING_LITERAL(createRefStringLength(opStr, opLength)); //TODO: static reference optimisation? //assign to the idn / compound - with _index pushLiteralArray(&arguments, idn); @@ -2194,7 +2196,7 @@ static void readInterpreterSections(Interpreter* interpreter) { case LITERAL_STRING: { char* s = readString(interpreter->bytecode, &interpreter->count); int length = strlen(s); - Literal literal = TO_STRING_LITERAL( copyString(s, length), length); + Literal literal = TO_STRING_LITERAL(createRefStringLength(s, length)); pushLiteralArray(&interpreter->literalCache, literal); freeLiteral(literal); @@ -2290,13 +2292,13 @@ static void readInterpreterSections(Interpreter* interpreter) { char* str = readString(interpreter->bytecode, &interpreter->count); int length = strlen(str); - Literal identifier = TO_IDENTIFIER_LITERAL(copyString(str, length), length); + Literal identifier = TO_IDENTIFIER_LITERAL(createRefStringLength(str, length)); pushLiteralArray(&interpreter->literalCache, identifier); #ifndef TOY_EXPORT if (command.verbose) { - printf("(identifier %s (hash: %x))\n", AS_IDENTIFIER(identifier), identifier.as.identifier.hash); + printf("(identifier %s (hash: %x))\n", toCString(AS_IDENTIFIER(identifier)), identifier.as.identifier.hash); } #endif diff --git a/source/literal.c b/source/literal.c index 26382dd..01553ca 100644 --- a/source/literal.c +++ b/source/literal.c @@ -21,7 +21,7 @@ static unsigned int hashString(const char* string, int length) { return hash; } -static unsigned int hash(unsigned int x) { +static unsigned int hashUInt(unsigned int x) { x = ((x >> 16) ^ x) * 0x45d9f3b; x = ((x >> 16) ^ x) * 0x45d9f3b; x = (x >> 16) ^ x; @@ -30,11 +30,18 @@ static unsigned int hash(unsigned int x) { //exposed functions void freeLiteral(Literal literal) { + //refstrings if (IS_STRING(literal)) { - FREE_ARRAY(char, AS_STRING(literal), literal.as.string.length + 1); + deleteRefString(AS_STRING(literal)); return; } + if (IS_IDENTIFIER(literal)) { + deleteRefString(AS_IDENTIFIER(literal)); + return; + } + + //compounds if (IS_ARRAY(literal) || literal.type == LITERAL_DICTIONARY_INTERMEDIATE || literal.type == LITERAL_TYPE_INTERMEDIATE) { freeLiteralArray(AS_ARRAY(literal)); FREE(LiteralArray, AS_ARRAY(literal)); @@ -47,17 +54,13 @@ void freeLiteral(Literal literal) { return; } + //complex literals if (IS_FUNCTION(literal)) { popScope(AS_FUNCTION(literal).scope); AS_FUNCTION(literal).scope = NULL; FREE_ARRAY(unsigned char, AS_FUNCTION(literal).bytecode, AS_FUNCTION(literal).length); } - if (IS_IDENTIFIER(literal)) { - FREE_ARRAY(char, AS_IDENTIFIER(literal), literal.as.identifier.length + 1); - return; - } - if (IS_TYPE(literal)) { for (int i = 0; i < AS_TYPE(literal).count; i++) { freeLiteral(((Literal*)(AS_TYPE(literal).subtypes))[i]); @@ -80,12 +83,12 @@ bool _isTruthy(Literal x) { return true; } -Literal _toStringLiteral(char* str, int length) { - return ((Literal){LITERAL_STRING, { .string.ptr = (char*)str, .string.length = length }}); +Literal _toStringLiteral(RefString* ptr) { + return ((Literal){LITERAL_STRING, { .string.ptr = ptr }}); } -Literal _toIdentifierLiteral(char* str, int length) { - return ((Literal){LITERAL_IDENTIFIER,{ .identifier.ptr = (char*)str, .identifier.length = length, .identifier.hash = hashString(str, length) }}); +Literal _toIdentifierLiteral(RefString* ptr) { + return ((Literal){LITERAL_IDENTIFIER,{ .identifier.ptr = ptr, .identifier.hash = hashString(toCString(ptr), lengthRefString(ptr)) }}); } Literal* _typePushSubtype(Literal* lit, Literal subtype) { @@ -112,7 +115,7 @@ Literal copyLiteral(Literal original) { return original; case LITERAL_STRING: { - return TO_STRING_LITERAL(copyString(AS_STRING(original), original.as.string.length), original.as.string.length); + return TO_STRING_LITERAL(copyRefString(AS_STRING(original))); } case LITERAL_ARRAY: { @@ -152,7 +155,7 @@ Literal copyLiteral(Literal original) { } case LITERAL_IDENTIFIER: { - return TO_IDENTIFIER_LITERAL(copyString(AS_IDENTIFIER(original), original.as.identifier.length), original.as.identifier.length); + return TO_IDENTIFIER_LITERAL(copyRefString(AS_IDENTIFIER(original))); } case LITERAL_TYPE: { @@ -212,14 +215,6 @@ Literal copyLiteral(Literal original) { } } -char* copyString(char* original, int length) { - //make a local copy of the char array - char* buffer = ALLOCATE(char, length + 1); - strncpy(buffer, original, length); - buffer[length] = '\0'; - return buffer; -} - bool literalsAreEqual(Literal lhs, Literal rhs) { //utility for other things if (lhs.type != rhs.type) { @@ -250,10 +245,7 @@ bool literalsAreEqual(Literal lhs, Literal rhs) { return AS_FLOAT(lhs) == AS_FLOAT(rhs); case LITERAL_STRING: - if (lhs.as.string.length != rhs.as.string.length) { - return false; - } - return !strncmp(AS_STRING(lhs), AS_STRING(rhs), lhs.as.string.length); + return equalsRefString(AS_STRING(lhs), AS_STRING(rhs)); case LITERAL_ARRAY: case LITERAL_DICTIONARY_INTERMEDIATE: //BUGFIX @@ -299,11 +291,11 @@ bool literalsAreEqual(Literal lhs, Literal rhs) { case LITERAL_IDENTIFIER: //check shortcuts - if (HASH_I(lhs) != HASH_I(rhs) && lhs.as.identifier.length != rhs.as.identifier.length) { + if (HASH_I(lhs) != HASH_I(rhs)) { return false; } - return !strncmp(AS_IDENTIFIER(lhs), AS_IDENTIFIER(rhs), lhs.as.identifier.length); + return equalsRefString(AS_IDENTIFIER(lhs), AS_IDENTIFIER(rhs)); case LITERAL_TYPE: //check types @@ -359,20 +351,20 @@ int hashLiteral(Literal lit) { return AS_BOOLEAN(lit) ? 1 : 0; case LITERAL_INTEGER: - return hash((unsigned int)AS_INTEGER(lit)); + return hashUInt((unsigned int)AS_INTEGER(lit)); case LITERAL_FLOAT: - return hash(*(unsigned int*)(&AS_FLOAT(lit))); + return hashUInt(*(unsigned int*)(&AS_FLOAT(lit))); case LITERAL_STRING: - return hashString(AS_STRING(lit), strlen(AS_STRING(lit))); + return hashString(toCString(AS_STRING(lit)), lengthRefString(AS_STRING(lit))); case LITERAL_ARRAY: { unsigned int res = 0; for (int i = 0; i < AS_ARRAY(lit)->count; i++) { res += hashLiteral(AS_ARRAY(lit)->literals[i]); } - return hash(res); + return hashUInt(res); } case LITERAL_DICTIONARY: { @@ -383,7 +375,7 @@ int hashLiteral(Literal lit) { res += hashLiteral(AS_DICTIONARY(lit)->entries[i].value); } } - return hash(res); + return hashUInt(res); } case LITERAL_FUNCTION: @@ -464,10 +456,10 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) { case LITERAL_STRING: { char buffer[MAX_STRING_LENGTH]; if (!quotes) { - snprintf(buffer, MAX_STRING_LENGTH, "%.*s", (int)strlen(AS_STRING(literal)), AS_STRING(literal)); + snprintf(buffer, MAX_STRING_LENGTH, "%.*s", lengthRefString(AS_STRING(literal)), toCString(AS_STRING(literal))); } else { - snprintf(buffer, MAX_STRING_LENGTH, "%c%.*s%c", quotes, (int)strlen(AS_STRING(literal)), AS_STRING(literal), quotes); + snprintf(buffer, MAX_STRING_LENGTH, "%c%.*s%c", quotes, lengthRefString(AS_STRING(literal)), toCString(AS_STRING(literal)), quotes); } printFn(buffer); } @@ -573,7 +565,7 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) { case LITERAL_IDENTIFIER: { char buffer[256]; - snprintf(buffer, 256, "%.*s", (int)strlen( AS_IDENTIFIER(literal) ), AS_IDENTIFIER(literal)); + snprintf(buffer, 256, "%.*s", lengthRefString(AS_IDENTIFIER(literal)), toCString(AS_IDENTIFIER(literal))); printFn(buffer); } break; diff --git a/source/literal.h b/source/literal.h index f24f9d6..e2e8f5a 100644 --- a/source/literal.h +++ b/source/literal.h @@ -2,6 +2,8 @@ #include "toy_common.h" +#include "refstring.h" + #include typedef enum { @@ -33,8 +35,8 @@ typedef struct { int integer; float number; struct { - char* ptr; - int length; + RefString* ptr; + //string hash? } string; void* array; @@ -47,8 +49,7 @@ typedef struct { } function; struct { //for variable names - char* ptr; - int length; + RefString* ptr; int hash; } identifier; @@ -62,7 +63,7 @@ typedef struct { struct { void* ptr; - int tag; + int tag; //TODO: remove tags? } opaque; } as; } Literal; @@ -95,11 +96,11 @@ typedef struct { #define TO_BOOLEAN_LITERAL(value) ((Literal){LITERAL_BOOLEAN, { .boolean = value }}) #define TO_INTEGER_LITERAL(value) ((Literal){LITERAL_INTEGER, { .integer = value }}) #define TO_FLOAT_LITERAL(value) ((Literal){LITERAL_FLOAT, { .number = value }}) -#define TO_STRING_LITERAL(value, l) _toStringLiteral(value, l) +#define TO_STRING_LITERAL(value) _toStringLiteral(value) #define TO_ARRAY_LITERAL(value) ((Literal){LITERAL_ARRAY, { .array = value }}) #define TO_DICTIONARY_LITERAL(value) ((Literal){LITERAL_DICTIONARY, { .dictionary = value }}) #define TO_FUNCTION_LITERAL(value, l) ((Literal){LITERAL_FUNCTION, { .function.bytecode = value, .function.scope = NULL, .function.length = l }}) -#define TO_IDENTIFIER_LITERAL(value, l) _toIdentifierLiteral(value, l) +#define TO_IDENTIFIER_LITERAL(value) _toIdentifierLiteral(value) #define TO_TYPE_LITERAL(value, c) ((Literal){ LITERAL_TYPE, { .type.typeOf = value, .type.constant = c, .type.subtypes = NULL, .type.capacity = 0, .type.count = 0 }}) #define TO_OPAQUE_LITERAL(value, t) ((Literal){ LITERAL_OPAQUE, { .opaque.ptr = value, .opaque.tag = t }}) @@ -114,13 +115,12 @@ TOY_API void freeLiteral(Literal literal); //BUGFIX: macros are not functions TOY_API bool _isTruthy(Literal x); -TOY_API Literal _toStringLiteral(char* str, int length); -TOY_API Literal _toIdentifierLiteral(char* str, int length); +TOY_API Literal _toStringLiteral(RefString* ptr); +TOY_API Literal _toIdentifierLiteral(RefString* ptr); TOY_API Literal* _typePushSubtype(Literal* lit, Literal subtype); //utils TOY_API Literal copyLiteral(Literal original); -TOY_API char* copyString(char* original, int length); TOY_API bool literalsAreEqual(Literal lhs, Literal rhs); TOY_API int hashLiteral(Literal lit); diff --git a/source/memory.c b/source/memory.c index feab031..98efd61 100644 --- a/source/memory.c +++ b/source/memory.c @@ -1,4 +1,5 @@ #include "memory.h" +#include "refstring.h" #include "console_colors.h" @@ -6,7 +7,7 @@ #include //default allocator -void* defaultAllocator(void* pointer, size_t oldSize, size_t newSize) { +void* defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSize) { if (newSize == 0 && oldSize == 0) { //causes issues, so just skip out with a NO-OP return NULL; @@ -28,10 +29,20 @@ void* defaultAllocator(void* pointer, size_t oldSize, size_t newSize) { return mem; } -//exposed API -static AllocatorFn allocator = defaultAllocator; +//static variables +static MemoryAllocatorFn allocator; -void setAllocator(AllocatorFn fn) { +//preload +static void __attribute__((constructor)) preloadMemoryAllocator() { + setMemoryAllocator(defaultMemoryAllocator); +} + +//exposed API +void* reallocate(void* pointer, size_t oldSize, size_t newSize) { + return allocator(pointer, oldSize, newSize); +} + +void setMemoryAllocator(MemoryAllocatorFn fn) { if (fn == NULL) { fprintf(stderr, ERROR "[internal] Memory allocator error (can't be null)\n" RESET); exit(-1); @@ -43,8 +54,5 @@ void setAllocator(AllocatorFn fn) { } allocator = fn; + setRefStringAllocatorFn(fn); } - -void* reallocate(void* pointer, size_t oldSize, size_t newSize) { - return allocator(pointer, oldSize, newSize); -} \ No newline at end of file diff --git a/source/memory.h b/source/memory.h index b5c8456..9d35eb2 100644 --- a/source/memory.h +++ b/source/memory.h @@ -11,7 +11,8 @@ #define FREE_ARRAY(type, pointer, oldCount) reallocate((type*)pointer, sizeof(type) * (oldCount), 0) //implementation details -typedef void* (*AllocatorFn)(void* pointer, size_t oldSize, size_t newSize); -TOY_API void setAllocator(AllocatorFn); - void* reallocate(void* pointer, size_t oldSize, size_t newSize); + +//assign the memory allocator +typedef void* (*MemoryAllocatorFn)(void* pointer, size_t oldSize, size_t newSize); +TOY_API void setMemoryAllocator(MemoryAllocatorFn); diff --git a/source/parser.c b/source/parser.c index 81c0969..bb165e3 100644 --- a/source/parser.c +++ b/source/parser.c @@ -119,6 +119,7 @@ static void declaration(Parser* parser, ASTNode** nodeHandle); static void parsePrecedence(Parser* parser, ASTNode** nodeHandle, PrecedenceRule rule); static Literal readTypeToLiteral(Parser* parser); +//TODO: resolve the messy order of these //the expression rules static Opcode asType(Parser* parser, ASTNode** nodeHandle) { Literal literal = readTypeToLiteral(parser); @@ -182,14 +183,14 @@ static Opcode compound(Parser* parser, ASTNode** nodeHandle) { parsePrecedence(parser, &right, PREC_PRIMARY); if (!right) { //error - freeNode(left); + freeASTNode(left); return OP_EOF; } //check we ARE defining a dictionary if (array) { error(parser, parser->previous, "Incorrect detection between array and dictionary"); - freeNode(array); + freeASTNode(array); return OP_EOF; } @@ -214,7 +215,7 @@ static Opcode compound(Parser* parser, ASTNode** nodeHandle) { //check we ARE defining an array if (dictionary) { error(parser, parser->current, "Incorrect detection between array and dictionary"); - freeNode(dictionary); + freeASTNode(dictionary); return OP_EOF; } @@ -269,7 +270,7 @@ static Opcode string(Parser* parser, ASTNode** nodeHandle) { error(parser, parser->previous, buffer); } - Literal literal = TO_STRING_LITERAL(copyString(parser->previous.lexeme, length), length); + Literal literal = TO_STRING_LITERAL(createRefStringLength(parser->previous.lexeme, length)); emitASTNodeLiteral(nodeHandle, literal); freeLiteral(literal); return OP_EOF; @@ -418,7 +419,7 @@ static Opcode unary(Parser* parser, ASTNode** nodeHandle) { parsePrecedence(parser, &tmpNode, PREC_TERNARY); //can be a literal //check for negative literals (optimisation) - if (tmpNode->type == AST_NODELITERAL && (IS_INTEGER(tmpNode->atomic.literal) || IS_FLOAT(tmpNode->atomic.literal))) { + if (tmpNode->type == AST_NODE_LITERAL && (IS_INTEGER(tmpNode->atomic.literal) || IS_FLOAT(tmpNode->atomic.literal))) { //negate directly, if int or float Literal lit = tmpNode->atomic.literal; @@ -437,22 +438,22 @@ static Opcode unary(Parser* parser, ASTNode** nodeHandle) { } //check for negated boolean errors - if (tmpNode->type == AST_NODELITERAL && IS_BOOLEAN(tmpNode->atomic.literal)) { + if (tmpNode->type == AST_NODE_LITERAL && IS_BOOLEAN(tmpNode->atomic.literal)) { error(parser, parser->previous, "Negative booleans are not allowed"); return OP_EOF; } - //actually emit the negation + //actually emit the negation node emitASTNodeUnary(nodeHandle, OP_NEGATE, tmpNode); } else if (parser->previous.type == TOKEN_NOT) { //temp handle to potentially negate values - parsePrecedence(parser, &tmpNode, PREC_CALL); //can be a literal + parsePrecedence(parser, &tmpNode, PREC_CALL); //can be a literal, grouping, fn call, etc. //check for inverted booleans - if (tmpNode->type == AST_NODELITERAL && IS_BOOLEAN(tmpNode->atomic.literal)) { - //negate directly, if int or float + if (tmpNode->type == AST_NODE_LITERAL && IS_BOOLEAN(tmpNode->atomic.literal)) { + //negate directly, if boolean Literal lit = tmpNode->atomic.literal; lit = TO_BOOLEAN_LITERAL(!AS_BOOLEAN(lit)); @@ -463,12 +464,6 @@ static Opcode unary(Parser* parser, ASTNode** nodeHandle) { return OP_EOF; } - //check for inverted number errors - if (tmpNode->type == AST_NODELITERAL && (IS_INTEGER(tmpNode->atomic.literal) || IS_FLOAT(tmpNode->atomic.literal))) { - error(parser, parser->previous, "Inverted numbers are not allowed"); - return OP_EOF; - } - //actually emit the negation emitASTNodeUnary(nodeHandle, OP_INVERT, tmpNode); } @@ -543,12 +538,9 @@ static Opcode identifier(Parser* parser, ASTNode** nodeHandle) { error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long"); } - char* cpy = copyString(identifierToken.lexeme, length); - Literal identifier = _toIdentifierLiteral(cpy, length); //BUGFIX: use this instead of the macro - + Literal identifier = TO_IDENTIFIER_LITERAL(createRefStringLength(identifierToken.lexeme, length)); emitASTNodeLiteral(nodeHandle, identifier); - - freeLiteral(identifier); //don't leave it hanging + freeLiteral(identifier); return OP_EOF; } @@ -594,6 +586,7 @@ static Opcode castingPrefix(Parser* parser, ASTNode** nodeHandle) { static Opcode castingInfix(Parser* parser, ASTNode** nodeHandle) { advance(parser); + //NOTE: using the precedence rules here switch(parser->previous.type) { case TOKEN_IDENTIFIER: identifier(parser, nodeHandle); @@ -624,28 +617,29 @@ static Opcode castingInfix(Parser* parser, ASTNode** nodeHandle) { return OP_TYPE_CAST; } +//TODO: fix these screwy names static Opcode incrementPrefix(Parser* parser, ASTNode** nodeHandle) { advance(parser); - ASTNode* node = NULL; - identifier(parser, &node); + ASTNode* tmpNode = NULL; + identifier(parser, &tmpNode); - emitASTNodePrefixIncrement(nodeHandle, node->atomic.literal, 1); + emitASTNodePrefixIncrement(nodeHandle, tmpNode->atomic.literal); - freeNode(node); + freeASTNode(tmpNode); return OP_EOF; } static Opcode incrementInfix(Parser* parser, ASTNode** nodeHandle) { - ASTNode* node = NULL; - identifier(parser, &node); + ASTNode* tmpNode = NULL; + identifier(parser, &tmpNode); advance(parser); - emitASTNodePostfixIncrement(nodeHandle, node->atomic.literal, 1); + emitASTNodePostfixIncrement(nodeHandle, tmpNode->atomic.literal); - freeNode(node); + freeASTNode(tmpNode); return OP_EOF; } @@ -653,25 +647,25 @@ static Opcode incrementInfix(Parser* parser, ASTNode** nodeHandle) { static Opcode decrementPrefix(Parser* parser, ASTNode** nodeHandle) { advance(parser); - ASTNode* node = NULL; - identifier(parser, &node); //weird + ASTNode* tmpNode = NULL; + identifier(parser, &tmpNode); //weird - emitASTNodePrefixIncrement(nodeHandle, node->atomic.literal, -1); + emitASTNodePrefixDecrement(nodeHandle, tmpNode->atomic.literal); - freeNode(node); + freeASTNode(tmpNode); return OP_EOF; } static Opcode decrementInfix(Parser* parser, ASTNode** nodeHandle) { - ASTNode* node = NULL; - identifier(parser, &node); + ASTNode* tmpNode = NULL; + identifier(parser, &tmpNode); advance(parser); - emitASTNodePostfixIncrement(nodeHandle, node->atomic.literal, -1); + emitASTNodePostfixDecrement(nodeHandle, tmpNode->atomic.literal); - freeNode(node); + freeASTNode(tmpNode); return OP_EOF; } @@ -698,17 +692,17 @@ static Opcode fnCall(Parser* parser, ASTNode** nodeHandle) { arguments->fnCollection.nodes = GROW_ARRAY(ASTNode, arguments->fnCollection.nodes, oldCapacity, arguments->fnCollection.capacity); } - ASTNode* node = NULL; - parsePrecedence(parser, &node, PREC_TERNARY); - arguments->fnCollection.nodes[arguments->fnCollection.count++] = *node; - FREE(ASTNode, node); + ASTNode* tmpNode = NULL; + parsePrecedence(parser, &tmpNode, PREC_TERNARY); + arguments->fnCollection.nodes[arguments->fnCollection.count++] = *tmpNode; + FREE(ASTNode, tmpNode); //simply free the tmpNode, so you don't free the children } while(match(parser, TOKEN_COMMA)); consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of argument list"); } //emit the call - emitASTFnCall(nodeHandle, arguments, arguments->fnCollection.count); + emitASTNodeFnCall(nodeHandle, arguments); return OP_FN_CALL; } @@ -722,7 +716,7 @@ static Opcode fnCall(Parser* parser, ASTNode** nodeHandle) { return OP_EOF; } -static Opcode indexAccess(Parser* parser, ASTNode** nodeHandle) { +static Opcode indexAccess(Parser* parser, ASTNode** nodeHandle) { //TODO: fix indexing signalling advance(parser); //val[first : second : third] @@ -740,7 +734,7 @@ static Opcode indexAccess(Parser* parser, ASTNode** nodeHandle) { //eat the first if (!match(parser, TOKEN_COLON)) { - freeNode(first); + freeASTNode(first); parsePrecedence(parser, &first, PREC_TERNARY); match(parser, TOKEN_COLON); readFirst = true; @@ -749,11 +743,11 @@ static Opcode indexAccess(Parser* parser, ASTNode** nodeHandle) { if (match(parser, TOKEN_BRACKET_RIGHT)) { if (readFirst) { - freeNode(second); + freeASTNode(second); second = NULL; } - freeNode(third); + freeASTNode(third); third = NULL; emitASTNodeIndex(nodeHandle, first, second, third); @@ -762,20 +756,20 @@ static Opcode indexAccess(Parser* parser, ASTNode** nodeHandle) { //eat the second if (!match(parser, TOKEN_COLON)) { - freeNode(second); + freeASTNode(second); parsePrecedence(parser, &second, PREC_TERNARY); match(parser, TOKEN_COLON); } if (match(parser, TOKEN_BRACKET_RIGHT)) { - freeNode(third); + freeASTNode(third); third = NULL; emitASTNodeIndex(nodeHandle, first, second, third); return OP_INDEX; } //eat the third - freeNode(third); + freeASTNode(third); parsePrecedence(parser, &third, PREC_TERNARY); emitASTNodeIndex(nodeHandle, first, second, third); @@ -787,16 +781,15 @@ static Opcode indexAccess(Parser* parser, ASTNode** nodeHandle) { static Opcode dot(Parser* parser, ASTNode** nodeHandle) { advance(parser); //for the dot - ASTNode* node = NULL; + ASTNode* tmpNode = NULL; + parsePrecedence(parser, &tmpNode, PREC_CALL); - parsePrecedence(parser, &node, PREC_CALL); - - if (node == NULL || node->binary.right == NULL) { + if (tmpNode == NULL || tmpNode->binary.right == NULL) { error(parser, parser->previous, "Expected function call after dot operator"); return OP_EOF; } - (*nodeHandle) = node; + (*nodeHandle) = tmpNode; return OP_DOT; //signal that the function name and arguments are in the wrong order } @@ -895,7 +888,7 @@ ParseRule* getRule(TokenType type) { return &parseRules[type]; } -//constant folding +//constant folding (optimisation) static bool calcStaticBinaryArithmetic(Parser* parser, ASTNode** nodeHandle) { switch((*nodeHandle)->binary.opcode) { case OP_ADDITION: @@ -916,16 +909,16 @@ static bool calcStaticBinaryArithmetic(Parser* parser, ASTNode** nodeHandle) { } //recurse to the left and right - if ((*nodeHandle)->binary.left->type == AST_NODEBINARY) { + if ((*nodeHandle)->binary.left->type == AST_NODE_BINARY) { calcStaticBinaryArithmetic(parser, &(*nodeHandle)->binary.left); } - if ((*nodeHandle)->binary.right->type == AST_NODEBINARY) { + if ((*nodeHandle)->binary.right->type == AST_NODE_BINARY) { calcStaticBinaryArithmetic(parser, &(*nodeHandle)->binary.right); } //make sure left and right are both literals - if (!((*nodeHandle)->binary.left->type == AST_NODELITERAL && (*nodeHandle)->binary.right->type == AST_NODELITERAL)) { + if (!((*nodeHandle)->binary.left->type == AST_NODE_LITERAL && (*nodeHandle)->binary.right->type == AST_NODE_LITERAL)) { return true; } @@ -1068,18 +1061,18 @@ static bool calcStaticBinaryArithmetic(Parser* parser, ASTNode** nodeHandle) { } //optimize by converting this node into a literal node - freeNode((*nodeHandle)->binary.left); - freeNode((*nodeHandle)->binary.right); + freeASTNode((*nodeHandle)->binary.left); + freeASTNode((*nodeHandle)->binary.right); - (*nodeHandle)->type = AST_NODELITERAL; + (*nodeHandle)->type = AST_NODE_LITERAL; (*nodeHandle)->atomic.literal = result; return true; } -static void dottify(Parser* parser, ASTNode** nodeHandle) { - //only if this is chained from a higher binary "fn_call" - if ((*nodeHandle)->type == AST_NODEBINARY) { +static void dottify(Parser* parser, ASTNode** nodeHandle) { //TODO: remove dot from the compiler entirely + //only if this is chained from a higher binary "fn call" + if ((*nodeHandle)->type == AST_NODE_BINARY) { if ((*nodeHandle)->binary.opcode == OP_FN_CALL) { (*nodeHandle)->binary.opcode = OP_DOT; (*nodeHandle)->binary.right->fnCall.argumentCount++; @@ -1117,7 +1110,7 @@ static void parsePrecedence(Parser* parser, ASTNode** nodeHandle, PrecedenceRule const Opcode opcode = infixRule(parser, &rhsNode); //NOTE: infix rule must advance the parser if (opcode == OP_EOF) { - freeNode(*nodeHandle); + freeASTNode(*nodeHandle); *nodeHandle = rhsNode; return; //we're done here } @@ -1129,6 +1122,7 @@ static void parsePrecedence(Parser* parser, ASTNode** nodeHandle, PrecedenceRule emitASTNodeBinary(nodeHandle, rhsNode, opcode); + //optimise away the constants if (!calcStaticBinaryArithmetic(parser, nodeHandle)) { return; } @@ -1160,19 +1154,19 @@ static void blockStmt(Parser* parser, ASTNode** nodeHandle) { (*nodeHandle)->block.nodes = GROW_ARRAY(ASTNode, (*nodeHandle)->block.nodes, oldCapacity, (*nodeHandle)->block.capacity); } - ASTNode* node = NULL; + ASTNode* tmpNode = NULL; //process the grammar rule for this line - declaration(parser, &node); + declaration(parser, &tmpNode); // Ground floor: perfumery / Stationery and leather goods / Wigs and haberdashery / Kitchenware and food / Going up! if (parser->panic) { return; } - //BUGFIX: statements no longer require an existing node - ((*nodeHandle)->block.nodes[(*nodeHandle)->block.count++]) = *node; - FREE(ASTNode, node); //simply free the tmp node + //BUGFIX: statements no longer require the existing node + ((*nodeHandle)->block.nodes[(*nodeHandle)->block.count++]) = *tmpNode; + FREE(ASTNode, tmpNode); //simply free the tmpNode, so you don't free the children } } @@ -1188,7 +1182,7 @@ static void printStmt(Parser* parser, ASTNode** nodeHandle) { static void assertStmt(Parser* parser, ASTNode** nodeHandle) { //set the node info (*nodeHandle) = ALLOCATE(ASTNode, 1); //special case, because I'm lazy - (*nodeHandle)->type = AST_NODEBINARY; + (*nodeHandle)->type = AST_NODE_BINARY; (*nodeHandle)->binary.opcode = OP_ASSERT; parsePrecedence(parser, &((*nodeHandle)->binary.left), PREC_TERNARY); @@ -1216,7 +1210,7 @@ static void ifStmt(Parser* parser, ASTNode** nodeHandle) { declaration(parser, &elsePath); } - emitASTNodePath(nodeHandle, AST_NODEPATH_IF, NULL, NULL, condition, thenPath, elsePath); + emitASTNodeIf(nodeHandle, condition, thenPath, elsePath); } static void whileStmt(Parser* parser, ASTNode** nodeHandle) { @@ -1231,40 +1225,40 @@ static void whileStmt(Parser* parser, ASTNode** nodeHandle) { consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of while clause"); declaration(parser, &thenPath); - emitASTNodePath(nodeHandle, AST_NODEPATH_WHILE, NULL, NULL, condition, thenPath, NULL); + emitASTNodeWhile(nodeHandle, condition, thenPath); } static void forStmt(Parser* parser, ASTNode** nodeHandle) { ASTNode* preClause = NULL; - ASTNode* postClause = NULL; ASTNode* condition = NULL; + ASTNode* postClause = NULL; ASTNode* thenPath = NULL; //read the clauses consume(parser, TOKEN_PAREN_LEFT, "Expected '(' at beginning of for clause"); - declaration(parser, &preClause); + + declaration(parser, &preClause); //allow defining variables in the pre-clause parsePrecedence(parser, &condition, PREC_TERNARY); - consume(parser, TOKEN_SEMICOLON, "Expected ';' after condition of for clause"); - parsePrecedence(parser, &postClause, PREC_ASSIGNMENT); + parsePrecedence(parser, &postClause, PREC_ASSIGNMENT); consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of for clause"); //read the path declaration(parser, &thenPath); - emitASTNodePath(nodeHandle, AST_NODEPATH_FOR, preClause, postClause, condition, thenPath, NULL); + emitASTNodeFor(nodeHandle, preClause, condition, postClause, thenPath); } static void breakStmt(Parser* parser, ASTNode** nodeHandle) { - emitASTNodePath(nodeHandle, AST_NODEPATH_BREAK, NULL, NULL, NULL, NULL, NULL); + emitASTNodeBreak(nodeHandle); consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of break statement"); } static void continueStmt(Parser* parser, ASTNode** nodeHandle) { - emitASTNodePath(nodeHandle, AST_NODEPATH_CONTINUE, NULL, NULL, NULL, NULL, NULL); + emitASTNodeContinue(nodeHandle); consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of continue statement"); } @@ -1287,13 +1281,13 @@ static void returnStmt(Parser* parser, ASTNode** nodeHandle) { parsePrecedence(parser, &node, PREC_TERNARY); returnValues->fnCollection.nodes[returnValues->fnCollection.count++] = *node; - FREE(ASTNode, node); + FREE(ASTNode, node); //free manually } while(match(parser, TOKEN_COMMA)); consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of return statement"); } - emitASTNodePath(nodeHandle, AST_NODEPATH_RETURN, NULL, NULL, NULL, returnValues, NULL); + emitASTNodeFnReturn(nodeHandle, returnValues); } static void importStmt(Parser* parser, ASTNode** nodeHandle) { @@ -1307,18 +1301,19 @@ static void importStmt(Parser* parser, ASTNode** nodeHandle) { } Literal idn = copyLiteral(node->atomic.literal); - freeNode(node); + freeASTNode(node); Literal alias = TO_NULL_LITERAL; if (match(parser, TOKEN_AS)) { + ASTNode* node = NULL; advance(parser); identifier(parser, &node); alias = copyLiteral(node->atomic.literal); - freeNode(node); + freeASTNode(node); } - emitASTNodeImport(nodeHandle, AST_NODEIMPORT, idn, alias); + emitASTNodeImport(nodeHandle, idn, alias); consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of import statement"); @@ -1337,18 +1332,19 @@ static void exportStmt(Parser* parser, ASTNode** nodeHandle) { } Literal idn = copyLiteral(node->atomic.literal); - freeNode(node); + freeASTNode(node); Literal alias = TO_NULL_LITERAL; if (match(parser, TOKEN_AS)) { + ASTNode* node; advance(parser); identifier(parser, &node); alias = copyLiteral(node->atomic.literal); - freeNode(node); + freeASTNode(node); } - emitASTNodeImport(nodeHandle, AST_NODEEXPORT, idn, alias); + emitASTNodeExport(nodeHandle, idn, alias); consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of export statement"); @@ -1516,8 +1512,7 @@ static Literal readTypeToLiteral(Parser* parser) { length = 256; error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long"); } - char* cpy = copyString(identifierToken.lexeme, length); - literal = _toIdentifierLiteral(cpy, strlen(cpy)); //BUGFIX: use this instead of the macro + literal = TO_IDENTIFIER_LITERAL(createRefStringLength(identifierToken.lexeme, length)); } break; @@ -1552,8 +1547,7 @@ static void varDecl(Parser* parser, ASTNode** nodeHandle) { error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long"); } - char* cpy = copyString(identifierToken.lexeme, length); - Literal identifier = _toIdentifierLiteral(cpy, strlen(cpy)); //BUGFIX: use this instead of the macro + Literal identifier = TO_IDENTIFIER_LITERAL(createRefStringLength(identifierToken.lexeme, length)); //read the type, if present Literal typeLiteral; @@ -1596,8 +1590,7 @@ static void fnDecl(Parser* parser, ASTNode** nodeHandle) { error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long"); } - char* cpy = copyString(identifierToken.lexeme, length); - Literal identifier = _toIdentifierLiteral(cpy, strlen(cpy)); //BUGFIX: use this instead of the macro + Literal identifier = TO_IDENTIFIER_LITERAL(createRefStringLength(identifierToken.lexeme, length)); //read the parameters and arity consume(parser, TOKEN_PAREN_LEFT, "Expected '(' after function identifier"); @@ -1623,8 +1616,7 @@ static void fnDecl(Parser* parser, ASTNode** nodeHandle) { error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long"); } - char* cpy = copyString(argIdentifierToken.lexeme, length); - Literal argIdentifier = _toIdentifierLiteral(cpy, strlen(cpy)); //BUGFIX: use this instead of the macro + Literal argIdentifier = TO_IDENTIFIER_LITERAL(createRefStringLength(argIdentifierToken.lexeme, length)); //set the type (array of any types) Literal argTypeLiteral = TO_TYPE_LITERAL(LITERAL_FUNCTION_ARG_REST, false); @@ -1659,9 +1651,7 @@ static void fnDecl(Parser* parser, ASTNode** nodeHandle) { error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long"); } - char* cpy = copyString(argIdentifierToken.lexeme, length); - - Literal argIdentifier = _toIdentifierLiteral(cpy, strlen(cpy)); //BUGFIX: use this instead of the macro + Literal argIdentifier = TO_IDENTIFIER_LITERAL(createRefStringLength(argIdentifierToken.lexeme, length)); //read optional type of the identifier Literal argTypeLiteral; @@ -1773,9 +1763,9 @@ ASTNode* scanParser(Parser* parser) { if (parser->panic) { synchronize(parser); //return an error node for this iteration - freeNode(node); + freeASTNode(node); node = ALLOCATE(ASTNode, 1); - node->type = AST_NODEERROR; + node->type = AST_NODE_ERROR; } return node; diff --git a/source/refstring.c b/source/refstring.c new file mode 100644 index 0000000..cbc74f1 --- /dev/null +++ b/source/refstring.c @@ -0,0 +1,103 @@ +#include "refstring.h" + +#include +#include + +//test variable sizes based on platform (safety) +#define STATIC_ASSERT(test_for_true) static_assert((test_for_true), "(" #test_for_true ") failed") + +STATIC_ASSERT(sizeof(RefString) == 12); +STATIC_ASSERT(sizeof(int) == 4); +STATIC_ASSERT(sizeof(char) == 1); + +//memory allocation +static RefStringAllocatorFn allocate; + +void setRefStringAllocatorFn(RefStringAllocatorFn allocator) { + allocate = allocator; +} + +//API +RefString* createRefString(char* cstring) { + int length = strlen(cstring); + + return createRefStringLength(cstring, length); +} + +RefString* createRefStringLength(char* cstring, int length) { + //allocate the memory area (including metadata space) + RefString* refString = (RefString*)allocate(NULL, 0, sizeof(int) * 2 + sizeof(char) * length + 1); + + //set the data + refString->refcount = 1; + refString->length = length; + strncpy(refString->data, cstring, refString->length); + + refString->data[refString->length] = '\0'; //string terminator + + return refString; +} + +void deleteRefString(RefString* refString) { + if (refString->refcount > 0) { + //decrement, then check + refString->refcount--; + if (refString->refcount <= 0) { + allocate(refString, sizeof(int) * 2 + sizeof(char) * refString->length + 1, 0); + } + } +} + +int countRefString(RefString* refString) { + return refString->refcount; +} + +int lengthRefString(RefString* refString) { + return refString->length; +} + +RefString* copyRefString(RefString* refString) { + refString->refcount++; + return refString; +} + +RefString* deepCopyRefString(RefString* refString) { + //deep copy, which can be modified immediately + RefString* newRefString = (RefString*)allocate(NULL, 0, sizeof(int) * 2 + refString->length + 1); + + memcpy(newRefString, refString, refString->length + 1); + + return newRefString; +} + +char* toCString(RefString* refString) { + return refString->data; +} + +bool equalsRefString(RefString* lhs, RefString* rhs) { + //same pointer + if (lhs == rhs) { + return true; + } + + //different length + if (lhs->length != rhs->length) { + return false; + } + + //same string + return strncmp(lhs->data, rhs->data, lhs->length) == 0; +} + +bool equalsRefStringCString(RefString* lhs, char* cstring) { + //get the rhs length + int length = strlen(cstring); + + //different length + if (lhs->length != length) { + return false; + } + + //same string + return strncmp(lhs->data, cstring, lhs->length) == 0; +} \ No newline at end of file diff --git a/source/refstring.h b/source/refstring.h new file mode 100644 index 0000000..a09ce8f --- /dev/null +++ b/source/refstring.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +//memory allocation hook +typedef void* (*RefStringAllocatorFn)(void* pointer, size_t oldSize, size_t newSize); +void setRefStringAllocatorFn(RefStringAllocatorFn); + +//the RefString structure +typedef struct RefString { + int refcount; + int length; + char data[1]; +} RefString; + +//API +RefString* createRefString(char* cstring); +RefString* createRefStringLength(char* cstring, int length); +void deleteRefString(RefString* refString); +int countRefString(RefString* refString); +int lengthRefString(RefString* refString); +RefString* copyRefString(RefString* refString); +RefString* deepCopyRefString(RefString* refString); +char* toCString(RefString* refString); +bool equalsRefString(RefString* lhs, RefString* rhs); +bool equalsRefStringCString(RefString* lhs, char* cstring); diff --git a/test/makefile b/test/makefile index 70f860a..afcd46c 100644 --- a/test/makefile +++ b/test/makefile @@ -3,10 +3,9 @@ CC=gcc IDIR +=. ../source ../repl CFLAGS +=$(addprefix -I,$(IDIR)) -g -Wall -W -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable LIBS += - ODIR = obj TARGETS = $(wildcard ../source/*.c) $(wildcard ../repl/lib_*.c) -TESTS = $(wildcard *.c) +TESTS = $(wildcard test_*.c) OBJ = $(addprefix $(ODIR)/,$(TARGETS:../source/%.c=%.o)) $(addprefix $(ODIR)/,$(TESTS:.c=.o)) .PRECIOUS: $(TESTS:%.c=../$(TOY_OUTDIR)/%.exe) diff --git a/test/test_ast_node.c b/test/test_ast_node.c index ef1ee37..5245362 100644 --- a/test/test_ast_node.c +++ b/test/test_ast_node.c @@ -4,20 +4,79 @@ #include "console_colors.h" #include +#include + +//lazy +#define ASSERT(test_for_true) if (!(test_for_true)) {\ + fprintf(stderr, ERROR "assert failed: %s\n" RESET, #test_for_true); \ + exit(-1); \ +} int main() { + //test literals { //test literals char* str = "foobar"; + Literal literal = TO_STRING_LITERAL(createRefString(str)); - Literal literal = TO_STRING_LITERAL(copyString(str, strlen(str)), strlen(str)); - - ASTNode* node; + //generate the node + ASTNode* node = NULL; emitASTNodeLiteral(&node, literal); + + //check node type + ASSERT(node->type == AST_NODE_LITERAL); + + //cleanup freeLiteral(literal); - freeNode(node); + freeASTNode(node); } + //test unary + { + //generate the child node + char* str = "foobar"; + Literal literal = TO_STRING_LITERAL(createRefString(str)); + ASTNode* childNode = NULL; + emitASTNodeLiteral(&childNode, literal); + + //generate the unary node + ASTNode* unary = NULL; + emitASTNodeUnary(&unary, OP_PRINT, childNode); + + //check node type + ASSERT(unary->type == AST_NODE_UNARY); + + //cleanup + freeLiteral(literal); + freeASTNode(unary); + } + + //test binary + { + //generate the child node + char* str = "foobar"; + Literal literal = TO_STRING_LITERAL(createRefString(str)); + ASTNode* nodeHandle = NULL; + emitASTNodeLiteral(&nodeHandle, literal); + + ASTNode* rhsChildNode = NULL; + emitASTNodeLiteral(&rhsChildNode, literal); + + //generate the unary node + emitASTNodeBinary(&nodeHandle, rhsChildNode, OP_PRINT); + + //check node type + ASSERT(nodeHandle->type == AST_NODE_BINARY); + ASSERT(nodeHandle->binary.opcode == OP_PRINT); + + //cleanup + freeLiteral(literal); + freeASTNode(nodeHandle); + } + + //TODO: more tests for other AST node types + + //test compounds { //test compound (dictionary) char* idn = "foobar"; @@ -27,8 +86,8 @@ int main() { ASTNode* left; ASTNode* right; - Literal identifier = TO_IDENTIFIER_LITERAL(copyString(idn, strlen(idn)), strlen(idn)); - Literal string = TO_STRING_LITERAL(copyString(str, strlen(str)), strlen(str)); + Literal identifier = TO_IDENTIFIER_LITERAL(createRefString(idn)); + Literal string = TO_STRING_LITERAL(createRefString(str)); emitASTNodeCompound(&dictionary, LITERAL_DICTIONARY); emitASTNodeLiteral(&left, identifier); @@ -46,7 +105,7 @@ int main() { setASTNodePair(&dictionary->compound.nodes[dictionary->compound.count++], left, right); //the real test - freeNode(dictionary); + freeASTNode(dictionary); freeLiteral(identifier); freeLiteral(string); } diff --git a/test/test_call_from_host.c b/test/test_call_from_host.c index 10d2115..dca9797 100644 --- a/test/test_call_from_host.c +++ b/test/test_call_from_host.c @@ -64,16 +64,16 @@ unsigned char* compileString(char* source, size_t* size) { ASTNode* node = scanParser(&parser); while(node != NULL) { //pack up and leave - if (node->type == AST_NODEERROR) { + if (node->type == AST_NODE_ERROR) { printf(ERROR "error node detected\n" RESET); - freeNode(node); + freeASTNode(node); freeCompiler(&compiler); freeParser(&parser); return NULL; } writeCompiler(&compiler, node); - freeNode(node); + freeASTNode(node); node = scanParser(&parser); } diff --git a/test/test_compiler.c b/test/test_compiler.c index a6945f0..d50f443 100644 --- a/test/test_compiler.c +++ b/test/test_compiler.c @@ -76,7 +76,7 @@ int main() { //cleanup FREE_ARRAY(unsigned char, bytecode, size); - freeNode(node); + freeASTNode(node); freeParser(&parser); freeCompiler(&compiler); } @@ -97,14 +97,14 @@ int main() { ASTNode* node = scanParser(&parser); while (node != NULL) { - if (node->type == AST_NODEERROR) { + if (node->type == AST_NODE_ERROR) { fprintf(stderr, ERROR "ERROR: Error node found" RESET); return -1; } //write writeCompiler(&compiler, node); - freeNode(node); + freeASTNode(node); node = scanParser(&parser); } diff --git a/test/test_interpreter.c b/test/test_interpreter.c index 3df0664..ea8f6a5 100644 --- a/test/test_interpreter.c +++ b/test/test_interpreter.c @@ -75,16 +75,16 @@ unsigned char* compileString(char* source, size_t* size) { ASTNode* node = scanParser(&parser); while(node != NULL) { //pack up and leave - if (node->type == AST_NODEERROR) { + if (node->type == AST_NODE_ERROR) { printf(ERROR "error node detected\n" RESET); - freeNode(node); + freeASTNode(node); freeCompiler(&compiler); freeParser(&parser); return NULL; } writeCompiler(&compiler, node); - freeNode(node); + freeASTNode(node); node = scanParser(&parser); } @@ -168,7 +168,7 @@ int main() { runInterpreter(&interpreter, bytecode, size); //cleanup - freeNode(node); + freeASTNode(node); freeParser(&parser); freeCompiler(&compiler); freeInterpreter(&interpreter); diff --git a/test/test_libraries.c b/test/test_libraries.c index f096a76..0fdf458 100644 --- a/test/test_libraries.c +++ b/test/test_libraries.c @@ -79,16 +79,16 @@ unsigned char* compileString(char* source, size_t* size) { ASTNode* node = scanParser(&parser); while(node != NULL) { //pack up and leave - if (node->type == AST_NODEERROR) { + if (node->type == AST_NODE_ERROR) { printf(ERROR "error node detected\n" RESET); - freeNode(node); + freeASTNode(node); freeCompiler(&compiler); freeParser(&parser); return NULL; } writeCompiler(&compiler, node); - freeNode(node); + freeASTNode(node); node = scanParser(&parser); } diff --git a/test/test_literal.c b/test/test_literal.c index 1c3e0b5..08c5df4 100644 --- a/test/test_literal.c +++ b/test/test_literal.c @@ -29,22 +29,18 @@ int main() { { //test string literals - char* buffer = ALLOCATE(char, 128); + char* buffer = "Hello world"; - snprintf(buffer, 128, "Hello world"); - - Literal literal = TO_STRING_LITERAL(buffer, 128); + Literal literal = TO_STRING_LITERAL(createRefString(buffer)); freeLiteral(literal); } { //test identifier literals - char* buffer = ALLOCATE(char, 128); + char buffer[] = "Hello world"; - snprintf(buffer, 128, "foobar"); - - Literal literal = TO_IDENTIFIER_LITERAL(buffer, 128); + Literal literal = TO_IDENTIFIER_LITERAL(createRefString(buffer)); freeLiteral(literal); } diff --git a/test/test_literal_array.c b/test/test_literal_array.c index 3b5ff97..9649b57 100644 --- a/test/test_literal_array.c +++ b/test/test_literal_array.c @@ -46,10 +46,10 @@ int main() { char* str_raw = "hello world"; char* idn_raw = "foobar"; - Literal string = TO_STRING_LITERAL(copyString(str_raw, strlen(str_raw)), strlen(str_raw)); - Literal identifier = TO_IDENTIFIER_LITERAL(copyString(idn_raw, strlen(idn_raw)), strlen(idn_raw)); + Literal string = TO_STRING_LITERAL(createRefString(str_raw)); + Literal identifier = TO_IDENTIFIER_LITERAL(createRefString(idn_raw)); - //[string, string] + //[string : string] Literal type = TO_TYPE_LITERAL(LITERAL_DICTIONARY, false); TYPE_PUSH_SUBTYPE(&type, TO_TYPE_LITERAL(LITERAL_STRING, false)); TYPE_PUSH_SUBTYPE(&type, TO_TYPE_LITERAL(LITERAL_STRING, false)); diff --git a/test/test_literal_dictionary.c b/test/test_literal_dictionary.c index 9f2c789..77f6f20 100644 --- a/test/test_literal_dictionary.c +++ b/test/test_literal_dictionary.c @@ -18,8 +18,8 @@ int main() { char* idn_raw = "foobar"; char* str_raw = "hello world"; - Literal identifier = TO_IDENTIFIER_LITERAL(copyString(idn_raw, strlen(idn_raw)), strlen(idn_raw)); - Literal string = TO_STRING_LITERAL(copyString(str_raw, strlen(str_raw)), strlen(str_raw)); + Literal identifier = TO_IDENTIFIER_LITERAL(createRefString(idn_raw)); + Literal string = TO_STRING_LITERAL(createRefString(str_raw)); LiteralDictionary dictionary; initLiteralDictionary(&dictionary); diff --git a/test/test_memory.c b/test/test_memory.c index bb1f15f..4ef503b 100644 --- a/test/test_memory.c +++ b/test/test_memory.c @@ -63,7 +63,7 @@ int main() { testMemoryAllocation(); //test the custom allocator - setAllocator(allocator); + setMemoryAllocator(allocator); testMemoryAllocation(); if (callCount != 8) { diff --git a/test/test_opaque_data_type.c b/test/test_opaque_data_type.c index cfcbf7a..2977bc9 100644 --- a/test/test_opaque_data_type.c +++ b/test/test_opaque_data_type.c @@ -62,16 +62,16 @@ unsigned char* compileString(char* source, size_t* size) { ASTNode* node = scanParser(&parser); while(node != NULL) { //pack up and leave - if (node->type == AST_NODEERROR) { + if (node->type == AST_NODE_ERROR) { printf(ERROR "error node detected\n" RESET); - freeNode(node); + freeASTNode(node); freeCompiler(&compiler); freeParser(&parser); return NULL; } writeCompiler(&compiler, node); - freeNode(node); + freeASTNode(node); node = scanParser(&parser); } diff --git a/test/test_parser.c b/test/test_parser.c index 24175e7..3ad9732 100644 --- a/test/test_parser.c +++ b/test/test_parser.c @@ -72,18 +72,18 @@ int main() { return -1; } - if (node->type != AST_NODEUNARY || node->unary.opcode != OP_PRINT) { - fprintf(stderr, ERROR "ERROR: ASTNode is not a print instruction" RESET); + if (node->type != AST_NODE_UNARY || node->unary.opcode != OP_PRINT) { + fprintf(stderr, ERROR "ERROR: ASTNode is not a unary print instruction" RESET); return -1; } - if (node->unary.child->type != AST_NODELITERAL || !IS_NULL(node->unary.child->atomic.literal)) { - fprintf(stderr, ERROR "ERROR: ASTNode to be printed is not a null value" RESET); + if (node->unary.child->type != AST_NODE_LITERAL || !IS_NULL(node->unary.child->atomic.literal)) { + fprintf(stderr, ERROR "ERROR: ASTNode to be printed is not a null literal" RESET); return -1; } //cleanup - freeNode(node); + freeASTNode(node); freeParser(&parser); } @@ -101,12 +101,12 @@ int main() { ASTNode* node = scanParser(&parser); while (node != NULL) { - if (node->type == AST_NODEERROR) { + if (node->type == AST_NODE_ERROR) { fprintf(stderr, ERROR "ERROR: Error node detected" RESET); return -1; } - freeNode(node); + freeASTNode(node); node = scanParser(&parser); } @@ -114,6 +114,7 @@ int main() { freeParser(&parser); free((void*)source); } + printf(NOTICE "All good\n" RESET); return 0; } diff --git a/test/test_scope.c b/test/test_scope.c index 765afbb..bdafcf5 100644 --- a/test/test_scope.c +++ b/test/test_scope.c @@ -16,7 +16,7 @@ int main() { //prerequisites char* idn_raw = "foobar"; - Literal identifier = TO_IDENTIFIER_LITERAL(copyString(idn_raw, strlen(idn_raw)), strlen(idn_raw)); + Literal identifier = TO_IDENTIFIER_LITERAL(createRefString(idn_raw)); Literal value = TO_INTEGER_LITERAL(42); Literal type = TO_TYPE_LITERAL(value.type, false); @@ -46,7 +46,7 @@ int main() { //prerequisites char* idn_raw = "foobar"; - Literal identifier = TO_IDENTIFIER_LITERAL(copyString(idn_raw, strlen(idn_raw)), strlen(idn_raw)); + Literal identifier = TO_IDENTIFIER_LITERAL(createRefString(idn_raw)); Literal type = TO_TYPE_LITERAL(LITERAL_INTEGER, false); //test declarations & assignments