#include #include #include #include #include // // Config. // #ifdef DEBUG #define DEBUG_TRACE_EXECUTION #endif #include "vm.h" #include "errors.c" #include "chunk.c" #include "objects.c" #include "compiler.h" #include "ops.h" #include "debug.h" #include "lexer.c" #include "read_line.c" #include "string_view.c" static VM vm; void init(void) { vm_init(&vm); } void halt(void) { vm_free(&vm); } void process_source(const StringView *source) { // Read tokens. Token *tokens = tokenize(source); if (errors_n != 0) { array_free(tokens); return; } // Compile chunk. Chunk *main = compile(tokens); if (errors_n != 0) { chunk_free(main); array_free(tokens); return; } #ifdef DEBUG disassemble_chunk(main); #endif // Interpret chunk. Object main_proc = make_lambda(main); CallFrame frame = (CallFrame){ .closure = main_proc.closure, }; array_push(vm.frames, frame); vm_interpret(&vm); // Free resources. chunk_free(main); array_free(tokens); } #define REPL_PROMPT "bdl> " void run_repl(void) { printf("BDL REPL (Press Ctrl-D or Ctrl-C to exit)\n"); while (true) { printf(REPL_PROMPT); StringView sv = read_line(); if (sv.start == NULL) { return; } process_source(&sv); // Check if there were any errors. if (errors_n != 0 && !supress_errors) { for (size_t i = 0; i < errors_n; i++) { Error err = errors[i]; for (size_t j = 0; j < err.col + sizeof(REPL_PROMPT) - 2; j++) { putchar(' '); } printf("|\n"); for (size_t j = 0; j < err.col + sizeof(REPL_PROMPT) - 2; j++) { putchar(' '); } printf("%s\n", error_msgs[err.value]); } errors_n = 0; continue; } } } void run_file(char *file_name) { FILE *file = fopen(file_name, "r"); if (!file) { fprintf(stderr, "error: couldn't open input file: %s\n", file_name); exit(EXIT_FAILURE); } // Read entire file into memory. fseek(file, 0, SEEK_END); size_t file_size = ftell(file); fseek(file, 0, SEEK_SET); char *source = malloc(file_size + 1); fread(source, 1, file_size, file); source[file_size] = 0; StringView sv = (StringView){ .start = source, .n = file_size, }; process_source(&sv); // Check if there were any errors. if (errors_n != 0 && !supress_errors) { report_errors(file_name); } free(source); fclose(file); } #define STDIN_BUF_CAP 16 void run_stdin(void) { size_t buf_size = 0; char *source = NULL; array_init(source, STDIN_BUF_CAP); char c; while ((c = getchar()) != EOF) { array_push(source, c); buf_size++; } StringView sv = (StringView){ .start = source, .n = buf_size, }; process_source(&sv); // Check if there were any errors. if (errors_n != 0 && !supress_errors) { report_errors("stdin"); } array_free(source); } #ifndef BIN_NAME #define BIN_NAME "bdl" #endif void print_usage(void) { printf("Usage: %s [options] \n", BIN_NAME); printf("\n"); printf("\t-i\tInteractive mode (REPL).\n"); printf("\n"); } int main(int argc, char *argv[]) { init(); int option; while ((option = getopt(argc, argv, "i")) != -1) { switch (option) { case 'i': { // Interactive mode. run_repl(); halt(); return EXIT_SUCCESS; } break; default: { print_usage(); return EXIT_FAILURE; } break; } } // Run from stdin. if (optind == argc) { run_stdin(); halt(); return EXIT_SUCCESS; } // Run from file. while (optind < argc) { char *file_name = argv[optind]; run_file(file_name); optind++; } halt(); return EXIT_SUCCESS; }