diff --git a/build.bat b/build.bat index 09e3643..3b8fbf4 100644 --- a/build.bat +++ b/build.bat @@ -1,26 +1,25 @@ @echo off +@setlocal pushd %~dp0 +set start=%time% + set exeName=lisp.exe set binDir=bin -mkdir quickbuild +mkdir quickbuild 2>nul pushd quickbuild -cl^ - ../src/main.c^ - /Fe%exeName% /W3 /TC^ - /nologo /EHsc /Z7^ - /link /incremental /debug:fastlink +echo ---------- Compiling ---------- +call timecmd cl ../src/main.c /Fe%exeName% /W3 /TC /nologo /EHsc /Z7 /link /incremental /debug:fastlink if %errorlevel% == 0 ( echo. if not exist ..\%binDir% mkdir ..\%binDir% move %exeName% ..\%binDir%\ > NUL pushd ..\%binDir% - echo ---------- Output start ---------- - %exeName% - echo ---------- Output end ---------- + echo ---------- Running ---------- + call timecmd %exeName% del %exeName% /S /Q > NUL popd ) else ( diff --git a/src/ast.c b/src/ast.c index e344857..5eb5349 100644 --- a/src/ast.c +++ b/src/ast.c @@ -27,6 +27,7 @@ typedef struct { typedef struct { char* value; + int length; } String; typedef struct { @@ -42,6 +43,7 @@ typedef struct { typedef struct { Lambda_List* parameters; Pair* form; + char* docstring; } Function; typedef struct { @@ -79,11 +81,12 @@ Ast_Node* create_ast_node_number(double number) { return node; } -Ast_Node* create_ast_node_string(char* str) { +Ast_Node* create_ast_node_string(char* str, int length) { Ast_Node* node = new(Ast_Node); node->type = Ast_Node_Type_String; node->value.string = new(String); node->value.string->value = str; + node->value.string->length = length; return node; } @@ -95,6 +98,13 @@ Ast_Node* create_ast_node_symbol(char* identifier) { return node; } +Ast_Node* create_ast_node_keyword(char* keyword) { + Ast_Node* node = new(Ast_Node); + node->type = Ast_Node_Type_Keyword; + node->value.keyword = new(Keyword); + node->value.keyword->identifier = keyword; + return node; +} Ast_Node* create_ast_node_built_in_function(char* identifier) { Ast_Node* node = new(Ast_Node); diff --git a/src/error.c b/src/error.c index 207c20e..1e44324 100644 --- a/src/error.c +++ b/src/error.c @@ -5,6 +5,7 @@ typedef enum { Error_Type_Symbol_Not_Defined, Error_Type_Not_A_Function, Error_Type_Not_Yet_Implemented, + Error_Type_Syntax_Error, Error_Type_Unknown_Error, } Error_Type; @@ -38,6 +39,7 @@ char* Error_Type_to_string(Error_Type type) { 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_Syntax_Error: return "Syntax Error"; default: return "Unknown Error"; } } diff --git a/src/eval.c b/src/eval.c index 008516e..f7a8224 100644 --- a/src/eval.c +++ b/src/eval.c @@ -81,7 +81,8 @@ 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) { - create_error(Error_Type_Wrong_Number_Of_Arguments, operands); + if (!error) + create_error(Error_Type_Wrong_Number_Of_Arguments, operands); return nullptr; } @@ -124,10 +125,14 @@ 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) { - create_error(Error_Type_Wrong_Number_Of_Arguments, operands); + if (!error) + create_error(Error_Type_Wrong_Number_Of_Arguments, operands); return nullptr; } - + bool truthy = is_truthy(operands->value.pair->first, env); + if (truthy) + return create_ast_node_nil(); + return create_ast_node_number(1); } else { report_error(Error_Type_Not_Yet_Implemented); } @@ -148,7 +153,7 @@ bool is_truthy (Ast_Node* expression, Environment* env) { Ast_Node* result = eval_expr(expression, env); switch (result->type) { case Ast_Node_Type_Nil: return false; - case Ast_Node_Type_Number: return result->value.number->value != 0; + /* case Ast_Node_Type_Number: return result->value.number->value != 0; */ default: return true; } } diff --git a/src/parse.c b/src/parse.c index 7ce6d2a..420b555 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1,12 +1,257 @@ -Ast_Node* parse_expression(char* expr) { - typedef enum { - Parser_State_Code, - Parser_State_String, - Parser_State_Comment, - } Parser_State; +typedef struct { + Ast_Node** data; + int length; + int next_index; +} Ast_Node_Array_List; - // initial state is code - Parser_State current_parser_state = Parser_State_Code; +Ast_Node_Array_List* create_Ast_Node_Array_List() { + Ast_Node_Array_List* ret = new (Ast_Node_Array_List); - return nullptr; + // create one with 16 entries first + ret->length = 16; + ret->data = (Ast_Node**)malloc(ret->length * sizeof(Ast_Node)); + ret->next_index = 0; + + return ret; +} + +void append_to_Ast_Node_Array_List(Ast_Node_Array_List* list, Ast_Node* node) { + if (list->next_index == list->length) { + list->length *= 2; + list->data = + (Ast_Node**)realloc(list->data, list->length * sizeof(Ast_Node)); + } + + list->data[list->next_index++] = node; +} + +void eat_comment_line(char* text, int* index_in_text) { + // safety check if we are actually starting a comment here + if (text[*index_in_text] != ';') + return; + + // eat the comment line + do { + ++(*index_in_text); + } while (text[(*index_in_text)] != '\n' && + text[(*index_in_text)] != '\0'); +} + +void eat_whitespace(char* text, int* index_in_text) { + // skip whitespaces + while (text[(*index_in_text)] == ' ' || + text[(*index_in_text)] == '\t' || + text[(*index_in_text)] == '\n') { + ++(*index_in_text); + } +} + +void eat_until_code(char* text, int* index_in_text) { + int position_before; + do { + position_before = *index_in_text; + eat_comment_line(text, index_in_text); + eat_whitespace(text, index_in_text); + } while (position_before != *index_in_text); +} + +char* read_atom(char* text, int* index_in_text) { + int atom_length = 0; + while (text[*index_in_text+atom_length] != ' ' && + text[*index_in_text+atom_length] != ')' && + text[*index_in_text+atom_length] != '(' && + text[*index_in_text+atom_length] != '\0' && + text[*index_in_text+atom_length] != '\n' && + text[*index_in_text+atom_length] != '\t') + { + ++atom_length; + } + + // let's mark the end of the atom there quickly, so the string can + // be copied from there easily and then put the char that was + // before there back + char before = text[*index_in_text+atom_length]; + text[*index_in_text+atom_length] = '\0'; + + // get the atom + char* atom = (char*)malloc(atom_length*sizeof(char)+1); // plus null char + strcpy(atom, text+(*index_in_text)); + + // restore the original string + text[*index_in_text+atom_length] = before; + + // update the index to point to the character after the atom + // ended + *index_in_text += atom_length; + + return atom; +} + +Ast_Node* parse_number(char* text, int* index_in_text) { + double number; + char* str_number = read_atom(text, index_in_text); + sscanf(str_number, "%lf", &number); + return create_ast_node_number(number); +} + + +Ast_Node* parse_keyword(char* text, int* index_in_text) { + // we are now on the colon + ++(*index_in_text); + char* str_keyword = read_atom(text, index_in_text); + return create_ast_node_keyword(str_keyword); +} + +Ast_Node* parse_symbol(char* text, int* index_in_text) { + // we are now at the first char of the symbol + char* str_symbol = read_atom(text, index_in_text); + return create_ast_node_symbol(str_symbol); +} + +Ast_Node* parse_string(char* text, int* index_in_text) { + // the first character is the '"' + ++(*index_in_text); + + // now we are at the first letter, if this is the closing '"' then + // it's easy + if (text[*index_in_text] == '"') { + char* str = new(char); + *str = '\0'; + return create_ast_node_string(str, 0); + } + + // okay so the first letter was not actually closing the string... + int string_length = 0; + while (text[*index_in_text+string_length] != '"' || + text[*index_in_text+string_length] == '\\') + { + ++string_length; + } + + // we found the end of the string + text[*index_in_text+string_length] = '\0'; + + char* string = (char*)malloc(string_length*sizeof(char)+1); // plus null char + strcpy(string, text+(*index_in_text)); + + text[*index_in_text+string_length] = '"'; + + *index_in_text += string_length +1; // plus one because we want to + // go after the quotes + + return create_ast_node_string(string, string_length); +} + +Ast_Node* parse_atom(char* text, int* index_in_text) { + // numbers + if ((text[*index_in_text] <= 57 && // if number + text[*index_in_text] >= 48) + || + ((text[*index_in_text] == '+' || // or if sign and then number + text[*index_in_text] == '-') + && + (text[*index_in_text +1] <= 57 && + text[*index_in_text +1] >= 48)) + || + ((text[*index_in_text] == '.') // or if . and then number + && + (text[*index_in_text +1] <= 57 && + text[*index_in_text +1] >= 48))) + return parse_number(text, index_in_text); + + // keywords + if (text[*index_in_text] == ':') + return parse_keyword(text, index_in_text); + + // strings + if (text[*index_in_text] == '"') + return parse_string(text, index_in_text); + + return parse_symbol(text, index_in_text); +} + +Ast_Node* parse_expression(char* text, int* index_in_text) { + // okay we know the text under the index is '(' + ++(*index_in_text); + + eat_whitespace(text, index_in_text); + + // if there was actually nothing in the list return nil + if (text[(*index_in_text)] == ')') { + ++(*index_in_text); + return create_ast_node_nil(); + } + + // okay there is something + Ast_Node* head = new(Ast_Node); + head->type = Ast_Node_Type_Pair; + head->value.pair = new(Pair); + Ast_Node* expression = head; + + while (true) { + if (text[(*index_in_text)] == '(') { + head->value.pair->first = parse_expression(text, index_in_text); + } else { + head->value.pair->first = parse_atom(text, index_in_text); + } + + eat_until_code(text, index_in_text); + + if (text[(*index_in_text)] == ')') { + head->value.pair->rest = create_ast_node_nil(); + ++(*index_in_text); + break; + } else if (text[(*index_in_text)] == '.') { + ++(*index_in_text); + eat_until_code(text, index_in_text); + + if (text[(*index_in_text)] == '(') + head->value.pair->rest = parse_expression(text, index_in_text); + else + head->value.pair->rest = parse_atom(text, index_in_text); + + eat_until_code(text, index_in_text); + + if (text[(*index_in_text)] != ')') + create_error(Error_Type_Syntax_Error, nullptr); + ++(*index_in_text); + break; + } else { + head->value.pair->rest = create_ast_node_pair(nullptr, nullptr); + head = head->value.pair->rest; + } + } + return expression; +} + +Ast_Node* parse_single_expression(char* text) { + int index_in_text = 0; + return parse_expression(text, &index_in_text); +} + +Ast_Node_Array_List* parse_program(char* text) { + Ast_Node_Array_List* program = create_Ast_Node_Array_List(); + + int index_in_text = 0; + + 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)); + } break; + case ';': { + eat_comment_line(text, &index_in_text); + } break; + case ' ': + case '\t': + case '\n': { + ++index_in_text; + } break; + default: + create_error(Error_Type_Syntax_Error, nullptr); + /* syntax error */ + } + } + return program; } diff --git a/src/testing.c b/src/testing.c index 0dcbbdf..8c7aa3d 100644 --- a/src/testing.c +++ b/src/testing.c @@ -4,16 +4,14 @@ #define pass 1 #define fail 0 -#define print_assert_equal_fail(variable, value, type, format) \ - printf("\nAssertion failed for '" #variable "'" \ - "\n\t in %s:%d" \ - "\n\texpected: " format \ - "\n\tgot: " format "\n", \ - __FILE__, __LINE__, (type)value, (type)variable) +#define print_assert_equal_fail(variable, value, type, format) \ + printf("\n%s:%d: Assertion failed\n\tfor '" #variable "'" \ + "\n\texpected: " format \ + "\n\tgot: " format "\n", \ + __FILE__, __LINE__, (type)value, (type)variable) #define print_assert_not_equal_fail(variable, value, type, format) \ - printf("\nAssertion failed for '" #variable "'" \ - "\n\t in %s:%d" \ + printf("\n%s:%d: Assertion failed\n\tfor '" #variable "'" \ "\n\texpected not: " format \ "\n\tgot anyways: " format "\n", \ __FILE__, __LINE__, (type)value, (type)variable) @@ -50,6 +48,13 @@ return fail; \ } +#define assert_equal_string(variable, value) \ + if (!string_equal(variable, value)) { \ + print_assert_equal_fail(variable, value, char*, "%s"); \ + return fail; \ + } + + #define assert_null(variable) \ assert_equal_int(variable, nullptr) @@ -74,21 +79,121 @@ } \ } \ +testresult test_parse_atom() { + int index_in_text = 0; + char string[] = + "123 -1.23e-2 " // numbers + "\"asd\" " // strings + ":key1 :key:2 " // keywords + "sym +"; // symbols + + // test numbers + Ast_Node* result = parse_atom(string, &index_in_text); + assert_equal_int(result->type, Ast_Node_Type_Number); + assert_equal_double(result->value.number->value, 123); + + ++index_in_text; + + result = parse_atom(string, &index_in_text); + assert_equal_int(result->type, Ast_Node_Type_Number); + assert_equal_double(result->value.number->value, -1.23e-2); + + // test strings + ++index_in_text; + + result = parse_atom(string, &index_in_text); + assert_equal_int(result->type, Ast_Node_Type_String); + assert_equal_string(result->value.string->value, "asd"); + + // test keywords + ++index_in_text; + + result = parse_atom(string, &index_in_text); + assert_equal_int(result->type, Ast_Node_Type_Keyword); + assert_equal_string(result->value.keyword->identifier, "key1"); + + ++index_in_text; + + result = parse_atom(string, &index_in_text); + assert_equal_int(result->type, Ast_Node_Type_Keyword); + assert_equal_string(result->value.keyword->identifier, "key:2"); + + // test symbols + ++index_in_text; + + result = parse_atom(string, &index_in_text); + assert_equal_int(result->type, Ast_Node_Type_Symbol); + assert_equal_string(result->value.symbol->identifier, "sym"); + + ++index_in_text; + + result = parse_atom(string, &index_in_text); + assert_equal_int(result->type, Ast_Node_Type_Symbol); + assert_equal_string(result->value.symbol->identifier, "+"); + + return pass; +} + +testresult test_parse_expression() { + int index_in_text = 0; + char string[] = "(fun + 12)"; + + Ast_Node* result = parse_expression(string, &index_in_text); + assert_no_error(error); + + assert_equal_int(result->type, Ast_Node_Type_Pair); + assert_equal_int(result->value.pair->first->type, Ast_Node_Type_Symbol); + assert_equal_string(result->value.pair->first->value.symbol->identifier, "fun"); + + result = result->value.pair->rest; + + assert_equal_int(result->type, Ast_Node_Type_Pair); + assert_equal_int(result->value.pair->first->type, Ast_Node_Type_Symbol); + assert_equal_string(result->value.pair->first->value.symbol->identifier, "+"); + + result = result->value.pair->rest; + + assert_equal_int(result->type, Ast_Node_Type_Pair); + assert_equal_int(result->value.pair->first->type, Ast_Node_Type_Number); + assert_equal_double(result->value.pair->first->value.number->value, 12); + + result = result->value.pair->rest; + + assert_equal_int(result->type, Ast_Node_Type_Nil); + + char string2[] = "(define fun (lambda (x) (+ 5 (* x x ))))"; + index_in_text = 0; + + result = parse_expression(string2, &index_in_text); + assert_no_error(error); + + assert_equal_int(result->type, Ast_Node_Type_Pair); + assert_equal_int(result->value.pair->first->type, Ast_Node_Type_Symbol); + assert_equal_string(result->value.pair->first->value.symbol->identifier, "define"); + + result = result->value.pair->rest; + + assert_equal_int(result->type, Ast_Node_Type_Pair); + assert_equal_int(result->value.pair->first->type, Ast_Node_Type_Symbol); + assert_equal_string(result->value.pair->first->value.symbol->identifier, "fun"); + + result = result->value.pair->rest; + + assert_equal_int(result->type, Ast_Node_Type_Pair); + assert_equal_int(result->value.pair->first->type, Ast_Node_Type_Pair); + assert_equal_int(result->value.pair->first->value.pair->first->type, Ast_Node_Type_Symbol); + assert_equal_string(result->value.pair->first->value.pair->first->value.symbol->identifier, "lambda"); + + result = result->value.pair->rest; + + + return pass; +} testresult test_built_in_add() { - Ast_Node* plus = create_ast_node_symbol("+"); - Ast_Node* ten = create_ast_node_number(10); - Ast_Node* four = create_ast_node_number(4); - Ast_Node* nil = create_ast_node_nil(); - Ast_Node* form = create_ast_node_pair( - plus, - create_ast_node_pair( - ten, - create_ast_node_pair( - four, - nil))); - - Ast_Node* result = eval_expr(form, create_empty_environment()); + char exp_string[] = "(+ 10 4)"; + Ast_Node* expression = parse_single_expression(exp_string); + Ast_Node* result = eval_expr(expression, create_empty_environment()); assert_no_error(error); assert_not_null(result); @@ -99,19 +204,9 @@ testresult test_built_in_add() { } testresult test_built_in_substract() { - Ast_Node* minus = create_ast_node_symbol("-"); - Ast_Node* ten = create_ast_node_number(10); - Ast_Node* four = create_ast_node_number(4); - Ast_Node* nil = create_ast_node_nil(); - Ast_Node* form = create_ast_node_pair( - minus, - create_ast_node_pair( - ten, - create_ast_node_pair( - four, - nil))); - - Ast_Node* result = eval_expr(form, create_empty_environment()); + char exp_string[] = "(- 10 4)"; + Ast_Node* expression = parse_single_expression(exp_string); + Ast_Node* result = eval_expr(expression, create_empty_environment()); assert_no_error(error); assert_not_null(result); @@ -123,19 +218,9 @@ testresult test_built_in_substract() { testresult test_built_in_multiply() { - Ast_Node* times = create_ast_node_symbol("*"); - Ast_Node* ten = create_ast_node_number(10); - Ast_Node* four = create_ast_node_number(4); - Ast_Node* nil = create_ast_node_nil(); - Ast_Node* form = create_ast_node_pair( - times, - create_ast_node_pair( - ten, - create_ast_node_pair( - four, - nil))); - - Ast_Node* result = eval_expr(form, create_empty_environment()); + char exp_string[] = "(* 10 4)"; + Ast_Node* expression = parse_single_expression(exp_string); + Ast_Node* result = eval_expr(expression, create_empty_environment()); assert_no_error(error); assert_not_null(result); @@ -147,19 +232,9 @@ testresult test_built_in_multiply() { testresult test_built_in_divide() { - Ast_Node* over = create_ast_node_symbol("/"); - Ast_Node* ten = create_ast_node_number(20); - Ast_Node* four = create_ast_node_number(4); - Ast_Node* nil = create_ast_node_nil(); - Ast_Node* form = create_ast_node_pair( - over, - create_ast_node_pair( - ten, - create_ast_node_pair( - four, - nil))); - - Ast_Node* result = eval_expr(form, create_empty_environment()); + char exp_string[] = "(/ 20 4)"; + Ast_Node* expression = parse_single_expression(exp_string); + Ast_Node* result = eval_expr(expression, create_empty_environment()); assert_null(error); assert_not_null(result); @@ -171,35 +246,20 @@ testresult test_built_in_divide() { testresult test_built_in_if() { - Ast_Node* _if = create_ast_node_symbol("if"); - Ast_Node* cond = create_ast_node_number(1); - Ast_Node* four = create_ast_node_number(4); - Ast_Node* five = create_ast_node_number(5); - Ast_Node* nil = create_ast_node_nil(); - Ast_Node* form = create_ast_node_pair( - _if, - create_ast_node_pair( - cond, - create_ast_node_pair( - four, - create_ast_node_pair( - five, - nil)))); - Ast_Node* result; - - // test *then* case - result = eval_expr(form, create_empty_environment()); + char exp_string1[] = "(if 1 4 5)"; + Ast_Node* expression = parse_single_expression(exp_string1); + Ast_Node* result = eval_expr(expression, create_empty_environment()); assert_no_error(error); assert_not_null(result); assert_equal_int(result->type, Ast_Node_Type_Number); assert_equal_double(result->value.number->value, 4); - // test *else* case - cond->value.number->value = 0; - result = eval_expr(form, create_empty_environment()); + char exp_string2[] = "(if () 4 5)"; + expression = parse_single_expression(exp_string2); + result = eval_expr(expression, create_empty_environment()); - assert_null(error); + assert_no_error(error); assert_not_null(result); assert_equal_int(result->type, Ast_Node_Type_Number); assert_equal_double(result->value.number->value, 5); @@ -208,24 +268,9 @@ testresult test_built_in_if() { } testresult test_built_in_and() { - Ast_Node* _and = create_ast_node_symbol("and"); - Ast_Node* cond1 = create_ast_node_number(1); - Ast_Node* cond2 = create_ast_node_string("asd"); - Ast_Node* cond3 = create_ast_node_number(4); - Ast_Node* nil = create_ast_node_nil(); - Ast_Node* form = create_ast_node_pair( - _and, - create_ast_node_pair( - cond1, - create_ast_node_pair( - cond2, - create_ast_node_pair( - cond3, - nil)))); - Ast_Node* result; - - // a true case - result = eval_expr(form, create_empty_environment()); + char exp_string1[] = "(and 1 \"asd\" 4)"; + Ast_Node* expression = parse_single_expression(exp_string1); + Ast_Node* result = eval_expr(expression, create_empty_environment()); assert_no_error(error); assert_not_null(result); @@ -233,8 +278,9 @@ testresult test_built_in_and() { assert_equal_double(result->value.number->value, 1); // a false case - cond1->value.number->value = 0; - result = eval_expr(form, create_empty_environment()); + char exp_string2[] = "(and () \"asd\" 4)"; + expression = parse_single_expression(exp_string2); + result = eval_expr(expression, create_empty_environment()); assert_no_error(error); assert_not_null(result); @@ -244,20 +290,9 @@ testresult test_built_in_and() { } testresult test_built_in_or() { - Ast_Node* _or = create_ast_node_symbol("or"); - Ast_Node* cond1 = create_ast_node_nil(); - Ast_Node* cond2 = create_ast_node_string("asd"); - Ast_Node* nil = create_ast_node_nil(); - Ast_Node* form = create_ast_node_pair( - _or, - create_ast_node_pair( - cond1, - create_ast_node_pair( - cond2, nil))); - Ast_Node* result; - - // a true case - result = eval_expr(form, create_empty_environment()); + char exp_string1[] = "(or \"asd\" nil)"; + Ast_Node* expression = parse_single_expression(exp_string1); + Ast_Node* result = eval_expr(expression, create_empty_environment()); assert_no_error(error); assert_not_null(result); @@ -265,14 +300,9 @@ testresult test_built_in_or() { assert_equal_double(result->value.number->value, 1); // a false case - cond2 = create_ast_node_nil(); - form = create_ast_node_pair( - _or, - create_ast_node_pair( - cond1, - create_ast_node_pair( - cond2, nil))); - result = eval_expr(form, create_empty_environment()); + char exp_string2[] = "(or () ())"; + expression = parse_single_expression(exp_string2); + result = eval_expr(expression, create_empty_environment()); assert_no_error(error); assert_not_null(result); @@ -282,9 +312,37 @@ testresult test_built_in_or() { } +testresult test_built_in_not() { + char exp_string1[] = "(not ())"; + Ast_Node* expression = parse_single_expression(exp_string1); + Ast_Node* result = eval_expr(expression, create_empty_environment()); + + // a true case + assert_no_error(error); + assert_not_null(result); + assert_equal_int(result->type, Ast_Node_Type_Number); + assert_equal_double(result->value.number->value, 1); + + // a false case + char exp_string2[] = "(not \"asd xD\")"; + expression = parse_single_expression(exp_string2); + result = eval_expr(expression, create_empty_environment()); + + assert_no_error(error); + assert_not_null(result); + assert_equal_int(result->type, Ast_Node_Type_Nil); + + return pass; +} + void run_all_tests() { log_level = Log_Level_None; + printf("-- Parsing --\n"); + invoke_test(test_parse_atom); + invoke_test(test_parse_expression); + + printf("\n-- Built ins --\n"); invoke_test(test_built_in_add); invoke_test(test_built_in_substract); invoke_test(test_built_in_multiply); @@ -292,5 +350,7 @@ void run_all_tests() { invoke_test(test_built_in_if); invoke_test(test_built_in_and); invoke_test(test_built_in_or); + invoke_test(test_built_in_not); + } diff --git a/todo.org b/todo.org index f23a0fc..82915cf 100644 --- a/todo.org +++ b/todo.org @@ -1,3 +1,4 @@ +* TODO =assert_equal_type= macro in testing * Build-in forms ** DONE +