| @@ -1,13 +1,6 @@ | |||||
| void assert_type (Ast_Node* node, Ast_Node_Type type) { | void assert_type (Ast_Node* node, Ast_Node_Type type) { | ||||
| if (!node) | |||||
| create_error(Error_Type_Unknown_Error, node); | |||||
| if (node->type == type) return; | 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); */ | |||||
| create_error(Error_Type_Type_Missmatch, node); | create_error(Error_Type_Type_Missmatch, node); | ||||
| } | } | ||||
| @@ -134,6 +134,19 @@ struct Ast_Node { | |||||
| // was forward declarated | // was forward declarated | ||||
| typedef struct Ast_Node Ast_Node; | typedef struct Ast_Node Ast_Node; | ||||
| typedef struct { | |||||
| Ast_Node** data; | |||||
| int length; | |||||
| int next_index; | |||||
| } Ast_Node_Array_List; | |||||
| typedef struct { | |||||
| Ast_Node_Array_List* positional_arguments; | |||||
| // TODO(Felix): Really use hashmap (keyword[sting] -> | |||||
| // value[Ast_Node*]) here | |||||
| Ast_Node_Array_List* keyword_keys; | |||||
| Ast_Node_Array_List* keyword_values; | |||||
| } Parsed_Arguments; | |||||
| Ast_Node* create_ast_node_nil() { | Ast_Node* create_ast_node_nil() { | ||||
| Ast_Node* node = new(Ast_Node); | Ast_Node* node = new(Ast_Node); | ||||
| @@ -39,84 +39,84 @@ bool ast_node_equal(Ast_Node* n1, Ast_Node* n2) { | |||||
| return false; | 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)) | |||||
| Ast_Node* built_in_equals(Parsed_Arguments* arguments) { | |||||
| for (int i = 0; i < arguments->positional_arguments->next_index-1; ++i) { | |||||
| if (!ast_node_equal( | |||||
| arguments->positional_arguments->data[i], | |||||
| arguments->positional_arguments->data[i+1])) | |||||
| return create_ast_node_nil(); | return create_ast_node_nil(); | ||||
| operands = operands->value.pair->rest; | |||||
| } | } | ||||
| return create_ast_node_number(1); | return create_ast_node_number(1); | ||||
| } | } | ||||
| Ast_Node* built_in_add(Ast_Node* operands) { | |||||
| Ast_Node* built_in_add(Parsed_Arguments* arguments) { | |||||
| double sum = 0; | double sum = 0; | ||||
| while (operands->type == Ast_Node_Type_Pair) { | |||||
| for (int i = 0; i < arguments->positional_arguments->next_index; ++i) { | |||||
| try { | try { | ||||
| assert_type(operands->value.pair->first, Ast_Node_Type_Number); | |||||
| assert_type(arguments->positional_arguments->data[i], Ast_Node_Type_Number); | |||||
| } | } | ||||
| sum += operands->value.pair->first->value.number->value; | |||||
| operands = operands->value.pair->rest; | |||||
| sum += arguments->positional_arguments->data[i]->value.number->value; | |||||
| } | } | ||||
| 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(Parsed_Arguments* arguments) { | |||||
| if (arguments->positional_arguments->next_index == 0) | |||||
| return create_ast_node_number(0); | |||||
| try { | try { | ||||
| assert_type(operands->value.pair->first, Ast_Node_Type_Number); | |||||
| assert_type(*arguments->positional_arguments->data, 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) { | |||||
| if (arguments->positional_arguments->next_index == 1) { | |||||
| return create_ast_node_number(-(*arguments->positional_arguments->data)->value.number->value); | |||||
| } | |||||
| // okay we have at least 2 arguments | |||||
| double difference = (*arguments->positional_arguments->data)->value.number->value; | |||||
| for (int i = 1; i < arguments->positional_arguments->next_index; ++i) { | |||||
| try { | try { | ||||
| assert_type(operands->value.pair->first, Ast_Node_Type_Number); | |||||
| assert_type(arguments->positional_arguments->data[i], Ast_Node_Type_Number); | |||||
| } | } | ||||
| difference -= operands->value.pair->first->value.number->value; | |||||
| operands = operands->value.pair->rest; | |||||
| difference -= arguments->positional_arguments->data[i]->value.number->value; | |||||
| } | } | ||||
| return create_ast_node_number(difference); | return create_ast_node_number(difference); | ||||
| } | } | ||||
| Ast_Node* built_in_multiply(Ast_Node* operands) { | |||||
| 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) { | |||||
| Ast_Node* built_in_multiply(Parsed_Arguments* arguments) { | |||||
| double product = 1; | |||||
| for (int i = 0; i < arguments->positional_arguments->next_index; ++i) { | |||||
| try { | try { | ||||
| assert_type(operands->value.pair->first, Ast_Node_Type_Number); | |||||
| assert_type(arguments->positional_arguments->data[i], Ast_Node_Type_Number); | |||||
| } | } | ||||
| product *= operands->value.pair->first->value.number->value; | |||||
| operands = operands->value.pair->rest; | |||||
| product *= arguments->positional_arguments->data[i]->value.number->value; | |||||
| } | } | ||||
| 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(Parsed_Arguments* arguments) { | |||||
| if (arguments->positional_arguments->next_index == 0) | |||||
| return create_ast_node_number(1); | |||||
| try { | try { | ||||
| assert_type(operands->value.pair->first, Ast_Node_Type_Number); | |||||
| assert_type(*arguments->positional_arguments->data, 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) { | |||||
| if (arguments->positional_arguments->next_index == 1) { | |||||
| return create_ast_node_number((*arguments->positional_arguments->data)->value.number->value); | |||||
| } | |||||
| // okay we have at least 2 arguments | |||||
| double difference = (*arguments->positional_arguments->data)->value.number->value; | |||||
| for (int i = 1; i < arguments->positional_arguments->next_index; ++i) { | |||||
| try { | try { | ||||
| assert_type(operands->value.pair->first, Ast_Node_Type_Number); | |||||
| assert_type(arguments->positional_arguments->data[i], Ast_Node_Type_Number); | |||||
| } | } | ||||
| quotient /= operands->value.pair->first->value.number->value; | |||||
| operands = operands->value.pair->rest; | |||||
| difference /= arguments->positional_arguments->data[i]->value.number->value; | |||||
| } | } | ||||
| return create_ast_node_number(quotient); | |||||
| return create_ast_node_number(difference); | |||||
| } | } | ||||
| @@ -2,6 +2,7 @@ typedef enum { | |||||
| Error_Type_Ill_Formed_List, | Error_Type_Ill_Formed_List, | ||||
| Error_Type_Ill_Formed_Arguments, | Error_Type_Ill_Formed_Arguments, | ||||
| Error_Type_Wrong_Number_Of_Arguments, | Error_Type_Wrong_Number_Of_Arguments, | ||||
| Error_Type_Unknown_Keyword_Argument, | |||||
| Error_Type_Type_Missmatch, | Error_Type_Type_Missmatch, | ||||
| Error_Type_Symbol_Not_Defined, | Error_Type_Symbol_Not_Defined, | ||||
| Error_Type_Not_A_Function, | Error_Type_Not_A_Function, | ||||
| @@ -39,6 +40,7 @@ char* Error_Type_to_string(Error_Type type) { | |||||
| switch (type) { | switch (type) { | ||||
| case Error_Type_Ill_Formed_List: return "Evaluation-error: Ill formed list"; | case Error_Type_Ill_Formed_List: return "Evaluation-error: Ill formed list"; | ||||
| case Error_Type_Ill_Formed_Arguments: return "Evaluation-error: Ill formed arguments"; | case Error_Type_Ill_Formed_Arguments: return "Evaluation-error: Ill formed arguments"; | ||||
| case Error_Type_Unknown_Keyword_Argument: return "Evaluation-error: Unknown keyword argument"; | |||||
| case Error_Type_Not_A_Function: return "Evaluation-error: Not a function"; | case Error_Type_Not_A_Function: return "Evaluation-error: Not a function"; | ||||
| case Error_Type_Symbol_Not_Defined: return "Evaluation-error: Symbol not defined"; | case Error_Type_Symbol_Not_Defined: return "Evaluation-error: Symbol not defined"; | ||||
| case Error_Type_Wrong_Number_Of_Arguments: return "Evaluation-error: Wrong number of arguments"; | case Error_Type_Wrong_Number_Of_Arguments: return "Evaluation-error: Wrong number of arguments"; | ||||
| @@ -56,14 +56,6 @@ Ast_Node* copy_list(Ast_Node* node) { | |||||
| return result; | return result; | ||||
| } | } | ||||
| typedef struct { | |||||
| Ast_Node_Array_List* positional_arguments; | |||||
| // TODO(Felix): Really use hashmap (keyword[sting] -> | |||||
| // value[Ast_Node*]) here | |||||
| Ast_Node_Array_List* keyword_keys; | |||||
| Ast_Node_Array_List* keyword_values; | |||||
| } Parsed_Arguments; | |||||
| Parsed_Arguments* eval_and_parse_arguments(Ast_Node* arguments, Environment* env) { | Parsed_Arguments* eval_and_parse_arguments(Ast_Node* arguments, Environment* env) { | ||||
| // TODO(Felix): if arguments is nil then maybe return a constant | // TODO(Felix): if arguments is nil then maybe return a constant | ||||
| // Parsed_Arguments_nil? | // Parsed_Arguments_nil? | ||||
| @@ -114,6 +106,15 @@ Parsed_Arguments* eval_and_parse_arguments(Ast_Node* arguments, Environment* env | |||||
| return result; | return result; | ||||
| } | } | ||||
| Ast_Node* extract_keyword_value(char* keyword, Parsed_Arguments* args) { | |||||
| // NOTE(Felix): This will be a hashmap lookup later | |||||
| for (int i = 0; i < args->keyword_keys->next_index; ++i) { | |||||
| if (string_equal(args->keyword_keys->data[i]->value.keyword->identifier, keyword)) | |||||
| return args->keyword_values->data[i]; | |||||
| } | |||||
| return nullptr; | |||||
| } | |||||
| Ast_Node* eval_arguments(Ast_Node* arguments, Environment* env, int *out_arguments_length) { | Ast_Node* eval_arguments(Ast_Node* arguments, Environment* env, int *out_arguments_length) { | ||||
| *out_arguments_length = 0; | *out_arguments_length = 0; | ||||
| if (arguments->type == Ast_Node_Type_Nil) { | if (arguments->type == Ast_Node_Type_Nil) { | ||||
| @@ -279,25 +280,27 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||||
| // to evaluate the arguments; eval_arguments will also tell | // to evaluate the arguments; eval_arguments will also tell | ||||
| // us the arguments_length. | // us the arguments_length. | ||||
| Ast_Node* evaluated_arguments; | Ast_Node* evaluated_arguments; | ||||
| Parsed_Arguments* evaluated_and_parsed_arguments; | |||||
| try { | try { | ||||
| evaluated_arguments = eval_arguments(arguments, env, &arguments_length); | evaluated_arguments = eval_arguments(arguments, env, &arguments_length); | ||||
| evaluated_and_parsed_arguments = eval_and_parse_arguments(arguments, env); | |||||
| } | } | ||||
| switch (operator->value.built_in_function->type) { | switch (operator->value.built_in_function->type) { | ||||
| case Built_In_Addition: { | case Built_In_Addition: { | ||||
| return built_in_add(evaluated_arguments); | |||||
| return built_in_add(evaluated_and_parsed_arguments); | |||||
| } | } | ||||
| case Built_In_Subtraction: { | case Built_In_Subtraction: { | ||||
| return built_in_substract(evaluated_arguments); | |||||
| return built_in_substract(evaluated_and_parsed_arguments); | |||||
| } | } | ||||
| case Built_In_Multiplication: { | case Built_In_Multiplication: { | ||||
| return built_in_multiply(evaluated_arguments); | |||||
| return built_in_multiply(evaluated_and_parsed_arguments); | |||||
| } | } | ||||
| case Built_In_Division: { | case Built_In_Division: { | ||||
| return built_in_divide(evaluated_arguments); | |||||
| return built_in_divide(evaluated_and_parsed_arguments); | |||||
| } | } | ||||
| case Built_In_Equal: { | case Built_In_Equal: { | ||||
| return built_in_equals(evaluated_arguments); | |||||
| return built_in_equals(evaluated_and_parsed_arguments); | |||||
| } | } | ||||
| case Built_In_Pair: { | case Built_In_Pair: { | ||||
| if (arguments_length != 2) { | if (arguments_length != 2) { | ||||
| @@ -355,12 +358,46 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||||
| return evaluated_arguments; | return evaluated_arguments; | ||||
| } | } | ||||
| case Built_In_Print: { | case Built_In_Print: { | ||||
| if (arguments_length != 1) { | |||||
| /* if (arguments_length != 1) { */ | |||||
| /* report_error(Error_Type_Wrong_Number_Of_Arguments); */ | |||||
| /* } */ | |||||
| /* print(evaluated_arguments->value.pair->first); */ | |||||
| /* printf("\n"); */ | |||||
| /* return arguments->value.pair->first; */ | |||||
| if (evaluated_and_parsed_arguments->positional_arguments->next_index == 0) { | |||||
| report_error(Error_Type_Wrong_Number_Of_Arguments); | report_error(Error_Type_Wrong_Number_Of_Arguments); | ||||
| } | } | ||||
| print(evaluated_arguments->value.pair->first); | |||||
| printf("\n"); | |||||
| return arguments->value.pair->first; | |||||
| char* sep = " "; | |||||
| char* end = "\n"; | |||||
| Ast_Node* temp = extract_keyword_value("sep", evaluated_and_parsed_arguments); | |||||
| if (temp) { | |||||
| try { | |||||
| assert_type(temp, Ast_Node_Type_String); | |||||
| } | |||||
| sep = temp->value.string->value; | |||||
| } | |||||
| temp = extract_keyword_value("end", evaluated_and_parsed_arguments); | |||||
| if (temp) { | |||||
| try { | |||||
| assert_type(temp, Ast_Node_Type_String); | |||||
| } | |||||
| end = temp->value.string->value; | |||||
| } | |||||
| print(*evaluated_and_parsed_arguments->positional_arguments->data); | |||||
| for (int i = 1; i < evaluated_and_parsed_arguments->positional_arguments->next_index; ++i) { | |||||
| printf("%s", sep); | |||||
| print(*(evaluated_and_parsed_arguments->positional_arguments->data+i)); | |||||
| } | |||||
| printf("%s", end); | |||||
| // return last positional argument | |||||
| return *(evaluated_and_parsed_arguments->positional_arguments->data+ | |||||
| (evaluated_and_parsed_arguments->positional_arguments->next_index-1)); | |||||
| } | } | ||||
| case Built_In_Read: { | case Built_In_Read: { | ||||
| if (arguments_length > 1) { | if (arguments_length > 1) { | ||||
| @@ -415,7 +452,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||||
| } | } | ||||
| // assume it's lambda function and evaluate the arguments | |||||
| // assume it's lambda function and evaluate the arguments | |||||
| arguments = eval_arguments(arguments, env, &arguments_length); | arguments = eval_arguments(arguments, env, &arguments_length); | ||||
| } | } | ||||
| @@ -0,0 +1,18 @@ | |||||
| // for colored console output | |||||
| #ifdef _WIN32 | |||||
| #include <windows.h> | |||||
| #pragma comment(lib, "Kernel32.lib") | |||||
| #endif | |||||
| void init () { | |||||
| // On Windows: manually enable colored console output | |||||
| #ifdef _WIN32 | |||||
| SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), | |||||
| ENABLE_PROCESSED_OUTPUT | | |||||
| ENABLE_WRAP_AT_EOL_OUTPUT | | |||||
| ENABLE_VIRTUAL_TERMINAL_PROCESSING); | |||||
| #endif | |||||
| // TODO(Felix): Init the constants here (Bulit-in function | |||||
| // ast_nodes, nil, ..more?) | |||||
| } | |||||
| @@ -15,6 +15,7 @@ | |||||
| #include "./built_ins.c" | #include "./built_ins.c" | ||||
| #include "./eval.c" | #include "./eval.c" | ||||
| #include "./testing.c" | #include "./testing.c" | ||||
| #include "./init.c" | |||||
| int interprete_file (char* file_content) { | int interprete_file (char* file_content) { | ||||
| Ast_Node_Array_List* program = parse_program(file_content); | Ast_Node_Array_List* program = parse_program(file_content); | ||||
| @@ -62,8 +63,9 @@ int interprete_stdin () { | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| int main (int argc, char *argv[]) { | int main (int argc, char *argv[]) { | ||||
| init(); | |||||
| if (argc > 1) { | if (argc > 1) { | ||||
| char* file_content = read_entire_file(argv[1]); | char* file_content = read_entire_file(argv[1]); | ||||
| if (file_content) { | if (file_content) { | ||||
| @@ -1,9 +1,3 @@ | |||||
| typedef struct { | |||||
| Ast_Node** data; | |||||
| int length; | |||||
| int next_index; | |||||
| } Ast_Node_Array_List; | |||||
| Ast_Node_Array_List* create_Ast_Node_Array_List() { | Ast_Node_Array_List* create_Ast_Node_Array_List() { | ||||
| Ast_Node_Array_List* ret = new (Ast_Node_Array_List); | Ast_Node_Array_List* ret = new (Ast_Node_Array_List); | ||||