From 1e178b08607cfe6f61ec83b1ac4893caf02a1be6 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 25 Aug 2025 17:19:50 +0900 Subject: [PATCH] codegen.c: complete monolithic function refactoring Extract final complex cases (NODE_OP_ASGN, NODE_MASGN), unify while/until loop handling, apply early return pattern to reduce indentation, and achieve complete switch statement consistency. The original 5000+ line monolithic function is now organized into 60+ focused functions while preserving all functionality and performance. Co-Authored-By: Claude --- mrbgems/mruby-compiler/core/codegen.c | 3023 ++++++++++++++----------- 1 file changed, 1683 insertions(+), 1340 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 10945854f..10eec8c52 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -2857,9 +2857,8 @@ gen_call(codegen_scope *s, node *tree, int val, int safe) if (safe) { dispatch(s, skip); } - if (val) { - push(); - } + if (!val) return; + push(); } static void @@ -3312,6 +3311,1616 @@ gen_blkmove(codegen_scope *s, uint16_t ainfo, int lv) push(); } +static void +codegen_op_asgn(codegen_scope *s, node *tree, int val) +{ + mrb_sym sym = nsym(tree->cdr->car); + mrb_int len; + const char *name = mrb_sym_name_len(s->mrb, sym, &len); + int idx, callargs = -1, vsp = -1; + + if ((len == 2 && name[0] == '|' && name[1] == '|') && + (nint(tree->car->car) == NODE_CONST || + nint(tree->car->car) == NODE_CVAR)) { + int catch_entry, begin, end; + int noexc, exc; + struct loopinfo *lp; + + lp = loop_push(s, LOOP_BEGIN); + lp->pc0 = new_label(s); + catch_entry = catch_handler_new(s); + begin = s->pc; + exc = cursp(); + codegen(s, tree->car, VAL); + end = s->pc; + noexc = genjmp_0(s, OP_JMP); + lp->type = LOOP_RESCUE; + catch_handler_set(s, catch_entry, MRB_CATCH_RESCUE, begin, end, s->pc); + genop_1(s, OP_EXCEPT, exc); + genop_1(s, OP_LOADF, exc); + dispatch(s, noexc); + loop_pop(s, NOVAL); + } + else if (nint(tree->car->car) == NODE_CALL) { + node *n = tree->car->cdr; + int base, i, nargs = 0; + callargs = 0; + + if (val) { + vsp = cursp(); + push(); + } + codegen(s, n->car, VAL); /* receiver */ + idx = new_sym(s, nsym(n->cdr->car)); + base = cursp()-1; + if (n->cdr->cdr->car) { + nargs = gen_values(s, n->cdr->cdr->car->car, VAL, 13); + if (nargs >= 0) { + callargs = nargs; + } + else { /* varargs */ + push(); + nargs = 1; + callargs = CALL_MAXARGS; + } + } + /* copy receiver and arguments */ + gen_move(s, cursp(), base, 1); + for (i=0; icar, VAL); + } + if (len == 2 && + ((name[0] == '|' && name[1] == '|') || + (name[0] == '&' && name[1] == '&'))) { + uint32_t pos; + + pop(); + if (val) { + if (vsp >= 0) { + gen_move(s, vsp, cursp(), 1); + } + pos = genjmp2_0(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), val); + } + else { + pos = genjmp2_0(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), val); + } + codegen(s, tree->cdr->cdr->car, VAL); + pop(); + if (val && vsp >= 0) { + gen_move(s, vsp, cursp(), 1); + } + if (nint(tree->car->car) == NODE_CALL) { + if (callargs == CALL_MAXARGS) { + pop(); + genop_2(s, OP_ARYPUSH, cursp(), 1); + } + else { + pop_n(callargs); + callargs++; + } + pop(); + idx = new_sym(s, attrsym(s, nsym(tree->car->cdr->cdr->car))); + genop_3(s, OP_SEND, cursp(), idx, callargs); + } + else { + gen_assignment(s, tree->car, NULL, cursp(), val); + } + dispatch(s, pos); + return; + } + codegen(s, tree->cdr->cdr->car, VAL); + push(); pop(); + pop(); pop(); + + if (len == 1 && name[0] == '+') { + gen_addsub(s, OP_ADD, cursp()); + } + else if (len == 1 && name[0] == '-') { + gen_addsub(s, OP_SUB, cursp()); + } + else if (len == 1 && name[0] == '*') { + genop_1(s, OP_MUL, cursp()); + } + else if (len == 1 && name[0] == '/') { + genop_1(s, OP_DIV, cursp()); + } + else if (len == 1 && name[0] == '<') { + genop_1(s, OP_LT, cursp()); + } + else if (len == 2 && name[0] == '<' && name[1] == '=') { + genop_1(s, OP_LE, cursp()); + } + else if (len == 1 && name[0] == '>') { + genop_1(s, OP_GT, cursp()); + } + else if (len == 2 && name[0] == '>' && name[1] == '=') { + genop_1(s, OP_GE, cursp()); + } + else { + idx = new_sym(s, sym); + genop_3(s, OP_SEND, cursp(), idx, 1); + } + if (callargs < 0) { + gen_assignment(s, tree->car, NULL, cursp(), val); + } + else { + if (val && vsp >= 0) { + gen_move(s, vsp, cursp(), 0); + } + if (callargs == CALL_MAXARGS) { + pop(); + genop_2(s, OP_ARYPUSH, cursp(), 1); + } + else { + pop_n(callargs); + callargs++; + } + pop(); + idx = new_sym(s, attrsym(s,nsym(tree->car->cdr->cdr->car))); + genop_3(s, OP_SEND, cursp(), idx, callargs); + } +} + +static void +codegen_masgn(codegen_scope *s, node *tree, int val) +{ + int len = 0, n = 0, post = 0; + node *t = tree->cdr, *p; + int rhs = cursp(); + + if (!val && nint(t->car) == NODE_ARRAY && t->cdr && nosplat(t->cdr)) { + /* fixed rhs */ + t = t->cdr; + while (t) { + codegen(s, t->car, VAL); + len++; + t = t->cdr; + } + tree = tree->car; + if (tree->car) { /* pre */ + t = tree->car; + n = 0; + while (t) { + if (n < len) { + gen_assignment(s, t->car, NULL, rhs+n, NOVAL); + n++; + } + else { + genop_1(s, OP_LOADNIL, rhs+n); + gen_assignment(s, t->car, NULL, rhs+n, NOVAL); + } + t = t->cdr; + } + } + t = tree->cdr; + if (t) { + if (t->cdr) { /* post count */ + p = t->cdr->car; + while (p) { + post++; + p = p->cdr; + } + } + if (t->car) { /* rest (len - pre - post) */ + int rn; + + if (len < post + n) { + rn = 0; + } + else { + rn = len - post - n; + } + if (cursp() == rhs+n) { + genop_2(s, OP_ARRAY, cursp(), rn); + } + else { + genop_3(s, OP_ARRAY2, cursp(), rhs+n, rn); + } + gen_assignment(s, t->car, NULL, cursp(), NOVAL); + n += rn; + } + if (t->cdr && t->cdr->car) { + t = t->cdr->car; + while (t) { + if (ncar, NULL, rhs+n, NOVAL); + } + else { + genop_1(s, OP_LOADNIL, cursp()); + gen_assignment(s, t->car, NULL, cursp(), NOVAL); + } + t = t->cdr; + n++; + } + } + } + pop_n(len); + } + else { + /* variable rhs */ + codegen(s, t, VAL); + gen_massignment(s, tree->car, rhs, val); + if (!val) { + pop(); + } + } +} + +static void +codegen_stmts(codegen_scope *s, node *tree, int val) +{ + if (val && !tree) { + genop_1(s, OP_LOADNIL, cursp()); + push(); + } + while (tree) { + codegen(s, tree->car, tree->cdr ? NOVAL : val); + tree = tree->cdr; + } +} + +static void +codegen_begin(codegen_scope *s, node *tree, int val) +{ + /* NODE_BEGIN contains a single body node directly in cdr */ + codegen(s, tree, val); +} + +static void +codegen_rescue(codegen_scope *s, node *tree, int val) +{ + int noexc; + uint32_t exend, pos1, pos2, tmp; + struct loopinfo *lp; + int catch_entry, begin, end; + + if (tree->car == NULL) return; + lp = loop_push(s, LOOP_BEGIN); + lp->pc0 = new_label(s); + catch_entry = catch_handler_new(s); + begin = s->pc; + codegen(s, tree->car, VAL); + pop(); + lp->type = LOOP_RESCUE; + end = s->pc; + noexc = genjmp_0(s, OP_JMP); + catch_handler_set(s, catch_entry, MRB_CATCH_RESCUE, begin, end, s->pc); + tree = tree->cdr; + exend = JMPLINK_START; + pos1 = JMPLINK_START; + if (tree->car) { + node *n2 = tree->car; + int exc = cursp(); + + genop_1(s, OP_EXCEPT, exc); + push(); + while (n2) { + node *n3 = n2->car; + node *n4 = n3->car; + + dispatch(s, pos1); + pos2 = JMPLINK_START; + do { + if (n4 && n4->car && nint(n4->car->car) == NODE_SPLAT) { + codegen(s, n4->car, VAL); + gen_move(s, cursp(), exc, 0); + push_n(2); pop_n(2); /* space for one arg and a block */ + pop(); + genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_SYM_2(s->mrb, __case_eqq)), 1); + } + else { + if (n4) { + codegen(s, n4->car, VAL); + } + else { + genop_2(s, OP_GETCONST, cursp(), new_sym(s, MRB_SYM_2(s->mrb, StandardError))); + push(); + } + pop(); + genop_2(s, OP_RESCUE, exc, cursp()); + } + tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, val); + pos2 = tmp; + if (n4) { + n4 = n4->cdr; + } + } while (n4); + pos1 = genjmp_0(s, OP_JMP); + dispatch_linked(s, pos2); + + pop(); + if (n3->cdr->car) { + gen_assignment(s, n3->cdr->car, NULL, exc, NOVAL); + } + if (n3->cdr->cdr->car) { + codegen(s, n3->cdr->cdr->car, val); + if (val) pop(); + } + tmp = genjmp(s, OP_JMP, exend); + exend = tmp; + n2 = n2->cdr; + push(); + } + if (pos1 != JMPLINK_START) { + dispatch(s, pos1); + genop_1(s, OP_RAISEIF, exc); + } + } + pop(); + tree = tree->cdr; + dispatch(s, noexc); + if (tree->car) { + codegen(s, tree->car, val); + } + else if (val) { + push(); + } + dispatch_linked(s, exend); + loop_pop(s, NOVAL); +} + +static void +codegen_ensure(codegen_scope *s, node *tree, int val) +{ + if (!tree->cdr || !tree->cdr->cdr || + (nint(tree->cdr->cdr->car) == NODE_STMTS && + tree->cdr->cdr->cdr)) { + int catch_entry, begin, end, target; + int idx; + + catch_entry = catch_handler_new(s); + begin = s->pc; + codegen(s, tree->car, val); + end = target = s->pc; + push(); + idx = cursp(); + genop_1(s, OP_EXCEPT, idx); + push(); + codegen(s, tree->cdr->cdr, NOVAL); + pop(); + genop_1(s, OP_RAISEIF, idx); + pop(); + catch_handler_set(s, catch_entry, MRB_CATCH_ENSURE, begin, end, target); + } + else { /* empty ensure ignored */ + codegen(s, tree->car, val); + } +} + +static void +codegen_lambda(codegen_scope *s, node *tree, int val) +{ + if (!val) return; + + int idx = lambda_body(s, tree, 1); + genop_2(s, OP_LAMBDA, cursp(), idx); + push(); +} + +static void +codegen_block(codegen_scope *s, node *tree, int val) +{ + if (!val) return; + + int idx = lambda_body(s, tree, 1); + genop_2(s, OP_BLOCK, cursp(), idx); + push(); +} + +static void +codegen_if(codegen_scope *s, node *tree, int val) +{ + uint32_t pos1, pos2; + mrb_bool nil_p = FALSE; + node *elsepart = tree->cdr->cdr->car; + + if (!tree->car) { + codegen(s, elsepart, val); + return; + } + if (true_always(tree->car)) { + codegen(s, tree->cdr->car, val); + return; + } + if (false_always(tree->car)) { + codegen(s, elsepart, val); + return; + } + if (nint(tree->car->car) == NODE_CALL) { + node *n = tree->car->cdr; + mrb_sym mid = nsym(n->cdr->car); + mrb_sym sym_nil_p = MRB_SYM_Q_2(s->mrb, nil); + if (mid == sym_nil_p && n->cdr->cdr->car == NULL) { + nil_p = TRUE; + codegen(s, n->car, VAL); + } + } + if (!nil_p) { + codegen(s, tree->car, VAL); + } + pop(); + if (val || tree->cdr->car) { + if (nil_p) { + pos2 = genjmp2_0(s, OP_JMPNIL, cursp(), val); + pos1 = genjmp_0(s, OP_JMP); + dispatch(s, pos2); + } + else { + pos1 = genjmp2_0(s, OP_JMPNOT, cursp(), val); + } + codegen(s, tree->cdr->car, val); + if (val) pop(); + if (elsepart || val) { + pos2 = genjmp_0(s, OP_JMP); + dispatch(s, pos1); + codegen(s, elsepart, val); + dispatch(s, pos2); + } + else { + dispatch(s, pos1); + } + } + else { /* empty then-part */ + if (elsepart) { + if (nil_p) { + pos1 = genjmp2_0(s, OP_JMPNIL, cursp(), val); + } + else { + pos1 = genjmp2_0(s, OP_JMPIF, cursp(), val); + } + codegen(s, elsepart, val); + dispatch(s, pos1); + } + else if (val && !nil_p) { + genop_1(s, OP_LOADNIL, cursp()); + push(); + } + } +} + +static void +codegen_and(codegen_scope *s, node *tree, int val) +{ + uint32_t pos; + + if (true_always(tree->car)) { + codegen(s, tree->cdr, val); + return; + } + if (false_always(tree->car)) { + codegen(s, tree->car, val); + return; + } + codegen(s, tree->car, VAL); + pop(); + pos = genjmp2_0(s, OP_JMPNOT, cursp(), val); + codegen(s, tree->cdr, val); + dispatch(s, pos); +} + +static void +codegen_or(codegen_scope *s, node *tree, int val) +{ + uint32_t pos; + + if (true_always(tree->car)) { + codegen(s, tree->car, val); + return; + } + if (false_always(tree->car)) { + codegen(s, tree->cdr, val); + return; + } + codegen(s, tree->car, VAL); + pop(); + pos = genjmp2_0(s, OP_JMPIF, cursp(), val); + codegen(s, tree->cdr, val); + dispatch(s, pos); +} + +static void +codegen_self(codegen_scope *s, node *tree, int val) +{ + if (!val) return; + + genop_1(s, OP_LOADSELF, cursp()); + push(); +} + +static void +codegen_nil(codegen_scope *s, node *tree, int val) +{ + if (!val) return; + + genop_1(s, OP_LOADNIL, cursp()); + push(); +} + +static void +codegen_true(codegen_scope *s, node *tree, int val) +{ + if (!val) return; + + genop_1(s, OP_LOADT, cursp()); + push(); +} + +static void +codegen_false(codegen_scope *s, node *tree, int val) +{ + if (!val) return; + + genop_1(s, OP_LOADF, cursp()); + push(); +} + +static void +codegen_lvar(codegen_scope *s, node *tree, int val) +{ + if (!val) return; + int idx = lv_idx(s, nsym(tree)); + + if (idx > 0) { + gen_move(s, cursp(), idx, val); + } + else { + gen_getupvar(s, cursp(), nsym(tree)); + } + push(); +} + +static void +codegen_nvar(codegen_scope *s, node *tree, int val) +{ + if (!val) return; + int idx = nint(tree); + + gen_move(s, cursp(), idx, val); + push(); +} + +static void +codegen_gvar(codegen_scope *s, node *tree, int val) +{ + if (!val) return; + int sym = new_sym(s, nsym(tree)); + + genop_2(s, OP_GETGV, cursp(), sym); + push(); +} + +static void +codegen_ivar(codegen_scope *s, node *tree, int val) +{ + if (!val) return; + int sym = new_sym(s, nsym(tree)); + + genop_2(s, OP_GETIV, cursp(), sym); + push(); +} + +static void +codegen_cvar(codegen_scope *s, node *tree, int val) +{ + if (!val) return; + int sym = new_sym(s, nsym(tree)); + + genop_2(s, OP_GETCV, cursp(), sym); + push(); +} + +static void +codegen_const(codegen_scope *s, node *tree, int val) +{ + int sym = new_sym(s, nsym(tree)); + + genop_2(s, OP_GETCONST, cursp(), sym); + if (val) push(); +} + +static void +codegen_sym(codegen_scope *s, node *tree, int val) +{ + if (!val) return; + + int sym = new_sym(s, nsym(tree)); + genop_2(s, OP_LOADSYM, cursp(), sym); + push(); +} + +static void +codegen_dsym(codegen_scope *s, node *tree, int val) +{ + codegen(s, tree, val); + if (!val) return; + gen_intern(s); +} + +static void +codegen_array(codegen_scope *s, node *tree, int val) +{ + int n; + + n = gen_values(s, tree, val, 0); + if (!val) return; + if (n >= 0) { + pop_n(n); + genop_2(s, OP_ARRAY, cursp(), n); + } + push(); +} + +static void +codegen_hash(codegen_scope *s, node *tree, int val) +{ + int nk = gen_hash(s, tree, val, GEN_LIT_ARY_MAX); + if (val && nk >= 0) { + pop_n(nk*2); + genop_2(s, OP_HASH, cursp(), nk); + push(); + } +} + +static void +codegen_splat(codegen_scope *s, node *tree, int val) +{ + codegen(s, tree, val); +} + +static void +codegen_scope_node(codegen_scope *s, node *tree, int val) +{ + scope_body(s, tree, NOVAL); +} + +static void +codegen_call_fcall(codegen_scope *s, node *tree, int val) +{ + gen_call(s, tree, val, 0); +} + +static void +codegen_dot2(codegen_scope *s, node *tree, int val) +{ + codegen(s, tree->car, val); + codegen(s, tree->cdr, val); + if (!val) return; + pop(); pop(); + genop_1(s, OP_RANGE_INC, cursp()); + push(); +} + +static void +codegen_dot3(codegen_scope *s, node *tree, int val) +{ + codegen(s, tree->car, val); + codegen(s, tree->cdr, val); + if (!val) return; + pop(); pop(); + genop_1(s, OP_RANGE_EXC, cursp()); + push(); +} + +static void +codegen_scall(codegen_scope *s, node *tree, int val) +{ + gen_call(s, tree, val, 1); +} + +static void +codegen_case(codegen_scope *s, node *tree, int val) +{ + int head = 0; + uint32_t pos1, pos2, pos3, tmp; + node *n; + + pos3 = JMPLINK_START; + if (tree->car) { + head = cursp(); + codegen(s, tree->car, VAL); + } + tree = tree->cdr; + while (tree) { + n = tree->car->car; + pos1 = pos2 = JMPLINK_START; + while (n) { + codegen(s, n->car, VAL); + if (head) { + gen_move(s, cursp(), head, 0); + push(); push(); pop(); pop(); pop(); + if (nint(n->car->car) == NODE_SPLAT) { + genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_SYM_2(s->mrb, __case_eqq)), 1); + } + else { + genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_OPSYM_2(s->mrb, eqq)), 1); + } + } + else { + pop(); + } + tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, !head); + pos2 = tmp; + n = n->cdr; + } + if (tree->car->car) { + pos1 = genjmp_0(s, OP_JMP); + dispatch_linked(s, pos2); + } + codegen(s, tree->car->cdr, val); + if (val) pop(); + tmp = genjmp(s, OP_JMP, pos3); + pos3 = tmp; + dispatch(s, pos1); + tree = tree->cdr; + } + if (val) { + uint32_t pos = cursp(); + genop_1(s, OP_LOADNIL, cursp()); + if (pos3 != JMPLINK_START) dispatch_linked(s, pos3); + if (head) pop(); + if (cursp() != pos) { + gen_move(s, cursp(), pos, 0); + } + push(); + } + else { + if (pos3 != JMPLINK_START) { + dispatch_linked(s, pos3); + } + if (head) { + pop(); + } + } +} + +static void +codegen_for(codegen_scope *s, node *tree, int val) +{ + for_body(s, tree); + if (val) push(); +} + +static void +codegen_while_until(codegen_scope *s, node *tree, int val, int nt) +{ + /* Handle modifier-specific optimizations first */ + if (nt == NODE_WHILE_MOD || nt == NODE_UNTIL_MOD) { + /* Post-tested loops: execute body first, then check condition */ + if (false_always(tree->car)) { + if (nt == NODE_WHILE_MOD) { + /* begin...end while false - execute once then exit */ + codegen(s, tree->cdr, val); + if (val) push(); + return; + } + } + else if (true_always(tree->car)) { + if (nt == NODE_UNTIL_MOD) { + /* begin...end until true - execute once then exit */ + codegen(s, tree->cdr, val); + if (val) push(); + return; + } + } + } + + uint32_t pos0 = JMPLINK_START; + if (nt == NODE_WHILE_MOD || nt == NODE_UNTIL_MOD) { + genjmp_0(s, OP_JMP); + pos0 = s->pc - mrb_insn_size[OP_JMP] + 1; + } + + if (true_always(tree->car)) { + if (nt == NODE_UNTIL || nt == NODE_UNTIL_MOD) { + if (val) { + genop_1(s, OP_LOADNIL, cursp()); + push(); + } + return; + } + } + else if (false_always(tree->car)) { + if (nt == NODE_WHILE || nt == NODE_WHILE_MOD) { + if (val) { + genop_1(s, OP_LOADNIL, cursp()); + push(); + } + return; + } + } + + struct loopinfo *lp = loop_push(s, LOOP_NORMAL); + + if (!val) lp->reg = -1; + lp->pc0 = new_label(s); + codegen(s, tree->car, VAL); + pop(); + + uint32_t pos; + if (nt == NODE_WHILE || nt == NODE_WHILE_MOD) { + pos = genjmp2_0(s, OP_JMPNOT, cursp(), NOVAL); + } + else { /* UNTIL */ + pos = genjmp2_0(s, OP_JMPIF, cursp(), NOVAL); + } + lp->pc1 = new_label(s); + genop_0(s, OP_NOP); /* for redo */ + dispatch(s, pos0); + codegen(s, tree->cdr, NOVAL); + genjmp(s, OP_JMP, lp->pc0); + dispatch(s, pos); + loop_pop(s, val); +} + +static void +codegen_negate(codegen_scope *s, node *tree, int val) +{ + int nt = nint(tree->car); + switch (nt) { +#ifndef MRB_NO_FLOAT + case NODE_FLOAT: + if (val) { + char *p = (char*)tree->cdr; + double f; + mrb_read_float(p, NULL, &f); + int off = new_lit_float(s, (mrb_float)-f); + + genop_2(s, OP_LOADL, cursp(), off); + push(); + } + break; +#endif + + case NODE_INT: + if (val) { + char *p = (char*)tree->cdr->car; + int base = nint(tree->cdr->cdr->car); + mrb_int i; + mrb_bool overflow; + + i = readint(s, p, base, TRUE, &overflow); + if (overflow) { + base = -base; + int off = new_litbint(s, p, base); + genop_2(s, OP_LOADL, cursp(), off); + } + else { + gen_int(s, cursp(), i); + } + push(); + } + break; + + default: + codegen(s, tree, VAL); + pop(); + push_n(2);pop_n(2); /* space for receiver&block */ + mrb_sym minus = MRB_OPSYM_2(s->mrb, minus); + if (!gen_uniop(s, minus, cursp())) { + genop_3(s, OP_SEND, cursp(), new_sym(s, minus), 0); + } + if (val) push(); + break; + } +} + +static void +codegen_float(codegen_scope *s, node *tree, int val) +{ + if (!val) return; + char *p = (char*)tree; + double f; + mrb_read_float(p, NULL, &f); + int off = new_lit_float(s, (mrb_float)f); + + genop_2(s, OP_LOADL, cursp(), off); + push(); +} + +static void +codegen_int(codegen_scope *s, node *tree, int val) +{ + if (!val) return; + char *p = (char*)tree->car; + int base = nint(tree->cdr->car); + mrb_int i; + mrb_bool overflow; + + i = readint(s, p, base, FALSE, &overflow); + if (overflow) { + int off = new_litbint(s, p, base); + genop_2(s, OP_LOADL, cursp(), off); + } + else { + gen_int(s, cursp(), i); + } + push(); +} + +static void +codegen_xstr(codegen_scope *s, node *tree, int val) +{ + char *p = (char*)tree->car; + mrb_int len = nint(tree->cdr); + int off = new_lit_str(s, p, len); + int sym; + + push(); + genop_2(s, OP_STRING, cursp(), off); + push(); push(); + pop_n(3); + sym = new_sym(s, MRB_OPSYM_2(s->mrb, tick)); /* ` */ + genop_3(s, OP_SSEND, cursp(), sym, 1); + if (val) push(); +} + +static void +codegen_words(codegen_scope *s, node *tree, int val) +{ + gen_literal_array(s, tree, FALSE, val); +} + +static void +codegen_dxstr(codegen_scope *s, node *tree, int val) +{ + node *n; + int sym = new_sym(s, MRB_SYM_2(s->mrb, Kernel)); + + push(); + codegen(s, tree->car, VAL); + n = tree->cdr; + while (n) { + if (nint(n->car->car) == NODE_XSTR) { + n->car->car = (struct mrb_ast_node*)(intptr_t)NODE_STR; + mrb_assert(!n->cdr); /* must be the end */ + } + codegen(s, n->car, VAL); + pop(); pop(); + genop_1(s, OP_STRCAT, cursp()); + push(); + n = n->cdr; + } + push(); /* for block */ + pop_n(3); + sym = new_sym(s, MRB_OPSYM_2(s->mrb, tick)); /* ` */ + genop_3(s, OP_SSEND, cursp(), sym, 1); + if (val) push(); +} + +static void +codegen_symbols(codegen_scope *s, node *tree, int val) +{ + gen_literal_array(s, tree, TRUE, val); +} + +static void +codegen_heredoc_dstr(codegen_scope *s, node *tree, int val) +{ + if (val) { + node *n = tree; + + if (!n) { + genop_1(s, OP_LOADNIL, cursp()); + push(); + return; + } + codegen(s, n->car, VAL); + n = n->cdr; + while (n) { + codegen(s, n->car, VAL); + pop(); pop(); + genop_1(s, OP_STRCAT, cursp()); + push(); + n = n->cdr; + } + } + else { + node *n = tree; + + while (n) { + if (nint(n->car->car) != NODE_STR) { + codegen(s, n->car, NOVAL); + } + n = n->cdr; + } + } +} + +static void +codegen_str(codegen_scope *s, node *tree, int val) +{ + if (val) { + char *p = (char*)tree->car; + mrb_int len = nint(tree->cdr); + int off = new_lit_str(s, p, len); + + genop_2(s, OP_STRING, cursp(), off); + push(); + } +} + +static void +codegen_dregx(codegen_scope *s, node *tree, int val) +{ + if (val) { + node *n = tree->car; + int sym = new_sym(s, mrb_intern_lit(s->mrb, REGEXP_CLASS)); + int argc = 1; + int off; + char *p; + + genop_1(s, OP_OCLASS, cursp()); + genop_2(s, OP_GETMCNST, cursp(), sym); + push(); + codegen(s, n->car, VAL); + n = n->cdr; + while (n) { + codegen(s, n->car, VAL); + pop(); pop(); + genop_1(s, OP_STRCAT, cursp()); + push(); + n = n->cdr; + } + n = tree->cdr->cdr; + if (n->car) { /* tail */ + p = (char*)n->car; + off = new_lit_cstr(s, p); + codegen(s, tree->car, VAL); + genop_2(s, OP_STRING, cursp(), off); + pop(); + genop_1(s, OP_STRCAT, cursp()); + push(); + } + if (n->cdr->car) { /* opt */ + char *p2 = (char*)n->cdr->car; + off = new_lit_cstr(s, p2); + genop_2(s, OP_STRING, cursp(), off); + push(); + argc++; + } + if (n->cdr->cdr) { /* enc */ + char *p2 = (char*)n->cdr->cdr; + off = new_lit_cstr(s, p2); + genop_2(s, OP_STRING, cursp(), off); + push(); + argc++; + } + push(); /* space for a block */ + pop_n(argc+2); + sym = new_sym(s, MRB_SYM_2(s->mrb, compile)); + genop_3(s, OP_SEND, cursp(), sym, argc); + push(); + } + else { + node *n = tree->car; + + while (n) { + if (nint(n->car->car) != NODE_STR) { + codegen(s, n->car, NOVAL); + } + n = n->cdr; + } + } +} + +static void +codegen_regx(codegen_scope *s, node *tree, int val) +{ + if (val) { + char *p1 = (char*)tree->car; + char *p2 = (char*)tree->cdr->car; + char *p3 = (char*)tree->cdr->cdr; + int sym = new_sym(s, mrb_intern_lit(s->mrb, REGEXP_CLASS)); + int off = new_lit_cstr(s, p1); + int argc = 1; + + genop_1(s, OP_OCLASS, cursp()); + genop_2(s, OP_GETMCNST, cursp(), sym); + push(); + genop_2(s, OP_STRING, cursp(), off); + push(); + if (p2 || p3) { + if (p2) { /* opt */ + off = new_lit_cstr(s, p2); + genop_2(s, OP_STRING, cursp(), off); + } + else { + genop_1(s, OP_LOADNIL, cursp()); + } + push(); + argc++; + if (p3) { /* enc */ + off = new_lit_str(s, p3, 1); + genop_2(s, OP_STRING, cursp(), off); + push(); + argc++; + } + } + push(); /* space for a block */ + pop_n(argc+2); + sym = new_sym(s, MRB_SYM_2(s->mrb, compile)); + genop_3(s, OP_SEND, cursp(), sym, argc); + push(); + } +} + +static void +codegen_asgn(codegen_scope *s, node *tree, int val) +{ + gen_assignment(s, tree->car, tree->cdr, 0, val); +} + +static void +codegen_def(codegen_scope *s, node *tree, int val) +{ + int sym = new_sym(s, nsym(tree->car)); + int idx = lambda_body(s, tree->cdr, 0); + + genop_1(s, OP_TCLASS, cursp()); + push(); + genop_2(s, OP_METHOD, cursp(), idx); + push(); pop(); + pop(); + genop_2(s, OP_DEF, cursp(), sym); + if (val) push(); +} + +static void +codegen_sdef(codegen_scope *s, node *tree, int val) +{ + node *recv = tree->car; + int sym = new_sym(s, nsym(tree->cdr->car)); + int idx = lambda_body(s, tree->cdr->cdr, 0); + + codegen(s, recv, VAL); + pop(); + genop_1(s, OP_SCLASS, cursp()); + push(); + genop_2(s, OP_METHOD, cursp(), idx); + push(); pop(); + pop(); + genop_2(s, OP_DEF, cursp(), sym); + if (val) push(); +} + +static void +codegen_postexe(codegen_scope *s, node *tree, int val) +{ + codegen(s, tree, NOVAL); +} + +static void +codegen_class(codegen_scope *s, node *tree, int val) +{ + int idx; + node *body; + + if (tree->car->car == (node*)0) { + genop_1(s, OP_LOADNIL, cursp()); + push(); + } + else if (tree->car->car == (node*)1) { + genop_1(s, OP_OCLASS, cursp()); + push(); + } + else { + codegen(s, tree->car->car, VAL); + } + if (tree->cdr->car) { + codegen(s, tree->cdr->car, VAL); + } + else { + genop_1(s, OP_LOADNIL, cursp()); + push(); + } + pop(); pop(); + idx = new_sym(s, nsym(tree->car->cdr)); + genop_2(s, OP_CLASS, cursp(), idx); + body = tree->cdr->cdr->car; + if (nint(body->cdr->car) == NODE_STMTS && body->cdr->cdr == NULL) { + genop_1(s, OP_LOADNIL, cursp()); + } + else { + idx = scope_body(s, body, val); + genop_2(s, OP_EXEC, cursp(), idx); + } + if (val) { + push(); + } +} + +static void +codegen_module(codegen_scope *s, node *tree, int val) +{ + int idx; + + if (tree->car->car == (node*)0) { + genop_1(s, OP_LOADNIL, cursp()); + push(); + } + else if (tree->car->car == (node*)1) { + genop_1(s, OP_OCLASS, cursp()); + push(); + } + else { + codegen(s, tree->car->car, VAL); + } + pop(); + idx = new_sym(s, nsym(tree->car->cdr)); + genop_2(s, OP_MODULE, cursp(), idx); + if (nint(tree->cdr->car->cdr->car) == NODE_STMTS && + tree->cdr->car->cdr->cdr == NULL) { + genop_1(s, OP_LOADNIL, cursp()); + } + else { + idx = scope_body(s, tree->cdr->car, val); + genop_2(s, OP_EXEC, cursp(), idx); + } + if (val) { + push(); + } +} + +static void +codegen_sclass(codegen_scope *s, node *tree, int val) +{ + int idx; + + codegen(s, tree->car, VAL); + pop(); + genop_1(s, OP_SCLASS, cursp()); + if (nint(tree->cdr->car->cdr->car) == NODE_STMTS && + tree->cdr->car->cdr->cdr == NULL) { + genop_1(s, OP_LOADNIL, cursp()); + } + else { + idx = scope_body(s, tree->cdr->car, val); + genop_2(s, OP_EXEC, cursp(), idx); + } + if (val) { + push(); + } +} + +static void +codegen_alias(codegen_scope *s, node *tree, int val) +{ + int a = new_sym(s, nsym(tree->car)); + int b = new_sym(s, nsym(tree->cdr)); + + genop_2(s, OP_ALIAS, a, b); + if (!val) return; + genop_1(s, OP_LOADNIL, cursp()); + push(); +} + +static void +codegen_undef(codegen_scope *s, node *tree, int val) +{ + node *t = tree; + + while (t) { + int symbol = new_sym(s, nsym(t->car)); + genop_1(s, OP_UNDEF, symbol); + t = t->cdr; + } + if (!val) return; + genop_1(s, OP_LOADNIL, cursp()); + push(); +} + +static void +codegen_return(codegen_scope *s, node *tree, int val) +{ + if (tree) { + gen_retval(s, tree); + } + else { + genop_1(s, OP_LOADNIL, cursp()); + } + if (s->loop) { + gen_return(s, OP_RETURN_BLK, cursp()); + } + else { + gen_return(s, OP_RETURN, cursp()); + } + if (!val) return; + push(); +} + +static void +codegen_break(codegen_scope *s, node *tree, int val) +{ + loop_break(s, tree); + if (!val) return; + push(); +} + +static void +codegen_next(codegen_scope *s, node *tree, int val) +{ + if (!s->loop) { + raise_error(s, "unexpected next"); + } + else if (s->loop->type == LOOP_NORMAL) { + codegen(s, tree, NOVAL); + genjmp(s, OP_JMPUW, s->loop->pc0); + } + else { + if (tree) { + codegen(s, tree, VAL); + pop(); + } + else { + genop_1(s, OP_LOADNIL, cursp()); + } + gen_return(s, OP_RETURN, cursp()); + } + if (!val) return; + push(); +} + +static void +codegen_colon2(codegen_scope *s, node *tree, int val) +{ + int sym = new_sym(s, nsym(tree->cdr)); + + codegen(s, tree->car, VAL); + pop(); + genop_2(s, OP_GETMCNST, cursp(), sym); + if (val) push(); +} + +static void +codegen_colon3(codegen_scope *s, node *tree, int val) +{ + int sym = new_sym(s, nsym(tree)); + + genop_1(s, OP_OCLASS, cursp()); + genop_2(s, OP_GETMCNST, cursp(), sym); + if (val) push(); +} + +static void +codegen_redo(codegen_scope *s, node *tree, int val) +{ + for (const struct loopinfo *lp = s->loop; ; lp = lp->prev) { + if (!lp) { + raise_error(s, "unexpected redo"); + break; + } + if (lp->type != LOOP_BEGIN && lp->type != LOOP_RESCUE) { + genjmp(s, OP_JMPUW, lp->pc1); + break; + } + } + if (!val) return; + push(); +} + +static void +codegen_retry(codegen_scope *s, node *tree, int val) +{ + const struct loopinfo *lp = s->loop; + + while (lp && lp->type != LOOP_RESCUE) { + lp = lp->prev; + } + if (!lp) { + raise_error(s, "unexpected retry"); + } + else { + genjmp(s, OP_JMPUW, lp->pc0); + } + if (!val) return; + push(); +} + +static void +codegen_back_ref(codegen_scope *s, node *tree, int val) +{ + if (!val) return; + + char buf[] = {'$', nchar(tree)}; + int sym = new_sym(s, mrb_intern(s->mrb, buf, sizeof(buf))); + genop_2(s, OP_GETGV, cursp(), sym); + push(); +} + +static void +codegen_nth_ref(codegen_scope *s, node *tree, int val) +{ + if (!val) return; + + mrb_state *mrb = s->mrb; + mrb_value str; + int sym; + + str = mrb_format(mrb, "$%d", nint(tree)); + sym = new_sym(s, mrb_intern_str(mrb, str)); + genop_2(s, OP_GETGV, cursp(), sym); + push(); +} + +static void +codegen_block_arg(codegen_scope *s, node *tree, int val) +{ + if (!tree) { + int idx = lv_idx(s, MRB_OPSYM_2(s->mrb, and)); + + if (idx == 0) { + gen_getupvar(s, cursp(), MRB_OPSYM_2(s->mrb, and)); + } + else { + gen_move(s, cursp(), idx, val); + } + if (val) push(); + } + else { + codegen(s, tree, val); + } +} + +static void +codegen_heredoc(codegen_scope *s, node *tree, int val) +{ + tree = ((struct mrb_parser_heredoc_info*)tree)->doc; + codegen_heredoc_dstr(s, tree, val); +} + +static void +codegen_super(codegen_scope *s, node *tree, int val) +{ + codegen_scope *s2 = s; + int lv = 0; + int n = 0, nk = 0, st = 0; + + push(); + while (!s2->mscope) { + lv++; + s2 = s2->prev; + if (!s2) break; + } + if (tree) { + node *args = tree->car; + if (args) { + st = n = gen_values(s, args, VAL, 14); + if (n < 0) { + st = 1; n = 15; + push(); + } + } + /* keyword arguments */ + if (tree->cdr->car) { + nk = gen_hash(s, tree->cdr->car->cdr, VAL, 14); + if (nk < 0) {st++; nk = 15;} + else st += nk*2; + n |= nk<<4; + } + /* block arguments */ + if (tree->cdr->cdr) { + codegen(s, tree->cdr->cdr, VAL); + } + else if (s2) gen_blkmove(s, s2->ainfo, lv); + else { + genop_1(s, OP_LOADNIL, cursp()); + push(); + } + } + else { + if (s2) gen_blkmove(s, s2->ainfo, lv); + else { + genop_1(s, OP_LOADNIL, cursp()); + push(); + } + } + st++; + pop_n(st+1); + genop_2(s, OP_SUPER, cursp(), n); + if (val) push(); +} + +static void +codegen_zsuper(codegen_scope *s, node *tree, int val) +{ + codegen_scope *s2 = s; + int lv = 0; + uint16_t ainfo = 0; + int n = CALL_MAXARGS; + int sp = cursp(); + + push(); /* room for receiver */ + while (!s2->mscope) { + lv++; + s2 = s2->prev; + if (!s2) break; + } + if (s2 && s2->ainfo > 0) { + ainfo = s2->ainfo; + } + if (lv > 0xf) codegen_error(s, "too deep nesting"); + if (ainfo > 0) { + genop_2S(s, OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf)); + push(); push(); push(); /* ARGARY pushes 3 values at most */ + pop(); pop(); pop(); + /* keyword arguments */ + if (ainfo & 0x1) { + n |= CALL_MAXARGS<<4; + push(); + } + /* block argument */ + if (tree && tree->cdr && tree->cdr->cdr) { + push(); + codegen(s, tree->cdr->cdr, VAL); + } + } + else { + /* block argument */ + if (tree && tree->cdr && tree->cdr->cdr) { + codegen(s, tree->cdr->cdr, VAL); + } + else if (s2) { + gen_blkmove(s, 0, lv); + } + else { + genop_1(s, OP_LOADNIL, cursp()); + } + n = 0; + } + s->sp = sp; + genop_2(s, OP_SUPER, cursp(), n); + if (val) push(); +} + +static void +codegen_yield(codegen_scope *s, node *tree, int val) +{ + codegen_scope *s2 = s; + int lv = 0, ainfo = -1; + int n = 0, nk = 0, sendv = 0; + + while (!s2->mscope) { + lv++; + s2 = s2->prev; + if (!s2) break; + } + if (s2) { + ainfo = (int)s2->ainfo; + } + if (ainfo < 0) codegen_error(s, "invalid yield (SyntaxError)"); + if (lv > 0xf) codegen_error(s, "too deep nesting"); + push(); + if (tree) { + if (tree->car) { + n = gen_values(s, tree->car, VAL, 14); + if (n < 0) { + n = sendv = 1; + push(); + } + } + if (tree->cdr->car) { + nk = gen_hash(s, tree->cdr->car->cdr, VAL, 14); + if (nk < 0) { + nk = 15; + } + } + } + push();pop(); /* space for a block */ + pop_n(n + (nk == 15 ? 1 : nk * 2) + 1); + genop_2S(s, OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf)); + if (sendv) n = CALL_MAXARGS; + genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_SYM_2(s->mrb, call)), n|(nk<<4)); + if (val) push(); +} + + static void codegen(codegen_scope *s, node *tree, int val) { @@ -3346,1043 +4955,171 @@ codegen(codegen_scope *s, node *tree, int val) tree = tree->cdr; switch (nt) { case NODE_STMTS: - if (val && !tree) { - genop_1(s, OP_LOADNIL, cursp()); - push(); - } - while (tree) { - codegen(s, tree->car, tree->cdr ? NOVAL : val); - tree = tree->cdr; - } + codegen_stmts(s, tree, val); break; case NODE_BEGIN: - /* NODE_BEGIN contains a single body node directly in cdr */ - codegen(s, tree, val); + codegen_begin(s, tree, val); break; case NODE_RESCUE: - { - int noexc; - uint32_t exend, pos1, pos2, tmp; - struct loopinfo *lp; - int catch_entry, begin, end; - - if (tree->car == NULL) goto exit; - lp = loop_push(s, LOOP_BEGIN); - lp->pc0 = new_label(s); - catch_entry = catch_handler_new(s); - begin = s->pc; - codegen(s, tree->car, VAL); - pop(); - lp->type = LOOP_RESCUE; - end = s->pc; - noexc = genjmp_0(s, OP_JMP); - catch_handler_set(s, catch_entry, MRB_CATCH_RESCUE, begin, end, s->pc); - tree = tree->cdr; - exend = JMPLINK_START; - pos1 = JMPLINK_START; - if (tree->car) { - node *n2 = tree->car; - int exc = cursp(); - - genop_1(s, OP_EXCEPT, exc); - push(); - while (n2) { - node *n3 = n2->car; - node *n4 = n3->car; - - dispatch(s, pos1); - pos2 = JMPLINK_START; - do { - if (n4 && n4->car && nint(n4->car->car) == NODE_SPLAT) { - codegen(s, n4->car, VAL); - gen_move(s, cursp(), exc, 0); - push_n(2); pop_n(2); /* space for one arg and a block */ - pop(); - genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_SYM_2(s->mrb, __case_eqq)), 1); - } - else { - if (n4) { - codegen(s, n4->car, VAL); - } - else { - genop_2(s, OP_GETCONST, cursp(), new_sym(s, MRB_SYM_2(s->mrb, StandardError))); - push(); - } - pop(); - genop_2(s, OP_RESCUE, exc, cursp()); - } - tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, val); - pos2 = tmp; - if (n4) { - n4 = n4->cdr; - } - } while (n4); - pos1 = genjmp_0(s, OP_JMP); - dispatch_linked(s, pos2); - - pop(); - if (n3->cdr->car) { - gen_assignment(s, n3->cdr->car, NULL, exc, NOVAL); - } - if (n3->cdr->cdr->car) { - codegen(s, n3->cdr->cdr->car, val); - if (val) pop(); - } - tmp = genjmp(s, OP_JMP, exend); - exend = tmp; - n2 = n2->cdr; - push(); - } - if (pos1 != JMPLINK_START) { - dispatch(s, pos1); - genop_1(s, OP_RAISEIF, exc); - } - } - pop(); - tree = tree->cdr; - dispatch(s, noexc); - if (tree->car) { - codegen(s, tree->car, val); - } - else if (val) { - push(); - } - dispatch_linked(s, exend); - loop_pop(s, NOVAL); - } + codegen_rescue(s, tree, val); break; case NODE_ENSURE: - if (!tree->cdr || !tree->cdr->cdr || - (nint(tree->cdr->cdr->car) == NODE_STMTS && - tree->cdr->cdr->cdr)) { - int catch_entry, begin, end, target; - int idx; - - catch_entry = catch_handler_new(s); - begin = s->pc; - codegen(s, tree->car, val); - end = target = s->pc; - push(); - idx = cursp(); - genop_1(s, OP_EXCEPT, idx); - push(); - codegen(s, tree->cdr->cdr, NOVAL); - pop(); - genop_1(s, OP_RAISEIF, idx); - pop(); - catch_handler_set(s, catch_entry, MRB_CATCH_ENSURE, begin, end, target); - } - else { /* empty ensure ignored */ - codegen(s, tree->car, val); - } + codegen_ensure(s, tree, val); break; case NODE_LAMBDA: - if (val) { - int idx = lambda_body(s, tree, 1); - - genop_2(s, OP_LAMBDA, cursp(), idx); - push(); - } + codegen_lambda(s, tree, val); break; case NODE_BLOCK: - if (val) { - int idx = lambda_body(s, tree, 1); - - genop_2(s, OP_BLOCK, cursp(), idx); - push(); - } + codegen_block(s, tree, val); break; case NODE_IF: - { - uint32_t pos1, pos2; - mrb_bool nil_p = FALSE; - node *elsepart = tree->cdr->cdr->car; - - if (!tree->car) { - codegen(s, elsepart, val); - goto exit; - } - if (true_always(tree->car)) { - codegen(s, tree->cdr->car, val); - goto exit; - } - if (false_always(tree->car)) { - codegen(s, elsepart, val); - goto exit; - } - if (nint(tree->car->car) == NODE_CALL) { - node *n = tree->car->cdr; - mrb_sym mid = nsym(n->cdr->car); - mrb_sym sym_nil_p = MRB_SYM_Q_2(s->mrb, nil); - if (mid == sym_nil_p && n->cdr->cdr->car == NULL) { - nil_p = TRUE; - codegen(s, n->car, VAL); - } - } - if (!nil_p) { - codegen(s, tree->car, VAL); - } - pop(); - if (val || tree->cdr->car) { - if (nil_p) { - pos2 = genjmp2_0(s, OP_JMPNIL, cursp(), val); - pos1 = genjmp_0(s, OP_JMP); - dispatch(s, pos2); - } - else { - pos1 = genjmp2_0(s, OP_JMPNOT, cursp(), val); - } - codegen(s, tree->cdr->car, val); - if (val) pop(); - if (elsepart || val) { - pos2 = genjmp_0(s, OP_JMP); - dispatch(s, pos1); - codegen(s, elsepart, val); - dispatch(s, pos2); - } - else { - dispatch(s, pos1); - } - } - else { /* empty then-part */ - if (elsepart) { - if (nil_p) { - pos1 = genjmp2_0(s, OP_JMPNIL, cursp(), val); - } - else { - pos1 = genjmp2_0(s, OP_JMPIF, cursp(), val); - } - codegen(s, elsepart, val); - dispatch(s, pos1); - } - else if (val && !nil_p) { - genop_1(s, OP_LOADNIL, cursp()); - push(); - } - } - } + codegen_if(s, tree, val); break; case NODE_AND: - { - uint32_t pos; - - if (true_always(tree->car)) { - codegen(s, tree->cdr, val); - goto exit; - } - if (false_always(tree->car)) { - codegen(s, tree->car, val); - goto exit; - } - codegen(s, tree->car, VAL); - pop(); - pos = genjmp2_0(s, OP_JMPNOT, cursp(), val); - codegen(s, tree->cdr, val); - dispatch(s, pos); - } + codegen_and(s, tree, val); break; case NODE_OR: - { - uint32_t pos; - - if (true_always(tree->car)) { - codegen(s, tree->car, val); - goto exit; - } - if (false_always(tree->car)) { - codegen(s, tree->cdr, val); - goto exit; - } - codegen(s, tree->car, VAL); - pop(); - pos = genjmp2_0(s, OP_JMPIF, cursp(), val); - codegen(s, tree->cdr, val); - dispatch(s, pos); - } + codegen_or(s, tree, val); break; case NODE_WHILE_MOD: case NODE_UNTIL_MOD: - /* Post-tested loops: execute body first, then check condition */ - if (false_always(tree->car)) { - if (nt == NODE_WHILE_MOD) { - /* begin...end while false - execute once then exit */ - codegen(s, tree->cdr, val); - if (val) push(); - goto exit; - } - } - else if (true_always(tree->car)) { - if (nt == NODE_UNTIL_MOD) { - /* begin...end until true - execute once then exit */ - codegen(s, tree->cdr, val); - if (val) push(); - goto exit; - } - } - genjmp_0(s, OP_JMP); - /* fall through */ case NODE_WHILE: case NODE_UNTIL: - { - uint32_t pos0 = JMPLINK_START; - if (nt == NODE_WHILE_MOD || nt == NODE_UNTIL_MOD) { - pos0 = s->pc - mrb_insn_size[OP_JMP] + 1; - } - - if (true_always(tree->car)) { - if (nt == NODE_UNTIL) { - if (val) { - genop_1(s, OP_LOADNIL, cursp()); - push(); - } - goto exit; - } - } - else if (false_always(tree->car)) { - if (nt == NODE_WHILE) { - if (val) { - genop_1(s, OP_LOADNIL, cursp()); - push(); - } - goto exit; - } - } - - struct loopinfo *lp = loop_push(s, LOOP_NORMAL); - - if (!val) lp->reg = -1; - lp->pc0 = new_label(s); - codegen(s, tree->car, VAL); - pop(); - - uint32_t pos; - if (nt == NODE_WHILE || nt == NODE_WHILE_MOD) { - pos = genjmp2_0(s, OP_JMPNOT, cursp(), NOVAL); - } - else { /* UNTIL */ - pos = genjmp2_0(s, OP_JMPIF, cursp(), NOVAL); - } - lp->pc1 = new_label(s); - genop_0(s, OP_NOP); /* for redo */ - dispatch(s, pos0); - codegen(s, tree->cdr, NOVAL); - genjmp(s, OP_JMP, lp->pc0); - dispatch(s, pos); - loop_pop(s, val); - } + codegen_while_until(s, tree, val, nt); break; case NODE_FOR: - for_body(s, tree); - if (val) push(); + codegen_for(s, tree, val); break; case NODE_CASE: - { - int head = 0; - uint32_t pos1, pos2, pos3, tmp; - node *n; - - pos3 = JMPLINK_START; - if (tree->car) { - head = cursp(); - codegen(s, tree->car, VAL); - } - tree = tree->cdr; - while (tree) { - n = tree->car->car; - pos1 = pos2 = JMPLINK_START; - while (n) { - codegen(s, n->car, VAL); - if (head) { - gen_move(s, cursp(), head, 0); - push(); push(); pop(); pop(); pop(); - if (nint(n->car->car) == NODE_SPLAT) { - genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_SYM_2(s->mrb, __case_eqq)), 1); - } - else { - genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_OPSYM_2(s->mrb, eqq)), 1); - } - } - else { - pop(); - } - tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, !head); - pos2 = tmp; - n = n->cdr; - } - if (tree->car->car) { - pos1 = genjmp_0(s, OP_JMP); - dispatch_linked(s, pos2); - } - codegen(s, tree->car->cdr, val); - if (val) pop(); - tmp = genjmp(s, OP_JMP, pos3); - pos3 = tmp; - dispatch(s, pos1); - tree = tree->cdr; - } - if (val) { - uint32_t pos = cursp(); - genop_1(s, OP_LOADNIL, cursp()); - if (pos3 != JMPLINK_START) dispatch_linked(s, pos3); - if (head) pop(); - if (cursp() != pos) { - gen_move(s, cursp(), pos, 0); - } - push(); - } - else { - if (pos3 != JMPLINK_START) { - dispatch_linked(s, pos3); - } - if (head) { - pop(); - } - } - } + codegen_case(s, tree, val); break; case NODE_SCOPE: - scope_body(s, tree, NOVAL); + codegen_scope_node(s, tree, val); break; case NODE_CALL: case NODE_FCALL: - gen_call(s, tree, val, 0); + codegen_call_fcall(s, tree, val); break; case NODE_SCALL: - gen_call(s, tree, val, 1); + codegen_scall(s, tree, val); break; case NODE_DOT2: - codegen(s, tree->car, val); - codegen(s, tree->cdr, val); - if (val) { - pop(); pop(); - genop_1(s, OP_RANGE_INC, cursp()); - push(); - } + codegen_dot2(s, tree, val); break; case NODE_DOT3: - codegen(s, tree->car, val); - codegen(s, tree->cdr, val); - if (val) { - pop(); pop(); - genop_1(s, OP_RANGE_EXC, cursp()); - push(); - } + codegen_dot3(s, tree, val); break; case NODE_COLON2: - { - int sym = new_sym(s, nsym(tree->cdr)); - - codegen(s, tree->car, VAL); - pop(); - genop_2(s, OP_GETMCNST, cursp(), sym); - if (val) push(); - } + codegen_colon2(s, tree, val); break; case NODE_COLON3: - { - int sym = new_sym(s, nsym(tree)); - - genop_1(s, OP_OCLASS, cursp()); - genop_2(s, OP_GETMCNST, cursp(), sym); - if (val) push(); - } + codegen_colon3(s, tree, val); break; case NODE_ARRAY: - { - int n; - - n = gen_values(s, tree, val, 0); - if (val) { - if (n >= 0) { - pop_n(n); - genop_2(s, OP_ARRAY, cursp(), n); - } - push(); - } - } + codegen_array(s, tree, val); break; case NODE_HASH: case NODE_KW_HASH: - { - int nk = gen_hash(s, tree, val, GEN_LIT_ARY_MAX); - if (val && nk >= 0) { - pop_n(nk*2); - genop_2(s, OP_HASH, cursp(), nk); - push(); - } - } + codegen_hash(s, tree, val); break; case NODE_SPLAT: - codegen(s, tree, val); + codegen_splat(s, tree, val); break; case NODE_ASGN: - gen_assignment(s, tree->car, tree->cdr, 0, val); + codegen_asgn(s, tree, val); break; case NODE_MASGN: - { - int len = 0, n = 0, post = 0; - node *t = tree->cdr, *p; - int rhs = cursp(); - - if (!val && nint(t->car) == NODE_ARRAY && t->cdr && nosplat(t->cdr)) { - /* fixed rhs */ - t = t->cdr; - while (t) { - codegen(s, t->car, VAL); - len++; - t = t->cdr; - } - tree = tree->car; - if (tree->car) { /* pre */ - t = tree->car; - n = 0; - while (t) { - if (n < len) { - gen_assignment(s, t->car, NULL, rhs+n, NOVAL); - n++; - } - else { - genop_1(s, OP_LOADNIL, rhs+n); - gen_assignment(s, t->car, NULL, rhs+n, NOVAL); - } - t = t->cdr; - } - } - t = tree->cdr; - if (t) { - if (t->cdr) { /* post count */ - p = t->cdr->car; - while (p) { - post++; - p = p->cdr; - } - } - if (t->car) { /* rest (len - pre - post) */ - int rn; - - if (len < post + n) { - rn = 0; - } - else { - rn = len - post - n; - } - if (cursp() == rhs+n) { - genop_2(s, OP_ARRAY, cursp(), rn); - } - else { - genop_3(s, OP_ARRAY2, cursp(), rhs+n, rn); - } - gen_assignment(s, t->car, NULL, cursp(), NOVAL); - n += rn; - } - if (t->cdr && t->cdr->car) { - t = t->cdr->car; - while (t) { - if (ncar, NULL, rhs+n, NOVAL); - } - else { - genop_1(s, OP_LOADNIL, cursp()); - gen_assignment(s, t->car, NULL, cursp(), NOVAL); - } - t = t->cdr; - n++; - } - } - } - pop_n(len); - } - else { - /* variable rhs */ - codegen(s, t, VAL); - gen_massignment(s, tree->car, rhs, val); - if (!val) { - pop(); - } - } - } + codegen_masgn(s, tree, val); break; case NODE_OP_ASGN: - { - mrb_sym sym = nsym(tree->cdr->car); - mrb_int len; - const char *name = mrb_sym_name_len(s->mrb, sym, &len); - int idx, callargs = -1, vsp = -1; - - if ((len == 2 && name[0] == '|' && name[1] == '|') && - (nint(tree->car->car) == NODE_CONST || - nint(tree->car->car) == NODE_CVAR)) { - int catch_entry, begin, end; - int noexc, exc; - struct loopinfo *lp; - - lp = loop_push(s, LOOP_BEGIN); - lp->pc0 = new_label(s); - catch_entry = catch_handler_new(s); - begin = s->pc; - exc = cursp(); - codegen(s, tree->car, VAL); - end = s->pc; - noexc = genjmp_0(s, OP_JMP); - lp->type = LOOP_RESCUE; - catch_handler_set(s, catch_entry, MRB_CATCH_RESCUE, begin, end, s->pc); - genop_1(s, OP_EXCEPT, exc); - genop_1(s, OP_LOADF, exc); - dispatch(s, noexc); - loop_pop(s, NOVAL); - } - else if (nint(tree->car->car) == NODE_CALL) { - node *n = tree->car->cdr; - int base, i, nargs = 0; - callargs = 0; - - if (val) { - vsp = cursp(); - push(); - } - codegen(s, n->car, VAL); /* receiver */ - idx = new_sym(s, nsym(n->cdr->car)); - base = cursp()-1; - if (n->cdr->cdr->car) { - nargs = gen_values(s, n->cdr->cdr->car->car, VAL, 13); - if (nargs >= 0) { - callargs = nargs; - } - else { /* varargs */ - push(); - nargs = 1; - callargs = CALL_MAXARGS; - } - } - /* copy receiver and arguments */ - gen_move(s, cursp(), base, 1); - for (i=0; icar, VAL); - } - if (len == 2 && - ((name[0] == '|' && name[1] == '|') || - (name[0] == '&' && name[1] == '&'))) { - uint32_t pos; - - pop(); - if (val) { - if (vsp >= 0) { - gen_move(s, vsp, cursp(), 1); - } - pos = genjmp2_0(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), val); - } - else { - pos = genjmp2_0(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), val); - } - codegen(s, tree->cdr->cdr->car, VAL); - pop(); - if (val && vsp >= 0) { - gen_move(s, vsp, cursp(), 1); - } - if (nint(tree->car->car) == NODE_CALL) { - if (callargs == CALL_MAXARGS) { - pop(); - genop_2(s, OP_ARYPUSH, cursp(), 1); - } - else { - pop_n(callargs); - callargs++; - } - pop(); - idx = new_sym(s, attrsym(s, nsym(tree->car->cdr->cdr->car))); - genop_3(s, OP_SEND, cursp(), idx, callargs); - } - else { - gen_assignment(s, tree->car, NULL, cursp(), val); - } - dispatch(s, pos); - goto exit; - } - codegen(s, tree->cdr->cdr->car, VAL); - push(); pop(); - pop(); pop(); - - if (len == 1 && name[0] == '+') { - gen_addsub(s, OP_ADD, cursp()); - } - else if (len == 1 && name[0] == '-') { - gen_addsub(s, OP_SUB, cursp()); - } - else if (len == 1 && name[0] == '*') { - genop_1(s, OP_MUL, cursp()); - } - else if (len == 1 && name[0] == '/') { - genop_1(s, OP_DIV, cursp()); - } - else if (len == 1 && name[0] == '<') { - genop_1(s, OP_LT, cursp()); - } - else if (len == 2 && name[0] == '<' && name[1] == '=') { - genop_1(s, OP_LE, cursp()); - } - else if (len == 1 && name[0] == '>') { - genop_1(s, OP_GT, cursp()); - } - else if (len == 2 && name[0] == '>' && name[1] == '=') { - genop_1(s, OP_GE, cursp()); - } - else { - idx = new_sym(s, sym); - genop_3(s, OP_SEND, cursp(), idx, 1); - } - if (callargs < 0) { - gen_assignment(s, tree->car, NULL, cursp(), val); - } - else { - if (val && vsp >= 0) { - gen_move(s, vsp, cursp(), 0); - } - if (callargs == CALL_MAXARGS) { - pop(); - genop_2(s, OP_ARYPUSH, cursp(), 1); - } - else { - pop_n(callargs); - callargs++; - } - pop(); - idx = new_sym(s, attrsym(s,nsym(tree->car->cdr->cdr->car))); - genop_3(s, OP_SEND, cursp(), idx, callargs); - } - } + codegen_op_asgn(s, tree, val); break; case NODE_SUPER: - { - codegen_scope *s2 = s; - int lv = 0; - int n = 0, nk = 0, st = 0; - - push(); - while (!s2->mscope) { - lv++; - s2 = s2->prev; - if (!s2) break; - } - if (tree) { - node *args = tree->car; - if (args) { - st = n = gen_values(s, args, VAL, 14); - if (n < 0) { - st = 1; n = 15; - push(); - } - } - /* keyword arguments */ - if (tree->cdr->car) { - nk = gen_hash(s, tree->cdr->car->cdr, VAL, 14); - if (nk < 0) {st++; nk = 15;} - else st += nk*2; - n |= nk<<4; - } - /* block arguments */ - if (tree->cdr->cdr) { - codegen(s, tree->cdr->cdr, VAL); - } - else if (s2) gen_blkmove(s, s2->ainfo, lv); - else { - genop_1(s, OP_LOADNIL, cursp()); - push(); - } - } - else { - if (s2) gen_blkmove(s, s2->ainfo, lv); - else { - genop_1(s, OP_LOADNIL, cursp()); - push(); - } - } - st++; - pop_n(st+1); - genop_2(s, OP_SUPER, cursp(), n); - if (val) push(); - } + codegen_super(s, tree, val); break; case NODE_ZSUPER: - { - codegen_scope *s2 = s; - int lv = 0; - uint16_t ainfo = 0; - int n = CALL_MAXARGS; - int sp = cursp(); - - push(); /* room for receiver */ - while (!s2->mscope) { - lv++; - s2 = s2->prev; - if (!s2) break; - } - if (s2 && s2->ainfo > 0) { - ainfo = s2->ainfo; - } - if (lv > 0xf) codegen_error(s, "too deep nesting"); - if (ainfo > 0) { - genop_2S(s, OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf)); - push(); push(); push(); /* ARGARY pushes 3 values at most */ - pop(); pop(); pop(); - /* keyword arguments */ - if (ainfo & 0x1) { - n |= CALL_MAXARGS<<4; - push(); - } - /* block argument */ - if (tree && tree->cdr && tree->cdr->cdr) { - push(); - codegen(s, tree->cdr->cdr, VAL); - } - } - else { - /* block argument */ - if (tree && tree->cdr && tree->cdr->cdr) { - codegen(s, tree->cdr->cdr, VAL); - } - else if (s2) { - gen_blkmove(s, 0, lv); - } - else { - genop_1(s, OP_LOADNIL, cursp()); - } - n = 0; - } - s->sp = sp; - genop_2(s, OP_SUPER, cursp(), n); - if (val) push(); - } + codegen_zsuper(s, tree, val); break; case NODE_RETURN: - if (tree) { - gen_retval(s, tree); - } - else { - genop_1(s, OP_LOADNIL, cursp()); - } - if (s->loop) { - gen_return(s, OP_RETURN_BLK, cursp()); - } - else { - gen_return(s, OP_RETURN, cursp()); - } - if (val) push(); + codegen_return(s, tree, val); break; case NODE_YIELD: - { - codegen_scope *s2 = s; - int lv = 0, ainfo = -1; - int n = 0, nk = 0, sendv = 0; - - while (!s2->mscope) { - lv++; - s2 = s2->prev; - if (!s2) break; - } - if (s2) { - ainfo = (int)s2->ainfo; - } - if (ainfo < 0) codegen_error(s, "invalid yield (SyntaxError)"); - if (lv > 0xf) codegen_error(s, "too deep nesting"); - push(); - if (tree) { - if (tree->car) { - n = gen_values(s, tree->car, VAL, 14); - if (n < 0) { - n = sendv = 1; - push(); - } - } - - if (tree->cdr->car) { - nk = gen_hash(s, tree->cdr->car->cdr, VAL, 14); - if (nk < 0) { - nk = 15; - } - } - } - push();pop(); /* space for a block */ - pop_n(n + (nk == 15 ? 1 : nk * 2) + 1); - genop_2S(s, OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf)); - if (sendv) n = CALL_MAXARGS; - genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_SYM_2(s->mrb, call)), n|(nk<<4)); - if (val) push(); - } + codegen_yield(s, tree, val); break; case NODE_BREAK: - loop_break(s, tree); - if (val) push(); + codegen_break(s, tree, val); break; case NODE_NEXT: - if (!s->loop) { - raise_error(s, "unexpected next"); - } - else if (s->loop->type == LOOP_NORMAL) { - codegen(s, tree, NOVAL); - genjmp(s, OP_JMPUW, s->loop->pc0); - } - else { - if (tree) { - codegen(s, tree, VAL); - pop(); - } - else { - genop_1(s, OP_LOADNIL, cursp()); - } - gen_return(s, OP_RETURN, cursp()); - } - if (val) push(); + codegen_next(s, tree, val); break; case NODE_REDO: - for (const struct loopinfo *lp = s->loop; ; lp = lp->prev) { - if (!lp) { - raise_error(s, "unexpected redo"); - break; - } - if (lp->type != LOOP_BEGIN && lp->type != LOOP_RESCUE) { - genjmp(s, OP_JMPUW, lp->pc1); - break; - } - } - if (val) push(); + codegen_redo(s, tree, val); break; case NODE_RETRY: - { - const struct loopinfo *lp = s->loop; - - while (lp && lp->type != LOOP_RESCUE) { - lp = lp->prev; - } - if (!lp) { - raise_error(s, "unexpected retry"); - break; - } - else { - genjmp(s, OP_JMPUW, lp->pc0); - } - if (val) push(); - } + codegen_retry(s, tree, val); break; case NODE_LVAR: - if (val) { - int idx = lv_idx(s, nsym(tree)); - - if (idx > 0) { - gen_move(s, cursp(), idx, val); - } - else { - gen_getupvar(s, cursp(), nsym(tree)); - } - push(); - } + codegen_lvar(s, tree, val); break; case NODE_NVAR: - if (val) { - int idx = nint(tree); - - gen_move(s, cursp(), idx, val); - - push(); - } + codegen_nvar(s, tree, val); break; case NODE_GVAR: - { - int sym = new_sym(s, nsym(tree)); - - genop_2(s, OP_GETGV, cursp(), sym); - if (val) push(); - } + codegen_gvar(s, tree, val); break; case NODE_IVAR: - { - int sym = new_sym(s, nsym(tree)); - - genop_2(s, OP_GETIV, cursp(), sym); - if (val) push(); - } + codegen_ivar(s, tree, val); break; case NODE_CVAR: - { - int sym = new_sym(s, nsym(tree)); - - genop_2(s, OP_GETCV, cursp(), sym); - if (val) push(); - } + codegen_cvar(s, tree, val); break; case NODE_CONST: - { - int sym = new_sym(s, nsym(tree)); - - genop_2(s, OP_GETCONST, cursp(), sym); - if (val) push(); - } + codegen_const(s, tree, val); break; case NODE_BACK_REF: - if (val) { - char buf[] = {'$', nchar(tree)}; - int sym = new_sym(s, mrb_intern(s->mrb, buf, sizeof(buf))); - - genop_2(s, OP_GETGV, cursp(), sym); - push(); - } + codegen_back_ref(s, tree, val); break; case NODE_NTH_REF: - if (val) { - mrb_state *mrb = s->mrb; - mrb_value str; - int sym; - - str = mrb_format(mrb, "$%d", nint(tree)); - sym = new_sym(s, mrb_intern_str(mrb, str)); - genop_2(s, OP_GETGV, cursp(), sym); - push(); - } + codegen_nth_ref(s, tree, val); break; case NODE_ARG: @@ -4390,512 +5127,118 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_BLOCK_ARG: - if (!tree) { - int idx = lv_idx(s, MRB_OPSYM_2(s->mrb, and)); - - if (idx == 0) { - gen_getupvar(s, cursp(), MRB_OPSYM_2(s->mrb, and)); - } - else { - gen_move(s, cursp(), idx, val); - } - if (val) push(); - } - else { - codegen(s, tree, val); - } + codegen_block_arg(s, tree, val); break; case NODE_INT: - if (val) { - char *p = (char*)tree->car; - int base = nint(tree->cdr->car); - mrb_int i; - mrb_bool overflow; - - i = readint(s, p, base, FALSE, &overflow); - if (overflow) { - int off = new_litbint(s, p, base); - genop_2(s, OP_LOADL, cursp(), off); - } - else { - gen_int(s, cursp(), i); - } - push(); - } + codegen_int(s, tree, val); break; #ifndef MRB_NO_FLOAT case NODE_FLOAT: - if (val) { - char *p = (char*)tree; - double f; - mrb_read_float(p, NULL, &f); - int off = new_lit_float(s, (mrb_float)f); - - genop_2(s, OP_LOADL, cursp(), off); - push(); - } + codegen_float(s, tree, val); break; #endif case NODE_NEGATE: - { - nt = nint(tree->car); - switch (nt) { -#ifndef MRB_NO_FLOAT - case NODE_FLOAT: - if (val) { - char *p = (char*)tree->cdr; - double f; - mrb_read_float(p, NULL, &f); - int off = new_lit_float(s, (mrb_float)-f); - - genop_2(s, OP_LOADL, cursp(), off); - push(); - } - break; -#endif - - case NODE_INT: - if (val) { - char *p = (char*)tree->cdr->car; - int base = nint(tree->cdr->cdr->car); - mrb_int i; - mrb_bool overflow; - - i = readint(s, p, base, TRUE, &overflow); - if (overflow) { - base = -base; - int off = new_litbint(s, p, base); - genop_2(s, OP_LOADL, cursp(), off); - } - else { - gen_int(s, cursp(), i); - } - push(); - } - break; - - default: - codegen(s, tree, VAL); - pop(); - push_n(2);pop_n(2); /* space for receiver&block */ - mrb_sym minus = MRB_OPSYM_2(s->mrb, minus); - if (!gen_uniop(s, minus, cursp())) { - genop_3(s, OP_SEND, cursp(), new_sym(s, minus), 0); - } - if (val) push(); - break; - } - } + codegen_negate(s, tree, val); break; case NODE_STR: - if (val) { - char *p = (char*)tree->car; - mrb_int len = nint(tree->cdr); - int off = new_lit_str(s, p, len); - - genop_2(s, OP_STRING, cursp(), off); - push(); - } + codegen_str(s, tree, val); break; case NODE_HEREDOC: - tree = ((struct mrb_parser_heredoc_info*)tree)->doc; - /* fall through */ + codegen_heredoc(s, tree, val); + break; + case NODE_DSTR: - if (val) { - node *n = tree; - - if (!n) { - genop_1(s, OP_LOADNIL, cursp()); - push(); - break; - } - codegen(s, n->car, VAL); - n = n->cdr; - while (n) { - codegen(s, n->car, VAL); - pop(); pop(); - genop_1(s, OP_STRCAT, cursp()); - push(); - n = n->cdr; - } - } - else { - node *n = tree; - - while (n) { - if (nint(n->car->car) != NODE_STR) { - codegen(s, n->car, NOVAL); - } - n = n->cdr; - } - } + codegen_heredoc_dstr(s, tree, val); break; case NODE_WORDS: - gen_literal_array(s, tree, FALSE, val); + codegen_words(s, tree, val); break; case NODE_SYMBOLS: - gen_literal_array(s, tree, TRUE, val); + codegen_symbols(s, tree, val); break; case NODE_DXSTR: - { - node *n; - int sym = new_sym(s, MRB_SYM_2(s->mrb, Kernel)); - - push(); - codegen(s, tree->car, VAL); - n = tree->cdr; - while (n) { - if (nint(n->car->car) == NODE_XSTR) { - n->car->car = (struct mrb_ast_node*)(intptr_t)NODE_STR; - mrb_assert(!n->cdr); /* must be the end */ - } - codegen(s, n->car, VAL); - pop(); pop(); - genop_1(s, OP_STRCAT, cursp()); - push(); - n = n->cdr; - } - push(); /* for block */ - pop_n(3); - sym = new_sym(s, MRB_OPSYM_2(s->mrb, tick)); /* ` */ - genop_3(s, OP_SSEND, cursp(), sym, 1); - if (val) push(); - } + codegen_dxstr(s, tree, val); break; case NODE_XSTR: - { - char *p = (char*)tree->car; - mrb_int len = nint(tree->cdr); - int off = new_lit_str(s, p, len); - int sym; - - push(); - genop_2(s, OP_STRING, cursp(), off); - push(); push(); - pop_n(3); - sym = new_sym(s, MRB_OPSYM_2(s->mrb, tick)); /* ` */ - genop_3(s, OP_SSEND, cursp(), sym, 1); - if (val) push(); - } + codegen_xstr(s, tree, val); break; case NODE_REGX: - if (val) { - char *p1 = (char*)tree->car; - char *p2 = (char*)tree->cdr->car; - char *p3 = (char*)tree->cdr->cdr; - int sym = new_sym(s, mrb_intern_lit(s->mrb, REGEXP_CLASS)); - int off = new_lit_cstr(s, p1); - int argc = 1; - - genop_1(s, OP_OCLASS, cursp()); - genop_2(s, OP_GETMCNST, cursp(), sym); - push(); - genop_2(s, OP_STRING, cursp(), off); - push(); - if (p2 || p3) { - if (p2) { /* opt */ - off = new_lit_cstr(s, p2); - genop_2(s, OP_STRING, cursp(), off); - } - else { - genop_1(s, OP_LOADNIL, cursp()); - } - push(); - argc++; - if (p3) { /* enc */ - off = new_lit_str(s, p3, 1); - genop_2(s, OP_STRING, cursp(), off); - push(); - argc++; - } - } - push(); /* space for a block */ - pop_n(argc+2); - sym = new_sym(s, MRB_SYM_2(s->mrb, compile)); - genop_3(s, OP_SEND, cursp(), sym, argc); - push(); - } + codegen_regx(s, tree, val); break; case NODE_DREGX: - if (val) { - node *n = tree->car; - int sym = new_sym(s, mrb_intern_lit(s->mrb, REGEXP_CLASS)); - int argc = 1; - int off; - char *p; - - genop_1(s, OP_OCLASS, cursp()); - genop_2(s, OP_GETMCNST, cursp(), sym); - push(); - codegen(s, n->car, VAL); - n = n->cdr; - while (n) { - codegen(s, n->car, VAL); - pop(); pop(); - genop_1(s, OP_STRCAT, cursp()); - push(); - n = n->cdr; - } - n = tree->cdr->cdr; - if (n->car) { /* tail */ - p = (char*)n->car; - off = new_lit_cstr(s, p); - codegen(s, tree->car, VAL); - genop_2(s, OP_STRING, cursp(), off); - pop(); - genop_1(s, OP_STRCAT, cursp()); - push(); - } - if (n->cdr->car) { /* opt */ - char *p2 = (char*)n->cdr->car; - off = new_lit_cstr(s, p2); - genop_2(s, OP_STRING, cursp(), off); - push(); - argc++; - } - if (n->cdr->cdr) { /* enc */ - char *p2 = (char*)n->cdr->cdr; - off = new_lit_cstr(s, p2); - genop_2(s, OP_STRING, cursp(), off); - push(); - argc++; - } - push(); /* space for a block */ - pop_n(argc+2); - sym = new_sym(s, MRB_SYM_2(s->mrb, compile)); - genop_3(s, OP_SEND, cursp(), sym, argc); - push(); - } - else { - node *n = tree->car; - - while (n) { - if (nint(n->car->car) != NODE_STR) { - codegen(s, n->car, NOVAL); - } - n = n->cdr; - } - } + codegen_dregx(s, tree, val); break; case NODE_SYM: - if (val) { - int sym = new_sym(s, nsym(tree)); - - genop_2(s, OP_LOADSYM, cursp(), sym); - push(); - } + codegen_sym(s, tree, val); break; case NODE_DSYM: - codegen(s, tree, val); - if (val) { - gen_intern(s); - } + codegen_dsym(s, tree, val); break; case NODE_SELF: - if (val) { - genop_1(s, OP_LOADSELF, cursp()); - push(); - } + codegen_self(s, tree, val); break; case NODE_NIL: - if (val) { - genop_1(s, OP_LOADNIL, cursp()); - push(); - } + codegen_nil(s, tree, val); break; case NODE_TRUE: - if (val) { - genop_1(s, OP_LOADT, cursp()); - push(); - } + codegen_true(s, tree, val); break; case NODE_FALSE: - if (val) { - genop_1(s, OP_LOADF, cursp()); - push(); - } + codegen_false(s, tree, val); break; case NODE_ALIAS: - { - int a = new_sym(s, nsym(tree->car)); - int b = new_sym(s, nsym(tree->cdr)); - - genop_2(s, OP_ALIAS, a, b); - if (val) { - genop_1(s, OP_LOADNIL, cursp()); - push(); - } - } - break; + codegen_alias(s, tree, val); + break; case NODE_UNDEF: - { - node *t = tree; - - while (t) { - int symbol = new_sym(s, nsym(t->car)); - genop_1(s, OP_UNDEF, symbol); - t = t->cdr; - } - if (val) { - genop_1(s, OP_LOADNIL, cursp()); - push(); - } - } + codegen_undef(s, tree, val); break; case NODE_CLASS: - { - int idx; - node *body; - - if (tree->car->car == (node*)0) { - genop_1(s, OP_LOADNIL, cursp()); - push(); - } - else if (tree->car->car == (node*)1) { - genop_1(s, OP_OCLASS, cursp()); - push(); - } - else { - codegen(s, tree->car->car, VAL); - } - if (tree->cdr->car) { - codegen(s, tree->cdr->car, VAL); - } - else { - genop_1(s, OP_LOADNIL, cursp()); - push(); - } - pop(); pop(); - idx = new_sym(s, nsym(tree->car->cdr)); - genop_2(s, OP_CLASS, cursp(), idx); - body = tree->cdr->cdr->car; - if (nint(body->cdr->car) == NODE_STMTS && body->cdr->cdr == NULL) { - genop_1(s, OP_LOADNIL, cursp()); - } - else { - idx = scope_body(s, body, val); - genop_2(s, OP_EXEC, cursp(), idx); - } - if (val) { - push(); - } - } + codegen_class(s, tree, val); break; case NODE_MODULE: - { - int idx; - - if (tree->car->car == (node*)0) { - genop_1(s, OP_LOADNIL, cursp()); - push(); - } - else if (tree->car->car == (node*)1) { - genop_1(s, OP_OCLASS, cursp()); - push(); - } - else { - codegen(s, tree->car->car, VAL); - } - pop(); - idx = new_sym(s, nsym(tree->car->cdr)); - genop_2(s, OP_MODULE, cursp(), idx); - if (nint(tree->cdr->car->cdr->car) == NODE_STMTS && - tree->cdr->car->cdr->cdr == NULL) { - genop_1(s, OP_LOADNIL, cursp()); - } - else { - idx = scope_body(s, tree->cdr->car, val); - genop_2(s, OP_EXEC, cursp(), idx); - } - if (val) { - push(); - } - } + codegen_module(s, tree, val); break; case NODE_SCLASS: - { - int idx; - - codegen(s, tree->car, VAL); - pop(); - genop_1(s, OP_SCLASS, cursp()); - if (nint(tree->cdr->car->cdr->car) == NODE_STMTS && - tree->cdr->car->cdr->cdr == NULL) { - genop_1(s, OP_LOADNIL, cursp()); - } - else { - idx = scope_body(s, tree->cdr->car, val); - genop_2(s, OP_EXEC, cursp(), idx); - } - if (val) { - push(); - } - } + codegen_sclass(s, tree, val); break; case NODE_DEF: - { - int sym = new_sym(s, nsym(tree->car)); - int idx = lambda_body(s, tree->cdr, 0); - - genop_1(s, OP_TCLASS, cursp()); - push(); - genop_2(s, OP_METHOD, cursp(), idx); - push(); pop(); - pop(); - genop_2(s, OP_DEF, cursp(), sym); - if (val) push(); - } + codegen_def(s, tree, val); break; case NODE_SDEF: - { - node *recv = tree->car; - int sym = new_sym(s, nsym(tree->cdr->car)); - int idx = lambda_body(s, tree->cdr->cdr, 0); - - codegen(s, recv, VAL); - pop(); - genop_1(s, OP_SCLASS, cursp()); - push(); - genop_2(s, OP_METHOD, cursp(), idx); - push(); pop(); - pop(); - genop_2(s, OP_DEF, cursp(), sym); - if (val) push(); - } + codegen_sdef(s, tree, val); break; case NODE_POSTEXE: - codegen(s, tree, NOVAL); + codegen_postexe(s, tree, val); break; default: break; } - exit: s->rlev = rlev; }