diff --git a/doc/LOLHALP b/doc/LOLHALP index d9ae9d2..4d4d3af 100644 --- a/doc/LOLHALP +++ b/doc/LOLHALP @@ -1,7 +1,6 @@ The below things should be fairly straightforward to implement. Just look in the commit logs at how similar features were implemented. -* 'until' keywords. * 'loop' keyword. (at least the infinitely looping version is easy.) * 'repeat' keyword. * 'ENTER', 'LEAVE', 'FIRST', 'NEXT', and 'LAST' phasers. diff --git a/lib/Yapsi.pm b/lib/Yapsi.pm index 3de270f..8286b52 100644 --- a/lib/Yapsi.pm +++ b/lib/Yapsi.pm @@ -17,11 +17,11 @@ grammar Yapsi::Perl6::Grammar { || || || || || } token statement_control { - || + || || } rule statement_control_if { 'if' [ 'else' ]? } - rule statement_control_while { 'while' } + rule statement_control_while_until { $=[ 'while' | 'until' ] } rule statement_control_unless { 'unless' } token lvalue { || || } token value { || || || @@ -120,7 +120,7 @@ class Yapsi::Compiler { my $*c = 0; # unique register counter my $*l = 0; # unique label counter my @skip = 'block', 'statement_control_if', - 'statement_control_while', 'statement_control_unless'; + 'statement_control_while_until', 'statement_control_unless'; my &sicify = -> $/, $key { if $m !=== $/ && $key eq 'block' { my $register = self.unique-register; @@ -176,7 +176,7 @@ class Yapsi::Compiler { "call $register"; push @blocksic, "`label $after-unless"; } - elsif $key eq 'statement_control_while' { + elsif $key eq 'statement_control_while_until' { my $before-while = self.unique-label; my $after-while = self.unique-label; push @blocksic, "`label $before-while"; @@ -187,7 +187,14 @@ class Yapsi::Compiler { :action(&sicify) ); my ($register, $) = $.ast.list; - push @blocksic, "jf $register, $after-while"; + given $ { + when / while / { + push @blocksic, "jf $register, $after-while"; + } + when / until / { + push @blocksic, "jt $register, $after-while"; + } + } my $block-name = $.ast; $register = self.unique-register; push @blocksic, diff --git a/t/compiler.t b/t/compiler.t index c104ed0..11f4654 100644 --- a/t/compiler.t +++ b/t/compiler.t @@ -31,6 +31,9 @@ my @programs-that-compile = 'my $a; if $a {}', 'if my $a {} else { say 42 }', 'my $a; while $a { say $a }', + 'unless 0 { say 42 }', + 'my $a=0; unless $a { say $a }', + 'my $a=0; until $a { say 42; ++$a; }', ; sub escape($string) { $string.subst("\n", "\\n", :g) } @@ -61,8 +64,8 @@ my @programs-that-don't-compile = # ' 'if $a {}', 'if 42 { $a }', 'if 5 {} else { $a }', - 'unless 0 { say "unless" }', - 'unless $a { say $a }' + 'unless {} ', + 'unless a {} ', ; for @programs-that-don't-compile -> $program { # ' diff --git a/t/runtime.t b/t/runtime.t index 4b14e5b..2b53155 100644 --- a/t/runtime.t +++ b/t/runtime.t @@ -36,6 +36,8 @@ my @tests = 'my $a; while $a { say 42 }', "", 'non-executing while loop', 'my $a = 42;unless $a { say 24 }', "", 'non-executing unless block', 'unless 0 { say 42 }', "42\n", 'executing unless block', + 'my $a=0; until $a { say 42; ++$a; }',"42\n", 'executing until loop structure', + 'until 42 { say 24; }' , "", 'non-executing until loop structure', # TODO -- Need to "instantiate" lexpads from some kind of "proto-lexpads" # 'my $a = 3; while --$a { say my $b; $b = 42 }', "Any()\nAny()\n", # 'each time a block is entered, it gets a fresh lexical pad',