X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fscript%2Finterpreter.c;h=07b716381aa14b5e43475a3ae30c2ca32a30e075;hb=c9ef07a849e2b0765e3163732ebf19efec9c04f7;hp=93316899c2fea2fa78a3881249359b374372d55f;hpb=3e305994d5b8dd9c51534927eaf2add03a10c2f2;p=nothing.git diff --git a/src/script/interpreter.c b/src/script/interpreter.c index 93316899..07b71638 100644 --- a/src/script/interpreter.c +++ b/src/script/interpreter.c @@ -7,48 +7,71 @@ #include "./interpreter.h" #include "./scope.h" -struct EvalResult eval_success(struct Expr expr, struct Expr scope) +struct EvalResult eval_success(struct Expr expr) { struct EvalResult result = { .is_error = false, .expr = expr, - .scope = scope, }; return result; } -struct EvalResult eval_failure(struct Expr error, struct Expr scope) +struct EvalResult eval_failure(struct Expr error) { struct EvalResult result = { .is_error = true, .expr = error, - .scope = scope }; return result; } -static struct EvalResult eval_atom(Gc *gc, 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; - /* TODO(#314): Evaluating symbols is not implemented */ switch (atom->type) { case ATOM_NUMBER: - case ATOM_SYMBOL: case ATOM_STRING: - return eval_success(atom_as_expr(atom), scope); + 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)), - scope); + atom_as_expr(atom))); } -static struct EvalResult eval_args(Gc *gc, struct Expr scope, struct Expr args) +static struct EvalResult eval_all_args(Gc *gc, struct Scope *scope, struct Expr args) { (void) scope; (void) args; @@ -63,12 +86,12 @@ static struct EvalResult eval_args(Gc *gc, struct Expr scope, struct Expr args) return car; } - struct EvalResult cdr = eval_args(gc, scope, args.cons->cdr); + 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)), scope); + return eval_success(cons_as_expr(create_cons(gc, car.expr, cdr.expr))); } default: {} @@ -76,65 +99,150 @@ static struct EvalResult eval_args(Gc *gc, struct Expr scope, struct Expr args) return eval_failure(CONS(gc, SYMBOL(gc, "unexpected-expression"), - args), - scope); + args)); } -static struct EvalResult plus_op(Gc *gc, struct Expr args, struct Expr scope) +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(CONS(gc, SYMBOL(gc, "expected-cons"), - args), - scope); + 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), - scope); + args.cons->car)); } result += args.cons->car.atom->num; args = args.cons->cdr; } - return eval_success(atom_as_expr(create_number_atom(gc, result)), scope); + 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 Expr scope, struct Cons *cons) +static struct EvalResult eval_funcall(Gc *gc, struct Scope *scope, struct Cons *cons) { assert(cons); (void) scope; - if (!symbol_p(cons->car)) { - return eval_failure(CONS(gc, - SYMBOL(gc, "expected-symbol"), - cons->car), - 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)); + } - /* TODO(#323): set builtin function is not implemented */ - if (strcmp(cons->car.atom->sym, "+") == 0) { - struct EvalResult args = eval_args(gc, 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(gc, args.expr, scope); + } else if (callable_p(cons->car)) { + /* TODO: Call cons->car */ } return eval_failure(CONS(gc, SYMBOL(gc, "unknown-function"), - cons->car), - scope); + cons->car)); } -struct EvalResult eval(Gc *gc, struct Expr scope, struct Expr expr) +struct EvalResult eval(Gc *gc, struct Scope *scope, struct Expr expr) { switch(expr.type) { case EXPR_ATOM: @@ -148,6 +256,5 @@ struct EvalResult eval(Gc *gc, struct Expr scope, struct Expr expr) return eval_failure(CONS(gc, SYMBOL(gc, "unexpected-expression"), - expr), - scope); + expr)); }