diff --git a/src/fun.c b/src/fun.c index 86c14f9..e74a589 100644 --- a/src/fun.c +++ b/src/fun.c @@ -3,6 +3,15 @@ #include "vm.h" #include "parser.h" #include +#include +#include + +static int is_blank_line(const char *s) { + for (const char *p = s; *p; ++p) { + if (*p != ' ' && *p != '\t' && *p != '\r' && *p != '\n') return 0; + } + return 1; +} int main(int argc, char **argv) { VM vm; @@ -25,7 +34,63 @@ int main(int argc, char **argv) { bytecode_free(bc); return 0; } - + + // REPL mode + printf("Fun REPL. Type code and press Enter. Submit an empty line to run. Type 'exit' or 'quit' to leave.\n"); + char *buffer = NULL; + size_t bufcap = 0; + size_t buflen = 0; + + for (;;) { + fputs(buflen == 0 ? "fun> " : "... ", stdout); + fflush(stdout); + + char line[4096]; + if (!fgets(line, sizeof(line), stdin)) { + puts(""); + break; // EOF + } + + // Exit commands + if (buflen == 0 && (strcmp(line, "exit\n") == 0 || strcmp(line, "quit\n") == 0)) { + break; + } + + // Empty line -> compile and run accumulated buffer + if (is_blank_line(line)) { + if (buflen == 0) continue; // ignore extra empty lines + // Null-terminate + if (buflen + 1 >= bufcap) { + bufcap = buflen + 1; + buffer = (char*)realloc(buffer, bufcap); + } + buffer[buflen] = '\0'; + + Bytecode *bc = parse_string_to_bytecode(buffer); + if (bc) { + vm_run(&vm, bc); + vm_print_output(&vm); + vm_clear_output(&vm); + bytecode_free(bc); + } + // reset buffer + buflen = 0; + continue; + } + + // Append line to buffer + size_t linelen = strlen(line); + if (buflen + linelen + 1 > bufcap) { + size_t newcap = bufcap == 0 ? 1024 : bufcap * 2; + while (newcap < buflen + linelen + 1) newcap *= 2; + buffer = (char*)realloc(buffer, newcap); + bufcap = newcap; + } + memcpy(buffer + buflen, line, linelen); + buflen += linelen; + } + + free(buffer); return 0; } diff --git a/src/parser.c b/src/parser.c index 5d35ffb..e1634b9 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1202,4 +1202,28 @@ Bytecode *parse_file_to_bytecode(const char *path) { free(src); return bc; +} + +Bytecode *parse_string_to_bytecode(const char *source) { + if (!source) { + fprintf(stderr, "Error: null source provided\n"); + return NULL; + } + size_t len = strlen(source); + + /* reset error state */ + g_has_error = 0; + g_err_pos = 0; + g_err_msg[0] = '\0'; + + Bytecode *bc = compile_minimal(source, len); + + if (g_has_error) { + int line = 1, col = 1; + calc_line_col(source, len, g_err_pos, &line, &col); + fprintf(stderr, "Parse error :%d:%d: %s\n", line, col, g_err_msg); + if (bc) bytecode_free(bc); + return NULL; + } + return bc; } \ No newline at end of file diff --git a/src/parser.h b/src/parser.h index 312b9a1..65defff 100644 --- a/src/parser.h +++ b/src/parser.h @@ -16,4 +16,7 @@ Bytecode *parse_file_to_bytecode(const char *path); +/* Parse source provided as a single string buffer (for REPL, tests, etc.). */ +Bytecode *parse_string_to_bytecode(const char *source); + #endif