We can parse expressions
This commit is contained in:
@@ -27,6 +27,7 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
char* value;
|
||||
int length;
|
||||
} String;
|
||||
|
||||
typedef struct {
|
||||
@@ -42,6 +43,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
Lambda_List* parameters;
|
||||
Pair* form;
|
||||
char* docstring;
|
||||
} Function;
|
||||
|
||||
typedef struct {
|
||||
@@ -79,11 +81,12 @@ Ast_Node* create_ast_node_number(double number) {
|
||||
return node;
|
||||
}
|
||||
|
||||
Ast_Node* create_ast_node_string(char* str) {
|
||||
Ast_Node* create_ast_node_string(char* str, int length) {
|
||||
Ast_Node* node = new(Ast_Node);
|
||||
node->type = Ast_Node_Type_String;
|
||||
node->value.string = new(String);
|
||||
node->value.string->value = str;
|
||||
node->value.string->length = length;
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -95,6 +98,13 @@ Ast_Node* create_ast_node_symbol(char* identifier) {
|
||||
return node;
|
||||
}
|
||||
|
||||
Ast_Node* create_ast_node_keyword(char* keyword) {
|
||||
Ast_Node* node = new(Ast_Node);
|
||||
node->type = Ast_Node_Type_Keyword;
|
||||
node->value.keyword = new(Keyword);
|
||||
node->value.keyword->identifier = keyword;
|
||||
return node;
|
||||
}
|
||||
|
||||
Ast_Node* create_ast_node_built_in_function(char* identifier) {
|
||||
Ast_Node* node = new(Ast_Node);
|
||||
|
||||
@@ -5,6 +5,7 @@ typedef enum {
|
||||
Error_Type_Symbol_Not_Defined,
|
||||
Error_Type_Not_A_Function,
|
||||
Error_Type_Not_Yet_Implemented,
|
||||
Error_Type_Syntax_Error,
|
||||
Error_Type_Unknown_Error,
|
||||
} Error_Type;
|
||||
|
||||
@@ -38,6 +39,7 @@ char* Error_Type_to_string(Error_Type type) {
|
||||
case Error_Type_Wrong_Number_Of_Arguments: return "Wrong number of arguments";
|
||||
case Error_Type_Type_Missmatch: return "Type Missmatch";
|
||||
case Error_Type_Not_Yet_Implemented: return "Not yet implemented";
|
||||
case Error_Type_Syntax_Error: return "Syntax Error";
|
||||
default: return "Unknown Error";
|
||||
}
|
||||
}
|
||||
|
||||
+9
-4
@@ -81,7 +81,8 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
||||
} else if (string_equal("if", operator_name)) {
|
||||
int operands_length = list_length(operands);
|
||||
if (operands_length != 2 && operands_length != 3) {
|
||||
create_error(Error_Type_Wrong_Number_Of_Arguments, operands);
|
||||
if (!error)
|
||||
create_error(Error_Type_Wrong_Number_Of_Arguments, operands);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -124,10 +125,14 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
||||
return create_ast_node_nil();
|
||||
} else if (string_equal("not", operator_name)) {
|
||||
if (list_length(operands) != 1) {
|
||||
create_error(Error_Type_Wrong_Number_Of_Arguments, operands);
|
||||
if (!error)
|
||||
create_error(Error_Type_Wrong_Number_Of_Arguments, operands);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool truthy = is_truthy(operands->value.pair->first, env);
|
||||
if (truthy)
|
||||
return create_ast_node_nil();
|
||||
return create_ast_node_number(1);
|
||||
} else {
|
||||
report_error(Error_Type_Not_Yet_Implemented);
|
||||
}
|
||||
@@ -148,7 +153,7 @@ bool is_truthy (Ast_Node* expression, Environment* env) {
|
||||
Ast_Node* result = eval_expr(expression, env);
|
||||
switch (result->type) {
|
||||
case Ast_Node_Type_Nil: return false;
|
||||
case Ast_Node_Type_Number: return result->value.number->value != 0;
|
||||
/* case Ast_Node_Type_Number: return result->value.number->value != 0; */
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
|
||||
+254
-9
@@ -1,12 +1,257 @@
|
||||
Ast_Node* parse_expression(char* expr) {
|
||||
typedef enum {
|
||||
Parser_State_Code,
|
||||
Parser_State_String,
|
||||
Parser_State_Comment,
|
||||
} Parser_State;
|
||||
typedef struct {
|
||||
Ast_Node** data;
|
||||
int length;
|
||||
int next_index;
|
||||
} Ast_Node_Array_List;
|
||||
|
||||
// initial state is code
|
||||
Parser_State current_parser_state = Parser_State_Code;
|
||||
Ast_Node_Array_List* create_Ast_Node_Array_List() {
|
||||
Ast_Node_Array_List* ret = new (Ast_Node_Array_List);
|
||||
|
||||
return nullptr;
|
||||
// create one with 16 entries first
|
||||
ret->length = 16;
|
||||
ret->data = (Ast_Node**)malloc(ret->length * sizeof(Ast_Node));
|
||||
ret->next_index = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void append_to_Ast_Node_Array_List(Ast_Node_Array_List* list, Ast_Node* node) {
|
||||
if (list->next_index == list->length) {
|
||||
list->length *= 2;
|
||||
list->data =
|
||||
(Ast_Node**)realloc(list->data, list->length * sizeof(Ast_Node));
|
||||
}
|
||||
|
||||
list->data[list->next_index++] = node;
|
||||
}
|
||||
|
||||
void eat_comment_line(char* text, int* index_in_text) {
|
||||
// safety check if we are actually starting a comment here
|
||||
if (text[*index_in_text] != ';')
|
||||
return;
|
||||
|
||||
// eat the comment line
|
||||
do {
|
||||
++(*index_in_text);
|
||||
} while (text[(*index_in_text)] != '\n' &&
|
||||
text[(*index_in_text)] != '\0');
|
||||
}
|
||||
|
||||
void eat_whitespace(char* text, int* index_in_text) {
|
||||
// skip whitespaces
|
||||
while (text[(*index_in_text)] == ' ' ||
|
||||
text[(*index_in_text)] == '\t' ||
|
||||
text[(*index_in_text)] == '\n') {
|
||||
++(*index_in_text);
|
||||
}
|
||||
}
|
||||
|
||||
void eat_until_code(char* text, int* index_in_text) {
|
||||
int position_before;
|
||||
do {
|
||||
position_before = *index_in_text;
|
||||
eat_comment_line(text, index_in_text);
|
||||
eat_whitespace(text, index_in_text);
|
||||
} while (position_before != *index_in_text);
|
||||
}
|
||||
|
||||
char* read_atom(char* text, int* index_in_text) {
|
||||
int atom_length = 0;
|
||||
while (text[*index_in_text+atom_length] != ' ' &&
|
||||
text[*index_in_text+atom_length] != ')' &&
|
||||
text[*index_in_text+atom_length] != '(' &&
|
||||
text[*index_in_text+atom_length] != '\0' &&
|
||||
text[*index_in_text+atom_length] != '\n' &&
|
||||
text[*index_in_text+atom_length] != '\t')
|
||||
{
|
||||
++atom_length;
|
||||
}
|
||||
|
||||
// let's mark the end of the atom there quickly, so the string can
|
||||
// be copied from there easily and then put the char that was
|
||||
// before there back
|
||||
char before = text[*index_in_text+atom_length];
|
||||
text[*index_in_text+atom_length] = '\0';
|
||||
|
||||
// get the atom
|
||||
char* atom = (char*)malloc(atom_length*sizeof(char)+1); // plus null char
|
||||
strcpy(atom, text+(*index_in_text));
|
||||
|
||||
// restore the original string
|
||||
text[*index_in_text+atom_length] = before;
|
||||
|
||||
// update the index to point to the character after the atom
|
||||
// ended
|
||||
*index_in_text += atom_length;
|
||||
|
||||
return atom;
|
||||
}
|
||||
|
||||
Ast_Node* parse_number(char* text, int* index_in_text) {
|
||||
double number;
|
||||
char* str_number = read_atom(text, index_in_text);
|
||||
sscanf(str_number, "%lf", &number);
|
||||
return create_ast_node_number(number);
|
||||
}
|
||||
|
||||
|
||||
Ast_Node* parse_keyword(char* text, int* index_in_text) {
|
||||
// we are now on the colon
|
||||
++(*index_in_text);
|
||||
char* str_keyword = read_atom(text, index_in_text);
|
||||
return create_ast_node_keyword(str_keyword);
|
||||
}
|
||||
|
||||
Ast_Node* parse_symbol(char* text, int* index_in_text) {
|
||||
// we are now at the first char of the symbol
|
||||
char* str_symbol = read_atom(text, index_in_text);
|
||||
return create_ast_node_symbol(str_symbol);
|
||||
}
|
||||
|
||||
Ast_Node* parse_string(char* text, int* index_in_text) {
|
||||
// the first character is the '"'
|
||||
++(*index_in_text);
|
||||
|
||||
// now we are at the first letter, if this is the closing '"' then
|
||||
// it's easy
|
||||
if (text[*index_in_text] == '"') {
|
||||
char* str = new(char);
|
||||
*str = '\0';
|
||||
return create_ast_node_string(str, 0);
|
||||
}
|
||||
|
||||
// okay so the first letter was not actually closing the string...
|
||||
int string_length = 0;
|
||||
while (text[*index_in_text+string_length] != '"' ||
|
||||
text[*index_in_text+string_length] == '\\')
|
||||
{
|
||||
++string_length;
|
||||
}
|
||||
|
||||
// we found the end of the string
|
||||
text[*index_in_text+string_length] = '\0';
|
||||
|
||||
char* string = (char*)malloc(string_length*sizeof(char)+1); // plus null char
|
||||
strcpy(string, text+(*index_in_text));
|
||||
|
||||
text[*index_in_text+string_length] = '"';
|
||||
|
||||
*index_in_text += string_length +1; // plus one because we want to
|
||||
// go after the quotes
|
||||
|
||||
return create_ast_node_string(string, string_length);
|
||||
}
|
||||
|
||||
Ast_Node* parse_atom(char* text, int* index_in_text) {
|
||||
// numbers
|
||||
if ((text[*index_in_text] <= 57 && // if number
|
||||
text[*index_in_text] >= 48)
|
||||
||
|
||||
((text[*index_in_text] == '+' || // or if sign and then number
|
||||
text[*index_in_text] == '-')
|
||||
&&
|
||||
(text[*index_in_text +1] <= 57 &&
|
||||
text[*index_in_text +1] >= 48))
|
||||
||
|
||||
((text[*index_in_text] == '.') // or if . and then number
|
||||
&&
|
||||
(text[*index_in_text +1] <= 57 &&
|
||||
text[*index_in_text +1] >= 48)))
|
||||
return parse_number(text, index_in_text);
|
||||
|
||||
// keywords
|
||||
if (text[*index_in_text] == ':')
|
||||
return parse_keyword(text, index_in_text);
|
||||
|
||||
// strings
|
||||
if (text[*index_in_text] == '"')
|
||||
return parse_string(text, index_in_text);
|
||||
|
||||
return parse_symbol(text, index_in_text);
|
||||
}
|
||||
|
||||
Ast_Node* parse_expression(char* text, int* index_in_text) {
|
||||
// okay we know the text under the index is '('
|
||||
++(*index_in_text);
|
||||
|
||||
eat_whitespace(text, index_in_text);
|
||||
|
||||
// if there was actually nothing in the list return nil
|
||||
if (text[(*index_in_text)] == ')') {
|
||||
++(*index_in_text);
|
||||
return create_ast_node_nil();
|
||||
}
|
||||
|
||||
// okay there is something
|
||||
Ast_Node* head = new(Ast_Node);
|
||||
head->type = Ast_Node_Type_Pair;
|
||||
head->value.pair = new(Pair);
|
||||
Ast_Node* expression = head;
|
||||
|
||||
while (true) {
|
||||
if (text[(*index_in_text)] == '(') {
|
||||
head->value.pair->first = parse_expression(text, index_in_text);
|
||||
} else {
|
||||
head->value.pair->first = parse_atom(text, index_in_text);
|
||||
}
|
||||
|
||||
eat_until_code(text, index_in_text);
|
||||
|
||||
if (text[(*index_in_text)] == ')') {
|
||||
head->value.pair->rest = create_ast_node_nil();
|
||||
++(*index_in_text);
|
||||
break;
|
||||
} else if (text[(*index_in_text)] == '.') {
|
||||
++(*index_in_text);
|
||||
eat_until_code(text, index_in_text);
|
||||
|
||||
if (text[(*index_in_text)] == '(')
|
||||
head->value.pair->rest = parse_expression(text, index_in_text);
|
||||
else
|
||||
head->value.pair->rest = parse_atom(text, index_in_text);
|
||||
|
||||
eat_until_code(text, index_in_text);
|
||||
|
||||
if (text[(*index_in_text)] != ')')
|
||||
create_error(Error_Type_Syntax_Error, nullptr);
|
||||
++(*index_in_text);
|
||||
break;
|
||||
} else {
|
||||
head->value.pair->rest = create_ast_node_pair(nullptr, nullptr);
|
||||
head = head->value.pair->rest;
|
||||
}
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
Ast_Node* parse_single_expression(char* text) {
|
||||
int index_in_text = 0;
|
||||
return parse_expression(text, &index_in_text);
|
||||
}
|
||||
|
||||
Ast_Node_Array_List* parse_program(char* text) {
|
||||
Ast_Node_Array_List* program = create_Ast_Node_Array_List();
|
||||
|
||||
int index_in_text = 0;
|
||||
|
||||
while (text[index_in_text] != '\0') {
|
||||
switch (text[index_in_text]) {
|
||||
case '(': {
|
||||
append_to_Ast_Node_Array_List(
|
||||
program, parse_expression(text, &index_in_text));
|
||||
} break;
|
||||
case ';': {
|
||||
eat_comment_line(text, &index_in_text);
|
||||
} break;
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n': {
|
||||
++index_in_text;
|
||||
} break;
|
||||
default:
|
||||
create_error(Error_Type_Syntax_Error, nullptr);
|
||||
/* syntax error */
|
||||
}
|
||||
}
|
||||
return program;
|
||||
}
|
||||
|
||||
+184
-124
@@ -4,16 +4,14 @@
|
||||
#define pass 1
|
||||
#define fail 0
|
||||
|
||||
#define print_assert_equal_fail(variable, value, type, format) \
|
||||
printf("\nAssertion failed for '" #variable "'" \
|
||||
"\n\t in %s:%d" \
|
||||
"\n\texpected: " format \
|
||||
"\n\tgot: " format "\n", \
|
||||
__FILE__, __LINE__, (type)value, (type)variable)
|
||||
#define print_assert_equal_fail(variable, value, type, format) \
|
||||
printf("\n%s:%d: Assertion failed\n\tfor '" #variable "'" \
|
||||
"\n\texpected: " format \
|
||||
"\n\tgot: " format "\n", \
|
||||
__FILE__, __LINE__, (type)value, (type)variable)
|
||||
|
||||
#define print_assert_not_equal_fail(variable, value, type, format) \
|
||||
printf("\nAssertion failed for '" #variable "'" \
|
||||
"\n\t in %s:%d" \
|
||||
printf("\n%s:%d: Assertion failed\n\tfor '" #variable "'" \
|
||||
"\n\texpected not: " format \
|
||||
"\n\tgot anyways: " format "\n", \
|
||||
__FILE__, __LINE__, (type)value, (type)variable)
|
||||
@@ -50,6 +48,13 @@
|
||||
return fail; \
|
||||
}
|
||||
|
||||
#define assert_equal_string(variable, value) \
|
||||
if (!string_equal(variable, value)) { \
|
||||
print_assert_equal_fail(variable, value, char*, "%s"); \
|
||||
return fail; \
|
||||
}
|
||||
|
||||
|
||||
#define assert_null(variable) \
|
||||
assert_equal_int(variable, nullptr)
|
||||
|
||||
@@ -74,21 +79,121 @@
|
||||
} \
|
||||
} \
|
||||
|
||||
testresult test_parse_atom() {
|
||||
int index_in_text = 0;
|
||||
char string[] =
|
||||
"123 -1.23e-2 " // numbers
|
||||
"\"asd\" " // strings
|
||||
":key1 :key:2 " // keywords
|
||||
"sym +"; // symbols
|
||||
|
||||
// test numbers
|
||||
Ast_Node* result = parse_atom(string, &index_in_text);
|
||||
assert_equal_int(result->type, Ast_Node_Type_Number);
|
||||
assert_equal_double(result->value.number->value, 123);
|
||||
|
||||
++index_in_text;
|
||||
|
||||
result = parse_atom(string, &index_in_text);
|
||||
assert_equal_int(result->type, Ast_Node_Type_Number);
|
||||
assert_equal_double(result->value.number->value, -1.23e-2);
|
||||
|
||||
// test strings
|
||||
++index_in_text;
|
||||
|
||||
result = parse_atom(string, &index_in_text);
|
||||
assert_equal_int(result->type, Ast_Node_Type_String);
|
||||
assert_equal_string(result->value.string->value, "asd");
|
||||
|
||||
// test keywords
|
||||
++index_in_text;
|
||||
|
||||
result = parse_atom(string, &index_in_text);
|
||||
assert_equal_int(result->type, Ast_Node_Type_Keyword);
|
||||
assert_equal_string(result->value.keyword->identifier, "key1");
|
||||
|
||||
++index_in_text;
|
||||
|
||||
result = parse_atom(string, &index_in_text);
|
||||
assert_equal_int(result->type, Ast_Node_Type_Keyword);
|
||||
assert_equal_string(result->value.keyword->identifier, "key:2");
|
||||
|
||||
// test symbols
|
||||
++index_in_text;
|
||||
|
||||
result = parse_atom(string, &index_in_text);
|
||||
assert_equal_int(result->type, Ast_Node_Type_Symbol);
|
||||
assert_equal_string(result->value.symbol->identifier, "sym");
|
||||
|
||||
++index_in_text;
|
||||
|
||||
result = parse_atom(string, &index_in_text);
|
||||
assert_equal_int(result->type, Ast_Node_Type_Symbol);
|
||||
assert_equal_string(result->value.symbol->identifier, "+");
|
||||
|
||||
return pass;
|
||||
}
|
||||
|
||||
testresult test_parse_expression() {
|
||||
int index_in_text = 0;
|
||||
char string[] = "(fun + 12)";
|
||||
|
||||
Ast_Node* result = parse_expression(string, &index_in_text);
|
||||
assert_no_error(error);
|
||||
|
||||
assert_equal_int(result->type, Ast_Node_Type_Pair);
|
||||
assert_equal_int(result->value.pair->first->type, Ast_Node_Type_Symbol);
|
||||
assert_equal_string(result->value.pair->first->value.symbol->identifier, "fun");
|
||||
|
||||
result = result->value.pair->rest;
|
||||
|
||||
assert_equal_int(result->type, Ast_Node_Type_Pair);
|
||||
assert_equal_int(result->value.pair->first->type, Ast_Node_Type_Symbol);
|
||||
assert_equal_string(result->value.pair->first->value.symbol->identifier, "+");
|
||||
|
||||
result = result->value.pair->rest;
|
||||
|
||||
assert_equal_int(result->type, Ast_Node_Type_Pair);
|
||||
assert_equal_int(result->value.pair->first->type, Ast_Node_Type_Number);
|
||||
assert_equal_double(result->value.pair->first->value.number->value, 12);
|
||||
|
||||
result = result->value.pair->rest;
|
||||
|
||||
assert_equal_int(result->type, Ast_Node_Type_Nil);
|
||||
|
||||
char string2[] = "(define fun (lambda (x) (+ 5 (* x x ))))";
|
||||
index_in_text = 0;
|
||||
|
||||
result = parse_expression(string2, &index_in_text);
|
||||
assert_no_error(error);
|
||||
|
||||
assert_equal_int(result->type, Ast_Node_Type_Pair);
|
||||
assert_equal_int(result->value.pair->first->type, Ast_Node_Type_Symbol);
|
||||
assert_equal_string(result->value.pair->first->value.symbol->identifier, "define");
|
||||
|
||||
result = result->value.pair->rest;
|
||||
|
||||
assert_equal_int(result->type, Ast_Node_Type_Pair);
|
||||
assert_equal_int(result->value.pair->first->type, Ast_Node_Type_Symbol);
|
||||
assert_equal_string(result->value.pair->first->value.symbol->identifier, "fun");
|
||||
|
||||
result = result->value.pair->rest;
|
||||
|
||||
assert_equal_int(result->type, Ast_Node_Type_Pair);
|
||||
assert_equal_int(result->value.pair->first->type, Ast_Node_Type_Pair);
|
||||
assert_equal_int(result->value.pair->first->value.pair->first->type, Ast_Node_Type_Symbol);
|
||||
assert_equal_string(result->value.pair->first->value.pair->first->value.symbol->identifier, "lambda");
|
||||
|
||||
result = result->value.pair->rest;
|
||||
|
||||
|
||||
return pass;
|
||||
}
|
||||
|
||||
testresult test_built_in_add() {
|
||||
Ast_Node* plus = create_ast_node_symbol("+");
|
||||
Ast_Node* ten = create_ast_node_number(10);
|
||||
Ast_Node* four = create_ast_node_number(4);
|
||||
Ast_Node* nil = create_ast_node_nil();
|
||||
Ast_Node* form = create_ast_node_pair(
|
||||
plus,
|
||||
create_ast_node_pair(
|
||||
ten,
|
||||
create_ast_node_pair(
|
||||
four,
|
||||
nil)));
|
||||
|
||||
Ast_Node* result = eval_expr(form, create_empty_environment());
|
||||
char exp_string[] = "(+ 10 4)";
|
||||
Ast_Node* expression = parse_single_expression(exp_string);
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment());
|
||||
|
||||
assert_no_error(error);
|
||||
assert_not_null(result);
|
||||
@@ -99,19 +204,9 @@ testresult test_built_in_add() {
|
||||
}
|
||||
|
||||
testresult test_built_in_substract() {
|
||||
Ast_Node* minus = create_ast_node_symbol("-");
|
||||
Ast_Node* ten = create_ast_node_number(10);
|
||||
Ast_Node* four = create_ast_node_number(4);
|
||||
Ast_Node* nil = create_ast_node_nil();
|
||||
Ast_Node* form = create_ast_node_pair(
|
||||
minus,
|
||||
create_ast_node_pair(
|
||||
ten,
|
||||
create_ast_node_pair(
|
||||
four,
|
||||
nil)));
|
||||
|
||||
Ast_Node* result = eval_expr(form, create_empty_environment());
|
||||
char exp_string[] = "(- 10 4)";
|
||||
Ast_Node* expression = parse_single_expression(exp_string);
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment());
|
||||
|
||||
assert_no_error(error);
|
||||
assert_not_null(result);
|
||||
@@ -123,19 +218,9 @@ testresult test_built_in_substract() {
|
||||
|
||||
|
||||
testresult test_built_in_multiply() {
|
||||
Ast_Node* times = create_ast_node_symbol("*");
|
||||
Ast_Node* ten = create_ast_node_number(10);
|
||||
Ast_Node* four = create_ast_node_number(4);
|
||||
Ast_Node* nil = create_ast_node_nil();
|
||||
Ast_Node* form = create_ast_node_pair(
|
||||
times,
|
||||
create_ast_node_pair(
|
||||
ten,
|
||||
create_ast_node_pair(
|
||||
four,
|
||||
nil)));
|
||||
|
||||
Ast_Node* result = eval_expr(form, create_empty_environment());
|
||||
char exp_string[] = "(* 10 4)";
|
||||
Ast_Node* expression = parse_single_expression(exp_string);
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment());
|
||||
|
||||
assert_no_error(error);
|
||||
assert_not_null(result);
|
||||
@@ -147,19 +232,9 @@ testresult test_built_in_multiply() {
|
||||
|
||||
|
||||
testresult test_built_in_divide() {
|
||||
Ast_Node* over = create_ast_node_symbol("/");
|
||||
Ast_Node* ten = create_ast_node_number(20);
|
||||
Ast_Node* four = create_ast_node_number(4);
|
||||
Ast_Node* nil = create_ast_node_nil();
|
||||
Ast_Node* form = create_ast_node_pair(
|
||||
over,
|
||||
create_ast_node_pair(
|
||||
ten,
|
||||
create_ast_node_pair(
|
||||
four,
|
||||
nil)));
|
||||
|
||||
Ast_Node* result = eval_expr(form, create_empty_environment());
|
||||
char exp_string[] = "(/ 20 4)";
|
||||
Ast_Node* expression = parse_single_expression(exp_string);
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment());
|
||||
|
||||
assert_null(error);
|
||||
assert_not_null(result);
|
||||
@@ -171,35 +246,20 @@ testresult test_built_in_divide() {
|
||||
|
||||
|
||||
testresult test_built_in_if() {
|
||||
Ast_Node* _if = create_ast_node_symbol("if");
|
||||
Ast_Node* cond = create_ast_node_number(1);
|
||||
Ast_Node* four = create_ast_node_number(4);
|
||||
Ast_Node* five = create_ast_node_number(5);
|
||||
Ast_Node* nil = create_ast_node_nil();
|
||||
Ast_Node* form = create_ast_node_pair(
|
||||
_if,
|
||||
create_ast_node_pair(
|
||||
cond,
|
||||
create_ast_node_pair(
|
||||
four,
|
||||
create_ast_node_pair(
|
||||
five,
|
||||
nil))));
|
||||
Ast_Node* result;
|
||||
|
||||
// test *then* case
|
||||
result = eval_expr(form, create_empty_environment());
|
||||
char exp_string1[] = "(if 1 4 5)";
|
||||
Ast_Node* expression = parse_single_expression(exp_string1);
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment());
|
||||
|
||||
assert_no_error(error);
|
||||
assert_not_null(result);
|
||||
assert_equal_int(result->type, Ast_Node_Type_Number);
|
||||
assert_equal_double(result->value.number->value, 4);
|
||||
|
||||
// test *else* case
|
||||
cond->value.number->value = 0;
|
||||
result = eval_expr(form, create_empty_environment());
|
||||
char exp_string2[] = "(if () 4 5)";
|
||||
expression = parse_single_expression(exp_string2);
|
||||
result = eval_expr(expression, create_empty_environment());
|
||||
|
||||
assert_null(error);
|
||||
assert_no_error(error);
|
||||
assert_not_null(result);
|
||||
assert_equal_int(result->type, Ast_Node_Type_Number);
|
||||
assert_equal_double(result->value.number->value, 5);
|
||||
@@ -208,24 +268,9 @@ testresult test_built_in_if() {
|
||||
}
|
||||
|
||||
testresult test_built_in_and() {
|
||||
Ast_Node* _and = create_ast_node_symbol("and");
|
||||
Ast_Node* cond1 = create_ast_node_number(1);
|
||||
Ast_Node* cond2 = create_ast_node_string("asd");
|
||||
Ast_Node* cond3 = create_ast_node_number(4);
|
||||
Ast_Node* nil = create_ast_node_nil();
|
||||
Ast_Node* form = create_ast_node_pair(
|
||||
_and,
|
||||
create_ast_node_pair(
|
||||
cond1,
|
||||
create_ast_node_pair(
|
||||
cond2,
|
||||
create_ast_node_pair(
|
||||
cond3,
|
||||
nil))));
|
||||
Ast_Node* result;
|
||||
|
||||
// a true case
|
||||
result = eval_expr(form, create_empty_environment());
|
||||
char exp_string1[] = "(and 1 \"asd\" 4)";
|
||||
Ast_Node* expression = parse_single_expression(exp_string1);
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment());
|
||||
|
||||
assert_no_error(error);
|
||||
assert_not_null(result);
|
||||
@@ -233,8 +278,9 @@ testresult test_built_in_and() {
|
||||
assert_equal_double(result->value.number->value, 1);
|
||||
|
||||
// a false case
|
||||
cond1->value.number->value = 0;
|
||||
result = eval_expr(form, create_empty_environment());
|
||||
char exp_string2[] = "(and () \"asd\" 4)";
|
||||
expression = parse_single_expression(exp_string2);
|
||||
result = eval_expr(expression, create_empty_environment());
|
||||
|
||||
assert_no_error(error);
|
||||
assert_not_null(result);
|
||||
@@ -244,20 +290,9 @@ testresult test_built_in_and() {
|
||||
}
|
||||
|
||||
testresult test_built_in_or() {
|
||||
Ast_Node* _or = create_ast_node_symbol("or");
|
||||
Ast_Node* cond1 = create_ast_node_nil();
|
||||
Ast_Node* cond2 = create_ast_node_string("asd");
|
||||
Ast_Node* nil = create_ast_node_nil();
|
||||
Ast_Node* form = create_ast_node_pair(
|
||||
_or,
|
||||
create_ast_node_pair(
|
||||
cond1,
|
||||
create_ast_node_pair(
|
||||
cond2, nil)));
|
||||
Ast_Node* result;
|
||||
|
||||
// a true case
|
||||
result = eval_expr(form, create_empty_environment());
|
||||
char exp_string1[] = "(or \"asd\" nil)";
|
||||
Ast_Node* expression = parse_single_expression(exp_string1);
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment());
|
||||
|
||||
assert_no_error(error);
|
||||
assert_not_null(result);
|
||||
@@ -265,14 +300,9 @@ testresult test_built_in_or() {
|
||||
assert_equal_double(result->value.number->value, 1);
|
||||
|
||||
// a false case
|
||||
cond2 = create_ast_node_nil();
|
||||
form = create_ast_node_pair(
|
||||
_or,
|
||||
create_ast_node_pair(
|
||||
cond1,
|
||||
create_ast_node_pair(
|
||||
cond2, nil)));
|
||||
result = eval_expr(form, create_empty_environment());
|
||||
char exp_string2[] = "(or () ())";
|
||||
expression = parse_single_expression(exp_string2);
|
||||
result = eval_expr(expression, create_empty_environment());
|
||||
|
||||
assert_no_error(error);
|
||||
assert_not_null(result);
|
||||
@@ -282,9 +312,37 @@ testresult test_built_in_or() {
|
||||
}
|
||||
|
||||
|
||||
testresult test_built_in_not() {
|
||||
char exp_string1[] = "(not ())";
|
||||
Ast_Node* expression = parse_single_expression(exp_string1);
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment());
|
||||
|
||||
// a true case
|
||||
assert_no_error(error);
|
||||
assert_not_null(result);
|
||||
assert_equal_int(result->type, Ast_Node_Type_Number);
|
||||
assert_equal_double(result->value.number->value, 1);
|
||||
|
||||
// a false case
|
||||
char exp_string2[] = "(not \"asd xD\")";
|
||||
expression = parse_single_expression(exp_string2);
|
||||
result = eval_expr(expression, create_empty_environment());
|
||||
|
||||
assert_no_error(error);
|
||||
assert_not_null(result);
|
||||
assert_equal_int(result->type, Ast_Node_Type_Nil);
|
||||
|
||||
return pass;
|
||||
}
|
||||
|
||||
void run_all_tests() {
|
||||
log_level = Log_Level_None;
|
||||
|
||||
printf("-- Parsing --\n");
|
||||
invoke_test(test_parse_atom);
|
||||
invoke_test(test_parse_expression);
|
||||
|
||||
printf("\n-- Built ins --\n");
|
||||
invoke_test(test_built_in_add);
|
||||
invoke_test(test_built_in_substract);
|
||||
invoke_test(test_built_in_multiply);
|
||||
@@ -292,5 +350,7 @@ void run_all_tests() {
|
||||
invoke_test(test_built_in_if);
|
||||
invoke_test(test_built_in_and);
|
||||
invoke_test(test_built_in_or);
|
||||
invoke_test(test_built_in_not);
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user