#!/usr/bin/env python
# -*- coding: utf-8 -*-

# CAVEAT UTILITOR
#
# This file was automatically generated by Grako.
#
#    https://pypi.python.org/pypi/grako/
#
# Any changes you make to it will be overwritten the next time
# the file is generated.


from __future__ import print_function, division, absolute_import, unicode_literals

from grako.buffering import Buffer
from grako.parsing import graken, Parser
from grako.util import re, RE_FLAGS, generic_main  # noqa


KEYWORDS = {}


class ModelSpecBuffer(Buffer):
    def __init__(
        self,
        text,
        whitespace=None,
        nameguard=None,
        comments_re=None,
        eol_comments_re=None,
        ignorecase=None,
        namechars='',
        **kwargs
    ):
        super(ModelSpecBuffer, self).__init__(
            text,
            whitespace=whitespace,
            nameguard=nameguard,
            comments_re=comments_re,
            eol_comments_re=eol_comments_re,
            ignorecase=ignorecase,
            namechars=namechars,
            **kwargs
        )


class ModelSpecParser(Parser):
    def __init__(
        self,
        whitespace=None,
        nameguard=None,
        comments_re=None,
        eol_comments_re=None,
        ignorecase=None,
        left_recursion=False,
        parseinfo=True,
        keywords=None,
        namechars='',
        buffer_class=ModelSpecBuffer,
        **kwargs
    ):
        if keywords is None:
            keywords = KEYWORDS
        super(ModelSpecParser, self).__init__(
            whitespace=whitespace,
            nameguard=nameguard,
            comments_re=comments_re,
            eol_comments_re=eol_comments_re,
            ignorecase=ignorecase,
            left_recursion=left_recursion,
            parseinfo=parseinfo,
            keywords=keywords,
            namechars=namechars,
            buffer_class=buffer_class,
            **kwargs
        )

    @graken()
    def _model_(self):
        with self._group():
            with self._choice():
                with self._option():
                    self._phenotype_or_variant_()
                with self._option():
                    self._labelled_outcome_group_()
                self._error('no available options')
        self.name_last_node('outcome')
        with self._optional():
            self._token('|')
            self._cut()
            self._condition_group_()
            self.name_last_node('conditions')
        self._token('~')
        self._predictors_()
        self.name_last_node('predictors')
        self._check_eof()
        self.ast._define(
            ['conditions', 'outcome', 'predictors'],
            []
        )

    @graken()
    def _condition_group_(self):

        def sep0():
            self._token(',')

        def block0():
            self._condition_()
        self._gather(block0, sep0)

    @graken()
    def _condition_(self):
        self._phenotype_or_variant_()
        self.name_last_node('name')
        with self._optional():
            self._token('=')
            self._integer_()
            self.name_last_node('level')
        self.ast._define(
            ['level', 'name'],
            []
        )

    @graken()
    def _labelled_outcome_group_(self):
        self._token('[')
        self._cut()

        def sep1():
            self._token(',')

        def block1():
            self._labelled_outcome_()
        self._gather(block1, sep1)
        self.name_last_node('tags')
        self._token(']')
        self.ast._define(
            ['tags'],
            []
        )

    @graken()
    def _labelled_outcome_(self):
        self._name_()
        self.name_last_node('key')
        self._token('=')
        self._phenotype_()
        self.name_last_node('name')
        self.ast._define(
            ['key', 'name'],
            []
        )

    @graken()
    def _genotype_(self):
        self._token('g(')
        self._cut()
        self._name_()
        self.name_last_node('variant')
        self._token(')')
        self.ast._define(
            ['variant'],
            []
        )

    @graken()
    def _factor_(self):
        self._token('factor(')
        self._cut()
        self._phenotype_()
        self.name_last_node('phen')
        self._token(')')
        with self._optional():
            self._token('as')
            self._name_()
            self.name_last_node('as_')
        self.ast._define(
            ['as_', 'phen'],
            []
        )

    @graken()
    def _pow_(self):
        self._token('pow(')
        self._cut()
        self._phenotype_()
        self.name_last_node('phen')
        self._token(', ')
        self._cut()
        self._integer_()
        self.name_last_node('power')
        self._token(')')
        with self._optional():
            self._token('as')
            self._name_()
            self.name_last_node('as_')
        self.ast._define(
            ['as_', 'phen', 'power'],
            []
        )

    @graken()
    def _ln_(self):
        self._token('ln(')
        self._cut()
        self._phenotype_()
        self.name_last_node('phen')
        self._token(')')
        with self._optional():
            self._token('as')
            self._name_()
            self.name_last_node('as_')
        self.ast._define(
            ['as_', 'phen'],
            []
        )

    @graken()
    def _log10_(self):
        self._token('log10(')
        self._cut()
        self._phenotype_()
        self.name_last_node('phen')
        self._token(')')
        with self._optional():
            self._token('as')
            self._name_()
            self.name_last_node('as_')
        self.ast._define(
            ['as_', 'phen'],
            []
        )

    @graken()
    def _predictors_(self):

        def sep0():
            self._token('+')

        def block0():
            self._expression_()
        self._positive_gather(block0, sep0)

    @graken()
    def _interaction_(self):
        with self._if():
            with self._group():
                with self._group():
                    with self._choice():
                        with self._option():
                            self._genotype_()
                        with self._option():
                            self._token('factor(')
                            self._name_()
                            self._token(')')
                        with self._option():
                            self._name_()
                        self._error('no available options')
                self._token('*')

        def sep2():
            self._token('*')

        def block2():
            with self._choice():
                with self._option():
                    self._factor_()
                with self._option():
                    self._phenotype_or_variant_()
                self._error('no available options')
        self._gather(block2, sep2)
        self.name_last_node('interaction')
        with self._optional():
            self._token('as')
            self._name_()
            self.name_last_node('as_')
        self.ast._define(
            ['as_', 'interaction'],
            []
        )

    @graken()
    def _SNPs_(self):
        self._token('SNPs')

    @graken()
    def _phenotype_(self):
        self._name_()
        self.name_last_node('name')
        self.ast._define(
            ['name'],
            []
        )

    @graken()
    def _name_(self):
        self._pattern(r'[A-Za-z0-9_:]+')

    @graken()
    def _phenotype_or_variant_(self):
        with self._choice():
            with self._option():
                self._genotype_()
            with self._option():
                self._phenotype_()
            self._error('no available options')

    @graken()
    def _integer_(self):
        self._pattern(r'[0-9]+')
        self.name_last_node('int')
        self.ast._define(
            ['int'],
            []
        )

    @graken()
    def _expression_(self):
        with self._choice():
            with self._option():
                self._SNPs_()
            with self._option():
                self._interaction_()
            with self._option():
                self._genotype_()
            with self._option():
                self._factor_()
            with self._option():
                self._ln_()
            with self._option():
                self._log10_()
            with self._option():
                self._pow_()
            with self._option():
                self._phenotype_()
            self._error('no available options')


