| @@ -8,34 +8,19 @@ | |||
| context-mode-map) | |||
| (context-mode 1) | |||
| ;; additional scripts | |||
| (defun save-and-find-test-script-and-compile () | |||
| (interactive) | |||
| (let ((build-script-name "test.bat")) | |||
| (save-and-find-build-script-and-compile))) | |||
| (defun save-and-find-run-script-and-compile () | |||
| (interactive) | |||
| (let ((build-script-name "run.bat")) | |||
| (save-and-find-build-script-and-compile))) | |||
| (defun save-and-find-debug-script-and-compile () | |||
| (interactive) | |||
| (let ((build-script-name "debug.bat")) | |||
| (save-and-find-build-script-and-compile))) | |||
| (defhydra hydra-context (context-mode-map "<f2>") | |||
| "Context Actions:" | |||
| ("b" save-and-find-build-script-and-compile "build" :color blue) | |||
| ("r" save-and-find-run-script-and-compile "run" :color blue) | |||
| ("d" save-and-find-debug-script-and-compile "debug" :color blue) | |||
| ("t" save-and-find-test-script-and-compile "test" :color blue) | |||
| ("o" browse-file-directory "open" :color blue) | |||
| ("q" nil "quit" :color blue)) | |||
| (define-key context-mode-map (kbd "<f2>") 'hydra-context/body) | |||
| (font-lock-add-keywords 'c++-mode | |||
| '(("\\<\\(if_debug\\|if_windows\\|if_linux\\|defer\\|proc\\)\\>" . | |||
| font-lock-keyword-face))))))) | |||
| (font-lock-add-keywords | |||
| 'c++-mode | |||
| '(("\\<\\(if_debug\\|if_windows\\|if_linux\\|defer\\|proc\\)\\>" . | |||
| font-lock-keyword-face))))))) | |||
| (c++-mode . ((eval . (company-clang-set-prefix "slime.h")) | |||
| (eval . (flycheck-mode 0)) | |||
| (eval . (rainbow-mode 0)) | |||
| @@ -5,31 +5,24 @@ proc lisp_object_equal(Lisp_Object* n1, Lisp_Object* n2) -> bool { | |||
| return false; | |||
| switch (n1->type) { | |||
| case Lisp_Object_Type::CFunction: | |||
| // TODO(Felix): make comparing work again. | |||
| return false; | |||
| /* return n1->value.built_in_function->type */ | |||
| /* == n2->value.built_in_function->type; */ | |||
| case Lisp_Object_Type::Function: | |||
| // if they have the same pointer, true is | |||
| // returned a few lines above | |||
| return false; | |||
| case Lisp_Object_Type::CFunction: // if they have the same | |||
| // pointer, true is returned a | |||
| // few lines above | |||
| case Lisp_Object_Type::Function: return false; | |||
| case Lisp_Object_Type::T: // code for t and nil should never be | |||
| // reached since they are memory unique | |||
| case Lisp_Object_Type::Nil: return true; | |||
| case Lisp_Object_Type::Symbol: // NOTE(Felix): this will be | |||
| // unnecessary once symbols and | |||
| // keywords are memory unique | |||
| case Lisp_Object_Type::Keyword: | |||
| return string_equal( | |||
| n1->value.identifier, | |||
| n2->value.identifier); | |||
| case Lisp_Object_Type::T: | |||
| case Lisp_Object_Type::Nil: | |||
| return true; | |||
| case Lisp_Object_Type::Number: | |||
| return n1->value.number == n2->value.number; | |||
| return string_equal(n1->value.identifier, n2->value.identifier); | |||
| case Lisp_Object_Type::Number: return n1->value.number == n2->value.number; | |||
| case Lisp_Object_Type::String: return string_equal(n1->value.string, n2->value.string); | |||
| case Lisp_Object_Type::Pair: | |||
| create_not_yet_implemented_error(); | |||
| return false; | |||
| case Lisp_Object_Type::String: | |||
| return string_equal(n1->value.string, n2->value.string); | |||
| case Lisp_Object_Type::Symbol: | |||
| return string_equal(n1->value.identifier, n2->value.identifier); | |||
| } | |||
| // we should never reach here | |||
| @@ -916,7 +909,7 @@ proc load_built_ins_into_environment(Environment* env) -> void { | |||
| Lisp_Object* result; | |||
| result = eval_expr(try_part, env); | |||
| if (error) { | |||
| if (Globals::error) { | |||
| delete_error(); | |||
| try { | |||
| result = eval_expr(catch_part, env); | |||
| @@ -28,7 +28,7 @@ constexpr bool is_debug_build = false; | |||
| else \ | |||
| while (1) \ | |||
| if (1) { \ | |||
| if(error) { \ | |||
| if(Globals::error) { \ | |||
| if (log_level == Log_Level::Debug) { \ | |||
| printf("in %s:%d\n", __FILE__, __LINE__); \ | |||
| } \ | |||
| @@ -44,7 +44,7 @@ constexpr bool is_debug_build = false; | |||
| else \ | |||
| while (1) \ | |||
| if (1) { \ | |||
| if(error) { \ | |||
| if(Globals::error) { \ | |||
| if (log_level == Log_Level::Debug) { \ | |||
| printf("in %s:%d\n", __FILE__, __LINE__); \ | |||
| } \ | |||
| @@ -1,4 +1,3 @@ | |||
| proc define_symbol(Lisp_Object* symbol, Lisp_Object* value, Environment* env) -> void { | |||
| // NOTE(Felix): right now we are simply adding the symol at the | |||
| // back of the list without checking if it already exists but are | |||
| @@ -1,6 +1,6 @@ | |||
| Error* error; | |||
| proc delete_error() -> void { | |||
| using Globals::error; | |||
| if (error) { | |||
| free(error); | |||
| error = nullptr; | |||
| @@ -15,6 +15,7 @@ proc create_error(const char* c_file_name, int c_file_line, Lisp_Object* type, S | |||
| delete_error(); | |||
| debug_break(); | |||
| using Globals::error; | |||
| error = new(Error); | |||
| error->type = type; | |||
| error->message = message; | |||
| @@ -387,7 +387,7 @@ proc eval_expr(Lisp_Object* node, Environment* env) -> Lisp_Object* { | |||
| return symbol; | |||
| } | |||
| case Lisp_Object_Type::Pair: { | |||
| current_source_code = node; | |||
| Globals::current_source_code = node; | |||
| Lisp_Object* lispOperator; | |||
| if (node->value.pair.first->type != Lisp_Object_Type::CFunction && | |||
| @@ -486,7 +486,7 @@ proc interprete_stdin() -> void { | |||
| built_in_load(Memory::create_string("pre.slime"), env); | |||
| if (error) { | |||
| if (Globals::error) { | |||
| log_error(); | |||
| delete_error(); | |||
| } | |||
| @@ -497,13 +497,13 @@ proc interprete_stdin() -> void { | |||
| line = read_expression(); | |||
| parsed = Parser::parse_single_expression(line); | |||
| free(line); | |||
| if (error) { | |||
| if (Globals::error) { | |||
| log_error(); | |||
| delete_error(); | |||
| continue; | |||
| } | |||
| evaluated = eval_expr(parsed, env); | |||
| if (error) { | |||
| if (Globals::error) { | |||
| log_error(); | |||
| delete_error(); | |||
| continue; | |||
| @@ -12,8 +12,12 @@ proc parse_argument_list(Lisp_Object*, Function*) -> void; | |||
| proc print_environment(Environment*) -> void; | |||
| proc Lisp_Object_Type_to_string(Lisp_Object_Type type) -> const char*; | |||
| namespace Memory { | |||
| proc get_or_create_lisp_object_keyword(const char* identifier) -> Lisp_Object*; | |||
| } | |||
| Lisp_Object* current_source_code = nullptr; | |||
| namespace Globals { | |||
| Lisp_Object* current_source_code = nullptr; | |||
| Error* error; | |||
| } | |||
| @@ -119,16 +119,17 @@ proc read_entire_file(char* filename) -> char* { | |||
| proc read_expression() -> char* { | |||
| char* line = (char*)malloc(100); | |||
| if(line == nullptr) | |||
| return nullptr; | |||
| char* linep = line; | |||
| size_t lenmax = 100, len = lenmax; | |||
| int c; | |||
| int nesting = 0; | |||
| if(line == NULL) | |||
| return NULL; | |||
| for(;;) { | |||
| while (true) { | |||
| c = fgetc(stdin); | |||
| if(c == EOF) | |||
| break; | |||
| @@ -137,9 +138,9 @@ proc read_expression() -> char* { | |||
| len = lenmax; | |||
| char * linen = (char*)realloc(linep, lenmax *= 2); | |||
| if(linen == NULL) { | |||
| if(linen == nullptr) { | |||
| free(linep); | |||
| return NULL; | |||
| return nullptr; | |||
| } | |||
| line = linen + (line - linep); | |||
| linep = linen; | |||
| @@ -168,8 +169,8 @@ proc read_line() -> char* { | |||
| int nesting = 0; | |||
| if(line == NULL) | |||
| return NULL; | |||
| if(line == nullptr) | |||
| return nullptr; | |||
| for(;;) { | |||
| c = fgetc(stdin); | |||
| @@ -180,9 +181,9 @@ proc read_line() -> char* { | |||
| len = lenmax; | |||
| char* linen = (char*)realloc(linep, lenmax *= 2); | |||
| if(linen == NULL) { | |||
| if(linen == nullptr) { | |||
| free(linep); | |||
| return NULL; | |||
| return nullptr; | |||
| } | |||
| line = linen + (line - linep); | |||
| linep = linen; | |||
| @@ -230,31 +231,34 @@ proc panic(char* message) -> void { | |||
| proc print(Lisp_Object* node, bool print_quotes = false, FILE* file = stdout) -> void { | |||
| switch (node->type) { | |||
| case (Lisp_Object_Type::Nil): fprintf(file, "()"); break; | |||
| case (Lisp_Object_Type::T): fprintf(file, "t"); break; | |||
| case (Lisp_Object_Type::Number): fprintf(file, "%f", node->value.number); break; | |||
| case (Lisp_Object_Type::Symbol): fprintf(file, "%s", Memory::get_c_str(node->value.identifier)); break; | |||
| case (Lisp_Object_Type::Keyword): fprintf(file, ":%s", Memory::get_c_str(node->value.identifier)); break; | |||
| case (Lisp_Object_Type::CFunction): fprintf(file, "[C-function]"); break; | |||
| case (Lisp_Object_Type::Nil): fputs("()", file); break; | |||
| case (Lisp_Object_Type::T): fputs("t", file); break; | |||
| case (Lisp_Object_Type::Number): fprintf(file, "%f", node->value.number); break; | |||
| case (Lisp_Object_Type::Keyword): fputs(":", file); // NOTE(Felix): intentionall fallthough | |||
| case (Lisp_Object_Type::Symbol): fprintf(file, Memory::get_c_str(node->value.identifier)); break; | |||
| case (Lisp_Object_Type::CFunction): fputs("[C-function]", file); break; | |||
| case (Lisp_Object_Type::String): { | |||
| if (print_quotes) | |||
| fprintf(file, "\"%s\"", Memory::get_c_str(node->value.string)); | |||
| if (print_quotes) { | |||
| putc('\"', file); | |||
| fputs(Memory::get_c_str(node->value.string), file); | |||
| putc('\"', file); | |||
| } | |||
| else | |||
| fprintf(file, "%s", Memory::get_c_str(node->value.string)); | |||
| fputs(Memory::get_c_str(node->value.string), file); | |||
| } break; | |||
| case (Lisp_Object_Type::Function): { | |||
| if (node->value.function.type == Function_Type::Lambda) | |||
| fprintf(file, "[lambda]"); | |||
| fputs("[lambda]", file); | |||
| else if (node->value.function.type == Function_Type::Special_Lambda) | |||
| fprintf(file, "[special-lambda]"); | |||
| fputs("[special-lambda]", file); | |||
| else if (node->value.function.type == Function_Type::Macro) | |||
| fprintf(file, "[macro]"); | |||
| fputs("[macro]", file); | |||
| else | |||
| assert(false); | |||
| } break; | |||
| case (Lisp_Object_Type::Pair): { | |||
| Lisp_Object* head = node; | |||
| fprintf(file, "("); | |||
| putc('(', file); | |||
| // NOTE(Felix): We cold do a while true here, however in case | |||
| // we want to print a broken list (for logging the error) we | |||
| @@ -266,38 +270,39 @@ proc print(Lisp_Object* node, bool print_quotes = false, FILE* file = stdout) -> | |||
| return; | |||
| if (head->type != Lisp_Object_Type::Pair) | |||
| break; | |||
| fprintf(file, " "); | |||
| putc(' ', file); | |||
| } | |||
| if (head->type != Lisp_Object_Type::Nil) { | |||
| fprintf(file, " . "); | |||
| fputs(" . ", file); | |||
| print(head); | |||
| } | |||
| fprintf(file, ")"); | |||
| putc(')', file); | |||
| } break; | |||
| } | |||
| } | |||
| proc print_error_location() -> void { | |||
| if (current_source_code) { | |||
| if (Globals::current_source_code) { | |||
| printf("%s (line %d, position %d) code:" console_red "\n ", | |||
| Memory::get_c_str( | |||
| current_source_code->sourceCodeLocation->file), | |||
| current_source_code->sourceCodeLocation->line, | |||
| current_source_code->sourceCodeLocation->column); | |||
| print(current_source_code); | |||
| Globals::current_source_code->sourceCodeLocation->file), | |||
| Globals::current_source_code->sourceCodeLocation->line, | |||
| Globals::current_source_code->sourceCodeLocation->column); | |||
| print(Globals::current_source_code); | |||
| } else { | |||
| printf("no source code location avaliable"); | |||
| fputs("no source code location avaliable", stdout); | |||
| } | |||
| } | |||
| proc log_error() -> void { | |||
| printf("%s%s%s\n", console_red, | |||
| Memory::get_c_str(error->message), | |||
| console_normal); | |||
| printf(" in: %s", console_cyan); | |||
| fputs(console_red, stdout); | |||
| fputs(Memory::get_c_str(Globals::error->message), stdout); | |||
| puts(console_normal); | |||
| fputs(" in: " console_cyan, stdout); | |||
| print_error_location(); | |||
| printf("%s\n", console_normal); | |||
| puts(console_normal); | |||
| } | |||
| @@ -1,17 +1,19 @@ | |||
| #include "slime.h" | |||
| // using namespace Slime; | |||
| int main(int argc, char* argv[]) { | |||
| if (argc > 1) { | |||
| if (Slime::string_equal(argv[1], "--run-tests")) { | |||
| return Slime::run_all_tests() ? 0 : 1; | |||
| if (string_equal(argv[1], "--run-tests")) { | |||
| return run_all_tests() ? 0 : 1; | |||
| } | |||
| Slime::interprete_file(argv[1]); | |||
| if (Slime::error) { | |||
| Slime::log_error(); | |||
| interprete_file(argv[1]); | |||
| if (Globals::error) { | |||
| log_error(); | |||
| return 1; | |||
| } | |||
| } else { | |||
| Slime::interprete_stdin(); | |||
| interprete_stdin(); | |||
| } | |||
| } | |||
| @@ -12,7 +12,7 @@ | |||
| #undef _CRT_SECURE_NO_DEPRECATE | |||
| #undef _CRT_SECURE_NO_WARNINGS | |||
| namespace Slime { | |||
| // namespace Slime { | |||
| # include "./defines.cpp" | |||
| # include "./structs.cpp" | |||
| # include "./forward_decls.cpp" | |||
| @@ -26,4 +26,4 @@ namespace Slime { | |||
| # include "./built_ins.cpp" | |||
| # include "./testing.cpp" | |||
| # include "./undefines.cpp" | |||
| } | |||
| // } | |||
| @@ -29,20 +29,20 @@ | |||
| } | |||
| #define assert_no_error() \ | |||
| if (error) { \ | |||
| print_assert_equal_fail(error, 0, size_t, "%zd"); \ | |||
| if (Globals::error) { \ | |||
| print_assert_equal_fail(Globals::error, 0, size_t, "%zd"); \ | |||
| printf("\nExpected no error to occur," \ | |||
| " but an error occured anyways:\n"); \ | |||
| log_error(); \ | |||
| return fail; \ | |||
| } \ | |||
| #define assert_error() \ | |||
| if (!error) { \ | |||
| print_assert_not_equal_fail(error, 0, size_t, "%zd"); \ | |||
| printf("\nExpected an error to occur," \ | |||
| " but no error occured:\n"); \ | |||
| return fail; \ | |||
| #define assert_error() \ | |||
| if (!Globals::error) { \ | |||
| print_assert_not_equal_fail(Globals::error, 0, size_t, "%zd"); \ | |||
| printf("\nExpected an error to occur," \ | |||
| " but no error occured:\n"); \ | |||
| return fail; \ | |||
| } \ | |||
| #define assert_equal_double(variable, value) \ | |||
| @@ -77,40 +77,40 @@ | |||
| #define assert_not_null(variable) \ | |||
| assert_not_equal_int(variable, nullptr) | |||
| #define invoke_test(name) \ | |||
| printf("" #name ":"); \ | |||
| if (name() == pass) { \ | |||
| for(size_t i = strlen(#name); i < 70; ++i) \ | |||
| printf((i%3==1)? "." : " "); \ | |||
| printf("%spassed%s\n", console_green, console_normal); \ | |||
| } \ | |||
| else { \ | |||
| result = false; \ | |||
| for(int i = -1; i < 70; ++i) \ | |||
| printf((i%3==1)? "." : " "); \ | |||
| printf("%sfailed%s\n", console_red, console_normal); \ | |||
| if(error) { \ | |||
| free(error); \ | |||
| error = nullptr; \ | |||
| } \ | |||
| } \ | |||
| #define invoke_test(name) \ | |||
| fputs("" #name ":", stdout); \ | |||
| if (name() == pass) { \ | |||
| for(size_t i = strlen(#name); i < 70; ++i) \ | |||
| fputs((i%3==1)? "." : " ", stdout); \ | |||
| fputs(console_green "passed\n" console_normal, stdout); \ | |||
| } \ | |||
| else { \ | |||
| result = false; \ | |||
| for(int i = -1; i < 70; ++i) \ | |||
| fputs((i%3==1)? "." : " ", stdout); \ | |||
| fputs(console_red "failed\n" console_normal, stdout); \ | |||
| if(Globals::error) { \ | |||
| free(Globals::error); \ | |||
| Globals::error = nullptr; \ | |||
| } \ | |||
| } \ | |||
| #define invoke_test_script(name) \ | |||
| printf("" name ":"); \ | |||
| if (test_file("tests/" name ".slime") == pass) { \ | |||
| for(size_t i = strlen(name); i < 70; ++i) \ | |||
| printf((i%3==1)? "." : " "); \ | |||
| printf("%spassed%s\n", console_green, console_normal); \ | |||
| } \ | |||
| else { \ | |||
| result = false; \ | |||
| for(int i = -1; i < 70; ++i) \ | |||
| printf((i%3==1)? "." : " "); \ | |||
| printf("%sfailed%s\n", console_red, console_normal); \ | |||
| if(error) { \ | |||
| free(error); \ | |||
| error = nullptr; \ | |||
| } \ | |||
| #define invoke_test_script(name) \ | |||
| fputs("" name ":", stdout); \ | |||
| if (test_file("tests/" name ".slime") == pass) { \ | |||
| for(size_t i = strlen(name); i < 70; ++i) \ | |||
| fputs((i%3==1)? "." : " ", stdout); \ | |||
| fputs(console_green "passed\n" console_normal, stdout); \ | |||
| } \ | |||
| else { \ | |||
| result = false; \ | |||
| for(int i = -1; i < 70; ++i) \ | |||
| fputs((i%3==1)? "." : " ", stdout); \ | |||
| fputs(console_red "failed\n" console_normal, stdout); \ | |||
| if(Globals::error) { \ | |||
| free(Globals::error); \ | |||
| Globals::error = nullptr; \ | |||
| } \ | |||
| } | |||
| proc test_eval_operands() -> testresult { | |||
| @@ -480,7 +480,7 @@ proc test_singular_t_and_nil() -> testresult { | |||
| proc test_file(const char* file) -> testresult { | |||
| Memory::reset(); | |||
| static Environment* env = Memory::create_built_ins_environment(); | |||
| Environment* env = Memory::create_built_ins_environment(); | |||
| Parser::init(env); | |||