Beispiel #1
0
 def P2(self):
     # 'name' is replaced in newSentence()
     return [
         Production(None,
                    self.callback,
                    priority=self.priority,
                    attributes=self.attributes)
     ]
Beispiel #2
0
class ProductionTestCase(unittest.TestCase):
    def setUp(self):
        # A -> B<b> C
        self.production = Production('A', self.callback)
        self.production.addSymbol('B', 'b')
        self.production.addSymbol('C')
        self.calls = list()

    def callback(self, grammar, **kwargs):
        self.calls.append(kwargs)
        return 42

    def test_duplicate(self):
        try:
            self.production.addSymbol('D', 'b')
        except GrammarError:
            pass
        else:
            self.fail()

    def test_kwargs(self):
        cb, kwargs = self.production.apply([1, 2], None)
        cb(self, **kwargs)
        self.assertEqual(self.calls, [{'b': 1}])
Beispiel #3
0
    def __addList(self, productions, prod, symbol, name, allowEmpty, sep):
        class ListSymbol(metaclass=Singleton):
            __reprval__ = 'List(%s, "%s")' % (symbol,
                                              '*' if allowEmpty else '+')

        if allowEmpty:
            clone = prod.cloned()
            self._wrapCallbackEmpty(name, clone)
            productions.append(clone)

        prod.addSymbol(ListSymbol, name=name)
        productions.append(prod)

        listProd = Production(ListSymbol, self._wrapCallbackOne())
        listProd.addSymbol(symbol, name='item')
        productions.append(listProd)

        listProd = Production(ListSymbol, self._wrapCallbackNext())
        listProd.addSymbol(ListSymbol, name='items')
        if sep is not None:
            listProd.addSymbol(sep)
        listProd.addSymbol(symbol, name='item')
        productions.append(listProd)
Beispiel #4
0
    def prepare(cls, **kwargs):  # pylint: disable=R0915
        # Obviously cannot use @production here

        # When mixing async and sync parsers in the same program this may be called twice,
        # because AsyncProductionParser inherits from ProductionParser
        if cls.productions():
            return

        # DECL -> identifier "->" PRODS
        prod = Production('DECL', cls.DECL)
        prod.addSymbol('LEFT', 'left')
        prod.addSymbol('arrow')
        prod.addSymbol('PRODS', 'prods')
        cls.__productions__.append(prod)

        # LEFT -> identifier
        prod = Production('LEFT', cls.LEFT)
        prod.addSymbol('identifier', 'name')
        cls.__productions__.append(prod)

        # LEFT -> identifier "<" posarg ">"
        prod = Production('LEFT', cls.LEFT)
        prod.addSymbol('identifier', 'name')
        prod.addSymbol('lchev')
        prod.addSymbol('identifier', 'posarg')
        prod.addSymbol('rchev')
        cls.__productions__.append(prod)

        # PRODS -> P
        prod = Production('PRODS', cls.PRODS1)
        prod.addSymbol('P', 'prodlist')
        cls.__productions__.append(prod)

        # PRODS -> PRODS "|" P
        prod = Production('PRODS', cls.PRODS2)
        prod.addSymbol('PRODS', 'prods')
        prod.addSymbol('union')
        prod.addSymbol('P', 'prodlist')
        cls.__productions__.append(prod)

        # P -> P SYM
        prod = Production('P', cls.P1)
        prod.addSymbol('P', 'prodlist')
        prod.addSymbol('SYM', 'sym')
        cls.__productions__.append(prod)

        # P -> ɛ
        prod = Production('P', cls.P2)
        cls.__productions__.append(prod)

        # SYM -> SYMNAME PROPERTIES
        prod = Production('SYM', cls.SYM)
        prod.addSymbol('SYMNAME', 'symname')
        prod.addSymbol('PROPERTIES', 'properties')
        cls.__productions__.append(prod)

        # SYM -> SYMNAME repeat PROPERTIES
        prod = Production('SYM', cls.SYMREP)
        prod.addSymbol('SYMNAME', 'symname')
        prod.addSymbol('repeat', 'repeat')
        prod.addSymbol('PROPERTIES', 'properties')
        cls.__productions__.append(prod)

        # SYM -> SYMNAME repeat lparen identifier rparen PROPERTIES
        prod = Production('SYM', cls.SYMREP)
        prod.addSymbol('SYMNAME', 'symname')
        prod.addSymbol('repeat', 'repeat')
        prod.addSymbol('lparen')
        prod.addSymbol('identifier', 'separator')
        prod.addSymbol('rparen')
        prod.addSymbol('PROPERTIES', 'properties')
        cls.__productions__.append(prod)

        # SYM -> SYMNAME repeat lparen litteral rparen PROPERTIES
        prod = Production('SYM', cls.SYMREP_LIT)
        prod.addSymbol('SYMNAME', 'symname')
        prod.addSymbol('repeat', 'repeat')
        prod.addSymbol('lparen')
        prod.addSymbol('litteral', 'separator')
        prod.addSymbol('rparen')
        prod.addSymbol('PROPERTIES', 'properties')
        cls.__productions__.append(prod)

        # SYMNAME -> identifier
        prod = Production('SYMNAME', cls.SYMNAME1)
        prod.addSymbol('identifier', 'identifier')
        cls.__productions__.append(prod)

        # SYMNAME -> litteral
        prod = Production('SYMNAME', cls.SYMNAME2)
        prod.addSymbol('litteral', 'litteral')
        cls.__productions__.append(prod)

        # PROPERTIES -> ɛ
        prod = Production('PROPERTIES', cls.PROPERTIES1)
        cls.__productions__.append(prod)

        # PROPERTIES -> lchev identifier rchev
        prod = Production('PROPERTIES', cls.PROPERTIES2)
        prod.addSymbol('lchev')
        prod.addSymbol('identifier', 'name')
        prod.addSymbol('rchev')
        cls.__productions__.append(prod)

        super().prepare(**kwargs)
