~washort/pymeta/ometa-2

« back to all changes in this revision

Viewing changes to pymeta/runtime.py

  • Committer: Allen Short
  • Date: 2009-11-10 06:40:06 UTC
  • mfrom: (43.2.9 error-reporting)
  • Revision ID: washort@allen-shorts-macbook-pro.local-20091110064006-og3a54tl6z0yyi75
MergeĀ "error-reporting"

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- test-case-name: pymeta.test.test_runtime -*-
 
2
 
1
3
"""
2
4
Code needed to run a grammar after it has been compiled.
3
5
"""
5
7
    """
6
8
    ?Redo from start
7
9
    """
 
10
    def __init__(self, *a):
 
11
        Exception.__init__(self, *a)
 
12
        self.position = a[0]
 
13
        self.error = a[1]
 
14
        if len(a) > 2:
 
15
            self.message = a[2]
 
16
 
 
17
    def __eq__(self, other):
 
18
        if other.__class__ == self.__class__:
 
19
            return (self.position, self.error) == (other.position, other.error)
 
20
 
 
21
class EOFError(ParseError):
 
22
    def __init__(self, position):
 
23
        ParseError.__init__(self, position, eof())
 
24
 
 
25
 
 
26
def expected(val):
 
27
    """
 
28
    Return an indication of expected input and the position where it was
 
29
    expected and not encountered.
 
30
    """
 
31
 
 
32
    return [("expected", val)]
 
33
 
 
34
def expectedOneOf(vals):
 
35
    """
 
36
    Return an indication of multiple possible expected inputs.
 
37
    """
 
38
 
 
39
    return [("expected", x) for x in vals]
 
40
 
 
41
def eof():
 
42
    """
 
43
    Return an indication that the end of the input was reached.
 
44
    """
 
45
    return [("message", "end of input")]
 
46
 
 
47
 
 
48
def joinErrors(errors):
 
49
    """
 
50
    Return the error from the branch that matched the most of the input.
 
51
    """
 
52
    errors.sort(reverse=True, key=lambda x: x.position)
 
53
    results = []
 
54
    pos = errors[0].position
 
55
    for err in errors:
 
56
        if pos == err.position:
 
57
            e = err.error
 
58
            if e is not None:
 
59
                for item in e:
 
60
                    if item not in results:
 
61
                        results.append(item)
 
62
        else:
 
63
            break
 
64
 
 
65
    return ParseError(pos, results)
 
66
 
8
67
 
9
68
class character(str):
10
69
    """
55
114
 
56
115
    def head(self):
57
116
        if self.position >= len(self.data):
58
 
            raise IndexError("out of range")
59
 
        return self.data[self.position]
 
117
            raise EOFError(self.position)
 
118
        return self.data[self.position], ParseError(self.position, None)
 
119
 
 
120
    def nullError(self):
 
121
        return ParseError(self.position, None)
60
122
 
61
123
    def tail(self):
62
124
        if self.tl is None:
89
151
        self.arg = arg
90
152
        self.parent = parent
91
153
        self.memo = {}
 
154
        self.err = parent.nullError()
92
155
 
93
156
    def head(self):
94
 
        return self.arg
 
157
        try:
 
158
            x = self.arg
 
159
        except:
 
160
            import pdb; pdb. set_trace()
 
161
        return self.arg, self.err
95
162
 
96
163
    def tail(self):
97
164
        return self.parent
143
210
            else:
144
211
                self.globals = globals
145
212
 
 
213
        self.currentError = self.input.nullError()
 
214
 
 
215
    def considerError(self, error):
 
216
        if error is not None:
 
217
            self.currentError = joinErrors([error, self.currentError])
 
218
 
146
219
 
147
220
    def superApply(self, ruleName, *args):
148
221
        """
191
264
            lr = LeftRecursion()
192
265
            memoRec = self.input.setMemo(ruleName, lr)
193
266
 
194
 
            memoRec = self.input.setMemo(ruleName,
195
 
                                         [rule(), self.input])
 
267
            #print "Calling", rule
 
268
            try:
 
