diff --git a/eval.c b/eval.c index 7754a700..d5babf23 100644 --- a/eval.c +++ b/eval.c @@ -1230,798 +1230,7 @@ static sexp make_opcode_procedure (sexp ctx, sexp op, sexp_uint_t i) { return res; } -/*********************** the virtual machine **************************/ - -static sexp sexp_save_stack (sexp ctx, sexp *stack, sexp_uint_t to) { - sexp res, *data; - sexp_uint_t i; - res = sexp_make_vector(ctx, sexp_make_fixnum(to), SEXP_VOID); - data = sexp_vector_data(res); - for (i=0; i= SEXP_INIT_STACK_SIZE) { - _ARG1 = sexp_global(ctx, SEXP_G_OOS_ERROR); - goto end_loop; - } -#endif - _ALIGN_IP(); - i = sexp_unbox_fixnum(_WORD0); - tmp1 = _ARG1; - make_call: - if (sexp_opcodep(tmp1)) { - /* compile non-inlined opcode applications on the fly */ - sexp_context_top(ctx) = top; - tmp1 = make_opcode_procedure(ctx, tmp1, i); - if (sexp_exceptionp(tmp1)) { - _ARG1 = tmp1; - goto call_error_handler; - } - } - if (! sexp_procedurep(tmp1)) - sexp_raise("non procedure application", sexp_list1(ctx, tmp1)); - j = i - sexp_unbox_fixnum(sexp_procedure_num_args(tmp1)); - if (j < 0) - sexp_raise("not enough args", - sexp_list2(ctx, tmp1, sexp_make_fixnum(i))); - if (j > 0) { - if (sexp_procedure_variadic_p(tmp1)) { - stack[top-i-1] = sexp_cons(ctx, stack[top-i-1], SEXP_NULL); - for (k=top-i; k=top-i; k--) - stack[k] = stack[k-1]; - stack[top-i-1] = SEXP_NULL; - top++; - i++; - } - _ARG1 = sexp_make_fixnum(i); - stack[top] = sexp_make_fixnum(ip+sizeof(sexp)-sexp_bytecode_data(bc)); - stack[top+1] = self; - stack[top+2] = sexp_make_fixnum(fp); - top += 3; - self = tmp1; - bc = sexp_procedure_code(self); - ip = sexp_bytecode_data(bc); - cp = sexp_procedure_vars(self); - fp = top-4; - break; - case SEXP_OP_FCALL0: - _ALIGN_IP(); - sexp_context_top(ctx) = top; - _PUSH(((sexp_proc1)sexp_opcode_func(_WORD0))(ctx sexp_api_pass(_WORD0, 0))); - ip += sizeof(sexp); - sexp_check_exception(); - break; - case SEXP_OP_FCALL1: - _ALIGN_IP(); - sexp_context_top(ctx) = top; - _ARG1 = ((sexp_proc2)sexp_opcode_func(_WORD0))(ctx sexp_api_pass(_WORD0, 1), _ARG1); - ip += sizeof(sexp); - sexp_check_exception(); - break; - case SEXP_OP_FCALL2: - _ALIGN_IP(); - sexp_context_top(ctx) = top; - _ARG2 = ((sexp_proc3)sexp_opcode_func(_WORD0))(ctx sexp_api_pass(_WORD0, 2), _ARG1, _ARG2); - top--; - ip += sizeof(sexp); - sexp_check_exception(); - break; - case SEXP_OP_FCALL3: - _ALIGN_IP(); - sexp_context_top(ctx) = top; - _ARG3 = ((sexp_proc4)sexp_opcode_func(_WORD0))(ctx sexp_api_pass(_WORD0, 3), _ARG1, _ARG2, _ARG3); - top -= 2; - ip += sizeof(sexp); - sexp_check_exception(); - break; - case SEXP_OP_FCALL4: - _ALIGN_IP(); - sexp_context_top(ctx) = top; - _ARG4 = ((sexp_proc5)sexp_opcode_func(_WORD0))(ctx sexp_api_pass(_WORD0, 4), _ARG1, _ARG2, _ARG3, _ARG4); - top -= 3; - ip += sizeof(sexp); - sexp_check_exception(); - break; - case SEXP_OP_FCALL5: - _ALIGN_IP(); - sexp_context_top(ctx) = top; - _ARG5 = ((sexp_proc6)sexp_opcode_func(_WORD0))(ctx sexp_api_pass(_WORD0, 5), _ARG1, _ARG2, _ARG3, _ARG4, _ARG5); - top -= 4; - ip += sizeof(sexp); - sexp_check_exception(); - break; - case SEXP_OP_FCALL6: - _ALIGN_IP(); - sexp_context_top(ctx) = top; - _ARG6 = ((sexp_proc7)sexp_opcode_func(_WORD0))(ctx sexp_api_pass(_WORD0, 6), _ARG1, _ARG2, _ARG3, _ARG4, _ARG5, _ARG6); - top -= 5; - ip += sizeof(sexp); - sexp_check_exception(); - break; - case SEXP_OP_JUMP_UNLESS: - _ALIGN_IP(); - if (stack[--top] == SEXP_FALSE) - ip += _SWORD0; - else - ip += sizeof(sexp_sint_t); - break; - case SEXP_OP_JUMP: - _ALIGN_IP(); - ip += _SWORD0; - break; - case SEXP_OP_PUSH: - _ALIGN_IP(); - _PUSH(_WORD0); - ip += sizeof(sexp); - break; - case SEXP_OP_DROP: - top--; - break; - case SEXP_OP_GLOBAL_REF: - _ALIGN_IP(); - if (sexp_cdr(_WORD0) == SEXP_UNDEF) - sexp_raise("undefined variable", sexp_list1(ctx, sexp_car(_WORD0))); - /* ... FALLTHROUGH ... */ - case SEXP_OP_GLOBAL_KNOWN_REF: - _ALIGN_IP(); - _PUSH(sexp_cdr(_WORD0)); - ip += sizeof(sexp); - break; - case SEXP_OP_STACK_REF: /* `pick' in forth */ - _ALIGN_IP(); - stack[top] = stack[top - _SWORD0]; - ip += sizeof(sexp); - top++; - break; - case SEXP_OP_LOCAL_REF: - _ALIGN_IP(); - stack[top] = stack[fp - 1 - _SWORD0]; - ip += sizeof(sexp); - top++; - break; - case SEXP_OP_LOCAL_SET: - _ALIGN_IP(); - stack[fp - 1 - _SWORD0] = _ARG1; - _ARG1 = SEXP_VOID; - ip += sizeof(sexp); - break; - case SEXP_OP_CLOSURE_REF: - _ALIGN_IP(); - _PUSH(sexp_vector_ref(cp, sexp_make_fixnum(_WORD0))); - ip += sizeof(sexp); - break; - case SEXP_OP_VECTOR_REF: - if (! sexp_vectorp(_ARG1)) - sexp_raise("vector-ref: not a vector", sexp_list1(ctx, _ARG1)); - else if (! sexp_fixnump(_ARG2)) - sexp_raise("vector-ref: not an integer", sexp_list1(ctx, _ARG2)); - i = sexp_unbox_fixnum(_ARG2); - if ((i < 0) || (i >= sexp_vector_length(_ARG1))) - sexp_raise("vector-ref: index out of range", sexp_list2(ctx, _ARG1, _ARG2)); - _ARG2 = sexp_vector_ref(_ARG1, _ARG2); - top--; - break; - case SEXP_OP_VECTOR_SET: - if (! sexp_vectorp(_ARG1)) - sexp_raise("vector-set!: not a vector", sexp_list1(ctx, _ARG1)); - else if (sexp_immutablep(_ARG1)) - sexp_raise("vector-set!: immutable vector", sexp_list1(ctx, _ARG1)); - else if (! sexp_fixnump(_ARG2)) - sexp_raise("vector-set!: not an integer", sexp_list1(ctx, _ARG2)); - i = sexp_unbox_fixnum(_ARG2); - if ((i < 0) || (i >= sexp_vector_length(_ARG1))) - sexp_raise("vector-set!: index out of range", sexp_list2(ctx, _ARG1, _ARG2)); - sexp_vector_set(_ARG1, _ARG2, _ARG3); - _ARG3 = SEXP_VOID; - top-=2; - break; - case SEXP_OP_VECTOR_LENGTH: - if (! sexp_vectorp(_ARG1)) - sexp_raise("vector-length: not a vector", sexp_list1(ctx, _ARG1)); - _ARG1 = sexp_make_fixnum(sexp_vector_length(_ARG1)); - break; - case SEXP_OP_STRING_REF: - if (! sexp_stringp(_ARG1)) - sexp_raise("string-ref: not a string", sexp_list1(ctx, _ARG1)); - else if (! sexp_fixnump(_ARG2)) - sexp_raise("string-ref: not an integer", sexp_list1(ctx, _ARG2)); - i = sexp_unbox_fixnum(_ARG2); - if ((i < 0) || (i >= sexp_string_length(_ARG1))) - sexp_raise("string-ref: index out of range", sexp_list2(ctx, _ARG1, _ARG2)); - _ARG2 = sexp_string_ref(_ARG1, _ARG2); - top--; - break; - case SEXP_OP_STRING_SET: - if (! sexp_stringp(_ARG1)) - sexp_raise("string-set!: not a string", sexp_list1(ctx, _ARG1)); - else if (sexp_immutablep(_ARG1)) - sexp_raise("string-set!: immutable string", sexp_list1(ctx, _ARG1)); - else if (! sexp_fixnump(_ARG2)) - sexp_raise("string-set!: not an integer", sexp_list1(ctx, _ARG2)); - else if (! sexp_charp(_ARG3)) - sexp_raise("string-set!: not a char", sexp_list1(ctx, _ARG3)); - i = sexp_unbox_fixnum(_ARG2); - if ((i < 0) || (i >= sexp_string_length(_ARG1))) - sexp_raise("string-set!: index out of range", sexp_list2(ctx, _ARG1, _ARG2)); - sexp_string_set(_ARG1, _ARG2, _ARG3); - _ARG3 = SEXP_VOID; - top-=2; - break; - case SEXP_OP_STRING_LENGTH: - if (! sexp_stringp(_ARG1)) - sexp_raise("string-length: not a string", sexp_list1(ctx, _ARG1)); - _ARG1 = sexp_make_fixnum(sexp_string_length(_ARG1)); - break; - case SEXP_OP_MAKE_PROCEDURE: - sexp_context_top(ctx) = top; - _ARG4 = sexp_make_procedure(ctx, _ARG1, _ARG2, _ARG3, _ARG4); - top-=3; - break; - case SEXP_OP_MAKE_VECTOR: - sexp_context_top(ctx) = top; - if (! sexp_fixnump(_ARG1)) - sexp_raise("make-vector: not an integer", sexp_list1(ctx, _ARG1)); - _ARG2 = sexp_make_vector(ctx, _ARG1, _ARG2); - top--; - break; - case SEXP_OP_MAKE_EXCEPTION: - _ARG5 = sexp_make_exception(ctx, _ARG1, _ARG2, _ARG3, _ARG4, _ARG5); - top -= 4; - break; - case SEXP_OP_AND: - _ARG2 = sexp_make_boolean((_ARG1 != SEXP_FALSE) && (_ARG2 != SEXP_FALSE)); - top--; - break; - case SEXP_OP_EOFP: - _ARG1 = sexp_make_boolean(_ARG1 == SEXP_EOF); break; - case SEXP_OP_NULLP: - _ARG1 = sexp_make_boolean(sexp_nullp(_ARG1)); break; - case SEXP_OP_FIXNUMP: - _ARG1 = sexp_make_boolean(sexp_fixnump(_ARG1)); break; - case SEXP_OP_SYMBOLP: - _ARG1 = sexp_make_boolean(sexp_symbolp(_ARG1)); break; - case SEXP_OP_CHARP: - _ARG1 = sexp_make_boolean(sexp_charp(_ARG1)); break; - case SEXP_OP_TYPEP: - _ALIGN_IP(); - _ARG1 = sexp_make_boolean(sexp_check_tag(_ARG1, _UWORD0)); - ip += sizeof(sexp); - break; - case SEXP_OP_MAKE: - _ALIGN_IP(); - _PUSH(sexp_alloc_tagged(ctx, _UWORD1, _UWORD0)); - ip += sizeof(sexp)*2; - break; - case SEXP_OP_SLOT_REF: - _ALIGN_IP(); - if (! sexp_check_tag(_ARG1, _UWORD0)) - sexp_raise("slot-ref: bad type", sexp_list2(ctx, sexp_c_string(ctx, sexp_type_name_by_index(ctx, _UWORD0), -1), _ARG1)); - _ARG1 = sexp_slot_ref(_ARG1, _UWORD1); - ip += sizeof(sexp)*2; - break; - case SEXP_OP_SLOT_SET: - _ALIGN_IP(); - if (! sexp_check_tag(_ARG1, _UWORD0)) - sexp_raise("slot-set!: bad type", sexp_list2(ctx, sexp_c_string(ctx, sexp_type_name_by_index(ctx, _UWORD0), -1), _ARG1)); - else if (sexp_immutablep(_ARG1)) - sexp_raise("slot-set!: immutable object", sexp_list1(ctx, _ARG1)); - sexp_slot_set(_ARG1, _UWORD1, _ARG2); - _ARG2 = SEXP_VOID; - ip += sizeof(sexp)*2; - top--; - break; - case SEXP_OP_CAR: - if (! sexp_pairp(_ARG1)) - sexp_raise("car: not a pair", sexp_list1(ctx, _ARG1)); - _ARG1 = sexp_car(_ARG1); break; - case SEXP_OP_CDR: - if (! sexp_pairp(_ARG1)) - sexp_raise("cdr: not a pair", sexp_list1(ctx, _ARG1)); - _ARG1 = sexp_cdr(_ARG1); break; - case SEXP_OP_SET_CAR: - if (! sexp_pairp(_ARG1)) - sexp_raise("set-car!: not a pair", sexp_list1(ctx, _ARG1)); - else if (sexp_immutablep(_ARG1)) - sexp_raise("set-car!: immutable pair", sexp_list1(ctx, _ARG1)); - sexp_car(_ARG1) = _ARG2; - _ARG2 = SEXP_VOID; - top--; - break; - case SEXP_OP_SET_CDR: - if (! sexp_pairp(_ARG1)) - sexp_raise("set-cdr!: not a pair", sexp_list1(ctx, _ARG1)); - else if (sexp_immutablep(_ARG1)) - sexp_raise("set-cdr!: immutable pair", sexp_list1(ctx, _ARG1)); - sexp_cdr(_ARG1) = _ARG2; - _ARG2 = SEXP_VOID; - top--; - break; - case SEXP_OP_CONS: - sexp_context_top(ctx) = top; - _ARG2 = sexp_cons(ctx, _ARG1, _ARG2); - top--; - break; - case SEXP_OP_ADD: -#if SEXP_USE_BIGNUMS - tmp1 = _ARG1, tmp2 = _ARG2; - sexp_context_top(ctx) = top; - if (sexp_fixnump(tmp1) && sexp_fixnump(tmp2)) { - j = sexp_unbox_fixnum(tmp1) + sexp_unbox_fixnum(tmp2); - if ((j < SEXP_MIN_FIXNUM) || (j > SEXP_MAX_FIXNUM)) - _ARG2 = sexp_add(ctx, tmp1=sexp_fixnum_to_bignum(ctx, tmp1), tmp2); - else - _ARG2 = sexp_make_fixnum(j); - } - else - _ARG2 = sexp_add(ctx, tmp1, tmp2); -#else - if (sexp_fixnump(_ARG1) && sexp_fixnump(_ARG2)) - _ARG2 = sexp_fx_add(_ARG1, _ARG2); -#if SEXP_USE_FLONUMS - else if (sexp_flonump(_ARG1) && sexp_flonump(_ARG2)) - _ARG2 = sexp_fp_add(ctx, _ARG1, _ARG2); - else if (sexp_flonump(_ARG1) && sexp_fixnump(_ARG2)) - _ARG2 = sexp_make_flonum(ctx, sexp_flonum_value(_ARG1) + (double)sexp_unbox_fixnum(_ARG2)); - else if (sexp_fixnump(_ARG1) && sexp_flonump(_ARG2)) - _ARG2 = sexp_make_flonum(ctx, (double)sexp_unbox_fixnum(_ARG1) + sexp_flonum_value(_ARG2)); -#endif - else sexp_raise("+: not a number", sexp_list2(ctx, _ARG1, _ARG2)); -#endif - top--; - break; - case SEXP_OP_SUB: -#if SEXP_USE_BIGNUMS - tmp1 = _ARG1, tmp2 = _ARG2; - sexp_context_top(ctx) = top; - if (sexp_fixnump(tmp1) && sexp_fixnump(tmp2)) { - j = sexp_unbox_fixnum(tmp1) - sexp_unbox_fixnum(tmp2); - if ((j < SEXP_MIN_FIXNUM) || (j > SEXP_MAX_FIXNUM)) - _ARG2 = sexp_sub(ctx, tmp1=sexp_fixnum_to_bignum(ctx, tmp1), tmp2); - else - _ARG2 = sexp_make_fixnum(j); - } - else - _ARG2 = sexp_sub(ctx, tmp1, tmp2); -#else - if (sexp_fixnump(_ARG1) && sexp_fixnump(_ARG2)) - _ARG2 = sexp_fx_sub(_ARG1, _ARG2); -#if SEXP_USE_FLONUMS - else if (sexp_flonump(_ARG1) && sexp_flonump(_ARG2)) - _ARG2 = sexp_fp_sub(ctx, _ARG1, _ARG2); - else if (sexp_flonump(_ARG1) && sexp_fixnump(_ARG2)) - _ARG2 = sexp_make_flonum(ctx, sexp_flonum_value(_ARG1) - (double)sexp_unbox_fixnum(_ARG2)); - else if (sexp_fixnump(_ARG1) && sexp_flonump(_ARG2)) - _ARG2 = sexp_make_flonum(ctx, (double)sexp_unbox_fixnum(_ARG1) - sexp_flonum_value(_ARG2)); -#endif - else sexp_raise("-: not a number", sexp_list2(ctx, _ARG1, _ARG2)); -#endif - top--; - break; - case SEXP_OP_MUL: -#if SEXP_USE_BIGNUMS - tmp1 = _ARG1, tmp2 = _ARG2; - sexp_context_top(ctx) = top; - if (sexp_fixnump(tmp1) && sexp_fixnump(tmp2)) { - prod = (sexp_lsint_t)sexp_unbox_fixnum(tmp1) * sexp_unbox_fixnum(tmp2); - if ((prod < SEXP_MIN_FIXNUM) || (prod > SEXP_MAX_FIXNUM)) - _ARG2 = sexp_mul(ctx, tmp1=sexp_fixnum_to_bignum(ctx, tmp1), tmp2); - else - _ARG2 = sexp_make_fixnum(prod); - } - else - _ARG2 = sexp_mul(ctx, tmp1, tmp2); -#else - if (sexp_fixnump(_ARG1) && sexp_fixnump(_ARG2)) - _ARG2 = sexp_fx_mul(_ARG1, _ARG2); -#if SEXP_USE_FLONUMS - else if (sexp_flonump(_ARG1) && sexp_flonump(_ARG2)) - _ARG2 = sexp_fp_mul(ctx, _ARG1, _ARG2); - else if (sexp_flonump(_ARG1) && sexp_fixnump(_ARG2)) - _ARG2 = sexp_make_flonum(ctx, sexp_flonum_value(_ARG1) * (double)sexp_unbox_fixnum(_ARG2)); - else if (sexp_fixnump(_ARG1) && sexp_flonump(_ARG2)) - _ARG2 = sexp_make_flonum(ctx, (double)sexp_unbox_fixnum(_ARG1) * sexp_flonum_value(_ARG2)); -#endif - else sexp_raise("*: not a number", sexp_list2(ctx, _ARG1, _ARG2)); -#endif - top--; - break; - case SEXP_OP_DIV: - sexp_context_top(ctx) = top; - if (_ARG2 == SEXP_ZERO) { -#if SEXP_USE_FLONUMS - if (sexp_flonump(_ARG1) && sexp_flonum_value(_ARG1) == 0.0) - _ARG2 = sexp_make_flonum(ctx, 0.0/0.0); - else -#endif - sexp_raise("divide by zero", SEXP_NULL); - } else if (sexp_fixnump(_ARG1) && sexp_fixnump(_ARG2)) { -#if SEXP_USE_FLONUMS - _ARG1 = sexp_fixnum_to_flonum(ctx, _ARG1); - _ARG2 = sexp_fixnum_to_flonum(ctx, _ARG2); - _ARG2 = sexp_fp_div(ctx, _ARG1, _ARG2); - if (sexp_flonum_value(_ARG2) == trunc(sexp_flonum_value(_ARG2))) - _ARG2 = sexp_make_fixnum(sexp_flonum_value(_ARG2)); -#else - _ARG2 = sexp_fx_div(_ARG1, _ARG2); -#endif - } -#if SEXP_USE_BIGNUMS - else - _ARG2 = sexp_div(ctx, _ARG1, _ARG2); -#else -#if SEXP_USE_FLONUMS - else if (sexp_flonump(_ARG1) && sexp_flonump(_ARG2)) - _ARG2 = sexp_fp_div(ctx, _ARG1, _ARG2); - else if (sexp_flonump(_ARG1) && sexp_fixnump(_ARG2)) - _ARG2 = sexp_make_flonum(ctx, sexp_flonum_value(_ARG1) / (double)sexp_unbox_fixnum(_ARG2)); - else if (sexp_fixnump(_ARG1) && sexp_flonump(_ARG2)) - _ARG2 = sexp_make_flonum(ctx, (double)sexp_unbox_fixnum(_ARG1) / sexp_flonum_value(_ARG2)); -#endif - else sexp_raise("/: not a number", sexp_list2(ctx, _ARG1, _ARG2)); -#endif - top--; - break; - case SEXP_OP_QUOTIENT: - if (sexp_fixnump(_ARG1) && sexp_fixnump(_ARG2)) { - if (_ARG2 == SEXP_ZERO) - sexp_raise("divide by zero", SEXP_NULL); - _ARG2 = sexp_fx_div(_ARG1, _ARG2); - top--; - } -#if SEXP_USE_BIGNUMS - else { - sexp_context_top(ctx) = top; - _ARG2 = sexp_quotient(ctx, _ARG1, _ARG2); - top--; - } -#else - else sexp_raise("quotient: not an integer", sexp_list2(ctx, _ARG1, _ARG2)); -#endif - break; - case SEXP_OP_REMAINDER: - if (sexp_fixnump(_ARG1) && sexp_fixnump(_ARG2)) { - if (_ARG2 == SEXP_ZERO) - sexp_raise("divide by zero", SEXP_NULL); - tmp1 = sexp_fx_rem(_ARG1, _ARG2); - top--; - _ARG1 = tmp1; - } -#if SEXP_USE_BIGNUMS - else { - sexp_context_top(ctx) = top; - _ARG2 = sexp_remainder(ctx, _ARG1, _ARG2); - top--; - } -#else - else sexp_raise("remainder: not an integer", sexp_list2(ctx, _ARG1, _ARG2)); -#endif - break; - case SEXP_OP_LT: - if (sexp_fixnump(_ARG1) && sexp_fixnump(_ARG2)) { - i = (sexp_sint_t)_ARG1 < (sexp_sint_t)_ARG2; -#if SEXP_USE_BIGNUMS - _ARG2 = sexp_make_boolean(i); - } else { - tmp1 = sexp_compare(ctx, _ARG1, _ARG2); - _ARG2 = sexp_fixnump(tmp1) - ? sexp_make_boolean(sexp_unbox_fixnum(tmp1) < 0) : tmp1; - } -#else -#if SEXP_USE_FLONUMS - } else if (sexp_flonump(_ARG1) && sexp_flonump(_ARG2)) { - i = sexp_flonum_value(_ARG1) < sexp_flonum_value(_ARG2); - } else if (sexp_flonump(_ARG1) && sexp_fixnump(_ARG2)) { - i = sexp_flonum_value(_ARG1) < (double)sexp_unbox_fixnum(_ARG2); - } else if (sexp_fixnump(_ARG1) && sexp_flonump(_ARG2)) { - i = (double)sexp_unbox_fixnum(_ARG1) < sexp_flonum_value(_ARG2); -#endif - } else sexp_raise("<: not a number", sexp_list2(ctx, _ARG1, _ARG2)); - _ARG2 = sexp_make_boolean(i); -#endif - top--; - break; - case SEXP_OP_LE: - if (sexp_fixnump(_ARG1) && sexp_fixnump(_ARG2)) { - i = (sexp_sint_t)_ARG1 <= (sexp_sint_t)_ARG2; -#if SEXP_USE_BIGNUMS - _ARG2 = sexp_make_boolean(i); - } else { - tmp1 = sexp_compare(ctx, _ARG1, _ARG2); - _ARG2 = sexp_fixnump(tmp1) - ? sexp_make_boolean(sexp_unbox_fixnum(tmp1) <= 0) : tmp1; - } -#else -#if SEXP_USE_FLONUMS - } else if (sexp_flonump(_ARG1) && sexp_flonump(_ARG2)) { - i = sexp_flonum_value(_ARG1) <= sexp_flonum_value(_ARG2); - } else if (sexp_flonump(_ARG1) && sexp_fixnump(_ARG2)) { - i = sexp_flonum_value(_ARG1) <= (double)sexp_unbox_fixnum(_ARG2); - } else if (sexp_fixnump(_ARG1) && sexp_flonump(_ARG2)) { - i = (double)sexp_unbox_fixnum(_ARG1) <= sexp_flonum_value(_ARG2); -#endif - } else sexp_raise("<=: not a number", sexp_list2(ctx, _ARG1, _ARG2)); - _ARG2 = sexp_make_boolean(i); -#endif - top--; - break; - case SEXP_OP_EQN: - if (sexp_fixnump(_ARG1) && sexp_fixnump(_ARG2)) { - i = _ARG1 == _ARG2; -#if SEXP_USE_BIGNUMS - _ARG2 = sexp_make_boolean(i); - } else { - tmp1 = sexp_compare(ctx, _ARG1, _ARG2); - _ARG2 = sexp_fixnump(tmp1) - ? sexp_make_boolean(sexp_unbox_fixnum(tmp1) == 0) : tmp1; - } -#else -#if SEXP_USE_FLONUMS - } else if (sexp_flonump(_ARG1) && sexp_flonump(_ARG2)) { - i = sexp_flonum_value(_ARG1) == sexp_flonum_value(_ARG2); - } else if (sexp_flonump(_ARG1) && sexp_fixnump(_ARG2)) { - i = sexp_flonum_value(_ARG1) == (double)sexp_unbox_fixnum(_ARG2); - } else if (sexp_fixnump(_ARG1) && sexp_flonump(_ARG2)) { - i = (double)sexp_unbox_fixnum(_ARG1) == sexp_flonum_value(_ARG2); -#endif - } else sexp_raise("=: not a number", sexp_list2(ctx, _ARG1, _ARG2)); - _ARG2 = sexp_make_boolean(i); -#endif - top--; - break; - case SEXP_OP_EQ: - _ARG2 = sexp_make_boolean(_ARG1 == _ARG2); - top--; - break; - case SEXP_OP_FIX2FLO: - if (sexp_fixnump(_ARG1)) - _ARG1 = sexp_fixnum_to_flonum(ctx, _ARG1); -#if SEXP_USE_BIGNUMS - else if (sexp_bignump(_ARG1)) - _ARG1 = sexp_make_flonum(ctx, sexp_bignum_to_double(_ARG1)); -#endif - else if (! sexp_flonump(_ARG1)) - sexp_raise("exact->inexact: not a number", sexp_list1(ctx, _ARG1)); - break; - case SEXP_OP_FLO2FIX: - if (sexp_flonump(_ARG1)) { - if (sexp_flonum_value(_ARG1) != trunc(sexp_flonum_value(_ARG1))) { - sexp_raise("inexact->exact: not an integer", sexp_list1(ctx, _ARG1)); -#if SEXP_USE_BIGNUMS - } else if ((sexp_flonum_value(_ARG1) > SEXP_MAX_FIXNUM) - || sexp_flonum_value(_ARG1) < SEXP_MIN_FIXNUM) { - _ARG1 = sexp_double_to_bignum(ctx, sexp_flonum_value(_ARG1)); -#endif - } else { - _ARG1 = sexp_make_fixnum((sexp_sint_t)sexp_flonum_value(_ARG1)); - } - } else if (! sexp_fixnump(_ARG1) && ! sexp_bignump(_ARG1)) { - sexp_raise("inexact->exact: not a number", sexp_list1(ctx, _ARG1)); - } - break; - case SEXP_OP_CHAR2INT: - if (! sexp_charp(_ARG1)) - sexp_raise("char->integer: not a character", sexp_list1(ctx, _ARG1)); - _ARG1 = sexp_make_fixnum(sexp_unbox_character(_ARG1)); - break; - case SEXP_OP_INT2CHAR: - if (! sexp_fixnump(_ARG1)) - sexp_raise("integer->char: not an integer", sexp_list1(ctx, _ARG1)); - _ARG1 = sexp_make_character(sexp_unbox_fixnum(_ARG1)); - break; - case SEXP_OP_CHAR_UPCASE: - if (! sexp_charp(_ARG1)) - sexp_raise("char-upcase: not a character", sexp_list1(ctx, _ARG1)); - _ARG1 = sexp_make_character(toupper(sexp_unbox_character(_ARG1))); - break; - case SEXP_OP_CHAR_DOWNCASE: - if (! sexp_charp(_ARG1)) - sexp_raise("char-downcase: not a character", sexp_list1(ctx, _ARG1)); - _ARG1 = sexp_make_character(tolower(sexp_unbox_character(_ARG1))); - break; - case SEXP_OP_WRITE_CHAR: - if (! sexp_charp(_ARG1)) - sexp_raise("write-char: not a character", sexp_list1(ctx, _ARG1)); - if (! sexp_oportp(_ARG2)) - sexp_raise("write-char: not an output-port", sexp_list1(ctx, _ARG2)); - sexp_write_char(ctx, sexp_unbox_character(_ARG1), _ARG2); - _ARG2 = SEXP_VOID; - top--; - break; - case SEXP_OP_NEWLINE: - if (! sexp_oportp(_ARG1)) - sexp_raise("newline: not an output-port", sexp_list1(ctx, _ARG1)); - sexp_newline(ctx, _ARG1); - _ARG1 = SEXP_VOID; - break; - case SEXP_OP_READ_CHAR: - if (! sexp_iportp(_ARG1)) - sexp_raise("read-char: not an intput-port", sexp_list1(ctx, _ARG1)); - i = sexp_read_char(ctx, _ARG1); - _ARG1 = (i == EOF) ? SEXP_EOF : sexp_make_character(i); - break; - case SEXP_OP_PEEK_CHAR: - if (! sexp_iportp(_ARG1)) - sexp_raise("peek-char: not an intput-port", sexp_list1(ctx, _ARG1)); - i = sexp_read_char(ctx, _ARG1); - sexp_push_char(ctx, i, _ARG1); - _ARG1 = (i == EOF) ? SEXP_EOF : sexp_make_character(i); - break; - case SEXP_OP_RET: - i = sexp_unbox_fixnum(stack[fp]); - stack[fp-i] = _ARG1; - top = fp-i+1; - self = stack[fp+2]; - bc = sexp_procedure_code(self); - ip = sexp_bytecode_data(bc) + sexp_unbox_fixnum(stack[fp+1]); - cp = sexp_procedure_vars(self); - fp = sexp_unbox_fixnum(stack[fp+3]); - break; - case SEXP_OP_DONE: - goto end_loop; - default: - sexp_raise("unknown opcode", sexp_list1(ctx, sexp_make_fixnum(*(ip-1)))); - } - goto loop; - - end_loop: - sexp_gc_release3(ctx); - sexp_context_top(ctx) = top; - return _ARG1; -} +#include "vm.c" /************************ library procedures **************************/ diff --git a/vm.c b/vm.c new file mode 100644 index 00000000..e0edd053 --- /dev/null +++ b/vm.c @@ -0,0 +1,797 @@ +/* vm.c -- stack-based virtual machine backend */ +/* Copyright (c) 2009-2010 Alex Shinn. All rights reserved. */ +/* BSD-style license: http://synthcode.com/license.txt */ + +/*********************** the virtual machine **************************/ + +static sexp sexp_save_stack (sexp ctx, sexp *stack, sexp_uint_t to) { + sexp res, *data; + sexp_uint_t i; + res = sexp_make_vector(ctx, sexp_make_fixnum(to), SEXP_VOID); + data = sexp_vector_data(res); + for (i=0; i= SEXP_INIT_STACK_SIZE) { + _ARG1 = sexp_global(ctx, SEXP_G_OOS_ERROR); + goto end_loop; + } +#endif + _ALIGN_IP(); + i = sexp_unbox_fixnum(_WORD0); + tmp1 = _ARG1; + make_call: + if (sexp_opcodep(tmp1)) { + /* compile non-inlined opcode applications on the fly */ + sexp_context_top(ctx) = top; + tmp1 = make_opcode_procedure(ctx, tmp1, i); + if (sexp_exceptionp(tmp1)) { + _ARG1 = tmp1; + goto call_error_handler; + } + } + if (! sexp_procedurep(tmp1)) + sexp_raise("non procedure application", sexp_list1(ctx, tmp1)); + j = i - sexp_unbox_fixnum(sexp_procedure_num_args(tmp1)); + if (j < 0) + sexp_raise("not enough args", + sexp_list2(ctx, tmp1, sexp_make_fixnum(i))); + if (j > 0) { + if (sexp_procedure_variadic_p(tmp1)) { + stack[top-i-1] = sexp_cons(ctx, stack[top-i-1], SEXP_NULL); + for (k=top-i; k=top-i; k--) + stack[k] = stack[k-1]; + stack[top-i-1] = SEXP_NULL; + top++; + i++; + } + _ARG1 = sexp_make_fixnum(i); + stack[top] = sexp_make_fixnum(ip+sizeof(sexp)-sexp_bytecode_data(bc)); + stack[top+1] = self; + stack[top+2] = sexp_make_fixnum(fp); + top += 3; + self = tmp1; + bc = sexp_procedure_code(self); + ip = sexp_bytecode_data(bc); + cp = sexp_procedure_vars(self); + fp = top-4; + break; + case SEXP_OP_FCALL0: + _ALIGN_IP(); + sexp_context_top(ctx) = top; + _PUSH(((sexp_proc1)sexp_opcode_func(_WORD0))(ctx sexp_api_pass(_WORD0, 0))); + ip += sizeof(sexp); + sexp_check_exception(); + break; + case SEXP_OP_FCALL1: + _ALIGN_IP(); + sexp_context_top(ctx) = top; + _ARG1 = ((sexp_proc2)sexp_opcode_func(_WORD0))(ctx sexp_api_pass(_WORD0, 1), _ARG1); + ip += sizeof(sexp); + sexp_check_exception(); + break; + case SEXP_OP_FCALL2: + _ALIGN_IP(); + sexp_context_top(ctx) = top; + _ARG2 = ((sexp_proc3)sexp_opcode_func(_WORD0))(ctx sexp_api_pass(_WORD0, 2), _ARG1, _ARG2); + top--; + ip += sizeof(sexp); + sexp_check_exception(); + break; + case SEXP_OP_FCALL3: + _ALIGN_IP(); + sexp_context_top(ctx) = top; + _ARG3 = ((sexp_proc4)sexp_opcode_func(_WORD0))(ctx sexp_api_pass(_WORD0, 3), _ARG1, _ARG2, _ARG3); + top -= 2; + ip += sizeof(sexp); + sexp_check_exception(); + break; + case SEXP_OP_FCALL4: + _ALIGN_IP(); + sexp_context_top(ctx) = top; + _ARG4 = ((sexp_proc5)sexp_opcode_func(_WORD0))(ctx sexp_api_pass(_WORD0, 4), _ARG1, _ARG2, _ARG3, _ARG4); + top -= 3; + ip += sizeof(sexp); + sexp_check_exception(); + break; + case SEXP_OP_FCALL5: + _ALIGN_IP(); + sexp_context_top(ctx) = top; + _ARG5 = ((sexp_proc6)sexp_opcode_func(_WORD0))(ctx sexp_api_pass(_WORD0, 5), _ARG1, _ARG2, _ARG3, _ARG4, _ARG5); + top -= 4; + ip += sizeof(sexp); + sexp_check_exception(); + break; + case SEXP_OP_FCALL6: + _ALIGN_IP(); + sexp_context_top(ctx) = top; + _ARG6 = ((sexp_proc7)sexp_opcode_func(_WORD0))(ctx sexp_api_pass(_WORD0, 6), _ARG1, _ARG2, _ARG3, _ARG4, _ARG5, _ARG6); + top -= 5; + ip += sizeof(sexp); + sexp_check_exception(); + break; + case SEXP_OP_JUMP_UNLESS: + _ALIGN_IP(); + if (stack[--top] == SEXP_FALSE) + ip += _SWORD0; + else + ip += sizeof(sexp_sint_t); + break; + case SEXP_OP_JUMP: + _ALIGN_IP(); + ip += _SWORD0; + break; + case SEXP_OP_PUSH: + _ALIGN_IP(); + _PUSH(_WORD0); + ip += sizeof(sexp); + break; + case SEXP_OP_DROP: + top--; + break; + case SEXP_OP_GLOBAL_REF: + _ALIGN_IP(); + if (sexp_cdr(_WORD0) == SEXP_UNDEF) + sexp_raise("undefined variable", sexp_list1(ctx, sexp_car(_WORD0))); + /* ... FALLTHROUGH ... */ + case SEXP_OP_GLOBAL_KNOWN_REF: + _ALIGN_IP(); + _PUSH(sexp_cdr(_WORD0)); + ip += sizeof(sexp); + break; + case SEXP_OP_STACK_REF: /* `pick' in forth */ + _ALIGN_IP(); + stack[top] = stack[top - _SWORD0]; + ip += sizeof(sexp); + top++; + break; + case SEXP_OP_LOCAL_REF: + _ALIGN_IP(); + stack[top] = stack[fp - 1 - _SWORD0]; + ip += sizeof(sexp); + top++; + break; + case SEXP_OP_LOCAL_SET: + _ALIGN_IP(); + stack[fp - 1 - _SWORD0] = _ARG1; + _ARG1 = SEXP_VOID; + ip += sizeof(sexp); + break; + case SEXP_OP_CLOSURE_REF: + _ALIGN_IP(); + _PUSH(sexp_vector_ref(cp, sexp_make_fixnum(_WORD0))); + ip += sizeof(sexp); + break; + case SEXP_OP_VECTOR_REF: + if (! sexp_vectorp(_ARG1)) + sexp_raise("vector-ref: not a vector", sexp_list1(ctx, _ARG1)); + else if (! sexp_fixnump(_ARG2)) + sexp_raise("vector-ref: not an integer", sexp_list1(ctx, _ARG2)); + i = sexp_unbox_fixnum(_ARG2); + if ((i < 0) || (i >= sexp_vector_length(_ARG1))) + sexp_raise("vector-ref: index out of range", sexp_list2(ctx, _ARG1, _ARG2)); + _ARG2 = sexp_vector_ref(_ARG1, _ARG2); + top--; + break; + case SEXP_OP_VECTOR_SET: + if (! sexp_vectorp(_ARG1)) + sexp_raise("vector-set!: not a vector", sexp_list1(ctx, _ARG1)); + else if (sexp_immutablep(_ARG1)) + sexp_raise("vector-set!: immutable vector", sexp_list1(ctx, _ARG1)); + else if (! sexp_fixnump(_ARG2)) + sexp_raise("vector-set!: not an integer", sexp_list1(ctx, _ARG2)); + i = sexp_unbox_fixnum(_ARG2); + if ((i < 0) || (i >= sexp_vector_length(_ARG1))) + sexp_raise("vector-set!: index out of range", sexp_list2(ctx, _ARG1, _ARG2)); + sexp_vector_set(_ARG1, _ARG2, _ARG3); + _ARG3 = SEXP_VOID; + top-=2; + break; + case SEXP_OP_VECTOR_LENGTH: + if (! sexp_vectorp(_ARG1)) + sexp_raise("vector-length: not a vector", sexp_list1(ctx, _ARG1)); + _ARG1 = sexp_make_fixnum(sexp_vector_length(_ARG1)); + break; + case SEXP_OP_STRING_REF: + if (! sexp_stringp(_ARG1)) + sexp_raise("string-ref: not a string", sexp_list1(ctx, _ARG1)); + else if (! sexp_fixnump(_ARG2)) + sexp_raise("string-ref: not an integer", sexp_list1(ctx, _ARG2)); + i = sexp_unbox_fixnum(_ARG2); + if ((i < 0) || (i >= sexp_string_length(_ARG1))) + sexp_raise("string-ref: index out of range", sexp_list2(ctx, _ARG1, _ARG2)); + _ARG2 = sexp_string_ref(_ARG1, _ARG2); + top--; + break; + case SEXP_OP_STRING_SET: + if (! sexp_stringp(_ARG1)) + sexp_raise("string-set!: not a string", sexp_list1(ctx, _ARG1)); + else if (sexp_immutablep(_ARG1)) + sexp_raise("string-set!: immutable string", sexp_list1(ctx, _ARG1)); + else if (! sexp_fixnump(_ARG2)) + sexp_raise("string-set!: not an integer", sexp_list1(ctx, _ARG2)); + else if (! sexp_charp(_ARG3)) + sexp_raise("string-set!: not a char", sexp_list1(ctx, _ARG3)); + i = sexp_unbox_fixnum(_ARG2); + if ((i < 0) || (i >= sexp_string_length(_ARG1))) + sexp_raise("string-set!: index out of range", sexp_list2(ctx, _ARG1, _ARG2)); + sexp_string_set(_ARG1, _ARG2, _ARG3); + _ARG3 = SEXP_VOID; + top-=2; + break; + case SEXP_OP_STRING_LENGTH: + if (! sexp_stringp(_ARG1)) + sexp_raise("string-length: not a string", sexp_list1(ctx, _ARG1)); + _ARG1 = sexp_make_fixnum(sexp_string_length(_ARG1)); + break; + case SEXP_OP_MAKE_PROCEDURE: + sexp_context_top(ctx) = top; + _ARG4 = sexp_make_procedure(ctx, _ARG1, _ARG2, _ARG3, _ARG4); + top-=3; + break; + case SEXP_OP_MAKE_VECTOR: + sexp_context_top(ctx) = top; + if (! sexp_fixnump(_ARG1)) + sexp_raise("make-vector: not an integer", sexp_list1(ctx, _ARG1)); + _ARG2 = sexp_make_vector(ctx, _ARG1, _ARG2); + top--; + break; + case SEXP_OP_MAKE_EXCEPTION: + _ARG5 = sexp_make_exception(ctx, _ARG1, _ARG2, _ARG3, _ARG4, _ARG5); + top -= 4; + break; + case SEXP_OP_AND: + _ARG2 = sexp_make_boolean((_ARG1 != SEXP_FALSE) && (_ARG2 != SEXP_FALSE)); + top--; + break; + case SEXP_OP_EOFP: + _ARG1 = sexp_make_boolean(_ARG1 == SEXP_EOF); break; + case SEXP_OP_NULLP: + _ARG1 = sexp_make_boolean(sexp_nullp(_ARG1)); break; + case SEXP_OP_FIXNUMP: + _ARG1 = sexp_make_boolean(sexp_fixnump(_ARG1)); break; + case SEXP_OP_SYMBOLP: + _ARG1 = sexp_make_boolean(sexp_symbolp(_ARG1)); break; + case SEXP_OP_CHARP: + _ARG1 = sexp_make_boolean(sexp_charp(_ARG1)); break; + case SEXP_OP_TYPEP: + _ALIGN_IP(); + _ARG1 = sexp_make_boolean(sexp_check_tag(_ARG1, _UWORD0)); + ip += sizeof(sexp); + break; + case SEXP_OP_MAKE: + _ALIGN_IP(); + _PUSH(sexp_alloc_tagged(ctx, _UWORD1, _UWORD0)); + ip += sizeof(sexp)*2; + break; + case SEXP_OP_SLOT_REF: + _ALIGN_IP(); + if (! sexp_check_tag(_ARG1, _UWORD0)) + sexp_raise("slot-ref: bad type", sexp_list2(ctx, sexp_c_string(ctx, sexp_type_name_by_index(ctx, _UWORD0), -1), _ARG1)); + _ARG1 = sexp_slot_ref(_ARG1, _UWORD1); + ip += sizeof(sexp)*2; + break; + case SEXP_OP_SLOT_SET: + _ALIGN_IP(); + if (! sexp_check_tag(_ARG1, _UWORD0)) + sexp_raise("slot-set!: bad type", sexp_list2(ctx, sexp_c_string(ctx, sexp_type_name_by_index(ctx, _UWORD0), -1), _ARG1)); + else if (sexp_immutablep(_ARG1)) + sexp_raise("slot-set!: immutable object", sexp_list1(ctx, _ARG1)); + sexp_slot_set(_ARG1, _UWORD1, _ARG2); + _ARG2 = SEXP_VOID; + ip += sizeof(sexp)*2; + top--; + break; + case SEXP_OP_CAR: + if (! sexp_pairp(_ARG1)) + sexp_raise("car: not a pair", sexp_list1(ctx, _ARG1)); + _ARG1 = sexp_car(_ARG1); break; + case SEXP_OP_CDR: + if (! sexp_pairp(_ARG1)) + sexp_raise("cdr: not a pair", sexp_list1(ctx, _ARG1)); + _ARG1 = sexp_cdr(_ARG1); break; + case SEXP_OP_SET_CAR: + if (! sexp_pairp(_ARG1)) + sexp_raise("set-car!: not a pair", sexp_list1(ctx, _ARG1)); + else if (sexp_immutablep(_ARG1)) + sexp_raise("set-car!: immutable pair", sexp_list1(ctx, _ARG1)); + sexp_car(_ARG1) = _ARG2; + _ARG2 = SEXP_VOID; + top--; + break; + case SEXP_OP_SET_CDR: + if (! sexp_pairp(_ARG1)) + sexp_raise("set-cdr!: not a pair", sexp_list1(ctx, _ARG1)); + else if (sexp_immutablep(_ARG1)) + sexp_raise("set-cdr!: immutable pair", sexp_list1(ctx, _ARG1)); + sexp_cdr(_ARG1) = _ARG2; + _ARG2 = SEXP_VOID; + top--; + break; + case SEXP_OP_CONS: + sexp_context_top(ctx) = top; + _ARG2 = sexp_cons(ctx, _ARG1, _ARG2); + top--; + break; + case SEXP_OP_ADD: +#if SEXP_USE_BIGNUMS + tmp1 = _ARG1, tmp2 = _ARG2; + sexp_context_top(ctx) = top; + if (sexp_fixnump(tmp1) && sexp_fixnump(tmp2)) { + j = sexp_unbox_fixnum(tmp1) + sexp_unbox_fixnum(tmp2); + if ((j < SEXP_MIN_FIXNUM) || (j > SEXP_MAX_FIXNUM)) + _ARG2 = sexp_add(ctx, tmp1=sexp_fixnum_to_bignum(ctx, tmp1), tmp2); + else + _ARG2 = sexp_make_fixnum(j); + } + else + _ARG2 = sexp_add(ctx, tmp1, tmp2); +#else + if (sexp_fixnump(_ARG1) && sexp_fixnump(_ARG2)) + _ARG2 = sexp_fx_add(_ARG1, _ARG2); +#if SEXP_USE_FLONUMS + else if (sexp_flonump(_ARG1) && sexp_flonump(_ARG2)) + _ARG2 = sexp_fp_add(ctx, _ARG1, _ARG2); + else if (sexp_flonump(_ARG1) && sexp_fixnump(_ARG2)) + _ARG2 = sexp_make_flonum(ctx, sexp_flonum_value(_ARG1) + (double)sexp_unbox_fixnum(_ARG2)); + else if (sexp_fixnump(_ARG1) && sexp_flonump(_ARG2)) + _ARG2 = sexp_make_flonum(ctx, (double)sexp_unbox_fixnum(_ARG1) + sexp_flonum_value(_ARG2)); +#endif + else sexp_raise("+: not a number", sexp_list2(ctx, _ARG1, _ARG2)); +#endif + top--; + break; + case SEXP_OP_SUB: +#if SEXP_USE_BIGNUMS + tmp1 = _ARG1, tmp2 = _ARG2; + sexp_context_top(ctx) = top; + if (sexp_fixnump(tmp1) && sexp_fixnump(tmp2)) { + j = sexp_unbox_fixnum(tmp1) - sexp_unbox_fixnum(tmp2); + if ((j < SEXP_MIN_FIXNUM) || (j > SEXP_MAX_FIXNUM)) + _ARG2 = sexp_sub(ctx, tmp1=sexp_fixnum_to_bignum(ctx, tmp1), tmp2); + else + _ARG2 = sexp_make_fixnum(j); + } + else + _ARG2 = sexp_sub(ctx, tmp1, tmp2); +#else + if (sexp_fixnump(_ARG1) && sexp_fixnump(_ARG2)) + _ARG2 = sexp_fx_sub(_ARG1, _ARG2); +#if SEXP_USE_FLONUMS + else if (sexp_flonump(_ARG1) && sexp_flonump(_ARG2)) + _ARG2 = sexp_fp_sub(ctx, _ARG1, _ARG2); + else if (sexp_flonump(_ARG1) && sexp_fixnump(_ARG2)) + _ARG2 = sexp_make_flonum(ctx, sexp_flonum_value(_ARG1) - (double)sexp_unbox_fixnum(_ARG2)); + else if (sexp_fixnump(_ARG1) && sexp_flonump(_ARG2)) + _ARG2 = sexp_make_flonum(ctx, (double)sexp_unbox_fixnum(_ARG1) - sexp_flonum_value(_ARG2)); +#endif + else sexp_raise("-: not a number", sexp_list2(ctx, _ARG1, _ARG2)); +#endif + top--; + break; + case SEXP_OP_MUL: +#if SEXP_USE_BIGNUMS + tmp1 = _ARG1, tmp2 = _ARG2; + sexp_context_top(ctx) = top; + if (sexp_fixnump(tmp1) && sexp_fixnump(tmp2)) { + prod = (sexp_lsint_t)sexp_unbox_fixnum(tmp1) * sexp_unbox_fixnum(tmp2); + if ((prod < SEXP_MIN_FIXNUM) || (prod > SEXP_MAX_FIXNUM)) + _ARG2 = sexp_mul(ctx, tmp1=sexp_fixnum_to_bignum(ctx, tmp1), tmp2); + else + _ARG2 = sexp_make_fixnum(prod); + } + else + _ARG2 = sexp_mul(ctx, tmp1, tmp2); +#else + if (sexp_fixnump(_ARG1) && sexp_fixnump(_ARG2)) + _ARG2 = sexp_fx_mul(_ARG1, _ARG2); +#if SEXP_USE_FLONUMS + else if (sexp_flonump(_ARG1) && sexp_flonump(_ARG2)) + _ARG2 = sexp_fp_mul(ctx, _ARG1, _ARG2); + else if (sexp_flonump(_ARG1) && sexp_fixnump(_ARG2)) + _ARG2 = sexp_make_flonum(ctx, sexp_flonum_value(_ARG1) * (double)sexp_unbox_fixnum(_ARG2)); + else if (sexp_fixnump(_ARG1) && sexp_flonump(_ARG2)) + _ARG2 = sexp_make_flonum(ctx, (double)sexp_unbox_fixnum(_ARG1) * sexp_flonum_value(_ARG2)); +#endif + else sexp_raise("*: not a number", sexp_list2(ctx, _ARG1, _ARG2)); +#endif + top--; + break; + case SEXP_OP_DIV: + sexp_context_top(ctx) = top; + if (_ARG2 == SEXP_ZERO) { +#if SEXP_USE_FLONUMS + if (sexp_flonump(_ARG1) && sexp_flonum_value(_ARG1) == 0.0) + _ARG2 = sexp_make_flonum(ctx, 0.0/0.0); + else +#endif + sexp_raise("divide by zero", SEXP_NULL); + } else if (sexp_fixnump(_ARG1) && sexp_fixnump(_ARG2)) { +#if SEXP_USE_FLONUMS + _ARG1 = sexp_fixnum_to_flonum(ctx, _ARG1); + _ARG2 = sexp_fixnum_to_flonum(ctx, _ARG2); + _ARG2 = sexp_fp_div(ctx, _ARG1, _ARG2); + if (sexp_flonum_value(_ARG2) == trunc(sexp_flonum_value(_ARG2))) + _ARG2 = sexp_make_fixnum(sexp_flonum_value(_ARG2)); +#else + _ARG2 = sexp_fx_div(_ARG1, _ARG2); +#endif + } +#if SEXP_USE_BIGNUMS + else + _ARG2 = sexp_div(ctx, _ARG1, _ARG2); +#else +#if SEXP_USE_FLONUMS + else if (sexp_flonump(_ARG1) && sexp_flonump(_ARG2)) + _ARG2 = sexp_fp_div(ctx, _ARG1, _ARG2); + else if (sexp_flonump(_ARG1) && sexp_fixnump(_ARG2)) + _ARG2 = sexp_make_flonum(ctx, sexp_flonum_value(_ARG1) / (double)sexp_unbox_fixnum(_ARG2)); + else if (sexp_fixnump(_ARG1) && sexp_flonump(_ARG2)) + _ARG2 = sexp_make_flonum(ctx, (double)sexp_unbox_fixnum(_ARG1) / sexp_flonum_value(_ARG2)); +#endif + else sexp_raise("/: not a number", sexp_list2(ctx, _ARG1, _ARG2)); +#endif + top--; + break; + case SEXP_OP_QUOTIENT: + if (sexp_fixnump(_ARG1) && sexp_fixnump(_ARG2)) { + if (_ARG2 == SEXP_ZERO) + sexp_raise("divide by zero", SEXP_NULL); + _ARG2 = sexp_fx_div(_ARG1, _ARG2); + top--; + } +#if SEXP_USE_BIGNUMS + else { + sexp_context_top(ctx) = top; + _ARG2 = sexp_quotient(ctx, _ARG1, _ARG2); + top--; + } +#else + else sexp_raise("quotient: not an integer", sexp_list2(ctx, _ARG1, _ARG2)); +#endif + break; + case SEXP_OP_REMAINDER: + if (sexp_fixnump(_ARG1) && sexp_fixnump(_ARG2)) { + if (_ARG2 == SEXP_ZERO) + sexp_raise("divide by zero", SEXP_NULL); + tmp1 = sexp_fx_rem(_ARG1, _ARG2); + top--; + _ARG1 = tmp1; + } +#if SEXP_USE_BIGNUMS + else { + sexp_context_top(ctx) = top; + _ARG2 = sexp_remainder(ctx, _ARG1, _ARG2); + top--; + } +#else + else sexp_raise("remainder: not an integer", sexp_list2(ctx, _ARG1, _ARG2)); +#endif + break; + case SEXP_OP_LT: + if (sexp_fixnump(_ARG1) && sexp_fixnump(_ARG2)) { + i = (sexp_sint_t)_ARG1 < (sexp_sint_t)_ARG2; +#if SEXP_USE_BIGNUMS + _ARG2 = sexp_make_boolean(i); + } else { + tmp1 = sexp_compare(ctx, _ARG1, _ARG2); + _ARG2 = sexp_fixnump(tmp1) + ? sexp_make_boolean(sexp_unbox_fixnum(tmp1) < 0) : tmp1; + } +#else +#if SEXP_USE_FLONUMS + } else if (sexp_flonump(_ARG1) && sexp_flonump(_ARG2)) { + i = sexp_flonum_value(_ARG1) < sexp_flonum_value(_ARG2); + } else if (sexp_flonump(_ARG1) && sexp_fixnump(_ARG2)) { + i = sexp_flonum_value(_ARG1) < (double)sexp_unbox_fixnum(_ARG2); + } else if (sexp_fixnump(_ARG1) && sexp_flonump(_ARG2)) { + i = (double)sexp_unbox_fixnum(_ARG1) < sexp_flonum_value(_ARG2); +#endif + } else sexp_raise("<: not a number", sexp_list2(ctx, _ARG1, _ARG2)); + _ARG2 = sexp_make_boolean(i); +#endif + top--; + break; + case SEXP_OP_LE: + if (sexp_fixnump(_ARG1) && sexp_fixnump(_ARG2)) { + i = (sexp_sint_t)_ARG1 <= (sexp_sint_t)_ARG2; +#if SEXP_USE_BIGNUMS + _ARG2 = sexp_make_boolean(i); + } else { + tmp1 = sexp_compare(ctx, _ARG1, _ARG2); + _ARG2 = sexp_fixnump(tmp1) + ? sexp_make_boolean(sexp_unbox_fixnum(tmp1) <= 0) : tmp1; + } +#else +#if SEXP_USE_FLONUMS + } else if (sexp_flonump(_ARG1) && sexp_flonump(_ARG2)) { + i = sexp_flonum_value(_ARG1) <= sexp_flonum_value(_ARG2); + } else if (sexp_flonump(_ARG1) && sexp_fixnump(_ARG2)) { + i = sexp_flonum_value(_ARG1) <= (double)sexp_unbox_fixnum(_ARG2); + } else if (sexp_fixnump(_ARG1) && sexp_flonump(_ARG2)) { + i = (double)sexp_unbox_fixnum(_ARG1) <= sexp_flonum_value(_ARG2); +#endif + } else sexp_raise("<=: not a number", sexp_list2(ctx, _ARG1, _ARG2)); + _ARG2 = sexp_make_boolean(i); +#endif + top--; + break; + case SEXP_OP_EQN: + if (sexp_fixnump(_ARG1) && sexp_fixnump(_ARG2)) { + i = _ARG1 == _ARG2; +#if SEXP_USE_BIGNUMS + _ARG2 = sexp_make_boolean(i); + } else { + tmp1 = sexp_compare(ctx, _ARG1, _ARG2); + _ARG2 = sexp_fixnump(tmp1) + ? sexp_make_boolean(sexp_unbox_fixnum(tmp1) == 0) : tmp1; + } +#else +#if SEXP_USE_FLONUMS + } else if (sexp_flonump(_ARG1) && sexp_flonump(_ARG2)) { + i = sexp_flonum_value(_ARG1) == sexp_flonum_value(_ARG2); + } else if (sexp_flonump(_ARG1) && sexp_fixnump(_ARG2)) { + i = sexp_flonum_value(_ARG1) == (double)sexp_unbox_fixnum(_ARG2); + } else if (sexp_fixnump(_ARG1) && sexp_flonump(_ARG2)) { + i = (double)sexp_unbox_fixnum(_ARG1) == sexp_flonum_value(_ARG2); +#endif + } else sexp_raise("=: not a number", sexp_list2(ctx, _ARG1, _ARG2)); + _ARG2 = sexp_make_boolean(i); +#endif + top--; + break; + case SEXP_OP_EQ: + _ARG2 = sexp_make_boolean(_ARG1 == _ARG2); + top--; + break; + case SEXP_OP_FIX2FLO: + if (sexp_fixnump(_ARG1)) + _ARG1 = sexp_fixnum_to_flonum(ctx, _ARG1); +#if SEXP_USE_BIGNUMS + else if (sexp_bignump(_ARG1)) + _ARG1 = sexp_make_flonum(ctx, sexp_bignum_to_double(_ARG1)); +#endif + else if (! sexp_flonump(_ARG1)) + sexp_raise("exact->inexact: not a number", sexp_list1(ctx, _ARG1)); + break; + case SEXP_OP_FLO2FIX: + if (sexp_flonump(_ARG1)) { + if (sexp_flonum_value(_ARG1) != trunc(sexp_flonum_value(_ARG1))) { + sexp_raise("inexact->exact: not an integer", sexp_list1(ctx, _ARG1)); +#if SEXP_USE_BIGNUMS + } else if ((sexp_flonum_value(_ARG1) > SEXP_MAX_FIXNUM) + || sexp_flonum_value(_ARG1) < SEXP_MIN_FIXNUM) { + _ARG1 = sexp_double_to_bignum(ctx, sexp_flonum_value(_ARG1)); +#endif + } else { + _ARG1 = sexp_make_fixnum((sexp_sint_t)sexp_flonum_value(_ARG1)); + } + } else if (! sexp_fixnump(_ARG1) && ! sexp_bignump(_ARG1)) { + sexp_raise("inexact->exact: not a number", sexp_list1(ctx, _ARG1)); + } + break; + case SEXP_OP_CHAR2INT: + if (! sexp_charp(_ARG1)) + sexp_raise("char->integer: not a character", sexp_list1(ctx, _ARG1)); + _ARG1 = sexp_make_fixnum(sexp_unbox_character(_ARG1)); + break; + case SEXP_OP_INT2CHAR: + if (! sexp_fixnump(_ARG1)) + sexp_raise("integer->char: not an integer", sexp_list1(ctx, _ARG1)); + _ARG1 = sexp_make_character(sexp_unbox_fixnum(_ARG1)); + break; + case SEXP_OP_CHAR_UPCASE: + if (! sexp_charp(_ARG1)) + sexp_raise("char-upcase: not a character", sexp_list1(ctx, _ARG1)); + _ARG1 = sexp_make_character(toupper(sexp_unbox_character(_ARG1))); + break; + case SEXP_OP_CHAR_DOWNCASE: + if (! sexp_charp(_ARG1)) + sexp_raise("char-downcase: not a character", sexp_list1(ctx, _ARG1)); + _ARG1 = sexp_make_character(tolower(sexp_unbox_character(_ARG1))); + break; + case SEXP_OP_WRITE_CHAR: + if (! sexp_charp(_ARG1)) + sexp_raise("write-char: not a character", sexp_list1(ctx, _ARG1)); + if (! sexp_oportp(_ARG2)) + sexp_raise("write-char: not an output-port", sexp_list1(ctx, _ARG2)); + sexp_write_char(ctx, sexp_unbox_character(_ARG1), _ARG2); + _ARG2 = SEXP_VOID; + top--; + break; + case SEXP_OP_NEWLINE: + if (! sexp_oportp(_ARG1)) + sexp_raise("newline: not an output-port", sexp_list1(ctx, _ARG1)); + sexp_newline(ctx, _ARG1); + _ARG1 = SEXP_VOID; + break; + case SEXP_OP_READ_CHAR: + if (! sexp_iportp(_ARG1)) + sexp_raise("read-char: not an intput-port", sexp_list1(ctx, _ARG1)); + i = sexp_read_char(ctx, _ARG1); + _ARG1 = (i == EOF) ? SEXP_EOF : sexp_make_character(i); + break; + case SEXP_OP_PEEK_CHAR: + if (! sexp_iportp(_ARG1)) + sexp_raise("peek-char: not an intput-port", sexp_list1(ctx, _ARG1)); + i = sexp_read_char(ctx, _ARG1); + sexp_push_char(ctx, i, _ARG1); + _ARG1 = (i == EOF) ? SEXP_EOF : sexp_make_character(i); + break; + case SEXP_OP_RET: + i = sexp_unbox_fixnum(stack[fp]); + stack[fp-i] = _ARG1; + top = fp-i+1; + self = stack[fp+2]; + bc = sexp_procedure_code(self); + ip = sexp_bytecode_data(bc) + sexp_unbox_fixnum(stack[fp+1]); + cp = sexp_procedure_vars(self); + fp = sexp_unbox_fixnum(stack[fp+3]); + break; + case SEXP_OP_DONE: + goto end_loop; + default: + sexp_raise("unknown opcode", sexp_list1(ctx, sexp_make_fixnum(*(ip-1)))); + } + goto loop; + + end_loop: + sexp_gc_release3(ctx); + sexp_context_top(ctx) = top; + return _ARG1; +} +