You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			111 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			111 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Python
		
	
from copy import deepcopy, copy
 | 
						|
from typing import Dict, Any, Generic, List
 | 
						|
from ..lexer import Token, LexerThread
 | 
						|
from ..common import ParserCallbacks
 | 
						|
 | 
						|
from .lalr_analysis import Shift, ParseTableBase, StateT
 | 
						|
from lark.exceptions import UnexpectedToken
 | 
						|
 | 
						|
###{standalone
 | 
						|
 | 
						|
class ParseConf(Generic[StateT]):
 | 
						|
    __slots__ = 'parse_table', 'callbacks', 'start', 'start_state', 'end_state', 'states'
 | 
						|
 | 
						|
    parse_table: ParseTableBase[StateT]
 | 
						|
    callbacks: ParserCallbacks
 | 
						|
    start: str
 | 
						|
 | 
						|
    start_state: StateT
 | 
						|
    end_state: StateT
 | 
						|
    states: Dict[StateT, Dict[str, tuple]]
 | 
						|
 | 
						|
    def __init__(self, parse_table: ParseTableBase[StateT], callbacks: ParserCallbacks, start: str):
 | 
						|
        self.parse_table = parse_table
 | 
						|
 | 
						|
        self.start_state = self.parse_table.start_states[start]
 | 
						|
        self.end_state = self.parse_table.end_states[start]
 | 
						|
        self.states = self.parse_table.states
 | 
						|
 | 
						|
        self.callbacks = callbacks
 | 
						|
        self.start = start
 | 
						|
 | 
						|
class ParserState(Generic[StateT]):
 | 
						|
    __slots__ = 'parse_conf', 'lexer', 'state_stack', 'value_stack'
 | 
						|
 | 
						|
    parse_conf: ParseConf[StateT]
 | 
						|
    lexer: LexerThread
 | 
						|
    state_stack: List[StateT]
 | 
						|
    value_stack: list
 | 
						|
 | 
						|
    def __init__(self, parse_conf: ParseConf[StateT], lexer: LexerThread, state_stack=None, value_stack=None):
 | 
						|
        self.parse_conf = parse_conf
 | 
						|
        self.lexer = lexer
 | 
						|
        self.state_stack = state_stack or [self.parse_conf.start_state]
 | 
						|
        self.value_stack = value_stack or []
 | 
						|
 | 
						|
    @property
 | 
						|
    def position(self) -> StateT:
 | 
						|
        return self.state_stack[-1]
 | 
						|
 | 
						|
    # Necessary for match_examples() to work
 | 
						|
    def __eq__(self, other) -> bool:
 | 
						|
        if not isinstance(other, ParserState):
 | 
						|
            return NotImplemented
 | 
						|
        return len(self.state_stack) == len(other.state_stack) and self.position == other.position
 | 
						|
 | 
						|
    def __copy__(self):
 | 
						|
        return self.copy()
 | 
						|
 | 
						|
    def copy(self, deepcopy_values=True) -> 'ParserState[StateT]':
 | 
						|
        return type(self)(
 | 
						|
            self.parse_conf,
 | 
						|
            self.lexer, # XXX copy
 | 
						|
            copy(self.state_stack),
 | 
						|
            deepcopy(self.value_stack) if deepcopy_values else copy(self.value_stack),
 | 
						|
        )
 | 
						|
 | 
						|
    def feed_token(self, token: Token, is_end=False) -> Any:
 | 
						|
        state_stack = self.state_stack
 | 
						|
        value_stack = self.value_stack
 | 
						|
        states = self.parse_conf.states
 | 
						|
        end_state = self.parse_conf.end_state
 | 
						|
        callbacks = self.parse_conf.callbacks
 | 
						|
 | 
						|
        while True:
 | 
						|
            state = state_stack[-1]
 | 
						|
            try:
 | 
						|
                action, arg = states[state][token.type]
 | 
						|
            except KeyError:
 | 
						|
                expected = {s for s in states[state].keys() if s.isupper()}
 | 
						|
                raise UnexpectedToken(token, expected, state=self, interactive_parser=None)
 | 
						|
 | 
						|
            assert arg != end_state
 | 
						|
 | 
						|
            if action is Shift:
 | 
						|
                # shift once and return
 | 
						|
                assert not is_end
 | 
						|
                state_stack.append(arg)
 | 
						|
                value_stack.append(token if token.type not in callbacks else callbacks[token.type](token))
 | 
						|
                return
 | 
						|
            else:
 | 
						|
                # reduce+shift as many times as necessary
 | 
						|
                rule = arg
 | 
						|
                size = len(rule.expansion)
 | 
						|
                if size:
 | 
						|
                    s = value_stack[-size:]
 | 
						|
                    del state_stack[-size:]
 | 
						|
                    del value_stack[-size:]
 | 
						|
                else:
 | 
						|
                    s = []
 | 
						|
 | 
						|
                value = callbacks[rule](s) if callbacks else s
 | 
						|
 | 
						|
                _action, new_state = states[state_stack[-1]][rule.origin.name]
 | 
						|
                assert _action is Shift
 | 
						|
                state_stack.append(new_state)
 | 
						|
                value_stack.append(value)
 | 
						|
 | 
						|
                if is_end and state_stack[-1] == end_state:
 | 
						|
                    return value_stack[-1]
 | 
						|
###}
 |