X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fscript%2Finterpreter.c;h=07b716381aa14b5e43475a3ae30c2ca32a30e075;hb=c9ef07a849e2b0765e3163732ebf19efec9c04f7;hp=39aedc38722cc7efbbe7666d0921d750764aa798;hpb=6fb180d6c5911e8800178d07a7e865b2065b4abb;p=nothing.git diff --git a/src/script/interpreter.c b/src/script/interpreter.c index 39aedc38..07b71638 100644 --- a/src/script/interpreter.c +++ b/src/script/interpreter.c @@ -2,10 +2,259 @@ #include #include +#include "./builtins.h" +#include "./expr.h" #include "./interpreter.h" +#include "./scope.h" -struct Expr eval(struct Expr expr) +struct EvalResult eval_success(struct Expr expr) { - /* TODO(#311): eval(expr) is not implemented */ - return expr; + struct EvalResult result = { + .is_error = false, + .expr = expr, + }; + + return result; +} + +struct EvalResult eval_failure(struct Expr error) +{ + struct EvalResult result = { + .is_error = true, + .expr = error, + }; + + return result; +} + +static struct EvalResult length(Gc *gc, struct Expr obj) +{ + if (!list_p(obj)) { + return eval_failure(list(gc, 3, + SYMBOL(gc, "wrong-argument-type"), + SYMBOL(gc, "listp"), + obj)); + } + + return eval_success(NUMBER(gc, length_of_list(obj))); +} + +static struct EvalResult eval_atom(Gc *gc, struct Scope *scope, struct Atom *atom) +{ + (void) scope; + (void) gc; + + switch (atom->type) { + case ATOM_NUMBER: + case ATOM_STRING: + return eval_success(atom_as_expr(atom)); + + case ATOM_SYMBOL: { + if (nil_p(atom_as_expr(atom))) { + return eval_success(atom_as_expr(atom)); + } + + struct Expr value = get_scope_value(scope, atom_as_expr(atom)); + + if (nil_p(value)) { + return eval_failure(CONS(gc, + SYMBOL(gc, "void-variable"), + atom_as_expr(atom))); + } + + return eval_success(value.cons->cdr); + } + } + + return eval_failure(CONS(gc, + SYMBOL(gc, "unexpected-expression"), + atom_as_expr(atom))); +} + +static struct EvalResult eval_all_args(Gc *gc, struct Scope *scope, struct Expr args) +{ + (void) scope; + (void) args; + + switch(args.type) { + case EXPR_ATOM: + return eval_atom(gc, scope, args.atom); + + case EXPR_CONS: { + struct EvalResult car = eval(gc, scope, args.cons->car); + if (car.is_error) { + return car; + } + + struct EvalResult cdr = eval_all_args(gc, scope, args.cons->cdr); + if (cdr.is_error) { + return cdr; + } + + return eval_success(cons_as_expr(create_cons(gc, car.expr, cdr.expr))); + } + + default: {} + } + + return eval_failure(CONS(gc, + SYMBOL(gc, "unexpected-expression"), + args)); +} + +static struct EvalResult plus_op(Gc *gc, struct Expr args) +{ + long int result = 0.0f; + + while (!nil_p(args)) { + if (args.type != EXPR_CONS) { + return eval_failure(CONS(gc, + SYMBOL(gc, "expected-cons"), + args)); + } + + if (args.cons->car.type != EXPR_ATOM || + args.cons->car.atom->type != ATOM_NUMBER) { + return eval_failure(CONS(gc, + SYMBOL(gc, "expected-number"), + args.cons->car)); + } + + result += args.cons->car.atom->num; + args = args.cons->cdr; + } + + return eval_success(atom_as_expr(create_number_atom(gc, result))); +} + +static struct EvalResult call_callable(Gc *gc, + struct Scope *scope, + struct Expr callable, + struct Expr args) { + if (!callable_p(callable)) { + return eval_failure(CONS(gc, + SYMBOL(gc, "expected-callable"), + callable)); + } + + if (!list_p(args)) { + return eval_failure(CONS(gc, + SYMBOL(gc, "expected-list"), + args)); + } + + struct Expr vars = callable.cons->cdr.cons->car; + + if (length_of_list(args) != length_of_list(vars)) { + return eval_failure(CONS(gc, + SYMBOL(gc, "wrong-number-of-arguments"), + NUMBER(gc, length_of_list(args)))); + } + + push_scope_frame(gc, scope, vars, args); + struct Expr body = callable.cons->cdr.cons->cdr; + + struct EvalResult result = eval_success(NIL(gc)); + + while (!nil_p(body)) { + print_expr_as_sexpr(body.cons->car); + result = eval(gc, scope, body.cons->car); + if (result.is_error) { + return result; + } + body = body.cons->cdr; + } + + pop_scope_frame(gc, scope); + + return result; +} + +static struct EvalResult eval_funcall(Gc *gc, struct Scope *scope, struct Cons *cons) +{ + assert(cons); + (void) scope; + + if (symbol_p(cons->car)) { + if (strcmp(cons->car.atom->sym, "+") == 0) { + struct EvalResult args = eval_all_args(gc, scope, cons->cdr); + if (args.is_error) { + return args; + } + return plus_op(gc, args.expr); + } else if (strcmp(cons->car.atom->sym, "set") == 0) { + struct Expr args = cons->cdr; + struct EvalResult n = length(gc, args); + + if (n.is_error) { + return n; + } + + if (n.expr.atom->num != 2) { + return eval_failure(list(gc, 3, + SYMBOL(gc, "wrong-number-of-arguments"), + SYMBOL(gc, "set"), + NUMBER(gc, n.expr.atom->num))); + } + + struct Expr name = args.cons->car; + if (!symbol_p(name)) { + return eval_failure(list(gc, 3, + SYMBOL(gc, "wrong-type-argument"), + SYMBOL(gc, "symbolp"), + name)); + } + + struct EvalResult value = eval(gc, scope, args.cons->cdr.cons->car); + if (value.is_error) { + return value; + } + + set_scope_value(gc, scope, name, value.expr); + + return eval_success(value.expr); + } else if (strcmp(cons->car.atom->sym, "quote") == 0) { + /* TODO: quote does not check the amout of it's arguments */ + return eval_success(cons->cdr.cons->car); + } else if (strcmp(cons->car.atom->sym, "lambda") == 0) { + return eval_success(cons_as_expr(cons)); + } else { + struct EvalResult r = eval_all_args(gc, scope, cons_as_expr(cons)); + + if (r.is_error) { + return r; + } + + if (!callable_p(r.expr.cons->car)) { + return eval_failure(CONS(gc, + SYMBOL(gc, "not-callable"), + r.expr.cons->car)); + } + + return call_callable(gc, scope, r.expr.cons->car, r.expr.cons->cdr); + } + } else if (callable_p(cons->car)) { + /* TODO: Call cons->car */ + } + + return eval_failure(CONS(gc, + SYMBOL(gc, "unknown-function"), + cons->car)); +} + +struct EvalResult eval(Gc *gc, struct Scope *scope, struct Expr expr) +{ + switch(expr.type) { + case EXPR_ATOM: + return eval_atom(gc, scope, expr.atom); + + case EXPR_CONS: + return eval_funcall(gc, scope, expr.cons); + + default: {} + } + + return eval_failure(CONS(gc, + SYMBOL(gc, "unexpected-expression"), + expr)); }