|
|
|
@@ -25,15 +25,58 @@ int list_length(Ast_Node* node) { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
void eval_operands(Ast_Node* operands, Environment* env) { |
|
|
|
while (!error) { |
|
|
|
if (operands->type == Ast_Node_Type_Pair) { |
|
|
|
operands->value.pair->first = eval_expr(operands->value.pair->first, env); |
|
|
|
operands = operands->value.pair->rest; |
|
|
|
} else { |
|
|
|
return; |
|
|
|
/** |
|
|
|
Copies a list, in that it creates a new list, however the items are |
|
|
|
the same as in the original (same pointers). This is neede to copy |
|
|
|
a list when evaluating a parameters list, but not wanting to change |
|
|
|
the parameters list. This happens if you have someting like: |
|
|
|
|
|
|
|
(define a 10) |
|
|
|
(define condition (quote (= a 10))) |
|
|
|
(eval condition) |
|
|
|
> 1.00000 |
|
|
|
|
|
|
|
If we wouldn't copy the parameters list, after calling eval would |
|
|
|
be baked into the quoted list. So even after changing a, the result |
|
|
|
of (eval condition) would be 1.00000. |
|
|
|
**/ |
|
|
|
Ast_Node* copy_list(Ast_Node* node) { |
|
|
|
// we don't copy immutables in here |
|
|
|
if (node->type != Ast_Node_Type_Pair) { |
|
|
|
return node; |
|
|
|
} |
|
|
|
|
|
|
|
Ast_Node* result = new(Ast_Node); |
|
|
|
result->type = Ast_Node_Type_Pair; |
|
|
|
result->value.pair = new(Pair); |
|
|
|
|
|
|
|
result->value.pair->first = copy_list(node->value.pair->first); |
|
|
|
result->value.pair->rest = copy_list(node->value.pair->rest); |
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
Ast_Node* eval_operands(Ast_Node* operands, Environment* env) { |
|
|
|
if (operands->type == Ast_Node_Type_Nil) { |
|
|
|
return operands; |
|
|
|
} |
|
|
|
|
|
|
|
// NOTE(Feilx): Instead of copying and then mutating it, we could |
|
|
|
// just build the resulting list on the fly |
|
|
|
Ast_Node* evaluated_operands = copy_list(operands); |
|
|
|
Ast_Node* current_head = evaluated_operands; |
|
|
|
/* print(operands); */ |
|
|
|
/* printf("\n"); */ |
|
|
|
/* print(evaluated_operands); */ |
|
|
|
/* printf("\n"); */ |
|
|
|
while (current_head->type == Ast_Node_Type_Pair) { |
|
|
|
try { |
|
|
|
current_head->value.pair->first = |
|
|
|
eval_expr(current_head->value.pair->first, env); |
|
|
|
} |
|
|
|
current_head = current_head->value.pair->rest; |
|
|
|
} |
|
|
|
return evaluated_operands; |
|
|
|
} |
|
|
|
|
|
|
|
Ast_Node* eval_expr(Ast_Node* node, Environment* env) { |
|
|
|
@@ -50,7 +93,11 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { |
|
|
|
ret->type = Ast_Node_Type_Nil; |
|
|
|
return ret; |
|
|
|
case Ast_Node_Type_Symbol: |
|
|
|
return lookup_symbol(node->value.symbol, env); |
|
|
|
Ast_Node* symbol; |
|
|
|
try { |
|
|
|
symbol = lookup_symbol(node->value.symbol, env); |
|
|
|
} |
|
|
|
return symbol; |
|
|
|
case Ast_Node_Type_Number: |
|
|
|
case Ast_Node_Type_Keyword: |
|
|
|
case Ast_Node_Type_String: |
|
|
|
@@ -64,7 +111,6 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { |
|
|
|
Ast_Node* operands = node->value.pair->rest; |
|
|
|
int operands_length; |
|
|
|
|
|
|
|
|
|
|
|
// check for built ins functions |
|
|
|
if (operator->type == Ast_Node_Type_Built_In_Function) { |
|
|
|
char* operator_name = operator->value.built_in_function->identifier; |
|
|
|
@@ -81,53 +127,62 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { |
|
|
|
if (operands_length != 1) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
|
|
|
|
return eval_expr(operands->value.pair->first, env); |
|
|
|
try { |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
} |
|
|
|
/* print(operands); */ |
|
|
|
Ast_Node* result; |
|
|
|
try { |
|
|
|
result = eval_expr(operands->value.pair->first, env); |
|
|
|
} |
|
|
|
return result; |
|
|
|
} else if (string_equal("prog", operator_name)) { |
|
|
|
if (operands->type == Ast_Node_Type_Nil) |
|
|
|
return operands; |
|
|
|
while (!error) { |
|
|
|
try { |
|
|
|
operands->value.pair->first = eval_expr(operands->value.pair->first, env); |
|
|
|
} |
|
|
|
|
|
|
|
if (operands->value.pair->rest->type == Ast_Node_Type_Pair) |
|
|
|
operands = operands->value.pair->rest; |
|
|
|
else { |
|
|
|
if (operands->value.pair->rest->type != Ast_Node_Type_Nil) |
|
|
|
report_error(Error_Type_Ill_Formed_List); |
|
|
|
break; |
|
|
|
} |
|
|
|
operands = copy_list(operands); |
|
|
|
Ast_Node* evaluated_operands; |
|
|
|
try { |
|
|
|
evaluated_operands = eval_operands(operands, env); |
|
|
|
} |
|
|
|
return operands->value.pair->first; |
|
|
|
|
|
|
|
// skip to the last evaluated operand and return it, |
|
|
|
// we use eval_operands here instead of doing it |
|
|
|
// manually, becuase we want to increase code reuse, |
|
|
|
// but at the cost that we have to find the end of the |
|
|
|
// list again |
|
|
|
while (evaluated_operands->value.pair->rest->type == Ast_Node_Type_Pair) { |
|
|
|
evaluated_operands = evaluated_operands->value.pair->rest; |
|
|
|
} |
|
|
|
return evaluated_operands->value.pair->first; |
|
|
|
} else if (string_equal("list", operator_name)) { |
|
|
|
try { |
|
|
|
eval_operands(operands, env); |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
} |
|
|
|
return operands; |
|
|
|
} else if (string_equal("=", operator_name)) { |
|
|
|
try { |
|
|
|
eval_operands(operands, env); |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
} |
|
|
|
return built_in_equals(operands); |
|
|
|
} else if (string_equal("+", operator_name)) { |
|
|
|
try { |
|
|
|
eval_operands(operands, env); |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
} |
|
|
|
return built_in_add(operands); |
|
|
|
} else if (string_equal("-", operator_name)) { |
|
|
|
try { |
|
|
|
eval_operands(operands, env); |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
} |
|
|
|
return built_in_substract(operands); |
|
|
|
} else if (string_equal("*", operator_name)) { |
|
|
|
try { |
|
|
|
eval_operands(operands, env); |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
} |
|
|
|
return built_in_multiply(operands); |
|
|
|
} else if (string_equal("/", operator_name)) { |
|
|
|
try { |
|
|
|
eval_operands(operands, env); |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
} |
|
|
|
return built_in_divide(operands); |
|
|
|
} else if (string_equal("define", operator_name)) { |
|
|
|
@@ -143,7 +198,9 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { |
|
|
|
report_error(Error_Type_Type_Missmatch); |
|
|
|
|
|
|
|
Ast_Node* value = operands->value.pair->rest->value.pair->first; |
|
|
|
value = eval_expr(value, env); |
|
|
|
try { |
|
|
|
value = eval_expr(value, env); |
|
|
|
} |
|
|
|
|
|
|
|
define_symbol(symbol, value, env); |
|
|
|
|
|
|
|
@@ -156,7 +213,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
try { |
|
|
|
eval_operands(operands, env); |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
} |
|
|
|
Ast_Node_Type type = operands->value.pair->first->type; |
|
|
|
switch (type) { |
|
|
|
@@ -180,7 +237,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { |
|
|
|
|
|
|
|
if (operands_length == 1) { |
|
|
|
try { |
|
|
|
eval_operands(operands, env); |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
} |
|
|
|
Ast_Node* error_code = operands->value.pair->first; |
|
|
|
if (error_code->type != Ast_Node_Type_Number) |
|
|
|
@@ -198,7 +255,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
try { |
|
|
|
eval_operands(operands, env); |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
} |
|
|
|
print(operands->value.pair->first); |
|
|
|
printf("\n"); |
|
|
|
@@ -213,7 +270,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { |
|
|
|
|
|
|
|
if (operands_length == 1) { |
|
|
|
try { |
|
|
|
eval_operands(operands, env); |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
} |
|
|
|
Ast_Node* prompt = operands->value.pair->first; |
|
|
|
if (prompt->type == Ast_Node_Type_String) |
|
|
|
@@ -231,7 +288,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
try { |
|
|
|
eval_operands(operands, env); |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
} |
|
|
|
|
|
|
|
return create_ast_node_pair(operands->value.pair->first, operands->value.pair->rest->value.pair->first); |
|
|
|
@@ -243,7 +300,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
try { |
|
|
|
eval_operands(operands, env); |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
} |
|
|
|
if (operands->value.pair->first->type == Ast_Node_Type_Nil) |
|
|
|
return create_ast_node_nil(); |
|
|
|
@@ -259,7 +316,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
try { |
|
|
|
eval_operands(operands, env); |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
} |
|
|
|
if (operands->value.pair->first->type == Ast_Node_Type_Nil) |
|
|
|
return create_ast_node_nil(); |
|
|
|
@@ -283,11 +340,17 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { |
|
|
|
try { |
|
|
|
truthy = is_truthy(condition, env); |
|
|
|
} |
|
|
|
Ast_Node* result; |
|
|
|
if (truthy) |
|
|
|
return eval_expr(then_part->value.pair->first, env); |
|
|
|
try{ |
|
|
|
result = eval_expr(then_part->value.pair->first, env); |
|
|
|
} |
|
|
|
else if (operands_length == 3) |
|
|
|
return eval_expr(else_part->value.pair->first, env); |
|
|
|
try { |
|
|
|
result = eval_expr(else_part->value.pair->first, env); |
|
|
|
} |
|
|
|
else return create_ast_node_nil(); |
|
|
|
return result; |
|
|
|
|
|
|
|
} else if (string_equal("and", operator_name)) { |
|
|
|
bool result = true; |
|
|
|
@@ -341,7 +404,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { |
|
|
|
|
|
|
|
// assume it's lambda function and evaluate the operands in |
|
|
|
// place |
|
|
|
eval_operands(operands, env); |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
} |
|
|
|
|
|
|
|
default: |
|
|
|
@@ -351,11 +414,12 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { |
|
|
|
} |
|
|
|
|
|
|
|
bool is_truthy (Ast_Node* expression, Environment* env) { |
|
|
|
Ast_Node* result = eval_expr(expression, env); |
|
|
|
if (error) return false; |
|
|
|
switch (result->type) { |
|
|
|
case Ast_Node_Type_Nil: return false; |
|
|
|
/* case Ast_Node_Type_Number: return result->value.number->value != 0; */ |
|
|
|
default: return true; |
|
|
|
Ast_Node* result; |
|
|
|
try { |
|
|
|
result = eval_expr(expression, env); |
|
|
|
} |
|
|
|
if (result->type == Ast_Node_Type_Nil) |
|
|
|
return false; |
|
|
|
return true; |
|
|
|
|
|
|
|
} |