Macros actually working
This commit is contained in:
@@ -125,6 +125,9 @@ typedef enum {
|
||||
Built_In_Rest,
|
||||
Built_In_Load,
|
||||
Built_In_Define,
|
||||
Built_In_Let,
|
||||
Built_In_Macro_Define,
|
||||
Built_In_Breakpoint,
|
||||
Built_In_Mutate,
|
||||
Built_In_Lambda,
|
||||
Built_In_Macro,
|
||||
@@ -147,6 +150,8 @@ char* Built_In_Name_to_string(Built_In_Name name) {
|
||||
case Built_In_Addition: return "+";
|
||||
case Built_In_And: return "and";
|
||||
case Built_In_Define: return "define";
|
||||
case Built_In_Macro_Define: return "macro-define";
|
||||
case Built_In_Breakpoint: return "breakpoint";
|
||||
case Built_In_Division: return "/";
|
||||
case Built_In_Equal: return "=";
|
||||
case Built_In_Eval: return "eval";
|
||||
@@ -157,6 +162,7 @@ char* Built_In_Name_to_string(Built_In_Name name) {
|
||||
case Built_In_If: return "if";
|
||||
case Built_In_Info: return "info";
|
||||
case Built_In_Lambda: return "lambda";
|
||||
case Built_In_Let: return "let";
|
||||
case Built_In_Less: return "<";
|
||||
case Built_In_Less_Equal: return "<=";
|
||||
case Built_In_List: return "list";
|
||||
@@ -248,36 +254,39 @@ Ast_Node* create_ast_node_keyword(char* keyword) {
|
||||
|
||||
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, "mutate")) type = Built_In_Mutate;
|
||||
else if (string_equal(name, "lambda")) type = Built_In_Lambda;
|
||||
else if (string_equal(name, "macro")) type = Built_In_Macro;
|
||||
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;
|
||||
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, "let")) type = Built_In_Let;
|
||||
else if (string_equal(name, "define")) type = Built_In_Define;
|
||||
else if (string_equal(name, "macro-define")) type = Built_In_Macro_Define;
|
||||
else if (string_equal(name, "breakpoint")) type = Built_In_Breakpoint;
|
||||
else if (string_equal(name, "mutate")) type = Built_In_Mutate;
|
||||
else if (string_equal(name, "lambda")) type = Built_In_Lambda;
|
||||
else if (string_equal(name, "macro")) type = Built_In_Macro;
|
||||
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);
|
||||
|
||||
@@ -56,6 +56,78 @@ Ast_Node* built_in_equals(Ast_Node* operands) {
|
||||
return create_ast_node_number(1);
|
||||
}
|
||||
|
||||
Ast_Node* built_in_greater(Ast_Node* operands) {
|
||||
double last_number = strtod("Inf", NULL);
|
||||
|
||||
while (operands->type == Ast_Node_Type_Pair) {
|
||||
try {
|
||||
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
|
||||
}
|
||||
|
||||
if (operands->value.pair->first->value.number->value >= last_number)
|
||||
return create_ast_node_nil();
|
||||
|
||||
last_number = operands->value.pair->first->value.number->value;
|
||||
operands = operands->value.pair->rest;
|
||||
}
|
||||
|
||||
return create_ast_node_number(1);
|
||||
}
|
||||
|
||||
Ast_Node* built_in_greater_equal(Ast_Node* operands) {
|
||||
double last_number = strtod("Inf", NULL);
|
||||
|
||||
while (operands->type == Ast_Node_Type_Pair) {
|
||||
try {
|
||||
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
|
||||
}
|
||||
|
||||
if (operands->value.pair->first->value.number->value > last_number)
|
||||
return create_ast_node_nil();
|
||||
|
||||
last_number = operands->value.pair->first->value.number->value;
|
||||
operands = operands->value.pair->rest;
|
||||
}
|
||||
|
||||
return create_ast_node_number(1);
|
||||
}
|
||||
|
||||
Ast_Node* built_in_less(Ast_Node* operands) {
|
||||
double last_number = strtod("-Inf", NULL);
|
||||
|
||||
while (operands->type == Ast_Node_Type_Pair) {
|
||||
try {
|
||||
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
|
||||
}
|
||||
|
||||
if (operands->value.pair->first->value.number->value <= last_number)
|
||||
return create_ast_node_nil();
|
||||
|
||||
last_number = operands->value.pair->first->value.number->value;
|
||||
operands = operands->value.pair->rest;
|
||||
}
|
||||
|
||||
return create_ast_node_number(1);
|
||||
}
|
||||
|
||||
Ast_Node* built_in_less_equal(Ast_Node* operands) {
|
||||
double last_number = strtod("-Inf", NULL);
|
||||
|
||||
while (operands->type == Ast_Node_Type_Pair) {
|
||||
try {
|
||||
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
|
||||
}
|
||||
|
||||
if (operands->value.pair->first->value.number->value < last_number)
|
||||
return create_ast_node_nil();
|
||||
|
||||
last_number = operands->value.pair->first->value.number->value;
|
||||
operands = operands->value.pair->rest;
|
||||
}
|
||||
|
||||
return create_ast_node_number(1);
|
||||
}
|
||||
|
||||
Ast_Node* built_in_add(Ast_Node* operands) {
|
||||
double sum = 0;
|
||||
while (operands->type == Ast_Node_Type_Pair) {
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
typedef enum {
|
||||
Environment_Type_Let,
|
||||
Environment_Type_Lambda,
|
||||
Environment_Type_Macro,
|
||||
} Environment_Type;
|
||||
|
||||
struct Environment {
|
||||
struct Environment* parent;
|
||||
Environment_Type type;
|
||||
|
||||
int capacity;
|
||||
int next_index;
|
||||
// TODO(Felix): Use a hashmap here.
|
||||
@@ -10,12 +17,12 @@ struct Environment {
|
||||
|
||||
typedef struct Environment Environment;
|
||||
|
||||
|
||||
Environment* create_child_environment(Environment* parent) {
|
||||
Environment* create_child_environment(Environment* parent, Environment_Type type) {
|
||||
Environment* env = new(Environment);
|
||||
|
||||
int start_capacity = 16;
|
||||
|
||||
env->type = type;
|
||||
env->parent = parent;
|
||||
env->capacity = start_capacity;
|
||||
env->next_index = 0;
|
||||
@@ -25,11 +32,20 @@ Environment* create_child_environment(Environment* parent) {
|
||||
return env;
|
||||
}
|
||||
|
||||
Environment* create_empty_environment() {
|
||||
return create_child_environment(nullptr);
|
||||
Environment* create_empty_environment(Environment_Type type) {
|
||||
return create_child_environment(nullptr, type);
|
||||
}
|
||||
|
||||
void define_symbol(Ast_Node* symbol, Ast_Node* value, Environment* env) {
|
||||
if (env->type == Environment_Type_Macro) {
|
||||
// NOTE(Felix): we know we have a parent because every
|
||||
// environment has a parent except the top level environment.
|
||||
// However the top level environment is not a let-environment,
|
||||
// so we would not land here
|
||||
define_symbol(symbol, value, env->parent);
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE(Felix): right now we are simply adding the symol at the
|
||||
// back of the list without checking if it already exists but are
|
||||
// also searching for thesymbol from the back, so we will find the
|
||||
@@ -47,19 +63,116 @@ void define_symbol(Ast_Node* symbol, Ast_Node* value, Environment* env) {
|
||||
++env->next_index;
|
||||
}
|
||||
|
||||
Ast_Node* lookup_symbol(Symbol* sym, Environment* env) {
|
||||
void define_macro_symbol(Ast_Node* symbol, Ast_Node* value, Environment* env) {
|
||||
if (!env->type == Environment_Type_Macro) {
|
||||
create_error(Error_Type_Unknown_Error, symbol);
|
||||
return;
|
||||
}
|
||||
|
||||
env->type = Environment_Type_Lambda;
|
||||
define_symbol(symbol, value, env);
|
||||
env->type = Environment_Type_Macro;
|
||||
}
|
||||
|
||||
void print_environment(Environment* env);
|
||||
|
||||
Ast_Node* lookup_symbol_in_this_envt(Symbol* sym, Environment* env) {
|
||||
for (int i = env->next_index - 1; i >= 0; --i)
|
||||
if (string_equal(env->keys[i], sym->identifier))
|
||||
return env->values[i];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (env->parent)
|
||||
return lookup_symbol(sym, env->parent);
|
||||
Ast_Node* lookup_symbol_from_lambda_env(Symbol* sym, Environment* env) {
|
||||
Ast_Node* result;
|
||||
do {
|
||||
if (env->type != Environment_Type_Lambda) {
|
||||
result = lookup_symbol_in_this_envt(sym, env);
|
||||
if (result) return result;
|
||||
}
|
||||
env = env->parent;
|
||||
} while (env);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Ast_Node* built_in = create_ast_node_built_in_function(sym->identifier);
|
||||
if (built_in)
|
||||
return built_in;
|
||||
Ast_Node* lookup_symbol_from_let_or_macro_env(Symbol* sym, Environment* env) {
|
||||
Ast_Node* result;
|
||||
do {
|
||||
result = lookup_symbol_in_this_envt(sym, env);
|
||||
if (result) return result;
|
||||
if (env->type == Environment_Type_Lambda)
|
||||
break;
|
||||
|
||||
env = env->parent;
|
||||
} while (env);
|
||||
|
||||
if (env) {
|
||||
do {
|
||||
if (env->type != Environment_Type_Lambda) {
|
||||
result = lookup_symbol_in_this_envt(sym, env);
|
||||
if (result) return result;
|
||||
}
|
||||
env = env->parent;
|
||||
} while (env);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Ast_Node* lookup_symbol(Symbol* sym, Environment* env) {
|
||||
// first check current environment
|
||||
Ast_Node* result;
|
||||
result = lookup_symbol_in_this_envt(sym, env);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
if (env->parent) {
|
||||
if (env->type == Environment_Type_Lambda) {
|
||||
result = lookup_symbol_from_lambda_env(sym, env->parent);
|
||||
} else {
|
||||
result = lookup_symbol_from_let_or_macro_env(sym, env->parent);
|
||||
}
|
||||
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
|
||||
result = create_ast_node_built_in_function(sym->identifier);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
create_error(Error_Type_Symbol_Not_Defined, create_ast_node_nil());
|
||||
printf("%s\n", sym->identifier);
|
||||
return nullptr;
|
||||
}
|
||||
void print_indent(int indent) {
|
||||
for (int i = 0; i < indent; ++i) {
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
|
||||
void print_environment_indent(Environment* env, int indent) {
|
||||
for (int i = 0; i < env->next_index; ++i) {
|
||||
print_indent(indent);
|
||||
printf("%s -> ", env->keys[i]);
|
||||
print(env->values[i]);
|
||||
printf("\n");
|
||||
}
|
||||
if (env->parent) {
|
||||
print_indent(indent);
|
||||
printf("parent");
|
||||
if (env->parent->type == Environment_Type_Lambda)
|
||||
printf(" (lambda)");
|
||||
else if (env->parent->type == Environment_Type_Macro)
|
||||
printf(" (macro)");
|
||||
else if (env->parent->type == Environment_Type_Let)
|
||||
printf(" (let)");
|
||||
printf(":\n");
|
||||
print_environment_indent(env->parent, indent+4);
|
||||
}
|
||||
}
|
||||
|
||||
void print_environment(Environment* env) {
|
||||
printf("\n=== Environment ===\n");
|
||||
print_environment_indent(env, 0);
|
||||
}
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ void delete_error() {
|
||||
|
||||
void create_error(Error_Type type, Ast_Node* location) {
|
||||
delete_error();
|
||||
|
||||
|
||||
error = new(Error);
|
||||
error->type = type;
|
||||
error->location = location;
|
||||
|
||||
+121
-7
@@ -1,7 +1,12 @@
|
||||
Ast_Node* eval_expr(Ast_Node* node, Environment* env);
|
||||
|
||||
Ast_Node* apply_arguments_to_function(Ast_Node* arguments, Function* function, Environment* parent) {
|
||||
Environment* new_env = create_child_environment(parent);
|
||||
// NOTE(Felix): if it is a macro, we will set it later, so we can
|
||||
// use the default "define_symbol" method here instead of
|
||||
// switching between "define_symbol" and "define_macro_symbol" all
|
||||
// the time
|
||||
|
||||
Environment* new_env = create_child_environment(parent, Environment_Type_Lambda);
|
||||
|
||||
// positional arguments
|
||||
for (int i = 0; i < function->positional_arguments->next_index; ++i) {
|
||||
@@ -137,10 +142,16 @@ Ast_Node* apply_arguments_to_function(Ast_Node* arguments, Function* function, E
|
||||
eval_time:
|
||||
Ast_Node* result;
|
||||
|
||||
// don't have to check every time if it is macro environment or
|
||||
// not
|
||||
if (function->is_macro)
|
||||
new_env->type = Environment_Type_Macro;
|
||||
|
||||
try {
|
||||
result = eval_expr(function->body, new_env);
|
||||
}
|
||||
|
||||
free(new_env);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -354,7 +365,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
||||
create_error(_type, node); \
|
||||
return nullptr; \
|
||||
}
|
||||
|
||||
|
||||
if (error)
|
||||
return nullptr;
|
||||
|
||||
@@ -392,6 +403,13 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
||||
// check for special form
|
||||
if (operator->type == Ast_Node_Type_Built_In_Function) {
|
||||
switch (operator->value.built_in_function->type) {
|
||||
case Built_In_Breakpoint: {
|
||||
print_environment(env);
|
||||
#ifdef _DEBUG
|
||||
__debugbreak();
|
||||
#endif
|
||||
return create_ast_node_nil();
|
||||
}
|
||||
case Built_In_Macro:
|
||||
case Built_In_Lambda: {
|
||||
/*
|
||||
@@ -420,6 +438,10 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
||||
try {
|
||||
parse_argument_list(arguments->value.pair->first, function);
|
||||
}
|
||||
} else {
|
||||
function->positional_arguments = create_positional_argument_list(1);
|
||||
function->keyword_arguments = create_keyword_argument_list(1);
|
||||
function->rest_argument = nullptr;
|
||||
}
|
||||
|
||||
arguments = arguments->value.pair->rest;
|
||||
@@ -440,6 +462,63 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
||||
ret->value.function = function;
|
||||
return ret;
|
||||
}
|
||||
case Built_In_Let: {
|
||||
// (let ((a 10)(b 20)) (body1) (body2))
|
||||
try {
|
||||
arguments_length = list_length(arguments);
|
||||
}
|
||||
if (arguments_length < 1)
|
||||
report_error(Error_Type_Wrong_Number_Of_Arguments);
|
||||
|
||||
Environment* let_env = create_child_environment(env, Environment_Type_Let);
|
||||
Ast_Node* bindings = arguments->value.pair->first;
|
||||
while (true) {
|
||||
if (bindings->type == Ast_Node_Type_Nil) {
|
||||
break;
|
||||
} else if (bindings->type != Ast_Node_Type_Pair) {
|
||||
report_error(Error_Type_Ill_Formed_Arguments);
|
||||
}
|
||||
|
||||
Ast_Node* sym = bindings->value.pair->first->value.pair->first;
|
||||
if(sym->type != Ast_Node_Type_Symbol) {
|
||||
report_error(Error_Type_Ill_Formed_Arguments);
|
||||
}
|
||||
Ast_Node* rest_sym = bindings->value.pair->first->value.pair->rest;
|
||||
if (rest_sym->type != Ast_Node_Type_Pair) {
|
||||
report_error(Error_Type_Ill_Formed_Arguments);
|
||||
}
|
||||
if (rest_sym->value.pair->rest->type != Ast_Node_Type_Nil) {
|
||||
report_error(Error_Type_Ill_Formed_Arguments);
|
||||
}
|
||||
|
||||
Ast_Node* value = rest_sym->value.pair->first;
|
||||
|
||||
define_symbol(sym, value, let_env);
|
||||
|
||||
bindings = bindings->value.pair->rest;
|
||||
}
|
||||
|
||||
arguments = arguments->value.pair->rest;
|
||||
|
||||
Ast_Node* evaluated_arguments;
|
||||
try {
|
||||
evaluated_arguments = eval_arguments(arguments, let_env, &arguments_length);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
return evaluated_arguments->value.pair->first;
|
||||
|
||||
}
|
||||
case Built_In_And: {
|
||||
bool result = true;
|
||||
while (arguments->type != Ast_Node_Type_Nil) {
|
||||
@@ -522,6 +601,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
||||
}
|
||||
return arguments->value.pair->first;
|
||||
}
|
||||
case Built_In_Macro_Define:
|
||||
case Built_In_Define: {
|
||||
try {
|
||||
arguments_length = list_length(arguments);
|
||||
@@ -531,15 +611,32 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
||||
}
|
||||
|
||||
Ast_Node* symbol = arguments->value.pair->first;
|
||||
if (symbol->type != Ast_Node_Type_Symbol)
|
||||
|
||||
if (symbol->type == Ast_Node_Type_Pair) {
|
||||
try {
|
||||
symbol = eval_expr(symbol, env);
|
||||
}
|
||||
}
|
||||
|
||||
if (symbol->type != Ast_Node_Type_Symbol) {
|
||||
report_error(Error_Type_Type_Missmatch);
|
||||
}
|
||||
|
||||
Ast_Node* value = arguments->value.pair->rest->value.pair->first;
|
||||
/* print(value); */
|
||||
try {
|
||||
value = eval_expr(value, env);
|
||||
}
|
||||
/* print(value); */
|
||||
|
||||
define_symbol(symbol, value, env);
|
||||
if (operator->value.built_in_function->type == Built_In_Macro_Define) {
|
||||
/* printf("Defining %s in the macro env to be ", symbol->value.symbol->identifier); */
|
||||
/* print(value); */
|
||||
|
||||
define_macro_symbol(symbol, value, env);
|
||||
}
|
||||
else
|
||||
define_symbol(symbol, value, env);
|
||||
|
||||
return value;
|
||||
}
|
||||
@@ -569,6 +666,18 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
||||
case Built_In_Equal: {
|
||||
return built_in_equals(evaluated_arguments);
|
||||
}
|
||||
case Built_In_Greater: {
|
||||
return built_in_greater(evaluated_arguments);
|
||||
}
|
||||
case Built_In_Greater_Equal: {
|
||||
return built_in_greater_equal(evaluated_arguments);
|
||||
}
|
||||
case Built_In_Less: {
|
||||
return built_in_less(evaluated_arguments);
|
||||
}
|
||||
case Built_In_Less_Equal: {
|
||||
return built_in_less_equal(evaluated_arguments);
|
||||
}
|
||||
case Built_In_Mutate: {
|
||||
if (arguments_length != 2)
|
||||
report_error(Error_Type_Wrong_Number_Of_Arguments);
|
||||
@@ -685,7 +794,11 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
||||
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_Function: {
|
||||
if (evaluated_arguments->value.pair->first->value.function->is_macro)
|
||||
return create_ast_node_keyword("dynamic-macro");
|
||||
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");
|
||||
@@ -715,8 +828,6 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
||||
|
||||
}
|
||||
|
||||
// assume it's lambda function and evaluate the arguments
|
||||
|
||||
if (operator->type == Ast_Node_Type_Function) {
|
||||
if (!operator->value.function->is_macro) {
|
||||
try {
|
||||
@@ -732,6 +843,9 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
||||
}
|
||||
}
|
||||
default: {
|
||||
#ifdef _DEBUG
|
||||
__debugbreak();
|
||||
#endif
|
||||
report_error(Error_Type_Not_A_Function);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -103,7 +103,8 @@ char* read_entire_file (char* filename) {
|
||||
|
||||
/* Read the entire file into memory. */
|
||||
size_t newLen = fread(fileContent, sizeof(char), bufsize, fp);
|
||||
/* fileContent[bufsize-5] = '\0'; */
|
||||
|
||||
fileContent[newLen] = '\0';
|
||||
if ( ferror( fp ) != 0 ) {
|
||||
fputs("Error reading file", stderr);
|
||||
}
|
||||
|
||||
@@ -68,8 +68,10 @@ void print(Ast_Node* node) {
|
||||
printf(":%s", node->value.keyword->identifier);
|
||||
} break;
|
||||
case (Ast_Node_Type_Function): {
|
||||
printf("[lambda]");
|
||||
/* print(node->value.function->body); */
|
||||
if (node->value.function->is_macro)
|
||||
printf("[macro]");
|
||||
else
|
||||
printf("[lambda]");
|
||||
} break;
|
||||
case (Ast_Node_Type_Built_In_Function): {
|
||||
printf("[built-in-function %s]", Built_In_Name_to_string(node->value.built_in_function->type));
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ int interprete_file (char* file_content) {
|
||||
log_error();
|
||||
return 1;
|
||||
}
|
||||
Environment* env = create_empty_environment();
|
||||
Environment* env = create_empty_environment(Environment_Type_Let);
|
||||
|
||||
built_in_load("pre.slime", env);
|
||||
if (error) {
|
||||
@@ -46,7 +46,7 @@ int interprete_file (char* file_content) {
|
||||
int interprete_stdin () {
|
||||
printf("Welcome to the lispy interpreter.\n");
|
||||
char* line;
|
||||
Environment* env = create_empty_environment();
|
||||
Environment* env = create_empty_environment(Environment_Type_Let);
|
||||
|
||||
built_in_load("pre.slime", env);
|
||||
if (error) {
|
||||
|
||||
+6
-2
@@ -27,6 +27,7 @@ void eat_comment_line(char* text, int* index_in_text) {
|
||||
do {
|
||||
++(*index_in_text);
|
||||
} while (text[(*index_in_text)] != '\n' &&
|
||||
text[(*index_in_text)] != '\r' &&
|
||||
text[(*index_in_text)] != '\0');
|
||||
}
|
||||
|
||||
@@ -34,7 +35,8 @@ 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') {
|
||||
text[(*index_in_text)] == '\n' ||
|
||||
text[(*index_in_text)] == '\r') {
|
||||
++(*index_in_text);
|
||||
}
|
||||
}
|
||||
@@ -55,6 +57,7 @@ char* read_atom(char* text, int* index_in_text) {
|
||||
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] != '\r' &&
|
||||
text[*index_in_text+atom_length] != '\t')
|
||||
{
|
||||
++atom_length;
|
||||
@@ -269,7 +272,8 @@ Ast_Node_Array_List* parse_program(char* text) {
|
||||
case ';':
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n': {
|
||||
case '\n':
|
||||
case '\r': {
|
||||
eat_until_code(text, &index_in_text);
|
||||
} break;
|
||||
default:
|
||||
|
||||
+13
-13
@@ -83,7 +83,7 @@ testresult test_eval_operands() {
|
||||
char operands_string[] = "((eval 1) (+ 1 2) \"okay\" (eval :haha))";
|
||||
Ast_Node* operands = parse_single_expression(operands_string);
|
||||
int operands_length;
|
||||
operands = eval_arguments(operands, create_empty_environment(), &operands_length);
|
||||
operands = eval_arguments(operands, create_empty_environment(Environment_Type_Let), &operands_length);
|
||||
|
||||
assert_no_error(error);
|
||||
assert_equal_int(list_length(operands), 4);
|
||||
@@ -227,7 +227,7 @@ testresult test_parse_expression() {
|
||||
testresult test_built_in_add() {
|
||||
char exp_string[] = "(+ 10 4)";
|
||||
Ast_Node* expression = parse_single_expression(exp_string);
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment());
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment(Environment_Type_Let));
|
||||
|
||||
assert_no_error(error);
|
||||
assert_not_null(result);
|
||||
@@ -240,7 +240,7 @@ testresult test_built_in_add() {
|
||||
testresult test_built_in_substract() {
|
||||
char exp_string[] = "(- 10 4)";
|
||||
Ast_Node* expression = parse_single_expression(exp_string);
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment());
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment(Environment_Type_Let));
|
||||
|
||||
assert_no_error(error);
|
||||
assert_not_null(result);
|
||||
@@ -254,7 +254,7 @@ testresult test_built_in_substract() {
|
||||
testresult test_built_in_multiply() {
|
||||
char exp_string[] = "(* 10 4)";
|
||||
Ast_Node* expression = parse_single_expression(exp_string);
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment());
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment(Environment_Type_Let));
|
||||
|
||||
assert_no_error(error);
|
||||
assert_not_null(result);
|
||||
@@ -268,7 +268,7 @@ testresult test_built_in_multiply() {
|
||||
testresult test_built_in_divide() {
|
||||
char exp_string[] = "(/ 20 4)";
|
||||
Ast_Node* expression = parse_single_expression(exp_string);
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment());
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment(Environment_Type_Let));
|
||||
|
||||
assert_null(error);
|
||||
assert_not_null(result);
|
||||
@@ -282,7 +282,7 @@ testresult test_built_in_divide() {
|
||||
testresult test_built_in_if() {
|
||||
char exp_string1[] = "(if 1 4 5)";
|
||||
Ast_Node* expression = parse_single_expression(exp_string1);
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment());
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment(Environment_Type_Let));
|
||||
|
||||
assert_no_error(error);
|
||||
assert_not_null(result);
|
||||
@@ -291,7 +291,7 @@ testresult test_built_in_if() {
|
||||
|
||||
char exp_string2[] = "(if () 4 5)";
|
||||
expression = parse_single_expression(exp_string2);
|
||||
result = eval_expr(expression, create_empty_environment());
|
||||
result = eval_expr(expression, create_empty_environment(Environment_Type_Let));
|
||||
|
||||
assert_no_error(error);
|
||||
assert_not_null(result);
|
||||
@@ -304,7 +304,7 @@ testresult test_built_in_if() {
|
||||
testresult test_built_in_and() {
|
||||
char exp_string1[] = "(and 1 \"asd\" 4)";
|
||||
Ast_Node* expression = parse_single_expression(exp_string1);
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment());
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment(Environment_Type_Let));
|
||||
|
||||
assert_no_error(error);
|
||||
assert_not_null(result);
|
||||
@@ -314,7 +314,7 @@ testresult test_built_in_and() {
|
||||
// a false case
|
||||
char exp_string2[] = "(and () \"asd\" 4)";
|
||||
expression = parse_single_expression(exp_string2);
|
||||
result = eval_expr(expression, create_empty_environment());
|
||||
result = eval_expr(expression, create_empty_environment(Environment_Type_Let));
|
||||
|
||||
assert_no_error(error);
|
||||
assert_not_null(result);
|
||||
@@ -326,7 +326,7 @@ testresult test_built_in_and() {
|
||||
testresult test_built_in_or() {
|
||||
char exp_string1[] = "(or \"asd\" nil)";
|
||||
Ast_Node* expression = parse_single_expression(exp_string1);
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment());
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment(Environment_Type_Let));
|
||||
|
||||
assert_no_error(error);
|
||||
assert_not_null(result);
|
||||
@@ -336,7 +336,7 @@ testresult test_built_in_or() {
|
||||
// a false case
|
||||
char exp_string2[] = "(or () ())";
|
||||
expression = parse_single_expression(exp_string2);
|
||||
result = eval_expr(expression, create_empty_environment());
|
||||
result = eval_expr(expression, create_empty_environment(Environment_Type_Let));
|
||||
|
||||
assert_no_error(error);
|
||||
assert_not_null(result);
|
||||
@@ -349,7 +349,7 @@ 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());
|
||||
Ast_Node* result = eval_expr(expression, create_empty_environment(Environment_Type_Let));
|
||||
|
||||
// a true case
|
||||
assert_no_error(error);
|
||||
@@ -360,7 +360,7 @@ testresult test_built_in_not() {
|
||||
// a false case
|
||||
char exp_string2[] = "(not \"asd xD\")";
|
||||
expression = parse_single_expression(exp_string2);
|
||||
result = eval_expr(expression, create_empty_environment());
|
||||
result = eval_expr(expression, create_empty_environment(Environment_Type_Let));
|
||||
|
||||
assert_no_error(error);
|
||||
assert_not_null(result);
|
||||
|
||||
Reference in New Issue
Block a user