| @@ -0,0 +1 @@ | |||||
| (/ (+ 1 (- 100 7 3)) 2) | |||||
| @@ -19,7 +19,7 @@ if %errorlevel% == 0 ( | |||||
| move %exeName% ..\%binDir%\ > NUL | move %exeName% ..\%binDir%\ > NUL | ||||
| pushd ..\%binDir% | pushd ..\%binDir% | ||||
| echo ---------- Running ---------- | echo ---------- Running ---------- | ||||
| call timecmd %exeName% | |||||
| call timecmd %exeName% test.lsp | |||||
| del %exeName% /S /Q > NUL | del %exeName% /S /Q > NUL | ||||
| popd | popd | ||||
| ) else ( | ) else ( | ||||
| @@ -54,9 +54,10 @@ Ast_Node* lookup_symbol(Symbol* sym, Environment* env) { | |||||
| } | } | ||||
| } | } | ||||
| char* message; | |||||
| asprintf(&message, "Symbol not defined: %s\n", sym->identifier); | |||||
| panic(message); | |||||
| create_error(Error_Type_Symbol_Not_Defined, create_ast_node_nil()); | |||||
| /* char* message; */ | |||||
| /* asprintf(&message, "Symbol not defined: %s\n", sym->identifier); */ | |||||
| /* panic(message); */ | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| @@ -6,6 +6,7 @@ typedef enum { | |||||
| Error_Type_Not_A_Function, | Error_Type_Not_A_Function, | ||||
| Error_Type_Not_Yet_Implemented, | Error_Type_Not_Yet_Implemented, | ||||
| Error_Type_Syntax_Error, | Error_Type_Syntax_Error, | ||||
| Error_Type_Unexpected_Eof, | |||||
| Error_Type_Unknown_Error, | Error_Type_Unknown_Error, | ||||
| } Error_Type; | } Error_Type; | ||||
| @@ -40,6 +41,8 @@ char* Error_Type_to_string(Error_Type type) { | |||||
| case Error_Type_Type_Missmatch: return "Type Missmatch"; | case Error_Type_Type_Missmatch: return "Type Missmatch"; | ||||
| case Error_Type_Not_Yet_Implemented: return "Not yet implemented"; | case Error_Type_Not_Yet_Implemented: return "Not yet implemented"; | ||||
| case Error_Type_Syntax_Error: return "Syntax Error"; | case Error_Type_Syntax_Error: return "Syntax Error"; | ||||
| case Error_Type_Unexpected_Eof: return "Unexpected EOF"; | |||||
| default: return "Unknown Error"; | default: return "Unknown Error"; | ||||
| } | } | ||||
| } | } | ||||
| @@ -43,6 +43,8 @@ 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; \ | ||||
| } | } | ||||
| @@ -56,7 +58,6 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||||
| case Ast_Node_Type_Number: | case Ast_Node_Type_Number: | ||||
| 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); | ||||
| Ast_Node* operands = node->value.pair->rest; | Ast_Node* operands = node->value.pair->rest; | ||||
| @@ -81,9 +82,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||||
| } 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 (operands_length != 2 && operands_length != 3) { | if (operands_length != 2 && operands_length != 3) { | ||||
| if (!error) | |||||
| create_error(Error_Type_Wrong_Number_Of_Arguments, operands); | |||||
| return nullptr; | |||||
| report_error(Error_Type_Wrong_Number_Of_Arguments); | |||||
| } | } | ||||
| Ast_Node* condition = operands->value.pair->first; | Ast_Node* condition = operands->value.pair->first; | ||||
| @@ -144,7 +143,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||||
| } | } | ||||
| default: | default: | ||||
| report_error(Error_Type_Unknown_Error); | |||||
| report_error(Error_Type_Not_A_Function); | |||||
| } | } | ||||
| #undef report_error | #undef report_error | ||||
| } | } | ||||
| @@ -57,10 +57,11 @@ char* read_entire_file (char* filename) { | |||||
| } | } | ||||
| /* Allocate our buffer to that size. */ | /* Allocate our buffer to that size. */ | ||||
| fileContent = malloc(sizeof(char) * (bufsize)); | |||||
| fileContent = malloc(sizeof(char) * (bufsize) +1); | |||||
| /* Read the entire file into memory. */ | /* Read the entire file into memory. */ | ||||
| size_t newLen = fread(fileContent, sizeof(char), bufsize, fp); | size_t newLen = fread(fileContent, sizeof(char), bufsize, fp); | ||||
| fileContent[bufsize-1] = '\0'; | |||||
| if ( ferror( fp ) != 0 ) { | if ( ferror( fp ) != 0 ) { | ||||
| fputs("Error reading file", stderr); | fputs("Error reading file", stderr); | ||||
| } | } | ||||
| @@ -72,3 +73,35 @@ char* read_entire_file (char* filename) { | |||||
| return fileContent; | return fileContent; | ||||
| /* Don't forget to call free() later! */ | /* Don't forget to call free() later! */ | ||||
| } | } | ||||
| char* read_line() { | |||||
| char * line = malloc(100), * linep = line; | |||||
| size_t lenmax = 100, len = lenmax; | |||||
| int c; | |||||
| if(line == NULL) | |||||
| return NULL; | |||||
| for(;;) { | |||||
| c = fgetc(stdin); | |||||
| if(c == EOF) | |||||
| break; | |||||
| if(--len == 0) { | |||||
| len = lenmax; | |||||
| char * linen = realloc(linep, lenmax *= 2); | |||||
| if(linen == NULL) { | |||||
| free(linep); | |||||
| return NULL; | |||||
| } | |||||
| line = linen + (line - linep); | |||||
| linep = linen; | |||||
| } | |||||
| if((*line++ = c) == '\n') | |||||
| break; | |||||
| } | |||||
| *line = '\0'; | |||||
| return linep; | |||||
| } | |||||
| @@ -77,9 +77,14 @@ void print(Ast_Node* node) { | |||||
| Ast_Node* head = node; | Ast_Node* head = node; | ||||
| printf("("); | printf("("); | ||||
| while (1) { | |||||
| // NOTE(Felix): We cold do a while true here, however in case | |||||
| // we want to print a broken list (for logging the error) we | |||||
| // should do mo checks. | |||||
| while (head) { | |||||
| print(head->value.pair->first); | print(head->value.pair->first); | ||||
| head = head->value.pair->rest; | head = head->value.pair->rest; | ||||
| if (!head) | |||||
| return; | |||||
| if (head->type != Ast_Node_Type_Pair) | if (head->type != Ast_Node_Type_Pair) | ||||
| break; | break; | ||||
| printf(" "); | printf(" "); | ||||
| @@ -17,16 +17,45 @@ | |||||
| #include "./testing.c" | #include "./testing.c" | ||||
| int main (int argc, char *argv[]) { | int main (int argc, char *argv[]) { | ||||
| /* if (argc > 1) { */ | |||||
| /* char* fileContent = read_entire_file(argv[1]); */ | |||||
| /* if (fileContent) { */ | |||||
| /* printf("File: %s\n", fileContent); */ | |||||
| /* } */ | |||||
| /* } else { */ | |||||
| /* printf("No source provided.\n"); */ | |||||
| /* } */ | |||||
| 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"); | |||||
| } else { | |||||
| printf("The file could not be read\n"); | |||||
| } | |||||
| } else { | |||||
| 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"); | |||||
| } | |||||
| } | |||||
| run_all_tests(); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -196,6 +196,11 @@ Ast_Node* parse_expression(char* text, int* index_in_text) { | |||||
| } | } | ||||
| eat_until_code(text, index_in_text); | eat_until_code(text, index_in_text); | ||||
| if (text[(*index_in_text)] == '\0') { | |||||
| create_error(Error_Type_Unexpected_Eof, expression); | |||||
| return nullptr; | |||||
| } | |||||
| if (text[(*index_in_text)] == ')') { | if (text[(*index_in_text)] == ')') { | ||||
| head->value.pair->rest = create_ast_node_nil(); | head->value.pair->rest = create_ast_node_nil(); | ||||
| @@ -237,8 +242,10 @@ Ast_Node_Array_List* parse_program(char* text) { | |||||
| while (text[index_in_text] != '\0') { | while (text[index_in_text] != '\0') { | ||||
| switch (text[index_in_text]) { | switch (text[index_in_text]) { | ||||
| case '(': { | case '(': { | ||||
| append_to_Ast_Node_Array_List( | |||||
| program, parse_expression(text, &index_in_text)); | |||||
| Ast_Node* parsed = parse_expression(text, &index_in_text); | |||||
| if (error) | |||||
| return nullptr; | |||||
| append_to_Ast_Node_Array_List(program, parsed); | |||||
| } break; | } break; | ||||
| case ';': { | case ';': { | ||||
| eat_comment_line(text, &index_in_text); | eat_comment_line(text, &index_in_text); | ||||
| @@ -249,8 +256,9 @@ Ast_Node_Array_List* parse_program(char* text) { | |||||
| ++index_in_text; | ++index_in_text; | ||||
| } break; | } break; | ||||
| default: | default: | ||||
| create_error(Error_Type_Syntax_Error, nullptr); | |||||
| /* syntax error */ | /* syntax error */ | ||||
| create_error(Error_Type_Syntax_Error, create_ast_node_nil()); | |||||
| return nullptr; | |||||
| } | } | ||||
| } | } | ||||
| return program; | return program; | ||||
| @@ -1,13 +0,0 @@ | |||||
| (+ 1 (- 100 7) 3) | |||||
| (defun unpack (&rest args) | |||||
| (car args)) | |||||
| (unpack '(1 2)) | |||||
| (defun add (&rest args) | |||||
| (if args | |||||
| (+ (first args) | |||||
| (apply 'add 'args))) | |||||
| 0) | |||||
| (add 2 123 99) | |||||
| @@ -15,9 +15,12 @@ | |||||
| ** DONE if | ** DONE if | ||||
| CLOSED: [2018-09-18 Di 12:14] | CLOSED: [2018-09-18 Di 12:14] | ||||
| ** TODO and (short circuiting) | |||||
| ** TODO or | |||||
| ** TODO not | |||||
| ** DONE and (short circuiting) | |||||
| CLOSED: [2018-10-05 Fr 22:21] | |||||
| ** DONE or | |||||
| CLOSED: [2018-10-05 Fr 22:21] | |||||
| ** DONE not | |||||
| CLOSED: [2018-10-05 Fr 22:21] | |||||
| #+begin_src emacs-lisp | #+begin_src emacs-lisp | ||||
| (not 1) ;; == (not . (1 . nil)) | (not 1) ;; == (not . (1 . nil)) | ||||
| (not (expression 1 3)) ;; == (not . ((expression . (1 . (3 . nil))) . nil)) | (not (expression 1 3)) ;; == (not . ((expression . (1 . (3 . nil))) . nil)) | ||||
| @@ -34,16 +37,12 @@ | |||||
| ** TODO load (import) | ** TODO load (import) | ||||
| ** TODO define | ** TODO define | ||||
| ** TODO lambda | ** TODO lambda | ||||
| ** TODO progn | ** TODO progn | ||||
| ** TODO eval | ** TODO eval | ||||
| ** TODO quote | ** TODO quote | ||||
| ** TODO print | ** TODO print | ||||
| ** TODO read | ** TODO read | ||||
| ** TODO help | ** TODO help | ||||
| * Types | * Types | ||||