Beispiel #5
0
    def prepare(cls):
        for prod in cls.productions():
            if prod.name is _StartState:
                break
        else:

            def acceptor(_, result):
                raise _Accept(result)

            prod = Production(_StartState, acceptor)
            prod.addSymbol(cls._defaultStartSymbol()
                           if cls.startSymbol is None else cls.startSymbol,
                           name='result')
            cls.__productions__.insert(0, prod)

        cls.startSymbol = _StartState
        super().prepare()

        states, goto = cls.__computeStates(prod)
        reachable = cls.__computeActions(states, goto)

        logger = logging.getLogger('LRParser')
        cls.__resolveConflicts(logger)

        usedTokens = set([
            symbol for state, symbol in cls.__actions__.keys()
            if symbol is not EOF
        ])
        if usedTokens != cls.tokenTypes():  # pragma: no cover
            logger.warning(
                'The following tokens are not used: %s', ','.join([
                    repr(sym) for sym in sorted(cls.tokenTypes() - usedTokens)
                ]))

        if reachable != cls.nonterminals():  # pragma: no cover
            logger.warning(
                'The following nonterminals are not reachable: %s', ','.join([
                    repr(sym) for sym in sorted(cls.nonterminals() - reachable)
                ]))

        # Reductions only need goto entries for nonterminals
        cls._goto = dict([((state, symbol), newState)
                          for (state, symbol), newState in goto.items()
                          if symbol not in cls.tokenTypes()])

        parts = list()
        if cls.nSR:
            parts.append('%d shift/reduce conflicts' % cls.nSR)
        if cls.nRR:
            parts.append('%d reduce/reduce conflicts' % cls.nRR)
        if parts:
            logger.warning(', '.join(parts))

        # Cast to tuple because sets are not totally ordered
        for index, state in enumerate([tuple(cls._startState)] + sorted(
            [tuple(state) for state in states if state != cls._startState])):
            logger.debug('State %d', index)
            for item in sorted(state):
                logger.debug('    %s', item)
                item.index = index
            cls.__lrstates__.append(sorted(state))
        logger.info('%d states.', len(states))
Beispiel #6
0
 def setUp(self):
     # A -> B<b> C
     self.production = Production('A', self.callback)
     self.production.addSymbol('B', 'b')
     self.production.addSymbol('C')
     self.calls = list()