## $Id: grammar_rules.pg 17096 2007-02-20 20:20:48Z paultcochrane $

## TITLE
##     The Perl 6 grammar
##
## DESCRIPTION
##
## These are the regexes used to compile Perl 6 programs.
## This is just a first draft of a grammar for parsing
## Perl 6 programs, undoubtedly more regexes will be added
## soon.  Much of the work is hidden in the <opparse>
## regex, which is defined in L<Perl6/parse.pir>
## and handles most expressions using a bottom-up
## parsing algorithm.

## This grammar is derived from "Synopsis 6: Subroutines"
## http://dev.perl.org/perl6/doc/design/syn/S06.html

grammar Perl6::Grammar ;

## C<TOP> defines the top level rule to the HLLCompiler.
token TOP { <program> }

## These regexes handle whitespace between comments and tokens

token ws {
    [ \s+
    | ^^ [ \# \N*
         | <?pod_comment>
         ]
    | \# [ <?PGE::Text::bracketed: <({[>
         | \N*
         ]
    ]*
}

regex pod_comment {
    ^^ = [ [ cut \h*: | end [\h\N*]? ]
         | for [ \h\N+: ] \n [ \N+\n ]*:
         | \w\N*: \n .*? \n = [ cut \h*: | end [\h\N*:]? ]
         ]
         [\n|$]
}


token program {
    ^ <statement_list> <?ws> [ $ | <?syntax_error> ]
}


token statement_list {
    <statement> [ <?statement_end> <statement> ]* <?statement_end>?
}


token statement_end {
    | [ <?ws> ; ]+
    | <after \}> :: \h* [ \#\N* ]? \n
}


## XXX: <statement_control> will likely become <%statement_control>.
## Since PGE doesn't support hashes in regexes yet, we're just using
## an alternation for now.
##
## The subrule C<< <expression:  ;> >> calls the C<expression> sub
## in L<src/parse.pir>, which passes control to the operator
## precedence parser.  The space+semicolon parameter tells
## the operator precedence parser to stop parsing the expression
## at any top-level semicolon (with optional leading <?ws>).
## (This may yet change as we refine things further.)

token statement {
    | <statement_control>
    | <block>
    | <closure_trait>
    | <class_block>
    | <use_statement>
    | <expression:  ;> <statement_modifier>?
}


