@@ -30,7 +30,8 @@ def flatten_ast(self, node):
30
30
# Validate locs
31
31
for attr in node .__dict__ :
32
32
if attr .endswith ('_loc' ) or attr .endswith ('_locs' ):
33
- self .assertTrue (attr in node ._locs )
33
+ self .assertTrue (attr in node ._locs ,
34
+ "%s not in %s._locs" % (attr , repr (node )))
34
35
for loc in node ._locs :
35
36
self .assertTrue (loc in node .__dict__ )
36
37
@@ -45,7 +46,7 @@ def flatten_ast(self, node):
45
46
return flat_node
46
47
47
48
_loc_re = re .compile (r"\s*([~^]+)\s+([a-z_0-9.]+)" )
48
- _path_re = re .compile (r"(([a-z_]+)|([0-9]+))(.)?" )
49
+ _path_re = re .compile (r"(([a-z_]+)|([0-9]+))(\ .)?" )
49
50
50
51
def match_loc (self , ast , matcher , root = lambda x : x ):
51
52
ast = root (ast )
@@ -68,9 +69,9 @@ def match_loc(self, ast, matcher, root=lambda x: x):
68
69
if path_match is None :
69
70
raise Exception ("invalid location matcher path %s" % path )
70
71
71
- path_field = path_match .group (1 )
72
- path_index = path_match .group (2 )
73
- path_last = not path_match .group (3 )
72
+ path_field = path_match .group (2 )
73
+ path_index = path_match .group (3 )
74
+ path_last = not path_match .group (4 )
74
75
75
76
if path_field is not None :
76
77
obj = getattr (obj , path_field )
@@ -148,3 +149,317 @@ def test_string(self):
148
149
"^ begin_loc"
149
150
" ^ end_loc" )
150
151
152
+ def test_ident (self ):
153
+ self .assertParsesExpr (
154
+ {'ty' : 'Name' , 'id' : 'foo' , 'ctx' : None },
155
+ "foo" ,
156
+ "~~~ loc" )
157
+
158
+ #
159
+ # OPERATORS
160
+ #
161
+
162
+ ast_1 = {'ty' : 'Num' , 'n' : 1 }
163
+
164
+ def test_unary (self ):
165
+ self .assertParsesExpr (
166
+ {'ty' : 'UnaryOp' , 'op' : {'ty' : 'UAdd' }, 'operand' : self .ast_1 },
167
+ "+1" ,
168
+ "~~ loc"
169
+ "~ op.loc" )
170
+
171
+ self .assertParsesExpr (
172
+ {'ty' : 'UnaryOp' , 'op' : {'ty' : 'USub' }, 'operand' : self .ast_1 },
173
+ "-1" ,
174
+ "~~ loc"
175
+ "~ op.loc" )
176
+
177
+ self .assertParsesExpr (
178
+ {'ty' : 'UnaryOp' , 'op' : {'ty' : 'Invert' }, 'operand' : self .ast_1 },
179
+ "~1" ,
180
+ "~~ loc"
181
+ "~ op.loc" )
182
+
183
+ def test_binary (self ):
184
+ self .assertParsesExpr (
185
+ {'ty' : 'BinOp' , 'op' : {'ty' : 'Pow' }, 'left' : self .ast_1 , 'right' : self .ast_1 },
186
+ "1 ** 1" ,
187
+ "~~~~~~ loc"
188
+ " ~~ op.loc" )
189
+
190
+ self .assertParsesExpr (
191
+ {'ty' : 'BinOp' , 'op' : {'ty' : 'Mult' }, 'left' : self .ast_1 , 'right' : self .ast_1 },
192
+ "1 * 1" ,
193
+ "~~~~~ loc"
194
+ " ^ op.loc" )
195
+
196
+ self .assertParsesExpr (
197
+ {'ty' : 'BinOp' , 'op' : {'ty' : 'Div' }, 'left' : self .ast_1 , 'right' : self .ast_1 },
198
+ "1 / 1" ,
199
+ "~~~~~ loc"
200
+ " ^ op.loc" )
201
+
202
+ self .assertParsesExpr (
203
+ {'ty' : 'BinOp' , 'op' : {'ty' : 'Mod' }, 'left' : self .ast_1 , 'right' : self .ast_1 },
204
+ "1 % 1" ,
205
+ "~~~~~ loc"
206
+ " ^ op.loc" )
207
+
208
+ self .assertParsesExpr (
209
+ {'ty' : 'BinOp' , 'op' : {'ty' : 'FloorDiv' }, 'left' : self .ast_1 , 'right' : self .ast_1 },
210
+ "1 // 1" ,
211
+ "~~~~~~ loc"
212
+ " ~~ op.loc" )
213
+
214
+ self .assertParsesExpr (
215
+ {'ty' : 'BinOp' , 'op' : {'ty' : 'Add' }, 'left' : self .ast_1 , 'right' : self .ast_1 },
216
+ "1 + 1" ,
217
+ "~~~~~ loc"
218
+ " ^ op.loc" )
219
+
220
+ self .assertParsesExpr (
221
+ {'ty' : 'BinOp' , 'op' : {'ty' : 'Sub' }, 'left' : self .ast_1 , 'right' : self .ast_1 },
222
+ "1 - 1" ,
223
+ "~~~~~ loc"
224
+ " ^ op.loc" )
225
+
226
+ def test_bitwise (self ):
227
+ self .assertParsesExpr (
228
+ {'ty' : 'BinOp' , 'op' : {'ty' : 'LShift' }, 'left' : self .ast_1 , 'right' : self .ast_1 },
229
+ "1 << 1" ,
230
+ "~~~~~~ loc"
231
+ " ~~ op.loc" )
232
+
233
+ self .assertParsesExpr (
234
+ {'ty' : 'BinOp' , 'op' : {'ty' : 'RShift' }, 'left' : self .ast_1 , 'right' : self .ast_1 },
235
+ "1 >> 1" ,
236
+ "~~~~~~ loc"
237
+ " ~~ op.loc" )
238
+
239
+ self .assertParsesExpr (
240
+ {'ty' : 'BinOp' , 'op' : {'ty' : 'BitAnd' }, 'left' : self .ast_1 , 'right' : self .ast_1 },
241
+ "1 & 1" ,
242
+ "~~~~~ loc"
243
+ " ^ op.loc" )
244
+
245
+ self .assertParsesExpr (
246
+ {'ty' : 'BinOp' , 'op' : {'ty' : 'BitOr' }, 'left' : self .ast_1 , 'right' : self .ast_1 },
247
+ "1 | 1" ,
248
+ "~~~~~ loc"
249
+ " ^ op.loc" )
250
+
251
+ self .assertParsesExpr (
252
+ {'ty' : 'BinOp' , 'op' : {'ty' : 'BitXor' }, 'left' : self .ast_1 , 'right' : self .ast_1 },
253
+ "1 ^ 1" ,
254
+ "~~~~~ loc"
255
+ " ^ op.loc" )
256
+
257
+ def test_compare (self ):
258
+ self .assertParsesExpr (
259
+ {'ty' : 'Compare' , 'ops' : [{'ty' : 'Lt' }],
260
+ 'left' : self .ast_1 , 'comparators' : [self .ast_1 ]},
261
+ "1 < 1" ,
262
+ "~~~~~ loc"
263
+ " ^ ops.0.loc" )
264
+
265
+ self .assertParsesExpr (
266
+ {'ty' : 'Compare' , 'ops' : [{'ty' : 'LtE' }],
267
+ 'left' : self .ast_1 , 'comparators' : [self .ast_1 ]},
268
+ "1 <= 1" ,
269
+ "~~~~~~ loc"
270
+ " ~~ ops.0.loc" )
271
+
272
+ self .assertParsesExpr (
273
+ {'ty' : 'Compare' , 'ops' : [{'ty' : 'Gt' }],
274
+ 'left' : self .ast_1 , 'comparators' : [self .ast_1 ]},
275
+ "1 > 1" ,
276
+ "~~~~~ loc"
277
+ " ^ ops.0.loc" )
278
+
279
+ self .assertParsesExpr (
280
+ {'ty' : 'Compare' , 'ops' : [{'ty' : 'GtE' }],
281
+ 'left' : self .ast_1 , 'comparators' : [self .ast_1 ]},
282
+ "1 >= 1" ,
283
+ "~~~~~~ loc"
284
+ " ~~ ops.0.loc" )
285
+
286
+ self .assertParsesExpr (
287
+ {'ty' : 'Compare' , 'ops' : [{'ty' : 'Eq' }],
288
+ 'left' : self .ast_1 , 'comparators' : [self .ast_1 ]},
289
+ "1 == 1" ,
290
+ "~~~~~~ loc"
291
+ " ~~ ops.0.loc" )
292
+
293
+ self .assertParsesExpr (
294
+ {'ty' : 'Compare' , 'ops' : [{'ty' : 'NotEq' }],
295
+ 'left' : self .ast_1 , 'comparators' : [self .ast_1 ]},
296
+ "1 != 1" ,
297
+ "~~~~~~ loc"
298
+ " ~~ ops.0.loc" )
299
+
300
+ self .assertParsesExpr (
301
+ {'ty' : 'Compare' , 'ops' : [{'ty' : 'NotEq' }],
302
+ 'left' : self .ast_1 , 'comparators' : [self .ast_1 ]},
303
+ "1 <> 1" ,
304
+ "~~~~~~ loc"
305
+ " ~~ ops.0.loc" )
306
+
307
+ self .assertParsesExpr (
308
+ {'ty' : 'Compare' , 'ops' : [{'ty' : 'In' }],
309
+ 'left' : self .ast_1 , 'comparators' : [self .ast_1 ]},
310
+ "1 in 1" ,
311
+ "~~~~~~ loc"
312
+ " ~~ ops.0.loc" )
313
+
314
+ self .assertParsesExpr (
315
+ {'ty' : 'Compare' , 'ops' : [{'ty' : 'NotIn' }],
316
+ 'left' : self .ast_1 , 'comparators' : [self .ast_1 ]},
317
+ "1 not in 1" ,
318
+ "~~~~~~~~~~ loc"
319
+ " ~~~~~~ ops.0.loc" )
320
+
321
+ self .assertParsesExpr (
322
+ {'ty' : 'Compare' , 'ops' : [{'ty' : 'Is' }],
323
+ 'left' : self .ast_1 , 'comparators' : [self .ast_1 ]},
324
+ "1 is 1" ,
325
+ "~~~~~~ loc"
326
+ " ~~ ops.0.loc" )
327
+
328
+ # self.assertParsesExpr(
329
+ # {'ty': 'Compare', 'ops': [{'ty': 'NotIs'}],
330
+ # 'left': self.ast_1, 'comparators': [self.ast_1]},
331
+ # "1 is not 1",
332
+ # "~~~~~~~~~~ loc"
333
+ # " ~~~~~~ ops.0.loc")
334
+
335
+ def test_compare_multi (self ):
336
+ self .assertParsesExpr (
337
+ {'ty' : 'Compare' , 'ops' : [{'ty' : 'Lt' }, {'ty' : 'LtE' }],
338
+ 'left' : self .ast_1 ,
339
+ 'comparators' : [{'ty' : 'Num' , 'n' : 2 }, {'ty' : 'Num' , 'n' : 3 }]},
340
+ "1 < 2 <= 3" ,
341
+ "~~~~~~~~~~ loc"
342
+ " ^ ops.0.loc"
343
+ " ~~ ops.1.loc" )
344
+
345
+ def test_boolop (self ):
346
+ self .assertParsesExpr (
347
+ {'ty' : 'BoolOp' , 'op' : {'ty' : 'And' }, 'values' : [self .ast_1 , self .ast_1 ]},
348
+ "1 and 1" ,
349
+ "~~~~~~~ loc"
350
+ " ~~~ op_locs.0" )
351
+
352
+ self .assertParsesExpr (
353
+ {'ty' : 'BoolOp' , 'op' : {'ty' : 'Or' }, 'values' : [self .ast_1 , self .ast_1 ]},
354
+ "1 or 1" ,
355
+ "~~~~~~ loc"
356
+ " ~~ op_locs.0" )
357
+
358
+ self .assertParsesExpr (
359
+ {'ty' : 'UnaryOp' , 'op' : {'ty' : 'Not' }, 'operand' : self .ast_1 },
360
+ "not 1" ,
361
+ "~~~~~ loc"
362
+ "~~~ op.loc" )
363
+
364
+ def test_boolop_multi (self ):
365
+ self .assertParsesExpr (
366
+ {'ty' : 'BoolOp' , 'op' : {'ty' : 'Or' }, 'values' : [self .ast_1 , self .ast_1 , self .ast_1 ]},
367
+ "1 or 1 or 1" ,
368
+ "~~~~~~~~~~~ loc"
369
+ " ~~ op_locs.0"
370
+ " ~~ op_locs.1" )
371
+
372
+ #
373
+ # STATEMENTS
374
+ #
375
+
376
+ ast_x = {'ty' : 'Name' , 'id' : 'x' , 'ctx' : None }
377
+ ast_y = {'ty' : 'Name' , 'id' : 'y' , 'ctx' : None }
378
+
379
+ def test_assign (self ):
380
+ self .assertParsesSuite (
381
+ [{'ty' : 'Assign' , 'targets' : [self .ast_x ], 'value' : self .ast_1 }],
382
+ "x = 1" ,
383
+ "~~~~~ 0.loc"
384
+ " ^ 0.op_locs.0" )
385
+
386
+ self .assertParsesSuite (
387
+ [{'ty' : 'Assign' , 'targets' : [self .ast_x , self .ast_y ], 'value' : self .ast_1 }],
388
+ "x = y = 1" ,
389
+ "~~~~~~~~~ 0.loc"
390
+ " ^ 0.op_locs.0"
391
+ " ^ 0.op_locs.1" )
392
+
393
+ def test_augassign (self ):
394
+ self .assertParsesSuite (
395
+ [{'ty' : 'AugAssign' , 'op' : {'ty' : 'Add' }, 'target' : self .ast_x , 'value' : self .ast_1 }],
396
+ "x += 1" ,
397
+ "~~~~~~ 0.loc"
398
+ " ~~ 0.op.loc" )
399
+
400
+ self .assertParsesSuite (
401
+ [{'ty' : 'AugAssign' , 'op' : {'ty' : 'Sub' }, 'target' : self .ast_x , 'value' : self .ast_1 }],
402
+ "x -= 1" ,
403
+ "~~~~~~ 0.loc"
404
+ " ~~ 0.op.loc" )
405
+
406
+ self .assertParsesSuite (
407
+ [{'ty' : 'AugAssign' , 'op' : {'ty' : 'Mult' }, 'target' : self .ast_x , 'value' : self .ast_1 }],
408
+ "x *= 1" ,
409
+ "~~~~~~ 0.loc"
410
+ " ~~ 0.op.loc" )
411
+
412
+ self .assertParsesSuite (
413
+ [{'ty' : 'AugAssign' , 'op' : {'ty' : 'Div' }, 'target' : self .ast_x , 'value' : self .ast_1 }],
414
+ "x /= 1" ,
415
+ "~~~~~~ 0.loc"
416
+ " ~~ 0.op.loc" )
417
+
418
+ self .assertParsesSuite (
419
+ [{'ty' : 'AugAssign' , 'op' : {'ty' : 'Mod' }, 'target' : self .ast_x , 'value' : self .ast_1 }],
420
+ "x %= 1" ,
421
+ "~~~~~~ 0.loc"
422
+ " ~~ 0.op.loc" )
423
+
424
+ self .assertParsesSuite (
425
+ [{'ty' : 'AugAssign' , 'op' : {'ty' : 'Pow' }, 'target' : self .ast_x , 'value' : self .ast_1 }],
426
+ "x **= 1" ,
427
+ "~~~~~~~ 0.loc"
428
+ " ~~~ 0.op.loc" )
429
+
430
+ self .assertParsesSuite (
431
+ [{'ty' : 'AugAssign' , 'op' : {'ty' : 'FloorDiv' }, 'target' : self .ast_x , 'value' : self .ast_1 }],
432
+ "x //= 1" ,
433
+ "~~~~~~~ 0.loc"
434
+ " ~~~ 0.op.loc" )
435
+
436
+ self .assertParsesSuite (
437
+ [{'ty' : 'AugAssign' , 'op' : {'ty' : 'RShift' }, 'target' : self .ast_x , 'value' : self .ast_1 }],
438
+ "x >>= 1" ,
439
+ "~~~~~~~ 0.loc"
440
+ " ~~~ 0.op.loc" )
441
+
442
+ self .assertParsesSuite (
443
+ [{'ty' : 'AugAssign' , 'op' : {'ty' : 'LShift' }, 'target' : self .ast_x , 'value' : self .ast_1 }],
444
+ "x <<= 1" ,
445
+ "~~~~~~~ 0.loc"
446
+ " ~~~ 0.op.loc" )
447
+
448
+ self .assertParsesSuite (
449
+ [{'ty' : 'AugAssign' , 'op' : {'ty' : 'BitAnd' }, 'target' : self .ast_x , 'value' : self .ast_1 }],
450
+ "x &= 1" ,
451
+ "~~~~~~ 0.loc"
452
+ " ~~ 0.op.loc" )
453
+
454
+ self .assertParsesSuite (
455
+ [{'ty' : 'AugAssign' , 'op' : {'ty' : 'BitOr' }, 'target' : self .ast_x , 'value' : self .ast_1 }],
456
+ "x |= 1" ,
457
+ "~~~~~~ 0.loc"
458
+ " ~~ 0.op.loc" )
459
+
460
+ self .assertParsesSuite (
461
+ [{'ty' : 'AugAssign' , 'op' : {'ty' : 'BitXor' }, 'target' : self .ast_x , 'value' : self .ast_1 }],
462
+ "x ^= 1" ,
463
+ "~~~~~~ 0.loc"
464
+ " ~~ 0.op.loc" )
465
+
0 commit comments