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

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


from __future__ import generator_stop

import sys

from tatsu.buffering import Buffer
from tatsu.parsing import Parser
from tatsu.parsing import tatsumasu, leftrec, nomemo
from tatsu.parsing import leftrec, nomemo  # noqa
from tatsu.util import re, generic_main  # noqa


KEYWORDS = {}  # type: ignore


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


class WeightedFormulaParser(Parser):
    def __init__(
        self,
        whitespace=None,
        nameguard=None,
        comments_re=None,
        eol_comments_re=None,
        ignorecase=None,
        left_recursion=True,
        parseinfo=True,
        keywords=None,
        namechars='',
        tokenizercls=WeightedFormulaBuffer,
        **kwargs
    ):
        if keywords is None:
            keywords = KEYWORDS
        super().__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,
            tokenizercls=tokenizercls,
            **kwargs
        )

    @tatsumasu()
    @nomemo
    def _start_(self):  # noqa
        self._expression_()
        self._check_eof()

    @tatsumasu()
    @leftrec
    def _expression_(self):  # noqa
        with self._choice():
            with self._option():
                self._expression_()
                self._token('+')
                self._term_()
            with self._option():
                self._term_()
            self._error('expecting one of: expression factor term')

    @tatsumasu()
    @leftrec
    def _term_(self):  # noqa
        with self._choice():
            with self._option():
                self._term_()
                self._token('*')
                self._factor_()
            with self._option():
                self._factor_()
            self._error('expecting one of: ( factor number term var')

    @tatsumasu()
    def _factor_(self):  # noqa
        with self._choice():
            with self._option():
                self._token('(')
                self._expression_()
                self._token(')')
            with self._option():
                self._number_()
            with self._option():
                self._var_()
            self._error('expecting one of: ( /#\\([^\\(+*,\\)]*\\)/ /[a-z][^\\(+*,\\)]*/ not  number var')

    @tatsumasu()
    def _var_(self):  # noqa
        with self._optional():
            self._token('not ')
        self._pattern('[a-z][^\\(+*,\\)]*')
        with self._optional():
            self._pattern('\\([^\\(+*\\)]*\\)')

    @tatsumasu()
    def _number_(self):  # noqa
        self._pattern('#\\([^\\(+*,\\)]*\\)')


class WeightedFormulaSemantics(object):
    def __init__(self, app):
        self._app = app

    def var2idx(self, var):
        return self._app.var2idx(var)

    def new_var(self):
        return self._app.new_var("")

    def clause_writer(self, p, c1 = 0, c2 = 0, connective = 0):
        return self._app.clause_writer(p, c1 = c1, c2 = c2, connective = connective)

    def start(self, ast):  # noqa
        self._app._clauses.append([ast])
        return ast

    def expression(self, ast):  # noqa
        if type(ast) == tuple and "+" in ast:
            n_var = self.new_var()
            self._app.clause_writer(n_var, c1 = ast[0], c2 = ast[2], connective = 5)
            return n_var
        return ast

    def term(self, ast):  # noqa
        if type(ast) == tuple and "*" in ast:
            n_var = self.new_var()
            self._app.clause_writer(n_var, c1 = ast[0], c2 = ast[2], connective = 4)
            return n_var
        return ast

    def factor(self, ast):  # noqa
        if type(ast) == tuple and ast[0] == "(":
            ast = ast[1]
        return ast

    def var(self, ast):  # noqa
        if type(ast) == tuple:
            act = ""
            for i in range(len(ast)):
                act += ast[i]
            ast = act
        if len(ast) > 3 and ast[:3] == "not":
            idx = -self.var2idx(ast[:3])
            # if the variable was optimized away, we know it is false
            if idx == 0:
                return self.number("#(1)")
        else:
            idx = self.var2idx(ast)
            # if the variable was optimized away, we know it is false
            if idx == 0:
                return self.number("#(0)")
        n_var = self.new_var()
        self._app._clauses.append([-n_var, idx])
        return n_var

    def number(self, ast):  # noqa
        n_var = self.new_var()
        self._app._weights[n_var] = ast[2:-1]
        return n_var
