#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));
}