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

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