def _MyPyType(typ): type_name = typ.name if type_name == 'map': k_type = _MyPyType(typ.children[0]) v_type = _MyPyType(typ.children[1]) return 'Dict[%s, %s]' % (k_type, v_type) if type_name == 'array': return 'List[%s]' % _MyPyType(typ.children[0]) if type_name == 'maybe': # TODO: maybe[int] and maybe[simple_sum] are invalid return 'Optional[%s]' % _MyPyType(typ.children[0]) if typ.resolved: if isinstance(typ.resolved, asdl_.Sum): # includes SimpleSum return '%s_t' % typ.name if isinstance(typ.resolved, asdl_.Product): return typ.name if isinstance(typ.resolved, asdl_.Use): return asdl_.TypeNameHeuristic(type_name) # 'id' falls through here return _PRIMITIVES[type_name]
def _GetCppType(typ): type_name = typ.name if type_name == 'map': k_type = _GetCppType(typ.children[0]) v_type = _GetCppType(typ.children[1]) return 'Dict<%s, %s>*' % (k_type, v_type) elif type_name == 'array': c_type = _GetCppType(typ.children[0]) return 'List<%s>*' % (c_type) elif type_name == 'maybe': c_type = _GetCppType(typ.children[0]) # TODO: maybe[int] and maybe[simple_sum] are invalid return c_type elif typ.resolved: if isinstance(typ.resolved, asdl_.SimpleSum): return '%s_t' % typ.name if isinstance(typ.resolved, asdl_.Sum): return '%s_t*' % typ.name if isinstance(typ.resolved, asdl_.Product): return '%s*' % typ.name if isinstance(typ.resolved, asdl_.Use): return '%s_asdl::%s*' % (typ.resolved.mod_name, asdl_.TypeNameHeuristic(type_name)) # 'id' falls through here return _PRIMITIVES[typ.name]
def main(argv): try: action = argv[1] except IndexError: raise RuntimeError('Action required') try: schema_path = argv[2] except IndexError: raise RuntimeError('Schema path required') schema_filename = os.path.basename(schema_path) if schema_filename in ('syntax.asdl', 'runtime.asdl'): app_types = {'id': UserType('id_kind_asdl', 'Id_t')} else: app_types = {} if action == 'c': # Generate C code for the lexer with open(schema_path) as f: schema_ast = front_end.LoadSchema(f, app_types) v = gen_cpp.CEnumVisitor(sys.stdout) v.VisitModule(schema_ast) elif action == 'cpp': # Generate C++ code for ASDL schemas out_prefix = argv[3] pretty_print_methods = bool(os.getenv('PRETTY_PRINT_METHODS', 'yes')) with open(schema_path) as f: schema_ast = front_end.LoadSchema(f, app_types) # asdl/typed_arith.asdl -> typed_arith_asdl ns = os.path.basename(schema_path).replace('.', '_') with open(out_prefix + '.h', 'w') as f: guard = ns.upper() f.write("""\ // %s.h is generated by asdl/tool.py #ifndef %s #define %s """ % (out_prefix, guard, guard)) f.write("""\ #include <cstdint> #include "mylib.h" // for Str, List, etc. """) if pretty_print_methods: f.write("""\ #include "hnode_asdl.h" using hnode_asdl::hnode_t; """) if app_types: f.write("""\ #include "id_kind_asdl.h" using id_kind_asdl::Id_t; """) for use in schema_ast.uses: # Forward declarations in the header, like # namespace syntax_asdl { class command_t; } # must come BEFORE namespace, so it can't be in the visitor. # assume sum type for now! cpp_names = [ 'class %s;' % asdl_.TypeNameHeuristic(n) for n in use.type_names ] f.write('namespace %s_asdl { %s }\n' % (use.mod_name, ' '.join(cpp_names))) f.write('\n') f.write("""\ namespace %s { """ % ns) v = gen_cpp.ForwardDeclareVisitor(f) v.VisitModule(schema_ast) debug_info = {} v2 = gen_cpp.ClassDefVisitor( f, pretty_print_methods=pretty_print_methods, simple_int_sums=_SIMPLE, debug_info=debug_info) v2.VisitModule(schema_ast) f.write(""" } // namespace %s #endif // %s """ % (ns, guard)) try: debug_info_path = argv[4] except IndexError: pass else: with open(debug_info_path, 'w') as f: from pprint import pformat f.write('''\ cpp_namespace = %r tags_to_types = \\ %s ''' % (ns, pformat(debug_info))) with open(out_prefix + '.cc', 'w') as f: f.write("""\ // %s.cc is generated by asdl/tool.py #include "%s.h" #include <assert.h> #include "asdl_runtime.h" // generated code uses wrappers here """ % (out_prefix, ns)) # To call pretty-printing methods for use in schema_ast.uses: f.write('#include "%s_asdl.h" // ASDL use\n' % use.mod_name) f.write("""\ // Generated code uses these types using hnode_asdl::hnode__Record; using hnode_asdl::hnode__Array; using hnode_asdl::hnode__External; using hnode_asdl::hnode__Leaf; using hnode_asdl::field; using hnode_asdl::color_e; """) if app_types: f.write('using id_kind_asdl::Id_str;\n') f.write(""" namespace %s { """ % ns) v3 = gen_cpp.MethodDefVisitor( f, pretty_print_methods=pretty_print_methods, simple_int_sums=_SIMPLE) v3.VisitModule(schema_ast) f.write(""" } // namespace %s """ % ns) elif action == 'mypy': # Generated typed MyPy code with open(schema_path) as f: schema_ast = front_end.LoadSchema(f, app_types) try: abbrev_module_name = argv[3] except IndexError: abbrev_mod = None else: # Weird Python rule for importing: fromlist needs to be non-empty. abbrev_mod = __import__(abbrev_module_name, fromlist=['.']) f = sys.stdout # TODO: Remove Any once we stop using it f.write("""\ from asdl import pybase from typing import Optional, List, Tuple, Dict, Any, cast, TYPE_CHECKING """) if schema_ast.uses: f.write('\n') f.write('if TYPE_CHECKING:\n') for use in schema_ast.uses: py_names = [asdl_.TypeNameHeuristic(n) for n in use.type_names] # indented f.write(' from _devbuild.gen.%s_asdl import %s\n' % (use.mod_name, ', '.join(py_names))) f.write('\n') for typ in app_types.itervalues(): if isinstance(typ, UserType): f.write('from _devbuild.gen.%s import %s\n' % (typ.mod_name, typ.type_name)) # HACK f.write('from _devbuild.gen.%s import Id_str\n' % typ.mod_name) f.write('\n') pretty_print_methods = bool(os.getenv('PRETTY_PRINT_METHODS', 'yes')) optional_fields = bool(os.getenv('OPTIONAL_FIELDS', 'yes')) if pretty_print_methods: f.write(""" from asdl import runtime # For runtime.NO_SPID from asdl.runtime import NewRecord, NewLeaf from _devbuild.gen.hnode_asdl import color_e, hnode, hnode_e, hnode_t, field """) abbrev_mod_entries = dir(abbrev_mod) if abbrev_mod else [] v = gen_python.GenMyPyVisitor( f, abbrev_mod_entries, pretty_print_methods=pretty_print_methods, optional_fields=optional_fields, simple_int_sums=_SIMPLE) v.VisitModule(schema_ast) if abbrev_mod: f.write("""\ # # CONCATENATED FILE # """) package, module = abbrev_module_name.split('.') path = os.path.join(package, module + '.py') with open(path) as in_f: f.write(in_f.read()) else: raise RuntimeError('Invalid action %r' % action)