My favorites | Sign in
Project Home Downloads Wiki Issues Source
Repository:
Checkout   Browse   Changes   Clones  
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126

.. _errors:

Error Reporting
===============


.. index:: errors

Introduction
------------

In some applications it is important not only to parse correctly structured
input, but also to give a helpful responses when the input is incorrectly
structured.

Lepl provides support for reporting errors in the input in three ways.

1. By checking when the entire input was consumed and, if not, reporting on
the location of deepest match.

2. By allowing a matcher to directly raise an exception.

3. By creating a parse tree with nodes that represent errors; these error
nodes can then be used, later, to raise exceptions.

The first approach is often the best compromise and is used by default (see
`.config.full_first_match()
<api/redirect.html#lepl.core.config.ConfigBuilder.full_first_match>`_,
:ref:`configuration <configuration>`). However, it is limited to a single
match and gives little information about the underlying problem.

The second approach is simple, but doesn't play well with backtracking.

The third approach is probably best for more complex situations, but remains
relatively unexplored. It may not scale well, for example.

.. index:: ^, make_error(), **, sexpr_throw(), node_throw(), Error()

Example
-------

Here is an example of the second and third approaches in use::

>>> from lepl import *

>>> class Term(List): pass
>>> class Factor(List): pass
>>> class Expression(List): pass

>>> expr = Delayed()
>>> number = Digit()[1:,...]
>>> badChar = AnyBut(Space() | Digit() | '(')[1:,...]

>>> with DroppedSpace():

>>> unopen = number ** make_error('no ( before {out_rest!s}') & ')'
>>> unclosed = ('(' & expr & Eos()) ** make_error('no ) for {in_rest!s}')

>>> term = Or(
>>> (number | '(' & expr & ')') > Term,
>>> badChar ^ 'unexpected text: {results[0]}',
>>> unopen,
>>> unclosed
>>> )
>>> muldiv = Any('*/')
>>> factor = (term & (muldiv & term)[:]) > Factor
>>> addsub = Any('+-')
>>> expr += (factor & (addsub & factor)[:]) > Expression
>>> line = (Empty() & expr & Eos()) >> sexpr_throw

>>> parser = line.get_parse()

>>> parser('1 + 2 * (3 + 4 - 5')[0]
[...]
File "<string>", line 1
1 + 2 * (3 + 4 - 5
^
lepl.matchers.error.Error: no ) for '(3 + 4 - 5'

>>> parser('1 + 2 * 3 + 4 - 5)')[0]
File "<string>", line 1
1 + 2 * 3 + 4 - 5)
^
lepl.matchers.error.Error: no ( before ')'

>>> parser('1 + 2 * (3 + four - 5)')[0]
File "<string>", line 1
1 + 2 * (3 + four - 5)
^
lepl.matchers.error.Error: unexpected text: four

>>> parser('1 + 2 ** (3 + 4 - 5)')[0]
File "<string>", line 1
1 + 2 ** (3 + 4 - 5)
^
lepl.matchers.error.Error: unexpected text: *


.. note::

This example follows the :ref:`applycase` and :ref:`complexor` patterns.

Also, the parentheses around expressions that are sent to ``>>`` are
critical.

.. index:: ^, Error(), SyntaxError()

Operators, Functions and Classes
--------------------------------

============================================================================= ======== ========
Name Type Action
============================================================================= ======== ========
``^`` Operator Raises an exception, given a format string. Formatting has the same named parameters as the ``KApply()`` matcher (results, stream_in, stream_out); implemented as KApply(`raise_error <api/redirect.html#lepl.matchers.error.raise_error>`_)
----------------------------------------------------------------------------- -------- --------
`raise_error() <api/redirect.html#lepl.matchers.error.raise_error>`_ Function See above.
----------------------------------------------------------------------------- -------- --------
``Error()`` Class Creates a parse tree node that can be used to trigger a later exception (``Error`` is a subclass of both ``Node`` and ``SyntaxError``).
----------------------------------------------------------------------------- -------- --------
`sexpr_throw() <api/redirect.html#lepl.support.list.sexpr_throw>`_ Function Walks a ``List()``--based parse tree and raises the first ``Error`` found.
----------------------------------------------------------------------------- -------- --------
`node_throw() <api/redirect.html#lepl.support.node.node_throw>`_ Function Walks a ``Node()``--based parse tree and raises the first ``Error`` found.
----------------------------------------------------------------------------- -------- --------
`make_error() <api/redirect.html#lepl.matchers.error.make_error>`_ Function Creates an ``Error`` node, given a format string.
============================================================================= ======== ========

Change log

8f2692346ba5 by andrew on Mar 19, 2011   Diff
docs without api links
Go to: 
Project members, sign in to write a code review

Older revisions

9a59cecbd954 by andrew on Mar 14, 2011   Diff
fixing docs
249af3234ee4 by andrew on Mar 7, 2011   Diff
improved (i think) rmemo + start of
cache level for streams.
committing now as about to try redo
lmemo.
d8f3eb2d1b3f by and...@small.europa2189 on May 18, 2010   Diff
explicit encode unicode chars in
regexps to avoid starange bug
All revisions of this file

File info

Size: 5142 bytes, 126 lines
Powered by Google Project Hosting