diff --git a/.gitignore b/.gitignore index 3092112..2329c99 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ *.user /vs/*/* /bin/slime +*.psess +*.vspx diff --git a/src/built_ins.c b/src/built_ins.c index bd1c660..259eba0 100644 --- a/src/built_ins.c +++ b/src/built_ins.c @@ -39,84 +39,84 @@ bool ast_node_equal(Ast_Node* n1, Ast_Node* n2) { return false; } -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])) +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(Parsed_Arguments* arguments) { +Ast_Node* built_in_add(Ast_Node* operands) { double sum = 0; - for (int i = 0; i < arguments->positional_arguments->next_index; ++i) { + while (operands->type == Ast_Node_Type_Pair) { try { - assert_type(arguments->positional_arguments->data[i], Ast_Node_Type_Number); + assert_type(operands->value.pair->first, Ast_Node_Type_Number); } - sum += arguments->positional_arguments->data[i]->value.number->value; + sum += operands->value.pair->first->value.number->value; + operands = operands->value.pair->rest; } return create_ast_node_number(sum); } -Ast_Node* built_in_substract(Parsed_Arguments* arguments) { - if (arguments->positional_arguments->next_index == 0) - return create_ast_node_number(0); - +Ast_Node* built_in_substract(Ast_Node* operands) { try { - assert_type(*arguments->positional_arguments->data, Ast_Node_Type_Number); + assert_type(operands->value.pair->first, Ast_Node_Type_Number); } + double difference = operands->value.pair->first->value.number->value; - 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) { + operands = operands->value.pair->rest; + while (operands->type == Ast_Node_Type_Pair) { try { - assert_type(arguments->positional_arguments->data[i], Ast_Node_Type_Number); + assert_type(operands->value.pair->first, Ast_Node_Type_Number); } - difference -= arguments->positional_arguments->data[i]->value.number->value; - } + difference -= operands->value.pair->first->value.number->value; + operands = operands->value.pair->rest; + } return create_ast_node_number(difference); } -Ast_Node* built_in_multiply(Parsed_Arguments* arguments) { - double product = 1; - for (int i = 0; i < arguments->positional_arguments->next_index; ++i) { +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) { try { - assert_type(arguments->positional_arguments->data[i], Ast_Node_Type_Number); + assert_type(operands->value.pair->first, Ast_Node_Type_Number); } - product *= arguments->positional_arguments->data[i]->value.number->value; - } + product *= operands->value.pair->first->value.number->value; + operands = operands->value.pair->rest; + } return create_ast_node_number(product); } -Ast_Node* built_in_divide(Parsed_Arguments* arguments) { - if (arguments->positional_arguments->next_index == 0) - return create_ast_node_number(1); - +Ast_Node* built_in_divide(Ast_Node* operands) { try { - assert_type(*arguments->positional_arguments->data, Ast_Node_Type_Number); + assert_type(operands->value.pair->first, Ast_Node_Type_Number); } + double quotient = operands->value.pair->first->value.number->value; - 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) { + operands = operands->value.pair->rest; + while (operands->type == Ast_Node_Type_Pair) { try { - assert_type(arguments->positional_arguments->data[i], Ast_Node_Type_Number); + assert_type(operands->value.pair->first, Ast_Node_Type_Number); } - difference /= arguments->positional_arguments->data[i]->value.number->value; - } - return create_ast_node_number(difference); + quotient /= operands->value.pair->first->value.number->value; + operands = operands->value.pair->rest; + } + return create_ast_node_number(quotient); } diff --git a/src/env.c b/src/env.c index 1cd8794..03a3ee6 100644 --- a/src/env.c +++ b/src/env.c @@ -10,12 +10,13 @@ struct Environment { typedef struct Environment Environment; -Environment* create_empty_environment() { + +Environment* create_child_environment(Environment* parent) { Environment* env = new(Environment); int start_capacity = 16; - env->parent = nullptr; + env->parent = parent; env->capacity = start_capacity; env->next_index = 0; env->keys = (char**)malloc(start_capacity * sizeof(char*)); @@ -24,6 +25,10 @@ Environment* create_empty_environment() { return env; } +Environment* create_empty_environment() { + return create_child_environment(nullptr); +} + void define_symbol(Ast_Node* symbol, Ast_Node* value, Environment* env) { // NOTE(Felix): right now we are simmply adding the symol at the // back of the list without checking if it already exists but are diff --git a/src/eval.c b/src/eval.c index e483d0b..023ce6f 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1,10 +1,33 @@ +Ast_Node* eval_expr(Ast_Node* node, Environment* env); + +Ast_Node* apply_arguments_to_function(Ast_Node* arguments, Function* function, Environment* parent) { + Environment* new_env = create_child_environment(parent); + + // positional arguments + for (int i = 0; i < function->positional_arguments->next_index; ++i) { + if (arguments->type == Ast_Node_Type_Pair) { + define_symbol( + create_ast_node_symbol(function->positional_arguments->identifiers[i]), + arguments->value.pair->first, new_env); + } else { + // not enough arguments given + create_error(Error_Type_Ill_Formed_Arguments, arguments); + return nullptr; + } + arguments = arguments->value.pair->rest; + } -Ast_Node* apply_arguments_to_function (Ast_Node* arguments, Ast_Node* function) { - printf("calling function, yey\n"); + Ast_Node* result; - return create_ast_node_nil(); + try { + result = eval_expr(function->body, new_env); + } + + return result; } +/* (define type (lambda (e) (if (and (= (old-type e) :pair) (= (first e) :my-type)) :my-type (old-type e)))) */ + /** This parses the argument specification of funcitons into their Function struct. It dois this by allocating new @@ -189,59 +212,8 @@ Ast_Node* copy_list(Ast_Node* node) { return result; } -Ast_Node* eval_expr(Ast_Node* node, Environment* env); bool is_truthy (Ast_Node* expression, Environment* env); -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? - - - typedef enum { - Expecting_Anything, - Expecting_Keyword_Key, - Expecting_Keyword_Value - } Parse_State; - - Parse_State parse_state = Expecting_Anything; - - Parsed_Arguments* result = new(Parsed_Arguments); - result->positional_arguments = create_Ast_Node_Array_List(16); - result->keyword_keys = create_Ast_Node_Array_List(16); - result->keyword_values = create_Ast_Node_Array_List(16); - - Ast_Node* current_head = copy_list(arguments); - Ast_Node* current_evaluated_head; - while (current_head->type == Ast_Node_Type_Pair) { - try { - current_evaluated_head = eval_expr(current_head->value.pair->first, env); - } - if (current_evaluated_head->type == Ast_Node_Type_Keyword) { - if (parse_state == Expecting_Anything || Expecting_Keyword_Key) { - append_to_Ast_Node_Array_List(result->keyword_keys, current_evaluated_head); - parse_state = Expecting_Keyword_Value; - } else { - create_error(Error_Type_Ill_Formed_Arguments, arguments); - return nullptr; - } - } else { - if (parse_state == Expecting_Anything) - append_to_Ast_Node_Array_List(result->positional_arguments, current_evaluated_head); - else if (parse_state == Expecting_Keyword_Value) { - append_to_Ast_Node_Array_List(result->keyword_values, current_evaluated_head); - parse_state = Expecting_Keyword_Key; - } - else { - create_error(Error_Type_Ill_Formed_Arguments, arguments); - return nullptr; - } - } - current_head = current_head->value.pair->rest; - } - - 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) { @@ -257,16 +229,27 @@ Ast_Node* eval_arguments(Ast_Node* arguments, Environment* env, int *out_argumen return arguments; } - // NOTE(Felix): Instead of copying and then mutating it, we could - // just build the resulting list on the fly - Ast_Node* evaluated_arguments = copy_list(arguments); - Ast_Node* current_head = evaluated_arguments; + Ast_Node* evaluated_arguments = create_ast_node_pair(nullptr, nullptr); + Ast_Node* evaluated_arguments_head = evaluated_arguments; + Ast_Node* current_head = arguments; while (current_head->type == Ast_Node_Type_Pair) { try { - current_head->value.pair->first = + evaluated_arguments_head->value.pair->first = eval_expr(current_head->value.pair->first, env); } current_head = current_head->value.pair->rest; + + if (current_head->type == Ast_Node_Type_Pair) { + evaluated_arguments_head->value.pair->rest = create_ast_node_pair(nullptr, nullptr); + evaluated_arguments_head = evaluated_arguments_head->value.pair->rest; + } + else if (current_head->type == Ast_Node_Type_Nil) { + evaluated_arguments_head->value.pair->rest = current_head; + } + else { + create_error(Error_Type_Ill_Formed_Arguments, arguments); + return nullptr; + } ++(*out_arguments_length); } return evaluated_arguments; @@ -298,8 +281,12 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { return node; case Ast_Node_Type_Pair: { Ast_Node* operator; - try { - operator = eval_expr(node->value.pair->first, env); + if (node->value.pair->first->type != Ast_Node_Type_Built_In_Function) { + try { + operator = eval_expr(node->value.pair->first, env); + } + } else { + operator = node->value.pair->first; } Ast_Node* arguments = node->value.pair->rest; @@ -458,27 +445,25 @@ 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_and_parsed_arguments); + return built_in_add(evaluated_arguments); } case Built_In_Subtraction: { - return built_in_substract(evaluated_and_parsed_arguments); + return built_in_substract(evaluated_arguments); } case Built_In_Multiplication: { - return built_in_multiply(evaluated_and_parsed_arguments); + return built_in_multiply(evaluated_arguments); } case Built_In_Division: { - return built_in_divide(evaluated_and_parsed_arguments); + return built_in_divide(evaluated_arguments); } case Built_In_Equal: { - return built_in_equals(evaluated_and_parsed_arguments); + return built_in_equals(evaluated_arguments); } case Built_In_Pair: { if (arguments_length != 2) { @@ -536,46 +521,12 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { return evaluated_arguments; } case Built_In_Print: { - /* 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) { + if (arguments_length != 1) { report_error(Error_Type_Wrong_Number_Of_Arguments); } - - 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)); + print(evaluated_arguments->value.pair->first); + printf("\n"); + return arguments->value.pair->first; } case Built_In_Read: { if (arguments_length > 1) { @@ -635,7 +586,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { if (operator->type == Ast_Node_Type_Function) { Ast_Node* result; try { - result = apply_arguments_to_function(arguments, operator); + result = apply_arguments_to_function(arguments, operator->value.function, env); } return result; } diff --git a/vs/slime.sln b/vs/slime.sln index d61dfe6..043c57f 100644 --- a/vs/slime.sln +++ b/vs/slime.sln @@ -6,6 +6,9 @@ MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slime", "slime.vcxproj", "{1A47A3ED-871F-4CB4-875B-8CAA385B1771}" EndProject Global + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86