| @@ -1,13 +1,6 @@ | |||
| void assert_type (Ast_Node* node, Ast_Node_Type type) { | |||
| if (!node) | |||
| create_error(Error_Type_Unknown_Error, node); | |||
| 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); | |||
| } | |||
| @@ -134,6 +134,19 @@ struct Ast_Node { | |||
| // was forward declarated | |||
| 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* node = new(Ast_Node); | |||
| @@ -39,84 +39,84 @@ bool ast_node_equal(Ast_Node* n1, Ast_Node* n2) { | |||
| 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(); | |||
| operands = operands->value.pair->rest; | |||
| } | |||
| 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; | |||
| while (operands->type == Ast_Node_Type_Pair) { | |||
| for (int i = 0; i < arguments->positional_arguments->next_index; ++i) { | |||
| 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); | |||
| } | |||
| 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 { | |||
| 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 { | |||
| 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); | |||
| } | |||
| 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 { | |||
| 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); | |||
| } | |||
| 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 { | |||
| 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 { | |||
| 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_Arguments, | |||
| Error_Type_Wrong_Number_Of_Arguments, | |||
| Error_Type_Unknown_Keyword_Argument, | |||
| Error_Type_Type_Missmatch, | |||
| Error_Type_Symbol_Not_Defined, | |||
| Error_Type_Not_A_Function, | |||
| @@ -39,6 +40,7 @@ char* Error_Type_to_string(Error_Type type) { | |||
| switch (type) { | |||
| 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_Unknown_Keyword_Argument: return "Evaluation-error: Unknown keyword argument"; | |||
| 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_Wrong_Number_Of_Arguments: return "Evaluation-error: Wrong number of arguments"; | |||
| @@ -56,14 +56,6 @@ Ast_Node* copy_list(Ast_Node* node) { | |||
| 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) { | |||
| // TODO(Felix): if arguments is nil then maybe return a constant | |||
| // Parsed_Arguments_nil? | |||
| @@ -114,6 +106,15 @@ Parsed_Arguments* eval_and_parse_arguments(Ast_Node* arguments, Environment* env | |||
| 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) { | |||
| *out_arguments_length = 0; | |||
| 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 | |||
| // us the arguments_length. | |||
| Ast_Node* evaluated_arguments; | |||
| Parsed_Arguments* evaluated_and_parsed_arguments; | |||
| try { | |||
| 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) { | |||
| case Built_In_Addition: { | |||
| return built_in_add(evaluated_arguments); | |||
| return built_in_add(evaluated_and_parsed_arguments); | |||
| } | |||
| case Built_In_Subtraction: { | |||
| return built_in_substract(evaluated_arguments); | |||
| return built_in_substract(evaluated_and_parsed_arguments); | |||
| } | |||
| case Built_In_Multiplication: { | |||
| return built_in_multiply(evaluated_arguments); | |||
| return built_in_multiply(evaluated_and_parsed_arguments); | |||
| } | |||
| case Built_In_Division: { | |||
| return built_in_divide(evaluated_arguments); | |||
| return built_in_divide(evaluated_and_parsed_arguments); | |||
| } | |||
| case Built_In_Equal: { | |||
| return built_in_equals(evaluated_arguments); | |||
| return built_in_equals(evaluated_and_parsed_arguments); | |||
| } | |||
| case Built_In_Pair: { | |||
| if (arguments_length != 2) { | |||
| @@ -355,12 +358,46 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||
| return evaluated_arguments; | |||
| } | |||
| 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); | |||
| } | |||
| 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: { | |||
| 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); | |||
| } | |||
| @@ -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 "./eval.c" | |||
| #include "./testing.c" | |||
| #include "./init.c" | |||
| int interprete_file (char* file_content) { | |||
| Ast_Node_Array_List* program = parse_program(file_content); | |||
| @@ -62,8 +63,9 @@ int interprete_stdin () { | |||
| return 0; | |||
| } | |||
| int main (int argc, char *argv[]) { | |||
| init(); | |||
| if (argc > 1) { | |||
| char* file_content = read_entire_file(argv[1]); | |||
| 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* ret = new (Ast_Node_Array_List); | |||