# New Ticket Created by Stephane Payrard
# Please include the string: [perl #51658]
# in the subject line of all future correspondence about this issue.
# <URL: http://rt.perl.org/rt3/Ticket/Display.html?id=51658 >
# use v6-alpha;
# use Test;
# plan 3;
# test for lexical self.
# and for some pair parsing and printing.
# should print :
# hi
# :a
# :!a
# :a(1)
# :a<1>
# :a(" > ")
class A { method h { "hi" }; method g { if (1) { self.h(); } } };
my $o = A.new;
# ok 'hi' eq $o.g()
say $o.h;
## See S02 for pair semantic
# note the test are dependant on the choice of the perl representation.
say :a.value; # Method 'perl' not found for invocant of class 'Boolean'
# should print True or Bool::True
say :a.perl;
# ok :a.perl eq ':a'
say :!a.perl;
# ok :!a.perl eq ':!a'
# not that the printing representation does not yet parse
# for the next two examples.
my $a = 1 ;
say :$a.perl;
# ok :$a.perl eq ':a(1)'
my $a = "1";
say :$a.perl;
# ok :$a.perl eq ':a<1>'
my $a = " > ";
say :$a.perl;
# ok :$a.perl eq ':a<1>'
# TBD; parse, but does not yet print
# my @a; @a[0]=1;
# say :@a.perl;
-----------------------
affected files :
languages/perl6/src/parser/actions.pm
languages/perl6/src/parser/grammar.pg
languages/perl6/src/classes/Pair.pir
Index: languages/perl6/src/parser/actions.pm
===================================================================
--- languages/perl6/src/parser/actions.pm (revision 26310)
+++ languages/perl6/src/parser/actions.pm (working copy)
@@ -30,10 +30,12 @@
our $?BLOCK;
our @?BLOCK;
our $?BLOCK_SIGNATURED;
+ our $?IS_METHOD;
+ our $?IN_METHOD;
## when entering a block, use any $?BLOCK_SIGNATURED if it exists,
## otherwise create an empty block with an empty first child to
## hold any parameters we might encounter inside the block.
- if ($key eq 'open') {
+ if $key eq 'open' {
if $?BLOCK_SIGNATURED {
$?BLOCK := $?BLOCK_SIGNATURED;
$?BLOCK_SIGNATURED := 0;
@@ -62,8 +64,18 @@
unless $?BLOCK.symbol('$!') {
$init.push( PAST::Var.new( :name('$!'), :isdecl(1) ) );
$?BLOCK.symbol( '$!', :scope('lexical') ); }
+ if $?IS_METHOD {
+ $init.push(PAST::Var.new(
+ :name('self'),
+ :isdecl(1)
+ ));
+ $?BLOCK.symbol('self', :scope('lexical'));
+ $?IS_METHOD := 0;
+ $init.push( PAST::Op.new( :inline( " store_lex 'self', self")));
+ }
+
}
- if ($key eq 'close') {
+ if $key eq 'close' {
my $past := @?BLOCK.shift();
$?BLOCK := @?BLOCK[0];
$past.push($($<statementlist>));
@@ -122,12 +134,12 @@
:pasttype('if'),
:node( $/ )
);
- if ( $<else> ) {
+ if $<else> {
my $else := $( $<else>[0] );
$else.blocktype('immediate');
$past.push( $else );
}
- while ($count != 0) {
+ while $count != 0 {
$count := $count - 1;
$expr := $( $<EXPR>[$count] );
$then := $( $<block>[$count] );
@@ -294,12 +306,12 @@
method statement_prefix($/) {
my $past := $($<statement>);
my $sym := ~$<sym>;
- if ($sym eq 'do') {
+ if $sym eq 'do' {
# fall through, just use the statement itself
}
## after the code in the try block is executed, bind $! to Undef,
## and set up the code to catch an exception, in case one is thrown
- elsif ($sym eq 'try') {
+ elsif $sym eq 'try' {
## Set up code to execute <statement> as a try node, and
## set $! to Undef if successful.
my $exitpir := " new %r, 'Undef'\n store_lex '$!', %r";
@@ -319,62 +331,58 @@
}
-method plurality_declarator($/) {
- my $past := $( $<routine_declarator> );
- if $<sym> eq 'multi' {
- my $pirflags := ~ $past.pirflags();
- my $arity := $past.arity();
- if $arity == 0 { $pirflags := $pirflags ~ ' :multi()'; }
- elsif $arity == 1 { $pirflags := $pirflags ~ ' :multi(_)'; }
- else {
- $pirflags := $pirflags ~ ' :multi(_';
- my $count := 1;
- while $count != $arity {
- $pirflags := $pirflags ~ ',_';
- $count := $count + 1;
+method routine($/, $key) {
+ our $?IS_METHOD;
+ our $?IN_METHOD;
+ if $key eq 'decls' {
+ $?IS_METHOD := 0;
+ $?IN_METHOD := 0;
+ if (~$<meth> eq 'method') {
+ $?IS_METHOD := 1; # reset in inner blocks
+ $?IN_METHOD := 1; # not reset in inner blocks
+ }
+ } else {
+ my $past := $($<routine_def>);
+ if $<decl> eq 'multi' {
+ my $pirflags := ~ $past.pirflags();
+ my $arity := $past.arity();
+ if $arity == 0 { $pirflags := $pirflags ~ ' :multi()'; }
+ elsif $arity == 1 { $pirflags := $pirflags ~ ' :multi(_)'; }
+ else {
+ $pirflags := $pirflags ~ ' :multi(_';
+ my $count := 1;
+ while $count != $arity {
+ $pirflags := $pirflags ~ ',_';
+ $count := $count + 1;
+ }
+ $pirflags := $pirflags ~ ')';
}
- $pirflags := $pirflags ~ ')';
+ $past.pirflags($pirflags);
}
- $past.pirflags($pirflags);
- }
- make $past;
-}
-
-method routine_declarator($/, $key) {
- if $key eq 'sub' {
- my $past := $($<routine_def>);
$past.blocktype('declaration');
+ if $?IN_METHOD {
+ $past.pirflags(':method');
+ }
$past.node($/);
make $past;
+
}
- elsif $key eq 'method' {
- my $past := $($<method_def>);
- $past.blocktype('declaration');
- $past.pirflags(':method');
- $past.node($/);
- make $past;
- }
}
-
method routine_def($/) {
+ our $?IS_METHOD;
my $past := $( $<block> );
if $<ident> {
$past.name( ~$<ident>[0] );
- our $?BLOCK;
- $?BLOCK.symbol(~$<ident>[0], :scope('package'));
+ if $?IS_METHOD {
+ our $?BLOCK;
+ $?BLOCK.symbol(~$<ident>[0], :scope('package'));
+ }
}
make $past;
}
-method method_def($/) {
- my $past := $( $<block> );
- if $<ident> {
- $past.name( ~$<ident>[0] );
- }
- make $past;
-}
method signature($/) {
my $params := PAST::Stmts.new( :node($/) );
@@ -468,7 +476,7 @@
method methodop($/, $key) {
my $past;
- if ($key eq 'null') {
+ if $key eq 'null' {
$past := PAST::Op.new();
}
else {
@@ -535,8 +543,12 @@
method noun($/, $key) {
my $past;
+ our $?IN_METHOD;
if $key eq 'self' {
- $past := PAST::Stmts.new( PAST::Op.new( :inline('%r = self'),
:node( $/ ) ) );
+ unless $?IN_METHOD {
+ $/.panic("can't use 'self' outside a method");
+ }
+ $past := PAST::Stmts.new( PAST::Op.new( :inline(" %r =
find_lex 'self'"), :node( $/ ) ) );
}
elsif $key eq 'undef' {
$past := PAST::Op.new(
@@ -781,6 +793,9 @@
method scoped($/) {
+ if $<typename> {
+ $/.panic('statically typed variables are not yet implemented');
+ }
my $past := $( $<variable_decl> );
make $past;
}
@@ -966,13 +981,13 @@
method circumfix($/, $key) {
my $past;
- if ($key eq '( )') {
+ if $key eq '( )' {
$past := $( $<statementlist> );
}
- if ($key eq '[ ]') {
+ if $key eq '[ ]' {
$past := $( $<statementlist> );
}
- elsif ($key eq '{ }') {
+ elsif $key eq '{ }' {
$past := $( $<pblock> );
}
make $past;
@@ -1048,15 +1063,15 @@
method quote_expression($/, $key) {
my $past;
- if ($key eq 'quote_regex') {
+ if $key eq 'quote_regex' {
$past := PAST::Block.new( $<quote_regex>,
:compiler('PGE::Perl6Regex'),
:blocktype('declaration'),
:node( $/ )
)
}
- elsif ($key eq 'quote_concat') {
- if ( +$<quote_concat> == 1 ) {
+ elsif $key eq 'quote_concat' {
+ if +$<quote_concat> == 1 {
$past := $( $<quote_concat>[0] );
}
else {
@@ -1090,10 +1105,10 @@
method quote_term($/, $key) {
my $past;
- if ($key eq 'literal') {
+ if $key eq 'literal' {
$past := PAST::Val.new( :value( ~$<quote_literal> ),
:returns('Perl6Str'), :node($/) );
}
- if ($key eq 'variable') {
+ if $key eq 'variable' {
$past := $( $<variable> );
}
make $past;
@@ -1127,9 +1142,9 @@
method semilist($/) {
my $past := PAST::Op.new( :node($/) );
- if ($<EXPR>) {
+ if $<EXPR> {
my $expr := $($<EXPR>[0]);
- if ($expr.name() eq 'infix:,') {
+ if $expr.name() eq 'infix:,' {
for @($expr) {
$past.push( $_ );
}
@@ -1144,10 +1159,10 @@
method listop($/, $key) {
my $past;
- if ($key eq 'arglist') {
+ if $key eq 'arglist' {
$past := $( $<arglist> );
}
- if ($key eq 'noarg') {
+ if $key eq 'noarg' {
$past := PAST::Op.new( );
}
$past.name( ~$<sym> );
@@ -1160,7 +1175,7 @@
method arglist($/) {
my $past := PAST::Op.new( :node($/) );
my $expr := $($<EXPR>);
- if ($expr.name() eq 'infix:,') {
+ if $expr.name() eq 'infix:,' {
for @($expr) {
$past.push( $_ );
}
@@ -1173,7 +1188,7 @@
method EXPR($/, $key) {
- if ($key eq 'end') {
+ if $key eq 'end' {
make $($<expr>);
}
else {
@@ -1239,13 +1254,12 @@
make $past;
}
-
method colonpair($/, $key) {
my $pair_key;
my $pair_val;
if $key eq 'false' {
- my $pair_key := PAST::Val.new( :value(~$<key>) );
+ $pair_key := PAST::Val.new( :value(~$<ident>) );
$pair_val := PAST::Var.new(
:name('False'),
:namespace('Bool'),
@@ -1253,10 +1267,9 @@
);
}
elsif $key eq 'value' {
- my $pair_key := PAST::Val.new( :value(~$<key>) );
+ $pair_key := PAST::Val.new( :value(~$<ident>) );
if $<postcircumfix> {
- # XXX TODO
- $/.panic('postcircumfix on colonpair not yet implemented');
+ $pair_val := PAST::Val.new( :value($<postcircumfix>))
}
else {
$pair_val := PAST::Var.new(
@@ -1266,7 +1279,12 @@
);
}
}
- else {
+ elsif $key eq 'varname' {
+ my $nm := $<variable><name>;
+ my $idx := $<variable><matchidx>;
+ $pair_key := PAST::Val.new( :value( ~$nm || ~$idx) );
+ $pair_val := $( $<variable> );
+ } else {
$/.panic($key ~ " pairs not yet implemented.");
}
Index: languages/perl6/src/parser/grammar.pg
===================================================================
--- languages/perl6/src/parser/grammar.pg (revision 26310)
+++ languages/perl6/src/parser/grammar.pg (working copy)
@@ -299,15 +299,11 @@
#### Subroutine and method definitions ####
-rule plurality_declarator {
- $<sym>=[multi|proto|only] <routine_declarator> {*}
+rule routine {
+ $<decl>=[multi|proto|only|''] $<meth>=[sub|method] {*} #= decls
+ <routine_def> {*} #= def
}
-token routine_declarator {
- | $<sym>='sub' <routine_def> {*} #= sub
- | $<sym>='method' <method_def> {*} #= method
-}
-
rule routine_def {
<ident>? <multisig>?
<trait>*
@@ -315,13 +311,6 @@
{*}
}
-rule method_def {
- <ident>? <multisig>?
- <trait>*
- <block>
- {*}
-}
-
rule trait {
| <trait_auxiliary>
| <trait_verb>
@@ -431,8 +420,7 @@
token noun {
| <package_declarator> {*} #= package_declarator
| <scope_declarator> {*} #= scope_declarator
- | <plurality_declarator> {*} #= plurality_declarator
- | <routine_declarator> {*} #= routine_declarator
+ | <routine> {*} #= routine
| <circumfix> {*} #= circumfix
| <variable> {*} #= variable
| <subcall> {*} #= subcall
@@ -479,7 +467,7 @@
rule scoped {
- <variable_decl> {*}
+ <typename>? <variable_decl> {*}
}
rule scope_declarator {
@@ -657,10 +645,10 @@
token colonpair {
':'
[
- | '!' <ident> {*} #= false
+ || '!' <ident> {*} #= false
| <ident> [ <.unsp>? <postcircumfix> ]? {*} #= value
| <postcircumfix> {*} #= structural
- | <sigil> <twigil>? <desigilname> {*} #= varname
+ | <variable> {*} #= varname
]
}
Index: languages/perl6/src/classes/Pair.pir
===================================================================
--- languages/perl6/src/classes/Pair.pir (revision 26310)
+++ languages/perl6/src/classes/Pair.pir (working copy)
@@ -17,6 +17,84 @@
$P1('Pair', 'Pair')
.end
+
+.sub get_string :method
+ $S0 = self.'perl'()
+ return ( $S0 )
+.end
+
+# should be pedagogical and gives the smartest representation of a pair
+.sub perl :method
+ $P0 = self.'key'()
+ $P1 = self.'value'()
+ $S0 = $P0.'WHAT'()
+ $S1 = $P1.'WHAT'()
+ if $S0 != 'Str' goto keyisnotstring
+ $S2 = $P0
+ $S3 = escape $S2
+ if $S3 != $S2 goto keyescaped
+ if $S1 != 'Bool' goto valnobool
+ $S5 = ":"
+ if $P1 goto trueval
+ concat $S5, "!"
+trueval:
+ concat $S5, $S2
+ .return ($S5)
+valnobool:
+ if $S1 == 'Str' goto valliteral
+ if $S1 == 'Int' goto valnum
+ if $S1 == 'Num' goto valnum
+ die "TBD"
+
+valliteral:
+ $S1 = $P1
+ $I0 = index $S1, '>'
+ if $I0 != -1 goto esc_val_litteral
+ $I0 = index $S1, '<'
+ if $I0 != -1 goto esc_val_litteral
+ $S6 = ":"
+ $S7 = $P0
+ concat $S6, $S7
+ concat $S6, '<'
+ $S7 = $P1
+ concat $S6, $S7
+ concat $S6, '>'
+ .return ( $S6 )
+
+esc_val_litteral:
+ $S1 = escape $S1
+ $S1 = concat '"', $S1
+ $S1 = concat $S1, '"'
+ $P1 = $S1 # fall-thru
+valnum:
+ $S6 = ":"
+ $S7 = $P0
+ concat $S6, $S7
+ concat $S6, '('
+ $S7 = $P1
+ concat $S6, $S7
+ concat $S6, ')'
+ .return ( $S6 )
+
+
+keyescaped:
+ die "TBD"
+
+keyisnotstring:
+ # ugly, probably not correct, certainly not yet supported
+ $S2 = "{ (my $p=Pair.new()), "
+ concat $S2, "$p[ "
+ $S3 = $P0.perl()
+ concat $S2, $S3
+ concat $S2, "] = "
+ $S3 = $P1.perl()
+ concat $S2, $S3
+ concat $S3, "}"
+keyissnottring:
+ die "TBD"
+.end
+
+
=back
=cut
bash-3.2$