From 1ea4cf5213eceb3b993cee040baed6538aab87a9 Mon Sep 17 00:00:00 2001 From: FelixBrendel Date: Tue, 9 Oct 2018 00:06:28 +0200 Subject: [PATCH] more things! --- build.bat | 2 + src/assert.c | 16 ++-- src/built_ins.c | 85 +++++++++++++++++++-- src/env.c | 12 +-- src/eval.c | 198 ++++++++++++++++++++++++++++++++++++++---------- src/helpers.c | 16 +++- src/parse.c | 7 +- todo.org | 50 +++++++++--- 8 files changed, 313 insertions(+), 73 deletions(-) diff --git a/build.bat b/build.bat index cbc0e41..7915cb5 100644 --- a/build.bat +++ b/build.bat @@ -8,6 +8,8 @@ set binDir=bin mkdir quickbuild 2>nul pushd quickbuild +taskkill /F /IM %exeName% > NUL 2> NUL + echo ---------- Compiling ---------- call timecmd cl ../src/main.c /Fe%exeName% /W3 /TC /nologo /EHsc /Z7 /link /incremental /debug:fastlink diff --git a/src/assert.c b/src/assert.c index 03549cf..ea07f62 100644 --- a/src/assert.c +++ b/src/assert.c @@ -1,11 +1,13 @@ void assert_type (Ast_Node* node, Ast_Node_Type type) { if (node->type == type) return; - char *wanted, *got, *message; - wanted = Ast_Node_Type_to_string(type); - got = Ast_Node_Type_to_string(node->type); - asprintf(&message, "Type assertion failed:\n\t" - "Wanted: %s\n\t" - "Got : %s\n", wanted, got); - panic(message); + /* char *wanted, *got, *message; */ + /* wanted = Ast_Node_Type_to_string(type); */ + /* got = Ast_Node_Type_to_string(node->type); */ + /* asprintf(&message, "Type assertion failed:\n\t" */ + /* "Wanted: %s\n\t" */ + /* "Got : %s\n", wanted, got); */ + /* panic(message); */ + + create_error(Error_Type_Type_Missmatch, node); } diff --git a/src/built_ins.c b/src/built_ins.c index d7131af..63ad94e 100644 --- a/src/built_ins.c +++ b/src/built_ins.c @@ -1,7 +1,66 @@ +bool ast_node_equal(Ast_Node* n1, Ast_Node* n2) { + if (n1 == n2) + return true; + if (n1->type != n2->type) + return false; + + switch (n1->type) { + case Ast_Node_Type_Built_In_Function: + return string_equal( + n1->value.built_in_function->identifier, + n2->value.built_in_function->identifier); + case Ast_Node_Type_Function: + // if they have the same pointer, true is + // returned a few lines above + return false; + case Ast_Node_Type_Keyword: + return string_equal( + n1->value.keyword->identifier, + n2->value.keyword->identifier); + case Ast_Node_Type_Nil: + return true; + case Ast_Node_Type_Number: + return + n1->value.number->value == + n2->value.number->value; + case Ast_Node_Type_Pair: + create_error(Error_Type_Not_Yet_Implemented, n1); + return false; + case Ast_Node_Type_String: + return string_equal( + n1->value.string->value, + n2->value.string->value); + case Ast_Node_Type_Symbol: + return string_equal( + n1->value.symbol->identifier, + n2->value.symbol->identifier); + } + + // we should never reach here + return false; +} + +Ast_Node* built_in_equals(Ast_Node* operands) { + if (operands->type == Ast_Node_Type_Nil) + return create_ast_node_number(1); + + Ast_Node* first = operands->value.pair->first; + + while (operands->type == Ast_Node_Type_Pair) { + if (!ast_node_equal(operands->value.pair->first, first)) + return create_ast_node_nil(); + operands = operands->value.pair->rest; + } + + return create_ast_node_number(1); +} + Ast_Node* built_in_add(Ast_Node* operands) { double sum = 0; while (operands->type == Ast_Node_Type_Pair) { - assert_type(operands->value.pair->first, Ast_Node_Type_Number); + try { + assert_type(operands->value.pair->first, Ast_Node_Type_Number); + } sum += operands->value.pair->first->value.number->value; operands = operands->value.pair->rest; } @@ -10,12 +69,16 @@ Ast_Node* built_in_add(Ast_Node* operands) { } Ast_Node* built_in_substract(Ast_Node* operands) { - assert_type(operands->value.pair->first, Ast_Node_Type_Number); + try { + assert_type(operands->value.pair->first, Ast_Node_Type_Number); + } double difference = operands->value.pair->first->value.number->value; operands = operands->value.pair->rest; while (operands->type == Ast_Node_Type_Pair) { - assert_type(operands->value.pair->first, Ast_Node_Type_Number); + try { + assert_type(operands->value.pair->first, Ast_Node_Type_Number); + } difference -= operands->value.pair->first->value.number->value; operands = operands->value.pair->rest; @@ -24,12 +87,16 @@ Ast_Node* built_in_substract(Ast_Node* operands) { } Ast_Node* built_in_multiply(Ast_Node* operands) { - assert_type(operands->value.pair->first, Ast_Node_Type_Number); + try { + assert_type(operands->value.pair->first, Ast_Node_Type_Number); + } double product = operands->value.pair->first->value.number->value; operands = operands->value.pair->rest; while (operands->type == Ast_Node_Type_Pair) { - assert_type(operands->value.pair->first, Ast_Node_Type_Number); + try { + assert_type(operands->value.pair->first, Ast_Node_Type_Number); + } product *= operands->value.pair->first->value.number->value; operands = operands->value.pair->rest; @@ -38,12 +105,16 @@ Ast_Node* built_in_multiply(Ast_Node* operands) { } Ast_Node* built_in_divide(Ast_Node* operands) { - assert_type(operands->value.pair->first, Ast_Node_Type_Number); + try { + assert_type(operands->value.pair->first, Ast_Node_Type_Number); + } double quotient = operands->value.pair->first->value.number->value; operands = operands->value.pair->rest; while (operands->type == Ast_Node_Type_Pair) { - assert_type(operands->value.pair->first, Ast_Node_Type_Number); + try { + assert_type(operands->value.pair->first, Ast_Node_Type_Number); + } quotient /= operands->value.pair->first->value.number->value; operands = operands->value.pair->rest; diff --git a/src/env.c b/src/env.c index b9ff38f..30a1f68 100644 --- a/src/env.c +++ b/src/env.c @@ -12,7 +12,7 @@ typedef struct Environment Environment; Environment* create_empty_environment() { Environment* env = new(Environment); - int start_capacity = 1; + int start_capacity = 16; env->parent = nullptr; env->capacity = start_capacity; @@ -54,17 +54,17 @@ Ast_Node* lookup_symbol(Symbol* sym, Environment* env) { "+", "-", "*", "/", ">", "<", "=", "<=", ">=", // Conditional stuff - "if", "and", "or", "not", + "if", "and", "or", "not", // Cons stuff - "first", "rest", "pair", + "pair", "first", "rest", // rest "load", "define", "lambda", "progn", - "eval", "quote", + "eval", "quote", "prog", "list", "print", "read", - "help", "exit" + "info", "type", "exit" }; - int built_in_count = 26; + int built_in_count = sizeof(built_in_names) / sizeof(char*); for (int i = 0; i < built_in_count; ++i) { if (string_equal(built_in_names[i], sym->identifier)) { diff --git a/src/eval.c b/src/eval.c index 897ce3f..d98f11d 100644 --- a/src/eval.c +++ b/src/eval.c @@ -56,46 +56,84 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { case Ast_Node_Type_String: return node; case Ast_Node_Type_Pair: { - Ast_Node* operator = eval_expr(node->value.pair->first, env); - if (error) return nullptr; + Ast_Node* operator; + try { + operator = eval_expr(node->value.pair->first, env); + } Ast_Node* operands = node->value.pair->rest; + int operands_length; + // 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)) { - int operands_length = list_length(operands); + 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); + try { + 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("prog", operator_name)) { + if (operands->type == Ast_Node_Type_Nil) + return operands; + while (!error) { + try { + operands->value.pair->first = eval_expr(operands->value.pair->first, env); + } + + if (operands->value.pair->rest->type == Ast_Node_Type_Pair) + operands = operands->value.pair->rest; + else { + if (operands->value.pair->rest->type != Ast_Node_Type_Nil) + report_error(Error_Type_Ill_Formed_List); + break; + } + } + return operands->value.pair->first; + } else if (string_equal("list", operator_name)) { + try { + eval_operands(operands, env); + } + return operands; + } else if (string_equal("=", operator_name)) { + try { + eval_operands(operands, env); + } + return built_in_equals(operands); } else if (string_equal("+", operator_name)) { - eval_operands(operands, env); - if (error) return nullptr; + try { + eval_operands(operands, env); + } return built_in_add(operands); } else if (string_equal("-", operator_name)) { - eval_operands(operands, env); - if (error) return nullptr; + try { + eval_operands(operands, env); + } return built_in_substract(operands); } else if (string_equal("*", operator_name)) { - eval_operands(operands, env); - if (error) return nullptr; + try { + eval_operands(operands, env); + } return built_in_multiply(operands); } else if (string_equal("/", operator_name)) { - eval_operands(operands, env); - if (error) return nullptr; + try { + eval_operands(operands, env); + } return built_in_divide(operands); } else if (string_equal("define", operator_name)) { - int operands_length = list_length(operands); - if (error) return nullptr; + try { + operands_length = list_length(operands); + } if (operands_length != 2) { report_error(Error_Type_Wrong_Number_Of_Arguments); } @@ -110,14 +148,40 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { define_symbol(symbol, value, env); return value; + } else if (string_equal("type", operator_name)) { + try { + operands_length = list_length(operands); + } + if (operands_length != 1) { + report_error(Error_Type_Wrong_Number_Of_Arguments); + } + try { + eval_operands(operands, env); + } + Ast_Node_Type type = operands->value.pair->first->type; + switch (type) { + case Ast_Node_Type_Built_In_Function: return create_ast_node_keyword("built-in-function"); + case Ast_Node_Type_Function: return create_ast_node_keyword("dynamic-function"); + case Ast_Node_Type_Keyword: return create_ast_node_keyword("keyword"); + case Ast_Node_Type_Nil: return create_ast_node_keyword("nil"); + case Ast_Node_Type_Number: return create_ast_node_keyword("number"); + case Ast_Node_Type_Pair: return create_ast_node_keyword("pair"); + case Ast_Node_Type_String: return create_ast_node_keyword("string"); + case Ast_Node_Type_Symbol: return create_ast_node_keyword("symbol"); + } + } else if (string_equal("exit", operator_name)) { - int operands_length = list_length(operands); - if (error) return nullptr; + try { + operands_length = list_length(operands); + } if (operands_length > 1) { report_error(Error_Type_Wrong_Number_Of_Arguments); } if (operands_length == 1) { + try { + eval_operands(operands, env); + } Ast_Node* error_code = operands->value.pair->first; if (error_code->type != Ast_Node_Type_Number) report_error(Error_Type_Type_Missmatch); @@ -127,26 +191,30 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { exit(0); } else if (string_equal("print", operator_name)) { - int operands_length = list_length(operands); - if (error) return nullptr; + try { + operands_length = list_length(operands); + } if (operands_length != 1) { report_error(Error_Type_Wrong_Number_Of_Arguments); } - eval_operands(operands, env); - if (error) return nullptr; + try { + eval_operands(operands, env); + } 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; + try { + operands_length = list_length(operands); + } if (operands_length > 1) { report_error(Error_Type_Wrong_Number_Of_Arguments); } if (operands_length == 1) { - eval_operands(operands, env); - if (error) return nullptr; + try { + eval_operands(operands, env); + } Ast_Node* prompt = operands->value.pair->first; if (prompt->type == Ast_Node_Type_String) printf("%s", prompt->value.string->value); @@ -155,9 +223,54 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { } char* line = read_line(); return create_ast_node_string(line, (int)strlen(line)); + } else if (string_equal("pair", operator_name)) { + try { + operands_length = list_length(operands); + } + if (operands_length != 2) { + report_error(Error_Type_Wrong_Number_Of_Arguments); + } + try { + eval_operands(operands, env); + } + + return create_ast_node_pair(operands->value.pair->first, operands->value.pair->rest->value.pair->first); + } else if (string_equal("first", operator_name)) { + try { + operands_length = list_length(operands); + } + if (operands_length != 1) { + report_error(Error_Type_Wrong_Number_Of_Arguments); + } + try { + eval_operands(operands, env); + } + if (operands->value.pair->first->type == Ast_Node_Type_Nil) + return create_ast_node_nil(); + if (operands->value.pair->first->type != Ast_Node_Type_Pair) + report_error(Error_Type_Type_Missmatch); + + return operands->value.pair->first->value.pair->first; + } else if (string_equal("rest", operator_name)) { + try { + operands_length = list_length(operands); + } + if (operands_length != 1) { + report_error(Error_Type_Wrong_Number_Of_Arguments); + } + try { + eval_operands(operands, env); + } + if (operands->value.pair->first->type == Ast_Node_Type_Nil) + return create_ast_node_nil(); + if (operands->value.pair->first->type != Ast_Node_Type_Pair) + report_error(Error_Type_Type_Missmatch); + + return operands->value.pair->first->value.pair->rest; } else if (string_equal("if", operator_name)) { - int operands_length = list_length(operands); - if (error) return nullptr; + try { + operands_length = list_length(operands); + } if (operands_length != 2 && operands_length != 3) { report_error(Error_Type_Wrong_Number_Of_Arguments); } @@ -166,8 +279,10 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { Ast_Node* then_part = operands->value.pair->rest; Ast_Node* else_part = then_part->value.pair->rest; - bool truthy = is_truthy(condition, env); - if (error) return nullptr; + bool truthy; + try { + truthy = is_truthy(condition, env); + } if (truthy) return eval_expr(then_part->value.pair->first, env); else if (operands_length == 3) @@ -180,8 +295,9 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { if (operands->type != Ast_Node_Type_Pair) { report_error(Error_Type_Ill_Formed_List); } - result &= is_truthy(operands->value.pair->first, env); - if (error) return nullptr; + try { + result &= is_truthy(operands->value.pair->first, env); + } operands = operands->value.pair->rest; if (!result) return create_ast_node_nil(); @@ -195,8 +311,9 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { if (operands->type != Ast_Node_Type_Pair) { report_error(Error_Type_Ill_Formed_List); } - result |= is_truthy(operands->value.pair->first, env); - if (error) return nullptr; + try { + result |= is_truthy(operands->value.pair->first, env); + } operands = operands->value.pair->rest; if (result) return create_ast_node_number(1);; @@ -204,13 +321,16 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { return create_ast_node_nil(); } else if (string_equal("not", operator_name)) { - if (list_length(operands) != 1) { - if (!error) - create_error(Error_Type_Wrong_Number_Of_Arguments, operands); - return nullptr; + try { + operands_length = list_length(operands); + } + if (operands_length != 1) { + report_error(Error_Type_Wrong_Number_Of_Arguments); + } + bool truthy; + try { + truthy = is_truthy(operands->value.pair->first, env); } - bool truthy = is_truthy(operands->value.pair->first, env); - if (error) return nullptr; if (truthy) return create_ast_node_nil(); return create_ast_node_number(1); diff --git a/src/helpers.c b/src/helpers.c index 08eea07..533bba0 100644 --- a/src/helpers.c +++ b/src/helpers.c @@ -1,6 +1,19 @@ #define new(type) (type*)malloc(sizeof(type)) #define nullptr NULL +#define concat_( a, b) a##b +#define label(prefix, lnum) concat_(prefix,lnum) +#define try \ + if (1) \ + goto label(body,__LINE__); \ + else \ + while (1) \ + if (1) { \ + if(error) return 0; \ + break; \ + } \ + else label(body,__LINE__): + typedef enum { false, true } bool; int string_equal(char* a, char* b) { @@ -75,7 +88,7 @@ char* read_entire_file (char* filename) { } char* read_line() { - char * line = malloc(100), * linep = line; + char* line = malloc(100), * linep = line; size_t lenmax = 100, len = lenmax; int c; @@ -102,6 +115,7 @@ char* read_line() { if((*line++ = c) == '\n') break; } + *line--; // we dont want the \n actually *line = '\0'; return linep; } diff --git a/src/parse.c b/src/parse.c index 6d731cb..f191246 100644 --- a/src/parse.c +++ b/src/parse.c @@ -250,9 +250,10 @@ Ast_Node_Array_List* parse_program(char* text) { while (text[index_in_text] != '\0') { switch (text[index_in_text]) { case '(': { - Ast_Node* parsed = parse_expression(text, &index_in_text); - if (error) - return nullptr; + Ast_Node* parsed; + try { + parsed = parse_expression(text, &index_in_text); + } append_to_Ast_Node_Array_List(program, parsed); } break; case ';': diff --git a/todo.org b/todo.org index a2cb9b1..b781d4e 100644 --- a/todo.org +++ b/todo.org @@ -31,25 +31,53 @@ #+RESULTS: : t -** TODO first (car) -** TODO rest (cdr) -** TODO pair (cons) +** DONE first (car) + CLOSED: [2018-10-08 Mo 20:28] +** DONE rest (cdr) + CLOSED: [2018-10-08 Mo 20:28] +** DONE pair (cons) + CLOSED: [2018-10-08 Mo 20:28] ** TODO load (import) -** TODO define +** DONE define + CLOSED: [2018-10-08 Mo 20:28] ** TODO lambda ** TODO progn -** TODO eval -** TODO quote -** TODO print -** TODO read -** TODO help +** DONE eval + CLOSED: [2018-10-08 Mo 20:28] +** DONE quote + CLOSED: [2018-10-08 Mo 20:28] + +** DONE list + CLOSED: [2018-10-08 Mo 21:06] + +#+begin_src emacs-lisp + (quote (cons 2 (cons 3 (cons 4 ())))) + ;; (cons 2 (cons 3 (cons 4 nil))) + (quote (2 . (3 . (4 . ())))) + ;; (2 3 4) +#+end_src + +#+begin_src emacs-lisp + (list (cons 2 (cons 3 (cons 4 ())))) + ;; ((2 3 4)) + (list (quote(2 . (3 . (4 . ()))))) +#+end_src + +** DONE print + CLOSED: [2018-10-08 Mo 20:28] +** DONE read + CLOSED: [2018-10-08 Mo 20:28] +** DONE type + CLOSED: [2018-10-08 Mo 21:30] + +** TODO info * Types - Symbol - Number - String - - Cons-cell (list) + - pair (cons-cell) - lambda function lambda - built-in function @@ -63,3 +91,5 @@ variable within an upper namespace it should infact change the environment even if the function exited + +(progn (setq x 4)(* x 2))