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

357 lines, 176 significant
1"""AST for ASDL.
2
3This is not self-hosted! If it were, it would look something like this.
4
5TODO: move it toward this schema
6
7type_expr =
8 NamedType(str name, asdl_type resolved)
9| ParameterizedType(str type_name, List[type_expr] children)
10
11Field = (type_expr typ, str name)
12
13Constructor = (List[Field] fields, str name, str shared_type)
14
15# TODO: use variant instead of constructor
16variant =
17 Simple(str name)
18 Compound(str name, List[fields])
19 SharedVariant(str tag_name, str shared_variant)
20
21Use = (List[str] module_parts, str type_names)
22Extern = (List[str] names)
23
24asdl_type =
25 Sum(List[Constructor] variants, List[str] generate)
26 | SimpleSum() # This is just List[name]
27 | Product(List[Field] fields)
28
29 # These go in the TypeLookup dict!
30 # Shouldn't they be a BINDING?
31 | Use %Use
32 | Extern %Extern
33
34binding =
35 TypeDecl(str name, asdl_type value)
36| SubTypeDecl(str name, type_expr base_class)
37
38Module = (
39 str name,
40 List[Use] uses,
41 List[Extern] externs,
42 # Are Type and SubType ordered? Right now they are. C++ and Python may
43 # differ in terms of order.
44 List[binding] defs
45)
46"""
47from __future__ import print_function
48
49import cStringIO
50
51from typing import List, Optional
52
53# The following classes are the AST for the ASDL schema, i.e. the "meta-AST".
54# See the EBNF at the top of the file to understand the logical connection
55# between the various node types.
56
57
58class _Printable(object):
59
60 def Print(self, f, indent):
61 raise NotImplementedError()
62
63 def __str__(self):
64 f = cStringIO.StringIO()
65 self.Print(f, 0)
66 return f.getvalue()
67
68
69class asdl_type_t(_Printable):
70 pass
71
72
73class UserType(asdl_type_t):
74
75 def __init__(self, mod_name, type_name):
76 # type: (str, str) -> None
77 self.mod_name = mod_name
78 self.type_name = type_name
79
80 def Print(self, f, indent):
81 ind = indent * ' '
82 f.write('%sUserType %s %s' % (self.mod_name, self.type_name))
83
84
85class Use(asdl_type_t):
86
87 def __init__(self, module_parts, type_names):
88 # type: (List[str], List[str]) -> None
89 self.module_parts = module_parts
90 self.type_names = type_names
91
92 def Print(self, f, indent):
93 ind = indent * ' '
94 f.write('%sUse %s {\n' % (ind, ' '.join(self.module_parts)))
95 f.write(' %s%s\n' % (ind, ', '.join(t for t in self.type_names)))
96 f.write('%s}\n' % ind)
97
98
99class Extern(asdl_type_t):
100
101 def __init__(self, names):
102 # type: (List[str]) -> None
103 self.names = names
104
105 def Print(self, f, indent):
106 ind = indent * ' '
107 f.write('%sExtern [ %s ]\n' % (ind, ' '.join(self.names)))
108
109
110class Module(_Printable):
111
112 def __init__(self, name, uses, externs, dfns):
113 # type: (str, List[Use], List[Extern], List[binding_t]) -> None
114 self.name = name
115 self.uses = uses
116 self.externs = externs
117 self.dfns = dfns
118
119 def Print(self, f, indent):
120 ind = indent * ' '
121 f.write('%sModule %s {\n' % (ind, self.name))
122
123 for u in self.uses:
124 u.Print(f, indent + 1)
125 f.write('\n')
126
127 for e in self.externs:
128 e.Print(f, indent + 1)
129 f.write('\n')
130
131 for d in self.dfns:
132 d.Print(f, indent + 1)
133 f.write('\n')
134 f.write('%s}\n' % ind)
135
136
137class binding_t(_Printable):
138 pass
139
140
141class TypeDecl(binding_t):
142 """A binding of name to a Sum or Product type."""
143
144 def __init__(self, name, value):
145 # type: (str, asdl_type_t) -> None
146 self.name = name
147 self.value = value
148
149 def Print(self, f, indent):
150 ind = indent * ' '
151 f.write('%sType %s {\n' % (ind, self.name))
152 self.value.Print(f, indent + 1)
153 f.write('%s}\n' % ind)
154
155
156class SubTypeDecl(binding_t):
157 """A declaration of a subtype.
158
159 CompoundWord < List[word_part]
160 """
161
162 def __init__(self, name, base_class):
163 # type: (str, type_expr_t) -> None
164 self.name = name
165 self.base_class = base_class
166
167 def Print(self, f, indent):
168 ind = indent * ' '
169 f.write('%sType %s {\n' % (ind, self.name))
170 self.base_class.Print(f, indent + 1)
171 f.write('%s}\n' % ind)
172
173
174class type_expr_t(_Printable):
175 pass
176
177
178class NamedType(type_expr_t):
179 """Int, string are resolved to a Primitive type 'Point' can be resolved to
180 CompoundSum instance, etc."""
181
182 def __init__(self, name):
183 # type: (str) -> None
184 self.name = name
185
186 # Mutated by _ResolveModule / _ResolveType
187 self.resolved = None # type: Optional[asdl_type_t]
188
189 def Print(self, f, indent):
190 f.write('NamedType %s' % (self.name)) # printed after field
191 f.write(' (%r)' % self.resolved)
192
193
194class ParameterizedType(type_expr_t):
195 """A parameterized type expression, e.g. the type of a field.
196
197 Examples:
198 List[mytype] # used to be mytype*
199 Optional[mytype] # used to by mytype?
200 Dict[str, int]
201 Dict[int, List[str]]
202 """
203
204 def __init__(self, type_name, children):
205 # type: (str, List[type_expr_t]) -> None
206 self.type_name = type_name
207 self.children = children
208
209 def Print(self, f, indent):
210 """Printed on one line."""
211 f.write('%s' % (self.type_name)) # printed after field
212 if self.children:
213 f.write(' [ ')
214 for i, child in enumerate(self.children):
215 if i != 0:
216 f.write(', ')
217 child.Print(f, indent + 1)
218 f.write(' ]')
219
220
221class Field(_Printable):
222
223 def __init__(self, typ, name):
224 # type: (type_expr_t, str) -> None
225 self.typ = typ # type expression
226 self.name = name # variable name
227
228 def Print(self, f, indent):
229 ind = indent * ' '
230 f.write('%sField %r ' % (ind, self.name))
231 self.typ.Print(f, indent)
232 f.write('\n')
233
234
235class Constructor(asdl_type_t):
236
237 def __init__(self, name, shared_type, fields):
238 # type: (str, Optional[type_expr_t], List[Field]) -> None
239 self.name = name
240 self.shared_type = shared_type # for DoubleQuoted %DoubleQuoted
241 self.fields = fields or []
242
243 def Print(self, f, indent):
244 ind = indent * ' '
245 f.write('%sConstructor %s' % (ind, self.name))
246 if self.shared_type:
247 f.write(' %%%s' % self.shared_type)
248
249 if self.fields:
250 f.write(' {\n')
251 for field in self.fields:
252 field.Print(f, indent + 1)
253 f.write('%s}' % ind)
254
255 f.write('\n')
256
257
258class Sum(_Printable):
259
260 def __init__(self, types, generate=None):
261 # type: (List[Constructor], Optional[List[str]]) -> None
262 self.types = types
263 self.generate = generate or [] # type: List[str]
264
265 def Print(self, f, indent):
266 ind = indent * ' '
267 f.write('%sSum {\n' % ind)
268 for t in self.types:
269 t.Print(f, indent + 1)
270 if self.generate:
271 f.write('%s generate %s\n' % (ind, self.generate))
272 f.write('%s}\n' % ind)
273
274
275class SimpleSum(Sum):
276 pass
277
278
279class Product(_Printable):
280
281 def __init__(self, fields):
282 # type: (List[Field]) -> None
283 self.fields = fields
284
285 def Print(self, f, indent):
286 ind = indent * ' '
287 f.write('%sProduct {\n' % ind)
288 for field in self.fields:
289 field.Print(f, indent + 1)
290 f.write('%s}\n' % ind)
291
292
293#
294# Helpers
295#
296
297
298def TypeNameHeuristic(t):
299 # type: (str) -> str
300 """For 'use'.
301
302 We don't parse the imported file, so we have a heuristic based on
303 the name! e.g. re_t or BraceGroup
304 """
305 return '%s_t' % t if t[0].islower() else t
306
307
308def MakeSimpleVariant(name):
309 # type: (str) -> Constructor
310 """
311 Used by frontend/{consts,options}_gen.py
312 """
313 return Constructor(name, None, None)
314
315
316def IsOptional(t):
317 # type: (type_expr_t) -> bool
318 if isinstance(t, NamedType):
319 return False
320
321 elif isinstance(t, ParameterizedType):
322 return t.type_name == 'Optional'
323
324 else:
325 raise AssertionError()
326
327
328def IsList(t):
329 # type: (type_expr_t) -> bool
330 if isinstance(t, NamedType):
331 return False
332
333 elif isinstance(t, ParameterizedType):
334 if t.type_name == 'List':
335 return True
336 if t.type_name == 'Optional':
337 return IsList(t.children[0])
338 return False
339
340 else:
341 raise AssertionError()
342
343
344def IsDict(t):
345 # type: (type_expr_t) -> bool
346 if isinstance(t, NamedType):
347 return False
348
349 elif isinstance(t, ParameterizedType):
350 if t.type_name == 'Dict':
351 return True
352 if t.type_name == 'Optional':
353 return IsDict(t.children[0])
354 return False
355
356 else:
357 raise AssertionError()