From 3a9a1921fe7a56cefe6650529a2572e9a8debc98 Mon Sep 17 00:00:00 2001 From: Felix Perktold Date: Tue, 23 Dec 2025 12:47:31 +0100 Subject: multiline support in REPL, tab completion for environment (no special forms yet) --- main.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 77 insertions(+), 9 deletions(-) (limited to 'main.c') diff --git a/main.c b/main.c index 5a7c893..3f851a8 100644 --- a/main.c +++ b/main.c @@ -8,7 +8,6 @@ env *global_env = NULL; - void eval_file(const char *filename) { FILE *f = fopen(filename, "r"); if (!f) { @@ -16,15 +15,63 @@ void eval_file(const char *filename) { return; } + int parens = 0; char line[1024]; + char buffer[4096] = ""; while (fgets(line, sizeof(line), f)) { if (*line == '\n' || *line == ';') continue; // skip empty lines or comments - yy_scan_string(line); - yyparse(); + for (char *c = line; *c != '\0'; c++) { + if (*c == '(') { + parens++; + } else if (*c == ')') { + parens--; + } + } + //append line to buffer + strcat(buffer, line); + strcat(buffer, "\n"); + if (parens <= 0) { + //if parens are balanced: parse + yy_scan_string(buffer); + yyparse(); + //reset buffer + buffer[0] = '\0'; + } } fclose(f); } +char *env_token_gen(const char *text, int state) { + static int len; + static env *nth_env; + if (state == 0) { + nth_env = global_env->next; + len = strlen(text); + } + + while (nth_env) { + const char *cur = nth_env->symbol; + nth_env = nth_env->next; + + if (strncmp(cur, text, len) == 0) { + return strdup(cur); + } + } + + return NULL; +} + +/* Dispatch function: called by readline to get all matches */ +char **my_completion(const char *text, int start, int end) { + /* Prevent default filename completion */ + rl_attempted_completion_over = 1; + return rl_completion_matches(text, env_token_gen); +} + +void init_readline() { + rl_attempted_completion_function = my_completion; +} + int main(int argc, char **argv) { // init global env global_env = env_create(NULL); @@ -46,13 +93,34 @@ int main(int argc, char **argv) { } // START REPL - char* line; - while ((line = readline("λ> ")) != NULL) { - if (*line) { - add_history(line); + init_readline(); + + int parens = 0; + char *line; + char buffer[4096] = ""; + char *prompt = "λ> "; + while ((line = readline(prompt)) != NULL) { + for (char *c = line; *c != '\0'; c++) { + if (*c == '(') { + parens++; + } else if (*c == ')') { + parens--; + } + } + //append line to buffer + strcat(buffer, line); + if (parens <= 0) { + //if parens are balanced parse + yy_scan_string(buffer); + yyparse(); + add_history(buffer); + //reset buffer and prompt string + buffer[0] = '\0'; + prompt = "λ> "; + } else { + strcat(buffer, "\n"); + prompt = " "; } - yy_scan_string(line); - yyparse(); free(line); } return 0; -- cgit v1.2.3