Added a simple REPL.
This commit is contained in:
parent
238a9a3bbe
commit
3a2afdea69
3 changed files with 93 additions and 1 deletions
67
src/fun.c
67
src/fun.c
|
|
@ -3,6 +3,15 @@
|
|||
#include "vm.h"
|
||||
#include "parser.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) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
24
src/parser.c
24
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 <input>:%d:%d: %s\n", line, col, g_err_msg);
|
||||
if (bc) bytecode_free(bc);
|
||||
return NULL;
|
||||
}
|
||||
return bc;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue