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

374 lines, 188 significant
1"""AST type definitions for Zephyr ASDL itself.
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, Tuple
52
53
54class _Printable(object):
55
56 def Print(self, f, indent):
57 raise NotImplementedError()
58
59 def __str__(self):
60 f = cStringIO.StringIO()
61 self.Print(f, 0)
62 return f.getvalue()
63
64
65class asdl_type_t(_Printable):
66 pass
67
68
69class DummyType(asdl_type_t):
70 """
71 Dummy value for subtyping: List_of_command < List[command]
72
73 TODO: Improve this representation
74 """
75 pass
76
77
78class Use(asdl_type_t):
79
80 def __init__(self, module_parts, type_names):
81 # type: (List[str], List[str]) -> None
82 self.module_parts = module_parts
83 self.type_names = type_names
84
85 def Print(self, f, indent):
86 ind = indent * ' '
87 f.write('%sUse %s {\n' % (ind, ' '.join(self.module_parts)))
88 f.write(' %s%s\n' % (ind, ', '.join(t for t in self.type_names)))
89 f.write('%s}\n' % ind)
90
91
92class Extern(asdl_type_t):
93
94 def __init__(self, names):
95 # type: (List[str]) -> None
96 self.names = names
97
98 def Print(self, f, indent):
99 ind = indent * ' '
100 f.write('%sExtern [ %s ]\n' % (ind, ' '.join(self.names)))
101
102
103class Module(_Printable):
104
105 def __init__(self, name, uses, externs, dfns):
106 # type: (str, List[Use], List[Extern], List[binding_t]) -> None
107 self.name = name
108 self.uses = uses
109 self.externs = externs
110 self.dfns = dfns
111
112 def Print(self, f, indent):
113 ind = indent * ' '
114 f.write('%sModule %s {\n' % (ind, self.name))
115
116 for u in self.uses:
117 u.Print(f, indent + 1)
118 f.write('\n')
119
120 for e in self.externs:
121 e.Print(f, indent + 1)
122 f.write('\n')
123
124 for d in self.dfns:
125 d.Print(f, indent + 1)
126 f.write('\n')
127 f.write('%s}\n' % ind)
128
129
130class binding_t(_Printable):
131 pass
132
133
134class TypeDecl(binding_t):
135 """A binding of name to a Sum or Product type."""
136
137 def __init__(self, name, value):
138 # type: (str, asdl_type_t) -> None
139 self.name = name
140 self.value = value
141
142 def Print(self, f, indent):
143 ind = indent * ' '
144 f.write('%sType %s {\n' % (ind, self.name))
145 self.value.Print(f, indent + 1)
146 f.write('%s}\n' % ind)
147
148
149class SubTypeDecl(binding_t):
150 """A declaration of a subtype.
151
152 CompoundWord < List[word_part]
153 """
154
155 def __init__(self, name, base_class):
156 # type: (str, type_expr_t) -> None
157 self.name = name
158 self.base_class = base_class
159
160 def Print(self, f, indent):
161 ind = indent * ' '
162 f.write('%sType %s {\n' % (ind, self.name))
163 self.base_class.Print(f, indent + 1)
164 f.write('%s}\n' % ind)
165
166
167class type_expr_t(_Printable):
168 pass
169
170
171class NamedType(type_expr_t):
172 """Int, string are resolved to a Primitive type 'Point' can be resolved to
173 CompoundSum instance, etc."""
174
175 def __init__(self, name):
176 # type: (str) -> None
177 self.name = name
178
179 # Mutated by _ResolveModule / _ResolveType
180 self.resolved = None # type: Optional[asdl_type_t]
181
182 def Print(self, f, indent):
183 f.write('NamedType %s' % (self.name)) # printed after field
184 f.write(' (%r)' % self.resolved)
185
186
187class ParameterizedType(type_expr_t):
188 """A parameterized type expression, e.g. the type of a field.
189
190 Examples:
191 List[mytype] # used to be mytype*
192 Optional[mytype] # used to by mytype?
193 Dict[str, int]
194 Dict[int, List[str]]
195 """
196
197 def __init__(self, type_name, children):
198 # type: (str, List[type_expr_t]) -> None
199 self.type_name = type_name
200 self.children = children
201
202 def Print(self, f, indent):
203 """Printed on one line."""
204 f.write('%s' % (self.type_name)) # printed after field
205 if self.children:
206 f.write(' [ ')
207 for i, child in enumerate(self.children):
208 if i != 0:
209 f.write(', ')
210 child.Print(f, indent + 1)
211 f.write(' ]')
212
213
214class Field(_Printable):
215
216 def __init__(self, typ, name):
217 # type: (type_expr_t, str) -> None
218 self.typ = typ # type expression
219 self.name = name # variable name
220
221 def Print(self, f, indent):
222 ind = indent * ' '
223 f.write('%sField %r ' % (ind, self.name))
224 self.typ.Print(f, indent)
225 f.write('\n')
226
227
228class Constructor(asdl_type_t):
229
230 def __init__(self, name, shared_type, fields):
231 # type: (str, Optional[type_expr_t], List[Field]) -> None
232 self.name = name
233 self.shared_type = shared_type # for DoubleQuoted %DoubleQuoted
234 self.fields = fields or []
235
236 def Print(self, f, indent):
237 ind = indent * ' '
238 f.write('%sConstructor %s' % (ind, self.name))
239 if self.shared_type:
240 f.write(' %%%s' % self.shared_type)
241
242 if self.fields:
243 f.write(' {\n')
244 for field in self.fields:
245 field.Print(f, indent + 1)
246 f.write('%s}' % ind)
247
248 f.write('\n')
249
250
251class Sum(_Printable):
252
253 def __init__(self, types, generate=None):
254 # type: (List[Constructor], Optional[List[str]]) -> None
255 self.types = types
256 self.generate = generate or [] # type: List[str]
257
258 def Print(self, f, indent):
259 ind = indent * ' '
260 f.write('%sSum {\n' % ind)
261 for t in self.types:
262 t.Print(f, indent + 1)
263 if self.generate:
264 f.write('%s generate %s\n' % (ind, self.generate))
265 f.write('%s}\n' % ind)
266
267
268class SimpleSum(Sum):
269 pass
270
271
272class Product(_Printable):
273
274 def __init__(self, fields):
275 # type: (List[Field]) -> None
276 self.fields = fields
277
278 def Print(self, f, indent):
279 ind = indent * ' '
280 f.write('%sProduct {\n' % ind)
281 for field in self.fields:
282 field.Print(f, indent + 1)
283 f.write('%s}\n' % ind)
284
285
286#
287# Helpers
288#
289
290
291def TypeNameHeuristic(asdl_name):
292 # type: (str) -> Tuple[str, bool]
293 """For 'use'.
294
295 We don't parse the imported file, so we have a heuristic based on
296 the name! e.g. re_t or BraceGroup
297 """
298 is_pointer = True
299
300 if asdl_name == 'id':
301 py_name = 'Id_t'
302 is_pointer = False
303
304 elif asdl_name == 'kind':
305 py_name = 'Kind_t'
306 is_pointer = False
307
308 elif asdl_name[0].islower():
309 py_name = '%s_t' % asdl_name
310
311 else:
312 py_name = asdl_name
313
314 return py_name, is_pointer
315
316
317def NameHack(sum_name):
318 if sum_name == 'id':
319 return 'Id'
320 elif sum_name == 'kind':
321 return 'Kind'
322 return sum_name
323
324
325def MakeSimpleVariant(name):
326 # type: (str) -> Constructor
327 """
328 Used by frontend/{consts,options}_gen.py
329 """
330 return Constructor(name, None, None)
331
332
333def IsOptional(t):
334 # type: (type_expr_t) -> bool
335 if isinstance(t, NamedType):
336 return False
337
338 elif isinstance(t, ParameterizedType):
339 return t.type_name == 'Optional'
340
341 else:
342 raise AssertionError()
343
344
345def IsList(t):
346 # type: (type_expr_t) -> bool
347 if isinstance(t, NamedType):
348 return False
349
350 elif isinstance(t, ParameterizedType):
351 if t.type_name == 'List':
352 return True
353 if t.type_name == 'Optional':
354 return IsList(t.children[0])
355 return False
356
357 else:
358 raise AssertionError()
359
360
361def IsDict(t):
362 # type: (type_expr_t) -> bool
363 if isinstance(t, NamedType):
364 return False
365
366 elif isinstance(t, ParameterizedType):
367 if t.type_name == 'Dict':
368 return True
369 if t.type_name == 'Optional':
370 return IsDict(t.children[0])
371 return False
372
373 else:
374 raise AssertionError()