Skip to content
This repository has been archived by the owner on Feb 3, 2021. It is now read-only.

Commit

Permalink
Add support for interpolation in regexes
Browse files Browse the repository at this point in the history
  • Loading branch information
bkeeler committed May 16, 2010
1 parent f34ed51 commit f2c2f18
Show file tree
Hide file tree
Showing 5 changed files with 415 additions and 54 deletions.
145 changes: 114 additions & 31 deletions src/NQP/Actions.pm
Expand Up @@ -47,11 +47,26 @@ sub colonpair_str($ast) {
}

method comp_unit($/) {
my $past := $<statementlist>.ast;
my $BLOCK := @BLOCK.shift;
$BLOCK.push($past);
$BLOCK.node($/);
make $BLOCK;
my $mainline := $<statementlist>.ast;
my $unit := @BLOCK.shift;

# We force a return here, because we have other
# :load/:init blocks to execute that we don't want
# to include as part of the mainline.
$unit.push(
PAST::Op.new( :pirop<return>, $mainline )
);

# If this code is loaded via load_bytecode, we want the unit mainline
# to be executed after all other loadinits have taken place.
$unit.push(
PAST::Block.new(
:pirflags(':load'), :lexical(0), :namespace(''),
PAST::Op.new( :pasttype<call>, PAST::Val.new( :value($unit) ) )
)
);
$unit.node($/);
make $unit;
}

