# Copyright (C) 2006, The Perl Foundation.
# $Id: lua51.pg 17096 2007-02-20 20:20:48Z paultcochrane $

grammar Lua::Grammar

rule start {
        | <chunk>
        | <error: syntax error>
}

rule chunk {
        [ <statement> [\;]? ]*
}

rule block {
        <chunk> [ <laststat> [\;]? ]?
}

rule statement {
        | <ifstat>
        | <whilestat>
        | <dostat>
        | <forstat>
        | <repeatstat>
        | <funcstat>
        | <localfunc>
        | <localstat>
        | <exprstat>
}

rule laststat {
        | <returnstat>
        | <breakstat>
}

rule ifstat {
        <ifthenblock> <elseifthenblock>* [ <'else'> <block> ]? <'end'>
}

rule ifthenblock {
        | <'if'> <cond> <'then'> <block>
#        | <'if'> <cond> <error: 'then' expected>
}

rule elseifthenblock {
        | <'elseif'> <cond> <'then'> <block>
#        | <'elseif'> <cond> <error: 'then' expected>
}

rule cond {
        <expr>
}

rule whilestat {
        | <'while'> <expr> <'do'> <block> <'end'>
#        | <'while'> <expr> <error: 'do' expected>
}

rule dostat {
        <'do'> <block> <'end'>
}

rule forstat {
        | <'for'> [ <fornum> | <forlist> ]
#        | <'for'> <Name> <error: '=' or 'in' expected>
}

rule fornum {
        | <Name> \= <expr> \, <expr> [ \, <expr> ]? <forbody>
#        | <Name> \= <expr> <error: ',' expected>
#        | <Name> <error: '=' expected>
}

rule forlist {
        | <namelist> <'in'> <explist1> <forbody>
#        | <namelist> <error: 'in' expected>
}

rule namelist {
        <Name> [ \, <Name> ]*
}

rule forbody {
        | <'do'> <block> <'end'>
#        | <'do'> <block> <error: 'end' expected>
#        | <error: 'do' expected>
}

rule repeatstat {
        | <'repeat'> <block> <'until'> <exp>
#        | <'repeat'> <block> <error: 'until' expected>
}

rule funcstat {
        <'function'> <funcname> <funcbody>
}

rule funcname {
        <Name> [ \. <Name> ]* [ \: <Name> ]?
}

rule funcbody {
        | \( \) <chunk> <'end'>
        | \( <parlist> \) <chunk> <'end'>
#        | \( <parlist>? <error: ')' expected>
#        | <error: '(' expected>
}

rule parlist {
        | <namelist> [ \, <'...'> ]?
        | <'...'>
}

rule localfunc {
        <'local'> <'function'> <Name> <funcbody>
}

rule localstat {
        <'local'> <namelist> [ \= <explist1> ]?
}

rule returnstat {
        <'return'> <explist1>?
}

rule breakstat {
        <'break'>
}

rule exprstat {
        <primaryexp> <assignment>?
}

rule assignment {
        | \, <primaryexp> <assignment>
        | \= <explist1>
#        | <error: '=' expected>
}

rule primaryexp {
        <prefixexp> [ \. <Name>
                    | <index>
                    | \: <Name> <funcargs>
                    | <funcargs>
                    ]*
}

rule index {
        | \[ <expr> \]
#        | \[ <expr> <error: ']' expected>
}

rule prefixexp {
        | <Name>
        | \( <expr> \)
#        | <error: unexpected symbol>
}

rule expr {
        [ <simpleexp> | <unop> <expr> ] [ <binop> <expr> ]*
}

rule simpleexp {
        | <Number>
        | <String>
        | <'nil'>
        | <'true'>
        | <'false'>
        | <'...'>
        | <constructor>
        | <'function'> <funcbody>
        | <primaryexp>
}

rule explist1 {
        <expr> [\, <expr>]*
}

rule funcargs {
        | \( \)
        | \( <explist1> \)
#        | \( <error: function arguments expected>
        | <constructor>
        | <String>
        | <error: function arguments expected>
}

rule constructor {
        | \{ \}
        | \{ <fieldlist> \}
}

rule fieldlist {
        <field> [ <fieldsep> <field> ]* <fieldsep>?
}

rule field {
        | <index> \= <expr>
#        | <index> <error: '=' expected>
        | <Name> \= <expr>
        | <expr>
}


token fieldsep {
        | \,
        | \;
}

token binop {
        | \+
        | \-
        | \*
        | \/
        | \%
        | \^
        | \.\.
        | \<\=
        | \<
        | \>\=
        | \>
        | \=\=
        | \~\=
        | and
        | or
}

token unop {
        | \-
        | not
        | \#
}

token String {
        | \" <quoted_literal: "> \"
        | \' <quoted_literal: '> \'
        | <long_string>
}

token Number {
        | 0 <[Xx]> <xdigit>+
        | [ <digit>+ [ \. <digit>* ]? | \. <digit>+ ]
          [ <[Ee]> <[+\-]>? <digit>+ ]?
}

token ws {
        [ \s+
        | \-\- <long_comment>
        | \-\- \N*
        ]*
}


proto 'infix:^'     is precedence('=')
                    is assoc('right')           { ... }

proto 'prefix:not'  is looser('infix:^')        { ... }
proto 'prefix:#'    is equiv('prefix:not')      { ... }
proto 'prefix:-'    is equiv('prefix:not')      { ... }

proto 'infix:*'     is looser('prefix:not')     { ... }
proto 'infix:/'     is equiv('infix:*')         { ... }
proto 'infix:%'     is equiv('infix:*')         { ... }

proto 'infix:+'     is looser('infix:*')        { ... }
proto 'infix:-'     is equiv('infix:+')         { ... }

proto 'infix:..'    is looser('infix:+')
                    is assoc('right')           { ... }

proto 'infix:<'     is looser('infix:..')       { ... }
proto 'infix:>'     is equiv('infix:<')         { ... }
proto 'infix:<='    is equiv('infix:<')         { ... }
proto 'infix:>='    is equiv('infix:<')         { ... }
proto 'infix:~='    is equiv('infix:<')         { ... }
proto 'infix:=='    is equiv('infix:<')         { ... }

proto 'infix:and'   is looser('infix:<')        { ... }

proto 'infix:or'    is looser('infix:and')      { ... }

