blob: fc1b16c668153f630234377d9b33e2059750ceee [file] [log] [blame]
Jeremy Hylton3e0055f2005-10-20 19:59:25 +00001"""An implementation of the Zephyr Abstract Syntax Definition Language.
2
3See http://asdl.sourceforge.net/ and
Senthil Kumaran2b80fa62010-05-18 13:48:45 +00004http://www.cs.princeton.edu/research/techreps/TR-554-97
Jeremy Hylton3e0055f2005-10-20 19:59:25 +00005
6Only supports top level module decl, not view. I'm guessing that view
7is intended to support the browser and I'm not interested in the
8browser.
Martin v. Löwiseae93b72006-02-28 00:12:47 +00009
10Changes for Python: Add support for module versions
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000011"""
12
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000013import os
Guido van Rossum805365e2007-05-07 22:24:25 +000014import sys
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000015import traceback
16
17import spark
18
Eli Benderskyb788a382013-09-26 06:31:32 -070019def output(*strings):
20 for s in strings:
21 sys.stdout.write(str(s) + "\n")
Guido van Rossum805365e2007-05-07 22:24:25 +000022
23
Benjamin Peterson87c8d872009-06-11 22:54:11 +000024class Token(object):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000025 # spark seems to dispatch in the parser based on a token's
26 # type attribute
27 def __init__(self, type, lineno):
28 self.type = type
29 self.lineno = lineno
30
31 def __str__(self):
32 return self.type
33
34 def __repr__(self):
35 return str(self)
36
37class Id(Token):
38 def __init__(self, value, lineno):
39 self.type = 'Id'
40 self.value = value
41 self.lineno = lineno
42
43 def __str__(self):
44 return self.value
Tim Peters710ab3b2006-02-28 18:30:36 +000045
Martin v. Löwiseae93b72006-02-28 00:12:47 +000046class String(Token):
47 def __init__(self, value, lineno):
48 self.type = 'String'
49 self.value = value
50 self.lineno = lineno
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000051
Guido van Rossum805365e2007-05-07 22:24:25 +000052class ASDLSyntaxError(Exception):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000053
54 def __init__(self, lineno, token=None, msg=None):
55 self.lineno = lineno
56 self.token = token
57 self.msg = msg
58
59 def __str__(self):
60 if self.msg is None:
61 return "Error at '%s', line %d" % (self.token, self.lineno)
62 else:
63 return "%s, line %d" % (self.msg, self.lineno)
64
65class ASDLScanner(spark.GenericScanner, object):
66
67 def tokenize(self, input):
68 self.rv = []
69 self.lineno = 1
70 super(ASDLScanner, self).tokenize(input)
71 return self.rv
72
73 def t_id(self, s):
74 r"[\w\.]+"
75 # XXX doesn't distinguish upper vs. lower, which is
76 # significant for ASDL.
77 self.rv.append(Id(s, self.lineno))
Tim Peters710ab3b2006-02-28 18:30:36 +000078
Martin v. Löwiseae93b72006-02-28 00:12:47 +000079 def t_string(self, s):
80 r'"[^"]*"'
81 self.rv.append(String(s, self.lineno))
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000082
83 def t_xxx(self, s): # not sure what this production means
84 r"<="
85 self.rv.append(Token(s, self.lineno))
86
87 def t_punctuation(self, s):
88 r"[\{\}\*\=\|\(\)\,\?\:]"
89 self.rv.append(Token(s, self.lineno))
90
91 def t_comment(self, s):
92 r"\-\-[^\n]*"
93 pass
94
95 def t_newline(self, s):
96 r"\n"
97 self.lineno += 1
98
99 def t_whitespace(self, s):
100 r"[ \t]+"
101 pass
102
103 def t_default(self, s):
104 r" . +"
Collin Winter4902e692007-08-30 18:18:27 +0000105 raise ValueError("unmatched input: %r" % s)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000106
107class ASDLParser(spark.GenericParser, object):
108 def __init__(self):
109 super(ASDLParser, self).__init__("module")
110
111 def typestring(self, tok):
112 return tok.type
113
114 def error(self, tok):
115 raise ASDLSyntaxError(tok.lineno, tok)
116
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000117 def p_module_0(self, info):
Benjamin Peterson6cb2b922011-03-12 18:28:16 -0600118 " module ::= Id Id { } "
119 module, name, _0, _1 = info
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000120 if module.value != "module":
121 raise ASDLSyntaxError(module.lineno,
122 msg="expected 'module', found %s" % module)
Benjamin Peterson6cb2b922011-03-12 18:28:16 -0600123 return Module(name, None)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000124
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000125 def p_module(self, info):
Benjamin Peterson6cb2b922011-03-12 18:28:16 -0600126 " module ::= Id Id { definitions } "
127 module, name, _0, definitions, _1 = info
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000128 if module.value != "module":
129 raise ASDLSyntaxError(module.lineno,
130 msg="expected 'module', found %s" % module)
Benjamin Peterson6cb2b922011-03-12 18:28:16 -0600131 return Module(name, definitions)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000132
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000133 def p_definition_0(self, definition):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000134 " definitions ::= definition "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000135 return definition[0]
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000136
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000137 def p_definition_1(self, definitions):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000138 " definitions ::= definition definitions "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000139 return definitions[0] + definitions[1]
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000140
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000141 def p_definition(self, info):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000142 " definition ::= Id = type "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000143 id, _, type = info
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000144 return [Type(id, type)]
145
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000146 def p_type_0(self, product):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000147 " type ::= product "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000148 return product[0]
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000149
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000150 def p_type_1(self, sum):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000151 " type ::= sum "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000152 return Sum(sum[0])
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000153
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000154 def p_type_2(self, info):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000155 " type ::= sum Id ( fields ) "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000156 sum, id, _0, attributes, _1 = info
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000157 if id.value != "attributes":
158 raise ASDLSyntaxError(id.lineno,
159 msg="expected attributes, found %s" % id)
160 return Sum(sum, attributes)
161
Benjamin Petersoncda75be2013-03-18 10:48:58 -0700162 def p_product_0(self, info):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000163 " product ::= ( fields ) "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000164 _0, fields, _1 = info
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000165 return Product(fields)
166
Benjamin Petersoncda75be2013-03-18 10:48:58 -0700167 def p_product_1(self, info):
168 " product ::= ( fields ) Id ( fields ) "
169 _0, fields, _1, id, _2, attributes, _3 = info
170 if id.value != "attributes":
171 raise ASDLSyntaxError(id.lineno,
172 msg="expected attributes, found %s" % id)
173 return Product(fields, attributes)
174
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000175 def p_sum_0(self, constructor):
Georg Brandl1f01deb2009-01-03 22:47:39 +0000176 " sum ::= constructor "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000177 return [constructor[0]]
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000178
Neal Norwitzbda355f2008-03-17 18:03:56 +0000179 def p_sum_1(self, info):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000180 " sum ::= constructor | sum "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000181 constructor, _, sum = info
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000182 return [constructor] + sum
183
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000184 def p_sum_2(self, info):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000185 " sum ::= constructor | sum "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000186 constructor, _, sum = info
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000187 return [constructor] + sum
188
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000189 def p_constructor_0(self, id):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000190 " constructor ::= Id "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000191 return Constructor(id[0])
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000192
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000193 def p_constructor_1(self, info):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000194 " constructor ::= Id ( fields ) "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000195 id, _0, fields, _1 = info
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000196 return Constructor(id, fields)
197
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000198 def p_fields_0(self, field):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000199 " fields ::= field "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000200 return [field[0]]
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000201
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000202 def p_fields_1(self, info):
Benjamin Peterson481ae502012-07-31 21:41:56 -0700203 " fields ::= fields , field "
204 fields, _, field = info
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000205 return fields + [field]
206
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000207 def p_field_0(self, type_):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000208 " field ::= Id "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000209 return Field(type_[0])
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000210
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000211 def p_field_1(self, info):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000212 " field ::= Id Id "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000213 type, name = info
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000214 return Field(type, name)
215
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000216 def p_field_2(self, info):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000217 " field ::= Id * Id "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000218 type, _, name = info
Benjamin Peterson87c8d872009-06-11 22:54:11 +0000219 return Field(type, name, seq=True)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000220
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000221 def p_field_3(self, info):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000222 " field ::= Id ? Id "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000223 type, _, name = info
Benjamin Peterson87c8d872009-06-11 22:54:11 +0000224 return Field(type, name, opt=True)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000225
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000226 def p_field_4(self, type_):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000227 " field ::= Id * "
Benjamin Peterson87c8d872009-06-11 22:54:11 +0000228 return Field(type_[0], seq=True)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000229
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000230 def p_field_5(self, type_):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000231 " field ::= Id ? "
Benjamin Peterson87c8d872009-06-11 22:54:11 +0000232 return Field(type[0], opt=True)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000233
Benjamin Peterson442f2092012-12-06 17:41:04 -0500234builtin_types = ("identifier", "string", "bytes", "int", "object", "singleton")
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000235
236# below is a collection of classes to capture the AST of an AST :-)
237# not sure if any of the methods are useful yet, but I'm adding them
238# piecemeal as they seem helpful
239
Benjamin Peterson87c8d872009-06-11 22:54:11 +0000240class AST(object):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000241 pass # a marker class
242
243class Module(AST):
Benjamin Peterson6cb2b922011-03-12 18:28:16 -0600244 def __init__(self, name, dfns):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000245 self.name = name
246 self.dfns = dfns
247 self.types = {} # maps type name to value (from dfns)
248 for type in dfns:
249 self.types[type.name.value] = type.value
250
251 def __repr__(self):
252 return "Module(%s, %s)" % (self.name, self.dfns)
253
254class Type(AST):
255 def __init__(self, name, value):
256 self.name = name
257 self.value = value
258
259 def __repr__(self):
260 return "Type(%s, %s)" % (self.name, self.value)
261
262class Constructor(AST):
263 def __init__(self, name, fields=None):
264 self.name = name
265 self.fields = fields or []
266
267 def __repr__(self):
268 return "Constructor(%s, %s)" % (self.name, self.fields)
269
270class Field(AST):
Benjamin Peterson87c8d872009-06-11 22:54:11 +0000271 def __init__(self, type, name=None, seq=False, opt=False):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000272 self.type = type
273 self.name = name
274 self.seq = seq
275 self.opt = opt
276
277 def __repr__(self):
278 if self.seq:
Benjamin Peterson87c8d872009-06-11 22:54:11 +0000279 extra = ", seq=True"
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000280 elif self.opt:
Benjamin Peterson87c8d872009-06-11 22:54:11 +0000281 extra = ", opt=True"
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000282 else:
283 extra = ""
284 if self.name is None:
285 return "Field(%s%s)" % (self.type, extra)
286 else:
287 return "Field(%s, %s%s)" % (self.type, self.name, extra)
288
289class Sum(AST):
290 def __init__(self, types, attributes=None):
291 self.types = types
292 self.attributes = attributes or []
293
294 def __repr__(self):
295 if self.attributes is None:
296 return "Sum(%s)" % self.types
297 else:
298 return "Sum(%s, %s)" % (self.types, self.attributes)
299
300class Product(AST):
Benjamin Petersoncda75be2013-03-18 10:48:58 -0700301 def __init__(self, fields, attributes=None):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000302 self.fields = fields
Benjamin Petersoncda75be2013-03-18 10:48:58 -0700303 self.attributes = attributes or []
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000304
305 def __repr__(self):
Benjamin Petersoncda75be2013-03-18 10:48:58 -0700306 if self.attributes is None:
307 return "Product(%s)" % self.fields
308 else:
309 return "Product(%s, %s)" % (self.fields, self.attributes)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000310
311class VisitorBase(object):
312
Benjamin Peterson87c8d872009-06-11 22:54:11 +0000313 def __init__(self, skip=False):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000314 self.cache = {}
315 self.skip = skip
316
317 def visit(self, object, *args):
318 meth = self._dispatch(object)
319 if meth is None:
320 return
321 try:
322 meth(object, *args)
Guido van Rossum805365e2007-05-07 22:24:25 +0000323 except Exception:
Alexandre Vassalottidf6f3fd2009-07-17 05:35:59 +0000324 output("Error visiting" + repr(object))
325 output(str(sys.exc_info()[1]))
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000326 traceback.print_exc()
327 # XXX hack
328 if hasattr(self, 'file'):
329 self.file.flush()
330 os._exit(1)
331
332 def _dispatch(self, object):
333 assert isinstance(object, AST), repr(object)
334 klass = object.__class__
335 meth = self.cache.get(klass)
336 if meth is None:
337 methname = "visit" + klass.__name__
338 if self.skip:
339 meth = getattr(self, methname, None)
340 else:
341 meth = getattr(self, methname)
342 self.cache[klass] = meth
343 return meth
344
345class Check(VisitorBase):
346
347 def __init__(self):
Benjamin Peterson87c8d872009-06-11 22:54:11 +0000348 super(Check, self).__init__(skip=True)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000349 self.cons = {}
350 self.errors = 0
351 self.types = {}
352
353 def visitModule(self, mod):
354 for dfn in mod.dfns:
355 self.visit(dfn)
356
357 def visitType(self, type):
358 self.visit(type.value, str(type.name))
359
360 def visitSum(self, sum, name):
361 for t in sum.types:
362 self.visit(t, name)
363
364 def visitConstructor(self, cons, name):
365 key = str(cons.name)
366 conflict = self.cons.get(key)
367 if conflict is None:
368 self.cons[key] = name
369 else:
Guido van Rossum805365e2007-05-07 22:24:25 +0000370 output("Redefinition of constructor %s" % key)
371 output("Defined in %s and %s" % (conflict, name))
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000372 self.errors += 1
373 for f in cons.fields:
374 self.visit(f, key)
375
376 def visitField(self, field, name):
377 key = str(field.type)
378 l = self.types.setdefault(key, [])
379 l.append(name)
380
381 def visitProduct(self, prod, name):
382 for f in prod.fields:
383 self.visit(f, name)
384
385def check(mod):
386 v = Check()
387 v.visit(mod)
388
389 for t in v.types:
Fred Drake34e4f522006-12-29 04:42:48 +0000390 if t not in mod.types and not t in builtin_types:
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000391 v.errors += 1
392 uses = ", ".join(v.types[t])
Guido van Rossum805365e2007-05-07 22:24:25 +0000393 output("Undefined type %s, used in %s" % (t, uses))
Tim Peters536cf992005-12-25 23:18:31 +0000394
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000395 return not v.errors
396
397def parse(file):
398 scanner = ASDLScanner()
399 parser = ASDLParser()
400
Eli Bendersky1891cff2013-09-26 09:35:39 -0700401 f = open(file)
Eli Bendersky99081232013-09-26 06:41:36 -0700402 try:
Eli Bendersky58fe1b12013-09-26 06:32:22 -0700403 buf = f.read()
Eli Bendersky99081232013-09-26 06:41:36 -0700404 finally:
405 f.close()
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000406 tokens = scanner.tokenize(buf)
407 try:
408 return parser.parse(tokens)
Guido van Rossum805365e2007-05-07 22:24:25 +0000409 except ASDLSyntaxError:
Georg Brandl8a732782009-04-12 11:34:13 +0000410 err = sys.exc_info()[1]
411 output(str(err))
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000412 lines = buf.split("\n")
Guido van Rossum805365e2007-05-07 22:24:25 +0000413 output(lines[err.lineno - 1]) # lines starts at 0, files at 1
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000414
415if __name__ == "__main__":
416 import glob
417 import sys
418
419 if len(sys.argv) > 1:
420 files = sys.argv[1:]
421 else:
422 testdir = "tests"
423 files = glob.glob(testdir + "/*.asdl")
Tim Peters536cf992005-12-25 23:18:31 +0000424
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000425 for file in files:
Guido van Rossum805365e2007-05-07 22:24:25 +0000426 output(file)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000427 mod = parse(file)
Georg Brandl8a732782009-04-12 11:34:13 +0000428 if not mod:
429 break
Guido van Rossum805365e2007-05-07 22:24:25 +0000430 output("module", mod.name)
431 output(len(mod.dfns), "definitions")
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000432 if not check(mod):
Guido van Rossum805365e2007-05-07 22:24:25 +0000433 output("Check failed")
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000434 else:
435 for dfn in mod.dfns:
Eli Benderskyb788a382013-09-26 06:31:32 -0700436 output(dfn.name, dfn.value)