1
- # Copyright (c) 2019-2023 by Rocky Bernstein
1
+ # Copyright (c) 2019-2024 by Rocky Bernstein
2
2
3
3
# This program is free software: you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
14
14
# along with this program. If not, see <http://www.gnu.org/licenses/>.
15
15
16
16
from copy import copy
17
+ from typing import Optional
17
18
18
19
from spark_parser import GenericASTTraversal , GenericASTTraversalPruningException
19
20
@@ -56,29 +57,34 @@ def is_docstring(node, version, co_consts):
56
57
return node == ASSIGN_DOC_STRING (co_consts [0 ], doc_load )
57
58
58
59
59
- def is_not_docstring (call_stmt_node ):
60
+ def is_not_docstring (call_stmt_node ) -> bool :
60
61
try :
61
62
return (
62
63
call_stmt_node == "call_stmt"
63
64
and call_stmt_node [0 ][0 ] == "LOAD_STR"
64
65
and call_stmt_node [1 ] == "POP_TOP"
65
66
)
66
- except :
67
+ except Exception :
67
68
return False
68
69
69
70
70
71
class TreeTransform (GenericASTTraversal , object ):
71
- def __init__ (self , version , show_ast = None , is_pypy = False ):
72
+ def __init__ (
73
+ self ,
74
+ version : tuple ,
75
+ is_pypy = False ,
76
+ show_ast : Optional [dict ] = None ,
77
+ ):
72
78
self .version = version
73
79
self .showast = show_ast
74
80
self .is_pypy = is_pypy
75
81
return
76
82
77
- def maybe_show_tree (self , ast ):
83
+ def maybe_show_tree (self , tree ):
78
84
if isinstance (self .showast , dict ) and (
79
85
self .showast .get ("before" ) or self .showast .get ("after" )
80
86
):
81
- maybe_show_tree (self , ast )
87
+ maybe_show_tree (self , tree )
82
88
83
89
def preorder (self , node = None ):
84
90
"""Walk the tree in roughly 'preorder' (a bit of a lie explained below).
@@ -122,6 +128,7 @@ def n_mkfunc(self, node):
122
128
123
129
mkfunc_pattr = node [- 1 ].pattr
124
130
if isinstance (mkfunc_pattr , tuple ):
131
+ assert isinstance (mkfunc_pattr , tuple )
125
132
assert len (mkfunc_pattr ) == 4 and isinstance (mkfunc_pattr , int )
126
133
127
134
if len (code .co_consts ) > 0 and isinstance (code .co_consts [0 ], str ):
@@ -216,6 +223,7 @@ def n_ifstmt(self, node):
216
223
return node
217
224
if isinstance (call [1 ], SyntaxTree ):
218
225
expr = call [1 ][0 ]
226
+ assert_expr .transformed_by = "n_ifstmt"
219
227
node = SyntaxTree (
220
228
kind ,
221
229
[
@@ -225,8 +233,8 @@ def n_ifstmt(self, node):
225
233
expr ,
226
234
RAISE_VARARGS_1 ,
227
235
],
236
+ transformed_by = "n_ifstmt" ,
228
237
)
229
- node .transformed_by = "n_ifstmt"
230
238
pass
231
239
pass
232
240
else :
@@ -254,9 +262,10 @@ def n_ifstmt(self, node):
254
262
255
263
LOAD_ASSERT = expr [0 ]
256
264
node = SyntaxTree (
257
- kind , [assert_expr , jump_cond , LOAD_ASSERT , RAISE_VARARGS_1 ]
265
+ kind ,
266
+ [assert_expr , jump_cond , LOAD_ASSERT , RAISE_VARARGS_1 ],
267
+ transformed_by = "n_ifstmt" ,
258
268
)
259
- node .transformed_by = ("n_ifstmt" ,)
260
269
pass
261
270
pass
262
271
return node
@@ -416,6 +425,12 @@ def n_list_for(self, list_for_node):
416
425
list_for_node .transformed_by = ("n_list_for" ,)
417
426
return list_for_node
418
427
428
+ def n_negated_testtrue (self , node ):
429
+ assert node [0 ] == "testtrue"
430
+ test_node = node [0 ][0 ]
431
+ test_node .transformed_by = "n_negated_testtrue"
432
+ return test_node
433
+
419
434
def n_stmts (self , node ):
420
435
if node .first_child () == "SETUP_ANNOTATIONS" :
421
436
prev = node [0 ][0 ]
@@ -448,26 +463,28 @@ def traverse(self, node, is_lambda=False):
448
463
node = self .preorder (node )
449
464
return node
450
465
451
- def transform (self , ast , code ):
452
- self .maybe_show_tree (ast )
453
- self .ast = copy (ast )
466
+ def transform (self , parse_tree : GenericASTTraversal , code ) -> GenericASTTraversal :
467
+ self .maybe_show_tree (parse_tree )
468
+ self .ast = copy (parse_tree )
469
+ del parse_tree
454
470
self .ast = self .traverse (self .ast , is_lambda = False )
471
+ n = len (self .ast )
455
472
456
473
try :
457
474
# Disambiguate a string (expression) which appears as a "call_stmt" at
458
475
# the beginning of a function versus a docstring. Seems pretty academic,
459
476
# but this is Python.
460
- call_stmt = ast [0 ][0 ]
477
+ call_stmt = self . ast [0 ][0 ]
461
478
if is_not_docstring (call_stmt ):
462
479
call_stmt .kind = "string_at_beginning"
463
480
call_stmt .transformed_by = "transform"
464
481
pass
465
- except :
482
+ except Exception :
466
483
pass
467
484
468
485
try :
469
- for i in range (len ( self . ast ) ):
470
- sstmt = ast [i ]
486
+ for i in range (n ):
487
+ sstmt = self . ast [i ]
471
488
if len (sstmt ) == 1 and sstmt == "sstmt" :
472
489
self .ast [i ] = self .ast [i ][0 ]
473
490
@@ -493,7 +510,7 @@ def transform(self, ast, code):
493
510
if self .ast [- 1 ] == RETURN_NONE :
494
511
self .ast .pop () # remove last node
495
512
# todo: if empty, add 'pass'
496
- except :
513
+ except Exception :
497
514
pass
498
515
499
516
return self .ast
0 commit comments