mruby-compiler: migrate NODE_CALL and NODE_FCALL to variable-sized nodes

Remove NODE_SCALL and NODE_FCALL node types, consolidating all method calls
into a single NODE_CALL variable-sized node structure. This simplifies the
AST by unifying call semantics while maintaining support for safe navigation
and different call types through node flags.

Key changes:
- Convert call nodes to use variable-sized allocation with call_node structure
- Unify new_call() and new_fcall() to create NODE_CALL nodes consistently
- Replace gen_call() with separate gen_call_var() and gen_call_assign_var()
- Add gen_call_assign_var() for assignment operations like h[k] = v
- Remove legacy call handling from main codegen switch statement
- Preserve argument structure using args pointer instead of unpacking
- Support safe calls, keyword arguments, and blocks in unified structure

This migration maintains backward compatibility while enabling more efficient
call node processing and reduced code duplication in the compiler.

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-09-14 06:59:58 +09:00
parent ecbf25378b
commit c5431ac293
4 changed files with 1340 additions and 1559 deletions
+173 -261
View File
@@ -155,6 +155,7 @@ static void catch_handler_set(codegen_scope *s, int ent, enum mrb_catch_type typ
static void gen_massignment(codegen_scope *s, node *tree, int sp, int val);
static void gen_masgn_var(codegen_scope *s, node *varnode, node *rhs, int sp, int val);
static void gen_call_assign_var(codegen_scope *s, node *varnode, node *rhs, int sp, int val);
static void codegen(codegen_scope *s, node *tree, int val);
static void raise_error(codegen_scope *s, const char *msg);
@@ -2747,112 +2748,6 @@ gen_hash(codegen_scope *s, node *tree, int val, int limit)
return len;
}
static void
gen_call(codegen_scope *s, node *tree, int val, int safe)
{
mrb_sym sym = node_to_sym(tree->cdr->car);
int skip = 0, n = 0, nk = 0, noop = no_optimize(s), noself = 0, blk = 0, sp_save = cursp();
enum mrb_insn opt_op = OP_NOP;
if (!noop) {
if (sym == MRB_OPSYM_2(s->mrb, add)) opt_op = OP_ADD;
else if (sym == MRB_OPSYM_2(s->mrb, sub)) opt_op = OP_SUB;
else if (sym == MRB_OPSYM_2(s->mrb, mul)) opt_op = OP_MUL;
else if (sym == MRB_OPSYM_2(s->mrb, div)) opt_op = OP_DIV;
else if (sym == MRB_OPSYM_2(s->mrb, lt)) opt_op = OP_LT;
else if (sym == MRB_OPSYM_2(s->mrb, le)) opt_op = OP_LE;
else if (sym == MRB_OPSYM_2(s->mrb, gt)) opt_op = OP_GT;
else if (sym == MRB_OPSYM_2(s->mrb, ge)) opt_op = OP_GE;
else if (sym == MRB_OPSYM_2(s->mrb, eq)) opt_op = OP_EQ;
else if (sym == MRB_OPSYM_2(s->mrb, aref)) opt_op = OP_GETIDX;
else if (sym == MRB_OPSYM_2(s->mrb, aset)) opt_op = OP_SETIDX;
}
if (!tree->car || (opt_op == OP_NOP &&
node_to_int(tree->car->car) == NODE_VARIABLE &&
VAR_NODE_TYPE(tree->car->cdr) == NODE_SELF)) {
noself = 1;
push();
}
else {
codegen(s, tree->car, VAL); /* receiver */
}
if (safe) {
int recv = cursp()-1;
gen_move(s, cursp(), recv, 1);
skip = genjmp2_0(s, OP_JMPNIL, cursp(), val);
}
tree = tree->cdr->cdr->car;
if (tree) {
if (tree->car) { /* positional arguments */
n = gen_values(s, tree->car, VAL, 14);
if (n < 0) { /* variable length */
noop = 1; /* not operator */
n = 15;
push();
}
}
if (tree->cdr->car) { /* keyword arguments */
noop = 1;
nk = gen_hash(s, tree->cdr->car->cdr, VAL, 14);
if (nk < 0) nk = 15;
}
}
if (tree && tree->cdr && tree->cdr->cdr) {
codegen(s, tree->cdr->cdr, VAL);
pop();
noop = 1;
blk = 1;
}
push();
s->sp = sp_save;
if (opt_op == OP_ADD && n == 1) {
gen_addsub(s, OP_ADD, cursp());
}
else if (opt_op == OP_SUB && n == 1) {
gen_addsub(s, OP_SUB, cursp());
}
else if (opt_op == OP_MUL && n == 1) {
gen_muldiv(s, OP_MUL, cursp());
}
else if (opt_op == OP_DIV && n == 1) {
gen_muldiv(s, OP_DIV, cursp());
}
else if (opt_op == OP_LT && n == 1) {
genop_1(s, OP_LT, cursp());
}
else if (opt_op == OP_LE && n == 1) {
genop_1(s, OP_LE, cursp());
}
else if (opt_op == OP_GT && n == 1) {
genop_1(s, OP_GT, cursp());
}
else if (opt_op == OP_GE && n == 1) {
genop_1(s, OP_GE, cursp());
}
else if (opt_op == OP_EQ && n == 1) {
genop_1(s, OP_EQ, cursp());
}
else if (opt_op == OP_SETIDX && n == 2) {
genop_1(s, OP_SETIDX, cursp());
}
else if (!noop && n == 0 && gen_uniop(s, sym, cursp())) {
/* constant folding succeeded */
}
else if (!noop && n == 1 && gen_binop(s, sym, cursp())) {
/* constant folding succeeded */
}
else if (noself) {
genop_3(s, blk ? OP_SSENDB : OP_SSEND, cursp(), new_sym(s, sym), n|(nk<<4));
}
else {
genop_3(s, blk ? OP_SENDB : OP_SEND, cursp(), new_sym(s, sym), n|(nk<<4));
}
if (safe) {
dispatch(s, skip);
}
if (!val) return;
push();
}
static void
gen_colon_assign_common(codegen_scope *s, node *rhs, int sp, int val, int idx, int final_op)
@@ -2938,7 +2833,6 @@ gen_assignment(codegen_scope *s, node *tree, node *rhs, int sp, int val)
break;
case NODE_CALL:
case NODE_SCALL:
/* keep evaluation order */
break;
@@ -2997,6 +2891,9 @@ gen_assignment(codegen_scope *s, node *tree, node *rhs, int sp, int val)
}
}
break;
case NODE_CALL:
gen_call_assign_var(s, tree->cdr, rhs, sp, val);
return;
default:
codegen_error(s, "unsupported variable-sized lhs");
break;
@@ -3013,97 +2910,6 @@ gen_assignment(codegen_scope *s, node *tree, node *rhs, int sp, int val)
tree = tree->cdr;
switch (type) {
case NODE_CALL:
case NODE_SCALL:
{
int noself = 0, safe = (type == NODE_SCALL), skip = 0, top, call, n = 0;
mrb_sym mid = node_to_sym(tree->cdr->car);
top = cursp();
if (val || sp == cursp()) {
push(); /* room for retval */
}
call = cursp();
if (!tree->car) {
noself = 1;
push();
}
else {
codegen(s, tree->car, VAL); /* receiver */
}
if (safe) {
int recv = cursp()-1;
gen_move(s, cursp(), recv, 1);
skip = genjmp2_0(s, OP_JMPNIL, cursp(), val);
}
tree = tree->cdr->cdr->car;
if (tree) {
if (tree->car) { /* positional arguments */
n = gen_values(s, tree->car, VAL, (tree->cdr->car)?13:14);
if (n < 0) { /* variable length */
n = 15;
push();
}
}
if (tree->cdr->car) { /* keyword arguments */
if (n == 13 || n == 14) {
pop_n(n);
genop_2(s, OP_ARRAY, cursp(), n);
push();
n = 15;
}
gen_hash(s, tree->cdr->car->cdr, VAL, 0);
if (n < 14) {
n++;
}
else {
pop_n(2);
genop_2(s, OP_ARYPUSH, cursp(), 1);
}
push();
}
}
if (rhs) {
codegen(s, rhs, VAL);
pop();
}
else {
gen_move(s, cursp(), sp, 0);
}
if (val) {
gen_move(s, top, cursp(), 1);
}
if (n < 15) {
n++;
if (n == 15) {
pop_n(14);
genop_2(s, OP_ARRAY, cursp(), 15);
}
}
else {
pop();
genop_2(s, OP_ARYPUSH, cursp(), 1);
}
push(); pop();
s->sp = call;
if (mid == MRB_OPSYM_2(s->mrb, aref) && n == 2) {
push_n(4); pop_n(4); /* self + idx + value + (invisible block for OP_SEND) */
genop_1(s, OP_SETIDX, cursp());
}
else {
int st = 2 /* self + block */ +
(((n >> 0) & 0x0f) < 15 ? ((n >> 0) & 0x0f) : 1) +
(((n >> 4) & 0x0f) < 15 ? ((n >> 4) & 0x0f) * 2 : 1);
push_n(st); pop_n(st);
genop_3(s, noself ? OP_SSEND : OP_SEND, cursp(), new_sym(s, attrsym(s, mid)), n);
}
if (safe) {
dispatch(s, skip);
}
s->sp = top;
}
break;
/* splat without assignment */
case NODE_NIL:
break;
@@ -3475,17 +3281,7 @@ gen_hash_var(codegen_scope *s, node *varnode, int val)
}
}
static void
codegen_call_fcall(codegen_scope *s, node *tree, int val)
{
gen_call(s, tree, val, 0);
}
static void
codegen_scall(codegen_scope *s, node *tree, int val)
{
gen_call(s, tree, val, 1);
}
/* Common function to generate bytecode for cons list string representation
* Handles list of elements where each element is either:
@@ -3652,8 +3448,8 @@ gen_call_var(codegen_scope *s, node *varnode, int val)
mrb_sym sym = CALL_NODE_METHOD(call);
int skip = 0, n = 0, nk = 0, noop = no_optimize(s), noself = 0, blk = 0, sp_save = cursp();
enum mrb_insn opt_op = OP_NOP;
int argc = CALL_NODE_ARGC(call);
int safe = CALL_NODE_SAFE(call);
node *args = call->args;
if (!noop) {
if (sym == MRB_OPSYM_2(s->mrb, add)) opt_op = OP_ADD;
@@ -3669,12 +3465,14 @@ gen_call_var(codegen_scope *s, node *varnode, int val)
else if (sym == MRB_OPSYM_2(s->mrb, aset)) opt_op = OP_SETIDX;
}
if (!CALL_NODE_RECEIVER(call)) {
if (!call->receiver || (opt_op == OP_NOP &&
node_to_int(call->receiver->car) == NODE_VARIABLE &&
VAR_NODE_TYPE(call->receiver->cdr) == NODE_SELF)) {
noself = 1;
push();
}
else {
codegen(s, CALL_NODE_RECEIVER(call), VAL); /* receiver */
codegen(s, call->receiver, VAL); /* receiver */
}
if (safe) {
@@ -3683,31 +3481,35 @@ gen_call_var(codegen_scope *s, node *varnode, int val)
skip = genjmp2_0(s, OP_JMPNIL, cursp(), val);
}
/* Generate arguments */
n = argc;
if (argc > 0) {
struct mrb_ast_node **args = CALL_NODE_ARGS(call);
int i;
for (i = 0; i < argc; i++) {
codegen(s, args[i], VAL);
}
if (n > 14) {
noop = 1;
/* Generate arguments - use gen_values to properly handle splat */
if (args && args->car) {
n = gen_values(s, args->car, VAL, 14);
if (n < 0) { /* variable length (contains splat) */
n = 15;
push();
noop = 1;
}
}
/* Handle keyword arguments if present */
if (CALL_NODE_HAS_KWARGS(call)) {
noop = 1;
nk = 1; /* Simplified - would need proper kwarg handling */
if (args && args->cdr && args->cdr->car) {
nk = gen_hash(s, args->cdr->car->cdr, VAL, 14);
if (nk < 0) {
nk = 15;
}
noop = 1;
}
}
/* Handle block if present */
if (CALL_NODE_HAS_BLOCK(call)) {
noop = 1;
blk = 1;
if (args && args->cdr && args->cdr->cdr) {
codegen(s, args->cdr->cdr, VAL);
pop();
blk = 1;
noop = 1;
}
}
push();
@@ -3764,6 +3566,150 @@ gen_call_var(codegen_scope *s, node *varnode, int val)
push();
}
static void
gen_call_assign_var(codegen_scope *s, node *varnode, node *rhs, int sp, int val)
{
enum node_type var_type = VAR_NODE_TYPE(varnode);
int noself = 0, safe = 0, skip = 0, top, callsp, n = 0, nk = 0;
mrb_sym mid = 0;
node *args = NULL;
node *receiver = NULL;
enum mrb_insn opt_op = OP_NOP;
int noop = no_optimize(s);
/* Extract information based on node type */
if (var_type == NODE_CALL) {
struct mrb_ast_call_node *call = call_node(varnode);
mid = call->method_name;
args = call->args;
receiver = call->receiver;
safe = call->safe_call;
}
else {
codegen_error(s, "unsupported call type in assignment");
return;
}
/* Convert method name to assignment form (e.g., [] -> []=) */
mrb_sym assign_mid = attrsym(s, mid);
/* Check for optimizable operations */
if (!noop) {
if (mid == MRB_OPSYM_2(s->mrb, aref)) opt_op = OP_SETIDX;
}
top = cursp();
if (val || sp == cursp()) {
push(); /* room for retval */
}
callsp = cursp();
/* Generate receiver */
if (!receiver) {
noself = 1;
push();
}
else {
codegen(s, receiver, VAL); /* receiver */
}
/* Handle safe navigation */
if (safe) {
int recv = cursp()-1;
gen_move(s, cursp(), recv, 1);
skip = genjmp2_0(s, OP_JMPNIL, cursp(), val);
}
/* Generate arguments from original call */
if (args && args->car) {
node *regular_args = args->car;
node *arg_iter = regular_args;
while (arg_iter) {
codegen(s, arg_iter->car, VAL);
n++;
arg_iter = arg_iter->cdr;
}
if (n > 13) { /* leave room for rhs */
pop_n(n);
genop_2(s, OP_ARRAY, cursp(), n);
push();
n = 15;
noop = 1;
}
}
/* Handle keyword arguments if present */
if (args && args->cdr && args->cdr->car) {
node *kwargs = args->cdr->car;
if (n == 13 || n == 14) {
pop_n(n);
genop_2(s, OP_ARRAY, cursp(), n);
push();
n = 15;
}
gen_hash(s, kwargs->cdr, VAL, 0);
if (n < 14) {
n++;
}
else {
pop_n(2);
genop_2(s, OP_ARYPUSH, cursp(), 1);
}
push();
noop = 1;
}
/* Generate rhs (the assigned value) */
if (rhs) {
codegen(s, rhs, VAL);
pop();
}
else {
/* For compound assignments, move the computed value from sp to cursp() */
gen_move(s, cursp(), sp, 0);
}
if (val) {
gen_move(s, top, cursp(), 1);
}
/* Account for the value being assigned (either from rhs or already on stack) */
if (n < 14) {
n++;
}
else {
if (rhs) {
pop_n(2);
genop_2(s, OP_ARYPUSH, cursp(), 1);
push();
}
}
/* Generate the optimized instruction or method call */
push(); push();
s->sp = callsp;
if (opt_op == OP_SETIDX && n == 2) {
/* Always preserve return value for SETIDX - assignments return the assigned value */
genop_1(s, OP_SETIDX, cursp());
}
else if (noself) {
genop_3(s, OP_SSEND, cursp(), new_sym(s, assign_mid), n|(nk<<4));
}
else {
genop_3(s, OP_SEND, cursp(), new_sym(s, assign_mid), n|(nk<<4));
}
if (safe) {
dispatch(s, skip);
}
/* Restore stack pointer like legacy code */
s->sp = top;
if (val) {
push();
}
}
static void
gen_array_var(codegen_scope *s, node *varnode, int val)
{
@@ -5412,22 +5358,6 @@ gen_defined_var(codegen_scope *s, node *varnode, int val)
}
}
// Group 12: Function Calls and Special Forms
static void
gen_fcall_var(codegen_scope *s, node *varnode, int val)
{
struct mrb_ast_fcall_node *n = fcall_node(varnode);
// Create a stack-allocated node structure for traditional codegen
struct mrb_ast_node stack_nodes[3];
stack_nodes[0].car = NULL; // no receiver (self)
stack_nodes[0].cdr = &stack_nodes[1];
stack_nodes[1].car = (node*)(intptr_t)n->method_name; // method name as int
stack_nodes[1].cdr = &stack_nodes[2];
stack_nodes[2].car = n->args;
stack_nodes[2].cdr = NULL;
gen_call(s, &stack_nodes[0], val, 0);
}
static void
gen_zsuper_var(codegen_scope *s, node *varnode, int val)
{
@@ -5940,10 +5870,6 @@ codegen_variable_node(codegen_scope *s, node *varnode, int val)
gen_defined_var(s, varnode, val);
return TRUE;
case NODE_FCALL:
gen_fcall_var(s, varnode, val);
return TRUE;
case NODE_ZSUPER:
gen_zsuper_var(s, varnode, val);
return TRUE;
@@ -6028,7 +5954,6 @@ codegen(codegen_scope *s, node *tree, int val)
}
head = (struct mrb_ast_head_node*)tree;
nt = node_to_int(tree->car);
s->rlev++;
if (s->rlev > MRB_CODEGEN_LEVEL_MAX) {
@@ -6047,24 +5972,11 @@ codegen(codegen_scope *s, node *tree, int val)
s->filename_sym = mrb_parser_get_filename(s->parser, head->filename_index);
}
nt = node_to_int(tree->car);
s->lineno = head->lineno;
tree = tree->cdr;
switch (nt) {
case NODE_CALL:
case NODE_FCALL:
codegen_call_fcall(s, tree, val);
break;
case NODE_SCALL:
codegen_scall(s, tree, val);
break;
case NODE_VARIABLE:
if (nt == NODE_VARIABLE) {
codegen_variable_node(s, tree, val);
break;
default:
break;
}
s->rlev = rlev;
}
+1 -18
View File
@@ -32,8 +32,6 @@ enum node_type {
NODE_ASGN,
NODE_OP_ASGN,
NODE_CALL,
NODE_SCALL,
NODE_FCALL,
NODE_SUPER,
NODE_ZSUPER,
NODE_ARRAY,
@@ -221,12 +219,7 @@ struct mrb_ast_call_node {
uint8_t has_block:1; /* Has block argument */
uint8_t safe_call:1; /* Safe navigation (&.) */
uint8_t reserved:5; /* Reserved for future flags */
/* Followed by variable data:
* - argc * sizeof(struct mrb_ast_node*) for regular arguments
* - struct mrb_ast_node* for kwargs (if has_kwargs)
* - struct mrb_ast_node* for block (if has_block)
*/
struct mrb_ast_node *args[]; /* Flexible array for arguments */
struct mrb_ast_node *args; /* Arguments Information */
};
/* Variable-sized array node with inline element storage */
@@ -802,13 +795,6 @@ struct mrb_ast_defined_node {
#define DEFINED_NODE_EXPR(n) (defined_node(n)->expr)
// Group 12: Function Calls and Special Forms
struct mrb_ast_fcall_node {
struct mrb_ast_var_header hdr;
mrb_sym method_name;
struct mrb_ast_node *args;
};
struct mrb_ast_lambda_node {
struct mrb_ast_var_header hdr;
struct mrb_ast_node *locals;
@@ -917,7 +903,6 @@ struct mrb_ast_postexe_node {
struct mrb_ast_node *body;
};
#define fcall_node(n) ((struct mrb_ast_fcall_node*)(n))
#define zsuper_node(n) ((struct mrb_ast_super_node*)(n))
#define lambda_node(n) ((struct mrb_ast_lambda_node*)(n))
#define zarray_node(n) ((struct mrb_ast_zarray_node*)(n))
@@ -940,8 +925,6 @@ struct mrb_ast_postexe_node {
#define postexe_node(n) ((struct mrb_ast_postexe_node*)(n))
#define sdef_node(n) ((struct mrb_ast_sdef_node*)(n))
#define FCALL_NODE_METHOD_NAME(n) (fcall_node(n)->method_name)
#define FCALL_NODE_ARGS(n) (fcall_node(n)->args)
#define LAMBDA_NODE_LOCALS(n) (lambda_node(n)->locals)
#define LAMBDA_NODE_ARGS(n) (lambda_node(n)->args)
#define LAMBDA_NODE_BODY(n) (lambda_node(n)->body)
+35 -92
View File
@@ -255,13 +255,6 @@ list3_gen(parser_state *p, node *a, node *b, node *c)
}
#define list3(a,b,c) list3_gen(p, (a),(b),(c))
static node*
list4_gen(parser_state *p, node *a, node *b, node *c, node *d)
{
return cons_head(a, cons(b, cons(c, cons(d, 0))));
}
#define list4(a,b,c,d) list4_gen(p, (a),(b),(c),(d))
static node*
append_gen(parser_state *p, node *a, node *b)
{
@@ -759,99 +752,49 @@ new_self(parser_state *p)
/* (:call a b c) */
static node*
new_call(parser_state *p, node *a, mrb_sym b, node *c, int pass)
new_call(parser_state *p, node *receiver, mrb_sym method, node *args, int pass)
{
node *n = list4(int_to_node(pass?NODE_CALL:NODE_SCALL), a, sym_to_node(b), c);
void_expr_error(p, a);
return n;
}
#if 0
/* Variable-sized call node creation */
static node*
new_call_var(parser_state *p, node *receiver, mrb_sym method, node *args, int pass)
{
/* Analyze the arguments to determine size needed */
uint8_t argc = 0;
/* Analyze the arguments to determine structure */
uint8_t has_kwargs = 0;
uint8_t has_block = 0;
node *regular_args = NULL, *kwargs = NULL, *block = NULL;
if (args) {
regular_args = args->car;
/* Check for kwargs and block */
if (args->cdr) {
kwargs = args->cdr->car;
has_kwargs = (kwargs != NULL);
has_kwargs = (args->cdr->car != NULL);
if (args->cdr->cdr) {
block = args->cdr->cdr;
has_block = (block != NULL);
has_block = (args->cdr->cdr != NULL);
}
}
}
/* Count regular arguments */
node *arg_iter = regular_args;
while (arg_iter) {
argc++;
arg_iter = arg_iter->cdr;
}
/* Calculate total size needed */
size_t base_size = sizeof(struct mrb_ast_call_node);
size_t args_size = argc * sizeof(struct mrb_ast_node*);
size_t kwargs_size = has_kwargs ? sizeof(struct mrb_ast_node*) : 0;
size_t block_size = has_block ? sizeof(struct mrb_ast_node*) : 0;
size_t total_size = base_size + args_size + kwargs_size + block_size;
/* Calculate size needed (fixed size now) */
size_t total_size = sizeof(struct mrb_ast_call_node);
enum mrb_ast_size_class class = size_to_class(total_size);
struct mrb_ast_call_node *n = (struct mrb_ast_call_node*)parser_alloc_var(p, total_size, class);
init_var_header(&n->header, p, pass ? NODE_CALL : NODE_SCALL, class);
init_var_header(&n->header, p, NODE_CALL, class);
n->receiver = receiver;
n->method_name = method;
n->argc = argc;
n->argc = 0; /* argc will be determined at codegen time to handle splats */
n->has_kwargs = has_kwargs;
n->has_block = has_block;
n->safe_call = (pass == 2); /* Assuming pass == 2 means safe call (&.) */
n->safe_call = (pass == 0); /* pass == 0 means safe call (&.) */
n->reserved = 0;
/* Copy regular arguments into flexible array */
arg_iter = regular_args;
for (int i = 0; i < argc; i++) {
n->args[i] = arg_iter->car;
arg_iter = arg_iter->cdr;
}
/* Add kwargs and block after regular arguments */
if (has_kwargs) {
n->args[argc] = kwargs;
}
if (has_block) {
n->args[argc + (has_kwargs ? 1 : 0)] = block;
}
/* Store args pointer directly - no need to unpack and repack */
n->args = args;
void_expr_error(p, receiver);
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
#endif
/* (:fcall self mid args) */
static node*
new_fcall(parser_state *p, mrb_sym b, node *c)
{
if (!p->var_nodes_enabled) {
node *n = list4((node*)NODE_FCALL, 0, sym_to_node(b), c);
return n;
}
size_t total_size = sizeof(struct mrb_ast_fcall_node);
enum mrb_ast_size_class class = size_to_class(total_size);
struct mrb_ast_fcall_node *fcall_node = (struct mrb_ast_fcall_node*)parser_alloc_var(p, total_size, class);
init_var_header(&fcall_node->hdr, p, NODE_FCALL, class);
fcall_node->method_name = b;
fcall_node->args = c;
return cons_head((node*)NODE_VARIABLE, (node*)fcall_node);
return new_call(p, NULL, b, c, '.');
}
/* (a b . c) */
@@ -2020,8 +1963,6 @@ endless_method_name(parser_state *p, node *defn)
static void
call_with_block(parser_state *p, node *a, node *b)
{
node *n;
switch (node_to_type(a->car)) {
case NODE_VARIABLE:
/* Handle variable-sized nodes wrapped in NODE_VARIABLE */
@@ -2064,17 +2005,30 @@ call_with_block(parser_state *p, node *a, node *b)
call_with_block(p, next_n->value, b);
return;
}
else if (var_type == NODE_CALL) {
/* Variable-sized call nodes - add block to existing args */
struct mrb_ast_call_node *call = call_node(a->cdr);
if (call->has_block) {
yyerror(NULL, p, "both block arg and actual block given");
return;
}
call->has_block = 1;
/* Use existing args and add block */
if (call->args) {
/* Modify existing callargs structure to add block */
args_with_block(p, call->args, b);
}
else {
/* Create new callargs with just the block */
call->args = new_callargs(p, NULL, NULL, b);
}
return;
}
}
/* For other variable-sized nodes, fall through to default */
break;
case NODE_CALL:
case NODE_FCALL:
case NODE_SCALL:
/* (NODE_CALL recv mid (args kw . blk)) */
n = a->cdr->cdr->cdr; /* (args kw . blk) */
if (!n->car) n->car = new_callargs(p, 0, 0, b);
else args_with_block(p, n->car, b);
break;
default:
break;
}
@@ -8162,19 +8116,8 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
offset++;
goto again;
case NODE_FCALL:
case NODE_CALL:
case NODE_SCALL:
switch (nodetype) {
case NODE_FCALL:
printf("NODE_FCALL:\n"); break;
case NODE_CALL:
printf("NODE_CALL(.):\n"); break;
case NODE_SCALL:
printf("NODE_SCALL(&.):\n"); break;
default:
break;
}
printf("NODE_CALL(.):\n"); break;
mrb_parser_dump(mrb, tree->car, offset+1);
dump_prefix(tree, offset+1);
printf("method='%s' (%d)\n",
File diff suppressed because it is too large Load Diff