aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOskari Timperi <oskari.timperi@iki.fi>2014-05-17 13:01:26 +0300
committerOskari Timperi <oskari.timperi@iki.fi>2014-05-17 13:01:26 +0300
commit50fb851ec2afac36e859db36aca04c471a9f8bc4 (patch)
tree3457f5c05fa418e22e6e7866e95b3a776fa7ba08
parent2836fa60045bcdd8c1c8c5ed775d711cc7f385a9 (diff)
downloadlispish-50fb851ec2afac36e859db36aca04c471a9f8bc4.tar.gz
lispish-50fb851ec2afac36e859db36aca04c471a9f8bc4.zip
move builtin functions to their own functions out of eval()
-rw-r--r--eval.c306
1 files changed, 181 insertions, 125 deletions
diff --git a/eval.c b/eval.c
index f48937f..98c3132 100644
--- a/eval.c
+++ b/eval.c
@@ -71,185 +71,241 @@ static int atom_cmp(struct atom *a, struct atom *b)
return result;
}
-struct atom *eval(struct atom *expr, struct env *env)
+struct atom *builtin_quote(struct atom *expr, struct env *env)
{
- if (IS_SYM(expr))
- {
- struct atom *atom = env_lookup(env, expr->str.str);
+ struct list *list = expr->list;
+ struct atom *op = LIST_FIRST(list);
+ return atom_clone(LIST_NEXT(op, entries));
+}
- if (atom)
- {
- return atom;
- }
- else
- {
- printf("error: undefined variable: %s\n",
- expr->str.str);
- return &nil_atom;
- }
- }
+struct atom *builtin_atom(struct atom *expr, struct env *env)
+{
+ struct list *list = expr->list;
+ struct atom *op = LIST_FIRST(list);
+ struct atom *a = LIST_NEXT(op, entries);
- if (!IS_LIST(expr))
- return expr;
+ if (!a)
+ return &nil_atom;
- struct list *list = expr->list;
+ if (IS_LIST(a))
+ return &false_atom;
+ else
+ return &true_atom;
+}
+struct atom *builtin_eq(struct atom *expr, struct env *env)
+{
+ struct list *list = expr->list;
struct atom *op = LIST_FIRST(list);
+ struct atom *a = CDR(op);
+ struct atom *b = CDR(a);
- if (strcmp(op->str.str, "quote") == 0)
+ if (!a || !b)
{
- return atom_clone(LIST_NEXT(op, entries));
+ printf("error: eq takes 2 arguments\n");
+ return &nil_atom;
}
- else if (strcmp(op->str.str, "atom") == 0)
- {
- struct atom *a = LIST_NEXT(op, entries);
- if (!a)
- return &nil_atom;
+ a = eval(a, env);
+ b = eval(b, env);
- if (IS_LIST(a))
- return &false_atom;
- else
- return &true_atom;
+ if (atom_cmp(a, b))
+ return &true_atom;
+
+ return &false_atom;
+}
+
+struct atom *builtin_basic_arithmetic(struct atom *expr, struct env *env)
+{
+ struct list *list = expr->list;
+ struct atom *op = LIST_FIRST(list);
+ struct atom *a = CDR(op);
+ struct atom *b = CDR(a);
+
+ if (!a || !b)
+ {
+ printf("error: %s takes 2 arguments\n", op->str.str);
+ return &nil_atom;
}
- else if (strcmp(op->str.str, "eq") == 0)
+
+ a = eval(a, env);
+ b = eval(b, env);
+
+ if (!(ATOM_TYPE(a) == ATOM_TYPE(b) && ATOM_TYPE(a) == ATOM_INT))
{
- struct atom *a = CDR(op);
- struct atom *b = CDR(a);
+ printf("error: %s works only for integers at the moment\n",
+ op->str.str);
+ return &nil_atom;
+ }
- if (!a || !b)
- {
- printf("error: eq takes 2 arguments\n");
- return &nil_atom;
- }
+ switch (*op->str.str)
+ {
+ case '+': return atom_new_int(a->l + b->l);
+ case '-': return atom_new_int(a->l - b->l);
+ case '/': return atom_new_int(a->l / b->l);
+ case '*': return atom_new_int(a->l * b->l);
+ }
- a = eval(a, env);
- b = eval(b, env);
+ return &nil_atom;
+}
- if (atom_cmp(a, b))
- return &true_atom;
+struct atom *builtin_gt(struct atom *expr, struct env *env)
+{
+ struct list *list = expr->list;
+ struct atom *op = LIST_FIRST(list);
+ struct atom *a = CDR(op);
+ struct atom *b = CDR(a);
- return &false_atom;
- }
- else if (strcmp(op->str.str, "+") == 0 ||
- strcmp(op->str.str, "-") == 0 ||
- strcmp(op->str.str, "/") == 0 ||
- strcmp(op->str.str, "*") == 0)
+ if (!a || !b)
{
- struct atom *a = CDR(op);
- struct atom *b = CDR(a);
+ printf("error: > takes 2 arguments\n");
+ return &nil_atom;
+ }
- if (!a || !b)
- {
- printf("error: %s takes 2 arguments\n", op->str.str);
- return &nil_atom;
- }
+ a = eval(a, env);
+ b = eval(b, env);
- a = eval(a, env);
- b = eval(b, env);
+ if (!(ATOM_TYPE(a) == ATOM_TYPE(b) && ATOM_TYPE(a) == ATOM_INT))
+ return &nil_atom;
- if (!(ATOM_TYPE(a) == ATOM_TYPE(b) && ATOM_TYPE(a) == ATOM_INT))
- return &nil_atom;
+ if (a->l > b->l)
+ return &true_atom;
- switch (*op->str.str)
- {
- case '+': return atom_new_int(a->l + b->l);
- case '-': return atom_new_int(a->l - b->l);
- case '/': return atom_new_int(a->l / b->l);
- case '*': return atom_new_int(a->l * b->l);
- }
+ return &false_atom;
+}
+
+struct atom *builtin_if(struct atom *expr, struct env *env)
+{
+ struct list *list = expr->list;
+ struct atom *op = LIST_FIRST(list);
+ struct atom *predicate = CDR(op);
+ struct atom *true_case = CDR(predicate);
+ struct atom *false_case = CDR(true_case);
+ if (!predicate || !true_case || !false_case)
+ {
+ printf("error: if takes 3 arguments\n");
return &nil_atom;
}
- else if (strcmp(op->str.str, ">") == 0)
- {
- struct atom *a = CDR(op);
- struct atom *b = CDR(a);
- if (!a || !b)
- {
- printf("error: > takes 2 arguments\n");
- return &nil_atom;
- }
+ predicate = eval(predicate, env);
- a = eval(a, env);
- b = eval(b, env);
+ if (IS_TRUE(predicate))
+ return eval(true_case, env);
- if (!(ATOM_TYPE(a) == ATOM_TYPE(b) && ATOM_TYPE(a) == ATOM_INT))
- return &nil_atom;
+ return eval(false_case, env);
+}
- if (a->l > b->l)
- return &true_atom;
+struct atom *builtin_mod(struct atom *expr, struct env *env)
+{
+ struct list *list = expr->list;
+ struct atom *op = LIST_FIRST(list);
+ struct atom *a = CDR(op);
+ struct atom *b = CDR(a);
- return &false_atom;
+ if (!a || !b)
+ {
+ printf("error: mod takes two arguments\n");
+ return &nil_atom;
}
- else if (strcmp(op->str.str, "if") == 0)
+
+ a = eval(a, env);
+ b = eval(b, env);
+
+ if (!IS_INT(a) || !IS_INT(b))
{
- struct atom *predicate = CDR(op);
- struct atom *true_case = CDR(predicate);
- struct atom *false_case = CDR(true_case);
+ printf("error: mod arguments must be integers\n");
+ return &nil_atom;
+ }
- if (!predicate || !true_case || !false_case)
- {
- printf("error: if takes 3 arguments\n");
- return &nil_atom;
- }
+ return atom_new_int(a->l % b->l);
+}
- predicate = eval(predicate, env);
+struct atom *builtin_define(struct atom *expr, struct env *env)
+{
+ struct list *list = expr->list;
+ struct atom *op = LIST_FIRST(list);
+ struct atom *expr_name = CDR(op);
+ struct atom *expr_value = CDR(expr_name);
- if (IS_TRUE(predicate))
- return eval(true_case, env);
+ if (!expr_name || !expr_value)
+ {
+ printf("error: define takes two arguments\n");
+ return &nil_atom;
+ }
- return eval(false_case, env);
+ if (!IS_SYM(expr_name))
+ {
+ printf("error: define: first arg must be symbol\n");
+ return &nil_atom;
}
- else if (strcmp(op->str.str, "mod") == 0)
+
+ expr_value = eval(expr_value, env);
+
+ if (!env_set(env, expr_name->str.str, expr_value))
{
- struct atom *a = CDR(op);
- struct atom *b = CDR(a);
+ printf("error: cannot redefine %s\n", expr_name->str.str);
+ return &nil_atom;
+ }
- if (!a || !b)
- {
- printf("error: mod takes two arguments\n");
- return &nil_atom;
- }
+ return expr_value;
+}
- a = eval(a, env);
- b = eval(b, env);
+typedef struct atom *(*builtin_function_t)(struct atom *, struct env *);
- if (!IS_INT(a) || !IS_INT(b))
- {
- printf("error: mod arguments must be integers\n");
- return &nil_atom;
- }
+static struct builtin_function_def
+{
+ const char *name;
+ builtin_function_t fn;
+} builtin_function_defs[] = {
+ { "quote", &builtin_quote },
+ { "atom", &builtin_atom },
+ { "eq", &builtin_eq },
+ { "+", &builtin_basic_arithmetic },
+ { "-", &builtin_basic_arithmetic },
+ { "/", &builtin_basic_arithmetic },
+ { "*", &builtin_basic_arithmetic },
+ { ">", &builtin_gt },
+ { "if", &builtin_if },
+ { "mod", &builtin_mod },
+ { "define", &builtin_define },
+
+ { NULL, NULL }
+};
- return atom_new_int(a->l % b->l);
- }
- else if (strcmp(op->str.str, "define") == 0)
+struct atom *eval(struct atom *expr, struct env *env)
+{
+ if (IS_SYM(expr))
{
- struct atom *expr_name = CDR(op);
- struct atom *expr_value = CDR(expr_name);
+ struct atom *atom = env_lookup(env, expr->str.str);
- if (!expr_name || !expr_value)
+ if (atom)
{
- printf("error: define takes two arguments\n");
- return &nil_atom;
+ return atom;
}
-
- if (!IS_SYM(expr_name))
+ else
{
- printf("error: define: first arg must be symbol\n");
+ printf("error: undefined variable: %s\n",
+ expr->str.str);
return &nil_atom;
}
+ }
+
+ if (!IS_LIST(expr))
+ return expr;
- expr_value = eval(expr_value, env);
+ struct list *list = expr->list;
+ struct atom *op = LIST_FIRST(list);
- if (!env_set(env, expr_name->str.str, expr_value))
+ struct builtin_function_def *def = builtin_function_defs;
+ while (def->name && def->fn)
+ {
+ if (strcmp(op->str.str, def->name) == 0)
{
- printf("error: cannot redefine %s\n", expr_name->str.str);
- return &nil_atom;
+ return def->fn(expr, env);
}
- return expr_value;
+ ++def;
}
printf("error: unknown function %s\n", op->str.str);