args));
}
-static struct EvalResult plus_op(Gc *gc, struct Expr args)
+/* TODO(#540): plus_op should be part of std library */
+static struct EvalResult
+plus_op(void *param, Gc *gc, struct Scope *scope, struct Expr args)
{
- long int result = 0.0f;
+ (void) param;
+ assert(gc);
+ assert(scope);
+
+ long int result = 0L;
while (!nil_p(args)) {
- if (args.type != EXPR_CONS) {
- return eval_failure(CONS(gc,
- SYMBOL(gc, "expected-cons"),
- args));
+ if (!cons_p(args)) {
+ return wrong_argument_type(gc, "consp", 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));
+ if (!number_p(CAR(args))) {
+ return wrong_argument_type(gc, "numberp", CAR(args));
}
- result += args.cons->car.atom->num;
- args = args.cons->cdr;
+ result += CAR(args).atom->num;
+ args = CDR(args);
}
- return eval_success(atom_as_expr(create_number_atom(gc, result)));
+ return eval_success(NUMBER(gc, result));
}
static struct EvalResult call_lambda(Gc *gc,
(void) 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) {
+ if (strcmp(cons->car.atom->sym, "set") == 0) {
struct Expr args = cons->cdr;
struct EvalResult n = length(gc, args);
struct Expr condition = NIL(gc);
struct Expr body = NIL(gc);
- struct EvalResult result = unpack_args(
+ struct EvalResult result = match_list(
gc, "e*", cons->cdr, &condition, &body);
if (result.is_error) {
return result;
assert(gc);
assert(scope);
- if (!list_p(args)) {
- return wrong_argument_type(gc, "listp", args);
- }
+ struct Expr xs = NIL(gc);
+ struct Expr x = NIL(gc);
- if (length_of_list(args) != 1) {
- return wrong_number_of_arguments(gc, length_of_list(args));
+ struct EvalResult result = match_list(gc, "e", args, &xs);
+ if (result.is_error) {
+ return result;
}
- struct Expr xs = args.cons->car;
-
if (nil_p(xs)) {
return eval_success(xs);
}
- return eval_success(xs.cons->car);
+ result = match_list(gc, "e*", xs, &x, NULL);
+ if (result.is_error) {
+ return result;
+ }
+
+ return eval_success(x);
+}
+
+/* TODO(#536): greaterThan does not support arbitrary amount of arguments */
+static struct EvalResult
+greaterThan(void *param, Gc *gc, struct Scope *scope, struct Expr args)
+{
+ assert(gc);
+ assert(scope);
+ (void) param;
+
+ long int x = 0, y = 0;
+
+ struct EvalResult result = match_list(gc, "dd", args, &x, &y);
+ if (result.is_error) {
+ return result;
+ }
+
+ if (x > y) {
+ /* TODO(#537): in ebisp t is not a special symbol that evaluates to itself */
+ return eval_success(SYMBOL(gc, "t"));
+ } else {
+ return eval_success(NIL(gc));
+ }
}
void load_std_library(Gc *gc, struct Scope *scope)
scope,
SYMBOL(gc, "car"),
NATIVE(gc, car, NULL));
+ set_scope_value(
+ gc,
+ scope,
+ SYMBOL(gc, ">"),
+ NATIVE(gc, greaterThan, NULL));
+ set_scope_value(
+ gc,
+ scope,
+ SYMBOL(gc, "+"),
+ NATIVE(gc, plus_op, NULL));
}
-/* TODO(#530): unpack_args doesn't support * format parameter */
struct EvalResult
-unpack_args(struct Gc *gc, const char *format, struct Expr args, ...)
+match_list(struct Gc *gc, const char *format, struct Expr xs, ...)
{
va_list args_list;
- va_start(args_list, args);
+ va_start(args_list, xs);
- if (!list_p(args)) {
+ /* TODO(#544): match_list is O(N) even in best case (format == "*") */
+ if (!list_p(xs)) {
va_end(args_list);
- return wrong_argument_type(gc, "listp", args);
+ return wrong_argument_type(gc, "listp", xs);
}
long int i = 0;
- for (i = 0; *format != 0 && !nil_p(args); ++i) {
- struct Expr arg = CAR(args);
+ for (i = 0; *format != 0 && !nil_p(xs); ++i) {
+ struct Expr x = CAR(xs);
switch (*format) {
case 'd': {
- if (!number_p(arg)) {
+ if (!number_p(x)) {
va_end(args_list);
- return wrong_argument_type(gc, "numberp", arg);
+ return wrong_argument_type(gc, "numberp", x);
}
long int *p = va_arg(args_list, long int *);
- *p = arg.atom->num;
+ if (p != NULL) {
+ *p = x.atom->num;
+ }
} break;
case 's': {
- if (!string_p(arg)) {
+ if (!string_p(x)) {
va_end(args_list);
- return wrong_argument_type(gc, "stringp", arg);
+ return wrong_argument_type(gc, "stringp", x);
}
const char **p = va_arg(args_list, const char**);
- *p = arg.atom->str;
+ if (p != NULL) {
+ *p = x.atom->str;
+ }
} break;
case 'q': {
- if (!symbol_p(arg)) {
+ if (!symbol_p(x)) {
va_end(args_list);
- return wrong_argument_type(gc, "symbolp", arg);
+ return wrong_argument_type(gc, "symbolp", x);
}
const char **p = va_arg(args_list, const char**);
- *p = arg.atom->sym;
+ if (p != NULL) {
+ *p = x.atom->sym;
+ }
} break;
case 'e': {
struct Expr *p = va_arg(args_list, struct Expr*);
- *p = arg;
+ *p = x;
} break;
case '*': {
struct Expr *p = va_arg(args_list, struct Expr*);
- *p = args;
- args = NIL(gc);
+ if (p != NULL) {
+ *p = xs;
+ }
+ xs = NIL(gc);
} break;
}
format++;
- if (!nil_p(args)) {
- args = CDR(args);
+ if (!nil_p(xs)) {
+ xs = CDR(xs);
}
}
- if (*format != 0 || !nil_p(args)) {
- return eval_failure(
- CONS(gc,
- SYMBOL(gc, "wrong-number-of-arguments"),
- NUMBER(gc, i)));
+ if (*format != 0 || !nil_p(xs)) {
+ return wrong_number_of_arguments(gc, i);
}
return eval_success(NIL(gc));
}
+
+/* TODO(#542): format_list(). Similar to match_list() but for constructing list */