diff options
| author | Oskari Timperi <oskari.timperi@iki.fi> | 2014-05-17 13:01:26 +0300 |
|---|---|---|
| committer | Oskari Timperi <oskari.timperi@iki.fi> | 2014-05-17 13:01:26 +0300 |
| commit | 50fb851ec2afac36e859db36aca04c471a9f8bc4 (patch) | |
| tree | 3457f5c05fa418e22e6e7866e95b3a776fa7ba08 | |
| parent | 2836fa60045bcdd8c1c8c5ed775d711cc7f385a9 (diff) | |
| download | lispish-50fb851ec2afac36e859db36aca04c471a9f8bc4.tar.gz lispish-50fb851ec2afac36e859db36aca04c471a9f8bc4.zip | |
move builtin functions to their own functions out of eval()
| -rw-r--r-- | eval.c | 306 |
1 files changed, 181 insertions, 125 deletions
@@ -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); |
