1
1
"""
2
- The :mod:`parser` module concerns itself with LL(1) parsing.
2
+ The :mod:`parser` module concerns itself with parsing Python source .
3
3
"""
4
4
5
5
from __future__ import absolute_import , division , print_function , unicode_literals
6
6
from . import source , diagnostic , lexer , ast
7
7
8
8
# Generic LL parsing combinators
9
- unmatched = object ()
9
+ class Unmatched :
10
+ def __repr__ (self ):
11
+ return "<can't parse>"
12
+ unmatched = Unmatched ()
13
+
14
+ _all_rules = []
15
+
16
+ def llrule (loc , expected , cases = 1 ):
17
+ if loc is None :
18
+ def decorator (rule ):
19
+ rule .expected = expected
20
+ return rule
21
+ else :
22
+ def decorator (inner_rule ):
23
+ if cases == 1 :
24
+ def rule (* args , ** kwargs ):
25
+ result = inner_rule (* args , ** kwargs )
26
+ if result is not unmatched :
27
+ rule .covered [0 ] = True
28
+ return result
29
+ else :
30
+ rule = inner_rule
31
+
32
+ rule .loc , rule .expected , rule .covered = \
33
+ loc , expected , [False ] * cases
34
+ _all_rules .append (rule )
35
+
36
+ return rule
37
+ return decorator
10
38
11
- def action (inner_rule ):
39
+ def action (inner_rule , loc = None ):
12
40
"""
13
41
A decorator returning a function that first runs ``inner_rule`` and then, if its
14
42
return value is not None, maps that value using ``mapper``.
@@ -18,50 +46,51 @@ def action(inner_rule):
18
46
Similar to attaching semantic actions to rules in traditional parser generators.
19
47
"""
20
48
def decorator (mapper ):
49
+ @llrule (loc , inner_rule .expected )
21
50
def outer_rule (parser ):
22
51
result = inner_rule (parser )
23
52
if isinstance (result , tuple ):
24
53
result = mapper (parser , * result )
25
54
elif result is not unmatched :
26
55
result = mapper (parser , result )
27
56
return result
28
- outer_rule .expected = inner_rule .expected
29
57
return outer_rule
30
58
return decorator
31
59
32
- def Eps (value = None ):
60
+ def Eps (value = None , loc = None ):
33
61
"""A rule that accepts no tokens (epsilon) and returns ``value``."""
62
+ @llrule (loc , lambda parser : [])
34
63
def rule (parser ):
35
64
return value
36
- rule .expected = lambda parser : [[]]
37
65
return rule
38
66
39
- def Tok (kind ):
67
+ def Tok (kind , loc = None ):
40
68
"""A rule that accepts a token of kind ``kind`` and returns it, or returns None."""
69
+ @llrule (loc , lambda parser : [kind ])
41
70
def rule (parser ):
42
71
return parser ._accept (kind )
43
- rule .expected = lambda parser : [[kind ]]
44
72
return rule
45
73
46
- def Loc (kind ):
74
+ def Loc (kind , loc = None ):
47
75
"""A rule that accepts a token of kind ``kind`` and returns its location, or returns None."""
76
+ @llrule (loc , lambda parser : [kind ])
48
77
def rule (parser ):
49
78
result = parser ._accept (kind )
50
79
if result is not unmatched :
51
80
return result .loc
52
81
return unmatched
53
- rule .expected = lambda parser : [[kind ]]
54
82
return rule
55
83
56
- def Rule (name ):
84
+ def Rule (name , loc = None ):
57
85
"""A proxy for a rule called ``name`` which may not be yet defined."""
86
+ @llrule (loc , lambda parser : getattr (parser , name ).expected (parser ))
58
87
def rule (parser ):
59
88
return getattr (parser , name )()
60
- rule .expected = lambda parser : getattr (parser , name ).expected (parser )
61
89
return rule
62
90
63
- def Expect (inner_rule ):
91
+ def Expect (inner_rule , loc = None ):
64
92
"""A rule that executes ``inner_rule`` and emits a diagnostic error if it returns None."""
93
+ @llrule (loc , inner_rule .expected )
65
94
def rule (parser ):
66
95
result = inner_rule (parser )
67
96
if result is unmatched :
@@ -78,76 +107,84 @@ def rule(parser):
78
107
parser .token .loc )
79
108
raise diagnostic .DiagnosticException (error )
80
109
return result
81
- rule .expected = inner_rule .expected
82
110
return rule
83
111
84
- def Seq (first_rule , * rest_of_rules ):
112
+ def Seq (first_rule , * rest_of_rules , ** kwargs ):
85
113
"""
86
114
A rule that accepts a sequence of tokens satisfying ``rules`` and returns a tuple
87
115
containing their return values, or None if the first rule was not satisfied.
88
116
"""
89
117
rest_of_rules = map (Expect , rest_of_rules )
118
+ @llrule (kwargs .get ('loc' , None ), first_rule .expected )
90
119
def rule (parser ):
91
120
first_result = first_rule (parser )
92
121
if first_result is not unmatched :
93
122
return tuple ([first_result ]) + tuple (map (lambda rule : rule (parser ), rest_of_rules ))
94
123
return unmatched
95
- rule .expected = \
96
- lambda parser : first_rule .expected (parser ) + \
97
- reduce (list .__add__ , map (lambda rule : rule .expected (parser ), rest_of_rules ))
98
124
return rule
99
125
100
- def SeqN (n , * inner_rules ):
126
+ def SeqN (n , * inner_rules , ** kwargs ):
101
127
"""
102
128
A rule that accepts a sequence of tokens satisfying ``rules`` and returns
103
129
the value returned by rule number ``n``, or None if the first rule was not satisfied.
104
130
"""
105
- @action (Seq (* inner_rules ))
131
+ @action (Seq (* inner_rules ), loc = kwargs . get ( 'loc' , None ) )
106
132
def rule (parser , * values ):
107
133
return values [n ]
108
134
return rule
109
135
110
- def Alt (* inner_rules ):
136
+ def Alt (* inner_rules , ** kwargs ):
111
137
"""
112
138
A rule that expects a sequence of tokens satisfying one of ``rules`` in sequence
113
139
(a rule is satisfied when it returns anything but None) and returns the return
114
140
value of that rule, or None if no rules were satisfied.
115
141
"""
116
- def rule (parser ):
117
- # semantically reduce(), but faster.
118
- for inner_rule in inner_rules :
119
- result = inner_rule (parser )
120
- if result is not unmatched :
121
- return result
122
- return unmatched
123
- rule .expected = \
124
- lambda parser : reduce (list .__add__ , map (lambda x : x .expected (parser ), inner_rules ))
142
+ loc = kwargs .get ('loc' , None )
143
+ expected = lambda parser : reduce (list .__add__ , map (lambda x : x .expected (parser ), inner_rules ))
144
+ if loc is not None :
145
+ @llrule (loc , expected , cases = len (inner_rules ))
146
+ def rule (parser ):
147
+ for idx , inner_rule in enumerate (inner_rules ):
148
+ result = inner_rule (parser )
149
+ if result is not unmatched :
150
+ rule .covered [idx ] = True
151
+ return result
152
+ return unmatched
153
+ else :
154
+ @llrule (loc , expected , cases = len (inner_rules ))
155
+ def rule (parser ):
156
+ for inner_rule in inner_rules :
157
+ result = inner_rule (parser )
158
+ if result is not unmatched :
159
+ return result
160
+ return unmatched
125
161
return rule
126
162
127
- def Opt (inner_rule ):
163
+ def Opt (inner_rule , loc = None ):
128
164
"""Shorthand for ``Alt(inner_rule, Eps())``"""
129
- return Alt (inner_rule , Eps ())
165
+ return Alt (inner_rule , Eps (), loc = loc )
130
166
131
- def Star (inner_rule ):
167
+ def Star (inner_rule , loc = None ):
132
168
"""
133
169
A rule that accepts a sequence of tokens satisfying ``inner_rule`` zero or more times,
134
170
and returns the returned values in a :class:`list`.
135
171
"""
172
+ @llrule (loc , lambda parser : [])
136
173
def rule (parser ):
137
174
results = []
138
175
while True :
139
176
result = inner_rule (parser )
140
177
if result is unmatched :
141
178
return results
142
179
results .append (result )
143
- rule .expected = lambda parser : []
144
180
return rule
145
181
146
- def Plus (inner_rule ):
182
+ def Plus (inner_rule , loc = None ):
147
183
"""
148
184
A rule that accepts a sequence of tokens satisfying ``inner_rule`` one or more times,
149
185
and returns the returned values in a :class:`list`.
150
186
"""
187
+ @llrule (loc , inner_rule .expected )
151
188
def rule (parser ):
152
189
result = inner_rule (parser )
153
190
if result is unmatched :
@@ -159,21 +196,21 @@ def rule(parser):
159
196
if result is unmatched :
160
197
return results
161
198
results .append (result )
162
- rule .expected = inner_rule .expected
163
199
return rule
164
200
165
- def List (inner_rule , separator_tok , trailing , leading = True ):
201
+ def List (inner_rule , separator_tok , trailing , leading = True , loc = None ):
166
202
if not trailing :
167
- @action (Seq (inner_rule , Star (SeqN (1 , Tok (separator_tok ), inner_rule ))))
168
- def rule (parser , first , rest ):
203
+ @action (Seq (inner_rule , Star (SeqN (1 , Tok (separator_tok ), inner_rule ))), loc = loc )
204
+ def outer_rule (parser , first , rest ):
169
205
return [first ] + rest
170
- return rule
206
+ return outer_rule
171
207
else :
172
208
# A rule like this: stmt (';' stmt)* [';']
173
209
# This doesn't yield itself to combinators above, because disambiguating
174
210
# another iteration of the Kleene star and the trailing separator
175
211
# requires two lookahead tokens (naively).
176
212
separator_rule = Tok (separator_tok )
213
+ @llrule (loc , inner_rule .expected )
177
214
def rule (parser ):
178
215
results = []
179
216
@@ -196,41 +233,40 @@ def rule(parser):
196
233
return results
197
234
else :
198
235
results .append (result )
199
- rule .expected = inner_rule .expected
200
236
return rule
201
237
202
238
# Python AST specific parser combinators
203
- def Newline ():
239
+ def Newline (loc = None ):
204
240
"""A rule that accepts token of kind ``newline`` and returns []."""
241
+ @llrule (loc , lambda parser : ['newline' ])
205
242
def rule (parser ):
206
243
if parser ._accept ('newline' ) is not unmatched :
207
244
return []
208
245
return unmatched
209
- rule .expected = lambda parser : [['newline' ]]
210
246
return rule
211
247
212
- def Oper (klass , * kinds ):
248
+ def Oper (klass , * kinds , ** kwargs ):
213
249
"""
214
250
A rule that accepts a sequence of tokens of kinds ``kinds`` and returns
215
251
an instance of ``klass`` with ``loc`` encompassing the entire sequence
216
252
or None if the first token is not of ``kinds[0]``.
217
253
"""
218
- @action (Seq (* map (Loc , kinds )))
254
+ @action (Seq (* map (Loc , kinds )), loc = kwargs . get ( 'loc' , None ) )
219
255
def rule (parser , * tokens ):
220
256
return klass (loc = tokens [0 ].join (tokens [- 1 ]))
221
257
return rule
222
258
223
- def BinOper (expr_rulename , op_rule , node = ast .BinOp ):
224
- @action (Seq (Rule (expr_rulename ), Star (Seq (op_rule , Rule (expr_rulename )))))
259
+ def BinOper (expr_rulename , op_rule , node = ast .BinOp , loc = None ):
260
+ @action (Seq (Rule (expr_rulename ), Star (Seq (op_rule , Rule (expr_rulename )))), loc = loc )
225
261
def rule (parser , lhs , trailers ):
226
262
for (op , rhs ) in trailers :
227
263
lhs = node (left = lhs , op = op , right = rhs ,
228
264
loc = lhs .loc .join (rhs .loc ))
229
265
return lhs
230
266
return rule
231
267
232
- def BeginEnd (begin_tok , inner_rule , end_tok , empty = None ):
233
- @action (Seq (Loc (begin_tok ), inner_rule , Loc (end_tok )))
268
+ def BeginEnd (begin_tok , inner_rule , end_tok , empty = None , loc = None ):
269
+ @action (Seq (Loc (begin_tok ), inner_rule , Loc (end_tok )), loc = loc )
234
270
def rule (parser , begin_loc , node , end_loc ):
235
271
if node is None :
236
272
node = empty ()
@@ -333,7 +369,7 @@ def varargslist_1(self, dstar_loc, kwarg_tok):
333
369
dstar_loc = dstar_loc , kwarg_loc = kwarg_tok .loc )
334
370
335
371
@action (Seq (Loc ('*' ), Tok ('ident' ),
336
- Opt (Seq (Loc ('**' , Tok ('ident' ) )))))
372
+ Opt (Seq (Loc ('**' ) , Tok ('ident' )))))
337
373
def varargslist_2 (self , star_loc , vararg_tok , kwarg_opt ):
338
374
dstar_loc , kwarg , kwarg_loc = None
339
375
if kwarg_opt :
0 commit comments