use v6-alpha; grammar KindaPerl6::Grammar { use KindaPerl6::Grammar::Regex; use KindaPerl6::Grammar::Mapping; use KindaPerl6::Grammar::Control; use KindaPerl6::Grammar::Parameters; use KindaPerl6::Grammar::Term; use KindaPerl6::Grammar::Statements; use KindaPerl6::Grammar::Quote; use KindaPerl6::Grammar::Sub; use KindaPerl6::Grammar::Token; my $Class_name; # for diagnostic messages sub get_class_name { $Class_name }; token ident_digit { [ [ | _ | ] | <''> ] }; token ident { | [ | _ ] [ ':<' '>' | '' ] | ยข }; token full_ident { [ <'::'> | <''> ] }; token namespace { | '::' [ | { return [ $$, @( $$ ) ] } | { return [ $$ ] } ] | { return [ ] } }; token to_line_end { | \N | <''> }; token pod_begin { | \n <'=end'> | . }; token pod_other { | \n <'=cut'> | . }; token ws { [ | <'#'> | \n [ | <'=begin'> | <'=kwid'> | <'=pod'> | <'=for'> | <'=head1'> | <''> ] | \s ] [ | <''> ] }; token opt_ws { | <''> }; token opt_ws2 { | <''> }; token opt_ws3 { | <''> }; token parse { | [ | { return [ $$, @( $$ ) ] } | { return [ $$ ] } ] | { return [] } }; token unit_type { <'class'> | <'grammar'> | <'role'> | <'module'> }; token trait_auxiliary { is | does | meta }; token class_trait { { return [ $$, $$ ] } }; token class_traits { | [ | { return [ $$, @( $$ ) ] } | { return [ $$ ] } ] | { return [] } }; token comp_unit { [\; | <''> ] [ <'use'> <'v6-'> \; | <''> ] [ <'{'> { $Class_name := ~$ } { COMPILER::add_pad( $Class_name ); } <'}'> [\; | <''> ] { my $env := @COMPILER::PAD[0]; COMPILER::drop_pad(); return ::CompUnit( 'unit_type' => $$, 'name' => $$, 'traits' => $$, 'attributes' => { }, 'methods' => { }, 'body' => ::Lit::Code( pad => $env, state => { }, sig => ::Sig( 'invocant' => undef, 'positional' => [ ], 'named' => { } ), body => $$, ), ) } ] | [ { $Class_name := 'Main'; COMPILER::add_pad( $Class_name ); } { my $env := @COMPILER::PAD[0]; COMPILER::drop_pad(); return ::CompUnit( 'unit_type' => 'module', 'name' => 'Main', 'traits' => [], 'attributes' => { }, 'methods' => { }, 'body' => ::Lit::Code( pad => $env, state => { }, sig => ::Sig( 'invocant' => undef, 'positional' => [ ], 'named' => { } ), body => $$, ), ) } ] }; token infix_op { <'+'> | <'-'> | <'*'> | <'/'> | eq | ne | <'=='> | <'!='> | <'&&'> | <'||'> | <'~~'> | <'~'> | '<=>' | '<=' | '>=' | '<' | '>' | '&' | '^' | '|' | '..' }; token hyper_op { <'>>'> | <''> }; token prefix_op { [ '$' | '@' | '%' | '?' | '!' | '++' | '--' | '+' | '-' | '~' | '|' ] }; token declarator { <'my'> | <'state'> | <'has'> | <'our'> }; token opt_declarator { {return $$;} | {return '';} }; token exp2 { { return $$ } }; token exp { # { say 'exp: going to match at ', $/.to; } [ <'??'> [ <'!!'> { # XXX TODO - expand macro # is &ternary: a macro? my $macro_ast := ::Var( 'sigil' => '&', 'twigil' => '', 'name' => 'ternary:', namespace => [ ] ); my $macro := COMPILER::get_var( $macro_ast ); if defined($macro) { # fetch the macro my $sub := ( @COMPILER::PAD[0] ).eval_ast( $macro_ast ); Main::expand_macro( $sub, $$, $$, $$ ); # say "# ternary macro = ", $sub.perl; } return ::Apply( 'code' => ::Var( 'sigil' => '&', 'twigil' => '', 'name' => 'ternary:', namespace => [ ] ), 'arguments' => [ $$, $$, $$ ], ); } | { say '*** Syntax error in ternary operation' } ] | { return ::Apply( 'code' => ::Var( 'sigil' => '&', 'twigil' => '', 'name' => 'infix:<' ~ $ ~ '>', namespace => [ ] ), 'arguments' => [ $$, $$ ], ) } | <'::='> { my $bind := ::Bind( 'parameters' => $$, 'arguments' => $$); COMPILER::begin_block( $bind ); # ::= compile-time return $bind; # := run-time } | <':='> { return ::Bind( 'parameters' => $$, 'arguments' => $$) } | <'='> { return ::Assign( 'parameters' => $$, 'arguments' => $$) } | { return $$ } ] }; token opt_ident { | { return $$ } | <''> { return 'postcircumfix:<( )>' } }; token term_meth { [ \. [ \( \) # { say 'found parameter list: ', $.perl } | \: | { return ::Call( 'invocant' => ::Proto( 'name' => ~$ ), 'method' => $$, 'arguments' => undef, 'hyper' => $$, ) } ] { return ::Call( 'invocant' => ::Proto( 'name' => ~$ ), 'method' => $$, 'arguments' => $$, 'hyper' => $$, ) } ] | [ \. # $obj.(42) [ \( # { say 'testing exp_parameter_list at ', $/.to } \) # { say 'found parameter list: ', $.perl } | \: | { return ::Call( 'invocant' => $$, 'method' => $$, 'arguments' => undef, 'hyper' => $$, ) } ] { return ::Call( 'invocant' => $$, 'method' => $$, 'arguments' => $$, 'hyper' => $$, ) } | \[ \] { return ::Index( 'obj' => $$, 'index' => $$ ) } # $a[exp] | \{ \} { return ::Lookup( 'obj' => $$, 'index' => $$ ) } # $a{exp} | \< \> { return ::Lookup( 'obj' => $$, 'index' => ::Val::Buf( 'buf' => ~$ ), ) } # $a | { return $$ } ] }; token sub_or_method_name { [ \. | <''> ] }; token opt_type { | [ <'::'> | <''> ] { return $$ } | <''> { return '' } }; token use_from_perl5 { ':from' {return 1} | {return 0} } #token index { XXX } #token lookup { XXX } token sigil { \$ |\% |\@ |\& }; token twigil { [ \. | \! | \^ | \* ] | <''> }; # XXX unused? # token var_name { | <'/'> | }; # used in Term.pm token undeclared_var { { # no pre-declaration checks return ::Var( sigil => ~$, twigil => ~$, name => ~$, namespace => $$, ) } }; token var { '/' { return ::Var( sigil => ~$, twigil => '', name => '/', namespace => [ ], ) } | { # check for pre-declaration return COMPILER::get_var( ::Var( sigil => ~$, twigil => ~$, name => ~$, namespace => $$, ) ) } }; token val { | { return $$ } # undef # | $ := # (not exposed to the outside) | { return $$ } # 123 | { return $$ } # True, False | { return $$ } # 123.456 | { return $$ } # 'moose' }; token val_bit { | True { return ::Val::Bit( 'bit' => 1 ) } | False { return ::Val::Bit( 'bit' => 0 ) } }; token val_undef { undef { return ::Val::Undef( ) } }; token val_num { XXX { return 'TODO: val_num' } }; token digits { \d [ | <''> ] }; token val_int { { return ::Val::Int( 'int' => ~$/ ) } }; # XXX obsolete? token exp_seq { | # { say 'exp_seq: matched ' } [ | \, [ \, | <''> ] { return [ $$, @( $$ ) ] } | [ \, | <''> ] { return [ $$ ] } ] | # { say 'exp_seq: end of match' } { return [] } }; token lit { #| { return $$ } # (a, b, c) #| { return $$ } # [a, b, c] #| { return $$ } # {a => x, b => y} #| { return $$ } # sub $x {...} | { return $$ } # ::Tree(a => x, b => y); }; token lit_seq { XXX { return 'TODO: lit_seq' } }; token lit_array { XXX { return 'TODO: lit_array' } }; token lit_hash { XXX { return 'TODO: lit_hash' } }; token lit_code { XXX { return 'TODO - Lit::Code' } }; token lit_object { <'::'> \( [ \) { # say 'Parsing Lit::Object ', $$, ($$).perl; return ::Lit::Object( 'class' => $$, 'fields' => $$ ) } | { say '*** Syntax Error parsing Constructor ',$$; die() } ] }; #token bind { # <':='> # { # return ::Bind( # 'parameters' => $$, # 'arguments' => $$, # ) # } #}; token call { \. \( \) { return ::Call( 'invocant' => $$, 'method' => $$, 'arguments' => $$, ) } }; token apply { [ [ \( \) | ] { return ::Apply( 'code' => COMPILER::get_var( ::Var( sigil => '&', twigil => '', name => $$, namespace => $$, ) ), 'arguments' => $$, ) } | { return ::Apply( 'code' => COMPILER::get_var( ::Var( sigil => '&', twigil => '', name => $$, namespace => $$, ) ), 'arguments' => [], ) } ] }; token opt_name { | '' }; token invocant { | \: { return $$ } | { return undef } }; token capture { # TODO - exp_seq / exp_mapping == positional / named # XXX use exp_parameter_list instead | \: { return ::Capture( 'invocant' => $$, 'array' => $$, 'hash' => [ ] ); } | { return ::Capture( 'invocant' => undef, 'array' => [ ], 'hash' => $$ ); } # ??? doesn't work here #| # { return ::Capture( 'invocant' => undef, 'array' => $$, 'hash' => [ ] ); } }; token sig { # TODO - exp_seq / exp_mapping == positional / named # ??? exp_parameter_list { # say ' invocant: ', ($$).perl; # say ' positional: ', ($$).perl; return ::Sig( 'invocant' => $$, 'positional' => $$, 'named' => { } ); } }; token base_class { } token subset { # example: subset Not_x of Str where { $_ ne 'x' } subset of where \{ # { say ' parsing statement list ' } { COMPILER::add_pad(); } [ \} | { say '*** Syntax Error in subset \'', get_class_name(), '.', $$, '\' near pos=', $/.to; die 'error in Block'; } ] { # say ' block: ', ($$).perl; my $env := @COMPILER::PAD[0]; COMPILER::drop_pad(); return ::Subset( 'name' => $$, 'base_class' => ::Proto( name => $$ ), 'block' => ::Sub( 'name' => undef, 'block' => ::Lit::Code( pad => $env, state => { }, sig => ::Sig( 'invocant' => undef, 'positional' => [ ], 'named' => { } ), body => $$, ), ), ); } } token begin_block { BEGIN \{ { COMPILER::add_pad(); } [ \} | { say '*** Syntax Error in BEGIN near pos=', $/.to; die 'error in Block'; } ] { # say ' block: ', ($$).perl; my $env := @COMPILER::PAD[0]; #print " grammar: dropping pad\n"; COMPILER::drop_pad(); #say "BEGIN block"; #print " grammar: entering begin block\n"; return COMPILER::begin_block( # $env, ::Lit::Code( pad => $env, state => { }, sig => ::Sig( 'invocant' => undef, 'positional' => [ ], 'named' => { } ), body => $$, ), ); } }; token check_block { CHECK \{ [ \} | { say '*** Syntax Error in CHECK block'; die 'error in Block'; } ] { #say "CHECK block"; return COMPILER::check_block( $$ ); } }; } =begin =head1 NAME KindaPerl6::Grammar - Grammar for KindaPerl6 =head1 SYNOPSIS my $match := $source.parse; ($$match).perl; # generated KindaPerl6 AST =head1 DESCRIPTION This module generates a syntax tree for the KindaPerl6 compiler. =head1 AUTHORS The Pugs Team Eperl6-compiler@perl.orgE. =head1 SEE ALSO The Perl 6 homepage at L. The Pugs homepage at L. =head1 COPYRIGHT Copyright 2006, 2007 by Flavio Soibelmann Glock, Audrey Tang and others. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See L =end