diff --git a/src/interpreter.c b/src/interpreter.c index 843d233..92dfe11 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -149,9 +149,63 @@ GroundValueType stringToValueType(char* in) { if (strcmp(in, "list") == 0) { return LIST; } + if (strcmp(in, "function") == 0) { + return FUNCTION; + } return CUSTOM; } +GroundDebugInstruction parseDebugInstruction(char* in) { + GroundDebugInstruction gdi; + size_t insize = strlen(in); + size_t spacepos = -1; + + for (size_t i = 0; i < insize; i++) { + if (in[i] == ' ') { + spacepos = i; + break; + } + } + + if (spacepos == -1) { + spacepos = insize; + } + + char* instruction = malloc(spacepos + 1); + if (!instruction) { + gdi.type = UNKNOWN; + gdi.arg = NULL; + return gdi; + } + strncpy(instruction, in, spacepos); + instruction[spacepos] = '\0'; + + if (strcmp(instruction, "dump") == 0) { + gdi.type = DUMP; + } else if (strcmp(instruction, "inspect") == 0) { + gdi.type = INSPECT; + } else if (strcmp(instruction, "eval") == 0) { + gdi.type = EVAL; + } else if (strcmp(instruction, "continue") == 0) { + gdi.type = CONTINUE; + } else if (strcmp(instruction, "exit") == 0) { + gdi.type = EXIT; + } else if (strcmp(instruction, "help") == 0) { + gdi.type = HELP; + } else { + gdi.type = UNKNOWN; + } + + size_t arglen = insize - spacepos; + gdi.arg = malloc(arglen + 1); + if (gdi.arg) { + strcpy(gdi.arg, in + spacepos + 1); + } + + free(instruction); + return gdi; +} + GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) { GroundLabel* labels = NULL; GroundVariable* variables = NULL; @@ -223,6 +277,92 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) { } } } + if (in->instructions[i].type == PAUSE) { + printf("Paused execution\n"); + printf("Previous instruction: "); + if (i > 0) { + printGroundInstruction(&in->instructions[i - 1]); + } + while (true) { + printf("\nprompt> "); + char buffer[256]; + if (fgets(buffer, sizeof(buffer), stdin) != NULL) { + buffer[strcspn(buffer, "\n")] = '\0'; + } else { + runtimeError(FIXME, "Failed to read input from console with fgets", NULL, -1); + } + GroundDebugInstruction gdi = parseDebugInstruction(buffer); + + bool shouldBreak = false; + switch (gdi.type) { + case CONTINUE: { + shouldBreak = true; + break; + } + case EXIT: { + exit(0); + break; + } + + case DUMP: { + if (scope.variables == NULL) { + printf("Can't access variables"); + break; + } + if (*scope.variables == NULL) { + printf("Can't access variables"); + break; + } + GroundVariable* entry; + GroundVariable* tmp; + GroundVariable* head = *scope.variables; + HASH_ITER(hh, head, entry, tmp) { + if (entry != NULL) { + printf("%s: ", entry->id); + printGroundValue(&entry->value); + printf("\n"); + } + } + break; + } + case INSPECT: { + printf("%s: ", gdi.arg); + GroundVariable* var = findVariable(*scope.variables, gdi.arg); + if (var == NULL) { + printf("(nothing)"); + } else { + printGroundValue(&var->value); + } + break; + } + case EVAL: { + GroundProgram program = parseFile(gdi.arg); + interpretGroundProgram(&program, &scope); + freeGroundProgram(&program); + break; + } + case HELP: { + printf("Ground Debugger Help\n"); + printf("Didn't mean to end up here? Type \"continue\" to escape this prompt.\n"); + printf("Commands:\n"); + printf(" continue: Continue execution of the program\n"); + printf(" exit: Stop execution early\n"); + printf(" dump: Shows all variables and their contents\n"); + printf(" inspect (variable): Shows the contents of a variable\n"); + printf(" eval (code): Runs Ground code in the current scope\n"); + printf(" help: Shows this help message"); + } + case UNKNOWN: { + printf("Unknown instruction (type \"help\" for help)"); + break; + } + } + if (shouldBreak) { + break; + } + } + continue; + } int ci = currentInstruction; GroundValue gv = interpretGroundInstruction(in->instructions[i], &scope); if (gv.type != NONE) { diff --git a/src/interpreter.h b/src/interpreter.h index 32b700f..62897f3 100644 --- a/src/interpreter.h +++ b/src/interpreter.h @@ -10,6 +10,10 @@ typedef enum GroundRuntimeError { ARG_TYPE_MISMATCH, TOO_FEW_ARGS, TOO_MANY_ARGS, UNKNOWN_LABEL, UNKNOWN_VARIABLE, LIST_ERROR, STRING_ERROR, MATH_ERROR, RETURN_TYPE_MISMATCH, FIXME } GroundRuntimeError; +typedef enum GroundDebugInstructionType { + DUMP, INSPECT, EVAL, CONTINUE, EXIT, HELP, UNKNOWN +} GroundDebugInstructionType; + typedef struct GroundLabel { char id[MAX_ID_LEN]; int lineNum; @@ -27,6 +31,11 @@ typedef struct GroundScope { GroundVariable** variables; } GroundScope; +typedef struct GroundDebugInstruction { + GroundDebugInstructionType type; + char* arg; +} GroundDebugInstruction; + GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope); GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scope); diff --git a/src/parser.c b/src/parser.c index d408645..3408340 100644 --- a/src/parser.c +++ b/src/parser.c @@ -169,6 +169,7 @@ static GroundInstType getInstructionType(const char* inst) { if (strcmp(inst, "init") == 0) return INIT; if (strcmp(inst, "use") == 0) return USE; if (strcmp(inst, "extern") == 0) return EXTERN; + if (strcmp(inst, "PAUSE") == 0) return PAUSE; fprintf(stderr, "Error: Unknown instruction: %s\n", inst); exit(EXIT_FAILURE); diff --git a/src/types.c b/src/types.c index 206ff08..ed7e41a 100644 --- a/src/types.c +++ b/src/types.c @@ -126,6 +126,10 @@ void printGroundValue(GroundValue* gv) { printf("]"); break; } + case FUNCTION: { + printf(""); + break; + } default: { printf("FIXME"); break; diff --git a/src/types.h b/src/types.h index d035e43..3b561e5 100644 --- a/src/types.h +++ b/src/types.h @@ -8,7 +8,7 @@ #include typedef enum GroundInstType { - IF, JUMP, END, INPUT, PRINT, PRINTLN, SET, GETTYPE, EXISTS, SETLIST, SETLISTAT, GETLISTAT, GETLISTSIZE, LISTAPPEND, GETSTRSIZE, GETSTRCHARAT, ADD, SUBTRACT, MULTIPLY, DIVIDE, EQUAL, INEQUAL, NOT, GREATER, LESSER, STOI, STOD, TOSTRING, FUN, RETURN, ENDFUN, PUSHARG, CALL, STRUCT, ENDSTRUCT, INIT, USE, EXTERN, CREATELABEL + IF, JUMP, END, INPUT, PRINT, PRINTLN, SET, GETTYPE, EXISTS, SETLIST, SETLISTAT, GETLISTAT, GETLISTSIZE, LISTAPPEND, GETSTRSIZE, GETSTRCHARAT, ADD, SUBTRACT, MULTIPLY, DIVIDE, EQUAL, INEQUAL, NOT, GREATER, LESSER, STOI, STOD, TOSTRING, FUN, RETURN, ENDFUN, PUSHARG, CALL, STRUCT, ENDSTRUCT, INIT, USE, EXTERN, CREATELABEL, PAUSE } GroundInstType; typedef enum GroundValueType { diff --git a/tests/function.grnd b/tests/function.grnd index 2d4f46d..fb1fc5d 100644 --- a/tests/function.grnd +++ b/tests/function.grnd @@ -1,5 +1,5 @@ -fun !dingus -string -int &x - return "dinglefart" +fun !dingus -string +return "dingus" endfun call !dingus &e diff --git a/tests/pause.grnd b/tests/pause.grnd new file mode 100644 index 0000000..7709eac --- /dev/null +++ b/tests/pause.grnd @@ -0,0 +1,8 @@ +fun !dingle -int + +endfun + +set &x 5 +set &y "dingle" +PAUSE +println "continuing"