fixed some bugs and stuff
This commit is contained in:
+2
-12
@@ -1,12 +1,2 @@
|
|||||||
((lambda (x) (* x x)) 2)
|
(define operators (list + - * /))
|
||||||
|
(print ((first operators) 1 2 3))
|
||||||
(setq a 3)
|
|
||||||
|
|
||||||
(let ((a 10))
|
|
||||||
(let ((b 5))
|
|
||||||
(setq a 4))
|
|
||||||
a)
|
|
||||||
|
|
||||||
|
|
||||||
a
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
@echo off
|
||||||
pushd %~dp0\vs
|
pushd %~dp0\vs
|
||||||
start lisp.sln
|
start lisp.sln
|
||||||
popd
|
popd
|
||||||
|
|||||||
+111
-47
@@ -25,15 +25,58 @@ int list_length(Ast_Node* node) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void eval_operands(Ast_Node* operands, Environment* env) {
|
/**
|
||||||
while (!error) {
|
Copies a list, in that it creates a new list, however the items are
|
||||||
if (operands->type == Ast_Node_Type_Pair) {
|
the same as in the original (same pointers). This is neede to copy
|
||||||
operands->value.pair->first = eval_expr(operands->value.pair->first, env);
|
a list when evaluating a parameters list, but not wanting to change
|
||||||
operands = operands->value.pair->rest;
|
the parameters list. This happens if you have someting like:
|
||||||
} else {
|
|
||||||
return;
|
(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) {
|
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;
|
ret->type = Ast_Node_Type_Nil;
|
||||||
return ret;
|
return ret;
|
||||||
case Ast_Node_Type_Symbol:
|
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_Number:
|
||||||
case Ast_Node_Type_Keyword:
|
case Ast_Node_Type_Keyword:
|
||||||
case Ast_Node_Type_String:
|
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;
|
Ast_Node* operands = node->value.pair->rest;
|
||||||
int operands_length;
|
int operands_length;
|
||||||
|
|
||||||
|
|
||||||
// check for built ins functions
|
// check for built ins functions
|
||||||
if (operator->type == Ast_Node_Type_Built_In_Function) {
|
if (operator->type == Ast_Node_Type_Built_In_Function) {
|
||||||
char* operator_name = operator->value.built_in_function->identifier;
|
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) {
|
if (operands_length != 1) {
|
||||||
report_error(Error_Type_Wrong_Number_Of_Arguments);
|
report_error(Error_Type_Wrong_Number_Of_Arguments);
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
return eval_expr(operands->value.pair->first, env);
|
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)) {
|
} else if (string_equal("prog", operator_name)) {
|
||||||
if (operands->type == Ast_Node_Type_Nil)
|
if (operands->type == Ast_Node_Type_Nil)
|
||||||
return operands;
|
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 = copy_list(operands);
|
||||||
operands = operands->value.pair->rest;
|
Ast_Node* evaluated_operands;
|
||||||
else {
|
try {
|
||||||
if (operands->value.pair->rest->type != Ast_Node_Type_Nil)
|
evaluated_operands = eval_operands(operands, env);
|
||||||
report_error(Error_Type_Ill_Formed_List);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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)) {
|
} else if (string_equal("list", operator_name)) {
|
||||||
try {
|
try {
|
||||||
eval_operands(operands, env);
|
operands = eval_operands(operands, env);
|
||||||
}
|
}
|
||||||
return operands;
|
return operands;
|
||||||
} else if (string_equal("=", operator_name)) {
|
} else if (string_equal("=", operator_name)) {
|
||||||
try {
|
try {
|
||||||
eval_operands(operands, env);
|
operands = eval_operands(operands, env);
|
||||||
}
|
}
|
||||||
return built_in_equals(operands);
|
return built_in_equals(operands);
|
||||||
} else if (string_equal("+", operator_name)) {
|
} else if (string_equal("+", operator_name)) {
|
||||||
try {
|
try {
|
||||||
eval_operands(operands, env);
|
operands = eval_operands(operands, env);
|
||||||
}
|
}
|
||||||
return built_in_add(operands);
|
return built_in_add(operands);
|
||||||
} else if (string_equal("-", operator_name)) {
|
} else if (string_equal("-", operator_name)) {
|
||||||
try {
|
try {
|
||||||
eval_operands(operands, env);
|
operands = eval_operands(operands, env);
|
||||||
}
|
}
|
||||||
return built_in_substract(operands);
|
return built_in_substract(operands);
|
||||||
} else if (string_equal("*", operator_name)) {
|
} else if (string_equal("*", operator_name)) {
|
||||||
try {
|
try {
|
||||||
eval_operands(operands, env);
|
operands = eval_operands(operands, env);
|
||||||
}
|
}
|
||||||
return built_in_multiply(operands);
|
return built_in_multiply(operands);
|
||||||
} else if (string_equal("/", operator_name)) {
|
} else if (string_equal("/", operator_name)) {
|
||||||
try {
|
try {
|
||||||
eval_operands(operands, env);
|
operands = eval_operands(operands, env);
|
||||||
}
|
}
|
||||||
return built_in_divide(operands);
|
return built_in_divide(operands);
|
||||||
} else if (string_equal("define", operator_name)) {
|
} 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);
|
report_error(Error_Type_Type_Missmatch);
|
||||||
|
|
||||||
Ast_Node* value = operands->value.pair->rest->value.pair->first;
|
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);
|
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);
|
report_error(Error_Type_Wrong_Number_Of_Arguments);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
eval_operands(operands, env);
|
operands = eval_operands(operands, env);
|
||||||
}
|
}
|
||||||
Ast_Node_Type type = operands->value.pair->first->type;
|
Ast_Node_Type type = operands->value.pair->first->type;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -180,7 +237,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
|||||||
|
|
||||||
if (operands_length == 1) {
|
if (operands_length == 1) {
|
||||||
try {
|
try {
|
||||||
eval_operands(operands, env);
|
operands = eval_operands(operands, env);
|
||||||
}
|
}
|
||||||
Ast_Node* error_code = operands->value.pair->first;
|
Ast_Node* error_code = operands->value.pair->first;
|
||||||
if (error_code->type != Ast_Node_Type_Number)
|
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);
|
report_error(Error_Type_Wrong_Number_Of_Arguments);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
eval_operands(operands, env);
|
operands = eval_operands(operands, env);
|
||||||
}
|
}
|
||||||
print(operands->value.pair->first);
|
print(operands->value.pair->first);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
@@ -213,7 +270,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
|||||||
|
|
||||||
if (operands_length == 1) {
|
if (operands_length == 1) {
|
||||||
try {
|
try {
|
||||||
eval_operands(operands, env);
|
operands = eval_operands(operands, env);
|
||||||
}
|
}
|
||||||
Ast_Node* prompt = operands->value.pair->first;
|
Ast_Node* prompt = operands->value.pair->first;
|
||||||
if (prompt->type == Ast_Node_Type_String)
|
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);
|
report_error(Error_Type_Wrong_Number_Of_Arguments);
|
||||||
}
|
}
|
||||||
try {
|
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);
|
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);
|
report_error(Error_Type_Wrong_Number_Of_Arguments);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
eval_operands(operands, env);
|
operands = eval_operands(operands, env);
|
||||||
}
|
}
|
||||||
if (operands->value.pair->first->type == Ast_Node_Type_Nil)
|
if (operands->value.pair->first->type == Ast_Node_Type_Nil)
|
||||||
return create_ast_node_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);
|
report_error(Error_Type_Wrong_Number_Of_Arguments);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
eval_operands(operands, env);
|
operands = eval_operands(operands, env);
|
||||||
}
|
}
|
||||||
if (operands->value.pair->first->type == Ast_Node_Type_Nil)
|
if (operands->value.pair->first->type == Ast_Node_Type_Nil)
|
||||||
return create_ast_node_nil();
|
return create_ast_node_nil();
|
||||||
@@ -283,11 +340,17 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
|||||||
try {
|
try {
|
||||||
truthy = is_truthy(condition, env);
|
truthy = is_truthy(condition, env);
|
||||||
}
|
}
|
||||||
|
Ast_Node* result;
|
||||||
if (truthy)
|
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)
|
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();
|
else return create_ast_node_nil();
|
||||||
|
return result;
|
||||||
|
|
||||||
} else if (string_equal("and", operator_name)) {
|
} else if (string_equal("and", operator_name)) {
|
||||||
bool result = true;
|
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
|
// assume it's lambda function and evaluate the operands in
|
||||||
// place
|
// place
|
||||||
eval_operands(operands, env);
|
operands = eval_operands(operands, env);
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -351,11 +414,12 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool is_truthy (Ast_Node* expression, Environment* env) {
|
bool is_truthy (Ast_Node* expression, Environment* env) {
|
||||||
Ast_Node* result = eval_expr(expression, env);
|
Ast_Node* result;
|
||||||
if (error) return false;
|
try {
|
||||||
switch (result->type) {
|
result = eval_expr(expression, env);
|
||||||
case Ast_Node_Type_Nil: return false;
|
|
||||||
/* case Ast_Node_Type_Number: return result->value.number->value != 0; */
|
|
||||||
default: return true;
|
|
||||||
}
|
}
|
||||||
|
if (result->type == Ast_Node_Type_Nil)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -12,7 +12,7 @@
|
|||||||
if(error) return 0; \
|
if(error) return 0; \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
else label(body,__LINE__):
|
else label(body,__LINE__):
|
||||||
|
|
||||||
typedef enum { false, true } bool;
|
typedef enum { false, true } bool;
|
||||||
|
|
||||||
@@ -70,11 +70,11 @@ char* read_entire_file (char* filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate our buffer to that size. */
|
/* Allocate our buffer to that size. */
|
||||||
fileContent = malloc(sizeof(char) * (bufsize) +1);
|
fileContent = (char*)calloc(bufsize, sizeof(char));
|
||||||
|
|
||||||
/* Read the entire file into memory. */
|
/* Read the entire file into memory. */
|
||||||
size_t newLen = fread(fileContent, sizeof(char), bufsize, fp);
|
size_t newLen = fread(fileContent, sizeof(char), bufsize, fp);
|
||||||
fileContent[bufsize-1] = '\0';
|
/* fileContent[bufsize-5] = '\0'; */
|
||||||
if ( ferror( fp ) != 0 ) {
|
if ( ferror( fp ) != 0 ) {
|
||||||
fputs("Error reading file", stderr);
|
fputs("Error reading file", stderr);
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,7 @@ char* read_line() {
|
|||||||
linep = linen;
|
linep = linen;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((*line++ = c) == '\n')
|
if((*line++ = (char)c) == '\n')
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
*line--; // we dont want the \n actually
|
*line--; // we dont want the \n actually
|
||||||
|
|||||||
+2
-4
@@ -31,8 +31,8 @@ int interprete_file (char* file_content) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
print(result);
|
/* print(result); */
|
||||||
printf("\n");
|
/* printf("\n"); */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,6 +76,4 @@ int main (int argc, char *argv[]) {
|
|||||||
run_all_tests();
|
run_all_tests();
|
||||||
return interprete_stdin();
|
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() {
|
testresult test_parse_atom() {
|
||||||
int index_in_text = 0;
|
int index_in_text = 0;
|
||||||
char string[] =
|
char string[] =
|
||||||
@@ -342,6 +375,9 @@ void run_all_tests() {
|
|||||||
invoke_test(test_parse_atom);
|
invoke_test(test_parse_atom);
|
||||||
invoke_test(test_parse_expression);
|
invoke_test(test_parse_expression);
|
||||||
|
|
||||||
|
printf("\n-- Basic evaluating --\n");
|
||||||
|
invoke_test(test_eval_operands);
|
||||||
|
|
||||||
printf("\n-- Built ins --\n");
|
printf("\n-- Built ins --\n");
|
||||||
invoke_test(test_built_in_add);
|
invoke_test(test_built_in_add);
|
||||||
invoke_test(test_built_in_substract);
|
invoke_test(test_built_in_substract);
|
||||||
|
|||||||
@@ -45,6 +45,13 @@
|
|||||||
** TODO progn
|
** TODO progn
|
||||||
** DONE eval
|
** DONE eval
|
||||||
CLOSED: [2018-10-08 Mo 20:28]
|
CLOSED: [2018-10-08 Mo 20:28]
|
||||||
|
|
||||||
|
(setq condition (quote (= a 10)))
|
||||||
|
(setq a 10)
|
||||||
|
(eval condition)
|
||||||
|
(setq a 11)
|
||||||
|
(eval condition)
|
||||||
|
|
||||||
** DONE quote
|
** DONE quote
|
||||||
CLOSED: [2018-10-08 Mo 20:28]
|
CLOSED: [2018-10-08 Mo 20:28]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user