1
0
Fork 0
forked from fun/fun

Added a simple REPL.

This commit is contained in:
Johannes Findeisen 2025-09-14 18:42:23 +02:00
commit 3a2afdea69
3 changed files with 93 additions and 1 deletions

View file

@ -3,6 +3,15 @@
#include "vm.h" #include "vm.h"
#include "parser.h" #include "parser.h"
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <stdlib.h>
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) { int main(int argc, char **argv) {
VM vm; VM vm;
@ -25,7 +34,63 @@ int main(int argc, char **argv) {
bytecode_free(bc); bytecode_free(bc);
return 0; 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; return 0;
} }

View file

@ -1202,4 +1202,28 @@ Bytecode *parse_file_to_bytecode(const char *path) {
free(src); free(src);
return bc; 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 <input>:%d:%d: %s\n", line, col, g_err_msg);
if (bc) bytecode_free(bc);
return NULL;
}
return bc;
} }

View file

@ -16,4 +16,7 @@
Bytecode *parse_file_to_bytecode(const char *path); 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 #endif