| @@ -1 +1 @@ | |||
| Subproject commit a20539587c9547084629fb730e12dab21ea8ccca | |||
| Subproject commit 43da71f8094e24c544c12352e02eb76c746e1c93 | |||
| @@ -0,0 +1,4 @@ | |||
| (define a 10) | |||
| (define (get-a-1) | |||
| a) | |||
| @@ -0,0 +1,8 @@ | |||
| (import "import1.slime") | |||
| (define (set-a-2 s) | |||
| (set! a s)) | |||
| (define (get-a-2) | |||
| a) | |||
| @@ -88,7 +88,7 @@ | |||
| (define (range (:from 0) :to) :doc "Returns a sequence of numbers starting with the number defined\nby the key =from= and ends with the number defined in =to=." (when (< from to) (pair from (range :from (+ 1 from) :to to)))) | |||
| (define (range-while (:from 0) to) :doc "Returns a sequence of numbers starting with the number defined\nby the key 'from' and ends with the number defined in 'to'." (define result (list (copy from))) (define head result) (mutate from (increment from)) (while (< from to) (begin (mutate head (pair (first head) (pair (copy from) nil))) (define head (rest head)) (mutate from (increment from)))) result) | |||
| (define (range-while (:from 0) :to) :doc "Returns a sequence of numbers starting with the number defined\nby the key 'from' and ends with the number defined in 'to'." (define result (list (copy from))) (define head result) (set! from (increment from)) (while (< from to) (begin (mutate head (pair (first head) (pair (copy from) nil))) (define head (rest head)) (set! from (increment from)))) result) | |||
| (define (map fun seq) :doc "Takes a function and a sequence as arguments and returns a new\nsequence which contains the results of using the first sequences\nelemens as argument to that function." (if (null? seq) seq (pair (fun (first seq)) (map fun (rest seq))))) | |||
| @@ -89,13 +89,13 @@ | |||
| ;; :key2 value2, | |||
| ;; :key1 value1)) | |||
| (assert (= (length (first p)) 6)) | |||
| (assert (= (ds::plist::get p :key1) 'value4)) | |||
| ;; (assert (= (length (first p)) 6)) | |||
| ;; (assert (= (ds::plist::get p :key1) 'value4)) | |||
| (ds::plist::remove! p :key1) | |||
| ;; p == ((:key2 value2, | |||
| ;; :key1 value1)) | |||
| ;; (ds::plist::remove! p :key1) | |||
| ;; ;; p == ((:key2 value2, | |||
| ;; ;; :key1 value1)) | |||
| (assert (= (length (first p)) 4)) | |||
| (assert (= (ds::plist::get p :key1) 'value1)) | |||
| (assert (= (ds::plist::get p :key2) 'value2)) | |||
| ;; (assert (= (length (first p)) 4)) | |||
| ;; (assert (= (ds::plist::get p :key1) 'value1)) | |||
| ;; (assert (= (ds::plist::get p :key2) 'value2)) | |||
| @@ -0,0 +1,17 @@ | |||
| (import "import1.slime") | |||
| (assert (= a 10)) | |||
| (assert (= (get-a-1) 10)) | |||
| (import "import2.slime") | |||
| (assert (= a 10)) | |||
| (assert (= (get-a-1) 10)) | |||
| (assert (= (get-a-2) 10)) | |||
| (set-a-2 11) | |||
| (assert (= a 11)) | |||
| (assert (= (get-a-1) 11)) | |||
| (assert (= (get-a-2) 11)) | |||
| @@ -7,7 +7,13 @@ set exeName=slime.exe | |||
| taskkill /F /IM %exeName% > NUL 2> NUL | |||
| 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 | |||
| call ..\timecmd cl ^ | |||
| ../src/main.cpp ^ | |||
| /I../3rd/ ^ | |||
| /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 ( | |||
| @@ -128,3 +128,24 @@ | |||
| #define in_caller_env fluid_let( \ | |||
| Globals::Current_Execution::envi_stack.next_index, \ | |||
| Globals::Current_Execution::envi_stack.next_index-1) | |||
| /* | |||
| * iterate over lisp vectors | |||
| */ | |||
| #define for_lisp_vector(v) \ | |||
| if (!v); else \ | |||
| if (int it_index = 0); else \ | |||
| for (auto it = v->value.vector.data; \ | |||
| it_index < v->value.vector.length; \ | |||
| it=v->value.vector.data+(++it_index)) | |||
| /* | |||
| * iterate over lisp lists | |||
| */ | |||
| #define for_lisp_list(l) \ | |||
| if (!l); else \ | |||
| if (int it_index = 0); else \ | |||
| for (Lisp_Object* head = l, *it; \ | |||
| Memory::get_type(head) == Lisp_Object_Type::Pair && (it = head->value.pair.first); \ | |||
| head = head->value.pair.rest, ++it_index) | |||
| @@ -1,3 +1,5 @@ | |||
| #pragma once | |||
| #include <functional> | |||
| #include "ftb/arraylist.hpp" | |||
| #include "ftb/hashmap.hpp" | |||
| @@ -182,11 +184,13 @@ namespace Slime { | |||
| void visualize_lisp_machine(); | |||
| void generate_docs(String* path); | |||
| void log_error(); | |||
| namespace Memory { | |||
| extern Lisp_Object* nil; | |||
| extern Lisp_Object* t; | |||
| Environment* create_child_environment(Environment* parent); | |||
| Environment* create_built_ins_environment(); | |||
| Lisp_Object* create_lisp_object_cfunction(bool is_special); | |||
| Lisp_Object* get_or_create_lisp_object_keyword(const char* identifier); | |||
| @@ -196,6 +200,7 @@ namespace Slime { | |||
| void free_everything(); | |||
| String* create_string(const char*); | |||
| Lisp_Object* create_lisp_object_number(double); | |||
| Lisp_Object* create_lisp_object_pointer(void*); | |||
| Lisp_Object* get_or_create_lisp_object_symbol(String* identifier); | |||
| Lisp_Object* get_or_create_lisp_object_symbol(const char*); | |||
| Lisp_Object* get_or_create_lisp_object_keyword(String* identifier); | |||
| @@ -0,0 +1,36 @@ | |||
| * mallocs | |||
| |------------------------------------------+------------------------| | |||
| | location | always freed | | |||
| |------------------------------------------+------------------------| | |||
| | [[file:3rd\ftb\arraylist.hpp::11]]: | yes | | |||
| | [[file:.\3rd\ftb\bucket_allocator.hpp::17]]: | yes | | |||
| | [[file:.\3rd\ftb\bucket_allocator.hpp::44]]: | yes | | |||
| | [[file:.\3rd\ftb\bucket_allocator.hpp::46]]: | yes | | |||
| | [[file:.\src\io.cpp::49]]: | yes | | |||
| | [[file:.\src\io.cpp::164]]: | yes | | |||
| | [[file:.\src\io.cpp::209]]: | yes | | |||
| | [[file:.\src\io.cpp::285]]: | yes | | |||
| | [[file:.\src\memory.cpp::158]]: | yes in free_everything | | |||
| | [[file:.\src\platform.cpp::3]]: | yes | | |||
| | [[file:.\src\platform.cpp::27]]: | yes | | |||
| | [[file:.\src\platform.cpp::47]]: | yes | | |||
| | [[file:.\src\platform.cpp::81]]: | yes | | |||
| |------------------------------------------+------------------------| | |||
| * news | |||
| |----------------------------------+-------------------------------------------------------------------------------------| | |||
| | location | always deleted | | |||
| |----------------------------------+-------------------------------------------------------------------------------------| | |||
| | [[file:.\src\eval.cpp::262]]: | ::new (&(result->positional.symbols)) Array_List<Lisp_Object*>; | | |||
| | [[file:.\src\eval.cpp::263]]: | ::new (&(result->keyword.keywords)) Array_List<Lisp_Object*>; | | |||
| | [[file:.\src\eval.cpp:264]]: | ::new (&(result->keyword.values)) Array_List<Lisp_Object*>; | | |||
| | [[file:.\src\io.cpp:284]]: | // allocate a new block of memory size char (1 byte) instead of wide char (2 bytes) | | |||
| | [[file:.\src\io.cpp:306]]: | wchar_t* wc = new wchar_t[cSize]; | | |||
| | [[file:.\src\memory.cpp:336]]: | // node->value.lambdaWrapper = new Lambda_Wrapper(function); | | |||
| | [[file:.\src\memory.cpp:383]]: | // inject a new array list; | | |||
| | [[file:.\src\parse.cpp:195]]: | // better for keeping track of the encountered new lines and | | |||
| | [[file:.\src\parse.cpp:196]]: | // characters since last new line so we can update the parser | | |||
| | [[file:.\src\parse.cpp:208]]: | /* new col = (count chars since last \n) + 1 */ | | |||
| |----------------------------------+-------------------------------------------------------------------------------------| | |||
| @@ -69,35 +69,47 @@ proc built_in_load(String* file_name) -> Lisp_Object* { | |||
| } | |||
| create_generic_error("The file to load '%s' was not found in the load path.", | |||
| Memory::get_c_str(file_name)); | |||
| return nullptr; | |||
| } | |||
| } | |||
| Lisp_Object* result = Memory::nil; | |||
| Array_List<Lisp_Object*> 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) { | |||
| try result = eval_expr(program.data[i]); | |||
| for (int i = 0; i < program->next_index; ++i) { | |||
| try result = eval_expr(program->data[i]); | |||
| } | |||
| delete program; | |||
| return result; | |||
| } | |||
| 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()); | |||
| get_current_environment()->parents.append(new_env); | |||
| push_environment(new_env); | |||
| defer { | |||
| pop_environment(); | |||
| }; | |||
| new_env = Memory::file_to_env_map.get_object(Memory::get_c_str(file_name)); | |||
| if (!new_env) { | |||
| // create new empty environment | |||
| try new_env = Memory::create_child_environment(get_root_environment()); | |||
| // TODO(Felix): check absoulute paths in the map, not just | |||
| // relative ones | |||
| Memory::file_to_env_map.set_object(Memory::get_c_str(file_name), new_env); | |||
| push_environment(new_env); | |||
| defer { | |||
| pop_environment(); | |||
| }; | |||
| Lisp_Object* res; | |||
| try res = built_in_load(file_name); | |||
| } | |||
| Lisp_Object* res = built_in_load(file_name); | |||
| get_current_environment()->parents.append(new_env); | |||
| return res; | |||
| return Memory::nil; | |||
| } | |||
| proc load_built_ins_into_environment() -> void { | |||
| @@ -128,3 +128,24 @@ | |||
| #define in_caller_env fluid_let( \ | |||
| Globals::Current_Execution::envi_stack.next_index, \ | |||
| Globals::Current_Execution::envi_stack.next_index-1) | |||
| /* | |||
| * iterate over lisp vectors | |||
| */ | |||
| #define for_lisp_vector(v) \ | |||
| if (!v); else \ | |||
| if (int it_index = 0); else \ | |||
| for (auto it = v->value.vector.data; \ | |||
| it_index < v->value.vector.length; \ | |||
| it=v->value.vector.data+(++it_index)) | |||
| /* | |||
| * iterate over lisp lists | |||
| */ | |||
| #define for_lisp_list(l) \ | |||
| if (!l); else \ | |||
| if (int it_index = 0); else \ | |||
| for (Lisp_Object* head = l, *it; \ | |||
| Memory::get_type(head) == Lisp_Object_Type::Pair && (it = head->value.pair.first); \ | |||
| head = head->value.pair.rest, ++it_index) | |||
| @@ -16,41 +16,6 @@ | |||
| # define if_linux if constexpr (true) | |||
| #endif | |||
| /* | |||
| * iterate over lisp vectors | |||
| */ | |||
| #define for_lisp_vector(v) \ | |||
| if (!v); else \ | |||
| if (int it_index = 0); else \ | |||
| for (auto it = v->value.vector.data; \ | |||
| it_index < v->value.vector.length; \ | |||
| it=v->value.vector.data+(++it_index)) | |||
| /* | |||
| * iterate over lisp lists | |||
| */ | |||
| #define for_lisp_list(l) \ | |||
| if (!l); else \ | |||
| if (int it_index = 0); else \ | |||
| for (Lisp_Object* head = l, *it; \ | |||
| Memory::get_type(head) == Lisp_Object_Type::Pair && (it = head->value.pair.first); \ | |||
| head = head->value.pair.rest, ++it_index) | |||
| /* | |||
| #define assert(cond) \ | |||
| if_debug { \ | |||
| if (!cond) { \ | |||
| if (log_level == Log_Level::Debug) { \ | |||
| printf("Assertion failed: %s %d", __FILE__, __LINE__); \ | |||
| } \ | |||
| debug_break(); \ | |||
| } \ | |||
| } else {} \ | |||
| */ | |||
| #define console_normal "\x1B[0m" | |||
| #define console_red "\x1B[31m" | |||
| #define console_green "\x1B[32m" | |||
| @@ -259,9 +259,9 @@ proc create_arguments_from_lambda_list_and_inject(Lisp_Object* arguments, Lisp_O | |||
| result = &function->value.function.args; | |||
| } | |||
| ::new (&(result->positional.symbols)) Array_List<Lisp_Object*>; | |||
| ::new (&(result->keyword.keywords)) Array_List<Lisp_Object*>; | |||
| ::new (&(result->keyword.values)) Array_List<Lisp_Object*>; | |||
| ::new (&result->positional.symbols) Array_List<Lisp_Object*>; | |||
| ::new (&result->keyword.keywords) Array_List<Lisp_Object*>; | |||
| ::new (&result->keyword.values) Array_List<Lisp_Object*>; | |||
| // first init the fields | |||
| // result->positional = create_positional_argument_list(16); | |||
| @@ -1,7 +1,10 @@ | |||
| #define _CRT_SECURE_NO_WARNINGS | |||
| #define _CRT_SECURE_NO_DEPRECATE | |||
| #define _CRTDBG_MAP_ALLOC | |||
| #include <stdlib.h> | |||
| #include <crtdbg.h> | |||
| #include <stdio.h> | |||
| #include <time.h> | |||
| #include <string.h> | |||
| @@ -39,3 +39,9 @@ proc append_to_keyword_argument_list(Keyword_Arguments* args, | |||
| args->keywords.append(keyword); | |||
| args->values.append(default_value); | |||
| } | |||
| Lisp_Object::~Lisp_Object() { | |||
| if (Memory::get_type(this) == Lisp_Object_Type::HashMap) { | |||
| this->value.hashMap.~Hash_Map(); | |||
| } | |||
| } | |||
| @@ -1,10 +1,13 @@ | |||
| #include "libslime.cpp" | |||
| int main(int argc, char* argv[]) { | |||
| if (argc > 1) { | |||
| if (Slime::string_equal(argv[1], "--run-tests")) { | |||
| int res = Slime::run_all_tests(); | |||
| // Slime::interprete_file((char*)"generate-docs.slime"); | |||
| _CrtDumpMemoryLeaks(); | |||
| return res ? 0 : 1; | |||
| } | |||
| @@ -6,6 +6,8 @@ namespace Memory { | |||
| Hash_Map<char*, Lisp_Object*> global_symbol_table; | |||
| Hash_Map<char*, Lisp_Object*> global_keyword_table; | |||
| Hash_Map<char*, Environment*> file_to_env_map; | |||
| // ------------------ | |||
| // lisp_objects | |||
| // ------------------ | |||
| @@ -177,13 +179,23 @@ namespace Memory { | |||
| free_spots_in_string_memory.next_index = 0; | |||
| ::new((&global_symbol_table)) Hash_Map<char*, Lisp_Object*>; | |||
| ::new((&global_keyword_table)) Hash_Map<char*, Lisp_Object*>; | |||
| global_symbol_table.~Hash_Map(); | |||
| global_keyword_table.~Hash_Map(); | |||
| file_to_env_map.~Hash_Map(); | |||
| ::new(&global_symbol_table) Hash_Map<char*, Lisp_Object*>; | |||
| ::new(&global_keyword_table) Hash_Map<char*, Lisp_Object*>; | |||
| ::new(&file_to_env_map) Hash_Map<char*, Lisp_Object*>; | |||
| try_void Parser::standard_in = create_string("stdin"); | |||
| object_memory.reset(); | |||
| environment_memory.reset(); | |||
| object_memory.~Bucket_Allocator(); | |||
| // environment_memory.~Bucket_Allocator(); | |||
| ::new(&object_memory) Bucket_Allocator<Lisp_Object, 1024>; | |||
| ::new(&environment_memory) Bucket_Allocator<Environment, 1024>; | |||
| next_free_spot_in_string_memory = string_memory; | |||
| @@ -373,7 +385,7 @@ namespace Memory { | |||
| return copy_lisp_object(n); | |||
| } | |||
| proc create_child_environment(Environment* parent) -> Environment* { | |||
| proc create_child_environment(Environment* parent) -> Environment* { | |||
| Environment* env = environment_memory.allocate(); | |||
| @@ -404,7 +416,7 @@ namespace Memory { | |||
| try load_built_ins_into_environment(); | |||
| built_in_load(Memory::create_string("pre.slime")); | |||
| try built_in_load(Memory::create_string("pre.slime")); | |||
| return ret; | |||
| } | |||
| @@ -98,7 +98,6 @@ namespace Parser { | |||
| // get the atom | |||
| String* ret = Memory::create_string("", atom_length); | |||
| // char* atom = (char*)malloc(atom_length*sizeof(char)+1); // plus null char | |||
| strcpy(&ret->data, text+(*index_in_text)); | |||
| // restore the original string | |||
| @@ -448,7 +447,7 @@ namespace Parser { | |||
| } | |||
| proc write_expanded_file(String* file_name, Array_List<Lisp_Object*> 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)); | |||
| @@ -465,21 +464,21 @@ namespace Parser { | |||
| exit(1); | |||
| } | |||
| for (int i = 0; i < program.next_index; ++i) { | |||
| for (int i = 0; i < program->next_index; ++i) { | |||
| // a macro will parse as nil for now, so we skip those | |||
| if (program.data[i] == Memory::nil) | |||
| if (program->data[i] == Memory::nil) | |||
| continue; | |||
| print(program.data[i], true, f); | |||
| print(program->data[i], true, f); | |||
| fprintf(f, "\n\n"); | |||
| } | |||
| } | |||
| proc parse_program(String* file_name, char* text) -> Array_List<Lisp_Object*> { | |||
| proc parse_program(String* file_name, char* text) -> Array_List<Lisp_Object*>* { | |||
| parser_file = file_name; | |||
| parser_line = 1; | |||
| parser_col = 0; | |||
| Array_List<Lisp_Object*> program; | |||
| Array_List<Lisp_Object*>* program = new Array_List<Lisp_Object*>; | |||
| int index_in_text = 0; | |||
| @@ -490,7 +489,7 @@ namespace Parser { | |||
| try_struct { | |||
| parsed = parse_expression(text, &index_in_text); | |||
| } | |||
| program.append(parsed); | |||
| program->append(parsed); | |||
| } break; | |||
| case ';': | |||
| case ' ': | |||
| @@ -103,6 +103,11 @@ struct Arguments { | |||
| struct Environment { | |||
| Array_List<Environment*> parents; | |||
| Hash_Map<void*, Lisp_Object*> hm; | |||
| ~Environment() { | |||
| parents.~Array_List(); | |||
| hm.~Hash_Map(); | |||
| } | |||
| }; | |||
| struct Function { | |||
| @@ -123,7 +128,7 @@ struct Lisp_Object { | |||
| u64 flags; | |||
| Lisp_Object* userType; // keyword | |||
| String* docstring; | |||
| union { | |||
| union value { | |||
| Symbol symbol; // used for symbols and keywords | |||
| double number; | |||
| String* string; | |||
| @@ -134,7 +139,9 @@ struct Lisp_Object { | |||
| void* pointer; | |||
| Continuation continuation; | |||
| Hash_Map<Lisp_Object*, Lisp_Object*> hashMap; | |||
| ~value() {} | |||
| } value; | |||
| ~Lisp_Object(); | |||
| }; | |||
| struct Error { | |||
| @@ -596,7 +596,7 @@ proc test_file(const char* file) -> testresult { | |||
| pop_environment(); | |||
| }; | |||
| built_in_load(Memory::create_string(file)); | |||
| try built_in_load(Memory::create_string(file)); | |||
| assert_no_error(); | |||
| return pass; | |||
| @@ -654,6 +654,7 @@ proc run_all_tests() -> bool { | |||
| invoke_test_script("automata"); | |||
| invoke_test_script("sicp"); | |||
| invoke_test_script("hashmaps"); | |||
| invoke_test_script("singular_imports"); | |||
| // Memory::print_status(); | |||