|
|
|
@@ -27,7 +27,7 @@ int list_length(Ast_Node* node) { |
|
|
|
|
|
|
|
/** |
|
|
|
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 |
|
|
|
the same as in the original (same pointers). This is needed to copy |
|
|
|
a list when evaluating a parameters list, but not wanting to change |
|
|
|
the parameters list. This happens if you have someting like: |
|
|
|
|
|
|
|
@@ -56,27 +56,83 @@ Ast_Node* copy_list(Ast_Node* node) { |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
Ast_Node* eval_operands(Ast_Node* operands, Environment* env) { |
|
|
|
if (operands->type == Ast_Node_Type_Nil) { |
|
|
|
return operands; |
|
|
|
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? |
|
|
|
|
|
|
|
|
|
|
|
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(); |
|
|
|
result->keyword_keys = create_Ast_Node_Array_List(); |
|
|
|
result->keyword_values = create_Ast_Node_Array_List(); |
|
|
|
|
|
|
|
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; |
|
|
|
} |
|
|
|
|
|
|
|
// NOTE(Feilx): Instead of copying and then mutating it, we could |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
Ast_Node* eval_arguments(Ast_Node* arguments, Environment* env, int *out_arguments_length) { |
|
|
|
*out_arguments_length = 0; |
|
|
|
if (arguments->type == Ast_Node_Type_Nil) { |
|
|
|
return arguments; |
|
|
|
} |
|
|
|
|
|
|
|
// NOTE(Felix): 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"); */ |
|
|
|
Ast_Node* evaluated_arguments = copy_list(arguments); |
|
|
|
Ast_Node* current_head = evaluated_arguments; |
|
|
|
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; |
|
|
|
++(*out_arguments_length); |
|
|
|
} |
|
|
|
return evaluated_operands; |
|
|
|
return evaluated_arguments; |
|
|
|
} |
|
|
|
|
|
|
|
Ast_Node* eval_expr(Ast_Node* node, Environment* env) { |
|
|
|
@@ -108,96 +164,107 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { |
|
|
|
operator = eval_expr(node->value.pair->first, env); |
|
|
|
} |
|
|
|
|
|
|
|
Ast_Node* operands = node->value.pair->rest; |
|
|
|
int operands_length; |
|
|
|
Ast_Node* arguments = node->value.pair->rest; |
|
|
|
int arguments_length; |
|
|
|
|
|
|
|
// check for built ins functions |
|
|
|
// check for special form |
|
|
|
if (operator->type == Ast_Node_Type_Built_In_Function) { |
|
|
|
char* operator_name = operator->value.built_in_function->identifier; |
|
|
|
if (string_equal("quote", operator_name)) { |
|
|
|
operands_length = list_length(operands); |
|
|
|
if (operands_length != 1) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
return operands->value.pair->first; |
|
|
|
} else if (string_equal("eval", operator_name)) { |
|
|
|
try { |
|
|
|
operands_length = list_length(operands); |
|
|
|
} |
|
|
|
if (operands_length != 1) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
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; |
|
|
|
switch (operator->value.built_in_function->type) { |
|
|
|
case Built_In_And: { |
|
|
|
bool result = true; |
|
|
|
while (arguments->type != Ast_Node_Type_Nil) { |
|
|
|
if (arguments->type != Ast_Node_Type_Pair) { |
|
|
|
report_error(Error_Type_Ill_Formed_List); |
|
|
|
} |
|
|
|
try { |
|
|
|
result &= is_truthy(arguments->value.pair->first, env); |
|
|
|
} |
|
|
|
arguments = arguments->value.pair->rest; |
|
|
|
|
|
|
|
operands = copy_list(operands); |
|
|
|
Ast_Node* evaluated_operands; |
|
|
|
try { |
|
|
|
evaluated_operands = eval_operands(operands, env); |
|
|
|
if (!result) return create_ast_node_nil(); |
|
|
|
} |
|
|
|
|
|
|
|
// 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 create_ast_node_number(1); |
|
|
|
} |
|
|
|
case Built_In_Or: { |
|
|
|
bool result = false; |
|
|
|
while (arguments->type != Ast_Node_Type_Nil) { |
|
|
|
if (arguments->type != Ast_Node_Type_Pair) { |
|
|
|
report_error(Error_Type_Ill_Formed_List); |
|
|
|
} |
|
|
|
try { |
|
|
|
result |= is_truthy(arguments->value.pair->first, env); |
|
|
|
} |
|
|
|
arguments = arguments->value.pair->rest; |
|
|
|
|
|
|
|
if (result) return create_ast_node_number(1);; |
|
|
|
} |
|
|
|
return evaluated_operands->value.pair->first; |
|
|
|
} else if (string_equal("list", operator_name)) { |
|
|
|
|
|
|
|
return create_ast_node_nil(); |
|
|
|
} |
|
|
|
case Built_In_Not: { |
|
|
|
try { |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
arguments_length = list_length(arguments); |
|
|
|
} |
|
|
|
return operands; |
|
|
|
} else if (string_equal("=", operator_name)) { |
|
|
|
try { |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
if (arguments_length != 1) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
return built_in_equals(operands); |
|
|
|
} else if (string_equal("+", operator_name)) { |
|
|
|
bool truthy; |
|
|
|
try { |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
truthy = is_truthy(arguments->value.pair->first, env); |
|
|
|
} |
|
|
|
return built_in_add(operands); |
|
|
|
} else if (string_equal("-", operator_name)) { |
|
|
|
if (truthy) |
|
|
|
return create_ast_node_nil(); |
|
|
|
return create_ast_node_number(1); |
|
|
|
} |
|
|
|
case Built_In_If: { |
|
|
|
try { |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
arguments_length = list_length(arguments); |
|
|
|
} |
|
|
|
return built_in_substract(operands); |
|
|
|
} else if (string_equal("*", operator_name)) { |
|
|
|
try { |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
if (arguments_length != 2 && arguments_length != 3) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
return built_in_multiply(operands); |
|
|
|
} else if (string_equal("/", operator_name)) { |
|
|
|
|
|
|
|
Ast_Node* condition = arguments->value.pair->first; |
|
|
|
Ast_Node* then_part = arguments->value.pair->rest; |
|
|
|
Ast_Node* else_part = then_part->value.pair->rest; |
|
|
|
|
|
|
|
bool truthy; |
|
|
|
try { |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
truthy = is_truthy(condition, env); |
|
|
|
} |
|
|
|
Ast_Node* result; |
|
|
|
if (truthy) |
|
|
|
try{ |
|
|
|
result = eval_expr(then_part->value.pair->first, env); |
|
|
|
} |
|
|
|
else if (arguments_length == 3) |
|
|
|
try { |
|
|
|
result = eval_expr(else_part->value.pair->first, env); |
|
|
|
} |
|
|
|
else return create_ast_node_nil(); |
|
|
|
return result; |
|
|
|
} |
|
|
|
case Built_In_Quote: { |
|
|
|
arguments_length = list_length(arguments); |
|
|
|
if (arguments_length != 1) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
return built_in_divide(operands); |
|
|
|
} else if (string_equal("define", operator_name)) { |
|
|
|
return arguments->value.pair->first; |
|
|
|
} |
|
|
|
case Built_In_Define: { |
|
|
|
try { |
|
|
|
operands_length = list_length(operands); |
|
|
|
arguments_length = list_length(arguments); |
|
|
|
} |
|
|
|
if (operands_length != 2) { |
|
|
|
if (arguments_length != 2) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
|
|
|
|
Ast_Node* symbol = operands->value.pair->first; |
|
|
|
Ast_Node* symbol = arguments->value.pair->first; |
|
|
|
if (symbol->type != Ast_Node_Type_Symbol) |
|
|
|
report_error(Error_Type_Type_Missmatch); |
|
|
|
|
|
|
|
Ast_Node* value = operands->value.pair->rest->value.pair->first; |
|
|
|
Ast_Node* value = arguments->value.pair->rest->value.pair->first; |
|
|
|
try { |
|
|
|
value = eval_expr(value, env); |
|
|
|
} |
|
|
|
@@ -205,206 +272,151 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { |
|
|
|
define_symbol(symbol, value, env); |
|
|
|
|
|
|
|
return value; |
|
|
|
} else if (string_equal("type", operator_name)) { |
|
|
|
try { |
|
|
|
operands_length = list_length(operands); |
|
|
|
} |
|
|
|
if (operands_length != 1) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// okay it is not a special form, so in any case we want |
|
|
|
// to evaluate the arguments; eval_arguments will also tell |
|
|
|
// us the arguments_length. |
|
|
|
Ast_Node* evaluated_arguments; |
|
|
|
try { |
|
|
|
evaluated_arguments = eval_arguments(arguments, env, &arguments_length); |
|
|
|
} |
|
|
|
|
|
|
|
switch (operator->value.built_in_function->type) { |
|
|
|
case Built_In_Addition: { |
|
|
|
return built_in_add(evaluated_arguments); |
|
|
|
} |
|
|
|
case Built_In_Subtraction: { |
|
|
|
return built_in_substract(evaluated_arguments); |
|
|
|
} |
|
|
|
case Built_In_Multiplication: { |
|
|
|
return built_in_multiply(evaluated_arguments); |
|
|
|
} |
|
|
|
case Built_In_Division: { |
|
|
|
return built_in_divide(evaluated_arguments); |
|
|
|
} |
|
|
|
case Built_In_Equal: { |
|
|
|
return built_in_equals(evaluated_arguments); |
|
|
|
} |
|
|
|
case Built_In_Pair: { |
|
|
|
if (arguments_length != 2) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
try { |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
} |
|
|
|
Ast_Node_Type type = operands->value.pair->first->type; |
|
|
|
switch (type) { |
|
|
|
case Ast_Node_Type_Built_In_Function: return create_ast_node_keyword("built-in-function"); |
|
|
|
case Ast_Node_Type_Function: return create_ast_node_keyword("dynamic-function"); |
|
|
|
case Ast_Node_Type_Keyword: return create_ast_node_keyword("keyword"); |
|
|
|
case Ast_Node_Type_Nil: return create_ast_node_keyword("nil"); |
|
|
|
case Ast_Node_Type_Number: return create_ast_node_keyword("number"); |
|
|
|
case Ast_Node_Type_Pair: return create_ast_node_keyword("pair"); |
|
|
|
case Ast_Node_Type_String: return create_ast_node_keyword("string"); |
|
|
|
case Ast_Node_Type_Symbol: return create_ast_node_keyword("symbol"); |
|
|
|
return create_ast_node_pair(evaluated_arguments->value.pair->first, evaluated_arguments->value.pair->rest->value.pair->first); |
|
|
|
} |
|
|
|
case Built_In_First: { |
|
|
|
if (arguments_length != 1) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
if (evaluated_arguments->value.pair->first->type == Ast_Node_Type_Nil) |
|
|
|
return create_ast_node_nil(); |
|
|
|
if (evaluated_arguments->value.pair->first->type != Ast_Node_Type_Pair) |
|
|
|
report_error(Error_Type_Type_Missmatch); |
|
|
|
|
|
|
|
} else if (string_equal("exit", operator_name)) { |
|
|
|
try { |
|
|
|
operands_length = list_length(operands); |
|
|
|
} |
|
|
|
if (operands_length > 1) { |
|
|
|
return evaluated_arguments->value.pair->first->value.pair->first; |
|
|
|
} |
|
|
|
case Built_In_Rest: { |
|
|
|
if (arguments_length != 1) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
if (evaluated_arguments->value.pair->first->type == Ast_Node_Type_Nil) |
|
|
|
return create_ast_node_nil(); |
|
|
|
if (evaluated_arguments->value.pair->first->type != Ast_Node_Type_Pair) |
|
|
|
report_error(Error_Type_Type_Missmatch); |
|
|
|
|
|
|
|
if (operands_length == 1) { |
|
|
|
try { |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
} |
|
|
|
Ast_Node* error_code = operands->value.pair->first; |
|
|
|
if (error_code->type != Ast_Node_Type_Number) |
|
|
|
report_error(Error_Type_Type_Missmatch); |
|
|
|
|
|
|
|
exit((int)error_code->value.number->value); |
|
|
|
return evaluated_arguments->value.pair->first->value.pair->rest; |
|
|
|
} |
|
|
|
case Built_In_Eval: { |
|
|
|
if (arguments_length != 1) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
exit(0); |
|
|
|
|
|
|
|
} else if (string_equal("print", operator_name)) { |
|
|
|
Ast_Node* result; |
|
|
|
try { |
|
|
|
operands_length = list_length(operands); |
|
|
|
result = eval_expr(evaluated_arguments->value.pair->first, env); |
|
|
|
} |
|
|
|
if (operands_length != 1) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
return result; |
|
|
|
} |
|
|
|
case Built_In_Prog: { |
|
|
|
if (evaluated_arguments->type == Ast_Node_Type_Nil) |
|
|
|
return evaluated_arguments; |
|
|
|
|
|
|
|
// skip to the last evaluated operand and return it, |
|
|
|
// we use eval_arguments here instead of doing it |
|
|
|
// manually, because we want to increase code reuse, |
|
|
|
// but at the cost that we have to find the end of the |
|
|
|
// list again |
|
|
|
while (evaluated_arguments->value.pair->rest->type == Ast_Node_Type_Pair) { |
|
|
|
evaluated_arguments = evaluated_arguments->value.pair->rest; |
|
|
|
} |
|
|
|
try { |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
return evaluated_arguments->value.pair->first; |
|
|
|
} |
|
|
|
case Built_In_List: { |
|
|
|
return evaluated_arguments; |
|
|
|
} |
|
|
|
case Built_In_Print: { |
|
|
|
if (arguments_length != 1) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
print(operands->value.pair->first); |
|
|
|
print(evaluated_arguments->value.pair->first); |
|
|
|
printf("\n"); |
|
|
|
return operands->value.pair->first; |
|
|
|
} else if (string_equal("read", operator_name)) { |
|
|
|
try { |
|
|
|
operands_length = list_length(operands); |
|
|
|
} |
|
|
|
if (operands_length > 1) { |
|
|
|
return arguments->value.pair->first; |
|
|
|
} |
|
|
|
case Built_In_Read: { |
|
|
|
if (arguments_length > 1) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
|
|
|
|
if (operands_length == 1) { |
|
|
|
try { |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
} |
|
|
|
Ast_Node* prompt = operands->value.pair->first; |
|
|
|
if (arguments_length == 1) { |
|
|
|
Ast_Node* prompt = evaluated_arguments->value.pair->first; |
|
|
|
if (prompt->type == Ast_Node_Type_String) |
|
|
|
printf("%s", prompt->value.string->value); |
|
|
|
else |
|
|
|
print(operands->value.pair->first); |
|
|
|
print(evaluated_arguments->value.pair->first); |
|
|
|
} |
|
|
|
char* line = read_line(); |
|
|
|
return create_ast_node_string(line, (int)strlen(line)); |
|
|
|
} else if (string_equal("pair", operator_name)) { |
|
|
|
try { |
|
|
|
operands_length = list_length(operands); |
|
|
|
} |
|
|
|
if (operands_length != 2) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
try { |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
} |
|
|
|
|
|
|
|
return create_ast_node_pair(operands->value.pair->first, operands->value.pair->rest->value.pair->first); |
|
|
|
} else if (string_equal("first", operator_name)) { |
|
|
|
try { |
|
|
|
operands_length = list_length(operands); |
|
|
|
} |
|
|
|
if (operands_length != 1) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
try { |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
} |
|
|
|
if (operands->value.pair->first->type == Ast_Node_Type_Nil) |
|
|
|
return create_ast_node_nil(); |
|
|
|
if (operands->value.pair->first->type != Ast_Node_Type_Pair) |
|
|
|
report_error(Error_Type_Type_Missmatch); |
|
|
|
|
|
|
|
return operands->value.pair->first->value.pair->first; |
|
|
|
} else if (string_equal("rest", operator_name)) { |
|
|
|
try { |
|
|
|
operands_length = list_length(operands); |
|
|
|
} |
|
|
|
if (operands_length != 1) { |
|
|
|
} |
|
|
|
case Built_In_Type: { |
|
|
|
if (arguments_length != 1) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
try { |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
} |
|
|
|
if (operands->value.pair->first->type == Ast_Node_Type_Nil) |
|
|
|
return create_ast_node_nil(); |
|
|
|
if (operands->value.pair->first->type != Ast_Node_Type_Pair) |
|
|
|
report_error(Error_Type_Type_Missmatch); |
|
|
|
|
|
|
|
return operands->value.pair->first->value.pair->rest; |
|
|
|
} else if (string_equal("if", operator_name)) { |
|
|
|
try { |
|
|
|
operands_length = list_length(operands); |
|
|
|
Ast_Node_Type type = evaluated_arguments->value.pair->first->type; |
|
|
|
switch (type) { |
|
|
|
case Ast_Node_Type_Built_In_Function: return create_ast_node_keyword("built-in-function"); |
|
|
|
case Ast_Node_Type_Function: return create_ast_node_keyword("dynamic-function"); |
|
|
|
case Ast_Node_Type_Keyword: return create_ast_node_keyword("keyword"); |
|
|
|
case Ast_Node_Type_Nil: return create_ast_node_keyword("nil"); |
|
|
|
case Ast_Node_Type_Number: return create_ast_node_keyword("number"); |
|
|
|
case Ast_Node_Type_Pair: return create_ast_node_keyword("pair"); |
|
|
|
case Ast_Node_Type_String: return create_ast_node_keyword("string"); |
|
|
|
case Ast_Node_Type_Symbol: return create_ast_node_keyword("symbol"); |
|
|
|
} |
|
|
|
if (operands_length != 2 && operands_length != 3) { |
|
|
|
} |
|
|
|
case Built_In_Exit: { |
|
|
|
if (arguments_length > 1) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
|
|
|
|
Ast_Node* condition = operands->value.pair->first; |
|
|
|
Ast_Node* then_part = operands->value.pair->rest; |
|
|
|
Ast_Node* else_part = then_part->value.pair->rest; |
|
|
|
|
|
|
|
bool truthy; |
|
|
|
try { |
|
|
|
truthy = is_truthy(condition, env); |
|
|
|
} |
|
|
|
Ast_Node* result; |
|
|
|
if (truthy) |
|
|
|
try{ |
|
|
|
result = eval_expr(then_part->value.pair->first, env); |
|
|
|
} |
|
|
|
else if (operands_length == 3) |
|
|
|
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; |
|
|
|
while (operands->type != Ast_Node_Type_Nil) { |
|
|
|
if (operands->type != Ast_Node_Type_Pair) { |
|
|
|
report_error(Error_Type_Ill_Formed_List); |
|
|
|
} |
|
|
|
try { |
|
|
|
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); |
|
|
|
} |
|
|
|
try { |
|
|
|
result |= is_truthy(operands->value.pair->first, env); |
|
|
|
} |
|
|
|
operands = operands->value.pair->rest; |
|
|
|
if (arguments_length == 1) { |
|
|
|
Ast_Node* error_code = evaluated_arguments->value.pair->first; |
|
|
|
if (error_code->type != Ast_Node_Type_Number) |
|
|
|
report_error(Error_Type_Type_Missmatch); |
|
|
|
|
|
|
|
if (result) return create_ast_node_number(1);; |
|
|
|
exit((int)error_code->value.number->value); |
|
|
|
} |
|
|
|
exit(0); |
|
|
|
} |
|
|
|
|
|
|
|
return create_ast_node_nil(); |
|
|
|
} else if (string_equal("not", operator_name)) { |
|
|
|
try { |
|
|
|
operands_length = list_length(operands); |
|
|
|
} |
|
|
|
if (operands_length != 1) { |
|
|
|
report_error(Error_Type_Wrong_Number_Of_Arguments); |
|
|
|
} |
|
|
|
bool truthy; |
|
|
|
try { |
|
|
|
truthy = is_truthy(operands->value.pair->first, env); |
|
|
|
} |
|
|
|
if (truthy) |
|
|
|
return create_ast_node_nil(); |
|
|
|
return create_ast_node_number(1); |
|
|
|
} else { |
|
|
|
default: |
|
|
|
report_error(Error_Type_Not_Yet_Implemented); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// assume it's lambda function and evaluate the operands in |
|
|
|
// place |
|
|
|
operands = eval_operands(operands, env); |
|
|
|
// assume it's lambda function and evaluate the arguments |
|
|
|
arguments = eval_arguments(arguments, env, &arguments_length); |
|
|
|
} |
|
|
|
|
|
|
|
default: |
|
|
|
|