# $Id: /mirror/trunk/languages/lolcode/src/parser/grammar.pg 29288 2008-07-10T20:41:17.208728Z tene  $

=begin overview

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

=end overview

grammar lolcode::Grammar is PCT::Grammar;

rule TOP {
    ['HAI' <version> <.statement_terminator>]?
    <block>
    ['KTHXBYE' <.statement_terminator>]?
    [ $ || <panic: 'Syntax error'> ]
    {*}
}

token version { \d+ [ '.' \d+ ]? }

rule statement {
    | <declare>    {*}   #= declare
    | <assign>     {*}   #= assign
    | <function>   {*}   #= function
    | <ifthen>     {*}   #= ifthen
    | <switch>     {*}   #= switch
    | <expression> {*}   #= expression
}

token statement_terminator { [ ',' | \n+ | $ ] }

rule declare {
    'I' 'HAS' 'A' <scope>? <variable> [ 'ITZ' <expression> ]?
    {*}
}

token scope {
    | 'FARAWAY'
    | 'NEARBY'
}

rule assign {
    <variable> 'R' <expression> {*}
}

rule function {
    # $<parameters> is only getting the first parameter, not all of them
    # like I'd expect...
    'HOW' 'DUZ' 'I' <variable> ['YR' $<parameters>=<variable> [ 'AN' 'YR' $<parameters>=<variable>]* ]?<.statement_terminator>
    {*}                         #= params
    <block>
    'IF' 'U' 'SAY' 'SO'
    {*}                         #= block
}

rule ifthen {
    <expression> <.statement_terminator>
    'O' 'RLY?' <.statement_terminator>
    'YA' 'RLY' <.statement_terminator>
    <block>
    [
      'MEBBE' <expression> <.statement_terminator>
      <block>
    ]*
    [
      'NO' 'WAI' <.statement_terminator>
      $<else>=<block>
    ]?
    'OIC'
    {*}
}

rule switch {
    'WTF?' <.statement_terminator>
    [
      'OMG' <value> <.statement_terminator>
      <block>
    ]+
    [
      'OMGWTF' <.statement_terminator>
      <else=block>
    ]?
    'OIC' {*}
}

rule block {
    {*}                                          #= open
    [<statement> <.statement_terminator>]*
    {*}                                          #= close
}

rule parameters {
    'YR' <identifier> [ 'AN' 'YR' <identifier> ]*
}

rule expression {
    [
    | $<tokens>=<operator>
    | $<tokens>=<variable>
    | $<tokens>=<value>
    | 'AN'
    | $<tokens>='MKAY'
    ]+ {*}
}

token value {
    | <float>    {*}                             #= float
    | <integer>  {*}                             #= integer
    | <boolean>  {*}                             #= boolean
    | <quote>    {*}                             #= quote
    | <bang>     {*}                             #= bang
}

token bang {
    '!' {*}
}

token operator { $<identifier>=(<.identifier> <.ws> 'OF'|'BOTH SAEM') {*} }
token variable { <identifier> {*} }

token identifier { <!keyword> <[a..zA..Z]> \w* }

# RT #46213 : Because PGE doesn't yet know how to do longest token matching,
# order all tokens in reverse alpha order to avoid a parsing bug.
token keyword {
    [ 'YR' | 'YA' | 'WTF?' | 'WIN' | 'WAI' | 'U' | 'SO'
    | 'SAY' | 'RLY?' | 'RLY' | 'R' 
    | 'OMGWTF' | 'OMG' | 'OIC' | 'OF' | 'O' | 'NO' | 'MKAY' | 'MEBBE' | 'KTHXBYE'
    | 'ITZ' | 'IF' | 'I' | 'HOW' | 'HAS' | 'GTFO' | 'FOUND' | 'FARAWAY' | 'FAIL' 
    | 'AN' | 'A' ] >>
}

token integer { '-'? \d+ {*} }

token float { '-'? \d+ '.' \d+ {*} }

rule boolean { [ 'WIN' | 'FAIL' ] {*} }

rule quote {
    [ <.before '"'> <yarn_literal> ]
    {*}
}

token ws { <!ww> [
    | ^^ \h* BTW \h \N* \n+
    | ^^ \h* OBTW .*? ^^ \h* TLDR \n+
    | \h+
    ]*
}
