| @@ -0,0 +1 @@ | |||
| (/ (+ 1 (- 100 7 3)) 2) | |||
| @@ -19,7 +19,7 @@ if %errorlevel% == 0 ( | |||
| move %exeName% ..\%binDir%\ > NUL | |||
| pushd ..\%binDir% | |||
| echo ---------- Running ---------- | |||
| call timecmd %exeName% | |||
| call timecmd %exeName% test.lsp | |||
| del %exeName% /S /Q > NUL | |||
| popd | |||
| ) 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; | |||
| } | |||
| @@ -6,6 +6,7 @@ typedef enum { | |||
| Error_Type_Not_A_Function, | |||
| Error_Type_Not_Yet_Implemented, | |||
| Error_Type_Syntax_Error, | |||
| Error_Type_Unexpected_Eof, | |||
| Error_Type_Unknown_Error, | |||
| } 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_Not_Yet_Implemented: return "Not yet implemented"; | |||
| case Error_Type_Syntax_Error: return "Syntax Error"; | |||
| case Error_Type_Unexpected_Eof: return "Unexpected EOF"; | |||
| 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) { | |||
| #define report_error(_type) { \ | |||
| create_error(_type, node); \ | |||
| log_error(); \ | |||
| exit(1); \ | |||
| return nullptr; \ | |||
| } | |||
| @@ -56,7 +58,6 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||
| case Ast_Node_Type_Number: | |||
| case Ast_Node_Type_String: | |||
| return node; | |||
| case Ast_Node_Type_Pair: { | |||
| Ast_Node* operator = eval_expr(node->value.pair->first, env); | |||
| 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)) { | |||
| int operands_length = list_length(operands); | |||
| 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; | |||
| @@ -144,7 +143,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||
| } | |||
| default: | |||
| report_error(Error_Type_Unknown_Error); | |||
| report_error(Error_Type_Not_A_Function); | |||
| } | |||
| #undef report_error | |||
| } | |||
| @@ -57,10 +57,11 @@ char* read_entire_file (char* filename) { | |||
| } | |||
| /* Allocate our buffer to that size. */ | |||
| fileContent = malloc(sizeof(char) * (bufsize)); | |||
| fileContent = malloc(sizeof(char) * (bufsize) +1); | |||
| /* Read the entire file into memory. */ | |||
| size_t newLen = fread(fileContent, sizeof(char), bufsize, fp); | |||
| fileContent[bufsize-1] = '\0'; | |||
| if ( ferror( fp ) != 0 ) { | |||
| fputs("Error reading file", stderr); | |||
| } | |||
| @@ -72,3 +73,35 @@ char* read_entire_file (char* filename) { | |||
| return fileContent; | |||
| /* 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; | |||
| 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); | |||
| head = head->value.pair->rest; | |||
| if (!head) | |||
| return; | |||
| if (head->type != Ast_Node_Type_Pair) | |||
| break; | |||
| printf(" "); | |||
| @@ -17,16 +17,45 @@ | |||
| #include "./testing.c" | |||
| 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; | |||
| } | |||
| @@ -196,6 +196,11 @@ Ast_Node* parse_expression(char* text, int* 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)] == ')') { | |||
| 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') { | |||
| switch (text[index_in_text]) { | |||
| 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; | |||
| case ';': { | |||
| eat_comment_line(text, &index_in_text); | |||
| @@ -249,8 +256,9 @@ Ast_Node_Array_List* parse_program(char* text) { | |||
| ++index_in_text; | |||
| } break; | |||
| default: | |||
| create_error(Error_Type_Syntax_Error, nullptr); | |||
| /* syntax error */ | |||
| create_error(Error_Type_Syntax_Error, create_ast_node_nil()); | |||
| return nullptr; | |||
| } | |||
| } | |||
| 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 | |||
| 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 | |||
| (not 1) ;; == (not . (1 . nil)) | |||
| (not (expression 1 3)) ;; == (not . ((expression . (1 . (3 . nil))) . nil)) | |||
| @@ -34,16 +37,12 @@ | |||
| ** TODO load (import) | |||
| ** TODO define | |||
| ** TODO lambda | |||
| ** TODO progn | |||
| ** TODO eval | |||
| ** TODO quote | |||
| ** TODO print | |||
| ** TODO read | |||
| ** TODO help | |||
| * Types | |||