mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 23:04:08 +10:00
Added verbose debugging option to the REPL
This commit is contained in:
45
repl/main.c
45
repl/main.c
@@ -138,6 +138,7 @@ typedef struct CmdLine {
|
|||||||
bool silentPrint;
|
bool silentPrint;
|
||||||
bool silentAssert;
|
bool silentAssert;
|
||||||
bool removeAssert;
|
bool removeAssert;
|
||||||
|
bool verboseDebugPrint;
|
||||||
} CmdLine;
|
} CmdLine;
|
||||||
|
|
||||||
void usageCmdLine(int argc, const char* argv[]) {
|
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-print\t\tSuppress output from the print keyword.\n");
|
||||||
printf(" --silent-assert\t\tSuppress output from the assert 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(" --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[]) {
|
void versionCmdLine(int argc, const char* argv[]) {
|
||||||
@@ -192,7 +194,8 @@ CmdLine parseCmdLine(int argc, const char* argv[]) {
|
|||||||
.infileLength = 0,
|
.infileLength = 0,
|
||||||
.silentPrint = false,
|
.silentPrint = false,
|
||||||
.silentAssert = false,
|
.silentAssert = false,
|
||||||
.removeAssert = false
|
.removeAssert = false,
|
||||||
|
.verboseDebugPrint = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
@@ -242,6 +245,10 @@ CmdLine parseCmdLine(int argc, const char* argv[]) {
|
|||||||
cmd.removeAssert = true;
|
cmd.removeAssert = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--verbose")) {
|
||||||
|
cmd.verboseDebugPrint = true;
|
||||||
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
cmd.error = true;
|
cmd.error = true;
|
||||||
}
|
}
|
||||||
@@ -251,21 +258,11 @@ CmdLine parseCmdLine(int argc, const char* argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//repl function
|
//repl function
|
||||||
int repl(const char* filepath, CmdLine cmd) {
|
int repl(const char* filepath) {
|
||||||
//output options
|
//output options
|
||||||
if (cmd.silentPrint) {
|
Toy_setPrintCallback(printCallback);
|
||||||
Toy_setPrintCallback(noOpCallback);
|
Toy_setErrorCallback(errorAndContinueCallback);
|
||||||
}
|
Toy_setAssertFailureCallback(errorAndContinueCallback);
|
||||||
else {
|
|
||||||
Toy_setPrintCallback(printCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd.silentAssert) {
|
|
||||||
Toy_setAssertFailureCallback(silentExitCallback);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Toy_setAssertFailureCallback(errorAndContinueCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
//vars to use
|
//vars to use
|
||||||
char prompt[256];
|
char prompt[256];
|
||||||
@@ -304,7 +301,7 @@ int repl(const char* filepath, CmdLine cmd) {
|
|||||||
Toy_bindLexer(&lexer, inputBuffer);
|
Toy_bindLexer(&lexer, inputBuffer);
|
||||||
Toy_Parser parser;
|
Toy_Parser parser;
|
||||||
Toy_bindParser(&parser, &lexer);
|
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
|
Toy_Ast* ast = Toy_scanParser(&bucket, &parser); //Ast is in the bucket, so it doesn't need to be freed
|
||||||
|
|
||||||
//parsing error, retry
|
//parsing error, retry
|
||||||
@@ -336,11 +333,11 @@ int repl(const char* filepath, CmdLine cmd) {
|
|||||||
static void debugStackPrint(Toy_Stack* stack) {
|
static void debugStackPrint(Toy_Stack* stack) {
|
||||||
//DEBUG: if there's anything on the stack, print it
|
//DEBUG: if there's anything on the stack, print it
|
||||||
if (stack->count > 0) {
|
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++) {
|
for (int i = 0; i < stack->count; i++) {
|
||||||
Toy_Value v = ((Toy_Value*)(stack + 1))[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) {
|
switch(v.type) {
|
||||||
case TOY_VALUE_NULL:
|
case TOY_VALUE_NULL:
|
||||||
@@ -396,7 +393,7 @@ static void debugStackPrint(Toy_Stack* stack) {
|
|||||||
static void debugScopePrint(Toy_Scope* scope, int depth) {
|
static void debugScopePrint(Toy_Scope* scope, int depth) {
|
||||||
//DEBUG: if there's anything in the scope, print it
|
//DEBUG: if there's anything in the scope, print it
|
||||||
if (scope->table->count > 0) {
|
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++) {
|
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) {
|
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;
|
continue;
|
||||||
@@ -405,7 +402,7 @@ static void debugScopePrint(Toy_Scope* scope, int depth) {
|
|||||||
Toy_Value k = scope->table->data[i].key;
|
Toy_Value k = scope->table->data[i].key;
|
||||||
Toy_Value v = scope->table->data[i].value;
|
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) {
|
switch(v.type) {
|
||||||
case TOY_VALUE_NULL:
|
case TOY_VALUE_NULL:
|
||||||
@@ -540,8 +537,10 @@ int main(int argc, const char* argv[]) {
|
|||||||
Toy_runVM(&vm);
|
Toy_runVM(&vm);
|
||||||
|
|
||||||
//print the debug info
|
//print the debug info
|
||||||
debugStackPrint(vm.stack);
|
if (cmd.verboseDebugPrint) {
|
||||||
debugScopePrint(vm.scope, 0);
|
debugStackPrint(vm.stack);
|
||||||
|
debugScopePrint(vm.scope, 0);
|
||||||
|
}
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
Toy_freeVM(&vm);
|
Toy_freeVM(&vm);
|
||||||
@@ -549,7 +548,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
free(source);
|
free(source);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
repl(argv[0], cmd);
|
repl(argv[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
2
scripts/a.toy
Normal file
2
scripts/a.toy
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
1 + 2;
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -173,7 +173,7 @@ Toy_Value Toy_accessScope(Toy_Scope* scope, Toy_String* key) {
|
|||||||
|
|
||||||
if (entryPtr == NULL) {
|
if (entryPtr == NULL) {
|
||||||
char buffer[key->length + 256];
|
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);
|
Toy_error(buffer);
|
||||||
return TOY_VALUE_FROM_NULL();
|
return TOY_VALUE_FROM_NULL();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -299,3 +299,22 @@ void Toy_stringifyValue(Toy_Value value, Toy_callbackType callback) {
|
|||||||
exit(-1);
|
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;
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@ typedef enum Toy_ValueType {
|
|||||||
TOY_VALUE_OPAQUE,
|
TOY_VALUE_OPAQUE,
|
||||||
TOY_VALUE_TYPE,
|
TOY_VALUE_TYPE,
|
||||||
TOY_VALUE_ANY,
|
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;
|
} Toy_ValueType;
|
||||||
|
|
||||||
//8 bytes in size
|
//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
|
//convert the value to a string, then forward it to a callback
|
||||||
TOY_API void Toy_stringifyValue(Toy_Value value, Toy_callbackType callback);
|
TOY_API void Toy_stringifyValue(Toy_Value value, Toy_callbackType callback);
|
||||||
|
|
||||||
|
//for debugging
|
||||||
|
TOY_API const char* Toy_private_getValueTypeAsCString(Toy_ValueType type);
|
||||||
|
|||||||
@@ -213,22 +213,30 @@ static void processArithmetic(Toy_VM* vm, Toy_OpcodeType opcode) {
|
|||||||
|
|
||||||
//check types
|
//check types
|
||||||
if ((!TOY_VALUE_IS_INTEGER(left) && !TOY_VALUE_IS_FLOAT(left)) || (!TOY_VALUE_IS_INTEGER(right) && !TOY_VALUE_IS_FLOAT(right))) {
|
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);
|
char buffer[256];
|
||||||
exit(-1);
|
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
|
//check for divide by zero
|
||||||
if (opcode == TOY_OPCODE_DIVIDE || opcode == TOY_OPCODE_MODULO) {
|
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)) {
|
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);
|
Toy_error("Can't divide or modulo by zero");
|
||||||
exit(-1);
|
Toy_freeValue(left);
|
||||||
|
Toy_freeValue(right);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//check for modulo by a float
|
//check for modulo by a float
|
||||||
if (opcode == TOY_OPCODE_MODULO && TOY_VALUE_IS_FLOAT(right)) {
|
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
|
Toy_error("Can't modulo by a float");
|
||||||
exit(-1);
|
Toy_freeValue(left);
|
||||||
|
Toy_freeValue(right);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//coerce ints into floats if needed
|
//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) {
|
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
|
char buffer[256];
|
||||||
exit(-1);
|
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
|
//get the comparison
|
||||||
@@ -470,7 +482,7 @@ static void processIndex(Toy_VM* vm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
else {
|
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);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -481,6 +493,9 @@ static void processIndex(Toy_VM* vm) {
|
|||||||
|
|
||||||
static void process(Toy_VM* vm) {
|
static void process(Toy_VM* vm) {
|
||||||
while(true) {
|
while(true) {
|
||||||
|
//prep by aligning to the 4-byte word
|
||||||
|
fixAlignment(vm);
|
||||||
|
|
||||||
Toy_OpcodeType opcode = READ_BYTE(vm);
|
Toy_OpcodeType opcode = READ_BYTE(vm);
|
||||||
|
|
||||||
switch(opcode) {
|
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);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid opcode %d found, exiting\n" TOY_CC_RESET, opcode);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//prepare for the next instruction
|
|
||||||
fixAlignment(vm);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ typedef struct Toy_VM {
|
|||||||
//easy access to memory
|
//easy access to memory
|
||||||
Toy_Bucket* stringBucket; //stores the string literals
|
Toy_Bucket* stringBucket; //stores the string literals
|
||||||
Toy_Bucket* scopeBucket; //stores the scopes
|
Toy_Bucket* scopeBucket; //stores the scopes
|
||||||
|
|
||||||
|
//TODO: panic flag
|
||||||
} Toy_VM;
|
} Toy_VM;
|
||||||
|
|
||||||
TOY_API void Toy_initVM(Toy_VM* vm);
|
TOY_API void Toy_initVM(Toy_VM* vm);
|
||||||
|
|||||||
@@ -17,7 +17,3 @@ print "\tHello\nworld";
|
|||||||
print "Hello world"[0,5];
|
print "Hello world"[0,5];
|
||||||
|
|
||||||
print ("hello" .. "world")[2,6];
|
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
|
|
||||||
|
|||||||
Reference in New Issue
Block a user