+ao_poly
+ao_lisp_do_modulo(struct ao_lisp_cons *cons)
+{
+ return ao_lisp_math(cons, builtin_modulo);
+}
+
+ao_poly
+ao_lisp_do_remainder(struct ao_lisp_cons *cons)
+{
+ return ao_lisp_math(cons, builtin_remainder);
+}
+
+ao_poly
+ao_lisp_compare(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op)
+{
+ ao_poly left;
+
+ if (!cons)
+ return _ao_lisp_bool_true;
+
+ left = cons->car;
+ cons = ao_lisp_poly_cons(cons->cdr);
+ while (cons) {
+ ao_poly right = cons->car;
+
+ if (op == builtin_equal) {
+ if (left != right)
+ return _ao_lisp_bool_false;
+ } else {
+ uint8_t lt = ao_lisp_poly_type(left);
+ uint8_t rt = ao_lisp_poly_type(right);
+ if (ao_lisp_integer_typep(lt) && ao_lisp_integer_typep(rt)) {
+ int32_t l = ao_lisp_poly_integer(left);
+ int32_t r = ao_lisp_poly_integer(right);
+
+ switch (op) {
+ case builtin_less:
+ if (!(l < r))
+ return _ao_lisp_bool_false;
+ break;
+ case builtin_greater:
+ if (!(l > r))
+ return _ao_lisp_bool_false;
+ break;
+ case builtin_less_equal:
+ if (!(l <= r))
+ return _ao_lisp_bool_false;
+ break;
+ case builtin_greater_equal:
+ if (!(l >= r))
+ return _ao_lisp_bool_false;
+ break;
+ default:
+ break;
+ }
+ } else if (lt == AO_LISP_STRING && rt == AO_LISP_STRING) {
+ int c = strcmp(ao_lisp_poly_string(left),
+ ao_lisp_poly_string(right));
+ switch (op) {
+ case builtin_less:
+ if (!(c < 0))
+ return _ao_lisp_bool_false;
+ break;
+ case builtin_greater:
+ if (!(c > 0))
+ return _ao_lisp_bool_false;
+ break;
+ case builtin_less_equal:
+ if (!(c <= 0))
+ return _ao_lisp_bool_false;
+ break;
+ case builtin_greater_equal:
+ if (!(c >= 0))
+ return _ao_lisp_bool_false;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ left = right;
+ cons = ao_lisp_poly_cons(cons->cdr);
+ }
+ return _ao_lisp_bool_true;
+}
+
+ao_poly
+ao_lisp_do_equal(struct ao_lisp_cons *cons)
+{
+ return ao_lisp_compare(cons, builtin_equal);
+}
+
+ao_poly
+ao_lisp_do_less(struct ao_lisp_cons *cons)
+{
+ return ao_lisp_compare(cons, builtin_less);
+}
+
+ao_poly
+ao_lisp_do_greater(struct ao_lisp_cons *cons)
+{
+ return ao_lisp_compare(cons, builtin_greater);
+}
+
+ao_poly
+ao_lisp_do_less_equal(struct ao_lisp_cons *cons)
+{
+ return ao_lisp_compare(cons, builtin_less_equal);
+}
+
+ao_poly
+ao_lisp_do_greater_equal(struct ao_lisp_cons *cons)
+{
+ return ao_lisp_compare(cons, builtin_greater_equal);
+}
+
+ao_poly
+ao_lisp_do_list_to_string(struct ao_lisp_cons *cons)
+{
+ if (!ao_lisp_check_argc(_ao_lisp_atom_list2d3estring, cons, 1, 1))
+ return AO_LISP_NIL;
+ if (!ao_lisp_check_argt(_ao_lisp_atom_list2d3estring, cons, 0, AO_LISP_CONS, 1))
+ return AO_LISP_NIL;
+ return ao_lisp_string_pack(ao_lisp_poly_cons(ao_lisp_arg(cons, 0)));
+}
+
+ao_poly
+ao_lisp_do_string_to_list(struct ao_lisp_cons *cons)
+{
+ if (!ao_lisp_check_argc(_ao_lisp_atom_string2d3elist, cons, 1, 1))
+ return AO_LISP_NIL;
+ if (!ao_lisp_check_argt(_ao_lisp_atom_string2d3elist, cons, 0, AO_LISP_STRING, 0))
+ return AO_LISP_NIL;
+ return ao_lisp_string_unpack(ao_lisp_poly_string(ao_lisp_arg(cons, 0)));
+}
+
+ao_poly
+ao_lisp_do_flush(struct ao_lisp_cons *cons)
+{
+ if (!ao_lisp_check_argc(_ao_lisp_atom_flush, cons, 0, 0))
+ return AO_LISP_NIL;
+ ao_lisp_os_flush();
+ return _ao_lisp_bool_true;
+}
+
+ao_poly
+ao_lisp_do_led(struct ao_lisp_cons *cons)
+{
+ ao_poly led;
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
+ return AO_LISP_NIL;
+ if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_INT, 0))
+ return AO_LISP_NIL;
+ led = ao_lisp_arg(cons, 0);
+ ao_lisp_os_led(ao_lisp_poly_int(led));
+ return led;
+}
+
+ao_poly
+ao_lisp_do_delay(struct ao_lisp_cons *cons)
+{
+ ao_poly delay;
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
+ return AO_LISP_NIL;
+ if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_INT, 0))
+ return AO_LISP_NIL;
+ delay = ao_lisp_arg(cons, 0);
+ ao_lisp_os_delay(ao_lisp_poly_int(delay));
+ return delay;
+}
+
+ao_poly
+ao_lisp_do_eval(struct ao_lisp_cons *cons)
+{
+ if (!ao_lisp_check_argc(_ao_lisp_atom_eval, cons, 1, 1))
+ return AO_LISP_NIL;
+ ao_lisp_stack->state = eval_sexpr;
+ return cons->car;
+}
+
+ao_poly
+ao_lisp_do_apply(struct ao_lisp_cons *cons)
+{
+ if (!ao_lisp_check_argc(_ao_lisp_atom_apply, cons, 2, INT_MAX))
+ return AO_LISP_NIL;
+ ao_lisp_stack->state = eval_apply;
+ return ao_lisp_cons_poly(cons);
+}
+
+ao_poly
+ao_lisp_do_read(struct ao_lisp_cons *cons)
+{
+ if (!ao_lisp_check_argc(_ao_lisp_atom_read, cons, 0, 0))
+ return AO_LISP_NIL;
+ return ao_lisp_read();
+}
+
+ao_poly
+ao_lisp_do_collect(struct ao_lisp_cons *cons)
+{
+ int free;
+ (void) cons;
+ free = ao_lisp_collect(AO_LISP_COLLECT_FULL);
+ return ao_lisp_int_poly(free);
+}
+
+ao_poly
+ao_lisp_do_nullp(struct ao_lisp_cons *cons)
+{
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
+ return AO_LISP_NIL;
+ if (ao_lisp_arg(cons, 0) == AO_LISP_NIL)
+ return _ao_lisp_bool_true;
+ else
+ return _ao_lisp_bool_false;
+}
+
+ao_poly
+ao_lisp_do_not(struct ao_lisp_cons *cons)
+{
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
+ return AO_LISP_NIL;
+ if (ao_lisp_arg(cons, 0) == _ao_lisp_bool_false)
+ return _ao_lisp_bool_true;
+ else
+ return _ao_lisp_bool_false;
+}
+
+static ao_poly
+ao_lisp_do_typep(int type, struct ao_lisp_cons *cons)
+{
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
+ return AO_LISP_NIL;
+ if (ao_lisp_poly_type(ao_lisp_arg(cons, 0)) == type)
+ return _ao_lisp_bool_true;
+ return _ao_lisp_bool_false;
+}
+
+ao_poly
+ao_lisp_do_pairp(struct ao_lisp_cons *cons)
+{
+ return ao_lisp_do_typep(AO_LISP_CONS, cons);
+}
+
+ao_poly
+ao_lisp_do_numberp(struct ao_lisp_cons *cons)
+{
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
+ return AO_LISP_NIL;
+ switch (ao_lisp_poly_type(ao_lisp_arg(cons, 0))) {
+ case AO_LISP_INT:
+ case AO_LISP_BIGINT:
+ return _ao_lisp_bool_true;
+ default:
+ return _ao_lisp_bool_false;
+ }
+}
+
+ao_poly
+ao_lisp_do_stringp(struct ao_lisp_cons *cons)
+{
+ return ao_lisp_do_typep(AO_LISP_STRING, cons);
+}
+
+ao_poly
+ao_lisp_do_symbolp(struct ao_lisp_cons *cons)
+{
+ return ao_lisp_do_typep(AO_LISP_ATOM, cons);
+}
+
+ao_poly
+ao_lisp_do_booleanp(struct ao_lisp_cons *cons)
+{
+ return ao_lisp_do_typep(AO_LISP_BOOL, cons);
+}
+
+ao_poly
+ao_lisp_do_procedurep(struct ao_lisp_cons *cons)
+{
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
+ return AO_LISP_NIL;
+ switch (ao_lisp_poly_type(ao_lisp_arg(cons, 0))) {
+ case AO_LISP_BUILTIN:
+ case AO_LISP_LAMBDA:
+ return _ao_lisp_bool_true;
+ default:
+ return _ao_lisp_bool_false;
+ }
+}
+
+/* This one is special -- a list is either nil or
+ * a 'proper' list with only cons cells
+ */
+ao_poly
+ao_lisp_do_listp(struct ao_lisp_cons *cons)
+{
+ ao_poly v;
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
+ return AO_LISP_NIL;
+ v = ao_lisp_arg(cons, 0);
+ for (;;) {
+ if (v == AO_LISP_NIL)
+ return _ao_lisp_bool_true;
+ if (ao_lisp_poly_type(v) != AO_LISP_CONS)
+ return _ao_lisp_bool_false;
+ v = ao_lisp_poly_cons(v)->cdr;
+ }
+}
+
+ao_poly
+ao_lisp_do_set_car(struct ao_lisp_cons *cons)
+{
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 2, 2))
+ return AO_LISP_NIL;
+ if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_CONS, 0))
+ return AO_LISP_NIL;
+ return ao_lisp_poly_cons(ao_lisp_arg(cons, 0))->car = ao_lisp_arg(cons, 1);
+}
+
+ao_poly
+ao_lisp_do_set_cdr(struct ao_lisp_cons *cons)
+{
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 2, 2))
+ return AO_LISP_NIL;
+ if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_CONS, 0))
+ return AO_LISP_NIL;
+ return ao_lisp_poly_cons(ao_lisp_arg(cons, 0))->cdr = ao_lisp_arg(cons, 1);
+}
+
+ao_poly
+ao_lisp_do_symbol_to_string(struct ao_lisp_cons *cons)
+{
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
+ return AO_LISP_NIL;
+ if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_ATOM, 0))
+ return AO_LISP_NIL;
+ return ao_lisp_string_poly(ao_lisp_string_copy(ao_lisp_poly_atom(ao_lisp_arg(cons, 0))->name));
+}
+
+ao_poly
+ao_lisp_do_string_to_symbol(struct ao_lisp_cons *cons)
+{
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
+ return AO_LISP_NIL;
+ if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_STRING, 0))
+ return AO_LISP_NIL;
+
+ return ao_lisp_atom_poly(ao_lisp_atom_intern(ao_lisp_poly_string(ao_lisp_arg(cons, 0))));
+}
+
+ao_poly
+ao_lisp_do_read_char(struct ao_lisp_cons *cons)
+{
+ int c;
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
+ return AO_LISP_NIL;
+ c = getchar();
+ return ao_lisp_int_poly(c);
+}
+
+ao_poly
+ao_lisp_do_write_char(struct ao_lisp_cons *cons)
+{
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
+ return AO_LISP_NIL;
+ if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_INT, 0))
+ return AO_LISP_NIL;
+ putchar(ao_lisp_poly_integer(ao_lisp_arg(cons, 0)));
+ return _ao_lisp_bool_true;
+}
+
+ao_poly
+ao_lisp_do_exit(struct ao_lisp_cons *cons)
+{
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
+ return AO_LISP_NIL;
+ ao_lisp_exception |= AO_LISP_EXIT;
+ return _ao_lisp_bool_true;
+}
+
+ao_poly
+ao_lisp_do_current_jiffy(struct ao_lisp_cons *cons)
+{
+ int jiffy;
+
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
+ return AO_LISP_NIL;
+ jiffy = ao_lisp_os_jiffy();
+ return (ao_lisp_int_poly(jiffy));
+}
+
+ao_poly
+ao_lisp_do_current_second(struct ao_lisp_cons *cons)
+{
+ int second;
+
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
+ return AO_LISP_NIL;
+ second = ao_lisp_os_jiffy() / AO_LISP_JIFFIES_PER_SECOND;
+ return (ao_lisp_int_poly(second));
+}
+
+ao_poly
+ao_lisp_do_jiffies_per_second(struct ao_lisp_cons *cons)
+{
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
+ return AO_LISP_NIL;
+ return (ao_lisp_int_poly(AO_LISP_JIFFIES_PER_SECOND));
+}