1 """An implementation of the Zephyr Abstract Syntax Definition Language.
3 See http://asdl.sourceforge.net/ and
4 http://www.cs.princeton.edu/~danwang/Papers/dsl97/dsl97-abstract.html.
6 Only supports top level module decl, not view. I'm guessing that view
7 is intended to support the browser and I'm not interested in the
19 # spark seems to dispatch in the parser based on a token's
21 def __init__(self
, type, lineno
):
32 def __init__(self
, value
, lineno
):
40 class ASDLSyntaxError
:
42 def __init__(self
, lineno
, token
=None, msg
=None):
49 return "Error at '%s', line %d" % (self
.token
, self
.lineno
)
51 return "%s, line %d" % (self
.msg
, self
.lineno
)
53 class ASDLScanner(spark
.GenericScanner
, object):
55 def tokenize(self
, input):
58 super(ASDLScanner
, self
).tokenize(input)
63 # XXX doesn't distinguish upper vs. lower, which is
64 # significant for ASDL.
65 self
.rv
.append(Id(s
, self
.lineno
))
67 def t_xxx(self
, s
): # not sure what this production means
69 self
.rv
.append(Token(s
, self
.lineno
))
71 def t_punctuation(self
, s
):
72 r
"[\{\}\*\=\|\(\)\,\?\:]"
73 self
.rv
.append(Token(s
, self
.lineno
))
75 def t_comment(self
, s
):
79 def t_newline(self
, s
):
83 def t_whitespace(self
, s
):
87 def t_default(self
, s
):
89 raise ValueError, "unmatched input: %s" % `s`
91 class ASDLParser(spark
.GenericParser
, object):
93 super(ASDLParser
, self
).__init
__("module")
95 def typestring(self
, tok
):
99 raise ASDLSyntaxError(tok
.lineno
, tok
)
101 def p_module_0(self
, (module
, name
, _0
, _1
)):
102 " module ::= Id Id { } "
103 if module
.value
!= "module":
104 raise ASDLSyntaxError(module
.lineno
,
105 msg
="expected 'module', found %s" % module
)
106 return Module(name
, None)
108 def p_module(self
, (module
, name
, _0
, definitions
, _1
)):
109 " module ::= Id Id { definitions } "
110 if module
.value
!= "module":
111 raise ASDLSyntaxError(module
.lineno
,
112 msg
="expected 'module', found %s" % module
)
113 return Module(name
, definitions
)
115 def p_definition_0(self
, (definition
,)):
116 " definitions ::= definition "
119 def p_definition_1(self
, (definitions
, definition
)):
120 " definitions ::= definition definitions "
121 return definitions
+ definition
123 def p_definition(self
, (id, _
, type)):
124 " definition ::= Id = type "
125 return [Type(id, type)]
127 def p_type_0(self
, (product
,)):
131 def p_type_1(self
, (sum,)):
135 def p_type_2(self
, (sum, id, _0
, attributes
, _1
)):
136 " type ::= sum Id ( fields ) "
137 if id.value
!= "attributes":
138 raise ASDLSyntaxError(id.lineno
,
139 msg
="expected attributes, found %s" % id)
140 return Sum(sum, attributes
)
142 def p_product(self
, (_0
, fields
, _1
)):
143 " product ::= ( fields ) "
144 # XXX can't I just construct things in the right order?
146 return Product(fields
)
148 def p_sum_0(self
, (constructor
,)):
149 " sum ::= constructor """
152 def p_sum_1(self, (constructor, _, sum)):
153 " sum ::= constructor |
sum "
154 return [constructor] + sum
156 def p_sum_2(self, (constructor, _, sum)):
157 " sum ::= constructor |
sum "
158 return [constructor] + sum
160 def p_constructor_0(self, (id,)):
161 " constructor
::= Id
"
162 return Constructor(id)
164 def p_constructor_1(self, (id, _0, fields, _1)):
165 " constructor
::= Id ( fields
) "
166 # XXX can't I just construct things in the right order?
168 return Constructor(id, fields)
170 def p_fields_0(self, (field,)):
174 def p_fields_1(self, (field, _, fields)):
175 " fields
::= field
, fields
"
176 return fields + [field]
178 def p_field_0(self, (type,)):
182 def p_field_1(self, (type, name)):
184 return Field(type, name)
186 def p_field_2(self, (type, _, name)):
187 " field
::= Id
* Id
"
188 return Field(type, name, seq=1)
190 def p_field_3(self, (type, _, name)):
191 " field
::= Id ? Id
"
192 return Field(type, name, opt=1)
194 def p_field_4(self, (type, _)):
196 return Field(type, seq=1)
198 def p_field_5(self, (type, _)):
200 return Field(type, opt=1)
202 builtin_types = ("identifier
", "string
", "int", "bool", "object")
204 # below is a collection of classes to capture the AST of an AST :-)
205 # not sure if any of the methods are useful yet, but I'm adding them
206 # piecemeal as they seem helpful
209 pass # a marker class
212 def __init__(self, name, dfns):
215 self.types = {} # maps type name to value (from dfns)
217 self.types[type.name.value] = type.value
220 return "Module(%s, %s)" % (self.name, self.dfns)
223 def __init__(self, name, value):
228 return "Type(%s, %s)" % (self.name, self.value)
230 class Constructor(AST):
231 def __init__(self, name, fields=None):
233 self.fields = fields or []
236 return "Constructor(%s, %s)" % (self.name, self.fields)
239 def __init__(self, type, name=None, seq=0, opt=0):
252 if self.name is None:
253 return "Field(%s%s)" % (self.type, extra)
255 return "Field(%s, %s%s)" % (self.type, self.name, extra)
258 def __init__(self, types, attributes=None):
260 self.attributes = attributes or []
263 if self.attributes is None:
264 return "Sum(%s)" % self.types
266 return "Sum(%s, %s)" % (self.types, self.attributes)
269 def __init__(self, fields):
273 return "Product(%s)" % self.fields
275 class VisitorBase(object):
277 def __init__(self, skip=0):
281 def visit(self, object, *args):
282 meth = self._dispatch(object)
287 except Exception, err:
288 print "Error visiting
", repr(object)
290 traceback.print_exc()
292 if hasattr(self, 'file'):
296 def _dispatch(self, object):
297 assert isinstance(object, AST), repr(object)
298 klass = object.__class__
299 meth = self.cache.get(klass)
301 methname = "visit
" + klass.__name__
303 meth = getattr(self, methname, None)
305 meth = getattr(self, methname)
306 self.cache[klass] = meth
309 class Check(VisitorBase):
312 super(Check, self).__init__(skip=1)
317 def visitModule(self, mod):
321 def visitType(self, type):
322 self.visit(type.value, str(type.name))
324 def visitSum(self, sum, name):
328 def visitConstructor(self, cons, name):
330 conflict = self.cons.get(key)
332 self.cons[key] = name
334 print "Redefinition of constructor
%s" % key
335 print "Defined
in %s and %s" % (conflict, name)
337 for f in cons.fields:
340 def visitField(self, field, name):
341 key = str(field.type)
342 l = self.types.setdefault(key, [])
345 def visitProduct(self, prod, name):
346 for f in prod.fields:
354 if not mod.types.has_key(t) and not t in builtin_types:
356 uses = ", ".join(v.types[t])
357 print "Undefined
type %s, used
in %s" % (t, uses)
362 scanner = ASDLScanner()
363 parser = ASDLParser()
365 buf = open(file).read()
366 tokens = scanner.tokenize(buf)
368 return parser.parse(tokens)
369 except ASDLSyntaxError, err:
371 lines = buf.split("\n")
372 print lines[err.lineno - 1] # lines starts at 0, files at 1
374 if __name__ == "__main__
":
378 if len(sys.argv) > 1:
382 files = glob.glob(testdir + "/*.asdl
")
387 print "module
", mod.name
388 print len(mod.dfns), "definitions
"