fixed some bugs and stuff
This commit is contained in:
+111
-47
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
+4
-4
@@ -12,7 +12,7 @@
|
||||
if(error) return 0; \
|
||||
break; \
|
||||
} \
|
||||
else label(body,__LINE__):
|
||||
else label(body,__LINE__):
|
||||
|
||||
typedef enum { false, true } bool;
|
||||
|
||||
@@ -70,11 +70,11 @@ char* read_entire_file (char* filename) {
|
||||
}
|
||||
|
||||
/* Allocate our buffer to that size. */
|
||||
fileContent = malloc(sizeof(char) * (bufsize) +1);
|
||||
fileContent = (char*)calloc(bufsize, sizeof(char));
|
||||
|
||||
/* Read the entire file into memory. */
|
||||
size_t newLen = fread(fileContent, sizeof(char), bufsize, fp);
|
||||
fileContent[bufsize-1] = '\0';
|
||||
/* fileContent[bufsize-5] = '\0'; */
|
||||
if ( ferror( fp ) != 0 ) {
|
||||
fputs("Error reading file", stderr);
|
||||
}
|
||||
@@ -112,7 +112,7 @@ char* read_line() {
|
||||
linep = linen;
|
||||
}
|
||||
|
||||
if((*line++ = c) == '\n')
|
||||
if((*line++ = (char)c) == '\n')
|
||||
break;
|
||||
}
|
||||
*line--; // we dont want the \n actually
|
||||
|
||||
+2
-4
@@ -31,8 +31,8 @@ int interprete_file (char* file_content) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
print(result);
|
||||
printf("\n");
|
||||
/* print(result); */
|
||||
/* printf("\n"); */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -76,6 +76,4 @@ int main (int argc, char *argv[]) {
|
||||
run_all_tests();
|
||||
return interprete_stdin();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -79,6 +79,39 @@
|
||||
} \
|
||||
} \
|
||||
|
||||
testresult test_eval_operands() {
|
||||
char operands_string[] = "((eval 1) (+ 1 2) \"okay\" (eval :haha))";
|
||||
Ast_Node* operands = parse_single_expression(operands_string);
|
||||
operands = eval_operands(operands, create_empty_environment());
|
||||
|
||||
assert_no_error(error);
|
||||
assert_equal_int(list_length(operands), 4);
|
||||
|
||||
assert_equal_int(operands->type, Ast_Node_Type_Pair);
|
||||
assert_equal_int(operands->value.pair->first->type, Ast_Node_Type_Number);
|
||||
assert_equal_int(operands->value.pair->first->value.number->value, 1);
|
||||
|
||||
operands = operands->value.pair->rest;
|
||||
|
||||
assert_equal_int(operands->type, Ast_Node_Type_Pair);
|
||||
assert_equal_int(operands->value.pair->first->type, Ast_Node_Type_Number);
|
||||
assert_equal_int(operands->value.pair->first->value.number->value, 3);
|
||||
|
||||
operands = operands->value.pair->rest;
|
||||
|
||||
assert_equal_int(operands->type, Ast_Node_Type_Pair);
|
||||
assert_equal_int(operands->value.pair->first->type, Ast_Node_Type_String);
|
||||
assert_equal_string(operands->value.pair->first->value.string->value, "okay");
|
||||
|
||||
operands = operands->value.pair->rest;
|
||||
|
||||
assert_equal_int(operands->type, Ast_Node_Type_Pair);
|
||||
assert_equal_int(operands->value.pair->first->type, Ast_Node_Type_Keyword);
|
||||
assert_equal_string(operands->value.pair->first->value.keyword->identifier, "haha");
|
||||
|
||||
return pass;
|
||||
}
|
||||
|
||||
testresult test_parse_atom() {
|
||||
int index_in_text = 0;
|
||||
char string[] =
|
||||
@@ -342,6 +375,9 @@ void run_all_tests() {
|
||||
invoke_test(test_parse_atom);
|
||||
invoke_test(test_parse_expression);
|
||||
|
||||
printf("\n-- Basic evaluating --\n");
|
||||
invoke_test(test_eval_operands);
|
||||
|
||||
printf("\n-- Built ins --\n");
|
||||
invoke_test(test_built_in_add);
|
||||
invoke_test(test_built_in_substract);
|
||||
|
||||
Reference in New Issue
Block a user