From 2625019add3d16d3ee5d210bcebdd999d3b0cc32 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Thu, 21 Oct 2021 18:23:18 +0200 Subject: Change environments to be a hash table --- src/bootstrap/main.c | 553 ++++++++++++++++++++++++--------------------------- 1 file changed, 257 insertions(+), 296 deletions(-) (limited to 'src/bootstrap/main.c') diff --git a/src/bootstrap/main.c b/src/bootstrap/main.c index 1cb7c82..a5888fd 100755 --- a/src/bootstrap/main.c +++ b/src/bootstrap/main.c @@ -21,307 +21,268 @@ #include "read_line.c" #include "string_view.c" -int main(void) { - // Initialize GC. +void +init(void) { + // Initialize garbage collector. gc_init(); - // Initialize key-value objects. - Object *k1 = MAKE_SYM("Alice"); - Object *k2 = MAKE_SYM("Bob"); - Object *k3 = MAKE_SYM("Dog"); - Object *v1 = make_fixnum(10); - Object *v2 = make_fixnum(49); - Object *v3 = make_fixnum(333); - - // Initialize hash table. - HashTable *table = ht_init(); - - // Add some key-value pairs. - ht_insert(table, k1, v1); - ht_insert(table, k2, v2); - ht_insert(table, k3, v3); - - // Test lookups. - Object *alice_val = ht_lookup(table, k1); - Object *bob_val = ht_lookup(table, MAKE_SYM("Bob")); - Object *dog_val = ht_lookup(table, k3); - - if (v1 == alice_val) { - printf("Alice match!\n"); + // Initialize singletons. + obj_nil = alloc_object(OBJ_TYPE_NIL); + obj_true = alloc_object(OBJ_TYPE_BOOL); + obj_false = alloc_object(OBJ_TYPE_BOOL); + obj_err = alloc_object(OBJ_TYPE_ERR); + obj_quote = make_symbol((StringView){"quote", 5}); + proc_if = alloc_object(OBJ_TYPE_ERR); + push_root(obj_nil); + push_root(obj_true); + push_root(obj_false); + push_root(obj_err); + push_root(obj_quote); + push_root(proc_if); + + // Global environment. + global_env = env_create(NULL); + // TODO: make sure we create symbols and strings only once (interning + // strings?) + push_active_env(global_env); + + // Primitive symbols. + MAKE_ENV_VAR(global_env, "else", obj_true); + MAKE_ENV_VAR(global_env, "nil", obj_nil); + MAKE_ENV_VAR(global_env, "if", proc_if); + + // Primitive procedures. + MAKE_ENV_PROC(global_env, "eval", proc_eval); + MAKE_ENV_PROC(global_env, "quote", proc_quote); + MAKE_ENV_PROC(global_env, "car", proc_car); + MAKE_ENV_PROC(global_env, "cdr", proc_cdr); + MAKE_ENV_PROC(global_env, "cons", proc_cons); + MAKE_ENV_PROC(global_env, "list", proc_list); + MAKE_ENV_PROC(global_env, "+", proc_sum); + MAKE_ENV_PROC(global_env, "-", proc_sub); + MAKE_ENV_PROC(global_env, "*", proc_mul); + MAKE_ENV_PROC(global_env, "/", proc_div); + MAKE_ENV_PROC(global_env, "%", proc_mod); + MAKE_ENV_PROC(global_env, "print", proc_print); + MAKE_ENV_PROC(global_env, "display", proc_display); + MAKE_ENV_PROC(global_env, "newline", proc_newline); + MAKE_ENV_PROC(global_env, "boolean?", proc_is_boolean); + MAKE_ENV_PROC(global_env, "nil?", proc_is_nil); + MAKE_ENV_PROC(global_env, "symbol?", proc_is_symbol); + MAKE_ENV_PROC(global_env, "string?", proc_is_string); + MAKE_ENV_PROC(global_env, "fixnum?", proc_is_fixnum); + MAKE_ENV_PROC(global_env, "pair?", proc_is_pair); + MAKE_ENV_PROC(global_env, "procedure?", proc_is_procedure); + MAKE_ENV_PROC(global_env, "error?", proc_is_error); + MAKE_ENV_PROC(global_env, "not", proc_not); + MAKE_ENV_PROC(global_env, "and", proc_and); + MAKE_ENV_PROC(global_env, "or", proc_or); + MAKE_ENV_PROC(global_env, "cond", proc_cond); + MAKE_ENV_PROC(global_env, "<", proc_num_less_than); + MAKE_ENV_PROC(global_env, "<=", proc_num_lesseq_than); + MAKE_ENV_PROC(global_env, ">", proc_num_greater_than); + MAKE_ENV_PROC(global_env, ">=", proc_num_greatereq_than); + MAKE_ENV_PROC(global_env, "=", proc_num_equal); + MAKE_ENV_PROC(global_env, "eq?", proc_equal); + MAKE_ENV_PROC(global_env, "def", proc_define); + MAKE_ENV_PROC(global_env, "set!", proc_set); + MAKE_ENV_PROC(global_env, "lambda", proc_lambda); + MAKE_ENV_PROC(global_env, "fun", proc_fun); + + // Runtime procedures. + MAKE_ENV_PROC(global_env, "supress-errors", proc_supress_errors); +} + +void +process_source(const StringView *source) { + Token *tokens = tokenize(source); + if (errors_n != 0) { + if (tokens != NULL) { + array_free(tokens); + } + return; + } + + Visitor visitor = (Visitor){ + .tokens = tokens, + .current = 0, + }; + while (has_next_token(&visitor) && peek_token(&visitor).type != TOKEN_EOF) { + // Check the root node stack size before parsing + size_t root_stack_size = array_size(gc.roots); + Object *root = parse_tree(&visitor); + array_head(gc.roots)->size = root_stack_size; + if (root == obj_err || errors_n != 0) { + break; + } + push_root(root); + + Object *result = eval(global_env, root); + if (result != obj_nil) { + display(result); + printf("\n"); + } + pop_root(); } - if (v2 == bob_val) { - printf("Bob match!\n"); + + if (tokens != NULL) { + 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) { + for (size_t i = 0; i < errors_n; i++) { + Error err = errors[i]; + fprintf(stderr, "%s", file_name); + if (err.line != 0) { + fprintf(stderr, ":%ld:%ld", err.line, err.col); + } + fprintf(stderr, ": %s\n", error_msgs[err.value]); + } + errors_n = 0; + } + + 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++; } - if (v3 == dog_val) { - printf("Dog match!\n"); + + StringView sv = (StringView){ + .start = source, + .n = buf_size, + }; + + 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]; + fprintf(stderr, "stdin"); + if (err.line != 0) { + fprintf(stderr, ":%ld:%ld", err.line, err.col); + } + fprintf(stderr, ": %s\n", error_msgs[err.value]); + } + errors_n = 0; } - ht_debug(table); - return 0; + 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"); } -// void -// init(void) { -// // Initialize garbage collector. -// gc_init(); - -// // Initialize singletons. -// obj_nil = alloc_object(OBJ_TYPE_NIL); -// obj_true = alloc_object(OBJ_TYPE_BOOL); -// obj_false = alloc_object(OBJ_TYPE_BOOL); -// obj_err = alloc_object(OBJ_TYPE_ERR); -// obj_quote = make_symbol((StringView){"quote", 5}); -// proc_if = alloc_object(OBJ_TYPE_ERR); -// push_root(obj_nil); -// push_root(obj_true); -// push_root(obj_false); -// push_root(obj_err); -// push_root(obj_quote); -// push_root(proc_if); - -// // Global environment. -// global_env = env_create(NULL); -// // TODO: make sure we create symbols and strings only once (interning -// // strings?) -// push_active_env(global_env); - -// // Primitive symbols. -// MAKE_ENV_VAR(global_env, "else", obj_true); -// MAKE_ENV_VAR(global_env, "nil", obj_nil); -// MAKE_ENV_VAR(global_env, "if", proc_if); - -// // Primitive procedures. -// MAKE_ENV_PROC(global_env, "eval", proc_eval); -// MAKE_ENV_PROC(global_env, "quote", proc_quote); -// MAKE_ENV_PROC(global_env, "car", proc_car); -// MAKE_ENV_PROC(global_env, "cdr", proc_cdr); -// MAKE_ENV_PROC(global_env, "cons", proc_cons); -// MAKE_ENV_PROC(global_env, "list", proc_list); -// MAKE_ENV_PROC(global_env, "+", proc_sum); -// MAKE_ENV_PROC(global_env, "-", proc_sub); -// MAKE_ENV_PROC(global_env, "*", proc_mul); -// MAKE_ENV_PROC(global_env, "/", proc_div); -// MAKE_ENV_PROC(global_env, "%", proc_mod); -// MAKE_ENV_PROC(global_env, "print", proc_print); -// MAKE_ENV_PROC(global_env, "display", proc_display); -// MAKE_ENV_PROC(global_env, "newline", proc_newline); -// MAKE_ENV_PROC(global_env, "boolean?", proc_is_boolean); -// MAKE_ENV_PROC(global_env, "nil?", proc_is_nil); -// MAKE_ENV_PROC(global_env, "symbol?", proc_is_symbol); -// MAKE_ENV_PROC(global_env, "string?", proc_is_string); -// MAKE_ENV_PROC(global_env, "fixnum?", proc_is_fixnum); -// MAKE_ENV_PROC(global_env, "pair?", proc_is_pair); -// MAKE_ENV_PROC(global_env, "procedure?", proc_is_procedure); -// MAKE_ENV_PROC(global_env, "error?", proc_is_error); -// MAKE_ENV_PROC(global_env, "not", proc_not); -// MAKE_ENV_PROC(global_env, "and", proc_and); -// MAKE_ENV_PROC(global_env, "or", proc_or); -// MAKE_ENV_PROC(global_env, "cond", proc_cond); -// MAKE_ENV_PROC(global_env, "<", proc_num_less_than); -// MAKE_ENV_PROC(global_env, "<=", proc_num_lesseq_than); -// MAKE_ENV_PROC(global_env, ">", proc_num_greater_than); -// MAKE_ENV_PROC(global_env, ">=", proc_num_greatereq_than); -// MAKE_ENV_PROC(global_env, "=", proc_num_equal); -// MAKE_ENV_PROC(global_env, "eq?", proc_equal); -// MAKE_ENV_PROC(global_env, "def", proc_define); -// MAKE_ENV_PROC(global_env, "set!", proc_set); -// MAKE_ENV_PROC(global_env, "lambda", proc_lambda); -// MAKE_ENV_PROC(global_env, "fun", proc_fun); - -// // Runtime procedures. -// MAKE_ENV_PROC(global_env, "supress-errors", proc_supress_errors); -// } - -// void -// process_source(const StringView *source) { -// Token *tokens = tokenize(source); -// if (errors_n != 0) { -// if (tokens != NULL) { -// array_free(tokens); -// } -// return; -// } - -// Visitor visitor = (Visitor){ -// .tokens = tokens, -// .current = 0, -// }; -// while (has_next_token(&visitor) && peek_token(&visitor).type != TOKEN_EOF) { -// // Check the root node stack size before parsing -// size_t root_stack_size = array_size(gc.roots); -// Object *root = parse_tree(&visitor); -// array_head(gc.roots)->size = root_stack_size; -// if (root == obj_err || errors_n != 0) { -// break; -// } -// push_root(root); - -// Object *result = eval(global_env, root); -// if (result != obj_nil) { -// display(result); -// printf("\n"); -// } -// pop_root(); -// } - -// if (tokens != NULL) { -// 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) { -// for (size_t i = 0; i < errors_n; i++) { -// Error err = errors[i]; -// fprintf(stderr, "%s", file_name); -// if (err.line != 0) { -// fprintf(stderr, ":%ld:%ld", err.line, err.col); -// } -// fprintf(stderr, ": %s\n", error_msgs[err.value]); -// } -// errors_n = 0; -// } - -// 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) { -// for (size_t i = 0; i < errors_n; i++) { -// Error err = errors[i]; -// fprintf(stderr, "stdin"); -// if (err.line != 0) { -// fprintf(stderr, ":%ld:%ld", err.line, err.col); -// } -// fprintf(stderr, ": %s\n", error_msgs[err.value]); -// } -// errors_n = 0; -// } - -// 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(); -// return EXIT_SUCCESS; -// } break; -// default: { -// print_usage(); -// return EXIT_FAILURE; -// } break; -// } -// } - -// // Run from stdin. -// if (optind == argc) { -// run_stdin(); -// return EXIT_SUCCESS; -// } - -// // Run from file. -// while (optind < argc) { -// char *file_name = argv[optind]; -// run_file(file_name); -// optind++; -// } - -// return EXIT_SUCCESS; -// } +int +main(int argc, char *argv[]) { + init(); + + int option; + while ((option = getopt(argc, argv, "i")) != -1) { + switch (option) { + case 'i': { + // Interactive mode. + run_repl(); + return EXIT_SUCCESS; + } break; + default: { + print_usage(); + return EXIT_FAILURE; + } break; + } + } + + // Run from stdin. + if (optind == argc) { + run_stdin(); + return EXIT_SUCCESS; + } + + // Run from file. + while (optind < argc) { + char *file_name = argv[optind]; + run_file(file_name); + optind++; + } + + return EXIT_SUCCESS; +} -- cgit v1.2.1