269
                memoRec = self.input.setMemo(ruleName,
 
270
                                             [rule(), self.input])
 
271
            except ParseError:
 
272
                #print "Failed", rule
 
273
                raise
 
274
            #print "Success", rule
196
275
            if lr.detected:
197
276
                sentinel = self.input
198
277
                while True:
210
289
 
211
290
        elif isinstance(memoRec, LeftRecursion):
212
291
            memoRec.detected = True
213
 
            raise ParseError()
 
292
            raise ParseError(None, None)
214
293
        self.input = memoRec[1]
215
294
        return memoRec[0]
216
295
 
219
298
        """
220
299
        Match a single item from the input of any kind.
221
300
        """
222
 
        try:
223
 
            h = self.input.head()
224
 
            self.input = self.input.tail()
225
 
            return h
226
 
        except IndexError:
227
 
            raise ParseError()
 
301
        h, p = self.input.head()
 
302
        self.input = self.input.tail()
 
303
        return h, p
228
304
 
229
305
    def exactly(self, wanted):
230
306
        """
233
309
        @param wanted: What to match.
234
310
        """
235
311
        i = self.input
236
 
        try:
237
 
            val = self.input.head()
238
 
            self.input = self.input.tail()
239
 
        except IndexError:
240
 
            raise ParseError()
 
312
        val, p = self.input.head()
 
313
        self.input = self.input.tail()
241
314
        if wanted == val:
242
 
            return wanted
 
315
            return val, p
243
316
        else:
244
317
            self.input = i
245
 
            raise ParseError()
 
318
            raise ParseError(p.position, expected(wanted))
246
319
 
247
320
    rule_exactly = exactly
248
321
 
254
327
        @param fn: A callable of no arguments.
255
328
        @param initial: Initial values to populate the returned list with.
256
329
        """
257
 
        ans = list(initial)
 
330
        ans = []
 
331
        for x, e in initial:
 
332
            ans.append(x)
258
333
        while True:
259
334
            try:
260
335
                m = self.input
261
 
                ans.append(fn())
262
 
            except ParseError:
 
336
                v, _ = fn()
 
337
                ans.append(v)
 
338
            except ParseError, e:
263
339
                self.input = m
264
340
                break
265
 
        return ans
 
341
        return ans, e
266
342
 
267
343
    def _or(self, fns):
268
344
        """
271
347
 
272
348
        @param fns: A list of no-argument callables.
273
349
        """
 
350
        errors = []
274
351
        for f in fns:
275
352
            try:
276
353
                m = self.input
277
 
                ret = f()
278
 
                return ret
279
 
            except ParseError:
 
354
                ret, err = f()
 
355
                errors.append(err)
 
356
                return ret, joinErrors(errors)
 
357
            except ParseError, e:
 
358
                errors.append(e)
280
359
                self.input = m
281
 
        raise ParseError()
 
360
        raise joinErrors(errors)
 
361
 
282
362
 
283
363
    def _not(self, fn):
284
364
        """
289
369
        m = self.input
290
370
        try:
291
371
            fn()
292
 
        except ParseError:
 
372
        except ParseError, e:
293
373
            self.input = m
294
 
            return True
 
374
            return True, self.input.nullError()
295
375
        else:
296
 
            raise ParseError()
 
376
            raise self.input.nullError()
297
377
 
298
378
    def eatWhitespace(self):
299
379
        """
301
381
        """
302
382
        while True:
303
383
            try:
304
 
                c = self.input.head()
305
 
            except IndexError:
 
384
                c, e = self.input.head()
 
385
            except EOFError, e:
306
386
                break
307
387
            t = self.input.tail()
308
388
            if c.isspace():
309
389
                self.input = t
310
390
            else:
311
391
                break
312
 
        return True
 
392
        return True, e
313
393
    rule_spaces = eatWhitespace
314
394
 
 
395
 
315
396
    def pred(self, expr):
316
397
        """
317
398
        Call the given function, raising ParseError if it returns false.
318
399
 
319
400
        @param expr: A callable of no arguments.
320
401
        """
