| @@ -1,2 +1,2 @@ | |||||
| ((nil . ((eval . (flycheck-mode 0)) | |||||
| ((c-mode . ((eval . (flycheck-mode 0)) | |||||
| (eval . (rainbow-mode 0))))) | (eval . (rainbow-mode 0))))) | ||||
| @@ -8,7 +8,7 @@ typedef enum { | |||||
| Ast_Node_Type_Number, | Ast_Node_Type_Number, | ||||
| Ast_Node_Type_String, | Ast_Node_Type_String, | ||||
| Ast_Node_Type_Cons_Cell, | |||||
| Ast_Node_Type_Pair, | |||||
| Ast_Node_Type_Function, | Ast_Node_Type_Function, | ||||
| Ast_Node_Type_Built_In_Function, | Ast_Node_Type_Built_In_Function, | ||||
| } Ast_Node_Type; | } Ast_Node_Type; | ||||
| @@ -32,16 +32,16 @@ typedef struct { | |||||
| typedef struct { | typedef struct { | ||||
| struct Ast_Node* first; | struct Ast_Node* first; | ||||
| struct Ast_Node* rest; | struct Ast_Node* rest; | ||||
| } Cons_Cell; | |||||
| } Pair; | |||||
| typedef struct { | typedef struct { | ||||
| Cons_Cell* regular_params; | |||||
| Cons_Cell* keyword_params; | |||||
| Pair* regular_params; | |||||
| Pair* keyword_params; | |||||
| } Lambda_List; | } Lambda_List; | ||||
| typedef struct { | typedef struct { | ||||
| Lambda_List* parameters; | Lambda_List* parameters; | ||||
| Cons_Cell* form; | |||||
| Pair* form; | |||||
| } Function; | } Function; | ||||
| typedef struct { | typedef struct { | ||||
| @@ -51,12 +51,12 @@ typedef struct { | |||||
| struct Ast_Node { | struct Ast_Node { | ||||
| Ast_Node_Type type; | Ast_Node_Type type; | ||||
| union { | union { | ||||
| Symbol* symbol; | |||||
| Keyword* keyword; | |||||
| Number* number; | |||||
| String* string; | |||||
| Cons_Cell* cons_cell; | |||||
| Function* function; | |||||
| Symbol* symbol; | |||||
| Keyword* keyword; | |||||
| Number* number; | |||||
| String* string; | |||||
| Pair* pair; | |||||
| Function* function; | |||||
| Built_In_Function* built_in_function; | Built_In_Function* built_in_function; | ||||
| } value; | } value; | ||||
| }; | }; | ||||
| @@ -67,7 +67,7 @@ typedef struct Ast_Node Ast_Node; | |||||
| Ast_Node* create_ast_node_nil() { | Ast_Node* create_ast_node_nil() { | ||||
| Ast_Node* node = new(Ast_Node); | Ast_Node* node = new(Ast_Node); | ||||
| node->type = Ast_Node_Type_Nil; | node->type = Ast_Node_Type_Nil; | ||||
| node->value.cons_cell = NULL; | |||||
| node->value.pair = NULL; | |||||
| return node; | return node; | ||||
| } | } | ||||
| @@ -106,9 +106,9 @@ Ast_Node* create_ast_node_built_in_function(char* identifier) { | |||||
| Ast_Node* create_ast_node_pair(Ast_Node* first, Ast_Node* rest) { | Ast_Node* create_ast_node_pair(Ast_Node* first, Ast_Node* rest) { | ||||
| Ast_Node* node = new(Ast_Node); | Ast_Node* node = new(Ast_Node); | ||||
| node->type = Ast_Node_Type_Cons_Cell; | |||||
| node->value.cons_cell = new(Cons_Cell); | |||||
| node->value.cons_cell->first = first; | |||||
| node->value.cons_cell->rest = rest; | |||||
| node->type = Ast_Node_Type_Pair; | |||||
| node->value.pair = new(Pair); | |||||
| node->value.pair->first = first; | |||||
| node->value.pair->rest = rest; | |||||
| return node; | return node; | ||||
| } | } | ||||
| @@ -1,52 +1,52 @@ | |||||
| Ast_Node* built_in_add(Ast_Node* operands) { | Ast_Node* built_in_add(Ast_Node* operands) { | ||||
| double sum = 0; | double sum = 0; | ||||
| while (operands->type == Ast_Node_Type_Cons_Cell) { | |||||
| assert_type(operands->value.cons_cell->first, Ast_Node_Type_Number); | |||||
| sum += operands->value.cons_cell->first->value.number->value; | |||||
| operands = operands->value.cons_cell->rest; | |||||
| while (operands->type == Ast_Node_Type_Pair) { | |||||
| assert_type(operands->value.pair->first, Ast_Node_Type_Number); | |||||
| sum += operands->value.pair->first->value.number->value; | |||||
| operands = operands->value.pair->rest; | |||||
| } | } | ||||
| return create_ast_node_number(sum); | return create_ast_node_number(sum); | ||||
| } | } | ||||
| Ast_Node* built_in_substract(Ast_Node* operands) { | Ast_Node* built_in_substract(Ast_Node* operands) { | ||||
| assert_type(operands->value.cons_cell->first, Ast_Node_Type_Number); | |||||
| double difference = operands->value.cons_cell->first->value.number->value; | |||||
| assert_type(operands->value.pair->first, Ast_Node_Type_Number); | |||||
| double difference = operands->value.pair->first->value.number->value; | |||||
| operands = operands->value.cons_cell->rest; | |||||
| while (operands->type == Ast_Node_Type_Cons_Cell) { | |||||
| assert_type(operands->value.cons_cell->first, Ast_Node_Type_Number); | |||||
| operands = operands->value.pair->rest; | |||||
| while (operands->type == Ast_Node_Type_Pair) { | |||||
| assert_type(operands->value.pair->first, Ast_Node_Type_Number); | |||||
| difference -= operands->value.cons_cell->first->value.number->value; | |||||
| operands = operands->value.cons_cell->rest; | |||||
| difference -= operands->value.pair->first->value.number->value; | |||||
| operands = operands->value.pair->rest; | |||||
| } | } | ||||
| return create_ast_node_number(difference); | return create_ast_node_number(difference); | ||||
| } | } | ||||
| Ast_Node* built_in_multiply(Ast_Node* operands) { | Ast_Node* built_in_multiply(Ast_Node* operands) { | ||||
| assert_type(operands->value.cons_cell->first, Ast_Node_Type_Number); | |||||
| double product = operands->value.cons_cell->first->value.number->value; | |||||
| assert_type(operands->value.pair->first, Ast_Node_Type_Number); | |||||
| double product = operands->value.pair->first->value.number->value; | |||||
| operands = operands->value.cons_cell->rest; | |||||
| while (operands->type == Ast_Node_Type_Cons_Cell) { | |||||
| assert_type(operands->value.cons_cell->first, Ast_Node_Type_Number); | |||||
| operands = operands->value.pair->rest; | |||||
| while (operands->type == Ast_Node_Type_Pair) { | |||||
| assert_type(operands->value.pair->first, Ast_Node_Type_Number); | |||||
| product *= operands->value.cons_cell->first->value.number->value; | |||||
| operands = operands->value.cons_cell->rest; | |||||
| product *= operands->value.pair->first->value.number->value; | |||||
| operands = operands->value.pair->rest; | |||||
| } | } | ||||
| return create_ast_node_number(product); | return create_ast_node_number(product); | ||||
| } | } | ||||
| Ast_Node* built_in_divide(Ast_Node* operands) { | Ast_Node* built_in_divide(Ast_Node* operands) { | ||||
| assert_type(operands->value.cons_cell->first, Ast_Node_Type_Number); | |||||
| double quotient = operands->value.cons_cell->first->value.number->value; | |||||
| assert_type(operands->value.pair->first, Ast_Node_Type_Number); | |||||
| double quotient = operands->value.pair->first->value.number->value; | |||||
| operands = operands->value.cons_cell->rest; | |||||
| while (operands->type == Ast_Node_Type_Cons_Cell) { | |||||
| assert_type(operands->value.cons_cell->first, Ast_Node_Type_Number); | |||||
| operands = operands->value.pair->rest; | |||||
| while (operands->type == Ast_Node_Type_Pair) { | |||||
| assert_type(operands->value.pair->first, Ast_Node_Type_Number); | |||||
| quotient /= operands->value.cons_cell->first->value.number->value; | |||||
| operands = operands->value.cons_cell->rest; | |||||
| quotient /= operands->value.pair->first->value.number->value; | |||||
| operands = operands->value.pair->rest; | |||||
| } | } | ||||
| return create_ast_node_number(quotient); | return create_ast_node_number(quotient); | ||||
| } | } | ||||
| @@ -1,6 +1,43 @@ | |||||
| typedef enum { | |||||
| Error_Type_Ill_Formed_List, | |||||
| Error_Type_Wrong_Number_Of_Arguments, | |||||
| Error_Type_Type_Missmatch, | |||||
| Error_Type_Symbol_Not_Defined, | |||||
| Error_Type_Not_A_Function, | |||||
| Error_Type_Not_Yet_Implemented, | |||||
| Error_Type_Unknown_Error, | |||||
| } Error_Type; | |||||
| typedef struct { | typedef struct { | ||||
| char* message; | |||||
| Ast_Node* location; | |||||
| Error_Type type; | |||||
| Ast_Node* location; | |||||
| } Error; | } Error; | ||||
| Error* error; | Error* error; | ||||
| void delete_error() { | |||||
| if (error) { | |||||
| free(error); | |||||
| error = NULL; | |||||
| } | |||||
| } | |||||
| void create_error(Error_Type type, Ast_Node* location) { | |||||
| delete_error(); | |||||
| error = new(Error); | |||||
| error->type = type; | |||||
| error->location = location; | |||||
| } | |||||
| char* Error_Type_to_string(Error_Type 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_Unknown_Error: return "Unknown Error"; | |||||
| } | |||||
| } | |||||
| @@ -7,24 +7,29 @@ | |||||
| Ast_Node* eval_expr(Ast_Node* node, Environment* env); | Ast_Node* eval_expr(Ast_Node* node, Environment* env); | ||||
| int is_truthy (Ast_Node* expression, Environment* env); | int is_truthy (Ast_Node* expression, Environment* env); | ||||
| int list_length(Ast_Node* node) { | |||||
| if (node->type != Ast_Node_Type_Pair) { | |||||
| create_error(Error_Type_Type_Missmatch, node); | |||||
| return 0; | |||||
| } | |||||
| return 1; | |||||
| } | |||||
| void eval_operands(Ast_Node* operands, Environment* env) { | void eval_operands(Ast_Node* operands, Environment* env) { | ||||
| while (!error) { | while (!error) { | ||||
| if (operands->type == Ast_Node_Type_Cons_Cell) { | |||||
| operands->value.cons_cell->first = eval_expr(operands->value.cons_cell->first, env); | |||||
| operands = operands->value.cons_cell->rest; | |||||
| if (operands->type == Ast_Node_Type_Pair) { | |||||
| operands->value.pair->first = eval_expr(operands->value.pair->first, env); | |||||
| operands = operands->value.pair->rest; | |||||
| } else { | } else { | ||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| // if we reach here we got an error | |||||
| log_error("An error occurred while evaluating operands to a function:"); | |||||
| } | } | ||||
| Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | ||||
| #define report_error(_message) \ | |||||
| error = new(Error); \ | |||||
| error->message = _message; \ | |||||
| error->location = node; \ | |||||
| #define report_error(_type) \ | |||||
| create_error(_type, node); \ | |||||
| return NULL | return NULL | ||||
| Ast_Node* ret = new(Ast_Node); | Ast_Node* ret = new(Ast_Node); | ||||
| @@ -38,15 +43,15 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||||
| case Ast_Node_Type_String: | case Ast_Node_Type_String: | ||||
| return node; | return node; | ||||
| case Ast_Node_Type_Cons_Cell: { | |||||
| Ast_Node* operator = eval_expr(node->value.cons_cell->first, env); | |||||
| Ast_Node* operands = node->value.cons_cell->rest; | |||||
| case Ast_Node_Type_Pair: { | |||||
| Ast_Node* operator = eval_expr(node->value.pair->first, env); | |||||
| 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.cons_cell->rest; | |||||
| return node->value.pair->rest; | |||||
| } else if (string_equal("+", operator_name)) { | } else if (string_equal("+", operator_name)) { | ||||
| eval_operands(operands, env); | eval_operands(operands, env); | ||||
| return built_in_add(operands); | return built_in_add(operands); | ||||
| @@ -60,25 +65,24 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||||
| eval_operands(operands, env); | eval_operands(operands, env); | ||||
| return built_in_divide(operands); | return built_in_divide(operands); | ||||
| } else if (string_equal("if", operator_name)) { | } else if (string_equal("if", operator_name)) { | ||||
| if (Ast_Node_Type_Cons_Cell != operands->value.cons_cell->rest->type || | |||||
| Ast_Node_Type_Cons_Cell != operands->value.cons_cell->rest->value.cons_cell->rest->type || | |||||
| Ast_Node_Type_Nil != operands->value.cons_cell->rest->value.cons_cell->rest->value.cons_cell->rest->type) | |||||
| { | |||||
| report_error("Ill formed if statement"); | |||||
| if (list_length(operands) != 3) { | |||||
| report_error(Error_Type_Wrong_Number_Of_Arguments); | |||||
| } | } | ||||
| Ast_Node* then_part = operands->value.cons_cell->rest; | |||||
| Ast_Node* else_part = then_part->value.cons_cell->rest; | |||||
| Ast_Node* condition = operands->value.pair->first; | |||||
| Ast_Node* then_part = operands->value.pair->rest; | |||||
| Ast_Node* else_part = then_part->value.pair->rest; | |||||
| if (is_truthy(operands->value.cons_cell->first, env)) | |||||
| return eval_expr(then_part->value.cons_cell->first, env); | |||||
| if (is_truthy(condition, env)) | |||||
| return eval_expr(then_part->value.pair->first, env); | |||||
| else | else | ||||
| return eval_expr(else_part->value.cons_cell->first, env); | |||||
| } else if (string_equal("not", operator_name)) { | |||||
| } else if (string_equal("and", operator_name)) { | |||||
| } else if (string_equal("or", operator_name)) { | |||||
| return eval_expr(else_part->value.pair->first, env); | |||||
| /* } else if (string_equal("not", operator_name)) { */ | |||||
| /* } else if (string_equal("and", operator_name)) { */ | |||||
| /* } else if (string_equal("or", operator_name)) { */ | |||||
| } else { | } else { | ||||
| report_error("The operator is not yet implemented"); | |||||
| report_error(Error_Type_Not_Yet_Implemented); | |||||
| } | } | ||||
| } | } | ||||
| @@ -88,7 +92,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||||
| } | } | ||||
| default: | default: | ||||
| report_error("Unknown error"); | |||||
| report_error(Error_Type_Unknown_Error); | |||||
| } | } | ||||
| #undef report_error | #undef report_error | ||||
| } | } | ||||
| @@ -1,3 +1,8 @@ | |||||
| #define console_normal "\x1B[0m" | |||||
| #define console_red "\x1B[31m" | |||||
| #define console_green "\x1B[32m" | |||||
| #define console_cyan "\x1B[36m" | |||||
| typedef enum { | typedef enum { | ||||
| Log_Level_None, | Log_Level_None, | ||||
| @@ -24,11 +29,6 @@ void log_message(Log_Level type, char* message) { | |||||
| printf("%s: %s\n",prefix, message); | printf("%s: %s\n",prefix, message); | ||||
| } | } | ||||
| void log_error(char* message) { | |||||
| log_message(Log_Level_Critical, message); | |||||
| log_message(Log_Level_Critical, error->message); | |||||
| } | |||||
| void panic(char* message) { | void panic(char* message) { | ||||
| log_message(Log_Level_Critical, message); | log_message(Log_Level_Critical, message); | ||||
| @@ -36,24 +36,16 @@ void panic(char* message) { | |||||
| } | } | ||||
| char* Ast_Node_Type_to_string (Ast_Node_Type type) { | |||||
| char* Ast_Node_Type_to_string(Ast_Node_Type type) { | |||||
| switch (type) { | switch (type) { | ||||
| case(Ast_Node_Type_Nil): | |||||
| return "nil"; | |||||
| case(Ast_Node_Type_Number): | |||||
| return "number"; | |||||
| case(Ast_Node_Type_String): | |||||
| return "string"; | |||||
| case(Ast_Node_Type_Symbol): | |||||
| return "symbol"; | |||||
| case(Ast_Node_Type_Keyword): | |||||
| return "keyword"; | |||||
| case(Ast_Node_Type_Function): | |||||
| return "function"; | |||||
| case(Ast_Node_Type_Built_In_Function): | |||||
| return "built-in function"; | |||||
| case(Ast_Node_Type_Cons_Cell): | |||||
| return "pair"; | |||||
| case(Ast_Node_Type_Nil): return "nil"; | |||||
| case(Ast_Node_Type_Number): return "number"; | |||||
| case(Ast_Node_Type_String): return "string"; | |||||
| case(Ast_Node_Type_Symbol): return "symbol"; | |||||
| case(Ast_Node_Type_Keyword): return "keyword"; | |||||
| case(Ast_Node_Type_Function): return "function"; | |||||
| case(Ast_Node_Type_Built_In_Function): return "built-in function"; | |||||
| case(Ast_Node_Type_Pair): return "pair"; | |||||
| } | } | ||||
| } | } | ||||
| @@ -80,14 +72,14 @@ void print(Ast_Node* node) { | |||||
| case (Ast_Node_Type_Built_In_Function): { | case (Ast_Node_Type_Built_In_Function): { | ||||
| printf("[built-in-function %s]", node->value.built_in_function->identifier); | printf("[built-in-function %s]", node->value.built_in_function->identifier); | ||||
| } break; | } break; | ||||
| case (Ast_Node_Type_Cons_Cell): { | |||||
| case (Ast_Node_Type_Pair): { | |||||
| Ast_Node* head = node; | Ast_Node* head = node; | ||||
| printf("("); | printf("("); | ||||
| while (1) { | while (1) { | ||||
| print(head->value.cons_cell->first); | |||||
| head = head->value.cons_cell->rest; | |||||
| if (head->type != Ast_Node_Type_Cons_Cell) | |||||
| print(head->value.pair->first); | |||||
| head = head->value.pair->rest; | |||||
| if (head->type != Ast_Node_Type_Pair) | |||||
| break; | break; | ||||
| printf(" "); | printf(" "); | ||||
| } | } | ||||
| @@ -101,3 +93,13 @@ void print(Ast_Node* node) { | |||||
| } break; | } break; | ||||
| } | } | ||||
| } | } | ||||
| void log_error() { | |||||
| printf("\t%s%s%s\n", console_red, | |||||
| Error_Type_to_string(error->type), | |||||
| console_normal); | |||||
| printf("\t in: %s", console_cyan); | |||||
| print(error->location); | |||||
| printf("%s\n", console_normal); | |||||
| } | |||||
| @@ -1,7 +1,3 @@ | |||||
| #define console_normal "\x1B[0m" | |||||
| #define console_red "\x1B[31m" | |||||
| #define console_green "\x1B[32m" | |||||
| #define epsilon 2.2204460492503131E-16 | #define epsilon 2.2204460492503131E-16 | ||||
| #define testresult int | #define testresult int | ||||
| @@ -16,16 +12,18 @@ | |||||
| __FILE__, __LINE__, (type)value, (type)variable) | __FILE__, __LINE__, (type)value, (type)variable) | ||||
| #define print_assert_not_equal_fail(variable, value, type, format) \ | #define print_assert_not_equal_fail(variable, value, type, format) \ | ||||
| printf("\n\tAssertion failed for '" #variable "'" \ | |||||
| printf("\n\tAssertion failed for '" #variable "'" \ | |||||
| "\n\t in %s:%d" \ | "\n\t in %s:%d" \ | ||||
| "\n\texpected not: " format \ | "\n\texpected not: " format \ | ||||
| "\n\tgot anyways: " format "\n", \ | "\n\tgot anyways: " format "\n", \ | ||||
| __FILE__, __LINE__, (type)value, (type)variable) | __FILE__, __LINE__, (type)value, (type)variable) | ||||
| /* print_assert_not_equal_fail(error, 0, int, "%d"); \ */ | |||||
| #define assert_no_error(error) \ | #define assert_no_error(error) \ | ||||
| if (error) { \ | if (error) { \ | ||||
| print_assert_not_equal_fail(error, 0, int, "%d"); \ | |||||
| printf("\t%s%s%s\n", console_red, error->message,console_normal); \ | |||||
| printf("\n\tExpected no error to occur," \ | |||||
| " but an error occured anyways:\n"); \ | |||||
| log_error(); \ | |||||
| return fail; \ | return fail; \ | ||||
| } \ | } \ | ||||
| @@ -63,13 +61,12 @@ | |||||
| #define invoke_test(name) \ | #define invoke_test(name) \ | ||||
| printf("" #name ":"); \ | printf("" #name ":"); \ | ||||
| for(int i = 0; i < 45 - strlen(#name); ++i) \ | for(int i = 0; i < 45 - strlen(#name); ++i) \ | ||||
| printf(" "); \ | |||||
| printf(" "); \ | |||||
| if (name() == pass) \ | if (name() == pass) \ | ||||
| printf("%spassed%s\n", console_green, console_normal); \ | printf("%spassed%s\n", console_green, console_normal); \ | ||||
| else { \ | else { \ | ||||
| printf("%sfailed%s\n", console_red, console_normal); \ | printf("%sfailed%s\n", console_red, console_normal); \ | ||||
| if(error) { \ | if(error) { \ | ||||
| log_error("Error while running test" #name); \ | |||||
| free(error); \ | free(error); \ | ||||
| error = NULL; \ | error = NULL; \ | ||||
| } \ | } \ | ||||
| @@ -14,9 +14,18 @@ | |||||
| ** DONE if | ** DONE if | ||||
| CLOSED: [2018-09-18 Di 12:14] | CLOSED: [2018-09-18 Di 12:14] | ||||
| ** TODO and | |||||
| ** TODO and (short circuiting) | |||||
| ** TODO or | ** TODO or | ||||
| ** TODO not | ** TODO not | ||||
| #+begin_src emacs-lisp | |||||
| (not 1) ;; == (not . (1 . nil)) | |||||
| (not (expression 1 3)) ;; == (not . ((expression . (1 . (3 . nil))) . nil)) | |||||
| (not) ;; == (not . nil) | |||||
| (not 1 2) ;; == (not . (1 . (2 . nil))) | |||||
| #+end_src | |||||
| #+RESULTS: | |||||
| : t | |||||
| ** TODO first (car) | ** TODO first (car) | ||||
| ** TODO rest (cdr) | ** TODO rest (cdr) | ||||