File: async_parser.py

package info (click to toggle)
python-ptk 1.3.8%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 416 kB
  • sloc: python: 3,616; makefile: 200
file content (102 lines) | stat: -rw-r--r-- 3,063 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# -*- coding: UTF-8 -*-

# (c) Jérôme Laheurte 2015-2019
# See LICENSE.txt

# XXXTODO: when pylint supports async, remove this...
# pylint: skip-file

from ptk.parser import production, LRParser, ProductionParser, leftAssoc, rightAssoc, nonAssoc, ParseError, _Accept, _Reduce, _Shift


class _AsyncShift(_Shift):
    async def asyncDoAction(self, grammar, stack, tok):
        return self.doAction(grammar, stack, tok)


class _AsyncReduce(_Reduce):
    async def asyncDoAction(self, grammar, stack, tok):
        callback, kwargs = self._getCallback(stack)
        prodVal = await callback(grammar, **kwargs)
        self._applied(grammar, stack, prodVal)
        return False


class AsyncProductionParser(ProductionParser):
    def _wrapCallbackNone(self, name, prod):
        previous = prod.callback
        async def callback(*args, **kwargs):
            kwargs[name] = None
            return await previous(*args, **kwargs)
        prod.callback = callback

    def _wrapCallbackEmpty(self, name, prod):
        previous = prod.callback
        async def cbEmpty(*args, **kwargs):
            if name is not None:
                kwargs[name] = []
            return await previous(*args, **kwargs)
        prod.callback = cbEmpty

    def _wrapCallbackOne(self):
        async def cbOne(_, item):
            return [item]
        return cbOne

    def _wrapCallbackNext(self):
        async def cbNext(_, items, item):
            items.append(item)
            return items
        return cbNext


def asyncCallbackByName(name):
    async def _wrapper(instance, *args, **kwargs):
        return await getattr(instance, name)(*args, **kwargs)
    return _wrapper


class AsyncLRParser(LRParser):
    """
    This class works like :py:class:`LRParser` but supports
    asynchronous methods (new in Python 3.5). You must use
    :py:class:`AsyncLexer` in conjuction with it:

    .. code-block:: python

    class Parser(AsyncLRParser, AsyncLexer):
        # ...

    And only use :py:func:`AsyncLexer.asyncFeed` to feed it the input
    stream. Semantic actions must be asynchronous methods as
    well. When the start symbol is reduced, the
    :py:func:`asyncNewSentence` method is awaited.
    """

    async def asyncNewToken(self, tok):
        try:
            for action, stack in self._processToken(tok):
                if await action.asyncDoAction(self, stack, tok):
                    break
        except _Accept as exc:
            self._restartParser()
            await self.asyncNewSentence(exc.result)
            return exc.result

    async def asyncNewSentence(self, result):
       """
       Awaited when the start symbol is reached.
       """
       raise NotImplementedError

    @classmethod
    def _createProductionParser(cls, name, priority, attrs):
        return AsyncProductionParser(asyncCallbackByName(name), priority, cls, attrs)

    @classmethod
    def _createShiftAction(cls, state):
        return _AsyncShift(state)

    @classmethod
    def _createReduceAction(cls, item):
        return _AsyncReduce(item)