# Path: pydsl/parser/parser.py
# class BottomUpParser(Parser):
#     """ leaf to root parser"""
#     def __init__(self, bnfgrammar):
#         self._lexer = lexer_factory(bnfgrammar.alphabet, ascii_encoding)
#         super().__init__(bnfgrammar)
# 
# Path: pydsl/grammar/symbol.py
# class NonTerminalSymbol(str, Symbol):
#     def __init__(self, name):
#         Symbol.__init__(self)
# 
#     def __str__(self):
#         return "<NonTS: " + self + ">"
# 
#     def __hash__(self):
#         return str.__hash__(self)
# 
#     def __eq__(self, other):
#         if not isinstance(other, NonTerminalSymbol):
#             return False
#         return str.__eq__(self,other)
# 
# class TerminalSymbol(Symbol):
# 
#     def __init__(self, gd):
#         if not isinstance(gd, Grammar):
#             raise TypeError("Expected Grammar, got %s" % (gd,))
#         Symbol.__init__(self)
#         if not gd:
#             raise Exception
#         self.gd = gd
# 
#     def __hash__(self):
#         return hash(self.gd)
# 
#     def check(self, data):# ->bool:
#         """Checks if input is recognized as this symbol"""
#         return check(self.gd, data)
# 
#     def first(self):
#         return self.gd.first
# 
#     def __eq__(self, other):
#         """StringTerminalSymbol are equals if definition and names are equal"""
#         try:
#             return self.gd == other.gd
#         except AttributeError:
#             return False
# 
#     def __str__(self):
#         return "<TS: " + str(self.gd) + ">"
# 
# class EndSymbol(Symbol):
#     _instance = None
#     def __new__(cls):
#         if cls._instance is None:
#             cls._instance = super(EndSymbol, cls).__new__(cls)
#         return cls._instance
# 
#     def __hash__(self):
#         assert(EndSymbol._instance is not None)
#         return hash(id(self._instance))
# 
#     def __eq__(self, other):
#         result = isinstance(other, EndSymbol) or EndSymbol == other
#         return result
# 
#     def __bool__(self):
#         return False
# 
#     def __str__(self):
#         return "$"
# 
# class Symbol(object):
#     pass
# 
# Path: pydsl/grammar/BNF.py
# class Production(object):
# 
#     def __init__(self, leftside, rightside):
#         # Left side must have at least one non terminal symbol
#         for element in rightside:
#             if not isinstance(element, Symbol):
#                 raise TypeError
#         self.leftside = tuple(leftside)
#         self.rightside = tuple(rightside)
# 
#     def __str__(self):
#         leftstr = " ".join([x for x in self.leftside])
#         rightstr = " ".join([str(x) for x in self.rightside])
#         return leftstr + "::=" + rightstr
# 
#     def __eq__(self, other):
#         try:
#             if len(self.leftside) != len(other.leftside):
#                 return False
#             if len(self.rightside) != len(other.rightside):
#                 return False
#             if not list_eq(self.leftside, other.leftside):
#                 return False
#             if not list_eq(self.rightside, other.rightside):
#                 return False
#         except AttributeError:
#             return False
#         return True
# 
#     def __hash__(self):
#         return hash(self.leftside) & hash(self.rightside)
# 
# Path: pydsl/grammar/definition.py
# class Grammar(object):
# 
#     def __init__(self, base_alphabet = None):
#         self.__base_alphabet = base_alphabet
# 
#     def enum(self):
#         """Generates every possible accepted string"""
#         raise NotImplementedError
# 
#     @property
#     def first(self):
#         """Alphabet that matches every possible first element.
#         the returned value is a subset of the base_alphabet"""
#         return self.alphabet
# 
#     @property
#     def minsize(self):# -> int:
#         """Returns the minimum size in alphabet tokens"""
#         return 0
# 
#     @property
#     def maxsize(self):
#         """Returns the max size in alphabet tokens"""
#         return None
# 
#     @property
#     def alphabet(self):
#         if not self.__base_alphabet:
#             raise AttributeError
#         return self.__base_alphabet


