Browse Source

built-ins are identified by an enum now

master
FelixBrendel 7 years ago
parent
commit
46f76fc3d9
9 changed files with 374 additions and 282 deletions
  1. +2
    -2
      .dir-locals.el
  2. +103
    -3
      src/ast.c
  3. +2
    -3
      src/built_ins.c
  4. +4
    -30
      src/env.c
  5. +2
    -0
      src/error.c
  6. +254
    -242
      src/eval.c
  7. +1
    -1
      src/io.c
  8. +2
    -1
      src/testing.c
  9. +4
    -0
      todo.org

+ 2
- 2
.dir-locals.el View File

@@ -32,5 +32,5 @@
("d" save-and-find-debug-script-and-compile "debug" :color blue)
("t" save-and-find-test-script-and-compile "test" :color blue)
("q" nil "quit" :color blue))
(define-key context-mode-map (kbd "<f2>") 'hydra-context/body)
)))))
(define-key context-mode-map (kbd "<f2>") 'hydra-context/body))))))

+ 103
- 3
src/ast.c View File

@@ -46,8 +46,77 @@ typedef struct {
char* docstring;
} Function;

typedef enum {
Built_In_Addition,
Built_In_Subtraction,
Built_In_Multiplication,
Built_In_Division,
Built_In_Greater,
Built_In_Less,
Built_In_Equal,
Built_In_Greater_Equal,
Built_In_Less_Equal,
Built_In_If,
Built_In_And,
Built_In_Or,
Built_In_Not,
Built_In_Pair,
Built_In_First,
Built_In_Rest,
Built_In_Load,
Built_In_Define,
Built_In_Lambda,
Built_In_Eval,
Built_In_Quote,
Built_In_Prog,
Built_In_List,
Built_In_Print,
Built_In_Read,
Built_In_Info,
Built_In_Type,
Built_In_Exit,
} Built_In_Name;

/**
This is used only for printing.
**/
char* Built_In_Name_to_string(Built_In_Name name) {
switch (name) {
case Built_In_Addition: return "+";
case Built_In_And: return "and";
case Built_In_Define: return "define";
case Built_In_Division: return "/";
case Built_In_Equal: return "=";
case Built_In_Eval: return "eval";
case Built_In_Exit: return "exit";
case Built_In_First: return "first";
case Built_In_Greater: return ">";
case Built_In_Greater_Equal: return ">=";
case Built_In_If: return "if";
case Built_In_Info: return "info";
case Built_In_Lambda: return "lambda";
case Built_In_Less: return "<";
case Built_In_Less_Equal: return "<=";
case Built_In_List: return "list";
case Built_In_Load: return "load";
case Built_In_Multiplication: return "*";
case Built_In_Not: return "not";
case Built_In_Or: return "or";
case Built_In_Pair: return "pair";
case Built_In_Print: return "print";
case Built_In_Prog: return "prog";
case Built_In_Quote: return "quote";
case Built_In_Read: return "read";
case Built_In_Rest: return "rest";
case Built_In_Subtraction: return "-";
case Built_In_Type: return "type";
}

return "Built in string missing in Built_In_Name_to_string";
}

typedef struct {
char* identifier;
Built_In_Name type;
} Built_In_Function;

struct Ast_Node {
@@ -106,11 +175,42 @@ Ast_Node* create_ast_node_keyword(char* keyword) {
return node;
}

Ast_Node* create_ast_node_built_in_function(char* identifier) {
Ast_Node* create_ast_node_built_in_function(char* name) {
Built_In_Name type;
if (string_equal(name, "+")) type = Built_In_Addition;
else if (string_equal(name, "-")) type = Built_In_Subtraction;
else if (string_equal(name, "*")) type = Built_In_Multiplication;
else if (string_equal(name, "/")) type = Built_In_Division;
else if (string_equal(name, "=")) type = Built_In_Equal;
else if (string_equal(name, ">")) type = Built_In_Greater;
else if (string_equal(name, ">=")) type = Built_In_Greater_Equal;
else if (string_equal(name, "<")) type = Built_In_Less;
else if (string_equal(name, "<=")) type = Built_In_Less_Equal;
else if (string_equal(name, "if")) type = Built_In_If;
else if (string_equal(name, "and")) type = Built_In_And;
else if (string_equal(name, "or")) type = Built_In_Or;
else if (string_equal(name, "not")) type = Built_In_Not;
else if (string_equal(name, "pair")) type = Built_In_Pair;
else if (string_equal(name, "first")) type = Built_In_First;
else if (string_equal(name, "rest")) type = Built_In_Rest;
else if (string_equal(name, "load")) type = Built_In_Load;
else if (string_equal(name, "define")) type = Built_In_Define;
else if (string_equal(name, "lambda")) type = Built_In_Lambda;
else if (string_equal(name, "eval")) type = Built_In_Eval;
else if (string_equal(name, "quote")) type = Built_In_Quote;
else if (string_equal(name, "prog")) type = Built_In_Prog;
else if (string_equal(name, "list")) type = Built_In_List;
else if (string_equal(name, "print")) type = Built_In_Print;
else if (string_equal(name, "read")) type = Built_In_Read;
else if (string_equal(name, "info")) type = Built_In_Info;
else if (string_equal(name, "type")) type = Built_In_Type;
else if (string_equal(name, "exit")) type = Built_In_Exit;
else return nullptr;

Ast_Node* node = new(Ast_Node);
node->type = Ast_Node_Type_Built_In_Function;
node->value.built_in_function = new(Built_In_Function);
node->value.built_in_function->identifier = identifier;
node->value.built_in_function->type = type;
return node;
}



+ 2
- 3
src/built_ins.c View File

@@ -6,9 +6,8 @@ bool ast_node_equal(Ast_Node* n1, Ast_Node* n2) {

switch (n1->type) {
case Ast_Node_Type_Built_In_Function:
return string_equal(
n1->value.built_in_function->identifier,
n2->value.built_in_function->identifier);
return n1->value.built_in_function->type
== n2->value.built_in_function->type;
case Ast_Node_Type_Function:
// if they have the same pointer, true is
// returned a few lines above


+ 4
- 30
src/env.c View File

@@ -3,6 +3,7 @@ struct Environment {
struct Environment* parent;
int capacity;
int next_index;
// TODO(Felix): Use a hashmap here.
char** keys;
Ast_Node* values;
};
@@ -49,37 +50,10 @@ Ast_Node* lookup_symbol(Symbol* sym, Environment* env) {
if (env->parent)
return lookup_symbol(sym, env->parent);

char* built_in_names[] = {
// Math stuff
"+", "-", "*", "/",
">", "<", "=", "<=", ">=",
// Conditional stuff
"if", "and", "or", "not",
// Cons stuff
"pair", "first", "rest",
// rest
"load", "define",
"lambda", "progn",
"eval", "quote", "prog", "list",
"print", "read",
"info", "type", "exit"
};
int built_in_count = sizeof(built_in_names) / sizeof(char*);

for (int i = 0; i < built_in_count; ++i) {
if (string_equal(built_in_names[i], sym->identifier)) {
Ast_Node* ret = new(Ast_Node);
ret->type = Ast_Node_Type_Built_In_Function;
ret->value.built_in_function = new(Built_In_Function);
ret->value.built_in_function->identifier = built_in_names[i];
return ret;
}
}
Ast_Node* built_in = create_ast_node_built_in_function(sym->identifier);
if (built_in)
return built_in;

create_error(Error_Type_Symbol_Not_Defined, create_ast_node_nil());
/* char* message; */
/* asprintf(&message, "Symbol not defined: %s\n", sym->identifier); */
/* panic(message); */

return nullptr;
}

+ 2
- 0
src/error.c View File

@@ -1,5 +1,6 @@
typedef enum {
Error_Type_Ill_Formed_List,
Error_Type_Ill_Formed_Arguments,
Error_Type_Wrong_Number_Of_Arguments,
Error_Type_Type_Missmatch,
Error_Type_Symbol_Not_Defined,
@@ -37,6 +38,7 @@ void create_error(Error_Type type, Ast_Node* location) {
char* Error_Type_to_string(Error_Type type) {
switch (type) {
case Error_Type_Ill_Formed_List: return "Evaluation-error: Ill formed list";
case Error_Type_Ill_Formed_Arguments: return "Evaluation-error: Ill formed arguments";
case Error_Type_Not_A_Function: return "Evaluation-error: Not a function";
case Error_Type_Symbol_Not_Defined: return "Evaluation-error: Symbol not defined";
case Error_Type_Wrong_Number_Of_Arguments: return "Evaluation-error: Wrong number of arguments";


+ 254
- 242
src/eval.c View File

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


+ 1
- 1
src/io.c View File

@@ -71,7 +71,7 @@ void print(Ast_Node* node) {
printf("[lambda]");
} break;
case (Ast_Node_Type_Built_In_Function): {
printf("[built-in-function %s]", node->value.built_in_function->identifier);
printf("[built-in-function %s]", Built_In_Name_to_string(node->value.built_in_function->type));
} break;
case (Ast_Node_Type_Pair): {
Ast_Node* head = node;


+ 2
- 1
src/testing.c View File

@@ -82,7 +82,8 @@
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());
int operands_length;
operands = eval_arguments(operands, create_empty_environment(), &operands_length);

assert_no_error(error);
assert_equal_int(list_length(operands), 4);


+ 4
- 0
todo.org View File

@@ -1,4 +1,8 @@
* TODO =assert_equal_type= macro in testing
* DONE use an enum for builtin identifiers
CLOSED: [2018-10-11 Do 17:15]
* TODO dont create new nils or builtins, but store one of each globally
* TODO source code locations for errors
* Build-in forms

** DONE +


Loading…
Cancel
Save