| @@ -1,2 +1,3 @@ | |||||
| ((c-mode . ((eval . (flycheck-mode 0)) | |||||
| (eval . (rainbow-mode 0))))) | |||||
| ((c-mode . ((eval . (company-clang-set-prefix "main.c")) | |||||
| (eval . (flycheck-mode 0)) | |||||
| (eval . (rainbow-mode 0))))) | |||||
| @@ -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.pair = NULL; | |||||
| node->value.pair = nullptr; | |||||
| return node; | return node; | ||||
| } | } | ||||
| @@ -50,4 +50,3 @@ Ast_Node* built_in_divide(Ast_Node* operands) { | |||||
| } | } | ||||
| return create_ast_node_number(quotient); | return create_ast_node_number(quotient); | ||||
| } | } | ||||
| @@ -11,10 +11,10 @@ typedef struct Environment Environment; | |||||
| Environment* create_empty_environment() { | Environment* create_empty_environment() { | ||||
| Environment* env = new(Environment); | Environment* env = new(Environment); | ||||
| env->parent = NULL; | |||||
| env->parent = nullptr; | |||||
| env->key_count = 0; | env->key_count = 0; | ||||
| env->keys = NULL; | |||||
| env->values = NULL; | |||||
| env->keys = nullptr; | |||||
| env->values = nullptr; | |||||
| return env; | return env; | ||||
| } | } | ||||
| @@ -58,5 +58,5 @@ Ast_Node* lookup_symbol(Symbol* sym, Environment* env) { | |||||
| asprintf(&message, "Symbol not defined: %s\n", sym->identifier); | asprintf(&message, "Symbol not defined: %s\n", sym->identifier); | ||||
| panic(message); | panic(message); | ||||
| return NULL; | |||||
| return nullptr; | |||||
| } | } | ||||
| @@ -18,7 +18,7 @@ Error* error; | |||||
| void delete_error() { | void delete_error() { | ||||
| if (error) { | if (error) { | ||||
| free(error); | free(error); | ||||
| error = NULL; | |||||
| error = nullptr; | |||||
| } | } | ||||
| } | } | ||||
| @@ -5,7 +5,8 @@ | |||||
| /* } */ | /* } */ | ||||
| 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); | |||||
| bool is_truthy (Ast_Node* expression, Environment* env); | |||||
| int list_length(Ast_Node* node) { | int list_length(Ast_Node* node) { | ||||
| if (node->type == Ast_Node_Type_Nil) | if (node->type == Ast_Node_Type_Nil) | ||||
| @@ -40,9 +41,10 @@ void eval_operands(Ast_Node* operands, Environment* env) { | |||||
| } | } | ||||
| Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | ||||
| #define report_error(_type) \ | |||||
| create_error(_type, node); \ | |||||
| return NULL | |||||
| #define report_error(_type) { \ | |||||
| create_error(_type, node); \ | |||||
| return nullptr; \ | |||||
| } | |||||
| Ast_Node* ret = new(Ast_Node); | Ast_Node* ret = new(Ast_Node); | ||||
| switch (node->type) { | switch (node->type) { | ||||
| @@ -80,7 +82,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||||
| int operands_length = list_length(operands); | int operands_length = list_length(operands); | ||||
| if (operands_length != 2 && operands_length != 3) { | if (operands_length != 2 && operands_length != 3) { | ||||
| create_error(Error_Type_Wrong_Number_Of_Arguments, operands); | create_error(Error_Type_Wrong_Number_Of_Arguments, operands); | ||||
| return NULL; | |||||
| return nullptr; | |||||
| } | } | ||||
| Ast_Node* condition = operands->value.pair->first; | Ast_Node* condition = operands->value.pair->first; | ||||
| @@ -92,10 +94,40 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||||
| else if (operands_length == 3) | else if (operands_length == 3) | ||||
| return eval_expr(else_part->value.pair->first, env); | return eval_expr(else_part->value.pair->first, env); | ||||
| else return create_ast_node_nil(); | else return create_ast_node_nil(); | ||||
| /* } else if (string_equal("not", operator_name)) { */ | |||||
| /* } else if (string_equal("and", operator_name)) { */ | |||||
| /* } else if (string_equal("or", operator_name)) { */ | |||||
| } else if (string_equal("and", operator_name)) { | |||||
| bool result = true; | |||||
| while (operands->type != Ast_Node_Type_Nil) { | |||||
| if (operands->type != Ast_Node_Type_Pair) { | |||||
| report_error(Error_Type_Ill_Formed_List); | |||||
| } | |||||
| result &= is_truthy(operands->value.pair->first, env); | |||||
| operands = operands->value.pair->rest; | |||||
| if (!result) return create_ast_node_nil(); | |||||
| } | |||||
| return create_ast_node_number(1); | |||||
| } else if (string_equal("or", operator_name)) { | |||||
| bool result = false; | |||||
| while (operands->type != Ast_Node_Type_Nil) { | |||||
| if (operands->type != Ast_Node_Type_Pair) { | |||||
| report_error(Error_Type_Ill_Formed_List); | |||||
| } | |||||
| result |= is_truthy(operands->value.pair->first, env); | |||||
| operands = operands->value.pair->rest; | |||||
| if (result) return create_ast_node_number(1);; | |||||
| } | |||||
| 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); | |||||
| return nullptr; | |||||
| } | |||||
| } else { | } else { | ||||
| report_error(Error_Type_Not_Yet_Implemented); | report_error(Error_Type_Not_Yet_Implemented); | ||||
| } | } | ||||
| @@ -112,11 +144,11 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||||
| #undef report_error | #undef report_error | ||||
| } | } | ||||
| int is_truthy (Ast_Node* expression, Environment* env) { | |||||
| bool is_truthy (Ast_Node* expression, Environment* env) { | |||||
| Ast_Node* result = eval_expr(expression, env); | Ast_Node* result = eval_expr(expression, env); | ||||
| switch (result->type) { | switch (result->type) { | ||||
| case Ast_Node_Type_Nil: return 0; | |||||
| 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 1; | |||||
| default: return true; | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,4 +1,7 @@ | |||||
| #define new(type) (type*)malloc(sizeof(type)) | #define new(type) (type*)malloc(sizeof(type)) | ||||
| #define nullptr NULL | |||||
| typedef enum { false, true } bool; | |||||
| int string_equal(char* a, char* b) { | int string_equal(char* a, char* b) { | ||||
| return !strcmp(a, b); | return !strcmp(a, b); | ||||
| @@ -9,7 +12,7 @@ int _vscprintf_so(const char * format, va_list pargs) { | |||||
| int retval; | int retval; | ||||
| va_list argcopy; | va_list argcopy; | ||||
| va_copy(argcopy, pargs); | va_copy(argcopy, pargs); | ||||
| retval = vsnprintf(NULL, 0, format, argcopy); | |||||
| retval = vsnprintf(nullptr, 0, format, argcopy); | |||||
| va_end(argcopy); | va_end(argcopy); | ||||
| return retval; | return retval; | ||||
| } | } | ||||
| @@ -35,9 +38,9 @@ int asprintf(char *strp[], const char *fmt, ...) { | |||||
| // asprintf implementation end | // asprintf implementation end | ||||
| char* read_entire_file (char* filename) { | char* read_entire_file (char* filename) { | ||||
| char *fileContent = NULL; | |||||
| char *fileContent = nullptr; | |||||
| FILE *fp = fopen(filename, "r"); | FILE *fp = fopen(filename, "r"); | ||||
| if (fp != NULL) { | |||||
| if (fp) { | |||||
| /* Go to the end of the file. */ | /* Go to the end of the file. */ | ||||
| if (fseek(fp, 0L, SEEK_END) == 0) { | if (fseek(fp, 0L, SEEK_END) == 0) { | ||||
| /* Get the size of the file. */ | /* Get the size of the file. */ | ||||
| @@ -24,7 +24,7 @@ void log_message(Log_Level type, char* message) { | |||||
| case Log_Level_Warning: prefix = "WARNING"; break; | case Log_Level_Warning: prefix = "WARNING"; break; | ||||
| case Log_Level_Info: prefix = "INFO"; break; | case Log_Level_Info: prefix = "INFO"; break; | ||||
| case Log_Level_Debug: prefix = "DEBUG"; break; | case Log_Level_Debug: prefix = "DEBUG"; break; | ||||
| default: return; | |||||
| default: return; | |||||
| } | } | ||||
| printf("%s: %s\n",prefix, message); | printf("%s: %s\n",prefix, message); | ||||
| } | } | ||||
| @@ -8,5 +8,5 @@ Ast_Node* parse_expression(char* expr) { | |||||
| // initial state is code | // initial state is code | ||||
| Parser_State current_parser_state = Parser_State_Code; | Parser_State current_parser_state = Parser_State_Code; | ||||
| return NULL; | |||||
| return nullptr; | |||||
| } | } | ||||
| @@ -51,10 +51,10 @@ | |||||
| } | } | ||||
| #define assert_null(variable) \ | #define assert_null(variable) \ | ||||
| assert_equal_int(variable, NULL) | |||||
| assert_equal_int(variable, nullptr) | |||||
| #define assert_not_null(variable) \ | #define assert_not_null(variable) \ | ||||
| assert_not_equal_int(variable, NULL) | |||||
| assert_not_equal_int(variable, nullptr) | |||||
| #define invoke_test(name) \ | #define invoke_test(name) \ | ||||
| @@ -70,7 +70,7 @@ | |||||
| printf("%sfailed%s\n", console_red, console_normal); \ | printf("%sfailed%s\n", console_red, console_normal); \ | ||||
| if(error) { \ | if(error) { \ | ||||
| free(error); \ | free(error); \ | ||||
| error = NULL; \ | |||||
| error = nullptr; \ | |||||
| } \ | } \ | ||||
| } \ | } \ | ||||
| @@ -236,10 +236,47 @@ testresult test_built_in_and() { | |||||
| cond1->value.number->value = 0; | cond1->value.number->value = 0; | ||||
| result = eval_expr(form, create_empty_environment()); | result = eval_expr(form, create_empty_environment()); | ||||
| assert_no_error(error); | |||||
| assert_not_null(result); | |||||
| assert_equal_int(result->type, Ast_Node_Type_Nil); | |||||
| return pass; | |||||
| } | |||||
| 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()); | |||||
| assert_no_error(error); | assert_no_error(error); | ||||
| assert_not_null(result); | assert_not_null(result); | ||||
| assert_equal_int(result->type, Ast_Node_Type_Number); | assert_equal_int(result->type, Ast_Node_Type_Number); | ||||
| assert_equal_double(result->value.number->value, 0); | |||||
| 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()); | |||||
| assert_no_error(error); | |||||
| assert_not_null(result); | |||||
| assert_equal_int(result->type, Ast_Node_Type_Nil); | |||||
| return pass; | return pass; | ||||
| } | } | ||||
| @@ -254,5 +291,6 @@ void run_all_tests() { | |||||
| invoke_test(test_built_in_divide); | invoke_test(test_built_in_divide); | ||||
| invoke_test(test_built_in_if); | invoke_test(test_built_in_if); | ||||
| invoke_test(test_built_in_and); | invoke_test(test_built_in_and); | ||||
| invoke_test(test_built_in_or); | |||||
| } | } | ||||