mruby-compiler: add pin operator to pattern matching

Add pin operator `^var` that matches against existing variable values
instead of creating new bindings. Also add bracket-less array pattern
syntax at top level: `in 1, 2, x` is equivalent to `in [1, 2, x]`.

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-12-17 13:42:22 +09:00
parent 21472638b9
commit 1de6340f1b
3 changed files with 4827 additions and 4582 deletions
+24
View File
@@ -4410,6 +4410,30 @@ codegen_pattern(codegen_scope *s, node *pattern, int target, uint32_t *fail_pos)
}
break;
case NODE_PAT_PIN:
{
struct mrb_ast_pat_pin_node *pat_pin = pat_pin_node(pattern);
/* Get the current value of the pinned variable */
int idx = lv_idx(s, pat_pin->name);
if (idx > 0) {
/* Compare: pinned_value === target */
gen_move(s, cursp(), idx, 0); /* Load pinned variable */
push();
gen_move(s, cursp(), target, 0); /* Load target */
push(); push(); pop(); pop(); pop();
genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_OPSYM_2(s->mrb, eqq)), 1);
/* Jump to fail if not matched */
tmp = genjmp2(s, OP_JMPNOT, cursp(), *fail_pos, 1);
*fail_pos = tmp;
}
else {
/* Variable not found - this is an error case, but for robustness fail the match */
tmp = genjmp(s, OP_JMP, *fail_pos);
*fail_pos = tmp;
}
}
break;
case NODE_PAT_ARRAY:
{
struct mrb_ast_pat_array_node *pat_arr = pat_array_node(pattern);
+61 -4
View File
@@ -632,6 +632,16 @@ new_pat_var(parser_state *p, mrb_sym name)
return (node*)n;
}
/* Create pin pattern node (^var) */
static node*
new_pat_pin(parser_state *p, mrb_sym name)
{
struct mrb_ast_pat_pin_node *n = NEW_NODE(pat_pin, NODE_PAT_PIN);
n->name = name;
/* Pin operator references existing variable, does not create new binding */
return (node*)n;
}
/* Create as pattern node (pattern => var) */
static node*
new_pat_as(parser_state *p, node *pattern, mrb_sym name)
@@ -2074,7 +2084,7 @@ prohibit_literals(parser_state *p, node *n)
%type <id> f_label f_kwrest
/* pattern matching */
%type <nd> in_clauses p_expr p_alt p_value p_var p_as p_array p_array_body p_array_elems p_rest p_hash p_hash_body p_hash_elems p_hash_elem p_kwrest
%type <nd> in_clauses p_expr p_alt p_value p_var p_as p_array p_array_body p_array_elems p_rest p_hash p_hash_body p_hash_elems p_hash_elem p_kwrest p_args_head p_args_post
%token tUPLUS "unary plus"
%token tUMINUS "unary minus"
@@ -3860,7 +3870,50 @@ in_clauses : opt_else
;
/* Pattern expressions for case/in */
/* Bracket-less array patterns: in 1, 2, x is same as in [1, 2, x] */
p_expr : p_as
| p_args_head p_as
{
$$ = new_pat_array(p, push($1, $2), 0, 0);
}
| p_args_head p_rest
{
$$ = new_pat_array(p, $1, $2, 0);
}
| p_args_head p_rest ',' p_args_post
{
$$ = new_pat_array(p, $1, $2, $4);
}
| p_rest
{
$$ = new_pat_array(p, 0, $1, 0);
}
| p_rest ',' p_args_post
{
$$ = new_pat_array(p, 0, $1, $3);
}
;
/* Comma-separated pattern list (prefix) */
p_args_head : p_as ','
{
$$ = list1($1);
}
| p_args_head p_as ','
{
$$ = push($1, $2);
}
;
/* Comma-separated pattern list (suffix, no trailing comma) */
p_args_post : p_as
{
$$ = list1($1);
}
| p_args_post ',' p_as
{
$$ = push($1, $3);
}
;
p_as : p_alt
@@ -3916,6 +3969,10 @@ p_value : p_var
}
| p_array
| p_hash
| '^' tIDENTIFIER
{
$$ = new_pat_pin(p, $2);
}
;
/* Array pattern: [a, b, *rest, c] */
@@ -3957,12 +4014,12 @@ p_array_body : p_array_elems
}
;
/* Non-rest array pattern elements */
p_array_elems : p_expr
/* Non-rest array pattern elements - use p_as, not p_expr to avoid bracket-less recursion */
p_array_elems : p_as
{
$$ = list1($1);
}
| p_array_elems ',' p_expr
| p_array_elems ',' p_as
{
$$ = push($1, $3);
}
File diff suppressed because it is too large Load Diff