#include "./builtins.h"
#include "./expr.h"
#include "./interpreter.h"
+#include "./scope.h"
-struct EvalResult eval_success(struct Expr expr)
+struct EvalResult eval_success(struct Expr expr, struct Expr scope)
{
struct EvalResult result = {
.is_error = false,
.expr = expr,
- .error = NULL
+ .scope = scope,
};
return result;
}
-struct EvalResult eval_failure(const char *error, struct Expr expr)
+struct EvalResult eval_failure(struct Expr error, struct Expr scope)
{
struct EvalResult result = {
.is_error = true,
- .error = error,
- .expr = expr
+ .expr = error,
+ .scope = scope
};
return result;
}
-static struct EvalResult eval_atom(struct Expr scope, struct Atom *atom)
+static struct EvalResult length(Gc *gc, struct Expr scope, struct Expr obj)
+{
+ if (!list_p(obj)) {
+ return eval_failure(list(gc, 3,
+ SYMBOL(gc, "wrong-argument-type"),
+ SYMBOL(gc, "listp"),
+ obj),
+ scope);
+ }
+
+ long int count = 0;
+
+ while (!nil_p(obj)) {
+ count++;
+ obj = obj.cons->cdr;
+ }
+
+ return eval_success(NUMBER(gc, count), scope);
+}
+
+static struct EvalResult eval_atom(Gc *gc, struct Expr scope, struct Atom *atom)
{
- /* TODO: eval_atom is not implemented */
- assert(atom);
(void) scope;
- return eval_failure("not implemented", void_expr());
+ (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_failure(CONS(gc,
+ SYMBOL(gc, "unexpected-expression"),
+ atom_as_expr(atom)),
+ scope);
}
-static struct EvalResult eval_args(struct Expr scope, struct Expr args)
+static struct EvalResult eval_all_args(Gc *gc, struct Expr 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)), scope);
}
default: {}
}
- return eval_failure("Unexpected expression", args);
+ return eval_failure(CONS(gc,
+ SYMBOL(gc, "unexpected-expression"),
+ args),
+ scope);
}
-static struct EvalResult plus_op(struct Expr args)
+static struct EvalResult plus_op(Gc *gc, struct Expr args, struct Expr scope)
{
- 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),
+ scope);
}
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),
+ scope);
}
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)), scope);
}
-static struct EvalResult eval_funcall(struct Expr scope, struct Cons *cons)
+static struct EvalResult eval_funcall(Gc *gc, struct Expr 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)) {
+ return eval_failure(CONS(gc,
+ SYMBOL(gc, "expected-symbol"),
+ cons->car),
+ scope);
}
- if (strcmp(cons->car.atom->sym, "+")) {
- struct EvalResult args = eval_args(scope, cons->cdr);
+ /* TODO(#323): set builtin function is not implemented */
+ 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(args.expr);
+ return plus_op(gc, args.expr, scope);
+ } else if (strcmp(cons->car.atom->sym, "set") == 0) {
+ struct Expr args = cons->cdr;
+ struct EvalResult n = length(gc, scope, args);
+
+ if (n.is_error) {
+ return n;
+ }
+ scope = n.scope;
+
+ 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)),
+ scope);
+ }
+
+ 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),
+ scope);
+ }
+
+ struct EvalResult value = eval(gc, scope, args.cons->cdr.cons->car);
+ if (value.is_error) {
+ return value;
+ }
+ scope = value.scope;
+
+ return eval_success(value.expr, set_scope_value(gc, scope, name, value.expr));
}
- return eval_failure("Unknown function", cons->car);
+ return eval_failure(CONS(gc,
+ SYMBOL(gc, "unknown-function"),
+ cons->car),
+ scope);
}
-struct EvalResult eval(struct Expr scope, struct Expr expr)
+struct EvalResult eval(Gc *gc, struct Expr 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),
+ scope);
}