method statementlist($/) {
Expand All @@ -60,9 +75,7 @@ method statementlist($/) {
for $<statement> {
my $ast := $_.ast;
$ast := $ast<sink> if pir::defined($ast<sink>);
if $ast.isa(PAST::Block) && !$ast.blocktype {
$ast := block_immediate($ast);
}
if $ast<bareblock> { $ast := block_immediate($ast); }
$past.push( $ast );
}
}
Expand Down Expand Up @@ -104,6 +117,7 @@ method blockoid($/) {
my $BLOCK := @BLOCK.shift;
$BLOCK.push($past);
$BLOCK.node($/);
$BLOCK.closure(1);
make $BLOCK;
}

Expand Down Expand Up @@ -280,8 +294,7 @@ method term:sym<lambda>($/) { make $<pblock>.ast; }

method fatarrow($/) {
my $past := $<val>.ast;
my $name := ?$<quote> ?? $<key>.ast !! $<key>.Str;
$past.named( $name );
$past.named( $<key>.Str );
make $past;
}

Expand Down Expand Up @@ -367,6 +380,10 @@ method scope_declarator:sym<our>($/) { make $<scoped>.ast; }
method scope_declarator:sym<has>($/) { make $<scoped>.ast; }

method scoped($/) {
make $<declarator>.ast;
}

method declarator($/) {
make $<routine_declarator>
?? $<routine_declarator>.ast
!! $<variable_declarator>.ast;
Expand Down Expand Up @@ -615,6 +632,10 @@ method arglist($/) {
if $past[$i].name eq '&prefix:<|>' {
$past[$i] := $past[$i][0];
$past[$i].flat(1);
if $past[$i].isa(PAST::Val)
&& pir::substr($past[$i].name, 0, 1) eq '%' {
$past[$i].named(1);
}
}
$i++;
}
Expand Down Expand Up @@ -649,9 +670,11 @@ method circumfix:sym<ang>($/) { make $<quote_EXPR>.ast; }
method circumfix:sym<« »>($/) { make $<quote_EXPR>.ast; }

method circumfix:sym<{ }>($/) {
make +$<pblock><blockoid><statementlist><statement> > 0
?? $<pblock>.ast
!! vivitype('%');
my $past := +$<pblock><blockoid><statementlist><statement> > 0
?? $<pblock>.ast
!! vivitype('%');
$past<bareblock> := 1;
make $past;
}

method circumfix:sym<sigil>($/) {
Expand Down Expand Up @@ -735,6 +758,7 @@ method quote_escape:sym<{ }>($/) {
:pirop('set S*'), block_immediate($<block>.ast), :node($/)
);
}
method quote_escape:sym<esc>($/) { make "\c[27]"; }

## Operators

Expand All @@ -761,6 +785,23 @@ method prefix:sym<make>($/) {
);
}

sub control($/, $id) {
make PAST::Op.new(
:node($/),
:pasttype('inline'),
:inline(
'.include "except_types.pasm"',
' %r = new "Exception"',
' %r["type"] = ' ~ $id,
' throw %r'
)
)
}

method term:sym<next>($/) { control($/, '.CONTROL_LOOP_NEXT') }
method term:sym<last>($/) { control($/, '.CONTROL_LOOP_LAST') }
method term:sym<redo>($/) { control($/, '.CONTROL_LOOP_REDO') }

method infix:sym<~~>($/) {
make PAST::Op.new( :pasttype<callmethod>, :name<ACCEPTS>, :node($/) );
}
Expand All @@ -773,29 +814,71 @@ class NQP::RegexActions is Regex::P6Regex::Actions {
make PAST::Regex.new( $past, :pasttype('pastnode') );
}

method metachar:sym<{ }>($/) { make $<codeblock>.ast; }
method metachar:sym<var>($/) {
my $past;
my $name := $<pos> ?? +$<pos> !! ~$<name>;
if $<quantified_atom> {
if $<var> {
$/.CURSOR.panic('"$var = " syntax not yet supported in regexes');
}
$past := $<quantified_atom>[0].ast;
if $past.pasttype eq 'quant' && $past[0].pasttype eq 'subrule' {
Regex::P6Regex::Actions::subrule_alias($past[0], $name);
}
elsif $past.pasttype eq 'subrule' { Regex::P6Regex::Actions::subrule_alias($past, $name); }
else {
$past := PAST::Regex.new( $past, :name($name), :pasttype('subcapture'), :node($/) );
}
}
else {
if $<var> {
my @MODIFIERS := Q:PIR {
%r = get_hll_global ['Regex';'P6Regex';'Actions'], '@MODIFIERS'
};
my $subtype := @MODIFIERS[0]<i> ?? 'interp_literal_i' !! 'interp_literal';
$past := PAST::Regex.new( $<var>.ast, :pasttype('pastnode'),
:subtype($subtype), :node($/) );
} else {
$past := PAST::Regex.new( '!BACKREF', $name, :pasttype('subrule'),
:subtype('method'), :node($/) );
}
}
make $past;
}

method assertion:sym<var>($/) {
make PAST::Regex.new( $<var>.ast, :pasttype('pastnode'),
:subtype('interp_regex'), :node($/) );
}


method assertion:sym<{ }>($/) { make $<codeblock>.ast; }
method metachar:sym<{ }>($/) {
make PAST::Regex.new(:node($/), :pasttype('pastnode'), $<codeblock>.ast);
}

method assertion:sym<{ }>($/) {
make PAST::Regex.new( :node($/), :pasttype('pastnode'), :subtype('interp_regex'),
$<codeblock>.ast );
}

method codeblock($/) {
my $block := $<block>.ast;
$block.blocktype('immediate');
my $past :=
PAST::Regex.new(
PAST::Stmts.new(
PAST::Op.new(
PAST::Var.new( :name('$/') ),
PAST::Op.new(
PAST::Var.new( :name('') ),
:name('MATCH'),
:pasttype('callmethod')
),
:pasttype('bind')
),
$block
make bindmatch($block);
}

sub bindmatch($past) {
PAST::Stmts.new(
PAST::Op.new(
PAST::Var.new( :name('$/') ),
PAST::Op.new(
PAST::Var.new( :name('') ),
:name('MATCH'),
:pasttype('callmethod')
),
:pasttype('pastnode')
);
make $past;
:pasttype('bind')
),
$past,
);
}
}
59 changes: 47 additions & 12 deletions src/NQP/Grammar.pm
Expand Up @@ -31,9 +31,10 @@ token ENDSTMT {
token ws {
|| <?MARKED('ws')>
|| <!ww>
[ \s+
[ \v+
| '#' \N*
| ^^ <.pod_comment>
| \h+
]*
<?MARKER('ws')>
}
Expand All @@ -51,10 +52,10 @@ token pod_comment {
^^ \h* '='
[
| 'begin' \h+ 'END' >>
[ .*? \n '=' 'end' \h+ 'END' » \N* || .* ]
[ .*? \n \h* '=' 'end' \h+ 'END' » \N* || .* ]
| 'begin' \h+ <identifier>
[
|| .*? \n '=' 'end' \h+ $<identifier> » \N*
|| .*? \n \h* '=' 'end' \h+ $<identifier> » \N*
|| <.panic: '=begin without matching =end'>
]
| 'begin' » \h*
Expand All @@ -63,10 +64,14 @@ token pod_comment {
|| .*? \n \h* '=' 'end' » \N*
|| <.panic: '=begin without matching =end'>
]
| <identifier>
.*? ^^ <?before \h* [
'='
[ 'cut' »
<.panic: 'Obsolete pod format, please use =begin/=end instead'> ]?
| \n ]>
|
[ <?before .*? ^^ '=cut' » >
<.panic: 'Obsolete pod format, please use =begin/=end instead'> ]?
[ <alpha> || \s || <.panic: 'Illegal pod directive'> ]
[ \s || <.panic: 'Illegal pod directive'> ]
\N*
]
}
Expand Down Expand Up @@ -224,9 +229,7 @@ token term:sym<statement_prefix> { <statement_prefix> }
token term:sym<lambda> { <?lambda> <pblock> }

token fatarrow {
| <key=.identifier> \h* '=>' <.ws> <val=.EXPR('i=')>
| $<quote>=<?[']> <key=.quote_EXPR: ':q'> \h* '=>' <.ws> <val=.EXPR('i=')>
| $<quote>=<?["]> <key=.quote_EXPR: ':qq'> \h* '=>' <.ws> <val=.EXPR('i=')>
<key=.identifier> \h* '=>' <.ws> <val=.EXPR('i=')>
}

token colonpair {
Expand Down Expand Up @@ -268,6 +271,13 @@ token scope_declarator:sym<our> { <sym> <scoped('our')> }
token scope_declarator:sym<has> { <sym> <scoped('has')> }

rule scoped($*SCOPE) {
| <declarator>
| <typename>+ <declarator> # eventually <multi_declarator>
}

token typename { <name> }

token declarator {
| <variable_declarator>
| <routine_declarator>
}
Expand Down Expand Up @@ -297,6 +307,7 @@ rule method_def {
token signature { [ [<.ws><parameter><.ws>] ** ',' ]? }

token parameter {
[ <typename> <.ws> ]* # <type_constraint>
[
| $<quant>=['*'] <param_var>
| [ <param_var> | <named_param> ] $<quant>=['?'|'!'|<?>]
Expand Down Expand Up @@ -390,9 +401,9 @@ token number {
proto token quote { <...> }
token quote:sym<apos> { <?[']> <quote_EXPR: ':q'> }
token quote:sym<dblq> { <?["]> <quote_EXPR: ':qq'> }
token quote:sym<q> { 'q' <![(]> <.ws> <quote_EXPR: ':q'> }
token quote:sym<qq> { 'qq' <![(]> <.ws> <quote_EXPR: ':qq'> }
token quote:sym<Q> { 'Q' <![(]> <.ws> <quote_EXPR> }
token quote:sym<q> { 'q' >> <![(]> <.ws> <quote_EXPR: ':q'> }
token quote:sym<qq> { 'qq' >> <![(]> <.ws> <quote_EXPR: ':qq'> }
token quote:sym<Q> { 'Q' >> <![(]> <.ws> <quote_EXPR> }
token quote:sym<Q:PIR> { 'Q:PIR' <.ws> <quote_EXPR> }
token quote:sym</ /> {
'/'
Expand All @@ -404,6 +415,7 @@ token quote:sym</ /> {

token quote_escape:sym<$> { <?[$]> <?quotemod_check('s')> <variable> }
token quote_escape:sym<{ }> { <?[{]> <?quotemod_check('c')> <block> }
token quote_escape:sym<esc> { \\ e <?quotemod_check('b')> }

token circumfix:sym<( )> { '(' <.ws> <EXPR>? ')' }
token circumfix:sym<[ ]> { '[' <.ws> <EXPR>? ']' }
Expand Down Expand Up @@ -523,6 +535,9 @@ token infix:sym<,> { <sym> <O('%comma, :pasttype<list>')> }

token prefix:sym<return> { <sym> \s <O('%list_prefix, :pasttype<return>')> }
token prefix:sym<make> { <sym> \s <O('%list_prefix')> }
token term:sym<last> { <sym> }
token term:sym<next> { <sym> }
token term:sym<redo> { <sym> }

method smartmatch($/) {
# swap rhs into invocant position
Expand All @@ -535,6 +550,26 @@ grammar NQP::Regex is Regex::P6Regex::Grammar {
':' <?before 'my'> <statement=.LANG('MAIN', 'statement')> <.ws> ';'
}

token metachar:sym<$> {
<sym> <!before \w>
}

token metachar:sym<var> {
[
| '$<' $<name>=[<-[>]>+] '>'
| '$' $<pos>=[\d+]
| <?before <[$@]> \w> <var=.LANG('MAIN', 'variable')>
| <?before '%' \w> <.panic: "Use of hash variable in patterns is reserved">
]

[ <.ws> '=' <.ws> <quantified_atom> ]?
}

token assertion:sym<var> {
| <?before <[$@]> \w> <var=.LANG('MAIN', 'variable')>
| <?before '%' \w> <.panic: "Use of hash variable in patterns is reserved">
}

token metachar:sym<{ }> {
<?[{]> <codeblock>
}
Expand Down

0 comments on commit f2c2f18

Please sign in to comment.