321
 
        if not expr():
322
 
            raise ParseError()
 
402
        val, e = expr()
 
403
        if not val:
 
404
            raise e
323
405
        else:
324
 
            return True
 
406
            return True, e
325
407
 
326
408
    def listpattern(self, expr):
327
409
        """
330
412
 
331
413
        @param expr: A callable of no arguments.
332
414
        """
333
 
        v = self.rule_anything()
 
415
        v, e = self.rule_anything()
334
416
        oldInput = self.input
335
417
        try:
336
418
            self.input = InputStream.fromIterable(v)
337
419
        except TypeError:
338
 
            raise ParseError()
339
 
        r = expr()
 
420
            e = self.input.nullError()
 
421
            e.error = expected("an iterable")
 
422
            raise e
 
423
        expr()
340
424
        self.end()
341
425
        self.input = oldInput
342
 
        return v
 
426
        return v, e
343
427
 
344
428
 
345
429
    def end(self):
373
457
        try:
374
458
            self.eatWhitespace()
375
459
            for c in tok:
376
 
                self.exactly(c)
377
 
            return tok
 
460
                v, e = self.exactly(c)
 
461
            return tok, e
378
462
        except ParseError:
379
463
            self.input = m
380
464
            raise
385
469
        """
386
470
        Match a single letter.
387
471
        """
388
 
        try:
389
 
            x = self.input.head()
390
 
            if x.isalpha():
391
 
                self.input = self.input.tail()
392
 
                return x
393
 
            else:
394
 
                raise ParseError()
395
 
        except IndexError:
396
 
            raise ParseError()
 
472
        x, e = self.rule_anything()
 
473
        if x.isalpha():
 
474
            return x, e
 
475
        else:
 
476
            e.error = expected("letter")
 
477
            raise e
397
478
 
398
479
    rule_letter = letter
399
480
 
401
482
        """
402
483
        Match a single alphanumeric character.
403
484
        """
404
 
        try:
405
 
            x = self.input.head()
406
 
        except IndexError:
407
 
            raise ParseError()
 
485
        x, e = self.rule_anything()
408
486
        if x.isalnum() or x == '_':
409
 
            self.input = self.input.tail()
410
 
            return x
 
487
            return x, e
411
488
        else:
412
 
            raise ParseError()
 
489
            e.error = expected("letter or digit")
 
490
            raise e
413
491
 
414
492
    rule_letterOrDigit = letterOrDigit
415
493
 
417
495
        """
418
496
        Match a single digit.
419
497
        """
420
 
        try:
421
 
            x = self.input.head()
422
 
        except IndexError:
423
 
            raise ParseError()
 
498
        x, e = self.rule_anything()
424
499
        if x.isdigit():
425
 
            self.input = self.input.tail()
426
 
            return x
 
500
            return x, e
427
501
        else:
428
 
            raise ParseError()
 
502
            e.error = expected("digit")
 
503
            raise e
429
504
 
430
505
    rule_digit = digit
431
506
 
441
516
        expr = []
442
517
        while True:
443
518
            try:
444
 
                c = self.rule_anything()
445
 
            except ParseError:
 
519
                c, e = self.rule_anything()
 
520
            except ParseError, e:
446
521
                endchar = None
447
522
                break
448
523
            if c in endChars and len(stack) == 0:
455
530
                elif len(stack) > 0 and c == stack[-1]:
456
531
                    stack.pop()
457
532
                elif c in delimiters.values():
458
 
                    raise ParseError()
 
533
                    raise ParseError(self.input.position, expected("Python expression"))
459
534
                elif c in "\"'":
460
535
                    while True:
461
 
                        strc = self.rule_anything()
 
536
                        strc, stre = self.rule_anything()
462
537
                        expr.append(strc)
463
538
                        if strc == c:
464
539
                            break
465
540
        if len(stack) > 0:
466
 
            raise ParseError()
467
 
        return ''.join(expr).strip(), endchar
 
541
            raise ParseError(self.input.position, expected("Python expression"))
 
542
        return (''.join(expr).strip(), endchar), e