"""This parser was generated by pyebnf on 2015-09-15T18:59:39.370833."""
from enum import Enum

from pyebnf import parser_base as PB
from pyebnf.primitive import alternation, concatenation, exclusion, one_or_more
from pyebnf.primitive import option, repeated, repetition, terminal, zero_or_more


class TokenType(Enum):
  """The token types for parse nodes generated by the Parser."""
  program = 1
  statement = 2
  assignment = 3
  variable = 4
  identifier = 5
  simple_identifier = 6
  complex_identifier = 7
  alpha_character = 8
  digit = 9
  reserved_words = 10
  expression = 11
  expression_terminal = 12
  number = 13
  string = 14
  double_string_char = 15
  single_string_char = 16
  all_characters = 17
  function_call = 18
  function_name = 19
  function_args = 20
  subexpression = 21
  branch = 22
  branch_if = 23
  branch_elif = 24
  branch_else = 25
  switch = 26
  switch_subject = 27
  switch_case = 28
  switch_default = 29
  operator = 30
  directive = 31
  eol = 32
  whitespace = 33
  comment = 34
  return_statement = 35


class Parser(PB.ParserBase):
  """This class contains methods for reading source code and generating a parse tree."""
  entry_point = "program"

  def program(self, text):
    """program = {directive} , {statement} , return_statement , "\eof" ;"""
    self._attempting(text)
    return concatenation([
      zero_or_more(
        self.directive,
        ignore_whitespace=True
      ),
      zero_or_more(
        self.statement,
        ignore_whitespace=True
      ),
      self.return_statement,
      "\\eof",
    ], ignore_whitespace=True)(text).retyped(TokenType.program)
  
  def statement(self, text):
    """statement = comment | assignment , ";" ;"""
    self._attempting(text)
    return alternation([
      self.comment,
      concatenation([
        self.assignment,
        ";",
      ], ignore_whitespace=True),
    ])(text)
  
  def assignment(self, text):
    """assignment = variable , (":=" | "<-") , expression ;"""
    self._attempting(text)
    return concatenation([
      self.variable,
      alternation([
        ":=",
        "<-",
      ]),
      self.expression,
    ], ignore_whitespace=True)(text).retyped(TokenType.assignment)
  
  def variable(self, text):
    """variable = identifier - reserved_words ;"""
    self._attempting(text)
    return exclusion(
      self.identifier,
      self.reserved_words
    )(text).compressed(TokenType.variable)
  
  def identifier(self, text):
    """identifier = simple_identifier | complex_identifier ;"""
    self._attempting(text)
    return alternation([
      self.simple_identifier,
      self.complex_identifier,
    ])(text).retyped(TokenType.identifier)
  
  def simple_identifier(self, text):
    """simple_identifier = (alpha_character | "_") . {alpha_character | digit | "_" | "."} ;"""
    self._attempting(text)
    return concatenation([
      alternation([
        self.alpha_character,
        "_",
      ]),
      zero_or_more(
        alternation([
          self.alpha_character,
          self.digit,
          "_",
          ".",
        ]),
        ignore_whitespace=False
      ),
    ], ignore_whitespace=False)(text).retyped(TokenType.simple_identifier)
  
  def complex_identifier(self, text):
    """complex_identifier = "[" . (all_characters - "]") + . "]" ;"""
    self._attempting(text)
    return concatenation([
      "[",
      one_or_more(
        exclusion(
          self.all_characters,
          "]"
        ),
        ignore_whitespace=False
      ),
      "]",
    ], ignore_whitespace=False)(text).retyped(TokenType.complex_identifier)
  
  def alpha_character(self, text):
    """alpha_character = ? get_ascii_letter ? ;"""
    self._attempting(text)
    return PB.get_ascii_letter(text).retyped(TokenType.alpha_character)
  
  def digit(self, text):
    """digit = ? get_digit ? ;"""
    self._attempting(text)
    return PB.get_digit(text).retyped(TokenType.digit)
  
  def reserved_words(self, text):
    """reserved_words = "return" | "if" | "elif" | "else" | "switch" | "when";"""
    self._attempting(text)
    return alternation([
      "return",
      "if",
      "elif",
      "else",
      "switch",
      "when",
    ])(text).retyped(TokenType.reserved_words)
  
  def expression(self, text):
    """expression = {operator} , expression_terminal , {operator + , expression} ;"""
    self._attempting(text)
    return concatenation([
      zero_or_more(
        self.operator,
        ignore_whitespace=True
      ),
      self.expression_terminal,
      zero_or_more(
        concatenation([
          one_or_more(
            self.operator,
            ignore_whitespace=True
          ),
          self.expression,
        ], ignore_whitespace=True),
        ignore_whitespace=True
      ),
    ], ignore_whitespace=True)(text).retyped(TokenType.expression)
  
  def expression_terminal(self, text):
    """expression_terminal = number
                           | string
                           | variable
                           | subexpression
                           | function_call
                           | branch
                           | switch ;"""
    self._attempting(text)
    return alternation([
      self.number,
      self.string,
      self.variable,
      self.subexpression,
      self.function_call,
      self.branch,
      self.switch,
    ])(text)
  
  def number(self, text):
    """number = ["-"] . ("0" | digit - "0" . {digit}) . ["." . digit +] ;"""
    self._attempting(text)
    return concatenation([
      option(
        "-"
      ),
      alternation([
        "0",
        concatenation([
          exclusion(
            self.digit,
            "0"
          ),
          zero_or_more(
            self.digit,
            ignore_whitespace=False
          ),
        ], ignore_whitespace=False),
      ]),
      option(
        concatenation([
          ".",
          one_or_more(
            self.digit,
            ignore_whitespace=False
          ),
        ], ignore_whitespace=False)
      ),
    ], ignore_whitespace=False)(text).compressed(TokenType.number)
  
  def string(self, text):
    """string = '"' . {double_string_char} . '"'
              | "'" . {single_string_char} . "'" ;"""
    self._attempting(text)
    return alternation([
      concatenation([
        '"',
        zero_or_more(
          self.double_string_char,
          ignore_whitespace=False
        ),
        '"',
      ], ignore_whitespace=False),
      concatenation([
        "'",
        zero_or_more(
          self.single_string_char,
          ignore_whitespace=False
        ),
        "'",
      ], ignore_whitespace=False),
    ])(text).compressed(TokenType.string)
  
  def double_string_char(self, text):
    """double_string_char = "\\" . all_characters - '"'
                          | "\" . '"'
                          | all_characters - '"' ;"""
    self._attempting(text)
    return alternation([
      concatenation([
        "\\\\",
        exclusion(
          self.all_characters,
          '"'
        ),
      ], ignore_whitespace=False),
      concatenation([
        "\\",
        '"',
      ], ignore_whitespace=False),
      exclusion(
        self.all_characters,
        '"'
      ),
    ])(text).retyped(TokenType.double_string_char)
  
  def single_string_char(self, text):
    """single_string_char = "\\" . all_characters - "'"
                          | "\" . "'"
                          | all_characters - "'" ;"""
    self._attempting(text)
    return alternation([
      concatenation([
        "\\\\",
        exclusion(
          self.all_characters,
          "'"
        ),
      ], ignore_whitespace=False),
      concatenation([
        "\\",
        "'",
      ], ignore_whitespace=False),
      exclusion(
        self.all_characters,
        "'"
      ),
    ])(text).retyped(TokenType.single_string_char)
  
  def all_characters(self, text):
    """all_characters = ? get_printable ? ;"""
    self._attempting(text)
    return PB.get_printable(text).retyped(TokenType.all_characters)
  
  def function_call(self, text):
    """function_call = function_name . "(" , [function_args] , ")" ;"""
    self._attempting(text)
    return concatenation([
      self.function_name,
      concatenation([
        "(",
        option(
          self.function_args
        ),
        ")",
      ], ignore_whitespace=True),
    ], ignore_whitespace=False)(text).retyped(TokenType.function_call)
  
  def function_name(self, text):
    """function_name = variable ;"""
    self._attempting(text)
    return self.variable(text).retyped(TokenType.function_name)
  
  def function_args(self, text):
    """function_args = expression , {"," , function_args} ;"""
    self._attempting(text)
    return concatenation([
      self.expression,
      zero_or_more(
        concatenation([
          ",",
          self.function_args,
        ], ignore_whitespace=True),
        ignore_whitespace=True
      ),
    ], ignore_whitespace=True)(text)
  
  def subexpression(self, text):
    """subexpression = "(" , expression , ")" ;"""
    self._attempting(text)
    return concatenation([
      "(",
      self.expression,
      ")",
    ], ignore_whitespace=True)(text).retyped(TokenType.subexpression)
  
  def branch(self, text):
    """branch = branch_if , {branch_elif} , branch_else ;
       b"""
    self._attempting(text)
    return concatenation([
      self.branch_if,
      zero_or_more(
        self.branch_elif,
        ignore_whitespace=True
      ),
      self.branch_else,
    ], ignore_whitespace=True)(text).retyped(TokenType.branch)
  
  def branch_if(self, text):
    """branch_if = "if" , expression , ":" , expression ;"""
    self._attempting(text)
    return concatenation([
      "if",
      self.expression,
      ":",
      self.expression,
    ], ignore_whitespace=True)(text).retyped(TokenType.branch_if)
  
  def branch_elif(self, text):
    """branch_elif = "elif" , expression , ":" , expression ;"""
    self._attempting(text)
    return concatenation([
      "elif",
      self.expression,
      ":",
      self.expression,
    ], ignore_whitespace=True)(text).retyped(TokenType.branch_elif)
  
  def branch_else(self, text):
    """branch_else = "else" , ":" , expression ;"""
    self._attempting(text)
    return concatenation([
      "else",
      ":",
      self.expression,
    ], ignore_whitespace=True)(text).retyped(TokenType.branch_else)
  
  def switch(self, text):
    """switch = switch_subject , switch_case + , [switch_default] ;
       s"""
    self._attempting(text)
    return concatenation([
      self.switch_subject,
      one_or_more(
        self.switch_case,
        ignore_whitespace=True
      ),
      option(
        self.switch_default
      ),
    ], ignore_whitespace=True)(text).retyped(TokenType.switch)
  
  def switch_subject(self, text):
    """switch_subject = "switch" , expression ;"""
    self._attempting(text)
    return concatenation([
      "switch",
      self.expression,
    ], ignore_whitespace=True)(text).retyped(TokenType.switch_subject)
  
  def switch_case(self, text):
    """switch_case = "when" , expression , ":" , expression ;"""
    self._attempting(text)
    return concatenation([
      "when",
      self.expression,
      ":",
      self.expression,
    ], ignore_whitespace=True)(text).retyped(TokenType.switch_case)
  
  def switch_default(self, text):
    """switch_default = "else" , ":" , expression ;"""
    self._attempting(text)
    return concatenation([
      "else",
      ":",
      self.expression,
    ], ignore_whitespace=True)(text).retyped(TokenType.switch_default)
  
  def operator(self, text):
    """operator = "+" | "-"  | "*"  | "/"  | "%" | "^"
                | "=" | "!=" | ">=" | "<=" | ">" | "<"
                | "!" | "|"  | "&"  | "?" ;"""
    self._attempting(text)
    return alternation([
      "+",
      "-",
      "*",
      "/",
      "%",
      "^",
      "=",
      "!=",
      ">=",
      "<=",
      ">",
      "<",
      "!",
      "|",
      "&",
      "?",
    ])(text).retyped(TokenType.operator)
  
  def directive(self, text):
    """directive = "#" . { all_characters - "\n" } . eol ;"""
    self._attempting(text)
    return concatenation([
      "#",
      zero_or_more(
        exclusion(
          self.all_characters,
          "\n"
        ),
        ignore_whitespace=False
      ),
      self.eol,
    ], ignore_whitespace=False)(text).compressed(TokenType.directive)
  
  def eol(self, text):
    """eol = { whitespace - "\n" } . "\n" ;"""
    self._attempting(text)
    return concatenation([
      zero_or_more(
        exclusion(
          self.whitespace,
          "\n"
        ),
        ignore_whitespace=False
      ),
      "\n",
    ], ignore_whitespace=False)(text)
  
  def whitespace(self, text):
    """whitespace = ? get_whitespace ? ;"""
    self._attempting(text)
    return PB.get_whitespace(text)
  
  def comment(self, text):
    """comment = "/*" . {all_characters - "*" | "*" . all_characters - "/"} . "*/" ;"""
    self._attempting(text)
    return concatenation([
      "/*",
      zero_or_more(
        alternation([
          exclusion(
            self.all_characters,
            "*"
          ),
          concatenation([
            "*",
            exclusion(
              self.all_characters,
              "/"
            ),
          ], ignore_whitespace=False),
        ]),
        ignore_whitespace=False
      ),
      "*/",
    ], ignore_whitespace=False)(text).compressed(TokenType.comment)
  
  def return_statement(self, text):
    """return_statement = ["return"] , expression , [";"] ;"""
    self._attempting(text)
    return concatenation([
      option(
        "return"
      ),
      self.expression,
      option(
        ";"
      ),
    ], ignore_whitespace=True)(text).retyped(TokenType.return_statement)
  


