| @@ -0,0 +1,36 @@ | |||||
| ((c-mode . ((eval . (company-clang-set-prefix "main.c")) | |||||
| (eval . (flycheck-mode 0)) | |||||
| (eval . (rainbow-mode 0)))) | |||||
| (nil . ((eval . (progn | |||||
| (defvar context-mode-map (make-sparse-keymap) | |||||
| "Keymap while context-mode is active.") | |||||
| (define-minor-mode context-mode | |||||
| "A temporary minor mode to be activated only specific to a buffer." | |||||
| nil | |||||
| :lighter " Context" | |||||
| 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) | |||||
| ("q" nil "quit" :color blue)) | |||||
| (define-key context-mode-map (kbd "<f2>") 'hydra-context/body) | |||||
| ))))) | |||||
| @@ -3,4 +3,6 @@ | |||||
| /*.ilk | /*.ilk | ||||
| /*.pdb | /*.pdb | ||||
| /.vs/ | /.vs/ | ||||
| /vs/ | |||||
| /vs/ | |||||
| /*.exe | |||||
| *.exe | |||||
| @@ -1 +1,12 @@ | |||||
| (/ (+ 1 (- 100 7 3)) 2) | |||||
| ((lambda (x) (* x x)) 2) | |||||
| (setq a 3) | |||||
| (let ((a 10)) | |||||
| (let ((b 5)) | |||||
| (setq a 4)) | |||||
| a) | |||||
| a | |||||
| @@ -2,8 +2,6 @@ | |||||
| @setlocal | @setlocal | ||||
| pushd %~dp0 | pushd %~dp0 | ||||
| set start=%time% | |||||
| set exeName=lisp.exe | set exeName=lisp.exe | ||||
| set binDir=bin | set binDir=bin | ||||
| @@ -17,11 +15,6 @@ if %errorlevel% == 0 ( | |||||
| echo. | echo. | ||||
| if not exist ..\%binDir% mkdir ..\%binDir% | if not exist ..\%binDir% mkdir ..\%binDir% | ||||
| move %exeName% ..\%binDir%\ > NUL | move %exeName% ..\%binDir%\ > NUL | ||||
| pushd ..\%binDir% | |||||
| echo ---------- Running ---------- | |||||
| call timecmd %exeName% test.lsp | |||||
| del %exeName% /S /Q > NUL | |||||
| popd | |||||
| ) else ( | ) else ( | ||||
| echo. | echo. | ||||
| echo Fucki'n 'ell | echo Fucki'n 'ell | ||||
| @@ -0,0 +1,3 @@ | |||||
| pushd %~dp0\vs | |||||
| start lisp.sln | |||||
| popd | |||||
| @@ -0,0 +1,9 @@ | |||||
| @echo off | |||||
| pushd %~dp0\bin | |||||
| call ..\build.bat | |||||
| if %errorlevel% == 0 ( | |||||
| echo ---------- Running ---------- | |||||
| call timecmd lisp.exe | |||||
| ) | |||||
| popd | |||||
| @@ -1,3 +0,0 @@ | |||||
| ((c-mode . ((eval . (company-clang-set-prefix "main.c")) | |||||
| (eval . (flycheck-mode 0)) | |||||
| (eval . (rainbow-mode 0))))) | |||||
| @@ -1,7 +1,8 @@ | |||||
| struct Environment { | struct Environment { | ||||
| struct Environment* parent; | struct Environment* parent; | ||||
| int key_count; | |||||
| int capacity; | |||||
| int next_index; | |||||
| char** keys; | char** keys; | ||||
| Ast_Node* values; | Ast_Node* values; | ||||
| }; | }; | ||||
| @@ -11,16 +12,37 @@ typedef struct Environment Environment; | |||||
| Environment* create_empty_environment() { | Environment* create_empty_environment() { | ||||
| Environment* env = new(Environment); | Environment* env = new(Environment); | ||||
| env->parent = nullptr; | |||||
| env->key_count = 0; | |||||
| env->keys = nullptr; | |||||
| env->values = nullptr; | |||||
| int start_capacity = 1; | |||||
| env->parent = nullptr; | |||||
| env->capacity = start_capacity; | |||||
| env->next_index = 0; | |||||
| env->keys = (char**)malloc(start_capacity * sizeof(char*)); | |||||
| env->values = (Ast_Node*)malloc(start_capacity * sizeof(Ast_Node)); | |||||
| return env; | return env; | ||||
| } | } | ||||
| void define_symbol(Ast_Node* symbol, Ast_Node* value, Environment* env) { | |||||
| // NOTE(Felix): right now we are simmply adding the symol at the | |||||
| // back of the list without checking if it already exists but are | |||||
| // also searching for thesymbol from the back, so we will find the | |||||
| // latest defined one first, but a bit messy. Later we should use | |||||
| // a hashmap here. @refactor | |||||
| if (env->next_index == env->capacity) { | |||||
| env->capacity *= 2; | |||||
| env->keys = (char**)realloc(env->keys, env->capacity * sizeof(char*)); | |||||
| env->values = (Ast_Node*)realloc(env->values, env->capacity * sizeof(Ast_Node)); | |||||
| } | |||||
| env->keys [env->next_index] = symbol->value.symbol->identifier; | |||||
| env->values[env->next_index] = *value; | |||||
| ++env->next_index; | |||||
| } | |||||
| Ast_Node* lookup_symbol(Symbol* sym, Environment* env) { | Ast_Node* lookup_symbol(Symbol* sym, Environment* env) { | ||||
| for (int i = 0; i < env->key_count; ++i) | |||||
| for (int i = env->next_index - 1; i >= 0; --i) | |||||
| if (string_equal(env->keys[i], sym->identifier)) | if (string_equal(env->keys[i], sym->identifier)) | ||||
| return env->values+i; | return env->values+i; | ||||
| @@ -30,19 +52,19 @@ Ast_Node* lookup_symbol(Symbol* sym, Environment* env) { | |||||
| char* built_in_names[] = { | char* built_in_names[] = { | ||||
| // Math stuff | // Math stuff | ||||
| "+", "-", "*", "/", | "+", "-", "*", "/", | ||||
| ">", "<", "=", | |||||
| ">", "<", "=", "<=", ">=", | |||||
| // Conditional stuff | // Conditional stuff | ||||
| "if", "and", "or", "not", | "if", "and", "or", "not", | ||||
| // Cons stuff | // Cons stuff | ||||
| "first", "rest", "pair", | "first", "rest", "pair", | ||||
| // rest | // rest | ||||
| "load", "define", | |||||
| "load", "define", | |||||
| "lambda", "progn", | "lambda", "progn", | ||||
| "eval", "quote", | |||||
| "print", "read", | |||||
| "help" | |||||
| "eval", "quote", | |||||
| "print", "read", | |||||
| "help", "exit" | |||||
| }; | }; | ||||
| int built_in_count = 23; | |||||
| int built_in_count = 26; | |||||
| for (int i = 0; i < built_in_count; ++i) { | for (int i = 0; i < built_in_count; ++i) { | ||||
| if (string_equal(built_in_names[i], sym->identifier)) { | if (string_equal(built_in_names[i], sym->identifier)) { | ||||
| @@ -7,6 +7,8 @@ typedef enum { | |||||
| Error_Type_Not_Yet_Implemented, | Error_Type_Not_Yet_Implemented, | ||||
| Error_Type_Syntax_Error, | Error_Type_Syntax_Error, | ||||
| Error_Type_Unexpected_Eof, | Error_Type_Unexpected_Eof, | ||||
| Error_Type_Unbalanced_Parenthesis, | |||||
| Error_Type_Trailing_Garbage, | |||||
| Error_Type_Unknown_Error, | Error_Type_Unknown_Error, | ||||
| } Error_Type; | } Error_Type; | ||||
| @@ -34,15 +36,16 @@ void create_error(Error_Type type, Ast_Node* location) { | |||||
| char* Error_Type_to_string(Error_Type type) { | char* Error_Type_to_string(Error_Type type) { | ||||
| switch (type) { | switch (type) { | ||||
| case Error_Type_Ill_Formed_List: return "Ill formed list"; | |||||
| case Error_Type_Not_A_Function: return "Not a function"; | |||||
| case Error_Type_Symbol_Not_Defined: return "Symbol not defined"; | |||||
| case Error_Type_Wrong_Number_Of_Arguments: return "Wrong number of arguments"; | |||||
| case Error_Type_Type_Missmatch: return "Type Missmatch"; | |||||
| case Error_Type_Not_Yet_Implemented: return "Not yet implemented"; | |||||
| 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_Symbol_Not_Defined: return "Evaluation-error: Symbol not defined"; | |||||
| case Error_Type_Wrong_Number_Of_Arguments: return "Evaluation-error: Wrong number of arguments"; | |||||
| case Error_Type_Type_Missmatch: return "Evaluation-error: Type Missmatch"; | |||||
| case Error_Type_Not_Yet_Implemented: return "Evaluation-error: Not yet implemented"; | |||||
| case Error_Type_Trailing_Garbage: return "Evaluation-error: Trailing garbage following expression"; | |||||
| case Error_Type_Syntax_Error: return "Syntax Error"; | case Error_Type_Syntax_Error: return "Syntax Error"; | ||||
| case Error_Type_Unexpected_Eof: return "Unexpected EOF"; | |||||
| case Error_Type_Unexpected_Eof: return "Parsing-error: Unexpected EOF"; | |||||
| case Error_Type_Unbalanced_Parenthesis: return "Parsing-error: Unbalanced parenthesis"; | |||||
| default: return "Unknown Error"; | default: return "Unknown Error"; | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,9 +1,5 @@ | |||||
| /* Ast_Node* apply_to_lambda () {} */ | /* Ast_Node* apply_to_lambda () {} */ | ||||
| /* Ast_Node* apply_to_built_in (Ast_Node* function, Ast_Node* arguments) { */ | |||||
| /* } */ | |||||
| Ast_Node* eval_expr(Ast_Node* node, Environment* env); | Ast_Node* eval_expr(Ast_Node* node, Environment* env); | ||||
| bool is_truthy (Ast_Node* expression, Environment* env); | bool is_truthy (Ast_Node* expression, Environment* env); | ||||
| @@ -43,10 +39,10 @@ void eval_operands(Ast_Node* operands, Environment* env) { | |||||
| Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | ||||
| #define report_error(_type) { \ | #define report_error(_type) { \ | ||||
| create_error(_type, node); \ | create_error(_type, node); \ | ||||
| log_error(); \ | |||||
| exit(1); \ | |||||
| return nullptr; \ | return nullptr; \ | ||||
| } | } | ||||
| if (error) | |||||
| return nullptr; | |||||
| Ast_Node* ret = new(Ast_Node); | Ast_Node* ret = new(Ast_Node); | ||||
| switch (node->type) { | switch (node->type) { | ||||
| @@ -56,31 +52,112 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||||
| case Ast_Node_Type_Symbol: | case Ast_Node_Type_Symbol: | ||||
| return lookup_symbol(node->value.symbol, env); | return lookup_symbol(node->value.symbol, env); | ||||
| case Ast_Node_Type_Number: | case Ast_Node_Type_Number: | ||||
| case Ast_Node_Type_Keyword: | |||||
| case Ast_Node_Type_String: | case Ast_Node_Type_String: | ||||
| return node; | return node; | ||||
| case Ast_Node_Type_Pair: { | case Ast_Node_Type_Pair: { | ||||
| Ast_Node* operator = eval_expr(node->value.pair->first, env); | Ast_Node* operator = eval_expr(node->value.pair->first, env); | ||||
| if (error) return nullptr; | |||||
| Ast_Node* operands = node->value.pair->rest; | Ast_Node* operands = node->value.pair->rest; | ||||
| // check for built ins functions | // check for built ins functions | ||||
| if (operator->type == Ast_Node_Type_Built_In_Function) { | if (operator->type == Ast_Node_Type_Built_In_Function) { | ||||
| char* operator_name = operator->value.built_in_function->identifier; | char* operator_name = operator->value.built_in_function->identifier; | ||||
| if (string_equal("quote", operator_name)) { | if (string_equal("quote", operator_name)) { | ||||
| return node->value.pair->rest; | |||||
| int operands_length = list_length(operands); | |||||
| if (operands_length != 1) { | |||||
| report_error(Error_Type_Wrong_Number_Of_Arguments); | |||||
| } | |||||
| return operands->value.pair->first; | |||||
| } else if (string_equal("eval", operator_name)) { | |||||
| int operands_length = list_length(operands); | |||||
| if (operands_length != 1) { | |||||
| report_error(Error_Type_Wrong_Number_Of_Arguments); | |||||
| } | |||||
| if (error) return nullptr; | |||||
| return eval_expr(operands->value.pair->first, env); | |||||
| } else if (string_equal("+", operator_name)) { | } else if (string_equal("+", operator_name)) { | ||||
| eval_operands(operands, env); | eval_operands(operands, env); | ||||
| if (error) return nullptr; | |||||
| return built_in_add(operands); | return built_in_add(operands); | ||||
| } else if (string_equal("-", operator_name)) { | } else if (string_equal("-", operator_name)) { | ||||
| eval_operands(operands, env); | eval_operands(operands, env); | ||||
| if (error) return nullptr; | |||||
| return built_in_substract(operands); | return built_in_substract(operands); | ||||
| } else if (string_equal("*", operator_name)) { | } else if (string_equal("*", operator_name)) { | ||||
| eval_operands(operands, env); | eval_operands(operands, env); | ||||
| if (error) return nullptr; | |||||
| return built_in_multiply(operands); | return built_in_multiply(operands); | ||||
| } else if (string_equal("/", operator_name)) { | } else if (string_equal("/", operator_name)) { | ||||
| eval_operands(operands, env); | eval_operands(operands, env); | ||||
| if (error) return nullptr; | |||||
| return built_in_divide(operands); | return built_in_divide(operands); | ||||
| } else if (string_equal("define", operator_name)) { | |||||
| int operands_length = list_length(operands); | |||||
| if (error) return nullptr; | |||||
| if (operands_length != 2) { | |||||
| report_error(Error_Type_Wrong_Number_Of_Arguments); | |||||
| } | |||||
| Ast_Node* symbol = operands->value.pair->first; | |||||
| if (symbol->type != Ast_Node_Type_Symbol) | |||||
| report_error(Error_Type_Type_Missmatch); | |||||
| Ast_Node* value = operands->value.pair->rest->value.pair->first; | |||||
| value = eval_expr(value, env); | |||||
| define_symbol(symbol, value, env); | |||||
| return value; | |||||
| } else if (string_equal("exit", operator_name)) { | |||||
| int operands_length = list_length(operands); | |||||
| if (error) return nullptr; | |||||
| if (operands_length > 1) { | |||||
| report_error(Error_Type_Wrong_Number_Of_Arguments); | |||||
| } | |||||
| if (operands_length == 1) { | |||||
| Ast_Node* error_code = operands->value.pair->first; | |||||
| if (error_code->type != Ast_Node_Type_Number) | |||||
| report_error(Error_Type_Type_Missmatch); | |||||
| exit((int)error_code->value.number->value); | |||||
| } | |||||
| exit(0); | |||||
| } else if (string_equal("print", operator_name)) { | |||||
| int operands_length = list_length(operands); | |||||
| if (error) return nullptr; | |||||
| if (operands_length != 1) { | |||||
| report_error(Error_Type_Wrong_Number_Of_Arguments); | |||||
| } | |||||
| eval_operands(operands, env); | |||||
| if (error) return nullptr; | |||||
| print(operands->value.pair->first); | |||||
| printf("\n"); | |||||
| return operands->value.pair->first; | |||||
| } else if (string_equal("read", operator_name)) { | |||||
| int operands_length = list_length(operands); | |||||
| if (error) return nullptr; | |||||
| if (operands_length > 1) { | |||||
| report_error(Error_Type_Wrong_Number_Of_Arguments); | |||||
| } | |||||
| if (operands_length == 1) { | |||||
| eval_operands(operands, env); | |||||
| if (error) return nullptr; | |||||
| Ast_Node* prompt = operands->value.pair->first; | |||||
| if (prompt->type == Ast_Node_Type_String) | |||||
| printf("%s", prompt->value.string->value); | |||||
| else | |||||
| print(operands->value.pair->first); | |||||
| } | |||||
| char* line = read_line(); | |||||
| return create_ast_node_string(line, (int)strlen(line)); | |||||
| } else if (string_equal("if", operator_name)) { | } else if (string_equal("if", operator_name)) { | ||||
| int operands_length = list_length(operands); | int operands_length = list_length(operands); | ||||
| if (error) return nullptr; | |||||
| if (operands_length != 2 && operands_length != 3) { | if (operands_length != 2 && operands_length != 3) { | ||||
| report_error(Error_Type_Wrong_Number_Of_Arguments); | report_error(Error_Type_Wrong_Number_Of_Arguments); | ||||
| } | } | ||||
| @@ -89,7 +166,9 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||||
| Ast_Node* then_part = operands->value.pair->rest; | Ast_Node* then_part = operands->value.pair->rest; | ||||
| Ast_Node* else_part = then_part->value.pair->rest; | Ast_Node* else_part = then_part->value.pair->rest; | ||||
| if (is_truthy(condition, env)) | |||||
| bool truthy = is_truthy(condition, env); | |||||
| if (error) return nullptr; | |||||
| if (truthy) | |||||
| return eval_expr(then_part->value.pair->first, env); | return eval_expr(then_part->value.pair->first, env); | ||||
| else if (operands_length == 3) | else if (operands_length == 3) | ||||
| return eval_expr(else_part->value.pair->first, env); | return eval_expr(else_part->value.pair->first, env); | ||||
| @@ -102,6 +181,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||||
| report_error(Error_Type_Ill_Formed_List); | report_error(Error_Type_Ill_Formed_List); | ||||
| } | } | ||||
| result &= is_truthy(operands->value.pair->first, env); | result &= is_truthy(operands->value.pair->first, env); | ||||
| if (error) return nullptr; | |||||
| operands = operands->value.pair->rest; | operands = operands->value.pair->rest; | ||||
| if (!result) return create_ast_node_nil(); | if (!result) return create_ast_node_nil(); | ||||
| @@ -116,6 +196,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||||
| report_error(Error_Type_Ill_Formed_List); | report_error(Error_Type_Ill_Formed_List); | ||||
| } | } | ||||
| result |= is_truthy(operands->value.pair->first, env); | result |= is_truthy(operands->value.pair->first, env); | ||||
| if (error) return nullptr; | |||||
| operands = operands->value.pair->rest; | operands = operands->value.pair->rest; | ||||
| if (result) return create_ast_node_number(1);; | if (result) return create_ast_node_number(1);; | ||||
| @@ -129,6 +210,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| bool truthy = is_truthy(operands->value.pair->first, env); | bool truthy = is_truthy(operands->value.pair->first, env); | ||||
| if (error) return nullptr; | |||||
| if (truthy) | if (truthy) | ||||
| return create_ast_node_nil(); | return create_ast_node_nil(); | ||||
| return create_ast_node_number(1); | return create_ast_node_number(1); | ||||
| @@ -150,6 +232,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||||
| bool is_truthy (Ast_Node* expression, Environment* env) { | bool is_truthy (Ast_Node* expression, Environment* env) { | ||||
| Ast_Node* result = eval_expr(expression, env); | Ast_Node* result = eval_expr(expression, env); | ||||
| if (error) return false; | |||||
| switch (result->type) { | switch (result->type) { | ||||
| case Ast_Node_Type_Nil: return false; | case Ast_Node_Type_Nil: return false; | ||||
| /* case Ast_Node_Type_Number: return result->value.number->value != 0; */ | /* case Ast_Node_Type_Number: return result->value.number->value != 0; */ | ||||
| @@ -16,46 +16,66 @@ | |||||
| #include "./eval.c" | #include "./eval.c" | ||||
| #include "./testing.c" | #include "./testing.c" | ||||
| int interprete_file (char* file_content) { | |||||
| Ast_Node_Array_List* program = parse_program(file_content); | |||||
| if (error) { | |||||
| log_error(); | |||||
| return 1; | |||||
| } | |||||
| Environment* env = create_empty_environment(); | |||||
| Ast_Node* result = create_ast_node_nil(); | |||||
| for (int i = 0; i < program->next_index; ++i) { | |||||
| result = eval_expr(program->data[i], env); | |||||
| if (error) { | |||||
| log_error(); | |||||
| return 1; | |||||
| } | |||||
| } | |||||
| print(result); | |||||
| printf("\n"); | |||||
| return 0; | |||||
| } | |||||
| int interprete_stdin () { | |||||
| printf("Welcome to the lispy interpreter.\n"); | |||||
| char* line; | |||||
| Environment* env = create_empty_environment(); | |||||
| Ast_Node* parsed, * evaluated; | |||||
| while (true) { | |||||
| printf(">"); | |||||
| line = read_line(); | |||||
| parsed = parse_single_expression(line); | |||||
| if (error) { | |||||
| log_error(); | |||||
| delete_error(); | |||||
| continue; | |||||
| } | |||||
| evaluated = eval_expr(parsed, env); | |||||
| if (error) { | |||||
| log_error(); | |||||
| delete_error(); | |||||
| continue; | |||||
| } | |||||
| print(evaluated); | |||||
| printf("\n"); | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| int main (int argc, char *argv[]) { | int main (int argc, char *argv[]) { | ||||
| if (argc > 1) { | if (argc > 1) { | ||||
| char* fileContent = read_entire_file(argv[1]); | |||||
| if (fileContent) { | |||||
| Ast_Node_Array_List* program = parse_program(fileContent); | |||||
| if (error) { | |||||
| log_error(); | |||||
| exit(1); | |||||
| } | |||||
| Environment* env = create_empty_environment(); | |||||
| Ast_Node* result = create_ast_node_nil(); | |||||
| for (int i = 0; i < program->next_index; ++i) { | |||||
| result = eval_expr(program->data[i], env); | |||||
| if (error) { | |||||
| log_error(); | |||||
| exit(1); | |||||
| } | |||||
| } | |||||
| print(result); | |||||
| printf("\n"); | |||||
| char* file_content = read_entire_file(argv[1]); | |||||
| if (file_content) { | |||||
| return interprete_file(file_content); | |||||
| } else { | } else { | ||||
| printf("The file could not be read\n"); | printf("The file could not be read\n"); | ||||
| return 1; | |||||
| } | } | ||||
| } else { | } else { | ||||
| run_all_tests(); | run_all_tests(); | ||||
| printf("Welcome to the lispy interpreter.\n"); | |||||
| char* line; | |||||
| Environment* env = create_empty_environment(); | |||||
| Ast_Node* parsed, * evaluated; | |||||
| while (true) { | |||||
| printf(">"); | |||||
| line = read_line(); | |||||
| parsed = parse_single_expression(line); | |||||
| evaluated = eval_expr(parsed, env); | |||||
| print(evaluated); | |||||
| printf("\n"); | |||||
| } | |||||
| return interprete_stdin(); | |||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -18,10 +18,8 @@ Ast_Node_Array_List* create_Ast_Node_Array_List() { | |||||
| void append_to_Ast_Node_Array_List(Ast_Node_Array_List* list, Ast_Node* node) { | void append_to_Ast_Node_Array_List(Ast_Node_Array_List* list, Ast_Node* node) { | ||||
| if (list->next_index == list->length) { | if (list->next_index == list->length) { | ||||
| list->length *= 2; | list->length *= 2; | ||||
| list->data = | |||||
| (Ast_Node**)realloc(list->data, list->length * sizeof(Ast_Node)); | |||||
| list->data = (Ast_Node**)realloc(list->data, list->length * sizeof(Ast_Node)); | |||||
| } | } | ||||
| list->data[list->next_index++] = node; | list->data[list->next_index++] = node; | ||||
| } | } | ||||
| @@ -231,7 +229,17 @@ Ast_Node* parse_expression(char* text, int* index_in_text) { | |||||
| Ast_Node* parse_single_expression(char* text) { | Ast_Node* parse_single_expression(char* text) { | ||||
| int index_in_text = 0; | int index_in_text = 0; | ||||
| return parse_expression(text, &index_in_text); | |||||
| Ast_Node* result; | |||||
| eat_until_code(text, &index_in_text); | |||||
| if (text[(index_in_text)] == '(') | |||||
| result = parse_expression(text, &index_in_text); | |||||
| else | |||||
| result = parse_atom(text, &index_in_text); | |||||
| eat_until_code(text, &index_in_text); | |||||
| if (text[(index_in_text)] == '\0') | |||||
| return result; | |||||
| create_error(Error_Type_Trailing_Garbage, create_ast_node_nil()); | |||||
| return nullptr; | |||||
| } | } | ||||
| Ast_Node_Array_List* parse_program(char* text) { | Ast_Node_Array_List* parse_program(char* text) { | ||||
| @@ -247,13 +255,11 @@ Ast_Node_Array_List* parse_program(char* text) { | |||||
| return nullptr; | return nullptr; | ||||
| append_to_Ast_Node_Array_List(program, parsed); | append_to_Ast_Node_Array_List(program, parsed); | ||||
| } break; | } break; | ||||
| case ';': { | |||||
| eat_comment_line(text, &index_in_text); | |||||
| } break; | |||||
| case ';': | |||||
| case ' ': | case ' ': | ||||
| case '\t': | case '\t': | ||||
| case '\n': { | case '\n': { | ||||
| ++index_in_text; | |||||
| eat_until_code(text, &index_in_text); | |||||
| } break; | } break; | ||||
| default: | default: | ||||
| /* syntax error */ | /* syntax error */ | ||||
| @@ -0,0 +1,10 @@ | |||||
| @echo off | |||||
| pushd %~dp0\bin | |||||
| call ..\build.bat | |||||
| if %errorlevel% == 0 ( | |||||
| echo ---------- Testing ---------- | |||||
| call timecmd lisp.exe test.lsp | |||||
| ) | |||||
| popd | |||||