diff --git a/repl/main.c b/repl/main.c index ef8e6a4..d88b9a9 100644 --- a/repl/main.c +++ b/repl/main.c @@ -138,6 +138,7 @@ typedef struct CmdLine { bool silentPrint; bool silentAssert; bool removeAssert; + bool verboseDebugPrint; } CmdLine; void usageCmdLine(int argc, const char* argv[]) { @@ -155,6 +156,7 @@ void helpCmdLine(int argc, const char* argv[]) { printf(" --silent-print\t\tSuppress output from the print keyword.\n"); printf(" --silent-assert\t\tSuppress output from the assert keyword.\n"); printf(" --remove-assert\t\tDo not include the assert statement in the bytecode.\n"); + printf(" -d, --verbose\t\tPrint debugging information about Toy's internals.\n"); } void versionCmdLine(int argc, const char* argv[]) { @@ -192,7 +194,8 @@ CmdLine parseCmdLine(int argc, const char* argv[]) { .infileLength = 0, .silentPrint = false, .silentAssert = false, - .removeAssert = false + .removeAssert = false, + .verboseDebugPrint = false, }; for (int i = 1; i < argc; i++) { @@ -242,6 +245,10 @@ CmdLine parseCmdLine(int argc, const char* argv[]) { cmd.removeAssert = true; } + else if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--verbose")) { + cmd.verboseDebugPrint = true; + } + else { cmd.error = true; } @@ -251,21 +258,11 @@ CmdLine parseCmdLine(int argc, const char* argv[]) { } //repl function -int repl(const char* filepath, CmdLine cmd) { +int repl(const char* filepath) { //output options - if (cmd.silentPrint) { - Toy_setPrintCallback(noOpCallback); - } - else { - Toy_setPrintCallback(printCallback); - } - - if (cmd.silentAssert) { - Toy_setAssertFailureCallback(silentExitCallback); - } - else { - Toy_setAssertFailureCallback(errorAndContinueCallback); - } + Toy_setPrintCallback(printCallback); + Toy_setErrorCallback(errorAndContinueCallback); + Toy_setAssertFailureCallback(errorAndContinueCallback); //vars to use char prompt[256]; @@ -304,7 +301,7 @@ int repl(const char* filepath, CmdLine cmd) { Toy_bindLexer(&lexer, inputBuffer); Toy_Parser parser; Toy_bindParser(&parser, &lexer); - Toy_configureParser(&parser, cmd.removeAssert); + Toy_configureParser(&parser, false); Toy_Ast* ast = Toy_scanParser(&bucket, &parser); //Ast is in the bucket, so it doesn't need to be freed //parsing error, retry @@ -336,11 +333,11 @@ int repl(const char* filepath, CmdLine cmd) { static void debugStackPrint(Toy_Stack* stack) { //DEBUG: if there's anything on the stack, print it if (stack->count > 0) { - printf("Stack Dump\n\ntype\tvalue\n"); + printf("Stack Dump\n-------------------------\ntype\tvalue\n"); for (int i = 0; i < stack->count; i++) { Toy_Value v = ((Toy_Value*)(stack + 1))[i]; - printf("%d\t", v.type); + printf("%s\t", Toy_private_getValueTypeAsCString(v.type)); switch(v.type) { case TOY_VALUE_NULL: @@ -396,7 +393,7 @@ static void debugStackPrint(Toy_Stack* stack) { static void debugScopePrint(Toy_Scope* scope, int depth) { //DEBUG: if there's anything in the scope, print it if (scope->table->count > 0) { - printf("Scope %d Dump\n\ntype\tname\tvalue\n", depth); + printf("Scope %d Dump\n-------------------------\ntype\tname\tvalue\n", depth); for (int i = 0; i < scope->table->capacity; i++) { if ( (TOY_VALUE_IS_STRING(scope->table->data[i].key) && TOY_VALUE_AS_STRING(scope->table->data[i].key)->type == TOY_STRING_NAME) == false) { continue; @@ -405,7 +402,7 @@ static void debugScopePrint(Toy_Scope* scope, int depth) { Toy_Value k = scope->table->data[i].key; Toy_Value v = scope->table->data[i].value; - printf("%d\t%s\t", v.type, TOY_VALUE_AS_STRING(k)->as.name.data); + printf("%s\t%s\t", Toy_private_getValueTypeAsCString(v.type), TOY_VALUE_AS_STRING(k)->as.name.data); switch(v.type) { case TOY_VALUE_NULL: @@ -540,8 +537,10 @@ int main(int argc, const char* argv[]) { Toy_runVM(&vm); //print the debug info - debugStackPrint(vm.stack); - debugScopePrint(vm.scope, 0); + if (cmd.verboseDebugPrint) { + debugStackPrint(vm.stack); + debugScopePrint(vm.scope, 0); + } //cleanup Toy_freeVM(&vm); @@ -549,7 +548,7 @@ int main(int argc, const char* argv[]) { free(source); } else { - repl(argv[0], cmd); + repl(argv[0]); } return 0; diff --git a/scripts/a.toy b/scripts/a.toy new file mode 100644 index 0000000..6a3aa62 --- /dev/null +++ b/scripts/a.toy @@ -0,0 +1,2 @@ + +1 + 2; \ No newline at end of file diff --git a/scripts/testificate.toy b/scripts/testificate.toy deleted file mode 100644 index b28b04f..0000000 --- a/scripts/testificate.toy +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/source/toy_scope.c b/source/toy_scope.c index 1aa2d7b..c3dd8de 100644 --- a/source/toy_scope.c +++ b/source/toy_scope.c @@ -173,7 +173,7 @@ Toy_Value Toy_accessScope(Toy_Scope* scope, Toy_String* key) { if (entryPtr == NULL) { char buffer[key->length + 256]; - sprintf(buffer, "Undefined variable: %s\n", key->as.name.data); //TODO: Toy_error + sprintf(buffer, "Undefined variable: %s\n", key->as.name.data); Toy_error(buffer); return TOY_VALUE_FROM_NULL(); } diff --git a/source/toy_value.c b/source/toy_value.c index 33c9f7d..b4f2d46 100644 --- a/source/toy_value.c +++ b/source/toy_value.c @@ -299,3 +299,22 @@ void Toy_stringifyValue(Toy_Value value, Toy_callbackType callback) { exit(-1); } } + +const char* Toy_private_getValueTypeAsCString(Toy_ValueType type) { + switch (type) { + case TOY_VALUE_NULL: return "null"; + case TOY_VALUE_BOOLEAN: return "bool"; + case TOY_VALUE_INTEGER: return "int"; + case TOY_VALUE_FLOAT: return "float"; + case TOY_VALUE_STRING: return "string"; + case TOY_VALUE_ARRAY: return "array"; + case TOY_VALUE_TABLE: return "table"; + case TOY_VALUE_FUNCTION: return "function"; + case TOY_VALUE_OPAQUE: return "opaque"; + case TOY_VALUE_TYPE: return "type"; + case TOY_VALUE_ANY: return "any"; + case TOY_VALUE_UNKNOWN: return "unknown"; + } + + return NULL; +} \ No newline at end of file diff --git a/source/toy_value.h b/source/toy_value.h index 61569d3..4cd4f3c 100644 --- a/source/toy_value.h +++ b/source/toy_value.h @@ -18,7 +18,7 @@ typedef enum Toy_ValueType { TOY_VALUE_OPAQUE, TOY_VALUE_TYPE, TOY_VALUE_ANY, - TOY_VALUE_UNKNOWN, //The correct value is unknown, but will be determined later + TOY_VALUE_UNKNOWN, //The correct type is unknown, but will be determined later } Toy_ValueType; //8 bytes in size @@ -71,3 +71,6 @@ TOY_API int Toy_compareValues(Toy_Value left, Toy_Value right); //convert the value to a string, then forward it to a callback TOY_API void Toy_stringifyValue(Toy_Value value, Toy_callbackType callback); + +//for debugging +TOY_API const char* Toy_private_getValueTypeAsCString(Toy_ValueType type); diff --git a/source/toy_vm.c b/source/toy_vm.c index b765f4b..0abbbc4 100644 --- a/source/toy_vm.c +++ b/source/toy_vm.c @@ -213,22 +213,30 @@ static void processArithmetic(Toy_VM* vm, Toy_OpcodeType opcode) { //check types if ((!TOY_VALUE_IS_INTEGER(left) && !TOY_VALUE_IS_FLOAT(left)) || (!TOY_VALUE_IS_INTEGER(right) && !TOY_VALUE_IS_FLOAT(right))) { - fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid types %d and %d passed to processArithmetic, exiting\n" TOY_CC_RESET, left.type, right.type); - exit(-1); + char buffer[256]; + snprintf(buffer, 256, "Invalid types '%s' and '%s' passed in arithmetic", Toy_private_getValueTypeAsCString(left.type), Toy_private_getValueTypeAsCString(right.type)); + Toy_error(buffer); + Toy_freeValue(left); + Toy_freeValue(right); + return; } //check for divide by zero if (opcode == TOY_OPCODE_DIVIDE || opcode == TOY_OPCODE_MODULO) { if ((TOY_VALUE_IS_INTEGER(right) && TOY_VALUE_AS_INTEGER(right) == 0) || (TOY_VALUE_IS_FLOAT(right) && TOY_VALUE_AS_FLOAT(right) == 0)) { - fprintf(stderr, TOY_CC_ERROR "ERROR: Can't divide by zero, exiting\n" TOY_CC_RESET); - exit(-1); + Toy_error("Can't divide or modulo by zero"); + Toy_freeValue(left); + Toy_freeValue(right); + return; } } //check for modulo by a float if (opcode == TOY_OPCODE_MODULO && TOY_VALUE_IS_FLOAT(right)) { - fprintf(stderr, TOY_CC_ERROR "ERROR: Can't modulo by a float, exiting\n" TOY_CC_RESET); //TODO: swap these with Toy_error so the repl doens't exit - exit(-1); + Toy_error("Can't modulo by a float"); + Toy_freeValue(left); + Toy_freeValue(right); + return; } //coerce ints into floats if needed @@ -293,8 +301,12 @@ static void processComparison(Toy_VM* vm, Toy_OpcodeType opcode) { } if (Toy_checkValuesAreComparable(left, right) == false) { - fprintf(stderr, TOY_CC_ERROR "ERROR: Can't compare value types %d and %d\n" TOY_CC_RESET, left.type, right.type); //TODO: typeToCString for error messages - exit(-1); + char buffer[256]; + snprintf(buffer, 256, "Can't compare value types '%s' and '%s'", Toy_private_getValueTypeAsCString(left.type), Toy_private_getValueTypeAsCString(right.type)); + Toy_error(buffer); + Toy_freeValue(left); + Toy_freeValue(right); + return; } //get the comparison @@ -470,7 +482,7 @@ static void processIndex(Toy_VM* vm) { } else { - fprintf(stderr, TOY_CC_ERROR "ERROR: Unknown value type %d found in processIndex, exiting\n" TOY_CC_RESET, value.type); + fprintf(stderr, TOY_CC_ERROR "ERROR: Unknown value type '%s' found in processIndex, exiting\n" TOY_CC_RESET, Toy_private_getValueTypeAsCString(value.type)); exit(-1); } @@ -481,6 +493,9 @@ static void processIndex(Toy_VM* vm) { static void process(Toy_VM* vm) { while(true) { + //prep by aligning to the 4-byte word + fixAlignment(vm); + Toy_OpcodeType opcode = READ_BYTE(vm); switch(opcode) { @@ -567,9 +582,6 @@ static void process(Toy_VM* vm) { fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid opcode %d found, exiting\n" TOY_CC_RESET, opcode); exit(-1); } - - //prepare for the next instruction - fixAlignment(vm); } } diff --git a/source/toy_vm.h b/source/toy_vm.h index a533253..1ada0ca 100644 --- a/source/toy_vm.h +++ b/source/toy_vm.h @@ -36,6 +36,8 @@ typedef struct Toy_VM { //easy access to memory Toy_Bucket* stringBucket; //stores the string literals Toy_Bucket* scopeBucket; //stores the scopes + + //TODO: panic flag } Toy_VM; TOY_API void Toy_initVM(Toy_VM* vm); diff --git a/tests/integrations/test_print.toy b/tests/integrations/test_print.toy index bd887dd..62aedf7 100644 --- a/tests/integrations/test_print.toy +++ b/tests/integrations/test_print.toy @@ -17,7 +17,3 @@ print "\tHello\nworld"; print "Hello world"[0,5]; print ("hello" .. "world")[2,6]; - -//TODO: in the repl, -s to supress output, or -d to print debugging info - -//TODO: the `assert` keyword will be useful for these