X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fscript%2Finterpreter.c;h=07b716381aa14b5e43475a3ae30c2ca32a30e075;hb=c9ef07a849e2b0765e3163732ebf19efec9c04f7;hp=e598ac77852f61e201be268961ca004b5aba11e5;hpb=92be23571da5921790dafa2d8e9a65d5a6e79ee3;p=nothing.git diff --git a/src/script/interpreter.c b/src/script/interpreter.c index e598ac77..07b71638 100644 --- a/src/script/interpreter.c +++ b/src/script/interpreter.c @@ -5,129 +5,256 @@ #include "./builtins.h" #include "./expr.h" #include "./interpreter.h" +#include "./scope.h" struct EvalResult eval_success(struct Expr expr) { struct EvalResult result = { .is_error = false, .expr = expr, - .error = NULL }; return result; } -struct EvalResult eval_failure(const char *error, struct Expr expr) +struct EvalResult eval_failure(struct Expr error) { struct EvalResult result = { .is_error = true, - .error = error, - .expr = expr + .expr = error, }; return result; } -static struct EvalResult eval_atom(struct Expr scope, struct Atom *atom) +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: - /* TODO: Evaluating symbols is not implemented */ - return eval_failure("Evaluating symbols is not implemented", - 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("Unexpected expression", atom_as_expr(atom)); + return eval_failure(CONS(gc, + SYMBOL(gc, "unexpected-expression"), + atom_as_expr(atom))); } -static struct EvalResult eval_args(struct Expr scope, struct Expr args) +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(scope, args.atom); + return eval_atom(gc, scope, args.atom); case EXPR_CONS: { - struct EvalResult car = eval(scope, args.cons->car); + struct EvalResult car = eval(gc, scope, args.cons->car); if (car.is_error) { return car; } - struct EvalResult cdr = eval_args(scope, args.cons->cdr); + struct EvalResult cdr = eval_all_args(gc, scope, args.cons->cdr); if (cdr.is_error) { return cdr; } - /* TODO: memory leak */ - return eval_success(cons_as_expr(create_cons(car.expr, cdr.expr))); + return eval_success(cons_as_expr(create_cons(gc, car.expr, cdr.expr))); } default: {} } - return eval_failure("Unexpected expression", args); + return eval_failure(CONS(gc, + SYMBOL(gc, "unexpected-expression"), + args)); } -static struct EvalResult plus_op(struct Expr args) +static struct EvalResult plus_op(Gc *gc, struct Expr args) { - float result = 0.0f; + long int result = 0.0f; while (!nil_p(args)) { if (args.type != EXPR_CONS) { - return eval_failure("Expected cons", args); + 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("Expected number", args.cons->car); + 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(result))); + 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(struct Expr scope, struct Cons *cons) +static struct EvalResult eval_funcall(Gc *gc, struct Scope *scope, struct Cons *cons) { assert(cons); (void) scope; - if (cons->car.type != EXPR_ATOM && cons->car.atom->type != ATOM_SYMBOL) { - return eval_failure("Not a function", cons->car); - } + 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)); + } - if (strcmp(cons->car.atom->sym, "+")) { - struct EvalResult args = eval_args(scope, cons->cdr); - if (args.is_error) { - return args; + return call_callable(gc, scope, r.expr.cons->car, r.expr.cons->cdr); } - return plus_op(args.expr); + } else if (callable_p(cons->car)) { + /* TODO: Call cons->car */ } - return eval_failure("Unknown function", cons->car); + return eval_failure(CONS(gc, + SYMBOL(gc, "unknown-function"), + cons->car)); } -struct EvalResult eval(struct Expr scope, struct Expr expr) +struct EvalResult eval(Gc *gc, struct Scope *scope, struct Expr expr) { switch(expr.type) { case EXPR_ATOM: - return eval_atom(scope, expr.atom); + return eval_atom(gc, scope, expr.atom); case EXPR_CONS: - return eval_funcall(scope, expr.cons); + return eval_funcall(gc, scope, expr.cons); default: {} } - return eval_failure("Unexpected expression", expr); + return eval_failure(CONS(gc, + SYMBOL(gc, "unexpected-expression"), + expr)); }