X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fscript%2Finterpreter.c;h=07b716381aa14b5e43475a3ae30c2ca32a30e075;hb=c9ef07a849e2b0765e3163732ebf19efec9c04f7;hp=3af4294ad295186b7133c021cf596e33cb3215ae;hpb=90909bd70b3e7464de91998b3d2d051dda88cdcb;p=nothing.git diff --git a/src/script/interpreter.c b/src/script/interpreter.c index 3af4294a..07b71638 100644 --- a/src/script/interpreter.c +++ b/src/script/interpreter.c @@ -2,108 +2,259 @@ #include #include +#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) { - /* TODO: eval_atom is not implemented */ - assert(atom); (void) scope; - return eval_failure("not implemented", void_expr()); + (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_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 scope, struct Expr args) +static struct EvalResult plus_op(Gc *gc, struct Expr args) { - (void) scope; - (void) args; - /* TODO: plus_op is not implemented*/ - return eval_failure("not implemnted", void_expr()); + 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 eval_funcall(struct Expr scope, struct Cons *cons) +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 (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(scope, 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)); }