# to be adapted...
# from Guido van Rossum: https://github.com/we-like-parsers/pegen/blob/master/story7/grammar.gram
# see also: https://medium.com/@gvanrossum_83706/adding-actions-to-a-peg-grammar-d5e00fa1092f


start: grammar ENDMARKER { grammar }

grammar:
    | metas rules { Grammar(rules + self.extra_rules, metas) }
    | rules { Grammar(rules + self.extra_rules, []) }

metas:
    | meta metas { [meta] + metas }
    | meta { [meta] }

meta:
    | "@" NAME NEWLINE { (name.string, None) }
    | "@" NAME NAME NEWLINE { (name.string, name1.string) }
    | "@" NAME STRING NEWLINE { (name.string, literal_eval(string.string)) }

rules:
    | rule rules { [rule] + rules }
    | rule { [rule] }

rule:
    | NAME ":" alts NEWLINE INDENT more_alts DEDENT { Rule(name.string, alts + more_alts) }
    | NAME ":" NEWLINE INDENT more_alts DEDENT { Rule(name.string, more_alts) }
    | NAME ":" alts NEWLINE { Rule(name.string, alts) }

more_alts:
    | "|" alts NEWLINE more_alts { alts + more_alts }
    | "|" alts NEWLINE { alts }

alts:
    | alt "|" alts { [alt] + alts }
    | alt { [alt] }

alt:
    | items action { Alt(items, action) }
    | items { Alt(items, None) }

items:
    | item items { [item] + items }
    | item { [item] }

item:
    | NAME '=' molecule { NamedItem(name.string, molecule) }
    | "&" atom { Lookahead(atom) }
    | "!" atom { Lookahead(atom, False) }
    | "~" { Cut() }
    | molecule { molecule }

molecule:
    | atom "?" { Maybe(atom) }
    | atom "*" { Loop(atom) }
    | atom "+" { Loop(atom, True) }
    | atom { atom }
    | "[" alts "]" { Maybe(self.synthetic_rule(alts)) }

atom:
    | NAME { name.string }
    | STRING {string.string }
    | "(" alts ")" { self.synthetic_rule(alts) }

action: "{" stuffs "}" { stuffs }

stuffs:
    | stuff stuffs { stuff + " " + stuffs }
    | stuff { stuff }

stuff:
    | "{" stuffs "}" { "{" + stuffs + "}" } 
    | NAME { name.string }
    | NUMBER { number.string }
    | STRING { string.string }
    | !"}" OP { op.string }
