1from copy import deepcopy, copy
2from typing import Dict, Any, Generic, List
3from ..lexer import Token, LexerThread
4from ..common import ParserCallbacks
5
6from .lalr_analysis import Shift, ParseTableBase, StateT
7from lark.exceptions import UnexpectedToken
8
9###{standalone
10
11class ParseConf(Generic[StateT]):
12 __slots__ = 'parse_table', 'callbacks', 'start', 'start_state', 'end_state', 'states'
13
14 parse_table: ParseTableBase[StateT]
15 callbacks: ParserCallbacks
16 start: str
17
18 start_state: StateT
19 end_state: StateT
20 states: Dict[StateT, Dict[str, tuple]]
21
22 def __init__(self, parse_table: ParseTableBase[StateT], callbacks: ParserCallbacks, start: str):
23 self.parse_table = parse_table
24
25 self.start_state = self.parse_table.start_states[start]
26 self.end_state = self.parse_table.end_states[start]
27 self.states = self.parse_table.states
28
29 self.callbacks = callbacks
30 self.start = start
31
32class ParserState(Generic[StateT]):
33 __slots__ = 'parse_conf', 'lexer', 'state_stack', 'value_stack'
34
35 parse_conf: ParseConf[StateT]
36 lexer: LexerThread
37 state_stack: List[StateT]
38 value_stack: list
39
40 def __init__(self, parse_conf: ParseConf[StateT], lexer: LexerThread, state_stack=None, value_stack=None):
41 self.parse_conf = parse_conf
42 self.lexer = lexer
43 self.state_stack = state_stack or [self.parse_conf.start_state]
44 self.value_stack = value_stack or []
45
46 @property
47 def position(self) -> StateT:
48 return self.state_stack[-1]
49
50 # Necessary for match_examples() to work
51 def __eq__(self, other) -> bool:
52 if not isinstance(other, ParserState):
53 return NotImplemented
54 return len(self.state_stack) == len(other.state_stack) and self.position == other.position
55
56 def __copy__(self):
57 return self.copy()
58
59 def copy(self, deepcopy_values=True) -> 'ParserState[StateT]':
60 return type(self)(
61 self.parse_conf,
62 self.lexer, # XXX copy
63 copy(self.state_stack),
64 deepcopy(self.value_stack) if deepcopy_values else copy(self.value_stack),
65 )
66
67 def feed_token(self, token: Token, is_end=False) -> Any:
68 state_stack = self.state_stack
69 value_stack = self.value_stack
70 states = self.parse_conf.states
71 end_state = self.parse_conf.end_state
72 callbacks = self.parse_conf.callbacks
73
74 while True:
75 state = state_stack[-1]
76 try:
77 action, arg = states[state][token.type]
78 except KeyError:
79 expected = {s for s in states[state].keys() if s.isupper()}
80 raise UnexpectedToken(token, expected, state=self, interactive_parser=None)
81
82 assert arg != end_state
83
84 if action is Shift:
85 # shift once and return
86 assert not is_end
87 state_stack.append(arg)
88 value_stack.append(token if token.type not in callbacks else callbacks[token.type](token))
89 return
90 else:
91 # reduce+shift as many times as necessary
92 rule = arg
93 size = len(rule.expansion)
94 if size:
95 s = value_stack[-size:]
96 del state_stack[-size:]
97 del value_stack[-size:]
98 else:
99 s = []
100
101 value = callbacks[rule](s) if callbacks else s
102
103 _action, new_state = states[state_stack[-1]][rule.origin.name]
104 assert _action is Shift
105 state_stack.append(new_state)
106 value_stack.append(value)
107
108 if is_end and state_stack[-1] == end_state:
109 return value_stack[-1]
110###}