## Here, the <expression> subrule doesn't parse any top-level
## bare closures (controlled by the space+brace argument).
token statement_control {
    <?ws>
    [ $<KEY>:=[if|unless] <expression:  {> <block>
        [ <?ws>: elsif <expression:  {> <block> ]*
        [ <?ws>: else <block> ]?
    | $<KEY>:=[while|until] <expression:  {> <block>
    | $<KEY>:=[repeat] <block>
        [ <?ws>: [while|until] <expression:  ;> ]
    | $<KEY>:=[loop] [ \( <expression> ; <expression> ; <expression> \) ]?
        <block>
    | $<KEY>:=[for] <expression:  {> <block>
    ]
}


token statement_modifier {
    <?ws> $<KEY>:=[if|unless|for|while|until] <expression:  ;>
}


token block {
    <?ws>
    \{
    <?ws> [ <statement_list> | <?null> ] <?ws>
    [ \} | <?syntax_error> ]
}


token closure_trait {
    $<trait>:=[ BEGIN | CHECK | INIT | END | START
              | ENTER | LEAVE | KEEP | UNDO
              | FIRST | NEXT  | LAST
              | PRE   | POST
              | CATCH | CONTROL
              ]
    <?ws>? <block>
}

token use_statement {
    <?ws> use <?ws> <version> <?ws> <expression:  ;>?
}

token version { <ident> }


## We handle Perl 6 expressions using PGE's operator
## precedence parser.  The tokens and sub for this are
## defined in L<Perl6/parser.pir>.  If written as a p6regex,
## it would look something like:
##     regex expression($stop) { { $opparse.parse($/, $stop) } }

## The <term> regex gets called from the operator precedence
## parser whenever it needs a term.

token term {
    [ <scoped_variables>
    | <variable>
    | <subroutine>
    | <block>
    | <try_block>
    | <regex_term>
    | <quote_term>
    | <number>
    | <integer>
    | <listop>
    | <circumfix>
    ] <postop>*
}


token postop {
    | <?dot> [ <postfix> | <postcircumfix> | <methodop> ]
    |        [ <postfix> | <postcircumfix> ]
}
## FIXME: Eventually this will likely read <%postfix | %postcircumfix>.
## And we may have to deal with precedence issues somewhere.

token dot { \. | [ \\ <?ws> ]? \. }

token postfix { $<KEY>:=[\+\+|--] }

token postcircumfix {
    | $<KEY>:=[\(] <?ws> <expression>? <?ws> $<KEY_CLOSE>:=[\)]
    | $<KEY>:=[\[] <?ws> <expression>? <?ws> $<KEY_CLOSE>:=[\]]
    | $<KEY>:=[\{] <?ws> <expression>? <?ws> $<KEY_CLOSE>:=[\}]
}

token methodop { <ident> [ <!postop> <listop_expression> ]? }
token listop { <ident> [ <!postop> <listop_expression> ]? }

token circumfix {
    | $<KEY>:=[\(] <?ws> <expression>? <?ws> $<KEY_CLOSE>:=[\)]
    | $<KEY>:=[\[] <?ws> <expression>? <?ws> $<KEY_CLOSE>:=[\]]
}

token reserved_word { [ if | unless | while | until | for | loop | do ] \b }

## This is a temporary rule that allows parsing of /regex/
## in term position.  It is likely to change.

token regex_term { / <regex: /> / }

rule scoped_variables {
    <scope_declarator> <variable>
}

token scope_declarator { [ my | our ] }
token class_declarator { [ class | grammar | module | role | package ] }

token class_block {
    <scope_declarator>?
    <class_declarator>
    $<name>:=[ <'::'>? <name> | <?null> ] ;
    <block>
}


## XXX: These are just placeholder regexes for demonstration,
## they certainly need to be expanded to be more complete.

token twigil { <[.^*+?=!]> }
token variable {  \$! | \$/ | \$_ | <sigil> <twigil>? <name> }
token sigil { <[$@%^&]> | <'::'> }
token name { <ident> [ <'::'> <ident> ]* }

token integer {
    | 0 [ b <[01]>+           [ _ <[01]>+ ]*
        | o <[0..7]>+         [ _ <[0..7]>+ ]*
        | x <[0..9a..fA..F]>+ [ _ <[0..9a..fA..F]>+ ]*
        | d \d+               [ _ \d+]*
        ]
    | \d+[_\d+]*
}

token number {
    \d+[_\d+]* [ \. \d+[_\d+]* [ <[Ee]> <[+\-]>? \d+ ]? ]
}

token quote_term {
    |    $<KEY>:=[']    <quote_expression> '
    |    $<KEY>:=["]    <quote_expression> "
    |    $<KEY>:=[\<\<] <quote_expression> \>\>
    |    $<KEY>:=[\<]   <quote_expression> \>
}

##  rules for parsing interpolated values in quotes.
##  FIXME: We're repeating the $<postop> portion here
##  because there's apparently an aliasing bug in PGE.
##  The first part of the rule handles non-scalar
##  interpolation (which must end with a postcircumfix operator);
##  the second part handles scalar interpolation.
token quote_interpolation {
    | <![$]> ::: <variable>
          $<postop>:=( <?dot> [ <postcircumfix> | $<method>:=<ident> ]
                     | <postcircumfix> )+
    | <variable>
          $<postop>:=( <?dot> [ <postcircumfix> | $<method>:=<ident> ]
                     | <postcircumfix> )*
}


## Subroutine parsing.  This is still under development.

rule subroutine {
    <scope_declarator>?
        [ <routine_modifier> <routine_type>? | <routine_type> ]
        <ident>?
        <trait>*
        [\( <signature> \)]?
        <block>}

rule subintro { <routine_modifier> <routine_type>? | <routine_type> }

token routine_modifier { multi | proto }

token routine_type { sub | method | submethod | macro | regex | token | rule }

token type { <routine_type> ::: <fail> | <ident> }

rule trait {
    | $<KEY>:=[is] <ident>[\( <expression> \)]?
    | $<KEY>:=[will] <ident> <block>
    | $<KEY>:=[of] <type>
    | $<KEY>:=[returns] <type>
}

rule signature {
    $<invocant>:=(<parameter> <':'>)?
    $<paramlist>:=(<parameter>? [, <parameter>]*)
    [ <'-->'> $<rettype>:=<type> ]?
}

##  XXX: <parameter> needs expansion for the various
##  parameter options available.

token parameter { $<variable>:=[<sigil> <twigil>? <ident>] }

rule try_block { try <block>}


## The <syntax_error> token generates a simple syntax
## error message, and displays the line number and context
## of the error.

token syntax_error { <?PGE::Util::die: Syntax error> }

## vim: expandtab sw=4
