| @@ -10,7 +10,6 @@ echo ---------- Compiling ---------- | |||
| call ..\timecmd cl ../src/main.cpp /D_PROFILING /D_DEBUG /D_DONT_BREAK_ON_ERRORS /Zi /std:c++latest /Fe%exeName% /W3 /wd4003 /nologo /EHsc /link /NODEFAULTLIB:libucrt libucrtd.lib | |||
| rem call ..\timecmd clang-cl ../src/main.cpp -o %exeName% /O2 /std:c++latest /W3 /Zi /EHsc | |||
| if %errorlevel% == 0 ( | |||
| echo. | |||
| echo ---- Running Tests ---- | |||
| @@ -45,7 +45,7 @@ proc lisp_object_equal(Lisp_Object* n1, Lisp_Object* n2) -> bool { | |||
| proc add_to_load_path(const char* path) -> void { | |||
| using Globals::load_path; | |||
| append_to_array_list(&load_path, (void*)path); | |||
| load_path.append((void*)path); | |||
| } | |||
| proc built_in_load(String* file_name) -> Lisp_Object* { | |||
| @@ -56,7 +56,7 @@ proc built_in_load(String* file_name) -> Lisp_Object* { | |||
| file_content = read_entire_file(Memory::get_c_str(file_name)); | |||
| if (!file_content) { | |||
| for_array_list (Globals::load_path) { | |||
| for (auto it: Globals::load_path) { | |||
| fullpath[0] = '\0'; | |||
| sprintf(fullpath, "%s%s", (char*)it, Memory::get_c_str(file_name)); | |||
| file_content = read_entire_file(fullpath); | |||
| @@ -65,7 +65,7 @@ proc built_in_load(String* file_name) -> Lisp_Object* { | |||
| } | |||
| if (!file_content) { | |||
| printf("Load path:\n"); | |||
| for_array_list (Globals::load_path) { | |||
| for (auto it : Globals::load_path) { | |||
| printf(" - %s\n", (char*) it); | |||
| } | |||
| create_generic_error("The file to load '%s' was not found in the load path.", | |||
| @@ -76,7 +76,7 @@ proc built_in_load(String* file_name) -> Lisp_Object* { | |||
| Lisp_Object* result = Memory::nil; | |||
| Lisp_Object_Array_List program; | |||
| Array_List<Lisp_Object*> program; | |||
| try program = Parser::parse_program(Memory::create_string(fullpath), file_content); | |||
| for (int i = 0; i < program.next_index; ++i) { | |||
| @@ -89,7 +89,7 @@ proc built_in_import(String* file_name) -> Lisp_Object* { | |||
| // create new empty environment | |||
| Environment* new_env; | |||
| try new_env = Memory::create_child_environment(get_root_environment()); | |||
| append_to_array_list(&get_current_environment()->parents, new_env); | |||
| get_current_environment()->parents.append(new_env); | |||
| push_environment(new_env); | |||
| defer { | |||
| @@ -422,6 +422,9 @@ proc load_built_ins_into_environment() -> void { | |||
| try func = Memory::create_lisp_object(); | |||
| Memory::set_type(func, Lisp_Object_Type::Function); | |||
| func->value.function.type = Function_Type::Macro; | |||
| new((&func->value.function.args.positional.symbols)) Array_List<Environment*>(16); | |||
| new((&func->value.function.args.keyword.keywords)) Array_List<Environment*>(16); | |||
| new((&func->value.function.args.keyword.values)) Array_List<Environment*>(16); | |||
| if (doc) func->docstring = doc->value.string; | |||
| @@ -470,6 +473,9 @@ proc load_built_ins_into_environment() -> void { | |||
| try func = Memory::create_lisp_object(); | |||
| Memory::set_type(func, Lisp_Object_Type::Function); | |||
| func->value.function.type = Function_Type::Lambda; | |||
| new((&func->value.function.args.positional.symbols)) Array_List<Environment*>(16); | |||
| new((&func->value.function.args.keyword.keywords)) Array_List<Environment*>(16); | |||
| new((&func->value.function.args.keyword.values)) Array_List<Environment*>(16); | |||
| if (doc) | |||
| func->docstring = doc->value.string; | |||
| @@ -834,7 +840,7 @@ proc load_built_ins_into_environment() -> void { | |||
| fetch(hm, key); | |||
| try assert_type(hm, Lisp_Object_Type::HashMap); | |||
| Lisp_Object* ret = (Lisp_Object*)hm_get_object(hm->value.hashMap, key); | |||
| Lisp_Object* ret = (Lisp_Object*)hm->value.hashMap.get_object(key); | |||
| if (!ret) | |||
| create_symbol_undefined_error("The key was not set in the hashmap"); | |||
| @@ -843,13 +849,13 @@ proc load_built_ins_into_environment() -> void { | |||
| define((hash-map-set! hm key value), "TODO") { | |||
| fetch(hm, key, value); | |||
| try assert_type(hm, Lisp_Object_Type::HashMap); | |||
| hm_set(hm->value.hashMap, key, value); | |||
| hm->value.hashMap.set_object(key, value); | |||
| return Memory::nil; | |||
| }; | |||
| define((hash-map-delete! hm key), "TODO") { | |||
| fetch(hm, key); | |||
| try assert_type(hm, Lisp_Object_Type::HashMap); | |||
| hm_delete_object(hm->value.hashMap, key); | |||
| hm->value.hashMap.delete_object(key); | |||
| return Memory::nil; | |||
| }; | |||
| define((vector . args), "TODO") { | |||
| @@ -45,113 +45,15 @@ | |||
| #define dont_break_on_errors fluid_let(Globals::breaking_on_errors, false) | |||
| #define ignore_logging fluid_let(Globals::log_level, Log_Level::None) | |||
| #define define_array_list(type, name) \ | |||
| \ | |||
| struct name##_Array_List { \ | |||
| type* data; \ | |||
| int length; \ | |||
| int next_index; \ | |||
| }; \ | |||
| \ | |||
| proc remove_index_from_array_list(name##_Array_List* arraylist, int index) -> void { \ | |||
| arraylist->data[index] = \ | |||
| arraylist->data[--(arraylist->next_index)]; \ | |||
| } \ | |||
| \ | |||
| proc append_to_array_list(name##_Array_List* arraylist, type element) -> void { \ | |||
| if (arraylist->next_index == arraylist->length) { \ | |||
| arraylist->length *= 2; \ | |||
| arraylist->data = \ | |||
| (type*)realloc(arraylist->data, arraylist->length * sizeof(type)); \ | |||
| } \ | |||
| arraylist->data[arraylist->next_index] = element; \ | |||
| arraylist->next_index++; \ | |||
| } \ | |||
| \ | |||
| proc _merge_array_lists(name##_Array_List* arr, int start, int mid, int end) -> void { \ | |||
| int start2 = mid + 1; \ | |||
| \ | |||
| /* If the direct merge is already sorted */ \ | |||
| if ((size_t)arr->data[mid] <= (size_t)arr->data[start2]) { \ | |||
| return; \ | |||
| } \ | |||
| \ | |||
| /* Two pointers to maintain start of both arrays to merge */ \ | |||
| while (start <= mid && start2 <= end) { \ | |||
| if ((size_t)arr->data[start] <= (size_t)arr->data[start2]) { \ | |||
| start++; \ | |||
| } \ | |||
| else { \ | |||
| type value = arr->data[start2]; \ | |||
| int index = start2; \ | |||
| \ | |||
| /* Shift all the elements between element 1; element 2, right by 1. */ \ | |||
| while (index != start) { \ | |||
| arr->data[index] = arr->data[index - 1]; \ | |||
| index--; \ | |||
| } \ | |||
| arr->data[start] = value; \ | |||
| \ | |||
| /* Update all the pointers */ \ | |||
| start++; \ | |||
| mid++; \ | |||
| start2++; \ | |||
| } \ | |||
| } \ | |||
| } \ | |||
| \ | |||
| proc sort_array_list(name##_Array_List* arraylist, int left=-1, int right=-1) -> void { \ | |||
| if (left == -1) { \ | |||
| sort_array_list(arraylist, 0, arraylist->next_index - 1); \ | |||
| return; \ | |||
| } else if (left == right) { \ | |||
| return; \ | |||
| } \ | |||
| \ | |||
| int middle = left + (right-left) / 2; \ | |||
| \ | |||
| sort_array_list(arraylist, left, middle); \ | |||
| sort_array_list(arraylist, middle+1, right); \ | |||
| \ | |||
| _merge_array_lists(arraylist, left, middle, right); \ | |||
| } \ | |||
| \ | |||
| proc sorted_array_list_find(name##_Array_List* arraylist, type elem, int left=-1, int right=-1) -> int { \ | |||
| if (left == -1) { \ | |||
| return sorted_array_list_find(arraylist, elem, 0, arraylist->next_index - 1); \ | |||
| } else if (left == right) { \ | |||
| if ((size_t)arraylist->data[left] == (size_t)elem) \ | |||
| return left; \ | |||
| return -1; \ | |||
| } else if (right < left) \ | |||
| return -1; \ | |||
| \ | |||
| int middle = left + (right-left) / 2; \ | |||
| \ | |||
| if ((size_t)arraylist->data[middle] < (size_t)elem) \ | |||
| return sorted_array_list_find(arraylist, elem, middle+1, right); \ | |||
| if ((size_t)arraylist->data[middle] > (size_t)elem) \ | |||
| return sorted_array_list_find(arraylist, elem, left, middle-1); \ | |||
| return middle; \ | |||
| } \ | |||
| \ | |||
| proc create_##name##_array_list(int initial_capacity = 16) -> name##_Array_List { \ | |||
| name##_Array_List ret; \ | |||
| ret.data = (type*)malloc(initial_capacity * sizeof(type)); \ | |||
| ret.next_index = 0; \ | |||
| ret.length = initial_capacity; \ | |||
| return ret; \ | |||
| } | |||
| /* | |||
| * iterate over array lists | |||
| */ | |||
| #define for_array_list(l) \ | |||
| if (int it_index = 0); else \ | |||
| for (auto it = (l).data[0]; \ | |||
| it_index < (l).next_index; \ | |||
| it=(l).data[++it_index]) | |||
| // #define for_array_list(l) \ | |||
| // if (int it_index = 0); else \ | |||
| // for (auto it = (l).data[0]; \ | |||
| // it_index < (l).next_index; \ | |||
| // it=(l).data[++it_index]) | |||
| /* | |||
| * iterate over lisp vectors | |||
| @@ -1,10 +1,10 @@ | |||
| proc define_symbol(Lisp_Object* symbol, Lisp_Object* value) -> void { | |||
| Environment* env = get_current_environment(); | |||
| hm_set(env->hm, symbol, value); | |||
| env->hm.set_object(symbol, value); | |||
| } | |||
| inline proc lookup_symbol_in_this_envt(Lisp_Object* sym, Environment* env) -> Lisp_Object* { | |||
| return (Lisp_Object*)hm_get_object(env->hm, sym); | |||
| return (Lisp_Object*)env->hm.get_object(sym); | |||
| } | |||
| proc environment_binds_symbol(Lisp_Object* sym, Environment* env) -> bool { | |||
| @@ -14,7 +14,7 @@ proc environment_binds_symbol(Lisp_Object* sym, Environment* env) -> bool { | |||
| proc find_binding_environment(Lisp_Object* sym, Environment* env) -> Environment* { | |||
| if (environment_binds_symbol(sym, env)) | |||
| return env; | |||
| for_array_list (env->parents) { | |||
| for (auto it : env->parents) { | |||
| if (Environment* ret = find_binding_environment(sym, it)) | |||
| return ret; | |||
| } | |||
| @@ -50,7 +50,7 @@ proc try_lookup_symbol(Lisp_Object* node, Environment* env) -> Lisp_Object* { | |||
| inline proc push_environment(Environment* env) -> void { | |||
| using namespace Globals::Current_Execution; | |||
| append_to_array_list(&envi_stack, env); | |||
| envi_stack.append(env); | |||
| } | |||
| inline proc pop_environment() -> void { | |||
| @@ -98,7 +98,7 @@ proc print_environment_indent(Environment* env, int indent) -> void { | |||
| // return; | |||
| // } | |||
| for_ptr_hash_map (env->hm) { | |||
| for_LO_to_LO_hash_map (env->hm) { | |||
| print_indent(indent); | |||
| printf("-> %s :: ", &(((Lisp_Object*)key)->value.symbol.identifier->data)); | |||
| print((Lisp_Object*)value); | |||
| @@ -38,7 +38,7 @@ proc create_extended_environment_for_function_application( | |||
| // for the function call | |||
| Lisp_Object* sym, *val; // used as temp storage to use `try` | |||
| Lisp_Object_Array_List read_in_keywords; | |||
| Array_List<Lisp_Object*> read_in_keywords; | |||
| int obligatory_keywords_count = 0; | |||
| int read_obligatory_keywords_count = 0; | |||
| @@ -69,7 +69,6 @@ proc create_extended_environment_for_function_application( | |||
| // added ones (array list), if end of parameters in encountered or | |||
| // something that is not a keyword is encountered or a keyword | |||
| // that is not recognized is encoutered, jump out of the loop. | |||
| read_in_keywords = create_Lisp_Object_array_list(); | |||
| if (arguments == Memory::nil) | |||
| return; | |||
| @@ -146,7 +145,7 @@ proc create_extended_environment_for_function_application( | |||
| Memory::copy_lisp_object_except_pairs(arguments->value.pair.rest->value.pair.first)); | |||
| } | |||
| append_to_array_list(&read_in_keywords, arguments->value.pair.first); | |||
| read_in_keywords.append(arguments->value.pair.first); | |||
| ++read_obligatory_keywords_count; | |||
| // overstep both for next one | |||
| @@ -253,7 +252,7 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Lisp_Object* function, | |||
| filling it in | |||
| */ | |||
| proc create_arguments_from_lambda_list_and_inject(Lisp_Object* arguments, Lisp_Object* function) -> void { | |||
| Arguments* result; | |||
| Arguments* result;; | |||
| if (Memory::get_type(function) == Lisp_Object_Type::CFunction) { | |||
| result = &function->value.cFunction->args; | |||
| } else { | |||
| @@ -261,8 +260,8 @@ proc create_arguments_from_lambda_list_and_inject(Lisp_Object* arguments, Lisp_O | |||
| } | |||
| // first init the fields | |||
| result->positional = create_positional_argument_list(16); | |||
| result->keyword = create_keyword_argument_list(16); | |||
| // result->positional = create_positional_argument_list(16); | |||
| // result->keyword = create_keyword_argument_list(16); | |||
| result->rest = nullptr; | |||
| // okay let's try to read some positional arguments | |||
| @@ -393,7 +392,7 @@ proc eval_expr(Lisp_Object* node) -> Lisp_Object* { | |||
| profile_this; | |||
| using namespace Globals::Current_Execution; | |||
| append_to_array_list(&call_stack, node); | |||
| call_stack.append(node); | |||
| defer { | |||
| // NOTE(Felix): We only delete the current entry from the call | |||
| // stack, if we did not encounter an error, otherwise we neet | |||
| @@ -29,6 +29,8 @@ namespace Memory { | |||
| proc create_built_ins_environment() -> Environment*; | |||
| proc get_or_create_lisp_object_keyword(const char* identifier) -> Lisp_Object*; | |||
| inline proc get_type(Lisp_Object* node) -> Lisp_Object_Type; | |||
| proc init(int, int, int) -> void; | |||
| proc free_everything() -> void; | |||
| } | |||
| namespace Parser { | |||
| @@ -46,10 +48,10 @@ namespace Globals { | |||
| char* bin_path = nullptr; | |||
| Log_Level log_level = Log_Level::Debug; | |||
| Void_Ptr_Array_List load_path = create_Void_Ptr_array_list(); | |||
| Array_List<void*> load_path; | |||
| namespace Current_Execution { | |||
| Lisp_Object_Array_List call_stack = create_Lisp_Object_array_list(); | |||
| Environment_Array_List envi_stack = create_Environment_array_list(); | |||
| Array_List<Lisp_Object*> call_stack; | |||
| Array_List<Environment*> envi_stack; | |||
| } | |||
| #ifdef _DONT_BREAK_ON_ERRORS | |||
| @@ -60,21 +62,20 @@ namespace Globals { | |||
| Error* error = nullptr; | |||
| } | |||
| inline bool hm_objects_match(char* a, char* b) { | |||
| bool hm_objects_match(char* a, char* b) { | |||
| return strcmp(a, b) == 0; | |||
| } | |||
| inline bool hm_objects_match(void* a, void* b) { | |||
| bool hm_objects_match(void* a, void* b) { | |||
| return a == b; | |||
| } | |||
| u32 hm_hash(void* ptr) { | |||
| unsigned int hm_hash(void* ptr) { | |||
| return ((unsigned long long)ptr * 2654435761) % 4294967296; | |||
| } | |||
| u32 hm_hash(char* str) { | |||
| u32 value = str[0] << 7; | |||
| unsigned int hm_hash(char* str) { | |||
| unsigned int value = str[0] << 7; | |||
| int i = 0; | |||
| while (str[i]) { | |||
| value = (10000003 * value) ^ str[i++]; | |||
| @@ -82,7 +83,7 @@ u32 hm_hash(char* str) { | |||
| return value ^ i; | |||
| } | |||
| inline bool hm_objects_match(Lisp_Object* a, Lisp_Object* b) { | |||
| bool hm_objects_match(Lisp_Object* a, Lisp_Object* b) { | |||
| return lisp_object_equal(a, b); | |||
| } | |||
| @@ -1 +1 @@ | |||
| Subproject commit 9c5512b1825ad838af7926587922f2083273a601 | |||
| Subproject commit 7e47157a5f47c6a7ff3d27e665aaa1a9d48efe2f | |||
| @@ -3,10 +3,10 @@ namespace GC { | |||
| int current_mark; | |||
| Lisp_Object_Array_List marked_objects; | |||
| String_Array_List marked_strings; | |||
| Environment_Array_List marked_environments; | |||
| Environment_Array_List protected_environments; | |||
| Array_List<Lisp_Object*> marked_objects; | |||
| Array_List<String*> marked_strings; | |||
| Array_List<Environment*> marked_environments; | |||
| Array_List<Environment*> protected_environments; | |||
| proc marked(Lisp_Object* node) -> bool { | |||
| return false; | |||
| @@ -21,11 +21,11 @@ namespace GC { | |||
| return; | |||
| // mark object itself | |||
| append_to_array_list(&marked_objects, node); | |||
| marked_objects.append(node); | |||
| // mark docstring | |||
| if (node->docstring) | |||
| append_to_array_list(&marked_strings, node->docstring); | |||
| marked_strings.append(node->docstring); | |||
| // mark type specific data | |||
| switch (Memory::get_type(node)) { | |||
| @@ -40,7 +40,7 @@ namespace GC { | |||
| } | |||
| } break; | |||
| case Lisp_Object_Type::String: { | |||
| append_to_array_list(&marked_strings, node->value.string); | |||
| marked_strings.append(node->value.string); | |||
| } break; | |||
| case Lisp_Object_Type::Function: { | |||
| // NOTE(Felix): We dont have to mark the symbols, keywords | |||
| @@ -49,8 +49,9 @@ namespace GC { | |||
| maybe_mark(node->value.function.parent_environment); | |||
| maybe_mark(node->value.function.body); | |||
| // mark the default arguemnt values: | |||
| for_array_list (node->value.function.args.keyword.values) { | |||
| if (it) maybe_mark(it); | |||
| for (auto it : node->value.function.args.keyword.values) { | |||
| if (it) | |||
| maybe_mark(it); | |||
| } | |||
| } break; | |||
| default: break; | |||
| @@ -62,10 +63,10 @@ namespace GC { | |||
| if (marked(env)) | |||
| return; | |||
| append_to_array_list(&marked_environments, env); | |||
| marked_environments.append(env); | |||
| for_array_list (env->parents) { | |||
| maybe_mark(it); | |||
| for (auto p : env->parents) { | |||
| maybe_mark(p); | |||
| } | |||
| // Lisp_Object* it = env->values[0]; | |||
| @@ -78,14 +79,12 @@ namespace GC { | |||
| profile_this; | |||
| ++current_mark; | |||
| for_array_list (protected_environments) maybe_mark(it); | |||
| for_array_list (Globals::Current_Execution::envi_stack) maybe_mark(it); | |||
| for (auto it : protected_environments) maybe_mark(it); | |||
| for (auto it : Globals::Current_Execution::envi_stack) maybe_mark(it); | |||
| } | |||
| proc gc_init_and_go() -> void { | |||
| current_mark = 0; | |||
| marked_objects = create_Lisp_Object_array_list(1024); | |||
| marked_environments = create_Environment_array_list(1024); | |||
| while (1) { | |||
| garbage_collect(); | |||
| @@ -285,7 +285,7 @@ proc print(Lisp_Object* node, bool print_repr = false, FILE* file = stdout) -> v | |||
| case (Lisp_Object_Type::CFunction): fputs("[C-function]", file); break; | |||
| case (Lisp_Object_Type::Pointer): fputs("[pointer]", file); break; | |||
| case (Lisp_Object_Type::HashMap): { | |||
| for_lisp_obj_hash_map (node->value.hashMap) { | |||
| for_LO_to_LO_hash_map (node->value.hashMap) { | |||
| fputs(" ", file); | |||
| print(key, true, file); | |||
| fputs(" -> ", file); | |||
| @@ -28,27 +28,14 @@ proc Lisp_Object_Type_to_string(Lisp_Object_Type type) -> const char* { | |||
| return "unknown"; | |||
| } | |||
| proc create_positional_argument_list(int initial_capacity) -> Positional_Arguments { | |||
| Positional_Arguments ret; | |||
| ret.symbols = create_Lisp_Object_array_list(initial_capacity); | |||
| return ret; | |||
| } | |||
| proc append_to_positional_argument_list(Positional_Arguments* args, Lisp_Object* sym) -> void { | |||
| append_to_array_list(&args->symbols, sym); | |||
| } | |||
| proc create_keyword_argument_list(int initial_capacity) -> Keyword_Arguments { | |||
| Keyword_Arguments ret; | |||
| ret.keywords = create_Lisp_Object_array_list(initial_capacity); | |||
| ret.values = create_Lisp_Object_array_list(initial_capacity); | |||
| return ret; | |||
| args->symbols.append(sym); | |||
| } | |||
| proc append_to_keyword_argument_list(Keyword_Arguments* args, | |||
| Lisp_Object* keyword, | |||
| Lisp_Object* default_value) -> void | |||
| { | |||
| append_to_array_list(&args->keywords, keyword); | |||
| append_to_array_list(&args->values, default_value); | |||
| args->keywords.append(keyword); | |||
| args->values.append(default_value); | |||
| } | |||
| @@ -3,14 +3,14 @@ namespace Memory { | |||
| // ------------------ | |||
| // global symbol / keyword table | |||
| // ------------------ | |||
| String_Hash_Map* global_symbol_table; | |||
| String_Hash_Map* global_keyword_table; | |||
| Hash_Map<char*, Lisp_Object*> global_symbol_table; | |||
| Hash_Map<char*, Lisp_Object*> global_keyword_table; | |||
| // ------------------ | |||
| // lisp_objects | |||
| // ------------------ | |||
| int object_memory_size; | |||
| Int_Array_List free_spots_in_object_memory; | |||
| Array_List<int> free_spots_in_object_memory; | |||
| Lisp_Object* object_memory; | |||
| int next_index_in_object_memory = 0; | |||
| @@ -18,7 +18,7 @@ namespace Memory { | |||
| // environments | |||
| // ------------------ | |||
| int environment_memory_size; | |||
| Environment_Array_List free_spots_in_environment_memory; | |||
| Array_List<Environment*> free_spots_in_environment_memory; | |||
| Environment* environment_memory; | |||
| int next_index_in_environment_memory = 0; | |||
| @@ -29,7 +29,7 @@ namespace Memory { | |||
| // free_spots_in_string_memory is an arraylist of pointers into | |||
| // the string_memory, where dead String objects live (which give | |||
| // information about their size) | |||
| Void_Ptr_Array_List free_spots_in_string_memory; | |||
| Array_List<void*> free_spots_in_string_memory; | |||
| String* string_memory; | |||
| String* next_free_spot_in_string_memory; | |||
| @@ -112,7 +112,7 @@ namespace Memory { | |||
| } | |||
| proc delete_string(String* str) { | |||
| append_to_array_list(&free_spots_in_string_memory, (void*)str); | |||
| free_spots_in_string_memory.append((void*)str); | |||
| } | |||
| proc duplicate_string(String* str) -> String* { | |||
| @@ -165,32 +165,29 @@ namespace Memory { | |||
| return object; | |||
| } | |||
| proc free_everything() { | |||
| free(global_symbol_table); | |||
| free(global_keyword_table); | |||
| proc free_everything() -> void { | |||
| // free(global_symbol_table); | |||
| // free(global_keyword_table); | |||
| free(object_memory); | |||
| free(environment_memory); | |||
| free(string_memory); | |||
| } | |||
| proc init(int oms, int ems, int sms) { | |||
| proc init(int oms, int ems, int sms) -> void { | |||
| char* exe_path = get_exe_dir(); | |||
| defer {free(exe_path);}; | |||
| add_to_load_path(exe_path); | |||
| add_to_load_path("../bin/"); | |||
| global_symbol_table = create_String_hashmap(); | |||
| global_keyword_table = create_String_hashmap(); | |||
| // global_symbol_table = create_String_hashmap(); | |||
| // global_keyword_table = create_String_hashmap(); | |||
| object_memory_size = oms; | |||
| environment_memory_size = ems; | |||
| string_memory_size = sms; | |||
| free_spots_in_object_memory = create_Int_array_list(); | |||
| free_spots_in_environment_memory = create_Environment_array_list(); | |||
| free_spots_in_string_memory = create_Void_Ptr_array_list(); | |||
| object_memory = (Lisp_Object*)malloc(object_memory_size * sizeof(Lisp_Object)); | |||
| environment_memory = (Environment*)malloc(environment_memory_size * sizeof(Environment)); | |||
| environment_memory = (Environment*)calloc(environment_memory_size, sizeof(Environment)); | |||
| string_memory = (String*)malloc(string_memory_size * sizeof(char)); | |||
| next_free_spot_in_string_memory = string_memory; | |||
| @@ -215,8 +212,9 @@ namespace Memory { | |||
| free_spots_in_environment_memory.next_index = 0; | |||
| free_spots_in_string_memory.next_index = 0; | |||
| global_symbol_table = create_String_hashmap(); | |||
| global_keyword_table = create_String_hashmap(); | |||
| ::new((&global_symbol_table)) Hash_Map<char*, Lisp_Object*>; | |||
| ::new((&global_keyword_table)) Hash_Map<char*, Lisp_Object*>; | |||
| try_void Parser::standard_in = create_string("stdin"); | |||
| @@ -241,7 +239,7 @@ namespace Memory { | |||
| Lisp_Object* node; | |||
| try node = create_lisp_object(); | |||
| set_type(node, Lisp_Object_Type::HashMap); | |||
| node->value.hashMap = create_Lisp_Obj_hashmap(); | |||
| ::new((&node->value.hashMap)) Hash_Map<Lisp_Object*, Lisp_Object*>; | |||
| return node; | |||
| } | |||
| @@ -315,7 +313,7 @@ namespace Memory { | |||
| set_type(node, Lisp_Object_Type::Symbol); | |||
| node->value.symbol.identifier = identifier; | |||
| node->value.symbol.hash = hash(identifier); | |||
| hm_set(global_symbol_table, get_c_str(identifier), node); | |||
| global_symbol_table.set_object(get_c_str(identifier), node); | |||
| return node; | |||
| } | |||
| @@ -325,19 +323,19 @@ namespace Memory { | |||
| set_type(node, Lisp_Object_Type::Keyword); | |||
| node->value.symbol.identifier = keyword; | |||
| node->value.symbol.hash = hash(keyword); | |||
| hm_set(global_keyword_table, get_c_str(keyword), node); | |||
| global_keyword_table.set_object(get_c_str(keyword), node); | |||
| return node; | |||
| } | |||
| proc get_or_create_lisp_object_symbol(String* identifier) -> Lisp_Object* { | |||
| if (auto ret = hm_get_object(global_symbol_table, get_c_str(identifier))) | |||
| if (auto ret = global_symbol_table.get_object(get_c_str(identifier))) | |||
| return (Lisp_Object*)ret; | |||
| else | |||
| return create_new_lisp_object_symbol(identifier); | |||
| } | |||
| proc get_or_create_lisp_object_symbol(const char* identifier) -> Lisp_Object* { | |||
| if (auto ret = hm_get_object(global_symbol_table, (char*)identifier)) | |||
| if (auto ret = global_symbol_table.get_object((char*)identifier)) | |||
| return (Lisp_Object*)ret; | |||
| else { | |||
| String* str; | |||
| @@ -347,14 +345,14 @@ namespace Memory { | |||
| } | |||
| proc get_or_create_lisp_object_keyword(String* keyword) -> Lisp_Object* { | |||
| if (auto ret = hm_get_object(global_keyword_table, get_c_str(keyword))) | |||
| if (auto ret = global_keyword_table.get_object(get_c_str(keyword))) | |||
| return (Lisp_Object*)ret; | |||
| else | |||
| return create_new_lisp_object_keyword(keyword); | |||
| } | |||
| proc get_or_create_lisp_object_keyword(const char* keyword) -> Lisp_Object* { | |||
| if (auto ret = hm_get_object(global_keyword_table, (char*)keyword)) | |||
| if (auto ret = global_keyword_table.get_object((char*)keyword)) | |||
| return (Lisp_Object*)ret; | |||
| else { | |||
| String* str; | |||
| @@ -370,6 +368,9 @@ namespace Memory { | |||
| // node->value.lambdaWrapper = new Lambda_Wrapper(function); | |||
| node->value.cFunction = new(cFunction); | |||
| node->value.cFunction->args = {}; | |||
| new((&node->value.cFunction->args.positional.symbols)) Array_List<Environment*>(16); | |||
| new((&node->value.cFunction->args.keyword.keywords)) Array_List<Environment*>(16); | |||
| new((&node->value.cFunction->args.keyword.values)) Array_List<Environment*>(16); | |||
| node->value.cFunction->is_special_form = is_special; | |||
| return node; | |||
| } | |||
| @@ -429,14 +430,14 @@ namespace Memory { | |||
| env = free_spots_in_environment_memory.data[--free_spots_in_environment_memory.next_index]; | |||
| } | |||
| int start_capacity = 16; | |||
| env->parents = create_Environment_array_list(); | |||
| // inject a new array list; | |||
| if (env->parents.data) | |||
| free(env->parents.data); | |||
| ::new((&env->parents)) Array_List<Environment*>; | |||
| if (parent) | |||
| append_to_array_list(&env->parents, parent); | |||
| env->parents.append(parent); | |||
| env->hm = create_Void_Ptr_hashmap(); | |||
| ::new((&env->hm)) Hash_Map<Lisp_Object*, Lisp_Object*>; | |||
| return env; | |||
| } | |||
| @@ -443,7 +443,7 @@ namespace Parser { | |||
| } | |||
| proc write_expanded_file(String* file_name, Lisp_Object_Array_List program) -> void { | |||
| proc write_expanded_file(String* file_name, Array_List<Lisp_Object*> program) -> void { | |||
| const char* ext = ".expanded"; | |||
| char* newName = (char*)calloc(10 + file_name->length, sizeof(char)); | |||
| strcpy(newName, Memory::get_c_str(file_name)); | |||
| @@ -469,12 +469,12 @@ namespace Parser { | |||
| } | |||
| } | |||
| proc parse_program(String* file_name, char* text) -> Lisp_Object_Array_List { | |||
| proc parse_program(String* file_name, char* text) -> Array_List<Lisp_Object*> { | |||
| parser_file = file_name; | |||
| parser_line = 1; | |||
| parser_col = 0; | |||
| Lisp_Object_Array_List program = create_Lisp_Object_array_list(); | |||
| Array_List<Lisp_Object*> program; | |||
| int index_in_text = 0; | |||
| @@ -485,7 +485,7 @@ namespace Parser { | |||
| try_struct { | |||
| parsed = parse_expression(text, &index_in_text); | |||
| } | |||
| append_to_array_list(&program, parsed); | |||
| program.append(parsed); | |||
| } break; | |||
| case ';': | |||
| case ' ': | |||
| @@ -0,0 +1,45 @@ | |||
| #define _CRT_SECURE_NO_WARNINGS | |||
| #define _CRT_SECURE_NO_DEPRECATE | |||
| #include <stdlib.h> | |||
| #include <stdio.h> | |||
| #include <time.h> | |||
| #include <string.h> | |||
| #include <cmath> | |||
| #include <ctype.h> | |||
| #include <stdarg.h> | |||
| #include <functional> | |||
| #ifdef _MSC_VER | |||
| # include <direct.h> | |||
| # include <windows.h> | |||
| #else | |||
| # include <unistd.h> | |||
| # include <signal.h> | |||
| #endif | |||
| #include "./ftb/arraylist.hpp" | |||
| #include "./ftb/macros.hpp" | |||
| #include "./ftb/profiler.hpp" | |||
| #include "./ftb/hashmap.hpp" | |||
| namespace Slime { | |||
| # include "./defines.cpp" | |||
| # include "./platform.cpp" | |||
| # include "./structs.cpp" | |||
| # include "./forward_decls.cpp" | |||
| # include "./memory.cpp" | |||
| # include "./gc.cpp" | |||
| # include "./lisp_object.cpp" | |||
| # include "./error.cpp" | |||
| # include "./io.cpp" | |||
| # include "./env.cpp" | |||
| # include "./parse.cpp" | |||
| # include "./eval.cpp" | |||
| # include "./visualization.cpp" | |||
| # include "./docgeneration.cpp" | |||
| # include "./built_ins.cpp" | |||
| # include "./testing.cpp" | |||
| # include "./undefines.cpp" | |||
| } | |||
| @@ -21,9 +21,20 @@ | |||
| # include <signal.h> | |||
| #endif | |||
| #include "./ftb/types.hpp" | |||
| #include "./ftb/macros.hpp" | |||
| #include "./ftb/profiler.hpp" | |||
| struct Lisp_Object; | |||
| u32 hm_hash(Lisp_Object* obj); | |||
| u32 hm_hash(char* obj); | |||
| u32 hm_hash(void* obj); | |||
| bool hm_objects_match(void* a, void* b); | |||
| bool hm_objects_match(char* a, char* b); | |||
| bool hm_objects_match(Lisp_Object* a, Lisp_Object* b); | |||
| #include "./ftb/hashmap.hpp" | |||
| #include "./ftb/arraylist.hpp" | |||
| namespace Slime { | |||
| # include "./defines.cpp" | |||
| @@ -42,5 +53,5 @@ namespace Slime { | |||
| # include "./docgeneration.cpp" | |||
| # include "./built_ins.cpp" | |||
| # include "./testing.cpp" | |||
| // # include "./undefines.cpp" | |||
| # include "./undefines.cpp" | |||
| } | |||
| @@ -0,0 +1,11 @@ | |||
| #include <functional> | |||
| #define _CRT_SECURE_NO_WARNINGS | |||
| #define _CRT_SECURE_NO_DEPRECATE | |||
| namespace Slime { | |||
| # include "./defines.cpp" | |||
| # include "./ftb/hashmap.hpp" | |||
| # include "./ftb/arraylist.hpp" | |||
| # include "./structs.cpp" | |||
| # include "./forward_decls.cpp" | |||
| # include "./undefines.cpp" | |||
| } | |||
| @@ -2,20 +2,21 @@ struct Lisp_Object; | |||
| struct String; | |||
| struct Environment; | |||
| // ARRAY LISTS | |||
| define_array_list(Lisp_Object*, Lisp_Object); | |||
| define_array_list(Environment*, Environment); | |||
| define_array_list(String*, String); | |||
| define_array_list(int, Int); | |||
| define_array_list(void*, Void_Ptr); | |||
| unsigned int hm_hash(char* str); | |||
| unsigned int hm_hash(void* str); | |||
| unsigned int hm_hash(Lisp_Object* str); | |||
| bool hm_objects_match(char* a, char* b); | |||
| bool hm_objects_match(void* a, void* b); | |||
| bool hm_objects_match(Lisp_Object* a, Lisp_Object* b); | |||
| // HASH MAPS | |||
| define_hash_map(char*, String); | |||
| define_hash_map(Lisp_Object*, Lisp_Obj); | |||
| define_hash_map(void*, Void_Ptr); | |||
| #define for_str_hash_map(hm) __for_hm_generator(char*, hm) | |||
| #define for_ptr_hash_map(hm) __for_hm_generator(void*, hm) | |||
| #define for_lisp_obj_hash_map(hm) __for_hm_generator(Lisp_Object*, hm) | |||
| // define_hash_map(char*, String); | |||
| // define_hash_map(Lisp_Object*, Lisp_Obj); | |||
| // define_hash_map(void*, Void_Ptr); | |||
| #define for_str_to_LO_hash_map(hm) __for_hm_generator(char*, Lisp_Object*, hm) | |||
| // #define for_ptr_hash_map(hm) __for_hm_generator(void*, hm) | |||
| #define for_LO_to_LO_hash_map(hm) __for_hm_generator(Lisp_Object*, Lisp_Object*, hm) | |||
| // STRUCTS | |||
| enum struct Thread_Type { | |||
| @@ -23,7 +24,6 @@ enum struct Thread_Type { | |||
| GarbageCollection | |||
| }; | |||
| enum struct Lisp_Object_Type { | |||
| Nil, | |||
| T, | |||
| @@ -65,8 +65,8 @@ enum struct Log_Level { | |||
| }; | |||
| struct Continuation { | |||
| Lisp_Object_Array_List* call_stack; | |||
| Environment_Array_List* envi_stack; | |||
| Array_List<Lisp_Object*> call_stack; | |||
| Array_List<Environment*> envi_stack; | |||
| }; | |||
| struct String { | |||
| @@ -101,15 +101,15 @@ struct Vector { | |||
| }; | |||
| struct Positional_Arguments { | |||
| Lisp_Object_Array_List symbols; | |||
| Array_List<Lisp_Object*> symbols; | |||
| }; | |||
| struct Keyword_Arguments { | |||
| // Array of Pointers to Lisp_Object<Keyword> | |||
| Lisp_Object_Array_List keywords; | |||
| Array_List<Lisp_Object*> keywords; | |||
| // NOTE(Felix): values[i] will be nullptr if no defalut value was | |||
| // declared for key identifiers[i] | |||
| Lisp_Object_Array_List values; | |||
| Array_List<Lisp_Object*> values; | |||
| }; | |||
| struct Arguments { | |||
| @@ -121,8 +121,8 @@ struct Arguments { | |||
| }; | |||
| struct Environment { | |||
| Environment_Array_List parents; | |||
| Void_Ptr_Hash_Map* hm; | |||
| Array_List<Environment*> parents; | |||
| Hash_Map<Lisp_Object*, Lisp_Object*> hm; | |||
| }; | |||
| struct Function { | |||
| @@ -153,7 +153,7 @@ struct Lisp_Object { | |||
| cFunction* cFunction; | |||
| void* pointer; | |||
| Continuation continuation; | |||
| Lisp_Obj_Hash_Map* hashMap; | |||
| Hash_Map<Lisp_Object*, Lisp_Object*> hashMap; | |||
| } value; | |||
| }; | |||
| @@ -115,79 +115,78 @@ | |||
| proc test_array_lists_adding_and_removing() -> testresult { | |||
| // test adding and removing | |||
| Int_Array_List list = create_Int_array_list(); | |||
| append_to_array_list(&list, 1); | |||
| append_to_array_list(&list, 2); | |||
| append_to_array_list(&list, 3); | |||
| append_to_array_list(&list, 4); | |||
| Array_List<int> list; | |||
| list.append(1); | |||
| list.append(2); | |||
| list.append(3); | |||
| list.append(4); | |||
| assert_equal_int(list.next_index, 4); | |||
| remove_index_from_array_list(&list, 0); | |||
| list.remove_index(0); | |||
| assert_equal_int(list.next_index, 3); | |||
| assert_equal_int(list.data[0], 4); | |||
| assert_equal_int(list.data[1], 2); | |||
| assert_equal_int(list.data[2], 3); | |||
| assert_equal_int(list[0], 4); | |||
| assert_equal_int(list[1], 2); | |||
| assert_equal_int(list[2], 3); | |||
| remove_index_from_array_list(&list, 2); | |||
| list.remove_index(2); | |||
| assert_equal_int(list.next_index, 2); | |||
| assert_equal_int(list.data[0], 4); | |||
| assert_equal_int(list.data[1], 2); | |||
| assert_equal_int(list[0], 4); | |||
| assert_equal_int(list[1], 2); | |||
| return pass; | |||
| } | |||
| proc test_array_lists_sorting() -> testresult { | |||
| // test adding and removing | |||
| Int_Array_List list = create_Int_array_list(); | |||
| append_to_array_list(&list, 1); | |||
| append_to_array_list(&list, 2); | |||
| append_to_array_list(&list, 3); | |||
| append_to_array_list(&list, 4); | |||
| Array_List<int> list; | |||
| list.append(1); | |||
| list.append(2); | |||
| list.append(3); | |||
| list.append(4); | |||
| sort_array_list(&list); | |||
| list.sort(); | |||
| assert_equal_int(list.next_index, 4); | |||
| assert_equal_int(list.data[0], 1); | |||
| assert_equal_int(list.data[1], 2); | |||
| assert_equal_int(list.data[2], 3); | |||
| assert_equal_int(list.data[3], 4); | |||
| assert_equal_int(list[0], 1); | |||
| assert_equal_int(list[1], 2); | |||
| assert_equal_int(list[2], 3); | |||
| assert_equal_int(list[3], 4); | |||
| append_to_array_list(&list, 0); | |||
| append_to_array_list(&list, 5); | |||
| list.append(0); | |||
| list.append(5); | |||
| assert_equal_int(list.next_index, 6); | |||
| sort_array_list(&list); | |||
| assert_equal_int(list.data[0], 0); | |||
| assert_equal_int(list.data[1], 1); | |||
| assert_equal_int(list.data[2], 2); | |||
| assert_equal_int(list.data[3], 3); | |||
| assert_equal_int(list.data[4], 4); | |||
| assert_equal_int(list.data[5], 5); | |||
| list.sort(); | |||
| assert_equal_int(list[0], 0); | |||
| assert_equal_int(list[1], 1); | |||
| assert_equal_int(list[2], 2); | |||
| assert_equal_int(list[3], 3); | |||
| assert_equal_int(list[4], 4); | |||
| assert_equal_int(list[5], 5); | |||
| return pass; | |||
| } | |||
| proc test_array_lists_searching() -> testresult { | |||
| Int_Array_List list = create_Int_array_list(); | |||
| append_to_array_list(&list, 1); | |||
| append_to_array_list(&list, 2); | |||
| append_to_array_list(&list, 3); | |||
| append_to_array_list(&list, 4); | |||
| Array_List<int> list; | |||
| list.append(1); | |||
| list.append(2); | |||
| list.append(3); | |||
| list.append(4); | |||
| int index = sorted_array_list_find(&list, 3); | |||
| int index = list.sorted_find(3); | |||
| assert_equal_int(index, 2); | |||
| index = sorted_array_list_find(&list, 1); | |||
| index = list.sorted_find(1); | |||
| assert_equal_int(index, 0); | |||
| index = sorted_array_list_find(&list, 5); | |||
| index = list.sorted_find(5); | |||
| assert_equal_int(index, -1); | |||
| return pass; | |||
| @@ -359,12 +359,12 @@ proc visualize_lisp_machine() -> void { | |||
| draw_new_line(3); | |||
| }; | |||
| proc draw_symbols_keywords_and_numbers = [&]() { | |||
| Lisp_Object_Array_List symbols = create_Lisp_Object_array_list(); | |||
| Lisp_Object_Array_List keywords = create_Lisp_Object_array_list(); | |||
| Lisp_Object_Array_List numbers = create_Lisp_Object_array_list(); | |||
| Lisp_Object_Array_List strings = create_Lisp_Object_array_list(); | |||
| Lisp_Object_Array_List pairs = create_Lisp_Object_array_list(); | |||
| Lisp_Object_Array_List lists = create_Lisp_Object_array_list(); | |||
| Array_List<Lisp_Object*> symbols; | |||
| Array_List<Lisp_Object*> keywords; | |||
| Array_List<Lisp_Object*> numbers; | |||
| Array_List<Lisp_Object*> strings; | |||
| Array_List<Lisp_Object*> pairs; | |||
| Array_List<Lisp_Object*> lists; | |||
| // loop over all used memory | |||
| for (int i = 0; i < Memory::next_index_in_object_memory; ++i) { | |||
| @@ -374,11 +374,11 @@ proc visualize_lisp_machine() -> void { | |||
| } | |||
| switch (Memory::get_type(Memory::object_memory+i)) { | |||
| case Lisp_Object_Type::Symbol: append_to_array_list(&symbols, Memory::object_memory+i); break; | |||
| case Lisp_Object_Type::String: append_to_array_list(&strings, Memory::object_memory+i); break; | |||
| case Lisp_Object_Type::Keyword: append_to_array_list(&keywords, Memory::object_memory+i); break; | |||
| case Lisp_Object_Type::Number : append_to_array_list(&numbers, Memory::object_memory+i); break; | |||
| case Lisp_Object_Type::Pair : append_to_array_list(&pairs, Memory::object_memory+i); break; | |||
| case Lisp_Object_Type::Symbol: symbols .append(Memory::object_memory+i); break; | |||
| case Lisp_Object_Type::String: strings .append(Memory::object_memory+i); break; | |||
| case Lisp_Object_Type::Keyword: keywords.append(Memory::object_memory+i); break; | |||
| case Lisp_Object_Type::Number : numbers .append(Memory::object_memory+i); break; | |||
| case Lisp_Object_Type::Pair : pairs .append(Memory::object_memory+i); break; | |||
| default: break; | |||
| } | |||
| @@ -386,36 +386,36 @@ proc visualize_lisp_machine() -> void { | |||
| } | |||
| // create the lists-list by filtering the pairs-list. | |||
| Lisp_Object_Array_List pairs_to_filter = create_Lisp_Object_array_list(); | |||
| Array_List<Lisp_Object*> pairs_to_filter; | |||
| // helper lambda: | |||
| proc remove_doubles_from_lisp_object_array_list = [&](Lisp_Object_Array_List list) -> void { | |||
| proc remove_doubles_from_lisp_object_array_list = [&](Array_List<Lisp_Object*> list) -> void { | |||
| if (list.next_index == 0) | |||
| return; | |||
| sort_array_list(&list); | |||
| Int_Array_List indices_to_filter = create_Int_array_list(); | |||
| list.sort(); | |||
| Array_List<int> indices_to_filter; | |||
| size_t last = (size_t)list.data[0]; | |||
| for (int i = 1; i < list.next_index; ++i) { | |||
| if ((size_t)list.data[i] == last) | |||
| append_to_array_list(&indices_to_filter, i); | |||
| indices_to_filter.append(i); | |||
| else | |||
| last = (size_t)list.data[i]; | |||
| } | |||
| for (int i = indices_to_filter.next_index; i >= 0; --i) { | |||
| remove_index_from_array_list(&list, indices_to_filter.data[i]); | |||
| list.remove_index(indices_to_filter.data[i]); | |||
| } | |||
| // sort again as removing items destroys the order | |||
| sort_array_list(&list); | |||
| list.sort(); | |||
| }; | |||
| // recursive lambda | |||
| std::function<void(Lisp_Object*)> filter_pair_and_children; | |||
| filter_pair_and_children = [&](Lisp_Object* pair) { | |||
| append_to_array_list(&pairs_to_filter, pair); | |||
| pairs_to_filter.append(pair); | |||
| if (Memory::get_type(pair->value.pair.first) == Lisp_Object_Type::Pair) | |||
| filter_pair_and_children(pair->value.pair.first); | |||
| @@ -437,8 +437,8 @@ proc visualize_lisp_machine() -> void { | |||
| // okay, so pairs_to_filter now only the pairs once each that | |||
| // we want to filter from the pairs list | |||
| for (int i = 0; i < pairs.next_index; ++i) { | |||
| if (sorted_array_list_find(&pairs_to_filter, pairs.data[i]) == -1) { | |||
| append_to_array_list(&lists, pairs.data[i]); | |||
| if (pairs_to_filter.sorted_find(pairs.data[i]) == -1) { | |||
| lists.append(pairs.data[i]); | |||
| } | |||
| } | |||