| @@ -34,4 +34,6 @@ | |||||
| (c++-mode . ((eval . (company-clang-set-prefix "slime.h")) | (c++-mode . ((eval . (company-clang-set-prefix "slime.h")) | ||||
| (eval . (flycheck-mode 0)) | (eval . (flycheck-mode 0)) | ||||
| (eval . (company-mode 0)) | |||||
| (eval . (rainbow-mode 0)) | |||||
| (eval . (setq c-backslash-max-column 99))))) | (eval . (setq c-backslash-max-column 99))))) | ||||
| @@ -1 +1 @@ | |||||
| Subproject commit f35d5c6d900447fc8d29e68abe4838b788f067b9 | |||||
| Subproject commit 07e89f384155abd4ec231edc173ce0d03244b1cf | |||||
| @@ -0,0 +1,36 @@ | |||||
| (define add-5 '()) | |||||
| (define res 1) | |||||
| (mutate! res (+ 2 (call/cc (lambda (cont) (set! add-5 cont) 1)) 3)) | |||||
| (assert (= res 6)) | |||||
| (add-5 100) | |||||
| (assert (= res 105)) | |||||
| (add-5 10) | |||||
| (assert (= res 15)) | |||||
| ;; ----------- works until here --------------- | |||||
| (set! res (+ 2 (call/cc (lambda (cont) (set! add-5 cont) 1)) 3)) | |||||
| ;; (print) | |||||
| ;; (print res 6) | |||||
| (assert (= res 6)) | |||||
| (add-5 100) | |||||
| ;; (print res 105) | |||||
| (assert (= res 105)) | |||||
| (add-5 10) | |||||
| (assert (= res 15)) | |||||
| ;; (print res 15) | |||||
| ;; (define fun '()) | |||||
| ;; (mutate! res (apply (call/cc (lambda (k) (set! fun k) +)) (list 1 2 3))) | |||||
| ;; (assert (= res 6)) | |||||
| ;; (fun -) | |||||
| ;; (assert (= res -1)) | |||||
| @@ -3,7 +3,8 @@ | |||||
| (define (make-counter) | (define (make-counter) | ||||
| (let ((var 0)) | (let ((var 0)) | ||||
| (lambda () | (lambda () | ||||
| (set! var (+ 1 var))))) | |||||
| (set! var (+ 1 var)) | |||||
| var))) | |||||
| (define counter1 (make-counter)) | (define counter1 (make-counter)) | ||||
| @@ -1 +1,7 @@ | |||||
| ;; (define (empty-function-body-test)) | |||||
| (define (empty-function-body-test)) | |||||
| ;; test that arguments to apply are only evaled once | |||||
| (define counter 0) | |||||
| (assert (= (apply (lambda (x) x) (begin (mutate! counter (+ 1 counter)) (list +))) | |||||
| +)) | |||||
| (assert (= counter 1)) | |||||
| @@ -7,9 +7,9 @@ set exeName=slime.exe | |||||
| taskkill /F /IM %exeName% > NUL 2> NUL | taskkill /F /IM %exeName% > NUL 2> NUL | ||||
| echo ---------- Compiling ---------- | echo ---------- Compiling ---------- | ||||
| call cl ^ | |||||
| call clang-cl ^ | |||||
| ../src/main.cpp^ | ../src/main.cpp^ | ||||
| /I../3rd/ /DEBUG:FULL ^ | |||||
| /I../3rd/ ^ | |||||
| /D_PROFILING /D_DEBUG /D_DONT_BREAK_ON_ERRORS ^ | /D_PROFILING /D_DEBUG /D_DONT_BREAK_ON_ERRORS ^ | ||||
| /Zi /std:c++latest /Fe%exeName% /W3 /wd4003 /wd4996 /nologo /EHsc | /Zi /std:c++latest /Fe%exeName% /W3 /wd4003 /wd4996 /nologo /EHsc | ||||
| @@ -149,49 +149,130 @@ namespace Slime { | |||||
| String file_name_built_ins = Memory::create_string(__FILE__); | String file_name_built_ins = Memory::create_string(__FILE__); | ||||
| defer_free(file_name_built_ins.data); | defer_free(file_name_built_ins.data); | ||||
| define_macro((call/cc fun), "TODO") { | |||||
| profile_with_name("(call/cc)"); | |||||
| using Globals::Current_Execution; | |||||
| Lisp_Object* args = Current_Execution.pcs[--Current_Execution.pcs.next_index]; | |||||
| try_void assert_list_length(args, 1); | |||||
| Lisp_Object* fun = args->value.pair.first; | |||||
| // 2. push cont on the stack and call, the fun is already | |||||
| // there | |||||
| Current_Execution.ats.append([] { | |||||
| try_void assert_type(Current_Execution.cs.data[Current_Execution.cs.next_index-1] | |||||
| , Lisp_Object_Type::Function); | |||||
| Lisp_Object* cont = Memory::create_lisp_object_continuation(); | |||||
| Current_Execution.ams.append(Current_Execution.cs.next_index-1); | |||||
| Current_Execution.pcs.append(Memory::nil); | |||||
| --cont->value.continuation->cs.next_index; | |||||
| Current_Execution.cs.append(cont); | |||||
| (Current_Execution.nass.end()-1)->append(NasAction::Step); | |||||
| }); | |||||
| (Current_Execution.nass.end()-1)->append(NasAction::And_Then_Action); | |||||
| // 1. resolve the function | |||||
| Current_Execution.cs.append(fun); | |||||
| (Current_Execution.nass.end()-1)->append(NasAction::Eval); | |||||
| }; | |||||
| define_macro((set! sym val), "TODO") { | |||||
| // NOTE(Felix): This COULD be a define_special in theory, | |||||
| // but because of call/cc, it cannot be anymore because | |||||
| // the define_symbol would not be a part of the | |||||
| // continuation. This happens for example in: | |||||
| /** | |||||
| (set! res (+ 2 (call/cc (lambda (cont) | |||||
| (set! add-5 cont) 1)) | |||||
| 3)) | |||||
| */ | |||||
| // So if 'set! WAS a define_special, then the param would | |||||
| // not be evaluated, but the whole call gets removed from | |||||
| // the stack, and in the body of 'set!, the 'val would be | |||||
| // recursively evaluated, and the 'call/cc would not see | |||||
| // the variable definition as part of the continuation. So | |||||
| // what we do istead, is writing 'set! as a macro and have | |||||
| // the variable definition as a and_then_action, so that | |||||
| // it is part of the continuation. | |||||
| profile_with_name("(set!)"); | |||||
| using Globals::Current_Execution; | |||||
| Lisp_Object* args = Current_Execution.pcs[--Current_Execution.pcs.next_index]; | |||||
| try_void assert_list_length(args, 2); | |||||
| Lisp_Object* sym = args->value.pair.first; | |||||
| Lisp_Object* val = args->value.pair.rest->value.pair.first; | |||||
| try_void assert_type(sym, Lisp_Object_Type::Symbol); | |||||
| // 2. find the binding and rebind | |||||
| Current_Execution.cs.append(sym); | |||||
| Current_Execution.ats.append([] { | |||||
| using Globals::Current_Execution; | |||||
| Lisp_Object* val = Current_Execution.cs.data[--Current_Execution.cs.next_index]; | |||||
| Lisp_Object* sym = Current_Execution.cs.data[Current_Execution.cs.next_index-1]; | |||||
| Environment* target_env = find_binding_environment(sym, get_current_environment()); | |||||
| if (!target_env) | |||||
| target_env = get_root_environment(); | |||||
| define_symbol(sym, val, target_env); | |||||
| }); | |||||
| (Current_Execution.nass.end()-1)->append(NasAction::And_Then_Action); | |||||
| // 1. eval the val | |||||
| Current_Execution.cs.append(val); | |||||
| (Current_Execution.nass.end()-1)->append(NasAction::Eval); | |||||
| }; | |||||
| define_macro((apply fun fun_args), "TODO") { | define_macro((apply fun fun_args), "TODO") { | ||||
| // NOTE(Felix): is has to be a macro because apply by | // NOTE(Felix): is has to be a macro because apply by | ||||
| // itself cannot return the result, we have to invoke eval | // itself cannot return the result, we have to invoke eval | ||||
| // and to prevent recursion, apply is a macro | // and to prevent recursion, apply is a macro | ||||
| profile_with_name("(apply)"); | profile_with_name("(apply)"); | ||||
| using namespace Globals::Current_Execution; | |||||
| using Globals::Current_Execution; | |||||
| Lisp_Object* args = pcs[--pcs.next_index]; | |||||
| Lisp_Object* args = Current_Execution.pcs[--Current_Execution.pcs.next_index]; | |||||
| try_void assert_list_length(args, 2); | try_void assert_list_length(args, 2); | ||||
| Lisp_Object* fun = args->value.pair.first; | Lisp_Object* fun = args->value.pair.first; | ||||
| Lisp_Object* fun_args = args->value.pair.rest->value.pair.first; | Lisp_Object* fun_args = args->value.pair.rest->value.pair.first; | ||||
| // 3. push args on the stack and apply | // 3. push args on the stack and apply | ||||
| ats.append([] { | |||||
| Lisp_Object* args_as_list = cs[--cs.next_index]; | |||||
| Current_Execution.ats.append([] { | |||||
| // BUG(Felix): we are not pushing on the ams, are we | |||||
| // doing it wrong? | |||||
| // Current_Execution.ams.append(Current_Execution.cs.next_index-2); | |||||
| Lisp_Object* args_as_list = Current_Execution.cs[--Current_Execution.cs.next_index]; | |||||
| for_lisp_list (args_as_list) { | for_lisp_list (args_as_list) { | ||||
| cs.append(it); | |||||
| Current_Execution.cs.append(it); | |||||
| } | } | ||||
| pcs.append(Memory::nil); | |||||
| (nass.end()-1)->append(NasAction::Step); | |||||
| Current_Execution.pcs.append(Memory::nil); | |||||
| (Current_Execution.nass.end()-1)->append(NasAction::Step); | |||||
| }); | }); | ||||
| (nass.end()-1)->append(NasAction::And_Then_Action); | |||||
| (Current_Execution.nass.end()-1)->append(NasAction::And_Then_Action); | |||||
| // 2. Eval fun_args and keep them on the stack | // 2. Eval fun_args and keep them on the stack | ||||
| ats.append([] { | |||||
| Current_Execution.ats.append([] { | |||||
| // NOTE(Felix): Flip the top 2 elements on cs because | // NOTE(Felix): Flip the top 2 elements on cs because | ||||
| // top is now the evaluated function, and below is the unevaluated args | // top is now the evaluated function, and below is the unevaluated args | ||||
| Lisp_Object* tmp = cs[cs.next_index-1]; | |||||
| cs[cs.next_index-1] = cs[cs.next_index-2]; | |||||
| cs[cs.next_index-2] = tmp; | |||||
| (nass.end()-1)->append(NasAction::Eval); | |||||
| Lisp_Object* tmp = Current_Execution.cs[Current_Execution.cs.next_index-1]; | |||||
| Current_Execution.cs[Current_Execution.cs.next_index-1] = Current_Execution.cs[Current_Execution.cs.next_index-2]; | |||||
| Current_Execution.cs[Current_Execution.cs.next_index-2] = tmp; | |||||
| (Current_Execution.nass.end()-1)->append(NasAction::Eval); | |||||
| }); | }); | ||||
| (nass.end()-1)->append(NasAction::And_Then_Action); | |||||
| (Current_Execution.nass.end()-1)->append(NasAction::And_Then_Action); | |||||
| // 1. Eval function and keep it on the stack, below it | // 1. Eval function and keep it on the stack, below it | ||||
| // store the unevaluated argument list | // store the unevaluated argument list | ||||
| ams.append(cs.next_index); | |||||
| cs.append(fun_args); | |||||
| cs.append(fun); | |||||
| (nass.end()-1)->append(NasAction::Eval); | |||||
| Current_Execution.ams.append(Current_Execution.cs.next_index); | |||||
| Current_Execution.cs.append(fun_args); | |||||
| Current_Execution.cs.append(fun); | |||||
| (Current_Execution.nass.end()-1)->append(NasAction::Eval); | |||||
| }; | }; | ||||
| define((get-counter), | define((get-counter), | ||||
| @@ -215,12 +296,12 @@ namespace Slime { | |||||
| "Takes one argument, and evaluates it two times.") | "Takes one argument, and evaluates it two times.") | ||||
| { | { | ||||
| profile_with_name("(eval)"); | profile_with_name("(eval)"); | ||||
| using namespace Globals::Current_Execution; | |||||
| using Globals::Current_Execution; | |||||
| // we know cs.data[cs.next_index] is allocated because the | // we know cs.data[cs.next_index] is allocated because the | ||||
| // macro cal lwas there just before | // macro cal lwas there just before | ||||
| cs.data[cs.next_index++] = pcs[--pcs.next_index]->value.pair.first; | |||||
| (nass.end()-1)->append(NasAction::Eval); | |||||
| (nass.end()-1)->append(NasAction::Eval); | |||||
| Current_Execution.cs.data[Current_Execution.cs.next_index++] = Current_Execution.pcs[--Current_Execution.pcs.next_index]->value.pair.first; | |||||
| (Current_Execution.nass.end()-1)->append(NasAction::Eval); | |||||
| (Current_Execution.nass.end()-1)->append(NasAction::Eval); | |||||
| }; | }; | ||||
| define_macro((begin . rest), | define_macro((begin . rest), | ||||
| @@ -228,18 +309,18 @@ namespace Slime { | |||||
| "and returns the last result.") | "and returns the last result.") | ||||
| { | { | ||||
| profile_with_name("(begin)"); | profile_with_name("(begin)"); | ||||
| using namespace Globals::Current_Execution; | |||||
| Lisp_Object* args = pcs[--pcs.next_index]; | |||||
| using Globals::Current_Execution; | |||||
| Lisp_Object* args = Current_Execution.pcs[--Current_Execution.pcs.next_index]; | |||||
| u32 length = list_length(args); | u32 length = list_length(args); | ||||
| cs.reserve(length); | |||||
| Current_Execution.cs.reserve(length); | |||||
| for_lisp_list(args) { | for_lisp_list(args) { | ||||
| cs.data[cs.next_index - 1 + (length - it_index)] = it; | |||||
| (nass.end()-1)->append(NasAction::Eval); | |||||
| (nass.end()-1)->append(NasAction::Pop); | |||||
| Current_Execution.cs.data[Current_Execution.cs.next_index - 1 + (length - it_index)] = it; | |||||
| (Current_Execution.nass.end()-1)->append(NasAction::Eval); | |||||
| (Current_Execution.nass.end()-1)->append(NasAction::Pop); | |||||
| } | } | ||||
| --(nass.end()-1)->next_index; | |||||
| cs.next_index += length; | |||||
| --(Current_Execution.nass.end()-1)->next_index; | |||||
| Current_Execution.cs.next_index += length; | |||||
| }; | }; | ||||
| define_macro((if test then_part else_part), | define_macro((if test then_part else_part), | ||||
| "Takes 3 arguments. If the first arguments evaluates to a truthy " | "Takes 3 arguments. If the first arguments evaluates to a truthy " | ||||
| @@ -247,12 +328,12 @@ namespace Slime { | |||||
| "it will evaluete the third one and return them respectively.") | "it will evaluete the third one and return them respectively.") | ||||
| { | { | ||||
| profile_with_name("(if)"); | profile_with_name("(if)"); | ||||
| using namespace Globals::Current_Execution; | |||||
| using Globals::Current_Execution; | |||||
| /* | | | <test> | | /* | | | <test> | | ||||
| | | -> | <then> | | | | -> | <then> | | ||||
| | <if> | | <else> | | | <if> | | <else> | | ||||
| | .... | | ...... | */ | | .... | | ...... | */ | ||||
| Lisp_Object* args = pcs.data[--pcs.next_index]; | |||||
| Lisp_Object* args = Current_Execution.pcs.data[--Current_Execution.pcs.next_index]; | |||||
| Lisp_Object* test = args->value.pair.first; | Lisp_Object* test = args->value.pair.first; | ||||
| args = args->value.pair.rest; | args = args->value.pair.rest; | ||||
| try_void assert_type(args, Lisp_Object_Type::Pair); | try_void assert_type(args, Lisp_Object_Type::Pair); | ||||
| @@ -263,14 +344,13 @@ namespace Slime { | |||||
| args = args->value.pair.rest; | args = args->value.pair.rest; | ||||
| try_void assert_type(args, Lisp_Object_Type::Nil); | try_void assert_type(args, Lisp_Object_Type::Nil); | ||||
| cs.append(alternative); | |||||
| cs.append(consequence); | |||||
| cs.append(test); | |||||
| (nass.end()-1)->append(NasAction::Eval); | |||||
| (nass.end()-1)->append(NasAction::If); | |||||
| (nass.end()-1)->append(NasAction::Eval); | |||||
| Current_Execution.cs.append(alternative); | |||||
| Current_Execution.cs.append(consequence); | |||||
| Current_Execution.cs.append(test); | |||||
| (Current_Execution.nass.end()-1)->append(NasAction::Eval); | |||||
| (Current_Execution.nass.end()-1)->append(NasAction::If); | |||||
| (Current_Execution.nass.end()-1)->append(NasAction::Eval); | |||||
| }; | }; | ||||
| define_macro((define definee . args), "") { | define_macro((define definee . args), "") { | ||||
| // NOTE(Felix): define has to be a macro, because we need | // NOTE(Felix): define has to be a macro, because we need | ||||
| @@ -279,9 +359,9 @@ namespace Slime { | |||||
| // want to recursivly evaluate the value, we use a macro | // want to recursivly evaluate the value, we use a macro | ||||
| // and a NasAction. | // and a NasAction. | ||||
| profile_with_name("(define)"); | profile_with_name("(define)"); | ||||
| using namespace Globals::Current_Execution; | |||||
| using Globals::Current_Execution; | |||||
| Lisp_Object* form = pcs.data[--pcs.next_index]; | |||||
| Lisp_Object* form = Current_Execution.pcs.data[--Current_Execution.pcs.next_index]; | |||||
| Lisp_Object* definee = form->value.pair.first; | Lisp_Object* definee = form->value.pair.first; | ||||
| form = form->value.pair.rest; | form = form->value.pair.rest; | ||||
| if (definee->type == Lisp_Object_Type::Symbol) { | if (definee->type == Lisp_Object_Type::Symbol) { | ||||
| @@ -302,10 +382,10 @@ namespace Slime { | |||||
| // TODO docs (maybe with hooks) we have to attach | // TODO docs (maybe with hooks) we have to attach | ||||
| // the docs to the result of evaluating | // the docs to the result of evaluating | ||||
| } | } | ||||
| cs.append(definee); | |||||
| cs.append(thing); | |||||
| (nass.end()-1)->append(NasAction::Define_Var); | |||||
| (nass.end()-1)->append(NasAction::Eval); | |||||
| Current_Execution.cs.append(definee); | |||||
| Current_Execution.cs.append(thing); | |||||
| (Current_Execution.nass.end()-1)->append(NasAction::Define_Var); | |||||
| (Current_Execution.nass.end()-1)->append(NasAction::Eval); | |||||
| } break; | } break; | ||||
| case Lisp_Object_Type::Pair: { | case Lisp_Object_Type::Pair: { | ||||
| try_void assert_type(definee->value.pair.first, Lisp_Object_Type::Symbol); | try_void assert_type(definee->value.pair.first, Lisp_Object_Type::Symbol); | ||||
| @@ -331,7 +411,7 @@ namespace Slime { | |||||
| func->value.function->body.lisp_body = maybe_wrap_body_in_begin(thing_cons); | func->value.function->body.lisp_body = maybe_wrap_body_in_begin(thing_cons); | ||||
| define_symbol(definee->value.pair.first, func); | define_symbol(definee->value.pair.first, func); | ||||
| cs.append(definee->value.pair.first); | |||||
| Current_Execution.cs.append(definee->value.pair.first); | |||||
| } break; | } break; | ||||
| default: { | default: { | ||||
| create_generic_error("you can only define symbols"); | create_generic_error("you can only define symbols"); | ||||
| @@ -356,7 +436,7 @@ namespace Slime { | |||||
| define_special((with-debug-log . rest), "") { | define_special((with-debug-log . rest), "") { | ||||
| profile_with_name("(enable-debug-log)"); | profile_with_name("(enable-debug-log)"); | ||||
| fetch(rest); | fetch(rest); | ||||
| Lisp_Object* result; | |||||
| Lisp_Object* result = Memory::nil; | |||||
| Globals::debug_log = true; | Globals::debug_log = true; | ||||
| in_caller_env { | in_caller_env { | ||||
| for_lisp_list(rest) { | for_lisp_list(rest) { | ||||
| @@ -679,26 +759,6 @@ namespace Slime { | |||||
| return val; | return val; | ||||
| }; | }; | ||||
| define_special((set! sym val), "TODO") { | |||||
| profile_with_name("(set!)"); | |||||
| fetch(sym, val); | |||||
| try assert_type(sym, Lisp_Object_Type::Symbol); | |||||
| Environment* target_env; | |||||
| in_caller_env { | |||||
| val = eval_expr(val); | |||||
| target_env = find_binding_environment(sym, get_current_environment()); | |||||
| if (!target_env) | |||||
| target_env = get_root_environment(); | |||||
| } | |||||
| push_environment(target_env); | |||||
| define_symbol(sym, val); | |||||
| pop_environment(); | |||||
| return val; | |||||
| }; | |||||
| define((set-car! target source), "TODO") { | define((set-car! target source), "TODO") { | ||||
| profile_with_name("(set-car!)"); | profile_with_name("(set-car!)"); | ||||
| fetch(target, source); | fetch(target, source); | ||||
| @@ -1108,12 +1168,12 @@ namespace Slime { | |||||
| fetch(sep, end, repr, things); | fetch(sep, end, repr, things); | ||||
| if (things != Memory::nil) { | if (things != Memory::nil) { | ||||
| bool print_repr = repr != Memory::nil; | |||||
| print(things->value.pair.first, repr); | |||||
| bool print_repr = (repr != Memory::nil); | |||||
| print(things->value.pair.first, print_repr); | |||||
| for_lisp_list(things->value.pair.rest) { | for_lisp_list(things->value.pair.rest) { | ||||
| print(sep); | print(sep); | ||||
| print(it, repr); | |||||
| print(it, print_repr); | |||||
| } | } | ||||
| } | } | ||||
| @@ -130,8 +130,8 @@ | |||||
| #define define_macro(def, docs) _define_helper(def, docs, Slime::C_Function_Type::cMacro, c_macro_body = []() -> void) | #define define_macro(def, docs) _define_helper(def, docs, Slime::C_Function_Type::cMacro, c_macro_body = []() -> void) | ||||
| #define in_caller_env fluid_let( \ | #define in_caller_env fluid_let( \ | ||||
| Globals::Current_Execution::envi_stack.next_index, \ | |||||
| Globals::Current_Execution::envi_stack.next_index-1) | |||||
| Globals::Current_Execution.envi_stack.next_index, \ | |||||
| Globals::Current_Execution.envi_stack.next_index-1) | |||||
| /* | /* | ||||
| @@ -54,23 +54,20 @@ namespace Slime { | |||||
| } | } | ||||
| inline proc push_environment(Environment* env) -> void { | inline proc push_environment(Environment* env) -> void { | ||||
| using namespace Globals::Current_Execution; | |||||
| envi_stack.append(env); | |||||
| Globals::Current_Execution.envi_stack.append(env); | |||||
| } | } | ||||
| inline proc pop_environment() -> void { | inline proc pop_environment() -> void { | ||||
| using namespace Globals::Current_Execution; | |||||
| --envi_stack.next_index; | |||||
| --Globals::Current_Execution.envi_stack.next_index; | |||||
| } | } | ||||
| inline proc get_root_environment() -> Environment* { | inline proc get_root_environment() -> Environment* { | ||||
| using namespace Globals::Current_Execution; | |||||
| return envi_stack.data[0]; | |||||
| return Globals::Current_Execution.envi_stack.data[0]; | |||||
| } | } | ||||
| inline proc get_current_environment() -> Environment* { | inline proc get_current_environment() -> Environment* { | ||||
| using namespace Globals::Current_Execution; | |||||
| return envi_stack.data[envi_stack.next_index-1]; | |||||
| return Globals::Current_Execution.envi_stack.data[ | |||||
| Globals::Current_Execution.envi_stack.next_index-1]; | |||||
| } | } | ||||
| proc lookup_symbol(Lisp_Object* node, Environment* env) -> Lisp_Object* { | proc lookup_symbol(Lisp_Object* node, Environment* env) -> Lisp_Object* { | ||||
| @@ -10,17 +10,17 @@ namespace Slime { | |||||
| proc create_error(const char* c_func_name, const char* c_file_name, | proc create_error(const char* c_func_name, const char* c_file_name, | ||||
| u32 c_file_line, Lisp_Object* type, String message) -> void | u32 c_file_line, Lisp_Object* type, String message) -> void | ||||
| { | { | ||||
| delete_error(); | |||||
| if (Globals::breaking_on_errors) { | |||||
| debug_break(); | |||||
| } | |||||
| using Globals::error; | using Globals::error; | ||||
| delete_error(); | |||||
| error = (Error*)malloc(sizeof(Error)) ; | error = (Error*)malloc(sizeof(Error)) ; | ||||
| error->type = type; | error->type = type; | ||||
| error->message = message; | error->message = message; | ||||
| log_error(); | log_error(); | ||||
| if (Globals::breaking_on_errors) { | |||||
| debug_break(); | |||||
| } | |||||
| if (Globals::log_level > Log_Level::None) { | if (Globals::log_level > Log_Level::None) { | ||||
| // c error location | // c error location | ||||
| printf("in"); | printf("in"); | ||||
| @@ -6,7 +6,7 @@ namespace Slime { | |||||
| u32 arg_end) -> Environment* | u32 arg_end) -> Environment* | ||||
| { | { | ||||
| profile_this(); | profile_this(); | ||||
| using namespace Globals::Current_Execution; | |||||
| using Globals::Current_Execution; | |||||
| u32 index_of_next_arg = arg_start; | u32 index_of_next_arg = arg_start; | ||||
| bool is_c_function = function->value.function->is_c; | bool is_c_function = function->value.function->is_c; | ||||
| @@ -41,9 +41,9 @@ namespace Slime { | |||||
| // programmers to know what they are doing. Bold claim I | // programmers to know what they are doing. Bold claim I | ||||
| // know. | // know. | ||||
| if (is_c_function) { | if (is_c_function) { | ||||
| define_symbol(arg_spec->positional.symbols.data[i], cs.data[index_of_next_arg], env); | |||||
| define_symbol(arg_spec->positional.symbols.data[i], Current_Execution.cs.data[index_of_next_arg], env); | |||||
| } else { | } else { | ||||
| define_symbol(arg_spec->positional.symbols.data[i], Memory::copy_lisp_object_except_pairs(cs.data[index_of_next_arg]), env); | |||||
| define_symbol(arg_spec->positional.symbols.data[i], Memory::copy_lisp_object_except_pairs(Current_Execution.cs.data[index_of_next_arg]), env); | |||||
| } | } | ||||
| ++index_of_next_arg; | ++index_of_next_arg; | ||||
| } | } | ||||
| @@ -56,11 +56,11 @@ namespace Slime { | |||||
| ++obligatory_keywords_count; | ++obligatory_keywords_count; | ||||
| } | } | ||||
| while (cs.data[index_of_next_arg]->type == Lisp_Object_Type::Keyword) { | |||||
| while (Current_Execution.cs.data[index_of_next_arg]->type == Lisp_Object_Type::Keyword) { | |||||
| // check if this one is even an accepted keyword | // check if this one is even an accepted keyword | ||||
| bool accepted = false; | bool accepted = false; | ||||
| for (u32 i = 0; i < arg_spec->keyword.keywords.next_index; ++i) { | for (u32 i = 0; i < arg_spec->keyword.keywords.next_index; ++i) { | ||||
| if (cs.data[index_of_next_arg] == arg_spec->keyword.keywords.data[i]) { | |||||
| if (Current_Execution.cs.data[index_of_next_arg] == arg_spec->keyword.keywords.data[i]) { | |||||
| accepted = true; | accepted = true; | ||||
| break; | break; | ||||
| } | } | ||||
| @@ -75,13 +75,13 @@ namespace Slime { | |||||
| "The function does not take the keyword argument ':%s'\n" | "The function does not take the keyword argument ':%s'\n" | ||||
| "and not all required keyword arguments have been read\n" | "and not all required keyword arguments have been read\n" | ||||
| "in to potentially count it as the rest argument.", | "in to potentially count it as the rest argument.", | ||||
| cs.data[index_of_next_arg]->value.symbol.data); | |||||
| Current_Execution.cs.data[index_of_next_arg]->value.symbol.data); | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| // This is an accepted kwarg; check if it was already | // This is an accepted kwarg; check if it was already | ||||
| // read in | // read in | ||||
| for (u32 i = 0; i < read_in_keywords.next_index; ++i) { | for (u32 i = 0; i < read_in_keywords.next_index; ++i) { | ||||
| if (cs.data[index_of_next_arg] == read_in_keywords.data[i]) | |||||
| if (Current_Execution.cs.data[index_of_next_arg] == read_in_keywords.data[i]) | |||||
| { | { | ||||
| // if we already read it in but also finished | // if we already read it in but also finished | ||||
| // all other kwargs, then count it as rest and | // all other kwargs, then count it as rest and | ||||
| @@ -92,7 +92,7 @@ namespace Slime { | |||||
| // in, it is an error | // in, it is an error | ||||
| create_generic_error( | create_generic_error( | ||||
| "The function already read the keyword argument ':%s'", | "The function already read the keyword argument ':%s'", | ||||
| cs.data[index_of_next_arg]->value.symbol.data); | |||||
| Current_Execution.cs.data[index_of_next_arg]->value.symbol.data); | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| } | } | ||||
| @@ -102,19 +102,19 @@ namespace Slime { | |||||
| if (index_of_next_arg+1 == arg_end) { | if (index_of_next_arg+1 == arg_end) { | ||||
| create_generic_error( | create_generic_error( | ||||
| "Attempting to set the keyword argument ':%s', but no value was supplied.", | "Attempting to set the keyword argument ':%s', but no value was supplied.", | ||||
| cs.data[index_of_next_arg]->value.symbol.data); | |||||
| Current_Execution.cs.data[index_of_next_arg]->value.symbol.data); | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| // if not set it and then add it to the array list | // if not set it and then add it to the array list | ||||
| Lisp_Object* key = cs.data[index_of_next_arg]; | |||||
| Lisp_Object* key = Current_Execution.cs.data[index_of_next_arg]; | |||||
| try sym = Memory::get_symbol(key->value.symbol); | try sym = Memory::get_symbol(key->value.symbol); | ||||
| ++index_of_next_arg; | ++index_of_next_arg; | ||||
| if (is_c_function) { | if (is_c_function) { | ||||
| try define_symbol(sym, cs.data[index_of_next_arg], env); | |||||
| try define_symbol(sym, Current_Execution.cs.data[index_of_next_arg], env); | |||||
| } else { | } else { | ||||
| try define_symbol(sym, Memory::copy_lisp_object_except_pairs(cs.data[index_of_next_arg]), env); | |||||
| try define_symbol(sym, Memory::copy_lisp_object_except_pairs(Current_Execution.cs.data[index_of_next_arg]), env); | |||||
| } | } | ||||
| read_in_keywords.append(key); | read_in_keywords.append(key); | ||||
| @@ -171,10 +171,10 @@ namespace Slime { | |||||
| } else { | } else { | ||||
| if (arg_spec->rest) { | if (arg_spec->rest) { | ||||
| Lisp_Object* list; | Lisp_Object* list; | ||||
| try list = Memory::create_list(cs.data[index_of_next_arg]); | |||||
| try list = Memory::create_list(Current_Execution.cs.data[index_of_next_arg]); | |||||
| Lisp_Object* head = list; | Lisp_Object* head = list; | ||||
| for (++index_of_next_arg;index_of_next_arg < arg_end; ++index_of_next_arg) { | for (++index_of_next_arg;index_of_next_arg < arg_end; ++index_of_next_arg) { | ||||
| try head->value.pair.rest = Memory::create_list(cs.data[index_of_next_arg]); | |||||
| try head->value.pair.rest = Memory::create_list(Current_Execution.cs.data[index_of_next_arg]); | |||||
| head = head->value.pair.rest; | head = head->value.pair.rest; | ||||
| } | } | ||||
| define_symbol(arg_spec->rest, list, env); | define_symbol(arg_spec->rest, list, env); | ||||
| @@ -313,13 +313,13 @@ namespace Slime { | |||||
| proc eval_expr(Lisp_Object* expr) -> Lisp_Object* { | proc eval_expr(Lisp_Object* expr) -> Lisp_Object* { | ||||
| profile_this(); | profile_this(); | ||||
| using namespace Globals::Current_Execution; | |||||
| using Globals::Current_Execution; | |||||
| nass.reserve(1); | |||||
| Array_List<NasAction>* nas = nass.data+(nass.next_index++); | |||||
| Current_Execution.nass.reserve(1); | |||||
| Array_List<NasAction>* nas = Current_Execution.nass.data+(Current_Execution.nass.next_index++); | |||||
| nas->alloc(); | nas->alloc(); | ||||
| defer { | defer { | ||||
| --nass.next_index; | |||||
| --Current_Execution.nass.next_index; | |||||
| nas->dealloc(); | nas->dealloc(); | ||||
| }; | }; | ||||
| @@ -332,13 +332,13 @@ namespace Slime { | |||||
| }; | }; | ||||
| proc push_pc_on_cs = [&] { | proc push_pc_on_cs = [&] { | ||||
| for_lisp_list (pcs.data[pcs.next_index-1]) { | |||||
| cs.append(it); | |||||
| for_lisp_list (Current_Execution.pcs.data[Current_Execution.pcs.next_index-1]) { | |||||
| Current_Execution.cs.append(it); | |||||
| } | } | ||||
| pcs.data[pcs.next_index-1] = Memory::nil; | |||||
| Current_Execution.pcs.data[Current_Execution.pcs.next_index-1] = Memory::nil; | |||||
| }; | }; | ||||
| cs.append(expr); | |||||
| Current_Execution.cs.append(expr); | |||||
| nas->append(NasAction::Eval); | nas->append(NasAction::Eval); | ||||
| NasAction current_action; | NasAction current_action; | ||||
| @@ -350,35 +350,36 @@ namespace Slime { | |||||
| current_action = nas->data[--nas->next_index]; | current_action = nas->data[--nas->next_index]; | ||||
| switch (current_action) { | switch (current_action) { | ||||
| case NasAction::Pop: { | case NasAction::Pop: { | ||||
| --cs.next_index; | |||||
| --Current_Execution.cs.next_index; | |||||
| } break; | } break; | ||||
| case NasAction::And_Then_Action: { | case NasAction::And_Then_Action: { | ||||
| ats.data[--ats.next_index](); | |||||
| Current_Execution.ats.data[--Current_Execution.ats.next_index](); | |||||
| } break; | } break; | ||||
| case NasAction::Pop_Environment: { | case NasAction::Pop_Environment: { | ||||
| pop_environment(); | pop_environment(); | ||||
| } break; | } break; | ||||
| case NasAction::Eval: { | case NasAction::Eval: { | ||||
| pc = cs.data[cs.next_index-1]; | |||||
| pc = Current_Execution.cs.data[Current_Execution.cs.next_index-1]; | |||||
| Lisp_Object_Type type = pc->type; | Lisp_Object_Type type = pc->type; | ||||
| switch (type) { | switch (type) { | ||||
| case Lisp_Object_Type::Symbol: { | case Lisp_Object_Type::Symbol: { | ||||
| cs.data[cs.next_index-1] = lookup_symbol(pc, get_current_environment()); | |||||
| Current_Execution.cs.data[Current_Execution.cs.next_index-1] | |||||
| = lookup_symbol(pc, get_current_environment()); | |||||
| } break; | } break; | ||||
| case Lisp_Object_Type::Pair: { | case Lisp_Object_Type::Pair: { | ||||
| cs.data[cs.next_index-1] = pc->value.pair.first; | |||||
| ams.append(cs.next_index-1); | |||||
| Current_Execution.cs.data[Current_Execution.cs.next_index-1] = pc->value.pair.first; | |||||
| Current_Execution.ams.append(Current_Execution.cs.next_index-1); | |||||
| if_debug { | if_debug { | ||||
| if (ams.next_index >= 2) { | |||||
| if (Current_Execution.ams.next_index >= 2) { | |||||
| assert("invalid ams state", | assert("invalid ams state", | ||||
| ams.data[ams.next_index-2] <= | |||||
| ams.data[ams.next_index-1]); | |||||
| Current_Execution.ams.data[Current_Execution.ams.next_index-2] <= | |||||
| Current_Execution.ams.data[Current_Execution.ams.next_index-1]); | |||||
| } | } | ||||
| } | } | ||||
| pcs.append(pc->value.pair.rest); | |||||
| mes.append(pc); | |||||
| Current_Execution.pcs.append(pc->value.pair.rest); | |||||
| Current_Execution.mes.append(pc); | |||||
| nas->append(NasAction::TM); | nas->append(NasAction::TM); | ||||
| nas->append(NasAction::Eval); | nas->append(NasAction::Eval); | ||||
| } break; | } break; | ||||
| @@ -389,18 +390,19 @@ namespace Slime { | |||||
| } | } | ||||
| } break; | } break; | ||||
| case NasAction::Macro_Write_Back: { | case NasAction::Macro_Write_Back: { | ||||
| *mes.data[--mes.next_index] = *cs[cs.next_index-1]; | |||||
| *(Current_Execution.mes.data[--Current_Execution.mes.next_index]) | |||||
| = *Current_Execution.cs[Current_Execution.cs.next_index-1]; | |||||
| } break; | } break; | ||||
| case NasAction::TM: { | case NasAction::TM: { | ||||
| pc = cs.data[cs.next_index-1]; | |||||
| pc = Current_Execution.cs.data[Current_Execution.cs.next_index-1]; | |||||
| Lisp_Object_Type type = pc->type; | Lisp_Object_Type type = pc->type; | ||||
| switch (type) { | switch (type) { | ||||
| case Lisp_Object_Type::Function: { | case Lisp_Object_Type::Function: { | ||||
| if(pc->value.function->is_c) { | if(pc->value.function->is_c) { | ||||
| if (pc->value.function->type.c_function_type == C_Function_Type::cMacro) { | if (pc->value.function->type.c_function_type == C_Function_Type::cMacro) { | ||||
| --cs.next_index; // remove the macro call from cs | |||||
| --ams.next_index; // remove the apply marker for the macro | |||||
| --Current_Execution.cs.next_index; // remove the macro call from cs | |||||
| --Current_Execution.ams.next_index; // remove the apply marker for the macro | |||||
| try pc->value.function->body.c_macro_body(); | try pc->value.function->body.c_macro_body(); | ||||
| } else if (pc->value.function->type.c_function_type == C_Function_Type::cSpecial) | } else if (pc->value.function->type.c_function_type == C_Function_Type::cSpecial) | ||||
| { | { | ||||
| @@ -412,7 +414,7 @@ namespace Slime { | |||||
| } else { | } else { | ||||
| nas->append(NasAction::Step); | nas->append(NasAction::Step); | ||||
| } | } | ||||
| --mes.next_index; | |||||
| --Current_Execution.mes.next_index; | |||||
| } else { | } else { | ||||
| if (pc->value.function->type.lisp_function_type == | if (pc->value.function->type.lisp_function_type == | ||||
| Lisp_Function_Type::Macro) | Lisp_Function_Type::Macro) | ||||
| @@ -422,16 +424,74 @@ namespace Slime { | |||||
| nas->append(NasAction::Macro_Write_Back); | nas->append(NasAction::Macro_Write_Back); | ||||
| nas->append(NasAction::Step); | nas->append(NasAction::Step); | ||||
| } else { | } else { | ||||
| --mes.next_index; | |||||
| --Current_Execution.mes.next_index; | |||||
| nas->append(NasAction::Step); | nas->append(NasAction::Step); | ||||
| } | } | ||||
| } | } | ||||
| } break; | } break; | ||||
| case Lisp_Object_Type::Continuation: { | |||||
| --Current_Execution.mes.next_index; | |||||
| --Current_Execution.ams.next_index; | |||||
| Lisp_Object* param = Current_Execution.pcs.data[--Current_Execution.pcs.next_index]; | |||||
| try assert_list_length(param, 1); | |||||
| param = param->value.pair.first; | |||||
| // NOTE(Felix): we could first get value and eval | |||||
| // it and restore the cont on an and_then_action | |||||
| // OR we could restore the cont now and push the | |||||
| // new unevaluated val on the stack and leave a | |||||
| // NAS_Actoin::Eval behind. So that's what we | |||||
| // gonna do. | |||||
| Globals::Current_Execution.cs.clear(); | |||||
| Globals::Current_Execution.ams.clear(); | |||||
| Globals::Current_Execution.pcs.clear(); | |||||
| Globals::Current_Execution.nass.clear(); | |||||
| Globals::Current_Execution.envi_stack.clear(); | |||||
| Globals::Current_Execution.ats.clear(); | |||||
| Globals::Current_Execution.mes.clear(); | |||||
| // TODO(Felix): This seems super inefficient | |||||
| for (auto it: pc->value.continuation->cs) { | |||||
| Globals::Current_Execution.cs.append(it); | |||||
| } | |||||
| for (auto it: pc->value.continuation->ams) { | |||||
| Globals::Current_Execution.ams.append(it); | |||||
| } | |||||
| for (auto it: pc->value.continuation->pcs) { | |||||
| Globals::Current_Execution.pcs.append(it); | |||||
| } | |||||
| for (auto it: pc->value.continuation->envi_stack) { | |||||
| Globals::Current_Execution.envi_stack.append(it); | |||||
| } | |||||
| for (auto it: pc->value.continuation->ats) { | |||||
| Globals::Current_Execution.ats.append(it); | |||||
| } | |||||
| for (auto it: pc->value.continuation->mes) { | |||||
| Globals::Current_Execution.mes.append(it); | |||||
| } | |||||
| { | |||||
| Globals::Current_Execution.nass.reserve(pc->value.continuation->nass.next_index); | |||||
| Globals::Current_Execution.nass.next_index = pc->value.continuation->nass.next_index; | |||||
| for (int i = 0; i < pc->value.continuation->nass.next_index; ++i) { | |||||
| Globals::Current_Execution.nass.data[i].alloc(); | |||||
| for (Globals::Current_Execution.nass.data[i].next_index = 0; | |||||
| Globals::Current_Execution.nass.data[i].next_index < pc->value.continuation->nass.data[i].next_index;) | |||||
| { | |||||
| Globals::Current_Execution.nass.data[i].append( | |||||
| pc->value.continuation->nass.data[i].data[Globals::Current_Execution.nass.data[i].next_index]); | |||||
| } | |||||
| } | |||||
| } | |||||
| Globals::Current_Execution.cs.append(param); | |||||
| (Current_Execution.nass.end()-1)->append(NasAction::Eval); | |||||
| // debug_break(); | |||||
| } break; | |||||
| default: { | default: { | ||||
| char* t = lisp_object_to_string(pc); | char* t = lisp_object_to_string(pc); | ||||
| defer { | |||||
| free(t); | |||||
| }; | |||||
| defer_free(t); | |||||
| create_generic_error("The first element of the pair was not a function but: %s in %s", | create_generic_error("The first element of the pair was not a function but: %s in %s", | ||||
| lisp_object_type_to_string(type), t); | lisp_object_type_to_string(type), t); | ||||
| return nullptr; | return nullptr; | ||||
| @@ -440,31 +500,31 @@ namespace Slime { | |||||
| } break; | } break; | ||||
| case NasAction::Step: { | case NasAction::Step: { | ||||
| if (pcs.data[pcs.next_index-1] == Memory::nil) { | |||||
| --pcs.next_index; | |||||
| u32 am = ams.data[--ams.next_index]; | |||||
| Lisp_Object* function = cs.data[am]; | |||||
| if (Current_Execution.pcs.data[Current_Execution.pcs.next_index-1] == Memory::nil) { | |||||
| --Current_Execution.pcs.next_index; | |||||
| u32 am = Current_Execution.ams.data[--Current_Execution.ams.next_index]; | |||||
| Lisp_Object* function = Current_Execution.cs.data[am]; | |||||
| try assert_type(function, Lisp_Object_Type::Function); | try assert_type(function, Lisp_Object_Type::Function); | ||||
| Environment* extended_env; | Environment* extended_env; | ||||
| try extended_env = create_extended_environment_for_function_application_nrc( | try extended_env = create_extended_environment_for_function_application_nrc( | ||||
| function, am+1, cs.next_index); | |||||
| cs.next_index = am; | |||||
| function, am+1, Current_Execution.cs.next_index); | |||||
| Current_Execution.cs.next_index = am; | |||||
| push_environment(extended_env); | push_environment(extended_env); | ||||
| if (function->value.function->is_c) { | if (function->value.function->is_c) { | ||||
| if (function->value.function->type.c_function_type == C_Function_Type::cMacro) | if (function->value.function->type.c_function_type == C_Function_Type::cMacro) | ||||
| try function->value.function->body.c_macro_body(); | try function->value.function->body.c_macro_body(); | ||||
| else | else | ||||
| try cs.append(function->value.function->body.c_body()); | |||||
| try Current_Execution.cs.append(function->value.function->body.c_body()); | |||||
| pop_environment(); | pop_environment(); | ||||
| } else { | } else { | ||||
| nas->append(NasAction::Pop_Environment); | nas->append(NasAction::Pop_Environment); | ||||
| nas->append(NasAction::Eval); | nas->append(NasAction::Eval); | ||||
| cs.append(function->value.function->body.lisp_body); | |||||
| Current_Execution.cs.append(function->value.function->body.lisp_body); | |||||
| } | } | ||||
| } else { | } else { | ||||
| cs.append(pcs.data[pcs.next_index-1]->value.pair.first); | |||||
| pcs.data[pcs.next_index-1] = pcs.data[pcs.next_index-1]->value.pair.rest; | |||||
| Current_Execution.cs.append(Current_Execution.pcs.data[Current_Execution.pcs.next_index-1]->value.pair.first); | |||||
| Current_Execution.pcs.data[Current_Execution.pcs.next_index-1] = Current_Execution.pcs.data[Current_Execution.pcs.next_index-1]->value.pair.rest; | |||||
| nas->append(NasAction::Step); | nas->append(NasAction::Step); | ||||
| nas->append(NasAction::Eval); | nas->append(NasAction::Eval); | ||||
| } | } | ||||
| @@ -474,29 +534,29 @@ namespace Slime { | |||||
| | <then> | | | <then> | | ||||
| | <else> | | | <else> | | ||||
| | .... | */ | | .... | */ | ||||
| cs.next_index -= 2; | |||||
| Current_Execution.cs.next_index -= 2; | |||||
| // NOTE(Felix): for false it is sufficent to pop 2 for | // NOTE(Felix): for false it is sufficent to pop 2 for | ||||
| // true we have to copy the then part to the new top | // true we have to copy the then part to the new top | ||||
| // of the stack | // of the stack | ||||
| if (cs.data[cs.next_index+1] != Memory::nil) { | |||||
| cs.data[cs.next_index-1] = cs.data[cs.next_index]; | |||||
| if (Current_Execution.cs.data[Current_Execution.cs.next_index+1] != Memory::nil) { | |||||
| Current_Execution.cs.data[Current_Execution.cs.next_index-1] = Current_Execution.cs.data[Current_Execution.cs.next_index]; | |||||
| } | } | ||||
| } break; | } break; | ||||
| case NasAction::Define_Var: { | case NasAction::Define_Var: { | ||||
| /* | <thing> | | /* | <thing> | | ||||
| | <symbol> | | | <symbol> | | ||||
| | .... | */ | | .... | */ | ||||
| cs.next_index -= 1; | |||||
| try assert_type(cs.data[cs.next_index-1], Lisp_Object_Type::Symbol); | |||||
| try define_symbol(cs.data[cs.next_index-1], cs.data[cs.next_index]); | |||||
| cs.data[cs.next_index-1] = Memory::t; | |||||
| Current_Execution.cs.next_index -= 1; | |||||
| try assert_type(Current_Execution.cs.data[Current_Execution.cs.next_index-1], Lisp_Object_Type::Symbol); | |||||
| try define_symbol(Current_Execution.cs.data[Current_Execution.cs.next_index-1], Current_Execution.cs.data[Current_Execution.cs.next_index]); | |||||
| Current_Execution.cs.data[Current_Execution.cs.next_index-1] = Memory::t; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| // debug_step(); | // debug_step(); | ||||
| return cs.data[--cs.next_index]; | |||||
| return Current_Execution.cs.data[--Current_Execution.cs.next_index]; | |||||
| } | } | ||||
| inline proc is_truthy(Lisp_Object* expression) -> bool { | inline proc is_truthy(Lisp_Object* expression) -> bool { | ||||
| @@ -506,6 +566,11 @@ namespace Slime { | |||||
| proc interprete_file (char* file_name) -> Lisp_Object* { | proc interprete_file (char* file_name) -> Lisp_Object* { | ||||
| try Memory::init(); | try Memory::init(); | ||||
| try Memory::load_pre(); | try Memory::load_pre(); | ||||
| defer { | |||||
| if_debug { | |||||
| Slime::Memory::free_everything(); | |||||
| } | |||||
| }; | |||||
| Lisp_Object* result; | Lisp_Object* result; | ||||
| @@ -517,6 +582,11 @@ namespace Slime { | |||||
| proc interprete_stdin() -> void { | proc interprete_stdin() -> void { | ||||
| try_void Memory::init(); | try_void Memory::init(); | ||||
| try_void Memory::load_pre(); | try_void Memory::load_pre(); | ||||
| defer { | |||||
| if_debug { | |||||
| Slime::Memory::free_everything(); | |||||
| } | |||||
| }; | |||||
| printf("Welcome to the lispy interpreter.\n%s\n", version_string); | printf("Welcome to the lispy interpreter.\n%s\n", version_string); | ||||
| @@ -48,6 +48,7 @@ namespace Slime { | |||||
| Lisp_Object* get_keyword(const char*); | Lisp_Object* get_keyword(const char*); | ||||
| Lisp_Object* create_lisp_object(f64); | Lisp_Object* create_lisp_object(f64); | ||||
| Lisp_Object* create_lisp_object(const char*); | Lisp_Object* create_lisp_object(const char*); | ||||
| Lisp_Object* create_lisp_object_continuation(); | |||||
| Lisp_Object* create_lisp_object_vector(Lisp_Object*); | Lisp_Object* create_lisp_object_vector(Lisp_Object*); | ||||
| Lisp_Object* create_lisp_object_vector(Lisp_Object*, Lisp_Object*); | Lisp_Object* create_lisp_object_vector(Lisp_Object*, Lisp_Object*); | ||||
| Lisp_Object* create_lisp_object_vector(Lisp_Object*, Lisp_Object*, Lisp_Object*); | Lisp_Object* create_lisp_object_vector(Lisp_Object*, Lisp_Object*, Lisp_Object*); | ||||
| @@ -79,10 +80,11 @@ namespace Slime { | |||||
| extern char* bin_path; | extern char* bin_path; | ||||
| extern Log_Level log_level; | extern Log_Level log_level; | ||||
| extern Array_List<void*> load_path; | extern Array_List<void*> load_path; | ||||
| namespace Current_Execution { | |||||
| extern Array_List<Lisp_Object*> call_stack; | |||||
| extern Array_List<Environment*> envi_stack; | |||||
| } | |||||
| // namespace Current_Execution { | |||||
| // extern Array_List<Lisp_Object*> call_stack; | |||||
| // extern Array_List<Environment*> envi_stack; | |||||
| // } | |||||
| extern Continuation Current_Execution; | |||||
| extern Error* error; | extern Error* error; | ||||
| extern bool breaking_on_errors; | extern bool breaking_on_errors; | ||||
| } | } | ||||
| @@ -79,11 +79,12 @@ namespace Slime::GC { | |||||
| } | } | ||||
| proc garbage_collect() -> void { | proc garbage_collect() -> void { | ||||
| using Globals::Current_Execution; | |||||
| profile_this(); | profile_this(); | ||||
| ++current_mark; | ++current_mark; | ||||
| for (auto it : protected_environments) maybe_mark(it); | |||||
| for (auto it : Globals::Current_Execution::envi_stack) maybe_mark(it); | |||||
| for (auto it : protected_environments) maybe_mark(it); | |||||
| for (auto it : Current_Execution.envi_stack) maybe_mark(it); | |||||
| } | } | ||||
| proc gc_init_and_go() -> void { | proc gc_init_and_go() -> void { | ||||
| @@ -24,15 +24,7 @@ namespace Slime::Globals { | |||||
| Hash_Map<void*, Source_Code_Location> source_code_locations; | Hash_Map<void*, Source_Code_Location> source_code_locations; | ||||
| Hash_Map<void*, Lisp_Object*> user_types; | Hash_Map<void*, Lisp_Object*> user_types; | ||||
| namespace Current_Execution { | |||||
| Array_List<Lisp_Object*> cs; // call stack | |||||
| Array_List<Lisp_Object*> pcs; // program counter stack | |||||
| Array_List<int> ams; // apply marker stack | |||||
| Array_List<Array_List<NasAction>> nass; // next action stack stack | |||||
| Array_List<Lambda<void()>> ats; // and then stack | |||||
| Array_List<Lisp_Object*> mes; // macro expansion stack | |||||
| Array_List<Environment*> envi_stack; | |||||
| } | |||||
| Continuation Current_Execution; | |||||
| Error* error = nullptr; | Error* error = nullptr; | ||||
| #ifdef _DONT_BREAK_ON_ERRORS | #ifdef _DONT_BREAK_ON_ERRORS | ||||
| @@ -435,7 +435,7 @@ namespace Slime { | |||||
| // first check if it is a quotation form, in that case we want | // first check if it is a quotation form, in that case we want | ||||
| // to print it prettier | // to print it prettier | ||||
| if (head->value.pair.first->type == Lisp_Object_Type::Symbol) { | if (head->value.pair.first->type == Lisp_Object_Type::Symbol) { | ||||
| String identifier = head->value.pair.first->value.symbol; | |||||
| // String identifier = head->value.pair.first->value.symbol; | |||||
| auto symbol = head->value.pair.first; | auto symbol = head->value.pair.first; | ||||
| @@ -525,23 +525,21 @@ namespace Slime { | |||||
| } | } | ||||
| proc print_current_execution() -> void { | proc print_current_execution() -> void { | ||||
| using Globals::Current_Execution::cs; | |||||
| using Globals::Current_Execution::pcs; | |||||
| using Globals::Current_Execution::nass; | |||||
| using Globals::Current_Execution::ams; | |||||
| using Globals::Current_Execution; | |||||
| printf("cs:\n "); | printf("cs:\n "); | ||||
| for (u32 i = 0; i < cs.next_index; ++i) { | |||||
| char* t = lisp_object_to_string(cs.data[i], true); | |||||
| for (u32 i = 0; i < Current_Execution.cs.next_index; ++i) { | |||||
| char* t = lisp_object_to_string(Current_Execution.cs.data[i], true); | |||||
| defer_free(t); | defer_free(t); | ||||
| printf(" %d: %s\n ", i, t); | printf(" %d: %s\n ", i, t); | ||||
| } | } | ||||
| printf("\npcs:\n "); | printf("\npcs:\n "); | ||||
| for (auto lo : pcs) { | |||||
| for (auto lo : Current_Execution.pcs) { | |||||
| print(lo, true); | print(lo, true); | ||||
| printf("\n "); | printf("\n "); | ||||
| } | } | ||||
| printf("\nnnas:\n "); | printf("\nnnas:\n "); | ||||
| for (auto nas: nass) { | |||||
| for (auto nas: Current_Execution.nass) { | |||||
| printf("nas:\n "); | printf("nas:\n "); | ||||
| for (auto na : nas) { | for (auto na : nas) { | ||||
| printf(" - %s\n ", [&] | printf(" - %s\n ", [&] | ||||
| @@ -562,7 +560,7 @@ namespace Slime { | |||||
| } | } | ||||
| } | } | ||||
| printf("\nams:\n "); | printf("\nams:\n "); | ||||
| for (auto am : ams) { | |||||
| for (auto am : Current_Execution.ams) { | |||||
| printf("%d\n ", am); | printf("%d\n ", am); | ||||
| } | } | ||||
| } | } | ||||
| @@ -16,6 +16,11 @@ s32 main(s32 argc, char* argv[]) { | |||||
| return res ? 0 : 1; | return res ? 0 : 1; | ||||
| } else if (Slime::string_equal(argv[1], "--generate-docs-file")) { | } else if (Slime::string_equal(argv[1], "--generate-docs-file")) { | ||||
| Slime::Memory::init(); | Slime::Memory::init(); | ||||
| defer { | |||||
| if_debug { | |||||
| Slime::Memory::free_everything(); | |||||
| } | |||||
| }; | |||||
| if (Slime::Globals::error) return 1; | if (Slime::Globals::error) return 1; | ||||
| Slime::built_in_load(Slime::Memory::create_string("generate-docs-file.slime")); | Slime::built_in_load(Slime::Memory::create_string("generate-docs-file.slime")); | ||||
| } else { | } else { | ||||
| @@ -131,13 +131,13 @@ namespace Slime::Memory { | |||||
| // Globals::load_path.dealloc(); | // Globals::load_path.dealloc(); | ||||
| Globals::user_types.dealloc(); | Globals::user_types.dealloc(); | ||||
| Globals::docs.dealloc(); | Globals::docs.dealloc(); | ||||
| Globals::Current_Execution::envi_stack.dealloc(); | |||||
| Globals::Current_Execution::cs.dealloc(); | |||||
| Globals::Current_Execution::ams.dealloc(); | |||||
| Globals::Current_Execution::pcs.dealloc(); | |||||
| Globals::Current_Execution::nass.dealloc(); | |||||
| Globals::Current_Execution::ats.dealloc(); | |||||
| Globals::Current_Execution::mes.dealloc(); | |||||
| Globals::Current_Execution.envi_stack.dealloc(); | |||||
| Globals::Current_Execution.cs.dealloc(); | |||||
| Globals::Current_Execution.ams.dealloc(); | |||||
| Globals::Current_Execution.pcs.dealloc(); | |||||
| Globals::Current_Execution.nass.dealloc(); | |||||
| Globals::Current_Execution.ats.dealloc(); | |||||
| Globals::Current_Execution.mes.dealloc(); | |||||
| free(Parser::standard_in.data); | free(Parser::standard_in.data); | ||||
| @@ -177,6 +177,7 @@ namespace Slime::Memory { | |||||
| defer_free(file_name.data); | defer_free(file_name.data); | ||||
| try_void built_in_load(file_name); | try_void built_in_load(file_name); | ||||
| } | } | ||||
| proc init() -> void { | proc init() -> void { | ||||
| profile_this(); | profile_this(); | ||||
| @@ -184,11 +185,6 @@ namespace Slime::Memory { | |||||
| environment_memory.alloc(1024, 8); | environment_memory.alloc(1024, 8); | ||||
| hashmap_memory.alloc(256, 8); | hashmap_memory.alloc(256, 8); | ||||
| system_shutdown_hook << [&] { | |||||
| if_debug { | |||||
| Slime::Memory::free_everything(); | |||||
| } | |||||
| }; | |||||
| char* exe_path = get_exe_dir(); | char* exe_path = get_exe_dir(); | ||||
| @@ -196,13 +192,13 @@ namespace Slime::Memory { | |||||
| global_keyword_table.alloc(); | global_keyword_table.alloc(); | ||||
| file_to_env_map.alloc(); | file_to_env_map.alloc(); | ||||
| Globals::Current_Execution::envi_stack.alloc(); | |||||
| Globals::Current_Execution::cs.alloc(); | |||||
| Globals::Current_Execution::nass.alloc(); | |||||
| Globals::Current_Execution::pcs.alloc(); | |||||
| Globals::Current_Execution::ams.alloc(); | |||||
| Globals::Current_Execution::ats.alloc(); | |||||
| Globals::Current_Execution::mes.alloc(); | |||||
| Globals::Current_Execution.envi_stack.alloc(); | |||||
| Globals::Current_Execution.cs.alloc(); | |||||
| Globals::Current_Execution.nass.alloc(); | |||||
| Globals::Current_Execution.pcs.alloc(); | |||||
| Globals::Current_Execution.ams.alloc(); | |||||
| Globals::Current_Execution.ats.alloc(); | |||||
| Globals::Current_Execution.mes.alloc(); | |||||
| Globals::docs.alloc(); | Globals::docs.alloc(); | ||||
| Globals::user_types.alloc(); | Globals::user_types.alloc(); | ||||
| @@ -221,7 +217,7 @@ namespace Slime::Memory { | |||||
| try_void Parser::standard_in = create_string("stdin"); | try_void Parser::standard_in = create_string("stdin"); | ||||
| Globals::Current_Execution::envi_stack.next_index = 0; | |||||
| Globals::Current_Execution.envi_stack.next_index = 0; | |||||
| Environment* env; | Environment* env; | ||||
| try_void env = create_built_ins_environment(); | try_void env = create_built_ins_environment(); | ||||
| push_environment(env); | push_environment(env); | ||||
| @@ -271,6 +267,28 @@ namespace Slime::Memory { | |||||
| return node; | return node; | ||||
| } | } | ||||
| proc create_lisp_object_continuation() -> Lisp_Object* { | |||||
| using Globals::Current_Execution; | |||||
| Lisp_Object* node; | |||||
| try node = create_lisp_object(); | |||||
| node->type = Lisp_Object_Type::Continuation; | |||||
| node->value.continuation = (Continuation*)malloc(sizeof(Continuation)); | |||||
| node->value.continuation->cs = Current_Execution.cs.clone(); | |||||
| node->value.continuation->pcs = Current_Execution.pcs.clone(); | |||||
| node->value.continuation->ams = Current_Execution.ams.clone(); | |||||
| node->value.continuation->ats = Current_Execution.ats.clone(); | |||||
| node->value.continuation->mes = Current_Execution.mes.clone(); | |||||
| node->value.continuation->envi_stack = Current_Execution.envi_stack.clone(); | |||||
| node->value.continuation->nass = Current_Execution.nass.clone(); | |||||
| for (u32 i = 0; i < node->value.continuation->nass.next_index; ++i) { | |||||
| node->value.continuation->nass.data[i] = node->value.continuation->nass.data[i].clone(); | |||||
| } | |||||
| return node; | |||||
| } | |||||
| proc allocate_vector(u32 size) -> Lisp_Object* { | proc allocate_vector(u32 size) -> Lisp_Object* { | ||||
| Lisp_Object* ret = object_memory.allocate(size); | Lisp_Object* ret = object_memory.allocate(size); | ||||
| if (!ret) { | if (!ret) { | ||||
| @@ -106,7 +106,7 @@ namespace Slime::Parser { | |||||
| Lisp_Object* ret; | Lisp_Object* ret; | ||||
| try ret = Memory::create_lisp_object(0.0); | try ret = Memory::create_lisp_object(0.0); | ||||
| sscanf(text+*index_in_text, "%lf", &ret->value.number); | |||||
| sscanf(text+*index_in_text, "%Lf", &ret->value.number); | |||||
| u32 atom_length = get_atom_text_length(text, index_in_text); | u32 atom_length = get_atom_text_length(text, index_in_text); | ||||
| step_char(text, index_in_text, atom_length); | step_char(text, index_in_text, atom_length); | ||||
| @@ -20,7 +20,6 @@ namespace Slime { | |||||
| Continuation, | Continuation, | ||||
| Pointer, | Pointer, | ||||
| HashMap, | HashMap, | ||||
| // OwningPointer, | |||||
| Function, | Function, | ||||
| Invalid_Garbage_Collected, | Invalid_Garbage_Collected, | ||||
| Invalid_Under_Construction | Invalid_Under_Construction | ||||
| @@ -61,8 +60,13 @@ namespace Slime { | |||||
| }; | }; | ||||
| struct Continuation { | struct Continuation { | ||||
| Array_List<Lisp_Object*> call_stack; | |||||
| Array_List<Environment*> envi_stack; | |||||
| Array_List<Lisp_Object*> cs; // call stack | |||||
| Array_List<Lisp_Object*> pcs; // program counter stack | |||||
| Array_List<int> ams; // apply marker stack | |||||
| Array_List<Array_List<NasAction>> nass; // next action stack stack | |||||
| Array_List<Lambda<void()>> ats; // and then stack | |||||
| Array_List<Lisp_Object*> mes; // macro expansion stack | |||||
| Array_List<Environment*> envi_stack; | |||||
| }; | }; | ||||
| struct String { | struct String { | ||||
| @@ -47,13 +47,13 @@ namespace Slime { | |||||
| #define assert_equal_f64(variable, value) \ | #define assert_equal_f64(variable, value) \ | ||||
| if (fabs((f64)variable - (f64)value) > epsilon) { \ | if (fabs((f64)variable - (f64)value) > epsilon) { \ | ||||
| print_assert_equal_fail(variable, value, f64, "%f"); \ | |||||
| print_assert_equal_fail(variable, value, f64, "%Lf"); \ | |||||
| return fail; \ | return fail; \ | ||||
| } | } | ||||
| #define assert_not_equal_f64(variable, value) \ | #define assert_not_equal_f64(variable, value) \ | ||||
| if (fabs((f64)variable - (f64)value) <= epsilon) { \ | if (fabs((f64)variable - (f64)value) <= epsilon) { \ | ||||
| print_assert_not_equal_fail(variable, value, f64, "%f"); \ | |||||
| print_assert_not_equal_fail(variable, value, f64, "L%f"); \ | |||||
| return fail; \ | return fail; \ | ||||
| } | } | ||||
| @@ -556,6 +556,11 @@ namespace Slime { | |||||
| bool result = true; | bool result = true; | ||||
| try Memory::init(); | try Memory::init(); | ||||
| try Memory::load_pre(); | try Memory::load_pre(); | ||||
| defer { | |||||
| if_debug { | |||||
| Slime::Memory::free_everything(); | |||||
| } | |||||
| }; | |||||
| push_environment(Memory::create_child_environment( | push_environment(Memory::create_child_environment( | ||||
| get_current_environment())); | get_current_environment())); | ||||
| printf("-- Util --\n"); | printf("-- Util --\n"); | ||||
| @@ -579,6 +584,7 @@ namespace Slime { | |||||
| printf("\n-- Test Files --\n"); | printf("\n-- Test Files --\n"); | ||||
| invoke_test_script("regression"); | invoke_test_script("regression"); | ||||
| invoke_test_script("continuations"); | |||||
| invoke_test_script("evaluation_of_default_args"); | invoke_test_script("evaluation_of_default_args"); | ||||
| invoke_test_script("case_and_cond"); | invoke_test_script("case_and_cond"); | ||||
| invoke_test_script("lexical_scope"); | invoke_test_script("lexical_scope"); | ||||
| @@ -1,3 +1,16 @@ | |||||
| * DONE continuation test1 | |||||
| CLOSED: [2020-03-31 Di 23:07] | |||||
| #+begin_src scheme | |||||
| (define add-2 ()) | |||||
| (+ 2 (call/cc (lambda (cont) (set! add-2 cont) 3))) | |||||
| ;; = 5 | |||||
| (add-2 10) | |||||
| ;; 12 | |||||
| (add-2 100) | |||||
| ;; 102 | |||||
| #+end_src | |||||
| * DONE docs as a external dict to make LO smaller | * DONE docs as a external dict to make LO smaller | ||||
| CLOSED: [2020-03-29 So 20:00] | CLOSED: [2020-03-29 So 20:00] | ||||
| * DONE and_then_action NAS_Action | * DONE and_then_action NAS_Action | ||||
| @@ -24,12 +37,20 @@ | |||||
| CLOSED: [2020-03-31 Di 11:58] | CLOSED: [2020-03-31 Di 11:58] | ||||
| * DONE update header files | * DONE update header files | ||||
| CLOSED: [2020-03-31 Di 11:58] | CLOSED: [2020-03-31 Di 11:58] | ||||
| * TODO assert list length for arguemns of macros | |||||
| because all the args are in last of pcs, so we can assert length | |||||
| * TODO rename cs to stack | |||||
| * TODO #f #t #void | |||||
| * TODO define-syntax-shorthand | * TODO define-syntax-shorthand | ||||
| (define-syntax-shorthand [ vector ] ) | (define-syntax-shorthand [ vector ] ) | ||||
| (define-syntax-shorthand { hash-map } ) | (define-syntax-shorthand { hash-map } ) | ||||
| * TODO revert ats to use funciton pointers if capturs are not working anyways | |||||
| use the stack to store immediate results, so no captures are necessary | |||||
| * TODO continuation test2 | |||||
| let a cont have a not expanded macro in cs and before calling the cont, expand the macro and let it | |||||
| bake in | |||||
| * TODO doc generation | * TODO doc generation | ||||
| * TODO assert list length for arguemns of macros | |||||
| ??? | |||||
| * TODO source code locations | * TODO source code locations | ||||
| * TODO function let | * TODO function let | ||||
| (let fac ([n 10]) | (let fac ([n 10]) | ||||