From 3a4017cea55da5a54f6b45cfc370f34513e13b05 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Tue, 30 Aug 2022 12:09:11 +1000 Subject: [PATCH] Lots of runtime errors --- source/interpreter.c | 89 ++++++++++++++++++++++++++-- source/literal.c | 5 ++ source/literal_dictionary.c | 8 +-- source/scope.c | 10 +++- test/test_interpreter.c | 113 ++++++++++++++++++++++++++---------- 5 files changed, 184 insertions(+), 41 deletions(-) diff --git a/source/interpreter.c b/source/interpreter.c index b2a1f9d..bc54c5b 100644 --- a/source/interpreter.c +++ b/source/interpreter.c @@ -50,12 +50,14 @@ bool injectNativeFn(Interpreter* interpreter, char* name, NativeFn func) { bool parseIdentifierToValue(Interpreter* interpreter, Literal* literalPtr) { //this converts identifiers to values if (IS_IDENTIFIER(*literalPtr)) { + // Literal idn = *literalPtr; if (!getScopeVariable(interpreter->scope, *literalPtr, literalPtr)) { printf(ERROR "Error: Undeclared variable \"");; printLiteral(*literalPtr); printf("\"\n" RESET); return false; } + // freeLiteral(idn); } return true; @@ -417,19 +419,26 @@ static bool execAssert(Interpreter* interpreter) { return false; } + freeLiteral(lhs); + freeLiteral(rhs); + return true; } static bool execPrint(Interpreter* interpreter) { //print what is on top of the stack, then pop it Literal lit = popLiteralArray(&interpreter->stack); - if (!parseIdentifierToValue(interpreter, &lit)) { - return false; + + if (IS_IDENTIFIER(lit)) { + Literal idn = lit; + if (!parseIdentifierToValue(interpreter, &lit)) { + return false; + } } printLiteralCustom(lit, interpreter->printOutput); - // freeLiteral(lit); //it's a reference (to the dictionaries), so don't free it + freeLiteral(lit); return true; } @@ -460,6 +469,8 @@ static bool rawLiteral(Interpreter* interpreter) { pushLiteralArray(&interpreter->stack, lit); + freeLiteral(lit); + return true; } @@ -481,10 +492,16 @@ static bool execNegate(Interpreter* interpreter) { printf(ERROR "[internal] The interpreter can't negate that literal: "); printLiteral(lit); printf("\n" RESET); + + freeLiteral(lit); + return false; } pushLiteralArray(&interpreter->stack, lit); + + freeLiteral(lit); + return true; } @@ -503,10 +520,16 @@ static bool execInvert(Interpreter* interpreter) { printf(ERROR "[internal] The interpreter can't invert that literal: "); printLiteral(lit); printf("\n" RESET); + + freeLiteral(lit); + return false; } pushLiteralArray(&interpreter->stack, lit); + + freeLiteral(lit); + return true; } @@ -531,6 +554,8 @@ static bool execArithmetic(Interpreter* interpreter, Opcode opcode) { Literal literal = TO_STRING_LITERAL( copyString(buffer, strlen(buffer)), strlen(buffer) ); pushLiteralArray(&interpreter->stack, literal); freeLiteral(literal); + freeLiteral(lhs); + freeLiteral(rhs); return true; } @@ -630,6 +655,10 @@ static bool execArithmetic(Interpreter* interpreter, Opcode opcode) { printf(" and "); printLiteral(rhs); printf("\n" RESET); + + freeLiteral(lhs); + freeLiteral(rhs); + return false; } @@ -666,9 +695,17 @@ static bool execVarDecl(Interpreter* interpreter, bool lng) { printf(ERROR "ERROR: Incorrect type assigned to variable \""); printLiteral(identifier); printf("\"\n" RESET); + + freeLiteral(identifier); + freeLiteral(type); + freeLiteral(val); + return false; } + freeLiteral(type); + freeLiteral(val); + return true; } @@ -710,6 +747,8 @@ static bool execFnDecl(Interpreter* interpreter, bool lng) { return false; } + freeLiteral(type); + return true; } @@ -740,6 +779,9 @@ static bool execVarAssign(Interpreter* interpreter) { return false; } + freeLiteral(lhs); + freeLiteral(rhs); + return true; } @@ -752,6 +794,9 @@ static bool execVarArithmeticAssign(Interpreter* interpreter) { pushLiteralArray(&interpreter->stack, lhs); pushLiteralArray(&interpreter->stack, rhs); + freeLiteral(lhs); + freeLiteral(rhs); + return true; } @@ -767,6 +812,10 @@ static bool execValCast(Interpreter* interpreter) { if (IS_NULL(value)) { printf(ERROR "ERROR: Can't cast a null value\n" RESET); + + freeLiteral(value); + freeLiteral(type); + return false; } @@ -835,6 +884,11 @@ static bool execValCast(Interpreter* interpreter) { //leave the new value on the stack pushLiteralArray(&interpreter->stack, result); + + freeLiteral(result); + freeLiteral(value); + freeLiteral(type); + return true; } @@ -853,6 +907,9 @@ static bool execCompareEqual(Interpreter* interpreter, bool invert) { pushLiteralArray(&interpreter->stack, TO_BOOLEAN_LITERAL(result)); + freeLiteral(lhs); + freeLiteral(rhs); + return true; } @@ -868,6 +925,8 @@ static bool execCompareLess(Interpreter* interpreter, bool invert) { printf(ERROR "ERROR: Incorrect type in comparison, value \""); printLiteral(lhs); printf("\"\n" RESET); + freeLiteral(lhs); + freeLiteral(rhs); return false; } @@ -875,6 +934,8 @@ static bool execCompareLess(Interpreter* interpreter, bool invert) { printf(ERROR "ERROR: Incorrect type in comparison, value \""); printLiteral(rhs); printf("\"\n" RESET); + freeLiteral(lhs); + freeLiteral(rhs); return false; } @@ -898,6 +959,9 @@ static bool execCompareLess(Interpreter* interpreter, bool invert) { pushLiteralArray(&interpreter->stack, TO_BOOLEAN_LITERAL(result)); + freeLiteral(lhs); + freeLiteral(rhs); + return true; } @@ -913,6 +977,8 @@ static bool execCompareLessEqual(Interpreter* interpreter, bool invert) { printf(ERROR "ERROR: Incorrect type in comparison, value \""); printLiteral(lhs); printf("\"\n" RESET); + freeLiteral(lhs); + freeLiteral(rhs); return false; } @@ -920,6 +986,8 @@ static bool execCompareLessEqual(Interpreter* interpreter, bool invert) { printf(ERROR "ERROR: Incorrect type in comparison, value \""); printLiteral(rhs); printf("\"\n" RESET); + freeLiteral(lhs); + freeLiteral(rhs); return false; } @@ -943,6 +1011,9 @@ static bool execCompareLessEqual(Interpreter* interpreter, bool invert) { pushLiteralArray(&interpreter->stack, TO_BOOLEAN_LITERAL(result)); + freeLiteral(lhs); + freeLiteral(rhs); + return true; } @@ -960,6 +1031,9 @@ static bool execAnd(Interpreter* interpreter) { pushLiteralArray(&interpreter->stack, TO_BOOLEAN_LITERAL(false)); } + freeLiteral(lhs); + freeLiteral(rhs); + return true; } @@ -977,6 +1051,9 @@ static bool execOr(Interpreter* interpreter) { pushLiteralArray(&interpreter->stack, TO_BOOLEAN_LITERAL(false)); } + freeLiteral(lhs); + freeLiteral(rhs); + return true; } @@ -1018,6 +1095,8 @@ static bool execFalseJump(Interpreter* interpreter) { interpreter->count = target + interpreter->codeStart; } + freeLiteral(lit); + return true; } @@ -1042,6 +1121,7 @@ static bool execFnCall(Interpreter* interpreter) { if (!parseIdentifierToValue(interpreter, &func)) { freeLiteralArray(&arguments); + freeLiteral(identifier); return false; } @@ -1221,6 +1301,7 @@ static bool execFnReturn(Interpreter* interpreter) { Literal lit = popLiteralArray(&interpreter->stack); parseIdentifierToValue(interpreter, &lit); pushLiteralArray(&returns, lit); //reverses the order + freeLiteral(lit); } //and back again @@ -1291,7 +1372,7 @@ static void execInterpreter(Interpreter* interpreter) { case OP_VAR_MODULO_ASSIGN: execVarArithmeticAssign(interpreter); if (!execArithmetic(interpreter, opcode)) { - popLiteralArray(&interpreter->stack); + freeLiteral(popLiteralArray(&interpreter->stack)); return; } if (!execVarAssign(interpreter)) { diff --git a/source/literal.c b/source/literal.c index 740976e..27ddd95 100644 --- a/source/literal.c +++ b/source/literal.c @@ -3,6 +3,7 @@ #include "literal_array.h" #include "literal_dictionary.h" +#include "scope.h" #include "console_colors.h" @@ -46,6 +47,10 @@ void freeLiteral(Literal literal) { return; } + if (IS_FUNCTION(literal)) { + popScope(AS_FUNCTION(literal).scope); + } + if (IS_IDENTIFIER(literal)) { FREE_ARRAY(char, AS_IDENTIFIER(literal), literal.as.identifier.length); return; diff --git a/source/literal_dictionary.c b/source/literal_dictionary.c index aa77377..42b8455 100644 --- a/source/literal_dictionary.c +++ b/source/literal_dictionary.c @@ -136,7 +136,7 @@ void freeLiteralDictionary(LiteralDictionary* dictionary) { void setLiteralDictionary(LiteralDictionary* dictionary, Literal key, Literal value) { if (IS_NULL(key)) { - fprintf(stderr, ERROR "[internal] Dictionaries can't have null keys\n" RESET); + fprintf(stderr, ERROR "[internal] Dictionaries can't have null keys (get)\n" RESET); return; } @@ -150,14 +150,14 @@ void setLiteralDictionary(LiteralDictionary* dictionary, Literal key, Literal va Literal getLiteralDictionary(LiteralDictionary* dictionary, Literal key) { if (IS_NULL(key)) { - fprintf(stderr, ERROR "[internal] Dictionaries can't have null keys\n" RESET); + fprintf(stderr, ERROR "[internal] Dictionaries can't have null keys (set)\n" RESET); return TO_NULL_LITERAL; } _entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, hashLiteral(key), true); if (entry != NULL) { - return entry->value; + return copyLiteral(entry->value); } else { return TO_NULL_LITERAL; @@ -166,7 +166,7 @@ Literal getLiteralDictionary(LiteralDictionary* dictionary, Literal key) { void removeLiteralDictionary(LiteralDictionary* dictionary, Literal key) { if (IS_NULL(key)) { - fprintf(stderr, ERROR "[internal] Dictionaries can't have null keys\n" RESET); + fprintf(stderr, ERROR "[internal] Dictionaries can't have null keys (remove)\n" RESET); return; } diff --git a/source/scope.c b/source/scope.c index 9fc5638..d907292 100644 --- a/source/scope.c +++ b/source/scope.c @@ -142,11 +142,15 @@ Scope* copyScope(Scope* original) { //copy the contents of the dictionaries for (int i = 0; i < original->variables.capacity; i++) { - setLiteralDictionary(&scope->variables, original->variables.entries[i].key, original->variables.entries[i].value); + if (!IS_NULL(original->variables.entries[i].key)) { + setLiteralDictionary(&scope->variables, original->variables.entries[i].key, original->variables.entries[i].value); + } } - for (int i = 0; i < original->variables.capacity; i++) { - setLiteralDictionary(&scope->types, original->types.entries[i].key, original->types.entries[i].value); + for (int i = 0; i < original->types.capacity; i++) { + if (!IS_NULL(original->types.entries[i].key)) { + setLiteralDictionary(&scope->types, original->types.entries[i].key, original->types.entries[i].value); + } } return scope; diff --git a/test/test_interpreter.c b/test/test_interpreter.c index 7c89aac..29b95cf 100644 --- a/test/test_interpreter.c +++ b/test/test_interpreter.c @@ -45,6 +45,67 @@ char* readFile(char* path, size_t* fileSize) { return buffer; } +unsigned char* compileString(char* source, size_t* size) { + Lexer lexer; + Parser parser; + Compiler compiler; + + initLexer(&lexer, source); + initParser(&parser, &lexer); + initCompiler(&compiler); + + //run the parser until the end of the source + Node* node = scanParser(&parser); + while(node != NULL) { + //pack up and leave + if (node->type == NODE_ERROR) { + printf(ERROR "error node detected\n" RESET); + freeNode(node); + freeCompiler(&compiler); + freeParser(&parser); + return NULL; + } + + writeCompiler(&compiler, node); + freeNode(node); + node = scanParser(&parser); + } + + //get the bytecode dump + unsigned char* tb = collateCompiler(&compiler, (int*)(size)); + + //cleanup + freeCompiler(&compiler); + freeParser(&parser); + //no lexer to clean up + + //finally + return tb; +} + +void runBinary(unsigned char* tb, size_t size) { + Interpreter interpreter; + initInterpreter(&interpreter); + runInterpreter(&interpreter, tb, size); + freeInterpreter(&interpreter); +} + +void runSource(char* source) { + size_t size = 0; + unsigned char* tb = compileString(source, &size); + if (!tb) { + return; + } + runBinary(tb, size); +} + +void runSourceFile(char* fname) { + size_t size = 0; //not used + char* source = readFile(fname, &size); + runSource(source); + free((void*)source); +} + int main() { { //test init & free @@ -88,39 +149,31 @@ int main() { } { - //source - size_t sourceLength = 0; - char* source = readFile("sample_code.toy", &sourceLength); + //run each file in ../scripts/test/ + int count = 12; + char* filenames[] = { + "arithmetic.toy", + "casting.toy", + "comparisons.toy", + "functions.toy", + "jumps.toy", + "logicals.toy", + "long-array.toy", + "long-dictionary.toy", + "long-literals.toy", + "native-functions.toy", + "panic-within-functions.toy", + "types.toy" + }; - //test basic compilation & collation - Lexer lexer; - Parser parser; - Compiler compiler; - Interpreter interpreter; + for (int i = 0; i < count; i++) { + printf("Running %s\n", filenames[i]); - initLexer(&lexer, source); - initParser(&parser, &lexer); - initCompiler(&compiler); - initInterpreter(&interpreter); + char buffer[128]; + snprintf(buffer, 128, "../scripts/test/%s", filenames[i]); - Node* node = scanParser(&parser); - - //write - writeCompiler(&compiler, node); - - //collate - int size = 0; - unsigned char* bytecode = collateCompiler(&compiler, &size); - - //run - runInterpreter(&interpreter, bytecode, size); - - //cleanup - FREE_ARRAY(char, source, sourceLength); - freeNode(node); - freeParser(&parser); - freeCompiler(&compiler); - freeInterpreter(&interpreter); + runSourceFile(buffer); + } } printf(NOTICE "All good\n" RESET);