use v6.e.PREVIEW; use Test; plan 29; # Do not change this file to done-testing my $ast; my $deparsed; my $raku; my @type = ; sub ast(RakuAST::Node:D $node --> Nil) { $ast := $node; $deparsed := $node.DEPARSE; $raku := 'use experimental :rakuast; ' ~ $node.raku; diag $deparsed.chomp; } subtest 'Statement list evaluates to its final statement' => { my $x = 12; my $y = 99; # ++$x; ; ++$y ast RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::ApplyPrefix.new( prefix => RakuAST::Prefix.new('++'), operand => RakuAST::Var::Lexical.new('$x') ) ), RakuAST::Statement::Empty.new, RakuAST::Statement::Expression.new( expression => RakuAST::ApplyPrefix.new( prefix => RakuAST::Prefix.new('++'), operand => RakuAST::Var::Lexical.new('$y') ) ) ); is-deeply $deparsed, q:to/CODE/, 'deparse'; ++$x; ; ++$y CODE my $expected = 100; for 'AST', $ast, 'Str', $deparsed, 'Raku', EVAL($raku) -> $type, $it { is-deeply EVAL($ast), $expected, "$type: Statement list evaluates to its final statement"; is $x, $expected - 87, "$type: First side-effecting statement was executed"; is $y, $expected, "$type: Second side-effecting statement was executed"; ++$expected; } } subtest 'Basic if / elsif / else structure' => { my ($a, $b, $c); # if $a { 1 } # elsif $b { 2 } # elsif $c { 3 } # else { 4 } ast RakuAST::Statement::If.new( condition => RakuAST::Var::Lexical.new('$a'), then => RakuAST::Block.new( body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::IntLiteral.new(1) ) ) ) ), elsifs => [ RakuAST::Statement::Elsif.new( condition => RakuAST::Var::Lexical.new('$b'), then => RakuAST::Block.new( body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::IntLiteral.new(2) ) ) ) ) ), RakuAST::Statement::Elsif.new( condition => RakuAST::Var::Lexical.new('$c'), then => RakuAST::Block.new( body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::IntLiteral.new(3) ) ) ) ) ) ], else => RakuAST::Block.new( body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::IntLiteral.new(4) ) ) ) ) ); is-deeply $deparsed, Q:to/CODE/, 'deparse'; if $a { 1 } elsif $b { 2 } elsif $c { 3 } else { 4 } CODE for 'AST', $ast, 'Str', $deparsed, 'Raku', EVAL($raku) -> $type, $it { $a = $b = $c = False; is-deeply EVAL($it), 4, "$type: When all conditions False, else is evaluated"; $c = True; is-deeply EVAL($it), 3, "$type: Latest elsif reachable when matched"; $b = True; is-deeply EVAL($it), 2, "$type: First elsif reachable when matched"; $a = True; is-deeply EVAL($it), 1, "$type: When the main condition is true, the then block is picked"; } } subtest 'simple if evaluation' => { my $a; # if $a { 1 } ast RakuAST::Statement::If.new( condition => RakuAST::Var::Lexical.new('$a'), then => RakuAST::Block.new( body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::IntLiteral.new(1) ) ) ) ) ); is-deeply $deparsed, Q:to/CODE/, 'deparse'; if $a { 1 } CODE for 'AST', $ast, 'Str', $deparsed, 'Raku', EVAL($raku) -> $type, $it { $a = True; is-deeply EVAL($it), 1, "$type: When simple if with no else has true condition"; $a = False; is-deeply EVAL($it), Empty, "$type: When simple if with no else has false condition"; } } subtest 'Basic with / orwith / else structure' => { my ($a, $b, $c); # with $a -> $x { 1 } # orwith -> $x { 2 } # orwith -> $x { 3 } # else -> $x { 4 } ast RakuAST::Statement::With.new( condition => RakuAST::Var::Lexical.new('$a'), then => RakuAST::PointyBlock.new( signature => RakuAST::Signature.new( parameters => ( RakuAST::Parameter.new( target => RakuAST::ParameterTarget::Var.new('$x') ), ) ), body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::IntLiteral.new(1) ) ) ) ), elsifs => [ RakuAST::Statement::Orwith.new( condition => RakuAST::Var::Lexical.new('$b'), then => RakuAST::PointyBlock.new( signature => RakuAST::Signature.new( parameters => ( RakuAST::Parameter.new( target => RakuAST::ParameterTarget::Var.new('$x') ), ) ), body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::IntLiteral.new(2) ) ) ) ) ), RakuAST::Statement::Orwith.new( condition => RakuAST::Var::Lexical.new('$c'), then => RakuAST::PointyBlock.new( signature => RakuAST::Signature.new( parameters => ( RakuAST::Parameter.new( target => RakuAST::ParameterTarget::Var.new('$x') ), ) ), body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::IntLiteral.new(3) ) ) ) ) ) ], else => RakuAST::PointyBlock.new( signature => RakuAST::Signature.new( parameters => ( RakuAST::Parameter.new( target => RakuAST::ParameterTarget::Var.new('$x') ), ) ), body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::IntLiteral.new(4) ) ) ) ) ); is-deeply $deparsed, Q:to/CODE/, 'deparse'; with $a -> $x { 1 } orwith $b -> $x { 2 } orwith $c -> $x { 3 } else -> $x { 4 } CODE for 'AST', $ast, 'Str', $deparsed, 'Raku', EVAL($raku) -> $type, $it { $a = $b = $c = Nil; is-deeply EVAL($it), 4, "$type: When all conditions undefined, else is evaluated"; $c = False; is-deeply EVAL($it), 3, "$type: Latest orwith reachable when matched"; $b = False; is-deeply EVAL($it), 2, "$type: First orwith reachable when matched"; $a = False; is-deeply EVAL($it), 1, "$type: When the main condition is defined, the then block is picked"; } } subtest 'simple with evaluation' => { my $a; # with $a -> $x { 1 } ast RakuAST::Statement::With.new( condition => RakuAST::Var::Lexical.new('$a'), then => RakuAST::PointyBlock.new( signature => RakuAST::Signature.new( parameters => ( RakuAST::Parameter.new( target => RakuAST::ParameterTarget::Var.new('$x') ), ) ), body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::IntLiteral.new(1) ) ) ) ) ); is-deeply $deparsed, Q:to/CODE/, 'deparse'; with $a -> $x { 1 } CODE for 'AST', $ast, 'Str', $deparsed, 'Raku', EVAL($raku) -> $type, $it { $a = False; is-deeply EVAL($it), 1, "$type: When simple when with no else has defined condition"; $a = Nil; is-deeply EVAL($it), Empty, "$type: When simple with if with no else has undefined condition"; } } subtest 'with topicalizes in the body' => { # with $a { $_ } else { $_ } ast RakuAST::Statement::With.new( condition => RakuAST::Var::Lexical.new('$a'), then => RakuAST::Block.new( body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::Var::Lexical.new('$_') ) ) ) ), else => RakuAST::Block.new( body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::Var::Lexical.new('$_') ) ) ) ) ); is-deeply $deparsed, Q:to/CODE/, 'deparse'; with $a { $_ } else { $_ } CODE for 'AST', $ast, 'Str', $deparsed, 'Raku', EVAL($raku) -> $type, $it { my $a = 42; is-deeply EVAL($it), 42, "$type: with topicalizes in the body"; $a = Int; is-deeply EVAL($it), Int, "$type: with topicalizes in the else body too"; } } subtest 'simple unless with a false condition' => { my $x = False; my $y = 9; # unless $x { ++$y } ast RakuAST::Statement::Unless.new( condition => RakuAST::Var::Lexical.new('$x'), body => RakuAST::Block.new( body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::ApplyPrefix.new( prefix => RakuAST::Prefix.new('++'), operand => RakuAST::Var::Lexical.new('$y') ) ) ) ) ) ); is-deeply $deparsed, Q:to/CODE/, 'deparse'; unless $x { ++$y } CODE my $expected = 10; for 'AST', $ast, 'Str', $deparsed, 'Raku', EVAL($raku) -> $type, $it { is-deeply EVAL($it), $expected, "$type: unless block with a false condition evaluates to its body"; is $y, $expected, "$type: side-effect of the body was performed"; ++$expected; } } subtest 'simple unless with a false condition' => { my $x = True; my $y = 9; # unless $x { ++$y } ast RakuAST::Statement::Unless.new( condition => RakuAST::Var::Lexical.new('$x'), body => RakuAST::Block.new( body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::ApplyPrefix.new( prefix => RakuAST::Prefix.new('++'), operand => RakuAST::Var::Lexical.new('$y') ) ) ) ) ) ); is-deeply $deparsed, Q:to/CODE/, 'deparse'; unless $x { ++$y } CODE for 'AST', $ast, 'Str', $deparsed, 'Raku', EVAL($raku) -> $type, $it { is-deeply EVAL($it), Empty, "$type: unless block with a false condition evaluates to Empty"; is $y, 9, "$type: side-effect of the body was not performed"; } } subtest 'simple without with an undefined condition' => { my $x = Nil; my $y = 9; # without $x { $y++ } ast RakuAST::Statement::Without.new( condition => RakuAST::Var::Lexical.new('$x'), body => RakuAST::Block.new( body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::ApplyPostfix.new( postfix => RakuAST::Postfix.new(:operator<++>), operand => RakuAST::Var::Lexical.new('$y') ) ) ) ) ) ); is-deeply $deparsed, Q:to/CODE/, 'deparse'; without $x { $y++ } CODE my $expected = 9; for 'AST', $ast, 'Str', $deparsed, 'Raku', EVAL($raku) -> $type, $it { is-deeply EVAL($it), $expected, "$type: without block with an undefined object evaluates to its body"; is $y, ++$expected, "$type: Side-effect of the body was performed"; } } subtest 'simple without with a defined condition' => { my $x = True; my $y = 9; # without $x { ++$y } ast RakuAST::Statement::Without.new( condition => RakuAST::Var::Lexical.new('$x'), body => RakuAST::Block.new( body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::ApplyPrefix.new( prefix => RakuAST::Prefix.new('++'), operand => RakuAST::Var::Lexical.new('$y') ) ) ) ) ) ); is-deeply $deparsed, Q:to/CODE/, 'deparse'; without $x { ++$y } CODE for 'AST', $ast, 'Str', $deparsed, 'Raku', EVAL($raku) -> $type, $it { is-deeply EVAL($it), Empty, "$type: a without block with a defined object evaluates to Empty"; is $y, 9, "$type: side-effect of the body was not performed"; } } subtest 'simple without with an undefined condition' => { my $x = Cool; # without $x { $_ } ast RakuAST::Statement::Without.new( condition => RakuAST::Var::Lexical.new('$x'), body => RakuAST::Block.new(body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::Var::Lexical.new('$_') ) ) ) ) ); is-deeply $deparsed, Q:to/CODE/, 'deparse'; without $x { $_ } CODE for 'AST', EVAL($ast), 'Str', EVAL($deparsed), 'Raku', EVAL(EVAL $raku) -> $type, $result { is-deeply $result, Cool, "$type: without block sets the topic"; } } subtest 'While loop at statement level evaluates to Nil' => { my $x; # while $x { --$x } ast RakuAST::Statement::Loop::While.new( condition => RakuAST::Var::Lexical.new('$x'), body => RakuAST::Block.new( body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::ApplyPrefix.new( prefix => RakuAST::Prefix.new('--'), operand => RakuAST::Var::Lexical.new('$x') ) ) ) ) ) ); is-deeply $deparsed, Q:to/CODE/.chomp, 'deparse'; while $x { --$x } CODE for 'AST', $ast, 'Str', $deparsed, 'Raku', EVAL($raku) -> $type, $it { $x = 5; is-deeply EVAL($it), Nil, "$type: while loop at statement level evaluates to Nil"; is-deeply $x, 0, "$type: Loop variable was decremented to zero"; } } subtest 'Until loop at statement level evaluates to Nil' => { my $x; # until !$x { --$x } ast RakuAST::Statement::Loop::Until.new( condition => RakuAST::ApplyPrefix.new( prefix => RakuAST::Prefix.new('!'), operand => RakuAST::Var::Lexical.new('$x') ), body => RakuAST::Block.new( body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::ApplyPrefix.new( prefix => RakuAST::Prefix.new('--'), operand => RakuAST::Var::Lexical.new('$x') ) ) ) ) ) ); is-deeply $deparsed, Q:to/CODE/.chomp, 'deparse'; until !$x { --$x } CODE for 'AST', $ast, 'Str', $deparsed, 'Raku', EVAL($raku) -> $type, $it { $x = 5; is-deeply EVAL($it), Nil, "$type: until loop at statement level evaluates to Nil"; is-deeply $x, 0, "$type: Loop variable was decremented to zero"; } } subtest 'Repeat while loop at statement level evaluates to Nil' => { my $x; # repeat { --$x } while $x ast RakuAST::Statement::Loop::RepeatWhile.new( condition => RakuAST::Var::Lexical.new('$x'), body => RakuAST::Block.new( body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::ApplyPrefix.new( prefix => RakuAST::Prefix.new('--'), operand => RakuAST::Var::Lexical.new('$x') ) ) ) ) ) ); is-deeply $deparsed, Q:to/CODE/.chomp, 'deparse'; repeat { --$x } while $x CODE for 'AST', $ast, 'Str', $deparsed, 'Raku', EVAL($raku) -> $type, $it { $x = 5; is-deeply EVAL($it), Nil, "$type: repeat until loop at statement level evaluates to Nil"; is-deeply $x, 0, "$type: loop variable decremented to 0"; } } subtest 'Repeat until loop at statement level evaluates to Nil' => { my $x; # repeat { --$x } until $x ast RakuAST::Statement::Loop::RepeatUntil.new( condition => RakuAST::Var::Lexical.new('$x'), body => RakuAST::Block.new( body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::ApplyPrefix.new( prefix => RakuAST::Prefix.new('--'), operand => RakuAST::Var::Lexical.new('$x') ) ) ) ) ) ); is-deeply $deparsed, Q:to/CODE/.chomp, 'deparse'; repeat { --$x } until $x CODE for 'AST', $ast, 'Str', $deparsed, 'Raku', EVAL($raku) -> $type, $it { $x = 0; is-deeply EVAL($it), Nil, "$type: repeat until loop at statement level evaluates to Nil"; is-deeply $x, -1, "$type: loop ran once"; } } subtest 'Loop block with setup and increment expression' => { my $count; # loop (my $i = 9; $i; --$i) { ++$count } ast RakuAST::Statement::Loop.new( setup => RakuAST::VarDeclaration::Simple.new( sigil => '$', desigilname => RakuAST::Name.from-identifier('i'), initializer => RakuAST::Initializer::Assign.new( RakuAST::IntLiteral.new(9) ) ), condition => RakuAST::Var::Lexical.new('$i'), increment => RakuAST::ApplyPrefix.new( prefix => RakuAST::Prefix.new('--'), operand => RakuAST::Var::Lexical.new('$i') ), body => RakuAST::Block.new( body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::ApplyPrefix.new( prefix => RakuAST::Prefix.new('++'), operand => RakuAST::Var::Lexical.new('$count') ) ) ) ) ) ); is-deeply $deparsed, q:to/CODE/.chomp, 'deparse'; loop (my $i = 9; $i; --$i) { ++$count } CODE for 'AST', $ast, 'Str', $deparsed, 'Raku', EVAL($raku) -> $type, $it { $count = 0; is-deeply EVAL($it), Nil, "$type: loop with setup and increment evaluates to Nil"; is-deeply $count, 9, "$type: loop ran as expected"; } } subtest 'Statement level for loop' => { my $count; # for 2 .. 7 -> $x { ++$count } ast RakuAST::Statement::For.new( source => RakuAST::ApplyInfix.new( left => RakuAST::IntLiteral.new(2), infix => RakuAST::Infix.new('..'), right => RakuAST::IntLiteral.new(7) ), body => RakuAST::PointyBlock.new( signature => RakuAST::Signature.new( parameters => ( RakuAST::Parameter.new( target => RakuAST::ParameterTarget::Var.new('$x') ), ) ), body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::ApplyPrefix.new( prefix => RakuAST::Prefix.new('++'), operand => RakuAST::Var::Lexical.new('$count') ) ) ) ) ) ); is-deeply $deparsed, q:to/CODE/.chomp, 'deparse'; for 2 .. 7 -> $x { ++$count } CODE for 'AST', $ast, 'Str', $deparsed, 'Raku', EVAL($raku) -> $type, $it { $count = 0; is-deeply EVAL($it), Nil, "$type: for loop evaluates to Nil"; is-deeply $count, 6, "$type: loop ran with expected number of times"; } } subtest 'for loop with explicit iteration variable' => { my $total; # for 2 .. 7 -> $x { $total = $total + $x } ast RakuAST::Statement::For.new( source => RakuAST::ApplyInfix.new( left => RakuAST::IntLiteral.new(2), infix => RakuAST::Infix.new('..'), right => RakuAST::IntLiteral.new(7) ), body => RakuAST::PointyBlock.new( signature => RakuAST::Signature.new( parameters => ( RakuAST::Parameter.new( target => RakuAST::ParameterTarget::Var.new('$x') ), ) ), body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::ApplyInfix.new( left => RakuAST::Var::Lexical.new('$total'), infix => RakuAST::Infix.new('='), right => RakuAST::ApplyInfix.new( left => RakuAST::Var::Lexical.new('$total'), infix => RakuAST::Infix.new('+'), right => RakuAST::Var::Lexical.new('$x') ) ) ) ) ) ) ); is-deeply $deparsed, q:to/CODE/.chomp, 'deparse'; for 2 .. 7 -> $x { $total = $total + $x } CODE my $sum = (2..7).sum; for 'AST', $ast, 'Str', $deparsed, 'Raku', EVAL($raku) -> $type, $it { $total = 0; is-deeply EVAL($it), Nil, "$type: result value of for"; is-deeply $total, $sum, "$type: correct value in iteration variable"; } } subtest 'Statement level for loop with implicit topic' => { my $total = 0; # for 2 .. 7 { $total = $total + $_ } ast RakuAST::Statement::For.new( source => RakuAST::ApplyInfix.new( left => RakuAST::IntLiteral.new(2), infix => RakuAST::Infix.new('..'), right => RakuAST::IntLiteral.new(7) ), body => RakuAST::Block.new( body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::ApplyInfix.new( left => RakuAST::Var::Lexical.new('$total'), infix => RakuAST::Infix.new('='), right => RakuAST::ApplyInfix.new( left => RakuAST::Var::Lexical.new('$total'), infix => RakuAST::Infix.new('+'), right => RakuAST::Var::Lexical.new('$_') ) ) ) ) ) ) ); is-deeply $deparsed, q:to/CODE/.chomp, 'deparse'; for 2 .. 7 { $total = $total + $_ } CODE my $sum = (2..7).sum; for 'AST', $ast, 'Str', $deparsed, 'Raku', EVAL($raku) -> $type, $it { $total = 0; is-deeply EVAL($it), Nil, "$type: result value of for"; is-deeply $total, $sum, "$type: correct value in implicit topic"; } } subtest 'given with explicit signature' => { # given $a -> $x { $x } ast RakuAST::Statement::Given.new( source => RakuAST::Var::Lexical.new('$a'), body => RakuAST::PointyBlock.new( signature => RakuAST::Signature.new( parameters => ( RakuAST::Parameter.new( target => RakuAST::ParameterTarget::Var.new('$x') ), ) ), body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::Var::Lexical.new('$x') ) ) ) ) ); is-deeply $deparsed, q:to/CODE/.chomp, 'deparse'; given $a -> $x { $x } CODE for 'AST', $ast, 'Str', $deparsed, 'Raku', EVAL($raku) -> $type, $it { my $a = 'concrete'; is-deeply EVAL($it), 'concrete', "$type: given topicalizes on the source (signature)"; $a = Str; is-deeply EVAL($it), Str, "$type: given topicalizes even an undefined source (signature)"; } } subtest 'given with implicit signature' => { # given $a { $_ } ast RakuAST::Statement::Given.new( source => RakuAST::Var::Lexical.new('$a'), body => RakuAST::Block.new( body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::Var::Lexical.new('$_') ) ) ) ) ); is-deeply $deparsed, q:to/CODE/.chomp, 'deparse'; given $a { $_ } CODE for 'AST', $ast, 'Str', $deparsed, 'Raku', EVAL($raku) -> $type, $it { my $a = 'concrete'; is-deeply EVAL($it), 'concrete', "$type: given topicalizes on the source (implicit)"; $a = Str; is-deeply EVAL($it), Str, "$type: given topicalizes even an undefined source (implicit)"; } } subtest 'given with when and default' => { # given $a { when 2 { "two" } when 3 { "three" } default { "another" } } ast RakuAST::Statement::Given.new( source => RakuAST::Var::Lexical.new('$a'), body => RakuAST::Block.new( body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::When.new( condition => RakuAST::IntLiteral.new(2), body => RakuAST::Block.new( body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::StrLiteral.new('two') ) ) ) ) ), RakuAST::Statement::When.new( condition => RakuAST::IntLiteral.new(3), body => RakuAST::Block.new( body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::StrLiteral.new('three') ) ) ) ) ), RakuAST::Statement::Default.new( body => RakuAST::Block.new( body => RakuAST::Blockoid.new( RakuAST::StatementList.new( RakuAST::Statement::Expression.new( expression => RakuAST::StrLiteral.new('another') ) ) ) ) ) ) ) ) ); is-deeply $deparsed, Q:to/CODE/.chomp, 'deparse'; given $a { when 2 { "two" } when 3 { "three" } default { "another" } } CODE for 'AST', $ast, 'Str', $deparsed, 'Raku', EVAL($raku) -> $type, $it { my $a = 2; is-deeply EVAL($type eq 'AST' ?? $ast !! $deparsed), 'two', "$type: first when statement matching gives correct result"; $a = 3; is-deeply EVAL($it), 'three', "$type: second when statement matching gives correct result"; $a = 4; is-deeply EVAL($it), 'another', "$type: no when statement giving default"; } } # This test calls an imported `&ok` to check the `use` works; the test plan # verifies that it really works. { sub ok(|) { die "Imported ok was not used" }; # use Test; ok 1, "use statement works" ast RakuAST::StatementList.new( RakuAST::Statement::Use.new( module-name => RakuAST::Name.from-identifier('Test') ), RakuAST::Statement::Expression.new( expression => RakuAST::Call::Name.new( name => RakuAST::Name.from-identifier('ok'), args => RakuAST::ArgList.new( RakuAST::IntLiteral.new(1), RakuAST::StrLiteral.new('use statements work') ) ) ) ); is-deeply $deparsed, Q:to/CODE/, 'deparse'; use Test; ok(1, "use statements work") CODE # EVALling produces test output EVAL($_) for $ast, $deparsed, EVAL($raku); } subtest "check parsing of 'use' pragma" => { # Apparently EVALling an AST does **NOT** set $*LANG yet, # so we fake one here for now my $*LANG = class { method set_pragma($,$) { } } # use MONKEY; nqp::const::STAT_ISDIR ast RakuAST::StatementList.new( RakuAST::Pragma.new(:name), RakuAST::Statement::Expression.new( expression => RakuAST::Nqp::Const.new("STAT_ISDIR") ) ); is-deeply $deparsed, Q:to/CODE/, 'deparse'; use MONKEY; nqp::const::STAT_ISDIR CODE is-deeply EVAL($_), 2, @type[$++] for $ast, $deparsed, EVAL($raku); } subtest "check parsing of 'no' pragma" => { # Apparently EVALling an AST does **NOT** set $*LANG yet, # so we fake one here for now my $*LANG = class { method set_pragma($,$) { } } # no trace; 42 ast RakuAST::StatementList.new( RakuAST::Pragma.new(:name, :off), RakuAST::Statement::Expression.new( expression => RakuAST::IntLiteral.new(42) ) ); is-deeply $deparsed, Q:to/CODE/, 'deparse'; no trace; 42 CODE is-deeply EVAL($_), 42, @type[$++] for $ast, $deparsed, EVAL($raku); } subtest "check parsing of 'need' pragma" => { # need Test ast RakuAST::StatementList.new( RakuAST::Statement::Need.new( module-names => ( RakuAST::Name.from-identifier("Test"), ) ), RakuAST::Statement::Import.new( module-name => RakuAST::Name.from-identifier("Test") ), RakuAST::Statement::Expression.new( expression => RakuAST::Call::Name.new( name => RakuAST::Name.from-identifier("ok"), args => RakuAST::ArgList.new( RakuAST::Var::Lexical.new("\$type") ) ) ) ); plan 7; # must run this number of tests is-deeply $deparsed, Q:to/CODE/, 'deparse'; need Test; import Test; ok($type) CODE for 'AST', $ast, 'Str', $deparsed, 'Raku', EVAL($raku) -> $type, $it { is-deeply EVAL($it), True, "$type: did eval work"; } } # vim: expandtab shiftwidth=4