import logging
    import copy
from pydsl.parser.parser import BottomUpParser
from pydsl.grammar.symbol import NonTerminalSymbol, TerminalSymbol, EndSymbol, Symbol
from pydsl.grammar.BNF import Production
from pydsl.grammar.definition import Grammar
from collections import Iterable, defaultdict
        from pydsl.check import check
                        else:
                            raise TypeError(x)
                    numberoptions += 1
                #if cursor is at the end of main rule, and current symbol is end, then append accept rule
                if symbol == EndSymbol() and lritem.previous_symbol() == productionset.initialsymbol and lritem.next_symbol() == EndSymbol():
                    result.append(itemindex, symbol, "Accept", None)
                    numberoptions += 1
            if not numberoptions:
                LOG.info("No rule found to generate a new parsertable entry ")
                LOG.debug("symbol: " + str(symbol))
                LOG.debug("itemset: " + str(itemset))
            elif numberoptions > 1: #FIXME can it count duplicated entries?
                raise Exception("LR Conflict %s" % symbol)
    return result
    
class ParserTable(defaultdict):
    """ Stores a state/symbol/action/new state relation """
    def __init__(self):
        defaultdict.__init__(self, lambda: defaultdict(lambda:{"action":"Fail"}))

    def append(self, state, symbol, action, destinationstate, production = None):
        """Appends a new rule"""
        if action not in (None, "Accept", "Shift", "Reduce"):
            raise TypeError
        rule = {"action":action, "dest":destinationstate}
        if action == "Reduce":
            if rule is None:
                raise TypeError("Expected production parameter")
            rule["rule"] = production
        while isinstance(symbol, TerminalSymbol) and isinstance(symbol.gd, Iterable) and len(symbol.gd) == 1 and isinstance(list(symbol.gd)[0], Grammar):

# Path: pydsl/parser/parser.py
# class BottomUpParser(Parser):
#     """ leaf to root parser"""
#     def __init__(self, bnfgrammar):
#         self._lexer = lexer_factory(bnfgrammar.alphabet, ascii_encoding)
#         super().__init__(bnfgrammar)
# 
# Path: pydsl/grammar/symbol.py
# class NonTerminalSymbol(str, Symbol):
#     def __init__(self, name):
#         Symbol.__init__(self)
# 
#     def __str__(self):
#         return "<NonTS: " + self + ">"
# 
#     def __hash__(self):
#         return str.__hash__(self)
# 
#     def __eq__(self, other):
#         if not isinstance(other, NonTerminalSymbol):
#             return False
#         return str.__eq__(self,other)
# 
# class TerminalSymbol(Symbol):
# 
#     def __init__(self, gd):
#         if not isinstance(gd, Grammar):
#             raise TypeError("Expected Grammar, got %s" % (gd,))
#         Symbol.__init__(self)
#         if not gd:
#             raise Exception
#         self.gd = gd
# 
#     def __hash__(self):
#         return hash(self.gd)
# 
#     def check(self, data):# ->bool:
#         """Checks if input is recognized as this symbol"""
#         return check(self.gd, data)
# 
#     def first(self):
#         return self.gd.first
# 
#     def __eq__(self, other):
#         """StringTerminalSymbol are equals if definition and names are equal"""
#         try:
#             return self.gd == other.gd
#         except AttributeError:
#             return False
# 
#     def __str__(self):
#         return "<TS: " + str(self.gd) + ">"
# 
# class EndSymbol(Symbol):
#     _instance = None
#     def __new__(cls):
#         if cls._instance is None:
#             cls._instance = super(EndSymbol, cls).__new__(cls)
#         return cls._instance
# 
#     def __hash__(self):
#         assert(EndSymbol._instance is not None)
#         return hash(id(self._instance))
# 
#     def __eq__(self, other):
#         result = isinstance(other, EndSymbol) or EndSymbol == other
#         return result
# 
#     def __bool__(self):
#         return False
# 
#     def __str__(self):
#         return "$"
# 
# class Symbol(object):
#     pass
# 
# Path: pydsl/grammar/BNF.py
# class Production(object):
# 
#     def __init__(self, leftside, rightside):
#         # Left side must have at least one non terminal symbol
#         for element in rightside:
#             if not isinstance(element, Symbol):
#                 raise TypeError
#         self.leftside = tuple(leftside)
#         self.rightside = tuple(rightside)
# 
#     def __str__(self):
#         leftstr = " ".join([x for x in self.leftside])
#         rightstr = " ".join([str(x) for x in self.rightside])
#         return leftstr + "::=" + rightstr
# 
#     def __eq__(self, other):
#         try:
#             if len(self.leftside) != len(other.leftside):
#                 return False
#             if len(self.rightside) != len(other.rightside):
#                 return False
#             if not list_eq(self.leftside, other.leftside):
#                 return False
#             if not list_eq(self.rightside, other.rightside):
#                 return False
#         except AttributeError:
#             return False
#         return True
# 
#     def __hash__(self):
#         return hash(self.leftside) & hash(self.rightside)
# 
# Path: pydsl/grammar/definition.py
# class Grammar(object):
# 
#     def __init__(self, base_alphabet = None):
#         self.__base_alphabet = base_alphabet
# 
#     def enum(self):
#         """Generates every possible accepted string"""
#         raise NotImplementedError
# 
#     @property
#     def first(self):
#         """Alphabet that matches every possible first element.
#         the returned value is a subset of the base_alphabet"""
#         return self.alphabet
# 
#     @property
#     def minsize(self):# -> int:
#         """Returns the minimum size in alphabet tokens"""
#         return 0
# 
#     @property
#     def maxsize(self):
#         """Returns the max size in alphabet tokens"""
#         return None
# 
#     @property
#     def alphabet(self):
#         if not self.__base_alphabet:
#             raise AttributeError
#         return self.__base_alphabet


