mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
parse.y: implement &nil in formal parameters
`&nil` is recently introduced in CRuby to explicitly declare that a method does not accept a block. When a block is passed, ArgumentError "no block accepted" is raised. This is analogous to `**nil` for keyword arguments. The noblock flag is encoded in bit 23 of OP_ENTER's aspec operand (24=n1:m5:o5:r1:m5:k5:d1:b1), avoiding the need for a new opcode. Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -922,6 +922,11 @@ MRB_API struct RClass* mrb_define_module_under_id(mrb_state *mrb, struct RClass
|
||||
*/
|
||||
#define MRB_ARGS_BLOCK() ((mrb_aspec)1)
|
||||
|
||||
/**
|
||||
* Function does not accept a block (&nil)
|
||||
*/
|
||||
#define MRB_ARGS_NOBLOCK() ((mrb_aspec)(1 << 23))
|
||||
|
||||
/**
|
||||
* Function accepts any number of arguments
|
||||
*/
|
||||
|
||||
+1
-1
@@ -69,7 +69,7 @@ OPCODE(CALL, Z) /* self.call(*, **, &) (But overlay the current cal
|
||||
OPCODE(BLKCALL, BB) /* R[a] = R[a].call(R[a+1],... ,R[a+b]); direct block call */
|
||||
OPCODE(SUPER, BB) /* R[a] = super(R[a+1],... ,R[a+b+1]) */
|
||||
OPCODE(ARGARY, BS) /* R[a] = argument array (16=m5:r1:m5:d1:lv4) */
|
||||
OPCODE(ENTER, W) /* arg setup according to flags (23=m5:o5:r1:m5:k5:d1:b1) */
|
||||
OPCODE(ENTER, W) /* arg setup according to flags (24=n1:m5:o5:r1:m5:k5:d1:b1) */
|
||||
OPCODE(KEY_P, BB) /* R[a] = kdict.key?(Syms[b]) */
|
||||
OPCODE(KEYEND, Z) /* raise unless kdict.empty? */
|
||||
OPCODE(KARG, BB) /* R[a] = kdict[Syms[b]]; kdict.delete(Syms[b]) */
|
||||
|
||||
@@ -72,6 +72,7 @@ struct RProc {
|
||||
#define MRB_ASPEC_KEY(a) (((a) >> 2) & 0x1f)
|
||||
#define MRB_ASPEC_KDICT(a) (((a) >> 1) & 0x1)
|
||||
#define MRB_ASPEC_BLOCK(a) ((a) & 1)
|
||||
#define MRB_ASPEC_NOBLOCK(a) (((a) >> 23) & 0x1)
|
||||
|
||||
#define MRB_PROC_CFUNC_FL 128
|
||||
#define MRB_PROC_CFUNC_P(p) (((p)->flags & MRB_PROC_CFUNC_FL) != 0)
|
||||
|
||||
@@ -2401,13 +2401,16 @@ lambda_body(codegen_scope *s, node *locals, struct mrb_ast_args *args, node *bod
|
||||
/* keyword arguments */
|
||||
ka = args->keyword_args ? node_len(args->keyword_args) : 0;
|
||||
kd = args->kwrest_arg ? 1 : 0;
|
||||
ba = args->block_arg ? 1 : 0;
|
||||
/* &nil: no block accepted (noblock flag in aspec) */
|
||||
mrb_bool noblock = args->block_arg == MRB_SYM(nil);
|
||||
ba = (args->block_arg && !noblock) ? 1 : 0;
|
||||
|
||||
if (ma > 0x1f || oa > 0x1f || pa > 0x1f || ka > 0x1f) {
|
||||
codegen_error(s, "too many formal arguments");
|
||||
}
|
||||
/* (23bits = 5:5:1:5:5:1:1) */
|
||||
a = MRB_ARGS_REQ(ma)
|
||||
/* (24bits = 1:5:5:1:5:5:1:1) */
|
||||
a = (noblock ? MRB_ARGS_NOBLOCK() : 0)
|
||||
| MRB_ARGS_REQ(ma)
|
||||
| MRB_ARGS_OPT(oa)
|
||||
| (ra ? MRB_ARGS_REST() : 0)
|
||||
| MRB_ARGS_POST(pa)
|
||||
|
||||
@@ -1215,7 +1215,7 @@ new_args_tail(parser_state *p, node *kws, mrb_sym kwrest, mrb_sym blk)
|
||||
}
|
||||
|
||||
local_add_blk(p);
|
||||
if (blk) local_add_f(p, blk);
|
||||
if (blk && blk != MRB_SYM(nil)) local_add_f(p, blk);
|
||||
|
||||
/* allocate register for keywords arguments */
|
||||
/* order is for Proc#parameters */
|
||||
@@ -4861,6 +4861,10 @@ f_block_arg : blkarg_mark tIDENTIFIER
|
||||
{
|
||||
$$ = $2;
|
||||
}
|
||||
| blkarg_mark keyword_nil
|
||||
{
|
||||
$$ = MRB_SYM(nil);
|
||||
}
|
||||
| blkarg_mark
|
||||
{
|
||||
$$ = intern_op(and);
|
||||
@@ -8047,6 +8051,8 @@ dump_args(mrb_state *mrb, struct mrb_ast_args *args, int offset, uint16_t lineno
|
||||
dump_prefix(offset, lineno);
|
||||
if (blk == MRB_OPSYM(and))
|
||||
printf("blk=&\n");
|
||||
else if (blk == MRB_SYM(nil))
|
||||
printf("blk=&nil\n");
|
||||
else
|
||||
printf("blk=&%s\n", mrb_sym_name(mrb, blk));
|
||||
}
|
||||
|
||||
+2797
-2839
File diff suppressed because it is too large
Load Diff
+3
-2
@@ -374,14 +374,15 @@ codedump(mrb_state *mrb, const mrb_irep *irep, FILE *out)
|
||||
print_lv_a(mrb, irep, a, out);
|
||||
break;
|
||||
CASE(OP_ENTER, W):
|
||||
fprintf(out, "ENTER\t\t%d:%d:%d:%d:%d:%d:%d (0x%x)\n",
|
||||
fprintf(out, "ENTER\t\t%d:%d:%d:%d:%d:%d:%d:%d (0x%x)\n",
|
||||
MRB_ASPEC_REQ(a),
|
||||
MRB_ASPEC_OPT(a),
|
||||
MRB_ASPEC_REST(a),
|
||||
MRB_ASPEC_POST(a),
|
||||
MRB_ASPEC_KEY(a),
|
||||
MRB_ASPEC_KDICT(a),
|
||||
MRB_ASPEC_BLOCK(a), a);
|
||||
MRB_ASPEC_BLOCK(a),
|
||||
MRB_ASPEC_NOBLOCK(a), a);
|
||||
break;
|
||||
CASE(OP_KEY_P, BB):
|
||||
fprintf(out, "KEY_P\t\tR%d\t:%s", a, mrb_sym_dump(mrb, irep->syms[b]));
|
||||
|
||||
@@ -2558,6 +2558,12 @@ RETRY_TRY_BLOCK:
|
||||
|
||||
mrb_value * const argv0 = argv;
|
||||
mrb_value blk = regs[ci_bidx(ci)];
|
||||
|
||||
/* &nil: reject block */
|
||||
if (MRB_ASPEC_NOBLOCK(a) && !mrb_nil_p(blk)) {
|
||||
RAISE_LIT(mrb, E_ARGUMENT_ERROR, "no block accepted");
|
||||
}
|
||||
|
||||
mrb_value kdict = mrb_nil_value();
|
||||
|
||||
/* keyword arguments */
|
||||
|
||||
Reference in New Issue
Block a user