generator.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. # Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved.
  2. # Licensed to PSF under a Contributor Agreement.
  3. # Modifications:
  4. # Copyright David Halter and Contributors
  5. # Modifications are dual-licensed: MIT and PSF.
  6. """
  7. This module defines the data structures used to represent a grammar.
  8. Specifying grammars in pgen is possible with this grammar::
  9. grammar: (NEWLINE | rule)* ENDMARKER
  10. rule: NAME ':' rhs NEWLINE
  11. rhs: items ('|' items)*
  12. items: item+
  13. item: '[' rhs ']' | atom ['+' | '*']
  14. atom: '(' rhs ')' | NAME | STRING
  15. This grammar is self-referencing.
  16. This parser generator (pgen2) was created by Guido Rossum and used for lib2to3.
  17. Most of the code has been refactored to make it more Pythonic. Since this was a
  18. "copy" of the CPython Parser parser "pgen", there was some work needed to make
  19. it more readable. It should also be slightly faster than the original pgen2,
  20. because we made some optimizations.
  21. """
  22. from ast import literal_eval
  23. from typing import TypeVar, Generic, Mapping, Sequence, Set, Union
  24. from parso.pgen2.grammar_parser import GrammarParser, NFAState
  25. _TokenTypeT = TypeVar("_TokenTypeT")
  26. class Grammar(Generic[_TokenTypeT]):
  27. """
  28. Once initialized, this class supplies the grammar tables for the
  29. parsing engine implemented by parse.py. The parsing engine
  30. accesses the instance variables directly.
  31. The only important part in this parsers are dfas and transitions between
  32. dfas.
  33. """
  34. def __init__(self,
  35. start_nonterminal: str,
  36. rule_to_dfas: Mapping[str, Sequence['DFAState[_TokenTypeT]']],
  37. reserved_syntax_strings: Mapping[str, 'ReservedString']):
  38. self.nonterminal_to_dfas = rule_to_dfas
  39. self.reserved_syntax_strings = reserved_syntax_strings
  40. self.start_nonterminal = start_nonterminal
  41. class DFAPlan:
  42. """
  43. Plans are used for the parser to create stack nodes and do the proper
  44. DFA state transitions.
  45. """
  46. def __init__(self, next_dfa: 'DFAState', dfa_pushes: Sequence['DFAState'] = []):
  47. self.next_dfa = next_dfa
  48. self.dfa_pushes = dfa_pushes
  49. def __repr__(self):
  50. return '%s(%s, %s)' % (self.__class__.__name__, self.next_dfa, self.dfa_pushes)
  51. class DFAState(Generic[_TokenTypeT]):
  52. """
  53. The DFAState object is the core class for pretty much anything. DFAState
  54. are the vertices of an ordered graph while arcs and transitions are the
  55. edges.
  56. Arcs are the initial edges, where most DFAStates are not connected and
  57. transitions are then calculated to connect the DFA state machines that have
  58. different nonterminals.
  59. """
  60. def __init__(self, from_rule: str, nfa_set: Set[NFAState], final: NFAState):
  61. assert isinstance(nfa_set, set)
  62. assert isinstance(next(iter(nfa_set)), NFAState)
  63. assert isinstance(final, NFAState)
  64. self.from_rule = from_rule
  65. self.nfa_set = nfa_set
  66. # map from terminals/nonterminals to DFAState
  67. self.arcs: dict[str, DFAState] = {}
  68. # In an intermediary step we set these nonterminal arcs (which has the
  69. # same structure as arcs). These don't contain terminals anymore.
  70. self.nonterminal_arcs: dict[str, DFAState] = {}
  71. # Transitions are basically the only thing that the parser is using
  72. # with is_final. Everyting else is purely here to create a parser.
  73. self.transitions: dict[Union[_TokenTypeT, ReservedString], DFAPlan] = {}
  74. self.is_final = final in nfa_set
  75. def add_arc(self, next_, label):
  76. assert isinstance(label, str)
  77. assert label not in self.arcs
  78. assert isinstance(next_, DFAState)
  79. self.arcs[label] = next_
  80. def unifystate(self, old, new):
  81. for label, next_ in self.arcs.items():
  82. if next_ is old:
  83. self.arcs[label] = new
  84. def __eq__(self, other):
  85. # Equality test -- ignore the nfa_set instance variable
  86. assert isinstance(other, DFAState)
  87. if self.is_final != other.is_final:
  88. return False
  89. # Can't just return self.arcs == other.arcs, because that
  90. # would invoke this method recursively, with cycles...
  91. if len(self.arcs) != len(other.arcs):
  92. return False
  93. for label, next_ in self.arcs.items():
  94. if next_ is not other.arcs.get(label):
  95. return False
  96. return True
  97. def __repr__(self):
  98. return '<%s: %s is_final=%s>' % (
  99. self.__class__.__name__, self.from_rule, self.is_final
  100. )
  101. class ReservedString:
  102. """
  103. Most grammars will have certain keywords and operators that are mentioned
  104. in the grammar as strings (e.g. "if") and not token types (e.g. NUMBER).
  105. This class basically is the former.
  106. """
  107. def __init__(self, value: str):
  108. self.value = value
  109. def __repr__(self):
  110. return '%s(%s)' % (self.__class__.__name__, self.value)
  111. def _simplify_dfas(dfas):
  112. """
  113. This is not theoretically optimal, but works well enough.
  114. Algorithm: repeatedly look for two states that have the same
  115. set of arcs (same labels pointing to the same nodes) and
  116. unify them, until things stop changing.
  117. dfas is a list of DFAState instances
  118. """
  119. changes = True
  120. while changes:
  121. changes = False
  122. for i, state_i in enumerate(dfas):
  123. for j in range(i + 1, len(dfas)):
  124. state_j = dfas[j]
  125. if state_i == state_j:
  126. del dfas[j]
  127. for state in dfas:
  128. state.unifystate(state_j, state_i)
  129. changes = True
  130. break
  131. def _make_dfas(start, finish):
  132. """
  133. Uses the powerset construction algorithm to create DFA states from sets of
  134. NFA states.
  135. Also does state reduction if some states are not needed.
  136. """
  137. # To turn an NFA into a DFA, we define the states of the DFA
  138. # to correspond to *sets* of states of the NFA. Then do some
  139. # state reduction.
  140. assert isinstance(start, NFAState)
  141. assert isinstance(finish, NFAState)
  142. def addclosure(nfa_state, base_nfa_set):
  143. assert isinstance(nfa_state, NFAState)
  144. if nfa_state in base_nfa_set:
  145. return
  146. base_nfa_set.add(nfa_state)
  147. for nfa_arc in nfa_state.arcs:
  148. if nfa_arc.nonterminal_or_string is None:
  149. addclosure(nfa_arc.next, base_nfa_set)
  150. base_nfa_set = set()
  151. addclosure(start, base_nfa_set)
  152. states = [DFAState(start.from_rule, base_nfa_set, finish)]
  153. for state in states: # NB states grows while we're iterating
  154. arcs = {}
  155. # Find state transitions and store them in arcs.
  156. for nfa_state in state.nfa_set:
  157. for nfa_arc in nfa_state.arcs:
  158. if nfa_arc.nonterminal_or_string is not None:
  159. nfa_set = arcs.setdefault(nfa_arc.nonterminal_or_string, set())
  160. addclosure(nfa_arc.next, nfa_set)
  161. # Now create the dfa's with no None's in arcs anymore. All Nones have
  162. # been eliminated and state transitions (arcs) are properly defined, we
  163. # just need to create the dfa's.
  164. for nonterminal_or_string, nfa_set in arcs.items():
  165. for nested_state in states:
  166. if nested_state.nfa_set == nfa_set:
  167. # The DFA state already exists for this rule.
  168. break
  169. else:
  170. nested_state = DFAState(start.from_rule, nfa_set, finish)
  171. states.append(nested_state)
  172. state.add_arc(nested_state, nonterminal_or_string)
  173. return states # List of DFAState instances; first one is start
  174. def _dump_nfa(start, finish):
  175. print("Dump of NFA for", start.from_rule)
  176. todo = [start]
  177. for i, state in enumerate(todo):
  178. print(" State", i, state is finish and "(final)" or "")
  179. for arc in state.arcs:
  180. label, next_ = arc.nonterminal_or_string, arc.next
  181. if next_ in todo:
  182. j = todo.index(next_)
  183. else:
  184. j = len(todo)
  185. todo.append(next_)
  186. if label is None:
  187. print(" -> %d" % j)
  188. else:
  189. print(" %s -> %d" % (label, j))
  190. def _dump_dfas(dfas):
  191. print("Dump of DFA for", dfas[0].from_rule)
  192. for i, state in enumerate(dfas):
  193. print(" State", i, state.is_final and "(final)" or "")
  194. for nonterminal, next_ in state.arcs.items():
  195. print(" %s -> %d" % (nonterminal, dfas.index(next_)))
  196. def generate_grammar(bnf_grammar: str, token_namespace) -> Grammar:
  197. """
  198. ``bnf_text`` is a grammar in extended BNF (using * for repetition, + for
  199. at-least-once repetition, [] for optional parts, | for alternatives and ()
  200. for grouping).
  201. It's not EBNF according to ISO/IEC 14977. It's a dialect Python uses in its
  202. own parser.
  203. """
  204. rule_to_dfas = {}
  205. start_nonterminal = None
  206. for nfa_a, nfa_z in GrammarParser(bnf_grammar).parse():
  207. # _dump_nfa(nfa_a, nfa_z)
  208. dfas = _make_dfas(nfa_a, nfa_z)
  209. # _dump_dfas(dfas)
  210. # oldlen = len(dfas)
  211. _simplify_dfas(dfas)
  212. # newlen = len(dfas)
  213. rule_to_dfas[nfa_a.from_rule] = dfas
  214. # print(nfa_a.from_rule, oldlen, newlen)
  215. if start_nonterminal is None:
  216. start_nonterminal = nfa_a.from_rule
  217. reserved_strings: dict[str, ReservedString] = {}
  218. for nonterminal, dfas in rule_to_dfas.items():
  219. for dfa_state in dfas:
  220. for terminal_or_nonterminal, next_dfa in dfa_state.arcs.items():
  221. if terminal_or_nonterminal in rule_to_dfas:
  222. dfa_state.nonterminal_arcs[terminal_or_nonterminal] = next_dfa
  223. else:
  224. transition = _make_transition(
  225. token_namespace,
  226. reserved_strings,
  227. terminal_or_nonterminal
  228. )
  229. dfa_state.transitions[transition] = DFAPlan(next_dfa)
  230. _calculate_tree_traversal(rule_to_dfas)
  231. return Grammar(start_nonterminal, rule_to_dfas, reserved_strings) # type: ignore[arg-type]
  232. def _make_transition(token_namespace, reserved_syntax_strings, label):
  233. """
  234. Creates a reserved string ("if", "for", "*", ...) or returns the token type
  235. (NUMBER, STRING, ...) for a given grammar terminal.
  236. """
  237. if label[0].isalpha():
  238. # A named token (e.g. NAME, NUMBER, STRING)
  239. return getattr(token_namespace, label)
  240. else:
  241. # Either a keyword or an operator
  242. assert label[0] in ('"', "'"), label
  243. assert not label.startswith('"""') and not label.startswith("'''")
  244. value = literal_eval(label)
  245. try:
  246. return reserved_syntax_strings[value]
  247. except KeyError:
  248. r = reserved_syntax_strings[value] = ReservedString(value)
  249. return r
  250. def _calculate_tree_traversal(nonterminal_to_dfas):
  251. """
  252. By this point we know how dfas can move around within a stack node, but we
  253. don't know how we can add a new stack node (nonterminal transitions).
  254. """
  255. # Map from grammar rule (nonterminal) name to a set of tokens.
  256. first_plans = {}
  257. nonterminals = list(nonterminal_to_dfas.keys())
  258. nonterminals.sort()
  259. for nonterminal in nonterminals:
  260. if nonterminal not in first_plans:
  261. _calculate_first_plans(nonterminal_to_dfas, first_plans, nonterminal)
  262. # Now that we have calculated the first terminals, we are sure that
  263. # there is no left recursion.
  264. for dfas in nonterminal_to_dfas.values():
  265. for dfa_state in dfas:
  266. transitions = dfa_state.transitions
  267. for nonterminal, next_dfa in dfa_state.nonterminal_arcs.items():
  268. for transition, pushes in first_plans[nonterminal].items():
  269. if transition in transitions:
  270. prev_plan = transitions[transition]
  271. # Make sure these are sorted so that error messages are
  272. # at least deterministic
  273. choices = sorted([
  274. (
  275. prev_plan.dfa_pushes[0].from_rule
  276. if prev_plan.dfa_pushes
  277. else prev_plan.next_dfa.from_rule
  278. ),
  279. (
  280. pushes[0].from_rule
  281. if pushes else next_dfa.from_rule
  282. ),
  283. ])
  284. raise ValueError(
  285. "Rule %s is ambiguous; given a %s token, we "
  286. "can't determine if we should evaluate %s or %s."
  287. % (
  288. (
  289. dfa_state.from_rule,
  290. transition,
  291. ) + tuple(choices)
  292. )
  293. )
  294. transitions[transition] = DFAPlan(next_dfa, pushes)
  295. def _calculate_first_plans(nonterminal_to_dfas, first_plans, nonterminal):
  296. """
  297. Calculates the first plan in the first_plans dictionary for every given
  298. nonterminal. This is going to be used to know when to create stack nodes.
  299. """
  300. dfas = nonterminal_to_dfas[nonterminal]
  301. new_first_plans = {}
  302. first_plans[nonterminal] = None # dummy to detect left recursion
  303. # We only need to check the first dfa. All the following ones are not
  304. # interesting to find first terminals.
  305. state = dfas[0]
  306. for transition, next_ in state.transitions.items():
  307. # It's a string. We have finally found a possible first token.
  308. new_first_plans[transition] = [next_.next_dfa]
  309. for nonterminal2, next_ in state.nonterminal_arcs.items():
  310. # It's a nonterminal and we have either a left recursion issue
  311. # in the grammar or we have to recurse.
  312. try:
  313. first_plans2 = first_plans[nonterminal2]
  314. except KeyError:
  315. first_plans2 = _calculate_first_plans(nonterminal_to_dfas, first_plans, nonterminal2)
  316. else:
  317. if first_plans2 is None:
  318. raise ValueError("left recursion for rule %r" % nonterminal)
  319. for t, pushes in first_plans2.items():
  320. new_first_plans[t] = [next_] + pushes
  321. first_plans[nonterminal] = new_first_plans
  322. return new_first_plans