# Copyright (C) 2007, The Perl Foundation. # $Id: Grammar.pg 23883 2007-12-14 15:17:07Z particle $ =begin overview The following is the grammar for nqp written as a sequence of Perl 6 rules. In each of the rules, the special notation C<{*}> marks a point in the rule where the corresponding action in NQP::Grammar::Actions is to be invoked (see F). These actions are then used to construct the AST nodes for the program. The C<#=> markers at the ends of lines are used to distinguish among multiple C<{*}> actions within a rule, by passing the value after the marker as a 'key' argument to the action method. =end overview grammar NQP::Grammar is PCT::Grammar; token TOP { [ $ || ] {*} } ## The and rules handle whitespace and comments. ## These are taken from an earlier draft of Perl 6, so they do not ## yet handle all valid forms of Perl 6 whitespace. token ws { {{ $P0 = match.'to'() $P1 = get_hll_global [ 'NQP::Grammar' ], '$!ws' if null $P1 goto set_new_ws $P2 = $P1.'to'() if $P0 != $P2 goto set_new_ws .return (1) set_new_ws: set_hll_global [ 'NQP::Grammar' ], '$!ws', match }} [ \s+ | ^^ [ \# \N* | <.pod_comment> ] | \# \N* ]* } token afterws { ## {{ $P0 = match.'to'() $P1 = get_hll_global [ 'NQP::Grammar' ], '$!ws' $P2 = $P1.'to'() if $P0 != $P2 goto end $P2 = $P1.'from'() if $P0 == $P1 goto end .return (1) end: }} } regex pod_comment { ^^ '=' [ [ 'cut' \h*: | 'end' [\h\N*]? ] | 'for' [ \h\N+: ] \n [ \N+\n ]*: | \w\N*: \n .*? \n '=' [ 'cut' \h*: | 'end' [\h\N*:]? ] ] [\n|$] } #### Blocks and Statements #### ## A is a statement list that is returned as ## a PAST::Block node. rule statement_block { {*} #= open {*} #= close } ## Parse a list of statements. rule statement_list { [ [ <.statement_end> || ] ]* {*} } ## Parse a single statement, which may be either a bare block ## or an expression. Any statement termination is handled by ## the calling rule. rule statement { | {*} #= if_statement | {*} #= unless_statement | {*} #= while_statement | {*} #= repeat_statement | {*} #= for_statement | {*} #= return_statement | {*} #= make_statement | {*} #= inline_pir_statement | {*} #= block | {*} #= EXPR } ## The statement_end rule detects when we're at valid statement ## termination point. A semicolon always acts as a valid ## statement ending point, as does the presence of any expression ## terminator. The MARK_STATEMENT_END subrule is used by other ## rules to indicate a valid statement end even when a terminator ## isn't present (e.g., the closing '}' at the end of a line for ## a ). token terminator { <[ } \] ) ]> | $ } token statement_end { || ';' || > || {{ $P0 = get_hll_global ['NQP::Grammar'], '$!endstmt' $P1 = get_hll_global ['NQP::Grammar'], '$!ws' $P2 = $P1.'from'() if $P0 != $P2 goto end .return (1) end: }} } token MARK_STATEMENT_END { {{ $P0 = match.'to'() $P0 = clone $P0 set_hll_global ['NQP::Grammar'], '$!endstmt', $P0 }} <.ws> } ## The if_statement handles conditional statements such as 'if' and ## 'unless'. rule if_statement { $=['if'] [ 'elsif' ]* [ 'else' $= ]? {*} } rule unless_statement { $=['unless'] {*} } rule while_statement { $=['while'|'until'] {*} } rule repeat_statement { 'repeat' $=['while'|'until'] {*} } rule for_statement { $=['for'] {*} } rule return_statement { $=['return'] [ || ] {*} } rule make_statement { $=['make'] [ || ] {*} } rule inline_pir_statement { 'PIR' [ {*} #= quote | 'q:to:' [ \' (<-['\n]>+) \' | \" (<-["\n]>+) \" | \< (<-[\>\n]>+) \> ] [:sigspace(0):ratchet(0) ';' \h*: \n $=[ [\N*:\n]*? ] ^^ \h*: $0 \h*: \n <.MARK_STATEMENT_END> ] {*} #= heredoc ] } ## Parse a block. If the closing brace is at the end of a line, ## then we call <.MARK_STATEMENT_END> so that any following ## rule can succeed. token block { '{' [ '}' || ] [ \h* [ \# \N* ]? \n <.MARK_STATEMENT_END> ]? {*} } #### Subroutine and method definitions #### rule routine_def { $=['sub'|'method'] '(' ')' {*} } rule signature { ( ( ',' | ) )* ( ( ',' | ) )* {*} } token param_var { [ | '$/' | ] {*} } #### Terms #### token term { * {*} #= end } token postfix { [ {*} #= methodop | {*} #= postcircumfix ] } token methodop { '.' '(' [ <.ws> ')' || ] {*} #= methodop } token postcircumfix { | '(' ')' {*} #= ( ) | '[' <.ws> ']' {*} #= [ ] | '{' <.ws> '}' {*} #= { } | '<' > '>' {*} #= < > } rule arglist { ? {*} } token noun { | {*} #= colonpair | {*} #= package_declarator | {*} #= scope_declarator | {*} #= routine_def | {*} #= circumfix | {*} #= variable | {*} #= subcall | {*} #= value | {*} #= name } token colonpair { | ':' [ '(' <.ws> ')' ] {*} } rule package_declarator { $=[module|class] [ || ';' {*} #= statement_block || {*} #= block ] } rule scope_declarator { $=[my|our] {*} } token circumfix { | '(' ? <.ws> ')' {*} #= ( ) | '$(' ? <.ws> ')' {*} #= $( ) | '@(' ? <.ws> ')' {*} #= @( ) } token variable { | '$<' ( <-[\>]>* ) '>' {*} #= $< > | '$/' {*} #= $/ | ? {*} #= $var } token sigil { <[$@%&]> } token twigil { <[.!^*+?=]> } token value { | {*} #= quote | {*} #= number | {*} #= typename } token quote { [ \' \' | '"' '"' | 'q' <.ws> '<' > '>' ] {*} } token typename { {*} #= name } token name { [ '::' ]* {*} } token number { \d+ {*} } token subcall { '(' ')' {*} } #### Expressions and operators #### rule EXPR is optable { ... } ## Terms proto 'term:' is precedence('z=') is parsed(&term) { ... } ## Unary prefix operators proto prefix:<+> is looser('term:') is pasttype('inline') { ... } proto prefix:<~> is equiv(prefix:<+>) is pasttype('inline') { ... } proto prefix:<-> is equiv(prefix:<+>) is pirop('n_neg') { ... } proto prefix: is equiv(prefix:<+>) is pasttype('inline') { ... } proto prefix: is equiv(prefix:<+>) is pasttype('inline') { ... } ## Multiplicative operators proto infix:<*> is looser(prefix:<+>) is pirop('n_mul') { ... } proto infix: is equiv(infix:<*>) is pirop('n_div') { ... } proto infix:<%> is equiv(infix:<*>) is pirop('n_mod') { ... } ## Additive operators proto infix:<+> is looser(infix:<*>) is pirop('n_add') { ... } proto infix:<-> is equiv(infix:<+>) is pirop('n_sub') { ... } ## Concatenation operators proto infix:<~> is looser(infix:<+>) is pirop('n_concat') { ... } ## Comparison operators proto infix:<==> is looser(infix:<+>) is pasttype('inline') { ... } proto infix: is equiv(infix:<==>) is pasttype('inline') { ... } proto infix: is equiv(infix:<==>) is pasttype('inline') { ... } proto infix: is equiv(infix:<==>) is pasttype('inline') { ... } ## Tight logical operators proto infix:<&&> is looser(infix:<==>) is pasttype('if') { ... } proto infix:<||> is looser(infix:<&&>) is pasttype('unless') { ... } ## Binding proto infix:<:=> is looser(infix:<||>) is lvalue(1) is pasttype('bind') { ... } ## Comma proto infix:<,> is looser(infix:<:=>) is assoc('list') { ... }