| @@ -1,2 +1,2 @@ | |||
| ((nil . ((eval . (flycheck-mode 0)) | |||
| ((c-mode . ((eval . (flycheck-mode 0)) | |||
| (eval . (rainbow-mode 0))))) | |||
| @@ -8,7 +8,7 @@ typedef enum { | |||
| Ast_Node_Type_Number, | |||
| Ast_Node_Type_String, | |||
| Ast_Node_Type_Cons_Cell, | |||
| Ast_Node_Type_Pair, | |||
| Ast_Node_Type_Function, | |||
| Ast_Node_Type_Built_In_Function, | |||
| } Ast_Node_Type; | |||
| @@ -32,16 +32,16 @@ typedef struct { | |||
| typedef struct { | |||
| struct Ast_Node* first; | |||
| struct Ast_Node* rest; | |||
| } Cons_Cell; | |||
| } Pair; | |||
| typedef struct { | |||
| Cons_Cell* regular_params; | |||
| Cons_Cell* keyword_params; | |||
| Pair* regular_params; | |||
| Pair* keyword_params; | |||
| } Lambda_List; | |||
| typedef struct { | |||
| Lambda_List* parameters; | |||
| Cons_Cell* form; | |||
| Pair* form; | |||
| } Function; | |||
| typedef struct { | |||
| @@ -51,12 +51,12 @@ typedef struct { | |||
| struct Ast_Node { | |||
| Ast_Node_Type type; | |||
| 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; | |||
| } value; | |||
| }; | |||
| @@ -67,7 +67,7 @@ typedef struct Ast_Node Ast_Node; | |||
| Ast_Node* create_ast_node_nil() { | |||
| Ast_Node* node = new(Ast_Node); | |||
| node->type = Ast_Node_Type_Nil; | |||
| node->value.cons_cell = NULL; | |||
| node->value.pair = NULL; | |||
| 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* 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; | |||
| } | |||
| @@ -1,52 +1,52 @@ | |||
| Ast_Node* built_in_add(Ast_Node* operands) { | |||
| 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); | |||
| } | |||
| 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); | |||
| } | |||
| 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); | |||
| } | |||
| 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); | |||
| } | |||
| @@ -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 { | |||
| char* message; | |||
| Ast_Node* location; | |||
| Error_Type type; | |||
| Ast_Node* location; | |||
| } 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); | |||
| 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) { | |||
| 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 { | |||
| 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) { | |||
| #define report_error(_message) \ | |||
| error = new(Error); \ | |||
| error->message = _message; \ | |||
| error->location = node; \ | |||
| #define report_error(_type) \ | |||
| create_error(_type, node); \ | |||
| return NULL | |||
| Ast_Node* ret = new(Ast_Node); | |||
| @@ -38,15 +43,15 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||
| case Ast_Node_Type_String: | |||
| 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 | |||
| if (operator->type == Ast_Node_Type_Built_In_Function) { | |||
| char* operator_name = operator->value.built_in_function->identifier; | |||
| if (string_equal("quote", operator_name)) { | |||
| return node->value.cons_cell->rest; | |||
| return node->value.pair->rest; | |||
| } else if (string_equal("+", operator_name)) { | |||
| eval_operands(operands, env); | |||
| return built_in_add(operands); | |||
| @@ -60,25 +65,24 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||
| eval_operands(operands, env); | |||
| return built_in_divide(operands); | |||
| } 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 | |||
| 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 { | |||
| 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: | |||
| report_error("Unknown error"); | |||
| report_error(Error_Type_Unknown_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 { | |||
| Log_Level_None, | |||
| @@ -24,11 +29,6 @@ void log_message(Log_Level type, char* 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) { | |||
| 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) { | |||
| 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): { | |||
| printf("[built-in-function %s]", node->value.built_in_function->identifier); | |||
| } break; | |||
| case (Ast_Node_Type_Cons_Cell): { | |||
| case (Ast_Node_Type_Pair): { | |||
| Ast_Node* head = node; | |||
| printf("("); | |||
| 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; | |||
| printf(" "); | |||
| } | |||
| @@ -101,3 +93,13 @@ void print(Ast_Node* node) { | |||
| } 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 testresult int | |||
| @@ -16,16 +12,18 @@ | |||
| __FILE__, __LINE__, (type)value, (type)variable) | |||
| #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\texpected not: " format \ | |||
| "\n\tgot anyways: " format "\n", \ | |||
| __FILE__, __LINE__, (type)value, (type)variable) | |||
| /* print_assert_not_equal_fail(error, 0, int, "%d"); \ */ | |||
| #define assert_no_error(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; \ | |||
| } \ | |||
| @@ -63,13 +61,12 @@ | |||
| #define invoke_test(name) \ | |||
| printf("" #name ":"); \ | |||
| for(int i = 0; i < 45 - strlen(#name); ++i) \ | |||
| printf(" "); \ | |||
| printf(" "); \ | |||
| if (name() == pass) \ | |||
| printf("%spassed%s\n", console_green, console_normal); \ | |||
| else { \ | |||
| printf("%sfailed%s\n", console_red, console_normal); \ | |||
| if(error) { \ | |||
| log_error("Error while running test" #name); \ | |||
| free(error); \ | |||
| error = NULL; \ | |||
| } \ | |||
| @@ -14,9 +14,18 @@ | |||
| ** DONE if | |||
| CLOSED: [2018-09-18 Di 12:14] | |||
| ** TODO and | |||
| ** TODO and (short circuiting) | |||
| ** TODO or | |||
| ** 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 rest (cdr) | |||