X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fscript%2Finterpreter.c;h=07b716381aa14b5e43475a3ae30c2ca32a30e075;hb=c9ef07a849e2b0765e3163732ebf19efec9c04f7;hp=004610ad169117936daa265758fe2938a9817bb6;hpb=c63912060941c2d83821afd1a4e77e30e2c42966;p=nothing.git diff --git a/src/script/interpreter.c b/src/script/interpreter.c index 004610ad..07b71638 100644 --- a/src/script/interpreter.c +++ b/src/script/interpreter.c @@ -7,47 +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, - .error = NULL }; return result; } -struct EvalResult eval_failure(const char *error, struct Expr expr, struct Expr scope) +struct EvalResult eval_failure(struct Expr error) { struct EvalResult result = { .is_error = true, - .error = error, - .scope = scope, - .expr = expr + .expr = error, }; 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("Unexpected expression", atom_as_expr(atom), scope); + return eval_failure(CONS(gc, + SYMBOL(gc, "unexpected-expression"), + 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; @@ -62,63 +86,163 @@ 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: {} } - return eval_failure("Unexpected expression", args, scope); + return eval_failure(CONS(gc, + SYMBOL(gc, "unexpected-expression"), + 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("Expected cons", args, scope); + 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, scope); + 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)), 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("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)); + } - /* 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; + 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); } - return plus_op(gc, args.expr, scope); + } else if (callable_p(cons->car)) { + /* TODO: Call cons->car */ } - return eval_failure("Unknown function", cons->car, scope); + return eval_failure(CONS(gc, + SYMBOL(gc, "unknown-function"), + 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: @@ -130,15 +254,7 @@ struct EvalResult eval(Gc *gc, struct Expr scope, struct Expr expr) default: {} } - return eval_failure("Unexpected expression", expr, scope); -} - -void print_eval_error(FILE *stream, struct EvalResult result) -{ - if (!result.is_error) { - return; - } - - fprintf(stream, "%s\n", result.error); - print_expr_as_sexpr(result.expr); + return eval_failure(CONS(gc, + SYMBOL(gc, "unexpected-expression"), + expr)); }