Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/lark/parsers/lalr_parser_state.py: 97%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

76 statements  

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###}