11"""Define partial Python code Parser used by editor and hyperparser.
22
3- Instances of StringTranslatePseudoMapping are used with str.translate.
3+ Instances of ParseMap are used with str.translate.
44
55The following bound search and match functions are defined:
66_synchre - start of popular statement;
1010_closere - line that must be followed by dedent.
1111_chew_ordinaryre - non-special characters.
1212"""
13- from collections .abc import Mapping
1413import re
1514import sys
1615
101100""" , re .VERBOSE ).match
102101
103102
104- class StringTranslatePseudoMapping ( Mapping ):
105- r"""Utility class to be used with str.translate()
103+ class ParseMap ( dict ):
104+ r"""Dict subclass that maps anything not in dict to 'x'.
106105
107- This Mapping class wraps a given dict. When a value for a key is
108- requested via __getitem__() or get(), the key is looked up in the
109- given dict. If found there, the value from the dict is returned.
110- Otherwise, the default value given upon initialization is returned.
106+ This is designed to be used with str.translate in study1.
107+ Anything not specifically mapped otherwise becomes 'x'.
108+ Example: replace everything except whitespace with 'x'.
111109
112- This allows using str.translate() to make some replacements, and to
113- replace all characters for which no replacement was specified with
114- a given character instead of leaving them as-is.
115-
116- For example, to replace everything except whitespace with 'x':
117-
118- >>> whitespace_chars = ' \t\n\r'
119- >>> preserve_dict = {ord(c): ord(c) for c in whitespace_chars}
120- >>> mapping = StringTranslatePseudoMapping(preserve_dict, ord('x'))
121- >>> text = "a + b\tc\nd"
122- >>> text.translate(mapping)
110+ >>> keepwhite = ParseMap((ord(c), ord(c)) for c in ' \t\n\r')
111+ >>> "a + b\tc\nd".translate(keepwhite)
123112 'x x x\tx\nx'
124113 """
125- def __init__ (self , non_defaults , default_value ):
126- self ._non_defaults = non_defaults
127- self ._default_value = default_value
128-
129- def _get (key , _get = non_defaults .get , _default = default_value ):
130- return _get (key , _default )
131- self ._get = _get
114+ # Calling this triples access time; see bpo-32940
115+ def __missing__ (self , key ):
116+ return 120 # ord('x')
132117
133- def __getitem__ (self , item ):
134- return self ._get (item )
135118
136- def __len__ (self ):
137- return len (self ._non_defaults )
138-
139- def __iter__ (self ):
140- return iter (self ._non_defaults )
141-
142- def get (self , key , default = None ):
143- return self ._get (key )
119+ # Map all ascii to 120 to avoid __missing__ call, then replace some.
120+ trans = ParseMap .fromkeys (range (128 ), 120 )
121+ trans .update ((ord (c ), ord ('(' )) for c in "({[" ) # open brackets => '(';
122+ trans .update ((ord (c ), ord (')' )) for c in ")}]" ) # close brackets => ')'.
123+ trans .update ((ord (c ), ord (c )) for c in "\" '\\ \n #" ) # Keep these.
144124
145125
146126class Parser :
@@ -224,16 +204,6 @@ def set_lo(self, lo):
224204 if lo > 0 :
225205 self .code = self .code [lo :]
226206
227- # Build a translation table to map uninteresting chars to 'x', open
228- # brackets to '(', close brackets to ')' while preserving quotes,
229- # backslashes, newlines and hashes. This is to be passed to
230- # str.translate() in _study1().
231- _tran = {}
232- _tran .update ((ord (c ), ord ('(' )) for c in "({[" )
233- _tran .update ((ord (c ), ord (')' )) for c in ")}]" )
234- _tran .update ((ord (c ), ord (c )) for c in "\" '\\ \n #" )
235- _tran = StringTranslatePseudoMapping (_tran , default_value = ord ('x' ))
236-
237207 def _study1 (self ):
238208 """Find the line numbers of non-continuation lines.
239209
@@ -250,7 +220,7 @@ def _study1(self):
250220 # uninteresting characters. This can cut the number of chars
251221 # by a factor of 10-40, and so greatly speed the following loop.
252222 code = self .code
253- code = code .translate (self . _tran )
223+ code = code .translate (trans )
254224 code = code .replace ('xxxxxxxx' , 'x' )
255225 code = code .replace ('xxxx' , 'x' )
256226 code = code .replace ('xx' , 'x' )
0 commit comments