method quote:sym<s>($/) {
# We are emulating Str.subst/subst-mutate here, by calling match, assigning the result to
# a temporary variable etc.
# Build the regex.
my $rx_block := $*SUBST_LHS_BLOCK;
$rx_block.push(QAST::Stmts.new);
my %sig_info := hash(parameters => []);
###################################################
###################################################
###################################################
###################################################
#⟱⟱⟱⟱ glitch seems to start on the next line, right after word `regex`⟱⟱⟱⟱
###################################################
###################################################
my $rx_coderef := regex_coderef($/, $*W.stub_code_object('Regex'),
$<sibble><left>.ast, 'anon', '', %sig_info, $rx_block, :use_outer_match(1));
# Quote needs to be closure-i-fied.
my $infixish := $<sibble><infixish>;
my $right;
if !$infixish || $infixish.Str eq '=' {
$right := WANTED($<sibble><right>.ast,'quote:s///');
}
else {
$right := $infixish.ast;
$right.push(QAST::Op.new(
:op('assign'),
QAST::Op.new( :op('p6scalarfromdesc'), QAST::Op.new( :op('null') ) ),
QAST::Var.new( :name('$/'), :scope('lexical') )
));
$right.push(WANTED($<sibble><right>.ast,'quote:s'));
}
my $rep_block := $*SUBST_RHS_BLOCK;
$rep_block.push(QAST::Stmts.new($right, :node($<sibble><right>)));
$*W.cur_lexpad()[0].push($rep_block);
my $closure := block_closure(reference_to_code_object(
$*W.create_simple_code_object($rep_block, 'Code'),
$rep_block));
# self.match($rx_coderef, |%options);
my $past := QAST::Op.new( :node($/), :op('callmethod'), :name('match'),
WANTED(QAST::Var.new( :name('$_'), :scope('lexical') ),'s'),
$rx_coderef
);
self.handle_and_check_adverbs($/, %SUBST_ALLOWED_ADVERBS, 'substitution', $past);
if $/[0] {
$past.push(QAST::IVal.new(:named('samespace'), :value(1)));
}
my $samespace := +$/[0];
my $sigspace := $samespace;
my $samecase := 0;
my $samemark := 0;
my $global := 0;
for $<rx_adverbs>.ast {
if $_.named eq 'samecase' || $_.named eq 'ii' {
$samecase := 1;
}
elsif $_.named eq 'samemark' || $_.named eq 'mm' {
$samemark := 1;
}
elsif $_.named eq 'global' || $_.named eq 'g' {
$global := 1;
}
elsif $_.named eq 'samespace' || $_.named eq 'ss' {
$samespace := 1;
$sigspace := 1;
}
elsif $_.named eq 'sigspace' || $_.named eq 's' {
$sigspace := 1;
}
}
my $result := $past.unique('subst_result');
my $global_result := $past.unique('subst_global_result');
my $List := $*W.find_symbol(['List']);
my $apply_matches := QAST::Op.new( :op('callmethod'), :name('dispatch:<!>'),
QAST::Op.new( :op('callmethod'), :name('Str'),
WANTED(QAST::Var.new( :name('$_'), :scope('lexical') ),'s/apply') ),
QAST::SVal.new( :value('APPLY-MATCHES') ),
QAST::WVal.new( :value($*W.find_symbol(['Str'])) ),
QAST::Var.new( :name($result), :scope('local') ),
$closure,
QAST::Var.new( :name('$/'), :scope('lexical') ), # caller dollar slash
QAST::IVal.new( :value(1) ), # set dollar slash
QAST::IVal.new( :value($sigspace) ),
QAST::IVal.new( :value($samespace) ),
QAST::IVal.new( :value($samecase) ),
QAST::IVal.new( :value($samemark) ),
);
$past := QAST::Op.new( :op('locallifetime'), :node($/),
QAST::Stmt.new(
# my $result;
QAST::Var.new( :name($result), :scope('local'), :decl('var') ),
# $result := self.match(...
QAST::Op.new( :op('bind'),
QAST::Var.new( :name($result), :scope('local') ),
$past
),
QAST::Op.new( :op('p6store'),
QAST::Var.new( :name('$/'), :scope('lexical') ),
QAST::Var.new( :name($result), :scope('local') ),
),
# It matched something. Either a single item or a list of matches.
QAST::Op.new( :op('if'),
QAST::Op.new( :op('unless'),# :name('&infix:<||>'),
QAST::Op.new( :op('istype'),
QAST::Var.new( :name($result), :scope('local') ),
QAST::WVal.new( :value($*W.find_symbol(['Match'])) )
),
QAST::Op.new( :op('if'),
QAST::Op.new( :op('istype'),
QAST::Var.new( :name($result), :scope('local') ),
QAST::WVal.new( :value($*W.find_symbol(['Positional'])) )
),
QAST::Op.new( :op('callmethod'), :name('elems'),
QAST::Var.new( :name($result), :scope('local') )
)
)
),
QAST::Op.new( :op('call'), :name('&infix:<=>'),
WANTED(QAST::Var.new( :name($<sym> eq 's' ?? '$_' !! '$/'), :scope('lexical') ),'s/assign'),
$apply_matches
),
( $<sym> eq 'S'
?? QAST::Op.new( :op('p6store'),
QAST::Var.new( :name('$/'), :scope('lexical') ),
WANTED(QAST::Var.new( :name('$_'), :scope('lexical') ),'S'),
)
!! QAST::Stmt.new()
),
),
# It will return a list of matches when we match globally, and a single
# match otherwise.
$<sym> eq 's' ?? (
$global ??
QAST::Op.new( :op('p6store'),
QAST::Var.new( :name('$/'), :scope('lexical') ),
QAST::Stmts.new(
QAST::Op.new( :op('bind'),
QAST::Var.new( :name($global_result), :scope('local'), :decl('var') ),
QAST::Op.new( :op('callmethod'), :name('CREATE'),
QAST::WVal.new( :value($List) )
)
),
QAST::Op.new( :op('bindattr'),
QAST::Var.new( :name($global_result), :scope('local') ),
QAST::WVal.new( :value($List) ),
QAST::SVal.new( :value('$!reified') ),
QAST::Op.new( :op('getattr'),
QAST::Var.new( :name($result), :scope('local') ),
QAST::WVal.new( :value($List) ),
QAST::SVal.new( :value('$!reified') )
)
),
QAST::Var.new( :name($global_result), :scope('local') )
)
) !! QAST::Stmt.new()
) !! QAST::Stmt.new(),
# The result of this operation.
QAST::Var.new( :name('$/'), :scope('lexical') )
),
);
$past.annotate('is_S', $<sym> eq 'S');
make WANTED($past, 's///'); # never carp about s/// in sink context
}