# Path: pydsl/parser/LR0.py
import logging
    import copy
from pydsl.parser.parser import BottomUpParser
from pydsl.grammar.symbol import NonTerminalSymbol, TerminalSymbol, EndSymbol, Symbol
from pydsl.grammar.BNF import Production
from pydsl.grammar.definition import Grammar
from collections import Iterable, defaultdict
        from pydsl.check import check

                        else:
                            raise TypeError(x)
                    numberoptions += 1
                #if cursor is at the end of main rule, and current symbol is end, then append accept rule
                if symbol == EndSymbol() and lritem.previous_symbol() == productionset.initialsymbol and lritem.next_symbol() == EndSymbol():
                    result.append(itemindex, symbol, "Accept", None)
                    numberoptions += 1
            if not numberoptions:
                LOG.info("No rule found to generate a new parsertable entry ")
                LOG.debug("symbol: " + str(symbol))
                LOG.debug("itemset: " + str(itemset))
            elif numberoptions > 1: #FIXME can it count duplicated entries?
                raise Exception("LR Conflict %s" % symbol)
    return result
    
class ParserTable(defaultdict):
    """ Stores a state/symbol/action/new state relation """
    def __init__(self):
        defaultdict.__init__(self, lambda: defaultdict(lambda:{"action":"Fail"}))

    def append(self, state, symbol, action, destinationstate, production = None):
        """Appends a new rule"""
        if action not in (None, "Accept", "Shift", "Reduce"):
            raise TypeError
        rule = {"action":action, "dest":destinationstate}
        if action == "Reduce":
            if rule is None:
                raise TypeError("Expected production parameter")
            rule["rule"] = production
        while isinstance(symbol, TerminalSymbol) and isinstance(symbol.gd, Iterable) and len(symbol.gd) == 1 and isinstance(list(symbol.gd)[0], Grammar):

            symbol = TerminalSymbol(list(symbol.gd)[0]) #Reduces symbol if its gd is a Sequence/Choice of 1 element