blob: 7df76c0e38f61a3ae9c0c2cf9cd78e3a3686b889 [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
Guido van Rossum805365e2007-05-07 22:24:25 +000019def output(string):
20 sys.stdout.write(string + "\n")
21
22
Benjamin Peterson87c8d872009-06-11 22:54:11 +000023class Token(object):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000024 # spark seems to dispatch in the parser based on a token's
25 # type attribute
26 def __init__(self, type, lineno):
27 self.type = type
28 self.lineno = lineno
29
30 def __str__(self):
31 return self.type
32
33 def __repr__(self):
34 return str(self)
35
36class Id(Token):
37 def __init__(self, value, lineno):
38 self.type = 'Id'
39 self.value = value
40 self.lineno = lineno
41
42 def __str__(self):
43 return self.value
Tim Peters710ab3b2006-02-28 18:30:36 +000044
Martin v. Löwiseae93b72006-02-28 00:12:47 +000045class String(Token):
46 def __init__(self, value, lineno):
47 self.type = 'String'
48 self.value = value
49 self.lineno = lineno
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000050
Guido van Rossum805365e2007-05-07 22:24:25 +000051class ASDLSyntaxError(Exception):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000052
53 def __init__(self, lineno, token=None, msg=None):
54 self.lineno = lineno
55 self.token = token
56 self.msg = msg
57
58 def __str__(self):
59 if self.msg is None:
60 return "Error at '%s', line %d" % (self.token, self.lineno)
61 else:
62 return "%s, line %d" % (self.msg, self.lineno)
63
64class ASDLScanner(spark.GenericScanner, object):
65
66 def tokenize(self, input):
67 self.rv = []
68 self.lineno = 1
69 super(ASDLScanner, self).tokenize(input)
70 return self.rv
71
72 def t_id(self, s):
73 r"[\w\.]+"
74 # XXX doesn't distinguish upper vs. lower, which is
75 # significant for ASDL.
76 self.rv.append(Id(s, self.lineno))
Tim Peters710ab3b2006-02-28 18:30:36 +000077
Martin v. Löwiseae93b72006-02-28 00:12:47 +000078 def t_string(self, s):
79 r'"[^"]*"'
80 self.rv.append(String(s, self.lineno))
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000081
82 def t_xxx(self, s): # not sure what this production means
83 r"<="
84 self.rv.append(Token(s, self.lineno))
85
86 def t_punctuation(self, s):
87 r"[\{\}\*\=\|\(\)\,\?\:]"
88 self.rv.append(Token(s, self.lineno))
89
90 def t_comment(self, s):
91 r"\-\-[^\n]*"
92 pass
93
94 def t_newline(self, s):
95 r"\n"
96 self.lineno += 1
97
98 def t_whitespace(self, s):
99 r"[ \t]+"
100 pass
101
102 def t_default(self, s):
103 r" . +"
Collin Winter4902e692007-08-30 18:18:27 +0000104 raise ValueError("unmatched input: %r" % s)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000105
106class ASDLParser(spark.GenericParser, object):
107 def __init__(self):
108 super(ASDLParser, self).__init__("module")
109
110 def typestring(self, tok):
111 return tok.type
112
113 def error(self, tok):
114 raise ASDLSyntaxError(tok.lineno, tok)
115
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000116 def p_module_0(self, info):
Benjamin Peterson6cb2b922011-03-12 18:28:16 -0600117 " module ::= Id Id { } "
118 module, name, _0, _1 = info
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000119 if module.value != "module":
120 raise ASDLSyntaxError(module.lineno,
121 msg="expected 'module', found %s" % module)
Benjamin Peterson6cb2b922011-03-12 18:28:16 -0600122 return Module(name, None)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000123
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000124 def p_module(self, info):
Benjamin Peterson6cb2b922011-03-12 18:28:16 -0600125 " module ::= Id Id { definitions } "
126 module, name, _0, definitions, _1 = info
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000127 if module.value != "module":
128 raise ASDLSyntaxError(module.lineno,
129 msg="expected 'module', found %s" % module)
Benjamin Peterson6cb2b922011-03-12 18:28:16 -0600130 return Module(name, definitions)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000131
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000132 def p_definition_0(self, definition):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000133 " definitions ::= definition "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000134 return definition[0]
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000135
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000136 def p_definition_1(self, definitions):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000137 " definitions ::= definition definitions "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000138 return definitions[0] + definitions[1]
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000139
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000140 def p_definition(self, info):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000141 " definition ::= Id = type "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000142 id, _, type = info
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000143 return [Type(id, type)]
144
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000145 def p_type_0(self, product):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000146 " type ::= product "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000147 return product[0]
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000148
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000149 def p_type_1(self, sum):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000150 " type ::= sum "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000151 return Sum(sum[0])
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000152
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000153 def p_type_2(self, info):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000154 " type ::= sum Id ( fields ) "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000155 sum, id, _0, attributes, _1 = info
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000156 if id.value != "attributes":
157 raise ASDLSyntaxError(id.lineno,
158 msg="expected attributes, found %s" % id)
159 return Sum(sum, attributes)
160
Benjamin Petersoncda75be2013-03-18 10:48:58 -0700161 def p_product_0(self, info):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000162 " product ::= ( fields ) "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000163 _0, fields, _1 = info
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000164 return Product(fields)
165
Benjamin Petersoncda75be2013-03-18 10:48:58 -0700166 def p_product_1(self, info):
167 " product ::= ( fields ) Id ( fields ) "
168 _0, fields, _1, id, _2, attributes, _3 = info
169 if id.value != "attributes":
170 raise ASDLSyntaxError(id.lineno,
171 msg="expected attributes, found %s" % id)
172 return Product(fields, attributes)
173
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000174 def p_sum_0(self, constructor):
Georg Brandl1f01deb2009-01-03 22:47:39 +0000175 " sum ::= constructor "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000176 return [constructor[0]]
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000177
Neal Norwitzbda355f2008-03-17 18:03:56 +0000178 def p_sum_1(self, info):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000179 " sum ::= constructor | sum "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000180 constructor, _, sum = info
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000181 return [constructor] + sum
182
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000183 def p_sum_2(self, info):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000184 " sum ::= constructor | sum "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000185 constructor, _, sum = info
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000186 return [constructor] + sum
187
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000188 def p_constructor_0(self, id):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000189 " constructor ::= Id "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000190 return Constructor(id[0])
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000191
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000192 def p_constructor_1(self, info):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000193 " constructor ::= Id ( fields ) "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000194 id, _0, fields, _1 = info
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000195 return Constructor(id, fields)
196
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000197 def p_fields_0(self, field):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000198 " fields ::= field "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000199 return [field[0]]
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000200
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000201 def p_fields_1(self, info):
Benjamin Peterson481ae502012-07-31 21:41:56 -0700202 " fields ::= fields , field "
203 fields, _, field = info
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000204 return fields + [field]
205
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000206 def p_field_0(self, type_):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000207 " field ::= Id "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000208 return Field(type_[0])
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000209
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000210 def p_field_1(self, info):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000211 " field ::= Id Id "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000212 type, name = info
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000213 return Field(type, name)
214
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000215 def p_field_2(self, info):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000216 " field ::= Id * Id "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000217 type, _, name = info
Benjamin Peterson87c8d872009-06-11 22:54:11 +0000218 return Field(type, name, seq=True)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000219
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000220 def p_field_3(self, info):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000221 " field ::= Id ? Id "
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000222 type, _, name = info
Benjamin Peterson87c8d872009-06-11 22:54:11 +0000223 return Field(type, name, opt=True)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000224
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000225 def p_field_4(self, type_):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000226 " field ::= Id * "
Benjamin Peterson87c8d872009-06-11 22:54:11 +0000227 return Field(type_[0], seq=True)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000228
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000229 def p_field_5(self, type_):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000230 " field ::= Id ? "
Benjamin Peterson87c8d872009-06-11 22:54:11 +0000231 return Field(type[0], opt=True)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000232
Benjamin Peterson442f2092012-12-06 17:41:04 -0500233builtin_types = ("identifier", "string", "bytes", "int", "object", "singleton")
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000234
235# below is a collection of classes to capture the AST of an AST :-)
236# not sure if any of the methods are useful yet, but I'm adding them
237# piecemeal as they seem helpful
238
Benjamin Peterson87c8d872009-06-11 22:54:11 +0000239class AST(object):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000240 pass # a marker class
241
242class Module(AST):
Benjamin Peterson6cb2b922011-03-12 18:28:16 -0600243 def __init__(self, name, dfns):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000244 self.name = name
245 self.dfns = dfns
246 self.types = {} # maps type name to value (from dfns)
247 for type in dfns:
248 self.types[type.name.value] = type.value
249
250 def __repr__(self):
251 return "Module(%s, %s)" % (self.name, self.dfns)
252
253class Type(AST):
254 def __init__(self, name, value):
255 self.name = name
256 self.value = value
257
258 def __repr__(self):
259 return "Type(%s, %s)" % (self.name, self.value)
260
261class Constructor(AST):
262 def __init__(self, name, fields=None):
263 self.name = name
264 self.fields = fields or []
265
266 def __repr__(self):
267 return "Constructor(%s, %s)" % (self.name, self.fields)
268
269class Field(AST):
Benjamin Peterson87c8d872009-06-11 22:54:11 +0000270 def __init__(self, type, name=None, seq=False, opt=False):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000271 self.type = type
272 self.name = name
273 self.seq = seq
274 self.opt = opt
275
276 def __repr__(self):
277 if self.seq:
Benjamin Peterson87c8d872009-06-11 22:54:11 +0000278 extra = ", seq=True"
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000279 elif self.opt:
Benjamin Peterson87c8d872009-06-11 22:54:11 +0000280 extra = ", opt=True"
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000281 else:
282 extra = ""
283 if self.name is None:
284 return "Field(%s%s)" % (self.type, extra)
285 else:
286 return "Field(%s, %s%s)" % (self.type, self.name, extra)
287
288class Sum(AST):
289 def __init__(self, types, attributes=None):
290 self.types = types
291 self.attributes = attributes or []
292
293 def __repr__(self):
294 if self.attributes is None:
295 return "Sum(%s)" % self.types
296 else:
297 return "Sum(%s, %s)" % (self.types, self.attributes)
298
299class Product(AST):
Benjamin Petersoncda75be2013-03-18 10:48:58 -0700300 def __init__(self, fields, attributes=None):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000301 self.fields = fields
Benjamin Petersoncda75be2013-03-18 10:48:58 -0700302 self.attributes = attributes or []
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000303
304 def __repr__(self):
Benjamin Petersoncda75be2013-03-18 10:48:58 -0700305 if self.attributes is None:
306 return "Product(%s)" % self.fields
307 else:
308 return "Product(%s, %s)" % (self.fields, self.attributes)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000309
310class VisitorBase(object):
311
Benjamin Peterson87c8d872009-06-11 22:54:11 +0000312 def __init__(self, skip=False):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000313 self.cache = {}
314 self.skip = skip
315
316 def visit(self, object, *args):
317 meth = self._dispatch(object)
318 if meth is None:
319 return
320 try:
321 meth(object, *args)
Guido van Rossum805365e2007-05-07 22:24:25 +0000322 except Exception:
Alexandre Vassalottidf6f3fd2009-07-17 05:35:59 +0000323 output("Error visiting" + repr(object))
324 output(str(sys.exc_info()[1]))
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000325 traceback.print_exc()
326 # XXX hack
327 if hasattr(self, 'file'):
328 self.file.flush()
329 os._exit(1)
330
331 def _dispatch(self, object):
332 assert isinstance(object, AST), repr(object)
333 klass = object.__class__
334 meth = self.cache.get(klass)
335 if meth is None:
336 methname = "visit" + klass.__name__
337 if self.skip:
338 meth = getattr(self, methname, None)
339 else:
340 meth = getattr(self, methname)
341 self.cache[klass] = meth
342 return meth
343
344class Check(VisitorBase):
345
346 def __init__(self):
Benjamin Peterson87c8d872009-06-11 22:54:11 +0000347 super(Check, self).__init__(skip=True)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000348 self.cons = {}
349 self.errors = 0
350 self.types = {}
351
352 def visitModule(self, mod):
353 for dfn in mod.dfns:
354 self.visit(dfn)
355
356 def visitType(self, type):
357 self.visit(type.value, str(type.name))
358
359 def visitSum(self, sum, name):
360 for t in sum.types:
361 self.visit(t, name)
362
363 def visitConstructor(self, cons, name):
364 key = str(cons.name)
365 conflict = self.cons.get(key)
366 if conflict is None:
367 self.cons[key] = name
368 else:
Guido van Rossum805365e2007-05-07 22:24:25 +0000369 output("Redefinition of constructor %s" % key)
370 output("Defined in %s and %s" % (conflict, name))
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000371 self.errors += 1
372 for f in cons.fields:
373 self.visit(f, key)
374
375 def visitField(self, field, name):
376 key = str(field.type)
377 l = self.types.setdefault(key, [])
378 l.append(name)
379
380 def visitProduct(self, prod, name):
381 for f in prod.fields:
382 self.visit(f, name)
383
384def check(mod):
385 v = Check()
386 v.visit(mod)
387
388 for t in v.types:
Fred Drake34e4f522006-12-29 04:42:48 +0000389 if t not in mod.types and not t in builtin_types:
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000390 v.errors += 1
391 uses = ", ".join(v.types[t])
Guido van Rossum805365e2007-05-07 22:24:25 +0000392 output("Undefined type %s, used in %s" % (t, uses))
Tim Peters536cf992005-12-25 23:18:31 +0000393
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000394 return not v.errors
395
396def parse(file):
397 scanner = ASDLScanner()
398 parser = ASDLParser()
399
400 buf = open(file).read()
401 tokens = scanner.tokenize(buf)
402 try:
403 return parser.parse(tokens)
Guido van Rossum805365e2007-05-07 22:24:25 +0000404 except ASDLSyntaxError:
Georg Brandl8a732782009-04-12 11:34:13 +0000405 err = sys.exc_info()[1]
406 output(str(err))
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000407 lines = buf.split("\n")
Guido van Rossum805365e2007-05-07 22:24:25 +0000408 output(lines[err.lineno - 1]) # lines starts at 0, files at 1
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000409
410if __name__ == "__main__":
411 import glob
412 import sys
413
414 if len(sys.argv) > 1:
415 files = sys.argv[1:]
416 else:
417 testdir = "tests"
418 files = glob.glob(testdir + "/*.asdl")
Tim Peters536cf992005-12-25 23:18:31 +0000419
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000420 for file in files:
Guido van Rossum805365e2007-05-07 22:24:25 +0000421 output(file)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000422 mod = parse(file)
Georg Brandl8a732782009-04-12 11:34:13 +0000423 if not mod:
424 break
Guido van Rossum805365e2007-05-07 22:24:25 +0000425 output("module", mod.name)
426 output(len(mod.dfns), "definitions")
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000427 if not check(mod):
Guido van Rossum805365e2007-05-07 22:24:25 +0000428 output("Check failed")
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000429 else:
430 for dfn in mod.dfns:
Guido van Rossum805365e2007-05-07 22:24:25 +0000431 output(dfn.type)