Skip to content

Commit

Permalink
RakuAST: add support for supply blocks
Browse files Browse the repository at this point in the history
- add RakuAST::StatementPrefix::Supply class
- adapt grammar and actions accordingly
- add tests, .rakufication and deparsing already handled by base class

This did *not* port the optimizations for single emit supplies.

  https://github.com/rakudo/rakudo/blob/main/src/Perl6/Actions.nqp#L2557-L2577

Feels this should be part of a more general optimization strategy
in RakuAST.
  • Loading branch information
lizmat committed Aug 3, 2023
1 parent 652b305 commit e13a6b0
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 2 deletions.
3 changes: 2 additions & 1 deletion src/Raku/Grammar.nqp
Original file line number Diff line number Diff line change
Expand Up @@ -1103,8 +1103,9 @@ grammar Raku::Grammar is HLL::Grammar does Raku::Common {
token statement-prefix:sym<eager> { <sym><.kok> <blorst> }
token statement-prefix:sym<gather> { <sym><.kok> <blorst> }
token statement-prefix:sym<quietly> { <sym><.kok> <blorst> }
token statement-prefix:sym<try> { <sym><.kok> <blorst> }
token statement-prefix:sym<start> { <sym><.kok> <blorst> }
token statement-prefix:sym<supply> { <sym><.kok> <blorst> }
token statement-prefix:sym<try> { <sym><.kok> <blorst> }
# Prefixes that work differently on for loops
token statement-prefix:sym<hyper> { <sym><.kok> <blorst> }
Expand Down
46 changes: 46 additions & 0 deletions src/Raku/ast/statementprefixes.rakumod
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,52 @@ class RakuAST::StatementPrefix::Start
}
}

# The `supply` statement prefix.
class RakuAST::StatementPrefix::Supply
is RakuAST::StatementPrefix::Thunky
is RakuAST::SinkPropagator
is RakuAST::ImplicitBlockSemanticsProvider
{
method type() { "supply" }

method propagate-sink(Bool $is-sunk) {
self.blorst.apply-sink(False);
}

method apply-implicit-block-semantics() {
self.blorst.set-fresh-variables(:match, :exception)
if nqp::istype(self.blorst, RakuAST::Block);
}

method IMPL-QAST-FORM-BLOCK(
RakuAST::IMPL::QASTContext $context,
str :$blocktype,
RakuAST::Expression :$expression
) {
if nqp::istype(self.blorst, RakuAST::Block) {
self.blorst.IMPL-QAST-FORM-BLOCK($context, :$blocktype, :$expression)
}
else {
my $block := QAST::Block.new(
:blocktype('declaration_static'),
QAST::Stmts.new(
RakuAST::VarDeclaration::Implicit::Special.new(:name('$/')).IMPL-QAST-DECL($context),
RakuAST::VarDeclaration::Implicit::Special.new(:name('$!')).IMPL-QAST-DECL($context),
self.blorst.IMPL-TO-QAST($context)
));
$block.arity(0);
$block
}
}

method IMPL-EXPR-QAST(RakuAST::IMPL::QASTContext $context) {
QAST::Op.new(:op<call>,
:name<&SUPPLY>,
self.IMPL-CLOSURE-QAST($context)
)
}
}

# Done by all phasers. Serves as little more than a marker for phasers, for
# easing locating them all.
class RakuAST::StatementPrefix::Phaser
Expand Down
68 changes: 67 additions & 1 deletion t/12-rakuast/statement-prefix.rakutest
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use v6.e.PREVIEW;
use Test;

plan 14;
plan 16;

my $ast;
my $deparsed;
Expand Down Expand Up @@ -461,4 +461,70 @@ subtest 'A start has a fresh $!' => {
}
}

subtest 'supply statement prefix with expression evaluates to Supply' => {
# supply emit(42)
ast RakuAST::StatementPrefix::Supply.new(
RakuAST::Statement::Expression.new(
expression => RakuAST::Call::Name.new(
name => RakuAST::Name.from-identifier("emit"),
args => RakuAST::ArgList.new(
RakuAST::IntLiteral.new(42)
)
)
)
);

# must be this number of tests
plan 7;

is-deeply $deparsed, 'supply emit(42)', 'deparse';

for
'AST', EVAL($ast),
'Str', EVAL($deparsed),
'Raku', EVAL(EVAL $raku)
-> $type, $supply {
isa-ok $supply, Supply, $type;
$supply.tap({ is $_, 42, 'emitted value ok' });
}
}

subtest 'supply statement prefix with block evaluates to Supply' => {
# supply { emit(42) }
ast RakuAST::StatementPrefix::Supply.new(
RakuAST::Block.new(
body => RakuAST::Blockoid.new(
RakuAST::StatementList.new(
RakuAST::Statement::Expression.new(
expression => RakuAST::Call::Name.new(
name => RakuAST::Name.from-identifier("emit"),
args => RakuAST::ArgList.new(
RakuAST::IntLiteral.new(42)
)
)
)
)
)
)
);

# must be this number of tests
plan 7;

is-deeply $deparsed, q:to/CODE/.chomp, 'deparse';
supply {
emit(42)
}
CODE

for
'AST', EVAL($ast),
'Str', EVAL($deparsed),
'Raku', EVAL(EVAL $raku)
-> $type, $supply {
isa-ok $supply, Supply, $type;
$supply.tap({ is $_, 42, 'emitted value ok' });
}
}

# vim: expandtab shiftwidth=4

0 comments on commit e13a6b0

Please sign in to comment.