static pic_value pic_regexp_regexp_match(pic_state *pic) { pic_value reg; const char *input; regmatch_t match[100]; pic_value matches, positions; pic_str *str; int i, offset; pic_get_args(pic, "oz", ®, &input); pic_assert_type(pic, reg, regexp); matches = pic_nil_value(); positions = pic_nil_value(); if (strchr(pic_regexp_data_ptr(reg)->flags, 'g') != NULL) { /* global search */ offset = 0; while (regexec(&pic_regexp_data_ptr(reg)->reg, input, 1, match, 0) != REG_NOMATCH) { pic_push(pic, pic_obj_value(pic_str_new(pic, input, match[0].rm_eo - match[0].rm_so)), matches); pic_push(pic, pic_int_value(offset), positions); offset += match[0].rm_eo; input += match[0].rm_eo; } } else { /* local search */ if (regexec(&pic_regexp_data_ptr(reg)->reg, input, 100, match, 0) == 0) { for (i = 0; i < 100; ++i) { if (match[i].rm_so == -1) { break; } str = pic_str_new(pic, input + match[i].rm_so, match[i].rm_eo - match[i].rm_so); pic_push(pic, pic_obj_value(str), matches); pic_push(pic, pic_int_value(match[i].rm_so), positions); } } } if (pic_nil_p(matches)) { matches = pic_false_value(); positions = pic_false_value(); } else { matches = pic_reverse(pic, matches); positions = pic_reverse(pic, positions); } return pic_values2(pic, matches, positions); }
static pic_value weak_call(pic_state *pic) { pic_value key, val, weak; int n; n = pic_get_args(pic, "o|o", &key, &val); if (! pic_obj_p(pic, key)) { pic_error(pic, "attempted to set a non-object key", 1, key); } weak = pic_closure_ref(pic, 0); if (n == 1) { if (! pic_weak_has(pic, weak, key)) { return pic_false_value(pic); } return pic_cons(pic, key, pic_weak_ref(pic, weak, key)); } else { if (pic_undef_p(pic, val)) { if (pic_weak_has(pic, weak, key)) { pic_weak_del(pic, weak, key); } } else { pic_weak_set(pic, weak, key, val); } return pic_undef_value(pic); } }
static pic_value reg_get(pic_state *pic, struct pic_reg *reg, void *key) { if (! pic_reg_has(pic, reg, key)) { return pic_false_value(); } return pic_cons(pic, pic_obj_value(key), pic_reg_ref(pic, reg, key)); }
static pic_value pic_bool_boolean_p(pic_state *pic) { pic_value v; pic_get_args(pic, "o", &v); return (pic_true_p(v) || pic_false_p(v)) ? pic_true_value() : pic_false_value(); }
/* TODO: replace it with native opcode */ static pic_value pic_bool_not(pic_state *pic) { pic_value v; pic_get_args(pic, "o", &v); return pic_false_p(v) ? pic_true_value() : pic_false_value(); }
static pic_value pic_macro_variable_eq_p(pic_state *pic) { size_t argc, i; pic_value *argv; pic_get_args(pic, "*", &argc, &argv); for (i = 0; i < argc; ++i) { if (! pic_var_p(argv[i])) { return pic_false_value(); } if (! pic_equal_p(pic, argv[i], argv[0])) { return pic_false_value(); } } return pic_true_value(); }
static pic_value pic_bool_boolean_eq_p(pic_state *pic) { size_t argc, i; pic_value *argv; pic_get_args(pic, "*", &argc, &argv); for (i = 0; i < argc; ++i) { if (! (pic_true_p(argv[i]) || pic_false_p(argv[i]))) { return pic_false_value(); } if (! pic_eq_p(argv[i], argv[0])) { return pic_false_value(); } } return pic_true_value(); }
static pic_value pic_char_char_p(pic_state *pic) { pic_value v; pic_get_args(pic, "o", &v); return pic_char_p(pic, v) ? pic_true_value(pic) : pic_false_value(pic); }
static pic_value pic_number_nan_p(pic_state *pic) { pic_value v; pic_get_args(pic, "o", &v); if (pic_float_p(pic, v) && isnan(pic_float(pic, v))) return pic_true_value(pic); else return pic_false_value(pic); }
void pic_init_error(pic_state *pic) { pic_defvar(pic, "current-exception-handlers", pic_nil_value(pic), pic_false_value(pic)); pic_defun(pic, "with-exception-handler", pic_error_with_exception_handler); pic_defun(pic, "raise", pic_error_raise); pic_defun(pic, "raise-continuable", pic_error_raise_continuable); pic_defun(pic, "error", pic_error_error); pic_defun(pic, "error-object?", pic_error_error_object_p); pic_defun(pic, "error-object-message", pic_error_error_object_message); pic_defun(pic, "error-object-irritants", pic_error_error_object_irritants); pic_defun(pic, "error-object-type", pic_error_error_object_type); }
static pic_value pic_dict_dictionary_ref(pic_state *pic) { struct pic_dict *dict; pic_sym *key; pic_get_args(pic, "dm", &dict, &key); if (! pic_dict_has(pic, dict, key)) { return pic_false_value(); } return pic_cons(pic, pic_obj_value(key), pic_dict_ref(pic, dict, key)); }
static pic_value native_exception_handler(pic_state *pic) { pic_value err; pic_get_args(pic, "o", &err); pic->err = err; pic_call(pic, pic_closure_ref(pic, 0), 1, pic_false_value(pic)); PIC_UNREACHABLE(); }
static pic_value pic_port_eof_object_p(pic_state *pic) { pic_value v; pic_get_args(pic, "o", &v); if (pic_vtype(v) == PIC_VTYPE_EOF) { return pic_true_value(); } else { return pic_false_value(); } }
static pic_value pic_port_binary_port_p(pic_state *pic) { pic_value v; pic_get_args(pic, "o", &v); if (pic_port_p(v) && (pic_port_ptr(v)->flags & PIC_PORT_BINARY) != 0) { return pic_true_value(); } else { return pic_false_value(); } }
static pic_value pic_number_finite_p(pic_state *pic) { pic_value v; pic_get_args(pic, "o", &v); if (pic_int_p(pic, v)) return pic_true_value(pic); if (pic_float_p(pic, v) && ! (isinf(pic_float(pic, v)) || isnan(pic_float(pic, v)))) return pic_true_value(pic); else return pic_false_value(pic); }
static pic_value pic_port_textual_port_p(pic_state *pic) { pic_value v; pic_get_args(pic, "o", &v); if (pic_port_p(v) && (pic_port_ptr(v)->flags & PIC_PORT_TEXT) != 0) { return pic_true_value(); } else { return pic_false_value(); } }
static pic_value pic_error_file_error_p(pic_state *pic) { pic_value v; struct pic_error *e; pic_get_args(pic, "o", &v); if (! pic_error_p(v)) { return pic_false_value(); } e = pic_error_ptr(v); return pic_bool_value(e->type == PIC_ERROR_FILE); }
pic_value pic_native_exception_handler(pic_state *pic) { pic_value err; struct pic_proc *cont; pic_get_args(pic, "o", &err); pic->err = err; cont = pic_proc_ptr(pic_proc_env_ref(pic, pic_get_proc(pic), "cont")); pic_apply1(pic, cont, pic_false_value()); PIC_UNREACHABLE(); }
static pic_value native_exception_handler(pic_state *pic) { pic_value err; struct pic_proc *cont; pic_get_args(pic, "o", &err); pic->err = err; cont = pic_proc_ptr(pic_attr_ref(pic, pic_obj_value(pic_get_proc(pic)), "@@escape")); pic_apply1(pic, cont, pic_false_value()); PIC_UNREACHABLE(); }
pic_value pic_file_exists_p(pic_state *pic) { char *fname; FILE *fp; pic_get_args(pic, "z", &fname); fp = fopen(fname, "r"); if (fp) { fclose(fp); return pic_true_value(); } else { return pic_false_value(); } }
pic_value pic_apply(pic_state *pic, struct pic_proc *proc, pic_value argv) { struct pic_code *pc, c; int ai = pic_gc_arena_preserve(pic); jmp_buf jmp; size_t argc, i; struct pic_code boot[2]; #if PIC_DIRECT_THREADED_VM static void *oplabels[] = { &&L_OP_POP, &&L_OP_PUSHNIL, &&L_OP_PUSHTRUE, &&L_OP_PUSHFALSE, &&L_OP_PUSHFLOAT, &&L_OP_PUSHINT, &&L_OP_PUSHCHAR, &&L_OP_PUSHCONST, &&L_OP_GREF, &&L_OP_GSET, &&L_OP_LREF, &&L_OP_LSET, &&L_OP_CREF, &&L_OP_CSET, &&L_OP_JMP, &&L_OP_JMPIF, &&L_OP_CALL, &&L_OP_TAILCALL, &&L_OP_RET, &&L_OP_LAMBDA, &&L_OP_CONS, &&L_OP_CAR, &&L_OP_CDR, &&L_OP_NILP, &&L_OP_ADD, &&L_OP_SUB, &&L_OP_MUL, &&L_OP_DIV, &&L_OP_EQ, &&L_OP_LT, &&L_OP_LE, &&L_OP_STOP }; #endif if (setjmp(jmp) == 0) { pic->jmp = &jmp; } else { goto L_RAISE; } argc = pic_length(pic, argv) + 1; #if VM_DEBUG puts("== booting VM..."); printf(" proc = "); pic_debug(pic, pic_obj_value(proc)); puts(""); printf(" argv = "); pic_debug(pic, argv); puts(""); printf(" irep = "); print_irep(pic, proc->u.irep); puts("\nLet's go!"); #endif PUSH(pic_obj_value(proc)); for (i = 1; i < argc; ++i) { PUSH(pic_car(pic, argv)); argv = pic_cdr(pic, argv); } /* boot! */ boot[0].insn = OP_CALL; boot[0].u.i = argc; boot[1].insn = OP_STOP; pc = boot; c = *pc; goto L_CALL; VM_LOOP { CASE(OP_POP) { POPN(1); NEXT; } CASE(OP_PUSHNIL) { PUSH(pic_nil_value()); NEXT; } CASE(OP_PUSHTRUE) { PUSH(pic_true_value()); NEXT; } CASE(OP_PUSHFALSE) { PUSH(pic_false_value()); NEXT; } CASE(OP_PUSHFLOAT) { PUSH(pic_float_value(c.u.f)); NEXT; } CASE(OP_PUSHINT) { PUSH(pic_int_value(c.u.i)); NEXT; } CASE(OP_PUSHCHAR) { PUSH(pic_char_value(c.u.c)); NEXT; } CASE(OP_PUSHCONST) { PUSH(pic->pool[c.u.i]); NEXT; } CASE(OP_GREF) { PUSH(pic->globals[c.u.i]); NEXT; } CASE(OP_GSET) { pic->globals[c.u.i] = POP(); NEXT; } CASE(OP_LREF) { PUSH(pic->ci->fp[c.u.i]); NEXT; } CASE(OP_LSET) { pic->ci->fp[c.u.i] = POP(); NEXT; } CASE(OP_CREF) { int depth = c.u.r.depth; struct pic_env *env; env = pic->ci->env; while (depth--) { env = env->up; } PUSH(env->values[c.u.r.idx]); NEXT; } CASE(OP_CSET) { int depth = c.u.r.depth; struct pic_env *env; env = pic->ci->env; while (depth--) { env = env->up; } env->values[c.u.r.idx] = POP(); NEXT; } CASE(OP_JMP) { pc += c.u.i; JUMP; } CASE(OP_JMPIF) { pic_value v; v = POP(); if (! pic_false_p(v)) { pc += c.u.i; JUMP; } NEXT; } CASE(OP_CALL) { pic_value x, v; pic_callinfo *ci; struct pic_proc *proc; L_CALL: x = pic->sp[-c.u.i]; if (! pic_proc_p(x)) { pic->errmsg = "invalid application"; goto L_RAISE; } proc = pic_proc_ptr(x); ci = PUSHCI(); ci->argc = c.u.i; ci->pc = pc; ci->fp = pic->sp - c.u.i; ci->env = NULL; if (pic_proc_cfunc_p(x)) { v = proc->u.cfunc(pic); pic->sp = ci->fp; POPCI(); PUSH(v); pic_gc_arena_restore(pic, ai); NEXT; } else { int i; pic_value rest; if (ci->argc != proc->u.irep->argc) { if (! (proc->u.irep->varg && ci->argc >= proc->u.irep->argc)) { pic->errmsg = "wrong number of arguments"; goto L_RAISE; } } /* prepare rest args */ if (proc->u.irep->varg) { rest = pic_nil_value(); for (i = 0; i < ci->argc - proc->u.irep->argc; ++i) { pic_gc_protect(pic, v = POP()); rest = pic_cons(pic, v, rest); } PUSH(rest); } /* prepare env */ if (proc->u.irep->cv_num == 0) { ci->env = proc->env; } else { ci->env = (struct pic_env *)pic_obj_alloc(pic, sizeof(struct pic_env), PIC_TT_ENV); ci->env->up = proc->env; ci->env->valuec = proc->u.irep->cv_num; ci->env->values = (pic_value *)pic_calloc(pic, ci->env->valuec, sizeof(pic_value)); for (i = 0; i < ci->env->valuec; ++i) { ci->env->values[i] = ci->fp[proc->u.irep->cv_tbl[i]]; } } pc = proc->u.irep->code; pic_gc_arena_restore(pic, ai); JUMP; } } CASE(OP_TAILCALL) { int argc; pic_value *argv; argc = c.u.i; argv = pic->sp - argc; for (i = 0; i < argc; ++i) { pic->ci->fp[i] = argv[i]; } pic->sp = pic->ci->fp + argc; pc = POPCI()->pc; /* c is not changed */ goto L_CALL; } CASE(OP_RET) { pic_value v; pic_callinfo *ci; if (pic->errmsg) { L_RAISE: goto L_STOP; } else { v = POP(); ci = POPCI(); pc = ci->pc; pic->sp = ci->fp; PUSH(v); } NEXT; } CASE(OP_LAMBDA) { struct pic_proc *proc; proc = pic_proc_new(pic, pic->irep[c.u.i], pic->ci->env); PUSH(pic_obj_value(proc)); pic_gc_arena_restore(pic, ai); NEXT; } CASE(OP_CONS) { pic_value a, b; pic_gc_protect(pic, b = POP()); pic_gc_protect(pic, a = POP()); PUSH(pic_cons(pic, a, b)); pic_gc_arena_restore(pic, ai); NEXT; } CASE(OP_CAR) { pic_value p; p = POP(); PUSH(pic_car(pic, p)); NEXT; } CASE(OP_CDR) { pic_value p; p = POP(); PUSH(pic_cdr(pic, p)); NEXT; } CASE(OP_NILP) { pic_value p; p = POP(); PUSH(pic_bool_value(pic_nil_p(p))); NEXT; } #define DEFINE_ARITH_OP(opcode, op) \ CASE(opcode) { \ pic_value a, b; \ b = POP(); \ a = POP(); \ if (pic_int_p(a) && pic_int_p(b)) { \ double f = (double)pic_int(a) op (double)pic_int(b); \ if (INT_MIN <= f && f <= INT_MAX) { \ PUSH(pic_int_value((int)f)); \ } \ else { \ PUSH(pic_float_value(f)); \ } \ } \ else if (pic_float_p(a) && pic_float_p(b)) { \ PUSH(pic_float_value(pic_float(a) op pic_float(b))); \ } \ else if (pic_int_p(a) && pic_float_p(b)) { \ PUSH(pic_float_value(pic_int(a) op pic_float(b))); \ } \ else if (pic_float_p(a) && pic_int_p(b)) { \ PUSH(pic_float_value(pic_float(a) op pic_int(b))); \ } \ else { \ pic->errmsg = #op " got non-number operands"; \ goto L_RAISE; \ } \ NEXT; \ } DEFINE_ARITH_OP(OP_ADD, +); DEFINE_ARITH_OP(OP_SUB, -); DEFINE_ARITH_OP(OP_MUL, *); /* special care for (int / int) division */ CASE(OP_DIV) { pic_value a, b; b = POP(); a = POP(); if (pic_int_p(a) && pic_int_p(b)) { PUSH(pic_float_value((double)pic_int(a) / pic_int(b))); } else if (pic_float_p(a) && pic_float_p(b)) { PUSH(pic_float_value(pic_float(a) / pic_float(b))); } else if (pic_int_p(a) && pic_float_p(b)) { PUSH(pic_float_value(pic_int(a) / pic_float(b))); } else if (pic_float_p(a) && pic_int_p(b)) { PUSH(pic_float_value(pic_float(a) / pic_int(b))); } else { pic->errmsg = "/ got non-number operands"; goto L_RAISE; } NEXT; } #define DEFINE_COMP_OP(opcode, op) \ CASE(opcode) { \ pic_value a, b; \ b = POP(); \ a = POP(); \ if (pic_int_p(a) && pic_int_p(b)) { \ PUSH(pic_bool_value(pic_int(a) op pic_int(b))); \ } \ else if (pic_float_p(a) && pic_float_p(b)) { \ PUSH(pic_bool_value(pic_float(a) op pic_float(b))); \ } \ else if (pic_int_p(a) && pic_int_p(b)) { \ PUSH(pic_bool_value(pic_int(a) op pic_float(b))); \ } \ else if (pic_float_p(a) && pic_int_p(b)) { \ PUSH(pic_bool_value(pic_float(a) op pic_int(b))); \ } \ else { \ pic->errmsg = #op " got non-number operands"; \ goto L_RAISE; \ } \ NEXT; \ } DEFINE_COMP_OP(OP_EQ, ==); DEFINE_COMP_OP(OP_LT, <); DEFINE_COMP_OP(OP_LE, <=); CASE(OP_STOP) { pic_value val; L_STOP: val = POP(); pic->jmp = NULL; if (pic->errmsg) { return pic_undef_value(); } #if VM_DEBUG puts("**VM END STATE**"); printf("stbase\t= %p\nsp\t= %p\n", pic->stbase, pic->sp); printf("cibase\t= %p\nci\t= %p\n", pic->cibase, pic->ci); if (pic->stbase < pic->sp) { pic_value *sp; printf("* stack trace:"); for (sp = pic->stbase; pic->sp != sp; ++sp) { pic_debug(pic, *sp); puts(""); } } if (pic->stbase > pic->sp) { puts("*** stack underflow!"); } #endif pic_gc_protect(pic, val); return val; } } VM_LOOP_END; }
void pic_defvar(pic_state *pic, const char *name, pic_value init) { pic_define(pic, name, pic_make_var(pic, init, pic_false_value(pic))); }