# $Id: /mirror/trunk/languages/chitchat/src/parser/grammar.pg 29324 2008-07-11T13:26:13.743814Z kjs  $

=begin overview

This is the grammar for ChitChat written as a sequence of Perl 6 rules.

=end overview

grammar ChitChat::Grammar is PCT::Grammar;

token TOP {
    <.ws>
    [ | <exprs>
      | <methods>
      | '!'
    ]+
    <.ws>
    [ $ || <.panic: 'Syntax error'> ]
    {*}
}

token whitespace { \h | \v | <comment> }

token ws { <.whitespace>* }

token comment { '"' <-["]>* '"' }

rule methods {
    '!' <id> 'class'? 'methodsFor:' <string>
    '!' [<method> '!']?
    '!'
}

rule method {
    <message> <pragma>? <temps>? <exprs>
    {*}
}

token message {
    | <id> {*}                      #= id
    | <binsel> <.ws> <id> {*}       #= binsel
    | [<keysel> <.ws> <id>]+ {*}    #= keysel
}

token pragma { '<' <keymsg> '>' }

rule temps {
    '|' [<id> ]* '|'
    {*}
}

token unit {
    | <id>                  {*}  #= id
    | <literal>             {*}  #= literal
    | <block>               {*}  #= block
    | <arrayconstructor>    {*}  #= arrayconstructor
    | '(' <expr> ')'        {*}  #= expr
}

rule unaryexpr {
    <unit> [<!keysel><id> ]+
    {*}
}

token primary {
    | <!unaryexpr> <unit> {*}   #= unit
    | <unaryexpr> {*}           #= unaryexpr
}

rule exprs {
    [
    | <expr> [ '.' <expr>]* ['.' '^' <expr>]? '.'?
    | '^' <expr> '.'?
    ]
    {*}
}

rule expr {
    [<id> [':='|'_']]* <expr2>
    {*}
}

rule expr2 {
    | <msgexpr> [ ';' <cascade> ]* {*}     #= msgexpr
    | <primary> {*}                        #= primary
}

token msgexpr {
    | <binexpr>      {*}  #= binexpr
    | <keyexpr>      {*}  #= keyexpr
    | <unaryexpr>    {*}  #= unaryexpr
}

token cascade {
    | <id> {*}            #= id
    | <binmsg> {*}        #= binmsg
    | <keymsg> {*}        #= keymsg
}

rule binexpr {
    <primary> <binmsg>+
    {*}
}

rule binmsg {
    <binsel> <primary>
    {*}
}

token binsel { <binchar>**{1..2} }

rule keyexpr {
    <keyexpr2> <keymsg>
    {*}
}

token keyexpr2 {
    | <!binexpr> <primary> {*}      #= primary
    | <binexpr> {*}                 #= binexpr
}

rule keymsg {
    [<keysel> <keyexpr2> ]+
    {*}
}

token keysel { <id> ':' }

rule block {
    '[' [[':' <id>]* '|']? <temps>? <exprs> ']'
    {*}
}

token arrayconstructor {
    '{' <exprs> '}'
}

token literal {
    | <number>           {*}  #= number
    | <string>           {*}  #= string
    | <charconst>        {*}  #= charconst
    | <symconst>         {*}  #= symconst
    | <arrayconst>       {*}  #= arrayconst
    | <binding>          {*}  #= binding
    | <eval>             {*}  #= eval
}

token arrayconst {
    | '#' <array>
    | '#' <bytearray>
}

token bytearray {
    '[' <number>* ']'
}

rule array {
    '(' <arrayelem>* ')'
}

rule arrayelem {
    | <literal>       {*}  #= literal
    | <array>         {*}  #= array
    | <bytearray>     {*}  #= bytearray
    | <arraysym>      {*}  #= arraysym
}

token number {
    [<.digit>+ 'r']? '-'? <.alnum>+ ['.' <.alnum>+]? [<exp> '-'? <dig>+]?
    {*}
}

token string {
    \' $<text>:=<-[']>* \'
    {*}
}

token charconst { '$' . }

token symconst {
    | '#'<symbol>
    | '#'<string>
}

token arraysym {
    [<id> | ':']*
}

token exp {
    <[deqs]>
}

token binding {
    '#{' [<id> '.']* <id> '}'
}

token symbol {
    | <id>
    | <binsel>
    | <keysel>**{1..2}
}

rule eval {
    '##(' <temps>? <exprs> ')'
}

token id {
    <alpha> [ <alpha> | <digit> ]*
    {*}
}

token binchar { <[+\-*/~,<>=&´?\\%]> }
