diff --git a/src/PAST/Compiler-Regex.pir b/src/PAST/Compiler-Regex.pir index 0c4812a..0ef6d13 100644 --- a/src/PAST/Compiler-Regex.pir +++ b/src/PAST/Compiler-Regex.pir @@ -783,7 +783,7 @@ Perform a subrule call. (cur, pos, fail) = self.'!rxregs'('cur pos fail') ops = self.'post_new'('Ops', 'node'=>node, 'result'=>cur) - .local pmc name, negate + .local pmc name $P0 = node.'name'() name = self.'as_post'($P0, 'rtype'=>'~') ops.'push'(name) @@ -796,13 +796,25 @@ Perform a subrule call. .local pmc zerowidth zerowidth = node.'zerowidth'() + .local pmc bindpast, bindpost + bindpast = node.'bindnames'() + unless bindpast goto bindpost_done + bindpost = self.'as_post'(bindpast, 'rtype'=>'*') + bindpost_done: + ops.'push_pirop'('inline', name, negate, zerowidth, 'inline'=>" # rx subrule %0 negate=%1 zerowidth=%2") self.'!cursorop'(ops, '!cursor_pos', 0, pos) ops.'push_pirop'('callmethod', name, cur, 'result'=>'$P10') ops.'push_pirop'(testop, '$P10', fail) - if zerowidth goto done + unless bindpast goto bindnames_done + ops.'push'(bindpost) + self.'!cursorop'(ops, '!cursor_names', 0, bindpost) + bindnames_done: + if zerowidth goto zerowidth_done ops.'push_pirop'('callmethod', "'pos'", '$P10', 'result'=>pos) + zerowidth_done: + done: .return (ops) .end diff --git a/src/PAST/Regex.pir b/src/PAST/Regex.pir index 6f1f92a..47c2a04 100644 --- a/src/PAST/Regex.pir +++ b/src/PAST/Regex.pir @@ -27,6 +27,13 @@ for regular expressions. .end +.sub 'bindnames' :method + .param pmc value :optional + .param int has_value :opt_flag + .tailcall self.'attr'('bindnames', value, has_value) +.end + + .sub 'negate' :method .param pmc value :optional .param int has_value :opt_flag diff --git a/src/Regex/Cursor.pir b/src/Regex/Cursor.pir index 2517add..f488106 100644 --- a/src/Regex/Cursor.pir +++ b/src/Regex/Cursor.pir @@ -19,7 +19,7 @@ grammars. load_bytecode 'P6object.pbc' .local pmc p6meta p6meta = new 'P6metaclass' - $P0 = p6meta.'new_class'('Regex::Cursor', 'attr'=>'$!target $!from $!pos $!match $!action @!bstack @!cstack') + $P0 = p6meta.'new_class'('Regex::Cursor', 'attr'=>'$!target $!from $!pos $!match $!action $!names @!bstack @!cstack') $P0 = box 0 set_global '$!generation', $P0 $P0 = new ['Boolean'] @@ -46,15 +46,37 @@ for the Cursor if one hasn't been created yet. $I0 = isa match, ['Regex';'Match'] if $I0 goto match_done + # First, create a Match object and bind it match_make: match = new ['Regex';'Match'] setattribute self, '$!match', match - $P0 = getattribute self, '$!target' - setattribute match, '$!target', $P0 - $P0 = getattribute self, '$!from' - setattribute match, '$!from', $P0 - $P0 = getattribute self, '$!pos' - setattribute match, '$!to', $P0 + .local pmc target, from, to + target = getattribute self, '$!target' + setattribute match, '$!target', target + from = getattribute self, '$!from' + setattribute match, '$!from', from + to = getattribute self, '$!pos' + setattribute match, '$!to', to + + # If it's not a successful match, or if there are + # no saved subcursors, we're done. + if to < from goto match_done + .local pmc cstack, cstack_it + cstack = getattribute self, '@!cstack' + if null cstack goto cstack_done + unless cstack goto cstack_done + cstack_it = iter cstack + cstack_loop: + unless cstack_it goto cstack_done + .local pmc subcur, subnames, submatch + subcur = shift cstack_it + # If the subcursor isn't bound with a name, skip it + subnames = getattribute subcur, '$!names' + if null subnames goto cstack_loop + match = subcur.'MATCH'() + match[subnames] = submatch + goto cstack_loop + cstack_done: match_done: .return (match) @@ -201,6 +223,18 @@ with a "real" Match object when requested. .end +=item !cursor_names(names) + +Set the Cursor's name (for binding) to names. + +=cut + +=sub '!cursor_names' :method + .param pmc names + setattribute self, '$!names', names +.end + + =item !cursor_pos(pos) Set the cursor's position to C. diff --git a/src/Regex/P6Regex/Actions.pm b/src/Regex/P6Regex/Actions.pm index fa2dcfd..2cd5648 100644 --- a/src/Regex/P6Regex/Actions.pm +++ b/src/Regex/P6Regex/Actions.pm @@ -213,7 +213,8 @@ method assertion:sym($/) { } method assertion:sym($/) { - my $past := PAST::Regex.new( :name(~$) , :pasttype('subrule') ); + my $past := PAST::Regex.new( :name(~$) , :pasttype('subrule'), + :bindnames(~$) ); make $past; }