| @@ -36,7 +36,7 @@ | |||||
| (font-lock-add-keywords 'c++-mode | (font-lock-add-keywords 'c++-mode | ||||
| '(("\\<\\(if_debug\\|if_windows\\|if_linux\\|defer\\|proc\\)\\>" . | '(("\\<\\(if_debug\\|if_windows\\|if_linux\\|defer\\|proc\\)\\>" . | ||||
| font-lock-keyword-face))))))) | font-lock-keyword-face))))))) | ||||
| (c++-mode . ((eval . (company-clang-set-prefix "main.cpp")) | |||||
| (c++-mode . ((eval . (company-clang-set-prefix "slime.h")) | |||||
| (eval . (flycheck-mode 0)) | (eval . (flycheck-mode 0)) | ||||
| (eval . (rainbow-mode 0)) | (eval . (rainbow-mode 0)) | ||||
| ))) | ))) | ||||
| @@ -122,6 +122,48 @@ struct { | |||||
| #define TOKENPASTE2(x, y) TOKENPASTE(x, y) | #define TOKENPASTE2(x, y) TOKENPASTE(x, y) | ||||
| #define defer auto TOKENPASTE2(__deferred_lambda_call, __COUNTER__) = deferrer << [&] | #define defer auto TOKENPASTE2(__deferred_lambda_call, __COUNTER__) = deferrer << [&] | ||||
| /* | |||||
| Usage of the create_error_macros: | |||||
| */ | |||||
| #define __create_error(keyword, ...) \ | |||||
| create_error( \ | |||||
| __FILE__, __LINE__, \ | |||||
| Memory::get_or_create_lisp_object_keyword(keyword), \ | |||||
| __VA_ARGS__) | |||||
| #define create_out_of_memory_error(...) \ | |||||
| __create_error("out-of-memory", __VA_ARGS__) | |||||
| #define create_generic_error(...) \ | |||||
| __create_error("generic", __VA_ARGS__) | |||||
| #define create_parsing_error(...) \ | |||||
| __create_error("parsing-error", __VA_ARGS__) | |||||
| #define create_symbol_undefined_error(...) \ | |||||
| __create_error("symbol-undefined", __VA_ARGS__) | |||||
| #define create_type_missmatch_error(expected, actual) \ | |||||
| __create_error("type-missmatch", \ | |||||
| "Type missmatch: expected %s, got %s", \ | |||||
| expected, actual) | |||||
| #define create_wrong_number_of_arguments_error(expected, actual) \ | |||||
| __create_error("wrong-number-of-arguments", \ | |||||
| "Wrong number of arguments: expected %d, got %d", \ | |||||
| expected, actual) | |||||
| #define assert_type(_node, _type) \ | |||||
| do { \ | |||||
| if (_node->type != _type) { \ | |||||
| create_type_missmatch_error("symbol", Lisp_Object_Type_to_string(_node->type)); \ | |||||
| return nullptr; \ | |||||
| } \ | |||||
| } while(0) | |||||
| #define console_normal "\x1B[0m" | #define console_normal "\x1B[0m" | ||||
| #define console_red "\x1B[31m" | #define console_red "\x1B[31m" | ||||
| #define console_green "\x1B[32m" | #define console_green "\x1B[32m" | ||||
| @@ -45,8 +45,8 @@ proc lookup_symbol(Lisp_Object* node, Environment* env) -> Lisp_Object* { | |||||
| return Memory::t; | return Memory::t; | ||||
| } | } | ||||
| printf("%s\n", Memory::get_c_str(identifier)); | |||||
| create_error(Error_Type::Symbol_Not_Defined, node->sourceCodeLocation); | |||||
| create_symbol_undefined_error("The symbol '%s' is not defined.", &identifier->data); | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| @@ -7,40 +7,69 @@ proc delete_error() -> void { | |||||
| } | } | ||||
| } | } | ||||
| proc create_error(Error_Type type, Source_Code_Location* location) -> void { | |||||
| proc create_error(const char* c_file_name, int c_file_line, Lisp_Object* type, String* message) -> void { | |||||
| if_debug { | |||||
| printf("Error created in:\n%s:%d\n", c_file_name, c_file_line); | |||||
| } | |||||
| delete_error(); | delete_error(); | ||||
| debug_break(); | debug_break(); | ||||
| error = new(Error); | error = new(Error); | ||||
| error->type = type; | error->type = type; | ||||
| error->location = location; | |||||
| error->message = message; | |||||
| } | } | ||||
| proc Error_Type_to_string(Error_Type type) -> const char* { | |||||
| switch (type) { | |||||
| case Error_Type::Assertion_Error: return "Assertion failed"; | |||||
| case Error_Type::File_Not_Found: return "File not found"; | |||||
| case Error_Type::Ill_Formed_Arguments: return "Evaluation-error: Ill formed arguments"; | |||||
| case Error_Type::Ill_Formed_Lambda_List: return "Evaluation-error: Ill formed lambda list"; | |||||
| case Error_Type::Ill_Formed_List: return "Evaluation-error: Ill formed list"; | |||||
| case Error_Type::Not_A_Function: return "Evaluation-error: Not a function"; | |||||
| case Error_Type::Not_Yet_Implemented: return "Evaluation-error: Not yet implemented"; | |||||
| case Error_Type::Symbol_Not_Defined: return "Evaluation-error: Symbol not defined"; | |||||
| case Error_Type::Syntax_Error: return "Syntax Error"; | |||||
| case Error_Type::Trailing_Garbage: return "Evaluation-error: Trailing garbage following expression"; | |||||
| case Error_Type::Type_Missmatch: return "Evaluation-error: Type Missmatch"; | |||||
| case Error_Type::Unbalanced_Parenthesis: return "Parsing-error: Unbalanced parenthesis"; | |||||
| case Error_Type::Unexpected_Eof: return "Parsing-error: Unexpected EOF"; | |||||
| case Error_Type::Unknown_Keyword_Argument: return "Evaluation-error: Unknown keyword argument"; | |||||
| case Error_Type::Wrong_Number_Of_Arguments: return "Evaluation-error: Wrong number of arguments"; | |||||
| case Error_Type::Out_Of_Memory: return "Runtime-error: Out of memory"; | |||||
| default: return "this error type doesn't have a desciption.."; | |||||
| } | |||||
| } | |||||
| proc assert_type(Lisp_Object* node, Lisp_Object_Type type) -> void { | |||||
| if (!node) | |||||
| create_error(Error_Type::Unknown_Error, nullptr); | |||||
| if (node->type == type) return; | |||||
| create_error(Error_Type::Type_Missmatch, node->sourceCodeLocation); | |||||
| proc create_error(const char* c_file_name, int c_file_line, Lisp_Object* type, const char* format, ...) -> void { | |||||
| // HACK(Felix): the length of all error strings is 200!!!!!!!!!! | |||||
| int length = 200; | |||||
| String* formatted_string = Memory::create_string("", length); | |||||
| int written_length; | |||||
| va_list args; | |||||
| va_start(args, format); | |||||
| written_length = vsnprintf(&formatted_string->data, length, format, args); | |||||
| va_end(args); | |||||
| formatted_string->length = written_length; | |||||
| create_error(c_file_name, c_file_line, type, formatted_string); | |||||
| } | } | ||||
| // proc Error_Type_to_string(Error_Type type) -> const char* { | |||||
| // switch (type) { | |||||
| // case Error_Type::Assertion_Error: return "Assertion failed"; | |||||
| // case Error_Type::File_Not_Found: return "File not found"; | |||||
| // case Error_Type::Ill_Formed_Arguments: return "Evaluation-error: Ill formed arguments"; | |||||
| // case Error_Type::Ill_Formed_Lambda_List: return "Evaluation-error: Ill formed lambda list"; | |||||
| // case Error_Type::Ill_Formed_List: return "Evaluation-error: Ill formed list"; | |||||
| // case Error_Type::Not_A_Function: return "Evaluation-error: Not a function"; | |||||
| // case Error_Type::Not_Yet_Implemented: return "Evaluation-error: Not yet implemented"; | |||||
| // case Error_Type::Symbol_Not_Defined: return "Evaluation-error: Symbol not defined"; | |||||
| // case Error_Type::Syntax_Error: return "Syntax Error"; | |||||
| // case Error_Type::Trailing_Garbage: return "Evaluation-error: Trailing garbage following expression"; | |||||
| // case Error_Type::Type_Missmatch: return "Evaluation-error: Type Missmatch"; | |||||
| // case Error_Type::Unbalanced_Parenthesis: return "Parsing-error: Unbalanced parenthesis"; | |||||
| // case Error_Type::Unexpected_Eof: return "Parsing-error: Unexpected EOF"; | |||||
| // case Error_Type::Unknown_Keyword_Argument: return "Evaluation-error: Unknown keyword argument"; | |||||
| // case Error_Type::Wrong_Number_Of_Arguments: return "Evaluation-error: Wrong number of arguments"; | |||||
| // case Error_Type::Out_Of_Memory: return "Runtime-error: Out of memory"; | |||||
| // default: return "this error type doesn't have a desciption.."; | |||||
| // } | |||||
| // } | |||||
| // proc assert_type(Lisp_Object* node, Lisp_Object_Type type) -> void { | |||||
| // if (!node) { | |||||
| // create_generic_error( | |||||
| // "The node where the type should have" | |||||
| // "been checked was nullptr."); | |||||
| // return; | |||||
| // } | |||||
| // if (node->type != type) | |||||
| // create_type_missmatch_error( | |||||
| // "" | |||||
| // ); | |||||
| // } | |||||
| @@ -5,18 +5,17 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) -> | |||||
| // positional arguments | // positional arguments | ||||
| for (int i = 0; i < function->positional_arguments->next_index; ++i) { | for (int i = 0; i < function->positional_arguments->next_index; ++i) { | ||||
| if (arguments->type == Lisp_Object_Type::Pair) { | |||||
| // TODO(Felix): here we create new lisp_object_symbols from | |||||
| // their identifiers but before we converted them to | |||||
| // strings from symbols... Wo maybe just use the symbols? | |||||
| define_symbol( | |||||
| Memory::get_or_create_lisp_object_symbol(function->positional_arguments->identifiers[i]), | |||||
| arguments->value.pair.first, new_env); | |||||
| } else { | |||||
| create_error(Error_Type::Ill_Formed_Arguments, arguments->sourceCodeLocation); | |||||
| if (arguments->type != Lisp_Object_Type::Pair) { | |||||
| create_wrong_number_of_arguments_error(function->positional_arguments->next_index, i); | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| // TODO(Felix): here we create new lisp_object_symbols from | |||||
| // their identifiers but before we converted them to | |||||
| // strings from symbols... Wo maybe just use the symbols? | |||||
| define_symbol( | |||||
| Memory::get_or_create_lisp_object_symbol(function->positional_arguments->identifiers[i]), | |||||
| arguments->value.pair.first, new_env); | |||||
| arguments = arguments->value.pair.rest; | arguments = arguments->value.pair.rest; | ||||
| } | } | ||||
| @@ -46,8 +45,9 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) -> | |||||
| // necessary keywords then we have to count the rest | // necessary keywords then we have to count the rest | ||||
| // as :rest here, instead od always creating an error | // as :rest here, instead od always creating an error | ||||
| // (special case with default variables) | // (special case with default variables) | ||||
| puts("??"); | |||||
| create_error(Error_Type::Ill_Formed_Arguments, arguments->sourceCodeLocation); | |||||
| create_generic_error( | |||||
| "The function does not take the keyword argument ':%s'", | |||||
| &(arguments->value.pair.first->value.identifier)); | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| @@ -61,7 +61,9 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) -> | |||||
| // necessary keywords then we have to count the rest | // necessary keywords then we have to count the rest | ||||
| // as :rest here, instead od always creating an error | // as :rest here, instead od always creating an error | ||||
| // (special case with default variables) | // (special case with default variables) | ||||
| create_error(Error_Type::Ill_Formed_Arguments, arguments->sourceCodeLocation); | |||||
| create_generic_error( | |||||
| "The function already read the keyword argument ':%s'", | |||||
| &(arguments->value.pair.first->value.identifier)); | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| } | } | ||||
| @@ -70,7 +72,9 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) -> | |||||
| // not already read in, is there a next element to actually | // not already read in, is there a next element to actually | ||||
| // set it to? | // set it to? | ||||
| if (arguments->value.pair.rest->type != Lisp_Object_Type::Pair) { | if (arguments->value.pair.rest->type != Lisp_Object_Type::Pair) { | ||||
| create_error(Error_Type::Ill_Formed_Arguments, arguments->sourceCodeLocation); | |||||
| create_generic_error( | |||||
| "Attempting to set the keyword argument ':%s', but no value was supplied.", | |||||
| &(arguments->value.pair.first->value.identifier)); | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| @@ -107,7 +111,10 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) -> | |||||
| if (function->keyword_arguments->values->data[i] == nullptr) { | if (function->keyword_arguments->values->data[i] == nullptr) { | ||||
| // if this one does not have a default value | // if this one does not have a default value | ||||
| if (!was_set) { | if (!was_set) { | ||||
| create_error(Error_Type::Ill_Formed_Arguments, arguments->sourceCodeLocation); | |||||
| create_generic_error( | |||||
| "There was no value supplied for the required " | |||||
| "keyword argument ':%s'.", | |||||
| &defined_keyword->data); | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| } else { | } else { | ||||
| @@ -135,7 +142,9 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) -> | |||||
| arguments, new_env); | arguments, new_env); | ||||
| } else { | } else { | ||||
| // rest was not declared but additional arguments were found | // rest was not declared but additional arguments were found | ||||
| create_error(Error_Type::Ill_Formed_Arguments, arguments->sourceCodeLocation); | |||||
| create_generic_error( | |||||
| "A rest argument was not declared " | |||||
| "but the function was called with additional arguments."); | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| } | } | ||||
| @@ -180,13 +189,17 @@ proc parse_argument_list(Lisp_Object* arguments, Function* function) -> void { | |||||
| string_equal(arguments->value.pair.first->value.identifier, "rest")) | string_equal(arguments->value.pair.first->value.identifier, "rest")) | ||||
| break; | break; | ||||
| else { | else { | ||||
| create_error(Error_Type::Ill_Formed_Lambda_List, arguments->sourceCodeLocation); | |||||
| create_parsing_error("A non recognized marker was found " | |||||
| "in the lambda list: ':%s'", | |||||
| &arguments->value.pair.first->value.identifier); | |||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| if (arguments->value.pair.first->type != Lisp_Object_Type::Symbol) { | if (arguments->value.pair.first->type != Lisp_Object_Type::Symbol) { | ||||
| create_error(Error_Type::Ill_Formed_Lambda_List, arguments->sourceCodeLocation); | |||||
| create_parsing_error("Only symbols and keywords can be " | |||||
| "parsed here, but found '%s'", | |||||
| Lisp_Object_Type_to_string(arguments->value.pair.first->type)); | |||||
| return; | return; | ||||
| } | } | ||||
| @@ -202,7 +215,7 @@ proc parse_argument_list(Lisp_Object* arguments, Function* function) -> void { | |||||
| // keywords, | // keywords, | ||||
| if (arguments->type != Lisp_Object_Type::Pair) { | if (arguments->type != Lisp_Object_Type::Pair) { | ||||
| if (arguments->type != Lisp_Object_Type::Nil) | if (arguments->type != Lisp_Object_Type::Nil) | ||||
| create_error(Error_Type::Ill_Formed_Lambda_List, arguments->sourceCodeLocation); | |||||
| create_parsing_error("The lambda list must be nil terminated."); | |||||
| return; | return; | ||||
| } | } | ||||
| @@ -210,25 +223,32 @@ proc parse_argument_list(Lisp_Object* arguments, Function* function) -> void { | |||||
| string_equal(arguments->value.pair.first->value.identifier, "keys")) | string_equal(arguments->value.pair.first->value.identifier, "keys")) | ||||
| { | { | ||||
| arguments = arguments->value.pair.rest; | arguments = arguments->value.pair.rest; | ||||
| if (arguments->type != Lisp_Object_Type::Pair || | |||||
| arguments->value.pair.first->type != Lisp_Object_Type::Symbol) | |||||
| { | |||||
| create_error(Error_Type::Ill_Formed_Lambda_List, arguments->sourceCodeLocation); | |||||
| return; | |||||
| if (arguments->type != Lisp_Object_Type::Pair) { | |||||
| create_parsing_error("Actual keys have to follow the :keys indicator."); | |||||
| } | } | ||||
| // if (arguments->value.pair.first->type != Lisp_Object_Type::Symbol) { | |||||
| // create_parsing_error( | |||||
| // "Only symbols can be parsed here, but found '%s'.", | |||||
| // Lisp_Object_Type_to_string(arguments->value.pair.first->type)); | |||||
| // return; | |||||
| // } | |||||
| while (arguments->type == Lisp_Object_Type::Pair) { | while (arguments->type == Lisp_Object_Type::Pair) { | ||||
| if (arguments->value.pair.first->type == Lisp_Object_Type::Keyword) { | if (arguments->value.pair.first->type == Lisp_Object_Type::Keyword) { | ||||
| if (string_equal(arguments->value.pair.first->value.identifier, "rest")) | if (string_equal(arguments->value.pair.first->value.identifier, "rest")) | ||||
| break; | break; | ||||
| else { | else { | ||||
| create_error(Error_Type::Ill_Formed_Lambda_List, arguments->sourceCodeLocation); | |||||
| create_parsing_error( | |||||
| "Only the :rest keyword can be parsed here, but got ':%s'.", | |||||
| &arguments->value.pair.first->value.identifier->data); | |||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| if (arguments->value.pair.first->type != Lisp_Object_Type::Symbol) { | if (arguments->value.pair.first->type != Lisp_Object_Type::Symbol) { | ||||
| create_error(Error_Type::Ill_Formed_Lambda_List, arguments->sourceCodeLocation); | |||||
| create_parsing_error( | |||||
| "Only symbols can be parsed here, but found '%s'.", | |||||
| Lisp_Object_Type_to_string(arguments->value.pair.first->type)); | |||||
| return; | return; | ||||
| } | } | ||||
| @@ -250,7 +270,7 @@ proc parse_argument_list(Lisp_Object* arguments, Function* function) -> void { | |||||
| next->value.pair.first); | next->value.pair.first); | ||||
| arguments = next->value.pair.rest; | arguments = next->value.pair.rest; | ||||
| } else { | } else { | ||||
| create_error(Error_Type::Ill_Formed_Lambda_List, arguments->sourceCodeLocation); | |||||
| create_parsing_error("Expecting a value after 'defaults-to'"); | |||||
| return; | return; | ||||
| } | } | ||||
| } else { | } else { | ||||
| @@ -268,7 +288,7 @@ proc parse_argument_list(Lisp_Object* arguments, Function* function) -> void { | |||||
| // if there is a rest argument | // if there is a rest argument | ||||
| if (arguments->type != Lisp_Object_Type::Pair) { | if (arguments->type != Lisp_Object_Type::Pair) { | ||||
| if (arguments->type != Lisp_Object_Type::Nil) | if (arguments->type != Lisp_Object_Type::Nil) | ||||
| create_error(Error_Type::Ill_Formed_Lambda_List, arguments->sourceCodeLocation); | |||||
| create_parsing_error("The lambda list must be nil terminated."); | |||||
| return; | return; | ||||
| } | } | ||||
| @@ -1,6 +1,8 @@ | |||||
| proc assert_type(Lisp_Object*, Lisp_Object_Type) -> void; | |||||
| // proc assert_type(Lisp_Object*, Lisp_Object_Type) -> void; | |||||
| proc built_in_load(String*, Environment*) -> Lisp_Object*; | proc built_in_load(String*, Environment*) -> Lisp_Object*; | ||||
| proc create_error(Error_Type, Source_Code_Location*) -> void; | |||||
| proc create_error(const char* c_file_name, int c_file_line, Lisp_Object* type, String* message) -> void; | |||||
| proc create_error(const char* c_file_name, int c_file_line, Lisp_Object* type, const char* format, ...) -> void; | |||||
| proc create_error(Lisp_Object* type, const char* message, const char* c_file_name, int c_file_line) -> void; | |||||
| proc eval_arguments(Lisp_Object*, Environment*, int*) -> Lisp_Object*; | proc eval_arguments(Lisp_Object*, Environment*, int*) -> Lisp_Object*; | ||||
| proc eval_expr(Lisp_Object*, Environment*) -> Lisp_Object*; | proc eval_expr(Lisp_Object*, Environment*) -> Lisp_Object*; | ||||
| proc is_truthy (Lisp_Object*, Environment*) -> bool; | proc is_truthy (Lisp_Object*, Environment*) -> bool; | ||||
| @@ -8,3 +10,8 @@ proc list_length(Lisp_Object*) -> int; | |||||
| proc load_built_ins_into_environment(Environment*) -> void; | proc load_built_ins_into_environment(Environment*) -> void; | ||||
| proc parse_argument_list(Lisp_Object*, Function*) -> void; | proc parse_argument_list(Lisp_Object*, Function*) -> void; | ||||
| proc print_environment(Environment*) -> 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*; | |||||
| } | |||||
| @@ -281,19 +281,19 @@ proc print(Lisp_Object* node, bool print_quotes = false, FILE* file = stdout) -> | |||||
| proc print_error_location() -> void { | proc print_error_location() -> void { | ||||
| if (error->location) { | |||||
| printf("%s (line %d, position %d)", | |||||
| Memory::get_c_str(error->location->file), | |||||
| error->location->line, | |||||
| error->location->column); | |||||
| } else { | |||||
| printf("no source code location avaliable"); | |||||
| } | |||||
| // if (error->location) { | |||||
| // printf("%s (line %d, position %d)", | |||||
| // Memory::get_c_str(error->location->file), | |||||
| // error->location->line, | |||||
| // error->location->column); | |||||
| // } else { | |||||
| // printf("no source code location avaliable"); | |||||
| // } | |||||
| } | } | ||||
| proc log_error() -> void { | proc log_error() -> void { | ||||
| printf("%s%s%s\n", console_red, | printf("%s%s%s\n", console_red, | ||||
| Error_Type_to_string(error->type), | |||||
| Memory::get_c_str(error->message), | |||||
| console_normal); | console_normal); | ||||
| printf(" in: %s", console_cyan); | printf(" in: %s", console_cyan); | ||||
| print_error_location(); | print_error_location(); | ||||
| @@ -3,7 +3,7 @@ namespace Memory { | |||||
| // ------------------ | // ------------------ | ||||
| // lisp_object | // lisp_object | ||||
| // ------------------ | // ------------------ | ||||
| int object_memory_size; | |||||
| int object_memory_size; | |||||
| Int_Array_List* free_spots_in_object_memory; | Int_Array_List* free_spots_in_object_memory; | ||||
| Lisp_Object* object_memory; | Lisp_Object* object_memory; | ||||
| int next_index_in_object_memory = 0; | int next_index_in_object_memory = 0; | ||||
| @@ -82,13 +82,33 @@ namespace Memory { | |||||
| return create_string(str, (int)strlen(str)); | return create_string(str, (int)strlen(str)); | ||||
| } | } | ||||
| // proc create_string_formatted (const char* format, ...) -> String* { | |||||
| // // HACK(Felix): the length of all strings is 200!!!!!!!!!! | |||||
| // // HACK(Felix): the length of all strings is 200!!!!!!!!!! | |||||
| // int length = 200; | |||||
| // String* ret = create_string("", length); | |||||
| // int written_length; | |||||
| // va_list args; | |||||
| // va_start(args, format); | |||||
| // written_length = vsnprintf(&ret->data, length, format, args); | |||||
| // va_end(args); | |||||
| // ret->length = written_length; | |||||
| // return ret; | |||||
| // } | |||||
| proc create_lisp_object() -> Lisp_Object* { | proc create_lisp_object() -> Lisp_Object* { | ||||
| int index; | int index; | ||||
| // if we have no free spots then append at the end | // if we have no free spots then append at the end | ||||
| if (free_spots_in_object_memory->next_index == 0) { | if (free_spots_in_object_memory->next_index == 0) { | ||||
| // if we still have space | // if we still have space | ||||
| if (object_memory_size == next_index_in_object_memory) { | if (object_memory_size == next_index_in_object_memory) { | ||||
| create_error(Error_Type::Out_Of_Memory, nullptr); | |||||
| create_out_of_memory_error( | |||||
| "There is not enough space in the lisp object" | |||||
| "memory to allocate additional lisp objects. " | |||||
| "Maybe try increasing the Memory size when " | |||||
| "calling Memory::init()"); | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| index = next_index_in_object_memory++; | index = next_index_in_object_memory++; | ||||
| @@ -162,6 +182,9 @@ namespace Memory { | |||||
| } | } | ||||
| proc get_or_create_lisp_object_symbol(const char* identifier) -> Lisp_Object* { | proc get_or_create_lisp_object_symbol(const char* identifier) -> Lisp_Object* { | ||||
| // TODO(Felix): This is really bad: we create a new string | |||||
| // even if the symbol/keyword is already existing, just to | |||||
| // check IF it exists and then never deleting it. | |||||
| return get_or_create_lisp_object_symbol( | return get_or_create_lisp_object_symbol( | ||||
| Memory::create_string(identifier)); | Memory::create_string(identifier)); | ||||
| } | } | ||||
| @@ -177,6 +200,9 @@ namespace Memory { | |||||
| } | } | ||||
| proc get_or_create_lisp_object_keyword(const char* keyword) -> Lisp_Object* { | proc get_or_create_lisp_object_keyword(const char* keyword) -> Lisp_Object* { | ||||
| // TODO(Felix): This is really bad: we create a new string | |||||
| // even if the symbol/keyword is already existing, just to | |||||
| // check IF it exists and then never deleting it. | |||||
| return get_or_create_lisp_object_keyword( | return get_or_create_lisp_object_keyword( | ||||
| Memory::create_string(keyword)); | Memory::create_string(keyword)); | ||||
| } | } | ||||
| @@ -166,15 +166,15 @@ namespace Parser { | |||||
| // we found the end of the string | // we found the end of the string | ||||
| text[*index_in_text+string_length] = '\0'; | text[*index_in_text+string_length] = '\0'; | ||||
| String* string = Memory::create_string("", string_length); | |||||
| if (!unescape_string(text+(*index_in_text))) { | if (!unescape_string(text+(*index_in_text))) { | ||||
| create_error( | |||||
| Error_Type::Unknown_Error, | |||||
| create_source_code_location(parser_file, parser_line, parser_col)); | |||||
| create_parsing_error( | |||||
| "The string '%s' at %s:%d:%d could not be unescaped.", | |||||
| text+(*index_in_text), parser_file, parser_line, parser_col); | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| String* string = Memory::create_string("", string_length); | |||||
| // TODO(Felix): manually copy to parse control sequences | // TODO(Felix): manually copy to parse control sequences | ||||
| // correctly without the need to unescape the string, also | // correctly without the need to unescape the string, also | ||||
| // better for keeping track of the encountered new lines and | // better for keeping track of the encountered new lines and | ||||
| @@ -314,7 +314,9 @@ namespace Parser { | |||||
| eat_until_code(text, index_in_text); | eat_until_code(text, index_in_text); | ||||
| if (text[(*index_in_text)] == '\0') { | if (text[(*index_in_text)] == '\0') { | ||||
| create_error(Error_Type::Unexpected_Eof, create_source_code_location(parser_file, parser_line, parser_col)); | |||||
| create_parsing_error( | |||||
| "Unexpected EOF in %s:%d:%d", | |||||
| parser_file, parser_line, parser_col); | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| @@ -337,7 +339,9 @@ namespace Parser { | |||||
| eat_until_code(text, index_in_text); | eat_until_code(text, index_in_text); | ||||
| if (text[(*index_in_text)] != ')') | if (text[(*index_in_text)] != ')') | ||||
| create_error(Error_Type::Syntax_Error, create_source_code_location(parser_file, parser_line, parser_col)); | |||||
| create_parsing_error( | |||||
| "Expected ')' after the element after the '.' in %s:%d:%d", | |||||
| create_source_code_location(parser_file, parser_line, parser_col)); | |||||
| ++parser_col; | ++parser_col; | ||||
| ++(*index_in_text); | ++(*index_in_text); | ||||
| break; | break; | ||||
| @@ -362,14 +366,11 @@ namespace Parser { | |||||
| // (define-syntax defun (name args :rest body) (...)) | // (define-syntax defun (name args :rest body) (...)) | ||||
| if (arguments_length < 2) { | if (arguments_length < 2) { | ||||
| create_error(Error_Type::Wrong_Number_Of_Arguments, expression->sourceCodeLocation); | |||||
| create_wrong_number_of_arguments_error(3, arguments_length); | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| if (arguments->value.pair.first->type != Lisp_Object_Type::Symbol) { | |||||
| create_error(Error_Type::Type_Missmatch, expression->sourceCodeLocation); | |||||
| return nullptr; | |||||
| } | |||||
| assert_type(arguments->value.pair.first, Lisp_Object_Type::Symbol); | |||||
| // extract the name | // extract the name | ||||
| Lisp_Object* symbol_for_macro = arguments->value.pair.first; | Lisp_Object* symbol_for_macro = arguments->value.pair.first; | ||||
| @@ -429,7 +430,8 @@ namespace Parser { | |||||
| // that, when an entry is not found immidiately, we | // that, when an entry is not found immidiately, we | ||||
| // know for sure that it does not exist in the table. | // know for sure that it does not exist in the table. | ||||
| create_error(Error_Type::Not_Yet_Implemented, expression->sourceCodeLocation); | |||||
| create_generic_error("deleting macros has not yet be implemented," | |||||
| "and I don't know if it is a good idea to do so."); | |||||
| return nullptr; | return nullptr; | ||||
| } else { | } else { | ||||
| // if threre is a macro named like this, then macroexpand | // if threre is a macro named like this, then macroexpand | ||||
| @@ -478,7 +480,9 @@ namespace Parser { | |||||
| eat_until_code(text, &index_in_text); | eat_until_code(text, &index_in_text); | ||||
| if (text[(index_in_text)] == '\0') | if (text[(index_in_text)] == '\0') | ||||
| return result; | return result; | ||||
| create_error(Error_Type::Trailing_Garbage, create_source_code_location(parser_file, parser_line, parser_col)); | |||||
| create_parsing_error("Trainling garbage after expression at %s:%d:%d", | |||||
| parser_file, parser_line, parser_col); | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| @@ -573,7 +577,8 @@ namespace Parser { | |||||
| } break; | } break; | ||||
| default: | default: | ||||
| /* syntax error */ | /* syntax error */ | ||||
| create_error(Error_Type::Syntax_Error, create_source_code_location(parser_file, parser_line, parser_col)); | |||||
| create_parsing_error("Garbage in file scope at %s:%d:%d", | |||||
| parser_file, parser_line, parser_col); | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| } | } | ||||
| @@ -6,11 +6,13 @@ | |||||
| #include <string.h> | #include <string.h> | ||||
| #include <cmath> | #include <cmath> | ||||
| #include <ctype.h> | #include <ctype.h> | ||||
| // #include <type_traits> | |||||
| #include <stdarg.h> | |||||
| #include <functional> | #include <functional> | ||||
| #undef _CRT_SECURE_NO_DEPRECATE | |||||
| #undef _CRT_SECURE_NO_WARNINGS | |||||
| namespace Slime { | |||||
| // namespace Slime { | |||||
| #include "./defines.cpp" | #include "./defines.cpp" | ||||
| #include "./structs.cpp" | #include "./structs.cpp" | ||||
| #include "./forward_decls.cpp" | #include "./forward_decls.cpp" | ||||
| @@ -24,7 +26,4 @@ namespace Slime { | |||||
| #include "./built_ins.cpp" | #include "./built_ins.cpp" | ||||
| #include "./testing.cpp" | #include "./testing.cpp" | ||||
| #include "./undefines.cpp" | #include "./undefines.cpp" | ||||
| } | |||||
| #undef _CRT_SECURE_NO_DEPRECATE | |||||
| #undef _CRT_SECURE_NO_WARNINGS | |||||
| // } | |||||
| @@ -26,25 +26,25 @@ enum struct Function_Type { | |||||
| Macro | Macro | ||||
| }; | }; | ||||
| enum struct Error_Type { | |||||
| Assertion_Error, | |||||
| File_Not_Found, | |||||
| Ill_Formed_Arguments, | |||||
| Ill_Formed_Lambda_List, | |||||
| Ill_Formed_List, | |||||
| Not_A_Function, | |||||
| Not_Yet_Implemented, | |||||
| Out_Of_Memory, | |||||
| Symbol_Not_Defined, | |||||
| Syntax_Error, | |||||
| Trailing_Garbage, | |||||
| Type_Missmatch, | |||||
| Unbalanced_Parenthesis, | |||||
| Unexpected_Eof, | |||||
| Unknown_Error, | |||||
| Unknown_Keyword_Argument, | |||||
| Wrong_Number_Of_Arguments, | |||||
| }; | |||||
| // enum struct Error_Type { | |||||
| // Assertion_Error, | |||||
| // File_Not_Found, | |||||
| // Ill_Formed_Arguments, | |||||
| // Ill_Formed_Lambda_List, | |||||
| // Ill_Formed_List, | |||||
| // Not_A_Function, | |||||
| // Not_Yet_Implemented, | |||||
| // Out_Of_Memory, | |||||
| // Symbol_Not_Defined, | |||||
| // Syntax_Error, | |||||
| // Trailing_Garbage, | |||||
| // Type_Missmatch, | |||||
| // Unbalanced_Parenthesis, | |||||
| // Unexpected_Eof, | |||||
| // Unknown_Error, | |||||
| // Unknown_Keyword_Argument, | |||||
| // Wrong_Number_Of_Arguments, | |||||
| // }; | |||||
| enum struct Log_Level { | enum struct Log_Level { | ||||
| None, | None, | ||||
| @@ -141,12 +141,15 @@ struct Environment { | |||||
| int capacity; | int capacity; | ||||
| int next_index; | int next_index; | ||||
| // TODO(Felix): Use a hashmap here. | // TODO(Felix): Use a hashmap here. | ||||
| char** keys; | |||||
| char** keys; | |||||
| Lisp_Object** values; | Lisp_Object** values; | ||||
| }; | }; | ||||
| struct Error { | struct Error { | ||||
| Error_Type type; | |||||
| Source_Code_Location* location; | |||||
| Lisp_Object* position; | |||||
| // type has to be a keyword | |||||
| Lisp_Object* type; | |||||
| String* message; | |||||
| }; | }; | ||||
| @@ -1,3 +1,4 @@ | |||||
| * TODO rename sliem to plisk | |||||
| * TODO BUG 1: eval dot notation | * TODO BUG 1: eval dot notation | ||||
| #+BEGIN_SRC lisp | #+BEGIN_SRC lisp | ||||
| (eval `(+ . ,(list 1 2 3))) | (eval `(+ . ,(list 1 2 3))) | ||||