OILS / asdl / asdl_main.py View on Github | oils.pub

174 lines, 119 significant
1#!/usr/bin/env python2
2"""
3asdl_main.py - Generate Python and C from ASDL schemas.
4"""
5from __future__ import print_function
6
7import optparse
8import os
9import sys
10
11from asdl import front_end
12from asdl import gen_cpp
13from asdl import gen_python
14from asdl import metrics
15from asdl.util import log
16
17from typing import Dict
18from typing import Any
19from typing import List
20
21ARG_0 = os.path.basename(sys.argv[0])
22
23
24def Options():
25 # type: () -> Any
26 """Returns an option parser instance."""
27
28 p = optparse.OptionParser()
29 p.add_option('--no-pretty-print-methods',
30 dest='pretty_print_methods',
31 action='store_false',
32 default=True,
33 help='Whether to generate pretty printing methods')
34
35 # Control Python constructors
36
37 # for hnode.asdl
38 p.add_option('--py-init-N',
39 dest='py_init_n',
40 action='store_true',
41 default=False,
42 help='Generate Python __init__ that requires every field')
43
44 # The default, which matches C++
45 p.add_option(
46 '--init-zero-N',
47 dest='init_zero_n',
48 action='store_true',
49 default=True,
50 help='Generate 0 arg and N arg constructors, in Python and C++')
51
52 p.add_option('--abbrev-module',
53 dest='abbrev_module',
54 default=None,
55 help='Import this module to find abbreviations')
56
57 return p
58
59
60class Abbrev(object):
61 """A struct for convenience"""
62
63 def __init__(self, module=None, ns=None, mod_entries=None):
64 # type: (str, str, List[str]) -> None
65 self.module = module
66 self.ns = ns
67 self.mod_entries = mod_entries
68
69
70def main(argv):
71 # type: (List[str]) -> None
72 o = Options()
73 opts, argv = o.parse_args(argv)
74
75 try:
76 action = argv[1]
77 except IndexError:
78 raise RuntimeError('Action required')
79
80 try:
81 schema_path = argv[2]
82 except IndexError:
83 raise RuntimeError('Schema path required')
84
85 schema_filename = os.path.basename(schema_path)
86
87 abbrev = Abbrev()
88 abbrev.module = opts.abbrev_module
89 if opts.abbrev_module:
90 # Weird Python rule for importing: fromlist needs to be non-empty.
91 abbrev_mod = __import__(opts.abbrev_module, fromlist=['.'])
92 abbrev.mod_entries = dir(abbrev_mod)
93 abbrev.ns = opts.abbrev_module.split('.')[-1] # e.g. syntax_abbrev
94 else:
95 abbrev_mod = None
96 abbrev.mod_entries = []
97 abbrev.ns = None
98
99 if action == 'metrics': # Sum type metrics
100 with open(schema_path) as f:
101 schema_ast, _ = front_end.LoadSchema(f)
102
103 v = metrics.MetricsVisitor(sys.stdout)
104 v.VisitModule(schema_ast)
105
106 elif action == 'closure': # count all types that command_t references
107 type_name = argv[3]
108 with open(schema_path) as f:
109 schema_ast, type_lookup = front_end.LoadSchema(f)
110
111 seen = {} # type: Dict[str, bool]
112 c = metrics.ClosureWalk(type_lookup, seen)
113 c.DoModule(schema_ast, type_name)
114 for name in sorted(seen):
115 print(name)
116 log('SHARED (%d): %s', len(c.shared), ' '.join(sorted(c.shared)))
117
118 elif action == 'c': # Generate C code for the lexer
119 with open(schema_path) as f:
120 schema_ast, _ = front_end.LoadSchema(f)
121
122 v0 = gen_cpp.CEnumVisitor(sys.stdout)
123 v0.VisitModule(schema_ast)
124
125 elif action == 'cpp': # Generate C++ code for ASDL schemas
126 out_prefix = argv[3]
127 try:
128 debug_info_path = argv[4]
129 except IndexError:
130 debug_info_path = None
131
132 with open(schema_path) as f:
133 schema_ast, _ = front_end.LoadSchema(f)
134
135 # asdl/typed_arith.asdl -> typed_arith_asdl
136 ns = os.path.basename(schema_path).replace('.', '_')
137
138 debug_info = gen_cpp.WriteHeaderFile(schema_ast, ARG_0, ns,
139 opts.pretty_print_methods,
140 out_prefix)
141
142 if debug_info_path:
143 gen_cpp.WriteDebugInfo(debug_info, ns, debug_info_path)
144
145 if not opts.pretty_print_methods:
146 # No .cc file at all
147 return
148
149 gen_cpp.WriteCppFile(schema_ast, ARG_0, ns, abbrev, out_prefix)
150
151 elif action == 'mypy': # Generated typed MyPy code
152 with open(schema_path) as f:
153 schema_ast, _ = front_end.LoadSchema(f)
154
155 f = sys.stdout # type: ignore
156
157 v4 = gen_python.GenMyPyVisitor(
158 f,
159 opts.abbrev_module,
160 abbrev.mod_entries,
161 pretty_print_methods=opts.pretty_print_methods,
162 py_init_n=opts.py_init_n)
163 v4.VisitModule(schema_ast)
164
165 else:
166 raise RuntimeError('Invalid action %r' % action)
167
168
169if __name__ == '__main__':
170 try:
171 main(sys.argv)
172 except RuntimeError as e:
173 print('%s: FATAL: %s' % (ARG_0, e), file=sys.stderr)
174 sys.exit(1)