]> git.madduck.net Git - etc/vim.git/blob - blib2to3/pgen2/grammar.py

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

minor performance improvement (~2% speedup in unit tests) (#858)
[etc/vim.git] / blib2to3 / pgen2 / grammar.py
1 # Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved.
2 # Licensed to PSF under a Contributor Agreement.
3
4 """This module defines the data structures used to represent a grammar.
5
6 These are a bit arcane because they are derived from the data
7 structures used by Python's 'pgen' parser generator.
8
9 There's also a table here mapping operators to their names in the
10 token module; the Python tokenize module reports all operators as the
11 fallback token code OP, but the parser needs the actual token code.
12
13 """
14
15 # Python imports
16 import os
17 import pickle
18 import tempfile
19
20 # Local imports
21 from . import token
22
23
24 class Grammar(object):
25     """Pgen parsing tables conversion class.
26
27     Once initialized, this class supplies the grammar tables for the
28     parsing engine implemented by parse.py.  The parsing engine
29     accesses the instance variables directly.  The class here does not
30     provide initialization of the tables; several subclasses exist to
31     do this (see the conv and pgen modules).
32
33     The load() method reads the tables from a pickle file, which is
34     much faster than the other ways offered by subclasses.  The pickle
35     file is written by calling dump() (after loading the grammar
36     tables using a subclass).  The report() method prints a readable
37     representation of the tables to stdout, for debugging.
38
39     The instance variables are as follows:
40
41     symbol2number -- a dict mapping symbol names to numbers.  Symbol
42                      numbers are always 256 or higher, to distinguish
43                      them from token numbers, which are between 0 and
44                      255 (inclusive).
45
46     number2symbol -- a dict mapping numbers to symbol names;
47                      these two are each other's inverse.
48
49     states        -- a list of DFAs, where each DFA is a list of
50                      states, each state is a list of arcs, and each
51                      arc is a (i, j) pair where i is a label and j is
52                      a state number.  The DFA number is the index into
53                      this list.  (This name is slightly confusing.)
54                      Final states are represented by a special arc of
55                      the form (0, j) where j is its own state number.
56
57     dfas          -- a dict mapping symbol numbers to (DFA, first)
58                      pairs, where DFA is an item from the states list
59                      above, and first is a set of tokens that can
60                      begin this grammar rule (represented by a dict
61                      whose values are always 1).
62
63     labels        -- a list of (x, y) pairs where x is either a token
64                      number or a symbol number, and y is either None
65                      or a string; the strings are keywords.  The label
66                      number is the index in this list; label numbers
67                      are used to mark state transitions (arcs) in the
68                      DFAs.
69
70     start         -- the number of the grammar's start symbol.
71
72     keywords      -- a dict mapping keyword strings to arc labels.
73
74     tokens        -- a dict mapping token numbers to arc labels.
75
76     """
77
78     def __init__(self):
79         self.symbol2number = {}
80         self.number2symbol = {}
81         self.states = []
82         self.dfas = {}
83         self.labels = [(0, "EMPTY")]
84         self.keywords = {}
85         self.tokens = {}
86         self.symbol2label = {}
87         self.start = 256
88         # Python 3.7+ parses async as a keyword, not an identifier
89         self.async_keywords = False
90
91     def dump(self, filename):
92         """Dump the grammar tables to a pickle file."""
93         with tempfile.NamedTemporaryFile(dir=os.path.dirname(filename), delete=False) as f:
94             pickle.dump(self.__dict__, f, pickle.HIGHEST_PROTOCOL)
95         os.replace(f.name, filename)
96
97     def load(self, filename):
98         """Load the grammar tables from a pickle file."""
99         with open(filename, "rb") as f:
100             d = pickle.load(f)
101         self.__dict__.update(d)
102
103     def loads(self, pkl):
104         """Load the grammar tables from a pickle bytes object."""
105         self.__dict__.update(pickle.loads(pkl))
106
107     def copy(self):
108         """
109         Copy the grammar.
110         """
111         new = self.__class__()
112         for dict_attr in ("symbol2number", "number2symbol", "dfas", "keywords",
113                           "tokens", "symbol2label"):
114             setattr(new, dict_attr, getattr(self, dict_attr).copy())
115         new.labels = self.labels[:]
116         new.states = self.states[:]
117         new.start = self.start
118         new.async_keywords = self.async_keywords
119         return new
120
121     def report(self):
122         """Dump the grammar tables to standard output, for debugging."""
123         from pprint import pprint
124         print("s2n")
125         pprint(self.symbol2number)
126         print("n2s")
127         pprint(self.number2symbol)
128         print("states")
129         pprint(self.states)
130         print("dfas")
131         pprint(self.dfas)
132         print("labels")
133         pprint(self.labels)
134         print("start", self.start)
135
136
137 # Map from operator to number (since tokenize doesn't do this)
138
139 opmap_raw = """
140 ( LPAR
141 ) RPAR
142 [ LSQB
143 ] RSQB
144 : COLON
145 , COMMA
146 ; SEMI
147 + PLUS
148 - MINUS
149 * STAR
150 / SLASH
151 | VBAR
152 & AMPER
153 < LESS
154 > GREATER
155 = EQUAL
156 . DOT
157 % PERCENT
158 ` BACKQUOTE
159 { LBRACE
160 } RBRACE
161 @ AT
162 @= ATEQUAL
163 == EQEQUAL
164 != NOTEQUAL
165 <> NOTEQUAL
166 <= LESSEQUAL
167 >= GREATEREQUAL
168 ~ TILDE
169 ^ CIRCUMFLEX
170 << LEFTSHIFT
171 >> RIGHTSHIFT
172 ** DOUBLESTAR
173 += PLUSEQUAL
174 -= MINEQUAL
175 *= STAREQUAL
176 /= SLASHEQUAL
177 %= PERCENTEQUAL
178 &= AMPEREQUAL
179 |= VBAREQUAL
180 ^= CIRCUMFLEXEQUAL
181 <<= LEFTSHIFTEQUAL
182 >>= RIGHTSHIFTEQUAL
183 **= DOUBLESTAREQUAL
184 // DOUBLESLASH
185 //= DOUBLESLASHEQUAL
186 -> RARROW
187 """
188
189 opmap = {}
190 for line in opmap_raw.splitlines():
191     if line:
192         op, name = line.split()
193         opmap[op] = getattr(token, name)