Просмотр исходного кода

fixed some bugs and stuff

master
FelixBrendel 7 лет назад
Родитель
Сommit
2d3892b034
7 измененных файлов: 162 добавлений и 66 удалений
  1. +2
    -12
      bin/test.lsp
  2. +1
    -0
      debug.bat
  3. +110
    -46
      src/eval.c
  4. +4
    -4
      src/helpers.c
  5. +2
    -4
      src/main.c
  6. +36
    -0
      src/testing.c
  7. +7
    -0
      todo.org

+ 2
- 12
bin/test.lsp Просмотреть файл

@@ -1,12 +1,2 @@
((lambda (x) (* x x)) 2)

(setq a 3)

(let ((a 10))
(let ((b 5))
(setq a 4))
a)


a

(define operators (list + - * /))
(print ((first operators) 1 2 3))

+ 1
- 0
debug.bat Просмотреть файл

@@ -1,3 +1,4 @@
@echo off
pushd %~dp0\vs pushd %~dp0\vs
start lisp.sln start lisp.sln
popd popd

+ 110
- 46
src/eval.c Просмотреть файл

@@ -25,15 +25,58 @@ int list_length(Ast_Node* node) {
return 0; 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) { 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);
} }

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)) { } 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 = 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)) { } 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);
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
src/helpers.c Просмотреть файл

@@ -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
src/main.c Просмотреть файл

@@ -31,8 +31,8 @@ int interprete_file (char* file_content) {
return 1; return 1;
} }
} }
print(result);
printf("\n");
/* print(result); */
/* 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;
} }

+ 36
- 0
src/testing.c Просмотреть файл

@@ -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);


+ 7
- 0
todo.org Просмотреть файл

@@ -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]




Загрузка…
Отмена
Сохранить