/* eval.c -- evaluator library implementation */ /* Copyright (c) 2009 Alex Shinn. All rights reserved. */ /* BSD-style license: http://synthcode.com/license.txt */ #include "chibi/eval.h" /************************************************************************/ static int scheme_initialized_p = 0; #if SEXP_USE_DEBUG_VM static void sexp_print_stack (sexp ctx, sexp *stack, int top, int fp, sexp out) { int i; if (! sexp_oportp(out)) out = sexp_current_error_port(ctx); for (i=0; i sexp_opcode_num_args(op)) && (! sexp_opcode_variadic_p(op))) { res = sexp_compile_error(ctx, "too many args for opcode", x); } else { res = analyze_app(ctx, sexp_cdr(x)); if (! sexp_exceptionp(res)) sexp_push(ctx, res, op); } } else { res = analyze_app(ctx, x); } } } else if (sexp_truep(sexp_listp(ctx, sexp_car(x))) || (sexp_synclop(sexp_car(x)) && sexp_truep(sexp_listp(ctx, sexp_synclo_expr(sexp_car(x)))))) { res = analyze_app(ctx, x); } else { res = sexp_compile_error(ctx, "invalid operand in application", x); } } else if (sexp_idp(x)) { res = analyze_var_ref(ctx, x, NULL); } else if (sexp_synclop(x)) { tmp = sexp_make_child_context(ctx, sexp_context_lambda(ctx)); sexp_context_env(tmp) = sexp_synclo_env(x); sexp_context_fv(tmp) = sexp_append2(tmp, sexp_synclo_free_vars(x), sexp_context_fv(tmp)); x = sexp_synclo_expr(x); res = analyze(tmp, x); } else { res = x; } if (sexp_exceptionp(res) && sexp_not(sexp_exception_source(res)) && sexp_pairp(x)) sexp_exception_source(res) = sexp_pair_source(x); sexp_gc_release4(ctx); return res; } sexp sexp_analyze (sexp ctx, sexp x) {return analyze(ctx, x);} static sexp_sint_t sexp_context_make_label (sexp ctx) { sexp_sint_t label; sexp_context_align_pos(ctx); label = sexp_context_pos(ctx); sexp_context_pos(ctx) += sizeof(sexp_uint_t); return label; } static void sexp_context_patch_label (sexp ctx, sexp_sint_t label) { sexp bc = sexp_context_bc(ctx); unsigned char *data = sexp_bytecode_data(bc)+label; *((sexp_sint_t*)data) = sexp_context_pos(ctx)-label; } static void generate_lit (sexp ctx, sexp value) { emit_push(ctx, value); } static void generate_seq (sexp ctx, sexp app) { sexp head=app, tail=sexp_cdr(app); sexp_uint_t tailp = sexp_context_tailp(ctx); sexp_context_tailp(ctx) = 0; for ( ; sexp_pairp(tail); head=tail, tail=sexp_cdr(tail)) if (sexp_pointerp(sexp_car(head)) && (! sexp_litp(sexp_car(head)))) { generate(ctx, sexp_car(head)); emit(ctx, SEXP_OP_DROP); sexp_context_depth(ctx)--; } sexp_context_tailp(ctx) = tailp; generate(ctx, sexp_car(head)); } static void generate_cnd (sexp ctx, sexp cnd) { sexp_sint_t label1, label2, tailp=sexp_context_tailp(ctx); sexp_context_tailp(ctx) = 0; generate(ctx, sexp_cnd_test(cnd)); sexp_context_tailp(ctx) = tailp; emit(ctx, SEXP_OP_JUMP_UNLESS); sexp_context_depth(ctx)--; label1 = sexp_context_make_label(ctx); generate(ctx, sexp_cnd_pass(cnd)); sexp_context_tailp(ctx) = tailp; emit(ctx, SEXP_OP_JUMP); sexp_context_depth(ctx)--; label2 = sexp_context_make_label(ctx); sexp_context_patch_label(ctx, label1); generate(ctx, sexp_cnd_fail(cnd)); sexp_context_patch_label(ctx, label2); } static void generate_non_global_ref (sexp ctx, sexp name, sexp cell, sexp lambda, sexp fv, int unboxp) { sexp_uint_t i; sexp loc = sexp_cdr(cell); if (loc == lambda && sexp_lambdap(lambda)) { /* local ref */ emit(ctx, SEXP_OP_LOCAL_REF); emit_word(ctx, sexp_param_index(lambda, name)); } else { /* closure ref */ for (i=0; sexp_pairp(fv); fv=sexp_cdr(fv), i++) if ((name == sexp_ref_name(sexp_car(fv))) && (loc == sexp_ref_loc(sexp_car(fv)))) break; emit(ctx, SEXP_OP_CLOSURE_REF); emit_word(ctx, i); } if (unboxp && (sexp_memq(ctx, name, sexp_lambda_sv(loc)) != SEXP_FALSE)) emit(ctx, SEXP_OP_CDR); sexp_context_depth(ctx)++; } static void generate_ref (sexp ctx, sexp ref, int unboxp) { sexp lam; if (! sexp_lambdap(sexp_ref_loc(ref))) { /* global ref */ if (unboxp) { emit(ctx, (sexp_cdr(sexp_ref_cell(ref)) == SEXP_UNDEF) ? SEXP_OP_GLOBAL_REF : SEXP_OP_GLOBAL_KNOWN_REF); emit_word(ctx, (sexp_uint_t)sexp_ref_cell(ref)); } else emit_push(ctx, sexp_ref_cell(ref)); } else { lam = sexp_context_lambda(ctx); generate_non_global_ref(ctx, sexp_ref_name(ref), sexp_ref_cell(ref), lam, sexp_lambda_fv(lam), unboxp); } } static void generate_set (sexp ctx, sexp set) { sexp ref = sexp_set_var(set), lambda; /* compile the value */ sexp_context_tailp(ctx) = 0; if (sexp_lambdap(sexp_set_value(set))) sexp_lambda_name(sexp_set_value(set)) = sexp_ref_name(ref); generate(ctx, sexp_set_value(set)); if (! sexp_lambdap(sexp_ref_loc(ref))) { /* global vars are set directly */ emit_push(ctx, sexp_ref_cell(ref)); emit(ctx, SEXP_OP_SET_CDR); } else { lambda = sexp_ref_loc(ref); if (sexp_truep(sexp_memq(ctx, sexp_ref_name(ref), sexp_lambda_sv(lambda)))) { /* stack or closure mutable vars are boxed */ generate_ref(ctx, ref, 0); emit(ctx, SEXP_OP_SET_CDR); } else { /* internally defined variable */ emit(ctx, SEXP_OP_LOCAL_SET); emit_word(ctx, sexp_param_index(lambda, sexp_ref_name(ref))); } } sexp_context_depth(ctx)--; } static void generate_opcode_app (sexp ctx, sexp app) { sexp op = sexp_car(app); sexp_sint_t i, num_args, inv_default=0; sexp_gc_var1(ls); sexp_gc_preserve1(ctx, ls); num_args = sexp_unbox_fixnum(sexp_length(ctx, sexp_cdr(app))); sexp_context_tailp(ctx) = 0; /* maybe push the default for an optional argument */ if ((num_args == sexp_opcode_num_args(op)) && sexp_opcode_variadic_p(op) && sexp_opcode_data(op) && (sexp_opcode_class(op) != SEXP_OPC_PARAMETER)) { if (sexp_opcode_inverse(op)) { inv_default = 1; } else { emit_push(ctx, sexp_opcode_data(op)); if (sexp_opcode_opt_param_p(op)) emit(ctx, SEXP_OP_CDR); sexp_context_depth(ctx)++; num_args++; } } /* push the arguments onto the stack in reverse order */ ls = ((sexp_opcode_inverse(op) && (sexp_opcode_class(op) != SEXP_OPC_ARITHMETIC)) ? sexp_cdr(app) : sexp_reverse(ctx, sexp_cdr(app))); for ( ; sexp_pairp(ls); ls = sexp_cdr(ls)) generate(ctx, sexp_car(ls)); /* push the default for inverse opcodes */ if (inv_default) { emit_push(ctx, sexp_opcode_data(op)); if (sexp_opcode_opt_param_p(op)) emit(ctx, SEXP_OP_CDR); sexp_context_depth(ctx)++; num_args++; } /* emit the actual operator call */ switch (sexp_opcode_class(op)) { case SEXP_OPC_ARITHMETIC: /* fold variadic arithmetic operators */ for (i=num_args-1; i>0; i--) emit(ctx, sexp_opcode_code(op)); break; case SEXP_OPC_ARITHMETIC_CMP: if (num_args > 2) { emit(ctx, SEXP_OP_STACK_REF); emit_word(ctx, 2); emit(ctx, SEXP_OP_STACK_REF); emit_word(ctx, 2); emit(ctx, sexp_opcode_code(op)); emit(ctx, SEXP_OP_AND); for (i=num_args-2; i>0; i--) { emit(ctx, SEXP_OP_STACK_REF); emit_word(ctx, 3); emit(ctx, SEXP_OP_STACK_REF); emit_word(ctx, 3); emit(ctx, sexp_opcode_code(op)); emit(ctx, SEXP_OP_AND); emit(ctx, SEXP_OP_AND); } } else emit(ctx, sexp_opcode_code(op)); break; case SEXP_OPC_FOREIGN: emit(ctx, sexp_opcode_code(op)); emit_word(ctx, (sexp_uint_t)op); break; case SEXP_OPC_TYPE_PREDICATE: case SEXP_OPC_ACCESSOR: case SEXP_OPC_CONSTRUCTOR: emit(ctx, sexp_opcode_code(op)); if ((sexp_opcode_class(op) != SEXP_OPC_CONSTRUCTOR) || sexp_opcode_code(op) == SEXP_OP_MAKE) { if (sexp_opcode_data(op)) emit_word(ctx, sexp_unbox_fixnum(sexp_opcode_data(op))); if (sexp_opcode_data2(op)) emit_word(ctx, sexp_unbox_fixnum(sexp_opcode_data2(op))); } break; case SEXP_OPC_PARAMETER: emit_push(ctx, sexp_opcode_data(op)); emit(ctx, ((num_args == 0) ? SEXP_OP_CDR : SEXP_OP_SET_CDR)); break; default: emit(ctx, sexp_opcode_code(op)); } sexp_context_depth(ctx) -= (num_args-1); sexp_gc_release1(ctx); } static void generate_general_app (sexp ctx, sexp app) { sexp_uint_t len = sexp_unbox_fixnum(sexp_length(ctx, sexp_cdr(app))), tailp = sexp_context_tailp(ctx); sexp_gc_var1(ls); sexp_gc_preserve1(ctx, ls); /* push the arguments onto the stack */ sexp_context_tailp(ctx) = 0; for (ls=sexp_reverse(ctx, sexp_cdr(app)); sexp_pairp(ls); ls=sexp_cdr(ls)) generate(ctx, sexp_car(ls)); /* push the operator onto the stack */ generate(ctx, sexp_car(app)); /* maybe overwrite the current frame */ emit(ctx, (tailp ? SEXP_OP_TAIL_CALL : SEXP_OP_CALL)); emit_word(ctx, (sexp_uint_t)sexp_make_fixnum(len)); sexp_context_tailp(ctx) = tailp; sexp_context_depth(ctx) -= len; sexp_gc_release1(ctx); } static void generate_app (sexp ctx, sexp app) { if (sexp_opcodep(sexp_car(app))) generate_opcode_app(ctx, app); else generate_general_app(ctx, app); } static void generate_lambda (sexp ctx, sexp lambda) { sexp ctx2, fv, ls, flags, len, ref, prev_lambda, prev_fv; sexp_uint_t k; sexp_gc_var2(tmp, bc); sexp_gc_preserve2(ctx, tmp, bc); prev_lambda = sexp_context_lambda(ctx); prev_fv = sexp_lambdap(prev_lambda) ? sexp_lambda_fv(prev_lambda) : SEXP_NULL; fv = sexp_lambda_fv(lambda); ctx2 = sexp_make_eval_context(ctx, sexp_context_stack(ctx), sexp_context_env(ctx), 0); sexp_context_lambda(ctx2) = lambda; /* allocate space for local vars */ for (ls=sexp_lambda_locals(lambda); sexp_pairp(ls); ls=sexp_cdr(ls)) emit_push(ctx2, SEXP_VOID); /* box mutable vars */ for (ls=sexp_lambda_sv(lambda); sexp_pairp(ls); ls=sexp_cdr(ls)) { k = sexp_param_index(lambda, sexp_car(ls)); if (k >= 0) { emit(ctx2, SEXP_OP_LOCAL_REF); emit_word(ctx2, k); emit_push(ctx2, sexp_car(ls)); emit(ctx2, SEXP_OP_CONS); emit(ctx2, SEXP_OP_LOCAL_SET); emit_word(ctx2, k); emit(ctx2, SEXP_OP_DROP); } } sexp_context_tailp(ctx2) = 1; generate(ctx2, sexp_lambda_body(lambda)); flags = sexp_make_fixnum((sexp_listp(ctx2, sexp_lambda_params(lambda)) == SEXP_FALSE) ? 1uL : 0uL); len = sexp_length(ctx2, sexp_lambda_params(lambda)); bc = finalize_bytecode(ctx2); sexp_bytecode_name(bc) = sexp_lambda_name(lambda); if (sexp_nullp(fv)) { /* shortcut, no free vars */ tmp = sexp_make_vector(ctx2, SEXP_ZERO, SEXP_VOID); tmp = sexp_make_procedure(ctx2, flags, len, bc, tmp); sexp_push(ctx, sexp_bytecode_literals(sexp_context_bc(ctx)), tmp); generate_lit(ctx, tmp); } else { /* push the closed vars */ emit_push(ctx, SEXP_VOID); emit_push(ctx, sexp_length(ctx, fv)); emit(ctx, SEXP_OP_MAKE_VECTOR); sexp_context_depth(ctx)--; for (k=0; sexp_pairp(fv); fv=sexp_cdr(fv), k++) { ref = sexp_car(fv); generate_non_global_ref(ctx, sexp_ref_name(ref), sexp_ref_cell(ref), prev_lambda, prev_fv, 0); emit_push(ctx, sexp_make_fixnum(k)); emit(ctx, SEXP_OP_STACK_REF); emit_word(ctx, 3); emit(ctx, SEXP_OP_VECTOR_SET); emit(ctx, SEXP_OP_DROP); sexp_context_depth(ctx)--; } /* push the additional procedure info and make the closure */ emit_push(ctx, bc); emit_push(ctx, len); emit_push(ctx, flags); emit(ctx, SEXP_OP_MAKE_PROCEDURE); } sexp_gc_release2(ctx); } static void generate (sexp ctx, sexp x) { if (sexp_pointerp(x)) { switch (sexp_pointer_tag(x)) { case SEXP_PAIR: generate_app(ctx, x); break; case SEXP_LAMBDA: generate_lambda(ctx, x); break; case SEXP_CND: generate_cnd(ctx, x); break; case SEXP_REF: generate_ref(ctx, x, 1); break; case SEXP_SET: generate_set(ctx, x); break; case SEXP_SEQ: generate_seq(ctx, sexp_seq_ls(x)); break; case SEXP_LIT: generate_lit(ctx, sexp_lit_value(x)); break; default: generate_lit(ctx, x); } } else { generate_lit(ctx, x); } } static sexp insert_free_var (sexp ctx, sexp x, sexp fv) { sexp name=sexp_ref_name(x), loc=sexp_ref_loc(x), ls; for (ls=fv; sexp_pairp(ls); ls=sexp_cdr(ls)) if ((name == sexp_ref_name(sexp_car(ls))) && (loc == sexp_ref_loc(sexp_car(ls)))) return fv; return sexp_cons(ctx, x, fv); } static sexp union_free_vars (sexp ctx, sexp fv1, sexp fv2) { sexp_gc_var1(res); if (sexp_nullp(fv2)) return fv1; sexp_gc_preserve1(ctx, res); for (res=fv2; sexp_pairp(fv1); fv1=sexp_cdr(fv1)) res = insert_free_var(ctx, sexp_car(fv1), res); sexp_gc_release1(ctx); return res; } static sexp diff_free_vars (sexp ctx, sexp lambda, sexp fv, sexp params) { sexp_gc_var1(res); sexp_gc_preserve1(ctx, res); res = SEXP_NULL; for ( ; sexp_pairp(fv); fv=sexp_cdr(fv)) if ((sexp_ref_loc(sexp_car(fv)) != lambda) || (sexp_memq(NULL, sexp_ref_name(sexp_car(fv)), params) == SEXP_FALSE)) sexp_push(ctx, res, sexp_car(fv)); sexp_gc_release1(ctx); return res; } sexp sexp_free_vars (sexp ctx, sexp x, sexp fv) { sexp_gc_var2(fv1, fv2); sexp_gc_preserve2(ctx, fv1, fv2); fv1 = fv; if (sexp_lambdap(x)) { fv1 = sexp_free_vars(ctx, sexp_lambda_body(x), SEXP_NULL); fv2 = sexp_flatten_dot(ctx, sexp_lambda_params(x)); fv2 = sexp_append2(ctx, sexp_lambda_locals(x), fv2); fv2 = diff_free_vars(ctx, x, fv1, fv2); sexp_lambda_fv(x) = fv2; fv1 = union_free_vars(ctx, fv2, fv); } else if (sexp_pairp(x)) { for ( ; sexp_pairp(x); x=sexp_cdr(x)) fv1 = sexp_free_vars(ctx, sexp_car(x), fv1); } else if (sexp_cndp(x)) { fv1 = sexp_free_vars(ctx, sexp_cnd_test(x), fv); fv1 = sexp_free_vars(ctx, sexp_cnd_pass(x), fv1); fv1 = sexp_free_vars(ctx, sexp_cnd_fail(x), fv1); } else if (sexp_seqp(x)) { for (x=sexp_seq_ls(x); sexp_pairp(x); x=sexp_cdr(x)) fv1 = sexp_free_vars(ctx, sexp_car(x), fv1); } else if (sexp_setp(x)) { fv1 = sexp_free_vars(ctx, sexp_set_value(x), fv); fv1 = sexp_free_vars(ctx, sexp_set_var(x), fv1); } else if (sexp_refp(x) && sexp_lambdap(sexp_ref_loc(x))) { fv1 = insert_free_var(ctx, x, fv); } else if (sexp_synclop(x)) { fv1 = sexp_free_vars(ctx, sexp_synclo_expr(x), fv); } sexp_gc_release2(ctx); return fv1; } static sexp make_param_list (sexp ctx, sexp_uint_t i) { sexp_gc_var1(res); sexp_gc_preserve1(ctx, res); res = SEXP_NULL; for ( ; i>0; i--) res = sexp_cons(ctx, sexp_make_fixnum(i), res); sexp_gc_release1(ctx); return res; } static sexp make_opcode_procedure (sexp ctx, sexp op, sexp_uint_t i) { sexp ls, bc, res, env; sexp_gc_var5(params, ref, refs, lambda, ctx2); if (i == sexp_opcode_num_args(op)) { /* return before preserving */ if (sexp_opcode_proc(op)) return sexp_opcode_proc(op); } else if (i < sexp_opcode_num_args(op)) { return sexp_compile_error(ctx, "not enough args for opcode", op); } else if (! sexp_opcode_variadic_p(op)) { /* i > num_args */ return sexp_compile_error(ctx, "too many args for opcode", op); } sexp_gc_preserve5(ctx, params, ref, refs, lambda, ctx2); params = make_param_list(ctx, i); lambda = sexp_make_lambda(ctx, params); ctx2 = sexp_make_child_context(ctx, lambda); env = sexp_extend_env(ctx2, sexp_context_env(ctx), params, lambda); sexp_context_env(ctx2) = env; for (ls=params, refs=SEXP_NULL; sexp_pairp(ls); ls=sexp_cdr(ls)) { ref = sexp_make_ref(ctx2, sexp_car(ls), sexp_env_cell(env, sexp_car(ls))); sexp_push(ctx2, refs, ref); } refs = sexp_reverse(ctx2, refs); refs = sexp_cons(ctx2, op, refs); generate_opcode_app(ctx2, refs); bc = finalize_bytecode(ctx2); sexp_bytecode_name(bc) = sexp_c_string(ctx2, sexp_opcode_name(op), -1); res=sexp_make_procedure(ctx2, SEXP_ZERO, sexp_make_fixnum(i), bc, SEXP_VOID); if (i == sexp_opcode_num_args(op)) sexp_opcode_proc(op) = res; sexp_gc_release5(ctx); 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)); 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, _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, _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, _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, _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, _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, _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; } /************************ library procedures **************************/ static sexp sexp_exception_type_func (sexp ctx, sexp exn) { if (sexp_exceptionp(exn)) return sexp_exception_kind(exn); else return sexp_type_exception(ctx, "not an exception", exn); } static sexp sexp_open_input_file (sexp ctx, sexp path) { FILE *in; if (! sexp_stringp(path)) return sexp_type_exception(ctx, "not a string", path); in = fopen(sexp_string_data(path), "r"); if (! in) return sexp_user_exception(ctx, SEXP_FALSE, "couldn't open input file", path); return sexp_make_input_port(ctx, in, path); } static sexp sexp_open_output_file (sexp ctx, sexp path) { FILE *out; if (! sexp_stringp(path)) return sexp_type_exception(ctx, "not a string", path); out = fopen(sexp_string_data(path), "w"); if (! out) return sexp_user_exception(ctx, SEXP_FALSE, "couldn't open output file", path); return sexp_make_output_port(ctx, out, path); } static sexp sexp_close_port (sexp ctx, sexp port) { if (! sexp_portp(port)) return sexp_type_exception(ctx, "not a port", port); if (! sexp_port_openp(port)) return sexp_user_exception(ctx, SEXP_FALSE, "port already closed", port); if (sexp_port_stream(port)) fclose(sexp_port_stream(port)); #if ! SEXP_USE_STRING_STREAMS if (sexp_port_buf(port) && sexp_oportp(port)) free(sexp_port_buf(port)); #endif sexp_port_openp(port) = 0; return SEXP_VOID; } void sexp_warn_undefs (sexp ctx, sexp from, sexp to, sexp out) { sexp x; for (x=from; sexp_pairp(x) && x!=to; x=sexp_cdr(x)) if (sexp_cdar(x) == SEXP_UNDEF) { sexp_write_string(ctx, "WARNING: reference to undefined variable: ", out); sexp_write(ctx, sexp_caar(x), out); sexp_write_char(ctx, '\n', out); } } #if SEXP_USE_DL #ifdef __MINGW32__ #include static sexp sexp_load_dl (sexp ctx, sexp file, sexp env) { sexp_proc2 init; HINSTANCE handle = LoadLibraryA(sexp_string_data(file)); if(!handle) return sexp_compile_error(ctx, "couldn't load dynamic library", file); init = (sexp_proc2) GetProcAddress(handle, "sexp_init_library"); if(!init) { FreeLibrary(handle); return sexp_compile_error(ctx, "dynamic library has no sexp_init_library", file); } return init(ctx, env); } #else static sexp sexp_load_dl (sexp ctx, sexp file, sexp env) { sexp_proc2 init; void *handle = dlopen(sexp_string_data(file), RTLD_LAZY); if (! handle) return sexp_compile_error(ctx, "couldn't load dynamic library", file); init = dlsym(handle, "sexp_init_library"); if (! init) { dlclose(handle); return sexp_compile_error(ctx, "dynamic library has no sexp_init_library", file); } return init(ctx, env); } #endif #endif sexp sexp_load (sexp ctx, sexp source, sexp env) { #if SEXP_USE_DL char *suffix; #endif sexp tmp, out=SEXP_FALSE; sexp_gc_var4(ctx2, x, in, res); if (! sexp_stringp(source)) return sexp_type_exception(ctx, "not a string", source); if (! sexp_envp(env)) return sexp_type_exception(ctx, "not an environment", env); #if SEXP_USE_DL suffix = sexp_string_data(source) + sexp_string_length(source) - strlen(sexp_so_extension); if (strcmp(suffix, sexp_so_extension) == 0) { res = sexp_load_dl(ctx, source, env); } else { #endif sexp_gc_preserve4(ctx, ctx2, x, in, res); res = SEXP_VOID; in = sexp_open_input_file(ctx, source); out = sexp_current_error_port(ctx); ctx2 = sexp_make_eval_context(ctx, NULL, env, 0); sexp_context_parent(ctx2) = ctx; tmp = sexp_env_bindings(env); sexp_context_tailp(ctx2) = 0; if (sexp_exceptionp(in)) { if (sexp_not(out)) out = sexp_current_error_port(ctx); if (sexp_oportp(out)) sexp_print_exception(ctx, in, out); res = in; } else { sexp_port_sourcep(in) = 1; while ((x=sexp_read(ctx, in)) != (sexp) SEXP_EOF) { res = sexp_eval(ctx2, x, env); if (sexp_exceptionp(res)) break; } if (x == SEXP_EOF) res = SEXP_VOID; sexp_close_port(ctx, in); } sexp_gc_release4(ctx); #if SEXP_USE_DL } #endif #if SEXP_USE_WARN_UNDEFS if (sexp_oportp(out) && ! sexp_exceptionp(res)) sexp_warn_undefs(ctx, sexp_env_bindings(env), tmp, out); #endif return res; } #if SEXP_USE_MATH #if SEXP_USE_BIGNUMS #define maybe_convert_bignum(z) \ else if (sexp_bignump(z)) d = sexp_bignum_to_double(z); #else #define maybe_convert_bignum(z) #endif #define define_math_op(name, cname) \ static sexp name (sexp ctx, sexp z) { \ double d; \ if (sexp_flonump(z)) \ d = sexp_flonum_value(z); \ else if (sexp_fixnump(z)) \ d = (double)sexp_unbox_fixnum(z); \ maybe_convert_bignum(z) \ else \ return sexp_type_exception(ctx, "not a number", z); \ return sexp_make_flonum(ctx, cname(d)); \ } define_math_op(sexp_exp, exp) define_math_op(sexp_log, log) define_math_op(sexp_sin, sin) define_math_op(sexp_cos, cos) define_math_op(sexp_tan, tan) define_math_op(sexp_asin, asin) define_math_op(sexp_acos, acos) define_math_op(sexp_atan, atan) define_math_op(sexp_round, round) define_math_op(sexp_trunc, trunc) define_math_op(sexp_floor, floor) define_math_op(sexp_ceiling, ceil) static sexp sexp_sqrt (sexp ctx, sexp z) { double d, r; if (sexp_flonump(z)) d = sexp_flonum_value(z); else if (sexp_fixnump(z)) d = (double)sexp_unbox_fixnum(z); maybe_convert_bignum(z) /* XXXX add bignum sqrt */ else return sexp_type_exception(ctx, "not a number", z); r = sqrt(d); if (sexp_fixnump(z) && ((r*r) == (double)sexp_unbox_fixnum(z))) return sexp_make_fixnum(round(r)); else return sexp_make_flonum(ctx, r); } #endif static sexp sexp_expt (sexp ctx, sexp x, sexp e) { long double f, x1, e1; sexp res; #if SEXP_USE_BIGNUMS if (sexp_bignump(e)) { /* bignum exponent needs special handling */ if ((x == SEXP_ZERO) || (x == SEXP_NEG_ONE)) res = sexp_make_flonum(ctx, pow(0, 0)); /* +nan.0 */ else if (x == SEXP_ONE) res = SEXP_ONE; /* 1.0 */ else if (sexp_flonump(x)) res = sexp_make_flonum(ctx, pow(sexp_flonum_value(x), sexp_bignum_to_double(e))); else res = sexp_make_flonum(ctx, pow(10.0, 1e100)); /* +inf.0 */ } else if (sexp_bignump(x)) { res = sexp_bignum_expt(ctx, x, e); } else { #endif if (sexp_fixnump(x)) x1 = sexp_unbox_fixnum(x); #if SEXP_USE_FLONUMS else if (sexp_flonump(x)) x1 = sexp_flonum_value(x); #endif else return sexp_type_exception(ctx, "expt: not a number", x); if (sexp_fixnump(e)) e1 = sexp_unbox_fixnum(e); #if SEXP_USE_FLONUMS else if (sexp_flonump(e)) e1 = sexp_flonum_value(e); #endif else return sexp_type_exception(ctx, "expt: not a number", e); f = pow(x1, e1); if ((f > SEXP_MAX_FIXNUM) || (f < SEXP_MIN_FIXNUM) #if SEXP_USE_FLONUMS || (! sexp_fixnump(x)) || (! sexp_fixnump(e)) #endif ) { #if SEXP_USE_BIGNUMS if (sexp_fixnump(x) && sexp_fixnump(e)) res = sexp_bignum_expt(ctx, sexp_fixnum_to_bignum(ctx, x), e); else #endif #if SEXP_USE_FLONUMS res = sexp_make_flonum(ctx, f); #else res = sexp_make_fixnum((sexp_sint_t)round(f)); #endif } else res = sexp_make_fixnum((sexp_sint_t)round(f)); #if SEXP_USE_BIGNUMS } #endif return res; } static sexp sexp_string_cmp (sexp ctx, sexp str1, sexp str2, sexp ci) { sexp_sint_t len1, len2, len, diff; if (! sexp_stringp(str1)) return sexp_type_exception(ctx, "not a string", str1); if (! sexp_stringp(str2)) return sexp_type_exception(ctx, "not a string", str2); len1 = sexp_string_length(str1); len2 = sexp_string_length(str2); len = ((len1= SEXP_OPC_NUM_OP_CLASSES)) res = sexp_type_exception(ctx, "make-opcode: bad opcode class", op_class); else if ((! sexp_fixnump(code)) || (sexp_unbox_fixnum(code) <= 0) || (sexp_unbox_fixnum(code) >= SEXP_OP_NUM_OPCODES)) res = sexp_type_exception(ctx, "make-opcode: bad opcode", code); else if (! sexp_fixnump(num_args)) res = sexp_type_exception(ctx, "make-opcode: bad num_args", num_args); else if (! sexp_fixnump(flags)) res = sexp_type_exception(ctx, "make-opcode: bad flags", flags); else { res = sexp_alloc_type(ctx, opcode, SEXP_OPCODE); sexp_opcode_class(res) = sexp_unbox_fixnum(op_class); sexp_opcode_code(res) = sexp_unbox_fixnum(code); sexp_opcode_num_args(res) = sexp_unbox_fixnum(num_args); sexp_opcode_flags(res) = sexp_unbox_fixnum(flags); sexp_opcode_arg1_type(res) = sexp_unbox_fixnum(arg1t); sexp_opcode_arg2_type(res) = sexp_unbox_fixnum(arg2t); sexp_opcode_inverse(res) = sexp_unbox_fixnum(invp); sexp_opcode_data(res) = data; sexp_opcode_data2(res) = data2; sexp_opcode_func(res) = func; sexp_opcode_name(res) = strdup(sexp_string_data(name)); } return res; } sexp sexp_make_foreign (sexp ctx, char *name, int num_args, int flags, sexp_proc1 f, sexp data) { sexp res; if (num_args > 6) { res = sexp_type_exception(ctx, "make-foreign: exceeded foreign arg limit", sexp_make_fixnum(num_args)); } else { res = sexp_alloc_type(ctx, opcode, SEXP_OPCODE); sexp_opcode_class(res) = SEXP_OPC_FOREIGN; sexp_opcode_code(res) = SEXP_OP_FCALL1+num_args-1; if (flags & 1) num_args--; sexp_opcode_num_args(res) = num_args; sexp_opcode_flags(res) = flags; sexp_opcode_name(res) = name; sexp_opcode_data(res) = data; sexp_opcode_func(res) = f; } return res; } sexp sexp_define_foreign_aux (sexp ctx, sexp env, char *name, int num_args, int flags, sexp_proc1 f, sexp data) { sexp_gc_var1(op); sexp_gc_preserve1(ctx, op); sexp res = SEXP_VOID; op = sexp_make_foreign(ctx, name, num_args, flags, f, data); if (sexp_exceptionp(op)) res = op; else sexp_env_define(ctx, env, sexp_intern(ctx, name), op); sexp_gc_release1(ctx); return res; } sexp sexp_define_foreign_param (sexp ctx, sexp env, char *name, int num_args, sexp_proc1 f, char *param) { sexp res; sexp_gc_var1(tmp); sexp_gc_preserve1(ctx, tmp); tmp = sexp_intern(ctx, param); tmp = sexp_env_cell(env, tmp); res = sexp_define_foreign_aux(ctx, env, name, num_args, 3, f, tmp); sexp_gc_release1(ctx); return res; } #if SEXP_USE_TYPE_DEFS sexp sexp_make_type_predicate (sexp ctx, sexp name, sexp type) { if (! sexp_fixnump(type)) return sexp_type_exception(ctx, "make-type-predicate: bad type", type); return sexp_make_opcode(ctx, name, sexp_make_fixnum(SEXP_OPC_TYPE_PREDICATE), sexp_make_fixnum(SEXP_OP_TYPEP), SEXP_ONE, SEXP_ZERO, SEXP_ZERO, SEXP_ZERO, SEXP_ZERO, type, NULL, NULL); } sexp sexp_make_constructor (sexp ctx, sexp name, sexp type) { sexp_uint_t type_size; if (! sexp_fixnump(type)) return sexp_type_exception(ctx, "make-constructor: bad type", type); type_size = sexp_type_size_base(sexp_type_by_index(ctx, sexp_unbox_fixnum(type))); return sexp_make_opcode(ctx, name, sexp_make_fixnum(SEXP_OPC_CONSTRUCTOR), sexp_make_fixnum(SEXP_OP_MAKE), SEXP_ZERO, SEXP_ZERO, SEXP_ZERO, SEXP_ZERO, SEXP_ZERO, type, sexp_make_fixnum(type_size), NULL); } sexp sexp_make_accessor (sexp ctx, sexp name, sexp type, sexp index, sexp code) { if (! sexp_fixnump(type)) return sexp_type_exception(ctx, "make-accessor: bad type", type); if ((! sexp_fixnump(index)) || (sexp_unbox_fixnum(index) < 0)) return sexp_type_exception(ctx, "make-accessor: bad index", index); return sexp_make_opcode(ctx, name, sexp_make_fixnum(SEXP_OPC_ACCESSOR), code, sexp_make_fixnum(sexp_unbox_fixnum(code)==SEXP_OP_SLOT_REF?1:2), SEXP_ZERO, type, SEXP_ZERO, SEXP_ZERO, type, index, NULL); } sexp sexp_make_getter (sexp ctx, sexp name, sexp type, sexp index) { return sexp_make_accessor(ctx, name, type, index, sexp_make_fixnum(SEXP_OP_SLOT_REF)); } sexp sexp_make_setter (sexp ctx, sexp name, sexp type, sexp index) { return sexp_make_accessor(ctx, name, type, index, sexp_make_fixnum(SEXP_OP_SLOT_SET)); } #endif #if SEXP_USE_STATIC_LIBS #include "clibs.c" #endif /*********************** standard environment *************************/ static struct sexp_struct core_forms[] = { {.tag=SEXP_CORE, .value={.core={SEXP_CORE_DEFINE, "define"}}}, {.tag=SEXP_CORE, .value={.core={SEXP_CORE_SET, "set!"}}}, {.tag=SEXP_CORE, .value={.core={SEXP_CORE_LAMBDA, "lambda"}}}, {.tag=SEXP_CORE, .value={.core={SEXP_CORE_IF, "if"}}}, {.tag=SEXP_CORE, .value={.core={SEXP_CORE_BEGIN, "begin"}}}, {.tag=SEXP_CORE, .value={.core={SEXP_CORE_QUOTE, "quote"}}}, {.tag=SEXP_CORE, .value={.core={SEXP_CORE_SYNTAX_QUOTE, "syntax-quote"}}}, {.tag=SEXP_CORE, .value={.core={SEXP_CORE_DEFINE_SYNTAX, "define-syntax"}}}, {.tag=SEXP_CORE, .value={.core={SEXP_CORE_LET_SYNTAX, "let-syntax"}}}, {.tag=SEXP_CORE, .value={.core={SEXP_CORE_LETREC_SYNTAX, "letrec-syntax"}}}, }; sexp sexp_make_env (sexp ctx) { sexp e = sexp_alloc_type(ctx, env, SEXP_ENV); sexp_env_lambda(e) = NULL; sexp_env_parent(e) = NULL; sexp_env_bindings(e) = SEXP_NULL; return e; } sexp sexp_make_null_env (sexp ctx, sexp version) { sexp_uint_t i; sexp e = sexp_make_env(ctx); for (i=0; i<(sizeof(core_forms)/sizeof(core_forms[0])); i++) sexp_env_define(ctx, e, sexp_intern(ctx, sexp_core_name(&core_forms[i])), sexp_copy_core(ctx, &core_forms[i])); return e; } sexp sexp_make_primitive_env (sexp ctx, sexp version) { int i; sexp_gc_var3(e, op, sym); sexp_gc_preserve3(ctx, e, op, sym); e = sexp_make_null_env(ctx, version); for (i=0; i<(sizeof(opcodes)/sizeof(opcodes[0])); i++) { op = sexp_copy_opcode(ctx, &opcodes[i]); if (sexp_opcode_opt_param_p(op) && sexp_opcode_data(op)) { sym = sexp_intern(ctx, (char*)sexp_opcode_data(op)); sexp_opcode_data(op) = sexp_env_cell_create(ctx, e, sym, SEXP_VOID, NULL); } sexp_env_define(ctx, e, sexp_intern(ctx, sexp_opcode_name(op)), op); } sexp_gc_release3(ctx); return e; } sexp sexp_find_module_file (sexp ctx, char *file) { sexp res=SEXP_FALSE, ls; char *dir, *path; sexp_uint_t slash, dirlen, filelen, len; #ifdef PLAN9 #define file_exists_p(path, buf) (stat(path, buf, 128) >= 0) unsigned char buf[128]; #else #define file_exists_p(path, buf) (! stat(path, buf)) struct stat buf_str; struct stat *buf = &buf_str; #endif filelen = strlen(file); ls = sexp_global(ctx, SEXP_G_MODULE_PATH); for ( ; sexp_pairp(ls) && sexp_not(res); ls=sexp_cdr(ls)) { dir = sexp_string_data(sexp_car(ls)); dirlen = sexp_string_length(sexp_car(ls)); slash = dir[dirlen-1] == '/'; len = dirlen+filelen+2-slash; path = (char*) malloc(len); memcpy(path, dir, dirlen); if (! slash) path[dirlen] = '/'; memcpy(path+len-filelen-1, file, filelen); path[len-1] = '\0'; if (file_exists_p(path, buf)) res = sexp_c_string(ctx, path, len-1); free(path); } return res; } #define sexp_file_not_found "couldn't find file in module path" sexp sexp_load_module_file (sexp ctx, char *file, sexp env) { sexp res; sexp_gc_var1(path); sexp_gc_preserve1(ctx, path); path = sexp_find_module_file(ctx, file); if (sexp_stringp(path)) { res = sexp_load(ctx, path, env); } else { path = sexp_c_string(ctx, file, -1); res = sexp_user_exception(ctx, SEXP_FALSE, sexp_file_not_found, path); } sexp_gc_release1(ctx); return res; } #if SEXP_USE_MODULES static sexp sexp_find_module_file_op (sexp ctx, sexp file) { if (! sexp_stringp(file)) return sexp_type_exception(ctx, "not a string", file); else return sexp_find_module_file(ctx, sexp_string_data(file)); } sexp sexp_load_module_file_op (sexp ctx, sexp file, sexp env) { if (! sexp_stringp(file)) return sexp_type_exception(ctx, "not a string", file); else if (! sexp_envp(env)) return sexp_type_exception(ctx, "not an environment", env); return sexp_load_module_file(ctx, sexp_string_data(file), env); } #endif sexp sexp_add_module_directory (sexp ctx, sexp dir, sexp appendp) { sexp ls; if (! sexp_stringp(dir)) return sexp_type_exception(ctx, "not a string", dir); if (sexp_truep(appendp)) { if (sexp_pairp(ls=sexp_global(ctx, SEXP_G_MODULE_PATH))) { for ( ; sexp_pairp(sexp_cdr(ls)); ls=sexp_cdr(ls)) ; sexp_cdr(ls) = sexp_list1(ctx, dir); } else { sexp_global(ctx, SEXP_G_MODULE_PATH) = sexp_list1(ctx, dir); } } else { sexp_push(ctx, sexp_global(ctx, SEXP_G_MODULE_PATH), dir); } return SEXP_VOID; } sexp sexp_load_standard_parameters (sexp ctx, sexp e) { /* add io port and interaction env parameters */ sexp_env_define(ctx, e, sexp_global(ctx, SEXP_G_CUR_IN_SYMBOL), sexp_make_input_port(ctx, stdin, SEXP_FALSE)); sexp_env_define(ctx, e, sexp_global(ctx, SEXP_G_CUR_OUT_SYMBOL), sexp_make_output_port(ctx, stdout, SEXP_FALSE)); sexp_env_define(ctx, e, sexp_global(ctx, SEXP_G_CUR_ERR_SYMBOL), sexp_make_output_port(ctx, stderr, SEXP_FALSE)); sexp_env_define(ctx, e, sexp_global(ctx, SEXP_G_INTERACTION_ENV_SYMBOL), e); return SEXP_VOID; } sexp sexp_load_standard_env (sexp ctx, sexp e, sexp version) { sexp_gc_var3(op, tmp, sym); sexp_gc_preserve3(ctx, op, tmp, sym); sexp_load_standard_parameters(ctx, e); #if SEXP_USE_DL sexp_env_define(ctx, e, sym=sexp_intern(ctx, "*shared-object-extension*"), tmp=sexp_c_string(ctx, sexp_so_extension, -1)); #endif tmp = sexp_list1(ctx, sym=sexp_intern(ctx, sexp_platform)); #if SEXP_USE_DL sexp_push(ctx, tmp, sym=sexp_intern(ctx, "dynamic-loading")); #endif #if SEXP_USE_MODULES sexp_push(ctx, tmp, sym=sexp_intern(ctx, "modules")); #endif #if SEXP_USE_BOEHM sexp_push(ctx, tmp, sym=sexp_intern(ctx, "boehm-gc")); #endif sexp_push(ctx, tmp, sym=sexp_intern(ctx, "chibi")); sexp_env_define(ctx, e, sexp_intern(ctx, "*features*"), tmp); sexp_global(ctx, SEXP_G_OPTIMIZATIONS) = SEXP_NULL; #if SEXP_USE_SIMPLIFY op = sexp_make_foreign(ctx, "simplify", 1, 0, (sexp_proc1)sexp_simplify, SEXP_VOID); tmp = sexp_cons(ctx, sexp_make_fixnum(500), op); sexp_push(ctx, sexp_global(ctx, SEXP_G_OPTIMIZATIONS), tmp); #endif /* load init.scm */ tmp = sexp_load_module_file(ctx, sexp_init_file, e); /* load and bind config env */ #if SEXP_USE_MODULES if (! sexp_exceptionp(tmp)) { sym = sexp_intern(ctx, "*config-env*"); if (! sexp_envp(tmp=sexp_global(ctx, SEXP_G_CONFIG_ENV))) { tmp = sexp_make_env(ctx); if (! sexp_exceptionp(tmp)) { sexp_global(ctx, SEXP_G_CONFIG_ENV) = tmp; sexp_env_parent(tmp) = e; op = sexp_load_module_file(ctx, sexp_config_file, tmp); if (sexp_exceptionp(op)) sexp_print_exception(ctx, op, sexp_current_error_port(ctx)); sexp_env_define(ctx, tmp, sym, tmp); } } sexp_env_define(ctx, e, sym, tmp); } #endif #if SEXP_USE_STATIC_LIBS sexp_init_all_libraries(ctx, e); #endif sexp_gc_release3(ctx); return sexp_exceptionp(tmp) ? tmp : e; } sexp sexp_make_standard_env (sexp ctx, sexp version) { sexp_gc_var1(env); sexp_gc_preserve1(ctx, env); env = sexp_make_primitive_env(ctx, version); if (! sexp_exceptionp(env)) sexp_load_standard_env(ctx, env, version); sexp_gc_release1(ctx); return env; } sexp sexp_env_copy (sexp ctx, sexp to, sexp from, sexp ls, sexp immutp) { sexp oldname, newname, value, out; if (! sexp_envp(to)) to = sexp_context_env(ctx); if (! sexp_envp(from)) from = sexp_context_env(ctx); if (sexp_not(ls)) { if (sexp_truep(immutp)) { value = sexp_make_env(ctx); sexp_env_parent(value) = sexp_env_parent(to); sexp_env_parent(to) = value; sexp_immutablep(value) = 1; sexp_env_bindings(value) = sexp_env_bindings(from); } else { for (ls=sexp_env_bindings(from); sexp_pairp(ls); ls=sexp_cdr(ls)) sexp_env_define(ctx, to, sexp_caar(ls), sexp_cdar(ls)); } } else { for ( ; sexp_pairp(ls); ls=sexp_cdr(ls)) { if (sexp_pairp(sexp_car(ls))) { newname = sexp_caar(ls); oldname = sexp_cdar(ls); } else { newname = oldname = sexp_car(ls); } value = sexp_env_ref(from, oldname, SEXP_UNDEF); if (value != SEXP_UNDEF) { sexp_env_define(ctx, to, newname, value); #if SEXP_USE_WARN_UNDEFS } else if (sexp_oportp(out=sexp_current_error_port(ctx))) { sexp_write_string(ctx, "WARNING: importing undefined variable: ", out); sexp_write(ctx, oldname, out); sexp_write_char(ctx, '\n', out); #endif } } } return SEXP_VOID; } /************************** eval interface ****************************/ sexp sexp_apply (sexp ctx, sexp proc, sexp args) { sexp res, ls, *stack = sexp_stack_data(sexp_context_stack(ctx)); sexp_sint_t top = sexp_context_top(ctx), len, offset; len = sexp_unbox_fixnum(sexp_length(ctx, args)); if (sexp_opcodep(proc)) proc = make_opcode_procedure(ctx, proc, len); if (! sexp_procedurep(proc)) { res = sexp_exceptionp(proc) ? proc : sexp_type_exception(ctx, "apply: not a procedure", proc); } else { offset = top + len; for (ls=args; sexp_pairp(ls); ls=sexp_cdr(ls), top++) stack[--offset] = sexp_car(ls); stack[top] = sexp_make_fixnum(len); top++; stack[top++] = SEXP_ZERO; stack[top++] = sexp_global(ctx, SEXP_G_FINAL_RESUMER); stack[top++] = SEXP_ZERO; sexp_context_top(ctx) = top; res = sexp_vm(ctx, proc); if (! res) res = SEXP_VOID; /* shouldn't happen */ } return res; } sexp sexp_compile (sexp ctx, sexp x) { sexp_gc_var3(ast, vec, res); sexp_gc_preserve3(ctx, ast, vec, res); ast = sexp_analyze(ctx, x); if (sexp_exceptionp(ast)) { res = ast; } else { res = sexp_global(ctx, SEXP_G_OPTIMIZATIONS); for ( ; sexp_pairp(res); res=sexp_cdr(res)) ast = sexp_apply_optimization(ctx, sexp_cdar(res), ast); sexp_free_vars(ctx, ast, SEXP_NULL); /* should return SEXP_NULL */ generate(ctx, ast); res = finalize_bytecode(ctx); vec = sexp_make_vector(ctx, 0, SEXP_VOID); res = sexp_make_procedure(ctx, SEXP_ZERO, SEXP_ZERO, res, vec); } sexp_gc_release3(ctx); return res; } sexp sexp_eval (sexp ctx, sexp obj, sexp env) { sexp_sint_t top; sexp ctx2; sexp_gc_var2(res, err_handler); sexp_gc_preserve2(ctx, res, err_handler); top = sexp_context_top(ctx); err_handler = sexp_cdr(sexp_global(ctx, SEXP_G_ERR_HANDLER)); sexp_cdr(sexp_global(ctx, SEXP_G_ERR_HANDLER)) = SEXP_FALSE; ctx2 = sexp_make_eval_context(ctx, sexp_context_stack(ctx), (env ? env : sexp_context_env(ctx)), 0); res = sexp_compile(ctx2, obj); if (! sexp_exceptionp(res)) res = sexp_apply(ctx2, res, SEXP_NULL); sexp_cdr(sexp_global(ctx, SEXP_G_ERR_HANDLER)) = err_handler; sexp_context_top(ctx) = top; sexp_gc_release2(ctx); return res; } sexp sexp_eval_string (sexp ctx, char *str, sexp env) { sexp res; sexp_gc_var1(obj); sexp_gc_preserve1(ctx, obj); obj = sexp_read_from_string(ctx, str); res = sexp_eval(ctx, obj, env); sexp_gc_release1(ctx); return res; } void sexp_scheme_init (void) { if (! scheme_initialized_p) { scheme_initialized_p = 1; sexp_init(); } }