Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
allow $x ~~ s/// to return Match or list of Match
s/// is now implemented in terms of .subst-mutate, which returns
the matches instead of the result, just as normal matching does.
  • Loading branch information
TimToady committed Dec 13, 2014
1 parent 8e76f01 commit 5a06ace
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 20 deletions.
19 changes: 4 additions & 15 deletions src/Perl6/Actions.nqp
Expand Up @@ -5126,21 +5126,10 @@ class Perl6::Actions is HLL::Actions does STDActions {
my $result_var := $lhs.unique('sm_result');
my $sm_call;

# In case the rhs is a substitution, the result should say if it actually
# matched something. Calling ACCEPTS will always be True for this case.
if $rhs.ann('is_subst') {
$sm_call := QAST::Stmt.new(
$rhs,
QAST::Op.new(
:op('callmethod'), :name('Bool'),
QAST::Var.new( :name('$/'), :scope('lexical') )
)
);
}
# Transliteration shuffles values around itself and returns the
# Right Thing regardless of whether we're in a smart-match or
# implicitely against $_, so we just do the RHS here.
elsif $rhs.ann('is_trans') {
if $rhs.ann('is_trans') {
$sm_call := QAST::Stmt.new(
$rhs
);
Expand Down Expand Up @@ -6117,10 +6106,10 @@ class Perl6::Actions is HLL::Actions does STDActions {
# Quote needs to be closure-i-fied.
my $closure := block_closure(make_thunk_ref($<sibble><right>.ast, $<sibble><right>));

# make $_ = $_.subst(...)
# make $/ = $_.subst-mutate(...)
my $past := QAST::Op.new(
:node($/),
:op('callmethod'), :name('subst'),
:op('callmethod'), :name('subst-mutate'),
QAST::Var.new( :name('$_'), :scope('lexical') ),
$rx_coderef, $closure
);
Expand All @@ -6134,7 +6123,7 @@ class Perl6::Actions is HLL::Actions does STDActions {
:node($/),
:op('call'),
:name('&infix:<=>'),
QAST::Var.new(:name('$_'), :scope('lexical')),
QAST::Var.new(:name('$/'), :scope('lexical')),
$past
);

Expand Down
5 changes: 5 additions & 0 deletions src/core/Cool.pm
Expand Up @@ -204,6 +204,11 @@ my class Cool { # declared in BOOTSTRAP
self.Stringy.subst($matcher, $replacement, |%adverbs);
}

proto method subst-mutate(|c) {
$/ := nqp::getlexdyn('$/');
{*}
}

proto method IO(|) { * }
multi method IO(|c) { IO::Path.new(self) }

Expand Down
3 changes: 2 additions & 1 deletion src/core/IO/Spec/Cygwin.pm
@@ -1,6 +1,7 @@
my class IO::Spec::Cygwin is IO::Spec::Unix {

method canonpath (Cool:D $path is copy) {
method canonpath (Cool:D $patharg) {
my $path = $patharg.Str;
$path.=subst(:g, '\\', '/');

# Handle network path names beginning with double slash
Expand Down
3 changes: 2 additions & 1 deletion src/core/IO/Spec/QNX.pm
@@ -1,6 +1,7 @@
my class IO::Spec::QNX is IO::Spec::Unix {

method canonpath ($path is copy, :$parent) {
method canonpath ($patharg, :$parent) {
my $path = $patharg.Str;
# Handle POSIX-style node names beginning with double slash (qnx, nto)
# (POSIX says: "a pathname that begins with two successive slashes
# may be interpreted in an implementation-defined manner, although
Expand Down
5 changes: 3 additions & 2 deletions src/core/IO/Spec/Unix.pm
@@ -1,13 +1,14 @@
my class IO::Spec::Unix is IO::Spec {

method canonpath( $path is copy, :$parent --> Str) {
method canonpath( $patharg, :$parent --> Str) {
my $path = $patharg.Str;
return '' if $path eq '';

$path ~~ s:g { '//' '/'* } = '/'; # xx////xx -> xx/xx
$path ~~ s:g { '/.'+ ['/' | $] } = '/'; # xx/././xx -> xx/xx
$path ~~ s { ^ './' <!before $> } = ''; # ./xx -> xx
if $parent {
while $path ~~ s:g { [^ | <?after '/'>] <!before '../'> <-[/]>+ '/..' ['/' | $ ] } = '' { };
Nil while $path ~~ s:g { [^ | <?after '/'>] <!before '../'> <-[/]>+ '/..' ['/' | $ ] } = '';
$path = '.' if $path eq '';
}
$path ~~ s { ^ '/..'+ ['/' | $] } = '/'; # /../..(/xx) -> /(xx)
Expand Down
3 changes: 2 additions & 1 deletion src/core/IO/Spec/Win32.pm
Expand Up @@ -7,7 +7,8 @@ my class IO::Spec::Win32 is IO::Spec::Unix {
my $UNCpath = regex { [<$slash> ** 2] <$notslash>+ <$slash> [<$notslash>+ | $] }
my $volume_rx = regex { <$driveletter> | <$UNCpath> }

method canonpath ($path, :$parent) {
method canonpath ($patharg, :$parent) {
my $path = $patharg.Str;
$path eq '' ?? '' !! self!canon-cat($path, :$parent);
}

Expand Down
32 changes: 32 additions & 0 deletions src/core/Str.pm
Expand Up @@ -674,6 +674,38 @@ my class Str does Stringy { # declared in BOOTSTRAP
}
}

multi method subst-mutate($self is rw: $matcher, $replacement,
:ii(:$samecase), :ss(:$samespace),
:$SET_CALLER_DOLLAR_SLASH, *%options) {
my $global = %options<g> || %options<global>;
my $caller_dollar_slash := nqp::getlexcaller('$/');
my $SET_DOLLAR_SLASH = $SET_CALLER_DOLLAR_SLASH || nqp::istype($matcher, Regex);
my @matches = self.match($matcher, |%options);
try $caller_dollar_slash = $/ if $SET_DOLLAR_SLASH;

return Nil unless @matches;
return Nil if @matches == 1 && !@matches[0];

my $prev = 0;
my $result = '';
for @matches -> $m {
try $caller_dollar_slash = $m if $SET_DOLLAR_SLASH;
$result ~= self.substr($prev, $m.from - $prev);

my $real_replacement = ~(nqp::istype($replacement,Callable)
?? ($replacement.count == 0 ?? $replacement() !! $replacement($m))
!! $replacement);
$real_replacement = $real_replacement.samecase(~$m) if $samecase;
$real_replacement = $real_replacement.samespace(~$m) if $samespace;
$result ~= $real_replacement;
$prev = $m.to;
}
my $last = @matches[@matches-1];
$result ~= self.substr($last.to);
$self = $result;
$global ?? (@matches,).list !! @matches[0];
}

multi method subst($matcher, $replacement,
:ii(:$samecase), :ss(:$samespace),
:$SET_CALLER_DOLLAR_SLASH, *%options) {
Expand Down

0 comments on commit 5a06ace

Please sign in to comment.