1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 '''
31 Default implementation of the helper classes for sequences (strings and lists).
32
33 The state is an integer offset. Sequence and a possible delta for the
34 offset are stored in the helper.
35 '''
36
37 from itertools import chain
38
39 from lepl.support.lib import fmt, add_defaults, str, LogMixin
40 from lepl.stream.core import StreamHelper, OFFSET, LINENO, CHAR, HashKey
41
42
44
45 - def __init__(self, id=None, factory=None, max=None, global_kargs=None,
46 cache_level=None, delta=None):
50
51
53
54 - def __init__(self, sequence, id=None, factory=None, max=None,
55 global_kargs=None, cache_level=None, delta=None):
65
66 - def key(self, state, other):
72
73 - def _fmt(self, sequence, offset, maxlen=60, left='', right='', index=True):
74 '''fmt a possibly long subsection of data.'''
75 if not sequence:
76 if index:
77 return fmt('{0!r}[{1:d}]', sequence, offset)
78 else:
79 return fmt('{0!r}', sequence)
80 if offset >= 0 and offset < len(sequence):
81 centre = offset
82 elif offset > 0:
83 centre = len(sequence) - 1
84 else:
85 centre = 0
86 begin, end = centre, centre+1
87 longest = None
88 while True:
89 if begin > 0:
90 if end < len(sequence):
91 template = '{0!s}...{1!s}...{2!s}'
92 else:
93 template = '{0!s}...{1!s}{2!s}'
94 else:
95 if end < len(sequence):
96 template = '{0!s}{1!s}...{2!s}'
97 else:
98 template = '{0!s}{1!s}{2!s}'
99 body = repr(sequence[begin:end])[len(left):]
100 if len(right):
101 body = body[:-len(right)]
102 text = fmt(template, left, body, right, offset)
103 if index:
104 text = fmt('{0!s}[{1:d}:]', text, offset)
105 if longest is None or len(text) <= maxlen:
106 longest = text
107 if len(text) > maxlen:
108 return longest
109 begin -= 1
110 end += 1
111 if begin < 0 and end > len(sequence):
112 return longest
113 begin = max(begin, 0)
114 end = min(end, len(sequence))
115
117 '''Location (separate method so subclasses can replace).'''
118 return fmt('offset {' + prefix + 'global_offset}, value {' + prefix + 'repr}',
119 **kargs)
120
129
130 - def kargs(self, state, prefix='', kargs=None):
131 '''
132 Generate a dictionary of values that describe the stream. These
133 may be extended by subclasses. They are provided to
134 `syntax_error_kargs`, for example.
135
136 Note: Calculating this can be expensive; use only for error messages,
137 not debug messages (that may be discarded).
138
139 Implementation note: Because some values are
140 '''
141 offset = state + self._delta[OFFSET]
142 if kargs is None: kargs = {}
143 add_defaults(kargs, self._kargs, prefix=prefix)
144 within = offset > -1 and offset < len(self._sequence)
145 data = self._fmt(self._sequence, state)
146 text = self._fmt(self._sequence, state, index=False)
147
148 defaults = {'data': data,
149 'global_data': data,
150 'text': text,
151 'global_text': text,
152 'offset': state,
153 'global_offset': offset,
154 'rest': self._fmt(self._sequence[offset:], 0, index=False),
155 'repr': repr(self._sequence[offset]) if within else '<EOS>',
156 'str': str(self._sequence[offset]) if within else '',
157 'lineno': 1,
158 'char': offset+1}
159 add_defaults(kargs, defaults, prefix=prefix)
160 add_defaults(kargs, {prefix + 'location': self._location(kargs, prefix)})
161 return kargs
162
163 - def next(self, state, count=1):
164 new_state = state+count
165 if new_state <= len(self._sequence):
166 stream = (new_state, self)
167 self.max.update(self._delta[OFFSET] + new_state - 1, stream)
168 return (self._sequence[state:new_state], stream)
169 else:
170 raise StopIteration
171
172 - def join(self, state, *values):
173 assert values, 'Cannot join zero general sequences'
174 result = values[0]
175 for value in values[1:]:
176 result += value
177 return result
178
181
182 - def line(self, state, empty_ok):
183 '''Returns the rest of the data.'''
184 new_state = len(self._sequence)
185 if state < new_state or (empty_ok and state == new_state):
186 stream = (new_state, self)
187 self.max.update(self._delta[OFFSET] + new_state, stream)
188 return (self._sequence[state:new_state], stream)
189 else:
190 raise StopIteration
191
192 - def len(self, state):
194
195 - def stream(self, state, value, id_=None, max=None):
203
206
208 try:
209 return fmt('{0:d}:{1!r}', state, self._sequence[state])
210 except IndexError:
211 return fmt('{0:d}:<EOS>', state)
212
216
218 return (self.max,
219 (state, type(self)(self._sequence, id=self.id,
220 factory=self.factory, max=None,
221 global_kargs=self.global_kargs,
222 delta=self._delta)))
223
224
225
227 '''
228 String-specific fmtting and location.
229 '''
230
231 - def __init__(self, sequence, id=None, factory=None, max=None,
232 global_kargs=None, cache_level=None, delta=None):
239
240 - def _fmt(self, sequence, offset, maxlen=60, left="'", right="'", index=True):
243
245 return fmt('line {' + prefix + 'lineno:d}, character {' + prefix + 'char:d}', **kargs)
246
248 offset = self._delta[OFFSET] + state
249 lineno = self._delta[LINENO] + self._sequence.count('\n', 0, state)
250 start = self._sequence.rfind('\n', 0, state)
251 if start > -1:
252 char = state - start
253 else:
254 char = self._delta[CHAR] + state
255 return (offset, lineno, char)
256
257 - def kargs(self, state, prefix='', kargs=None):
258 if kargs is None: kargs = {}
259 (_, lineno, char) = self.delta(state)
260 start = self._sequence.rfind('\n', 0, state) + 1
261 end = self._sequence.find('\n', state)
262
263 if end < 0:
264 rest = repr(self._sequence[state:])
265 all = str(self._sequence[start:])
266 else:
267 rest = repr(self._sequence[state:end])
268 all = str(self._sequence[start:end])
269 add_defaults(kargs, {
270 'type': '<string>',
271 'filename': '<string>',
272 'rest': rest,
273 'all': all,
274 'lineno': lineno,
275 'char': char}, prefix=prefix)
276 return super(StringHelper, self).kargs(state, prefix=prefix, kargs=kargs)
277
278 - def join(self, state, *values):
280
281 - def line(self, state, empty_ok):
282 '''Returns up to, and including then next \n'''
283 max_len = len(self._sequence)
284 if state < max_len or (empty_ok and state == max_len):
285 end = self._sequence.find('\n', state) + 1
286 if not end: end = len(self._sequence)
287 return (self._sequence[state:end], (end, self))
288 else:
289 raise StopIteration
290
291 - def stream(self, state, value, id_=None, max=None):
297
298
300 '''
301 List-specific fprmatting
302 '''
303
304 - def _fmt(self, sequence, offset, maxlen=60, left="[", right="]", index=True):
307
308 - def join(self, state, *values):
309 return list(chain(*values))
310