44import os
55import sys
66import textwrap
7+ import types
78
89from argparse import ArgumentParser
910from contextlib import contextmanager
@@ -100,11 +101,12 @@ def asdl_of(name, obj):
100101class EmitVisitor (asdl .VisitorBase ):
101102 """Visit that emits lines"""
102103
103- def __init__ (self , file ):
104+ def __init__ (self , file , metadata = None ):
104105 self .file = file
105106 self .identifiers = set ()
106107 self .singletons = set ()
107108 self .types = set ()
109+ self ._metadata = metadata
108110 super (EmitVisitor , self ).__init__ ()
109111
110112 def emit_identifier (self , name ):
@@ -127,6 +129,42 @@ def emit(self, s, depth, reflow=True):
127129 line = (" " * TABSIZE * depth ) + line
128130 self .file .write (line + "\n " )
129131
132+ @property
133+ def metadata (self ):
134+ if self ._metadata is None :
135+ raise ValueError (
136+ "%s was expecting to be annnotated with metadata"
137+ % type (self ).__name__
138+ )
139+ return self ._metadata
140+
141+ @metadata .setter
142+ def metadata (self , value ):
143+ self ._metadata = value
144+
145+ class MetadataVisitor (asdl .VisitorBase ):
146+ def __init__ (self , * args , ** kwargs ):
147+ super ().__init__ (* args , ** kwargs )
148+
149+ # Metadata:
150+ # - simple_sums: Tracks the list of compound type
151+ # names where all the constructors
152+ # belonging to that type lack of any
153+ # fields.
154+ self .metadata = types .SimpleNamespace (
155+ simple_sums = set ()
156+ )
157+
158+ def visitModule (self , mod ):
159+ for dfn in mod .dfns :
160+ self .visit (dfn )
161+
162+ def visitType (self , type ):
163+ self .visit (type .value , type .name )
164+
165+ def visitSum (self , sum , name ):
166+ if is_simple (sum ):
167+ self .metadata .simple_sums .add (name )
130168
131169class TypeDefVisitor (EmitVisitor ):
132170 def visitModule (self , mod ):
@@ -244,7 +282,7 @@ def visitField(self, field, depth):
244282 ctype = get_c_type (field .type )
245283 name = field .name
246284 if field .seq :
247- if field .type == 'cmpop' :
285+ if field .type in self . metadata . simple_sums :
248286 self .emit ("asdl_int_seq *%(name)s;" % locals (), depth )
249287 else :
250288 _type = field .type
@@ -304,7 +342,7 @@ def get_args(self, fields):
304342 name = f .name
305343 # XXX should extend get_c_type() to handle this
306344 if f .seq :
307- if f .type == 'cmpop' :
345+ if f .type in self . metadata . simple_sums :
308346 ctype = "asdl_int_seq *"
309347 else :
310348 ctype = f"asdl_{ f .type } _seq *"
@@ -549,16 +587,11 @@ def visitFieldDeclaration(self, field, name, sum=None, prod=None, depth=0):
549587 ctype = get_c_type (field .type )
550588 self .emit ("%s %s;" % (ctype , field .name ), depth )
551589
552- def isSimpleSum (self , field ):
553- # XXX can the members of this list be determined automatically?
554- return field .type in ('expr_context' , 'boolop' , 'operator' ,
555- 'unaryop' , 'cmpop' )
556-
557590 def isNumeric (self , field ):
558591 return get_c_type (field .type ) in ("int" , "bool" )
559592
560593 def isSimpleType (self , field ):
561- return self .isSimpleSum ( field ) or self .isNumeric (field )
594+ return field . type in self .metadata . simple_sums or self .isNumeric (field )
562595
563596 def visitField (self , field , name , sum = None , prod = None , depth = 0 ):
564597 ctype = get_c_type (field .type )
@@ -1282,18 +1315,23 @@ def emit(s, d):
12821315
12831316 def set (self , field , value , depth ):
12841317 if field .seq :
1285- # XXX should really check for is_simple, but that requires a symbol table
1286- if field .type == "cmpop" :
1318+ if field .type in self .metadata .simple_sums :
12871319 # While the sequence elements are stored as void*,
1288- # ast2obj_cmpop expects an enum
1320+ # simple sums expects an enum
12891321 self .emit ("{" , depth )
12901322 self .emit ("Py_ssize_t i, n = asdl_seq_LEN(%s);" % value , depth + 1 )
12911323 self .emit ("value = PyList_New(n);" , depth + 1 )
12921324 self .emit ("if (!value) goto failed;" , depth + 1 )
12931325 self .emit ("for(i = 0; i < n; i++)" , depth + 1 )
12941326 # This cannot fail, so no need for error handling
1295- self .emit ("PyList_SET_ITEM(value, i, ast2obj_cmpop(state, (cmpop_ty)asdl_seq_GET(%s, i)));" % value ,
1296- depth + 2 , reflow = False )
1327+ self .emit (
1328+ "PyList_SET_ITEM(value, i, ast2obj_{0}(state, ({0}_ty)asdl_seq_GET({1}, i)));" .format (
1329+ field .type ,
1330+ value
1331+ ),
1332+ depth + 2 ,
1333+ reflow = False ,
1334+ )
12971335 self .emit ("}" , depth )
12981336 else :
12991337 self .emit ("value = ast2obj_list(state, (asdl_seq*)%s, ast2obj_%s);" % (value , field .type ), depth )
@@ -1362,11 +1400,13 @@ class PartingShots(StaticVisitor):
13621400"""
13631401
13641402class ChainOfVisitors :
1365- def __init__ (self , * visitors ):
1403+ def __init__ (self , * visitors , metadata = None ):
13661404 self .visitors = visitors
1405+ self .metadata = metadata
13671406
13681407 def visit (self , object ):
13691408 for v in self .visitors :
1409+ v .metadata = self .metadata
13701410 v .visit (object )
13711411 v .emit ("" , 0 )
13721412
@@ -1468,7 +1508,7 @@ def generate_module_def(mod, f, internal_h):
14681508 f .write (' return 1;\n ' )
14691509 f .write ('};\n \n ' )
14701510
1471- def write_header (mod , f ):
1511+ def write_header (mod , metadata , f ):
14721512 f .write (textwrap .dedent ("""
14731513 #ifndef Py_INTERNAL_AST_H
14741514 #define Py_INTERNAL_AST_H
@@ -1483,12 +1523,19 @@ def write_header(mod, f):
14831523 #include "pycore_asdl.h"
14841524
14851525 """ ).lstrip ())
1486- c = ChainOfVisitors (TypeDefVisitor (f ),
1487- SequenceDefVisitor (f ),
1488- StructVisitor (f ))
1526+
1527+ c = ChainOfVisitors (
1528+ TypeDefVisitor (f ),
1529+ SequenceDefVisitor (f ),
1530+ StructVisitor (f ),
1531+ metadata = metadata
1532+ )
14891533 c .visit (mod )
1534+
14901535 f .write ("// Note: these macros affect function definitions, not only call sites.\n " )
1491- PrototypeVisitor (f ).visit (mod )
1536+ prototype_visitor = PrototypeVisitor (f , metadata = metadata )
1537+ prototype_visitor .visit (mod )
1538+
14921539 f .write (textwrap .dedent ("""
14931540
14941541 PyObject* PyAST_mod2obj(mod_ty t);
@@ -1535,8 +1582,7 @@ def write_internal_h_footer(mod, f):
15351582 #endif /* !Py_INTERNAL_AST_STATE_H */
15361583 """ ), file = f )
15371584
1538-
1539- def write_source (mod , f , internal_h_file ):
1585+ def write_source (mod , metadata , f , internal_h_file ):
15401586 generate_module_def (mod , f , internal_h_file )
15411587
15421588 v = ChainOfVisitors (
@@ -1549,6 +1595,7 @@ def write_source(mod, f, internal_h_file):
15491595 Obj2ModVisitor (f ),
15501596 ASTModuleVisitor (f ),
15511597 PartingShots (f ),
1598+ metadata = metadata
15521599 )
15531600 v .visit (mod )
15541601
@@ -1561,6 +1608,10 @@ def main(input_filename, c_filename, h_filename, internal_h_filename, dump_modul
15611608 if not asdl .check (mod ):
15621609 sys .exit (1 )
15631610
1611+ metadata_visitor = MetadataVisitor ()
1612+ metadata_visitor .visit (mod )
1613+ metadata = metadata_visitor .metadata
1614+
15641615 with c_filename .open ("w" ) as c_file , \
15651616 h_filename .open ("w" ) as h_file , \
15661617 internal_h_filename .open ("w" ) as internal_h_file :
@@ -1569,8 +1620,8 @@ def main(input_filename, c_filename, h_filename, internal_h_filename, dump_modul
15691620 internal_h_file .write (auto_gen_msg )
15701621
15711622 write_internal_h_header (mod , internal_h_file )
1572- write_source (mod , c_file , internal_h_file )
1573- write_header (mod , h_file )
1623+ write_source (mod , metadata , c_file , internal_h_file )
1624+ write_header (mod , metadata , h_file )
15741625 write_internal_h_footer (mod , internal_h_file )
15751626
15761627 print (f"{ c_filename } , { h_filename } , { internal_h_filename } regenerated." )
0 commit comments