class ModelSpecSemantics(object):
    def model(self, ast):
        return ast

    def condition_group(self, ast):
        return ast

    def condition(self, ast):
        return ast

    def labelled_outcome_group(self, ast):
        return ast

    def labelled_outcome(self, ast):
        return ast

    def genotype(self, ast):
        return ast

    def factor(self, ast):
        return ast

    def pow(self, ast):
        return ast

    def ln(self, ast):
        return ast

    def log10(self, ast):
        return ast

    def predictors(self, ast):
        return ast

    def interaction(self, ast):
        return ast

    def SNPs(self, ast):
        return ast

    def phenotype(self, ast):
        return ast

    def name(self, ast):
        return ast

    def phenotype_or_variant(self, ast):
        return ast

    def integer(self, ast):
        return ast

    def expression(self, ast):
        return ast


def main(filename, startrule, **kwargs):
    with open(filename) as f:
        text = f.read()
    parser = ModelSpecParser()
    return parser.parse(text, startrule, filename=filename, **kwargs)


if __name__ == '__main__':
    import json
    from grako.util import asjson

    ast = generic_main(main, ModelSpecParser, name='ModelSpec')
    print('AST:')
    print(ast)
    print()
    print('JSON:')
    print(json.dumps(asjson(ast), indent=2))
    print()
