| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 1 | """An implementation of the Zephyr Abstract Syntax Definition Language. | 
 | 2 |  | 
 | 3 | See http://asdl.sourceforge.net/ and | 
| Senthil Kumaran | cccfce1 | 2010-05-18 13:40:23 +0000 | [diff] [blame] | 4 | http://www.cs.princeton.edu/research/techreps/TR-554-97 | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 5 |  | 
 | 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 | 
 | 8 | browser. | 
| Martin v. Löwis | eae93b7 | 2006-02-28 00:12:47 +0000 | [diff] [blame] | 9 |  | 
 | 10 | Changes for Python: Add support for module versions | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 11 | """ | 
 | 12 |  | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 13 | import os | 
 | 14 | import traceback | 
 | 15 |  | 
 | 16 | import spark | 
 | 17 |  | 
| Benjamin Peterson | dea29d0 | 2009-06-07 22:35:00 +0000 | [diff] [blame] | 18 | class Token(object): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 19 |     # spark seems to dispatch in the parser based on a token's | 
 | 20 |     # type attribute | 
 | 21 |     def __init__(self, type, lineno): | 
 | 22 |         self.type = type | 
 | 23 |         self.lineno = lineno | 
 | 24 |  | 
 | 25 |     def __str__(self): | 
 | 26 |         return self.type | 
 | 27 |  | 
 | 28 |     def __repr__(self): | 
 | 29 |         return str(self) | 
 | 30 |  | 
 | 31 | class Id(Token): | 
 | 32 |     def __init__(self, value, lineno): | 
 | 33 |         self.type = 'Id' | 
 | 34 |         self.value = value | 
 | 35 |         self.lineno = lineno | 
 | 36 |  | 
 | 37 |     def __str__(self): | 
 | 38 |         return self.value | 
| Tim Peters | 710ab3b | 2006-02-28 18:30:36 +0000 | [diff] [blame] | 39 |  | 
| Martin v. Löwis | eae93b7 | 2006-02-28 00:12:47 +0000 | [diff] [blame] | 40 | class String(Token): | 
 | 41 |     def __init__(self, value, lineno): | 
 | 42 |         self.type = 'String' | 
 | 43 |         self.value = value | 
 | 44 |         self.lineno = lineno | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 45 |  | 
| Benjamin Peterson | dea29d0 | 2009-06-07 22:35:00 +0000 | [diff] [blame] | 46 | class ASDLSyntaxError(Exception): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 47 |  | 
 | 48 |     def __init__(self, lineno, token=None, msg=None): | 
 | 49 |         self.lineno = lineno | 
 | 50 |         self.token = token | 
 | 51 |         self.msg = msg | 
 | 52 |  | 
 | 53 |     def __str__(self): | 
 | 54 |         if self.msg is None: | 
 | 55 |             return "Error at '%s', line %d" % (self.token, self.lineno) | 
 | 56 |         else: | 
 | 57 |             return "%s, line %d" % (self.msg, self.lineno) | 
 | 58 |  | 
 | 59 | class ASDLScanner(spark.GenericScanner, object): | 
 | 60 |  | 
 | 61 |     def tokenize(self, input): | 
 | 62 |         self.rv = [] | 
 | 63 |         self.lineno = 1 | 
 | 64 |         super(ASDLScanner, self).tokenize(input) | 
 | 65 |         return self.rv | 
 | 66 |  | 
 | 67 |     def t_id(self, s): | 
 | 68 |         r"[\w\.]+" | 
 | 69 |         # XXX doesn't distinguish upper vs. lower, which is | 
 | 70 |         # significant for ASDL. | 
 | 71 |         self.rv.append(Id(s, self.lineno)) | 
| Tim Peters | 710ab3b | 2006-02-28 18:30:36 +0000 | [diff] [blame] | 72 |  | 
| Martin v. Löwis | eae93b7 | 2006-02-28 00:12:47 +0000 | [diff] [blame] | 73 |     def t_string(self, s): | 
 | 74 |         r'"[^"]*"' | 
 | 75 |         self.rv.append(String(s, self.lineno)) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 76 |  | 
 | 77 |     def t_xxx(self, s): # not sure what this production means | 
 | 78 |         r"<=" | 
 | 79 |         self.rv.append(Token(s, self.lineno)) | 
 | 80 |  | 
 | 81 |     def t_punctuation(self, s): | 
 | 82 |         r"[\{\}\*\=\|\(\)\,\?\:]" | 
 | 83 |         self.rv.append(Token(s, self.lineno)) | 
 | 84 |  | 
 | 85 |     def t_comment(self, s): | 
 | 86 |         r"\-\-[^\n]*" | 
 | 87 |         pass | 
 | 88 |  | 
 | 89 |     def t_newline(self, s): | 
 | 90 |         r"\n" | 
 | 91 |         self.lineno += 1 | 
 | 92 |  | 
 | 93 |     def t_whitespace(self, s): | 
 | 94 |         r"[ \t]+" | 
 | 95 |         pass | 
 | 96 |  | 
 | 97 |     def t_default(self, s): | 
 | 98 |         r" . +" | 
 | 99 |         raise ValueError, "unmatched input: %s" % `s` | 
 | 100 |  | 
 | 101 | class ASDLParser(spark.GenericParser, object): | 
 | 102 |     def __init__(self): | 
 | 103 |         super(ASDLParser, self).__init__("module") | 
 | 104 |  | 
 | 105 |     def typestring(self, tok): | 
 | 106 |         return tok.type | 
 | 107 |  | 
 | 108 |     def error(self, tok): | 
 | 109 |         raise ASDLSyntaxError(tok.lineno, tok) | 
 | 110 |  | 
| Martin v. Löwis | eae93b7 | 2006-02-28 00:12:47 +0000 | [diff] [blame] | 111 |     def p_module_0(self, (module, name, version, _0, _1)): | 
 | 112 |         " module ::= Id Id version { } " | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 113 |         if module.value != "module": | 
 | 114 |             raise ASDLSyntaxError(module.lineno, | 
 | 115 |                                   msg="expected 'module', found %s" % module) | 
| Martin v. Löwis | eae93b7 | 2006-02-28 00:12:47 +0000 | [diff] [blame] | 116 |         return Module(name, None, version) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 117 |  | 
| Martin v. Löwis | eae93b7 | 2006-02-28 00:12:47 +0000 | [diff] [blame] | 118 |     def p_module(self, (module, name, version, _0, definitions, _1)): | 
 | 119 |         " module ::= Id Id version { definitions } " | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 120 |         if module.value != "module": | 
 | 121 |             raise ASDLSyntaxError(module.lineno, | 
 | 122 |                                   msg="expected 'module', found %s" % module) | 
| Martin v. Löwis | eae93b7 | 2006-02-28 00:12:47 +0000 | [diff] [blame] | 123 |         return Module(name, definitions, version) | 
| Tim Peters | 710ab3b | 2006-02-28 18:30:36 +0000 | [diff] [blame] | 124 |  | 
| Martin v. Löwis | eae93b7 | 2006-02-28 00:12:47 +0000 | [diff] [blame] | 125 |     def p_version(self, (version, V)): | 
 | 126 |         "version ::= Id String" | 
 | 127 |         if version.value != "version": | 
 | 128 |             raise ASDLSyntaxError(version.lineno, | 
 | 129 |                                 msg="expected 'version', found %" % version) | 
 | 130 |         return V | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 131 |  | 
 | 132 |     def p_definition_0(self, (definition,)): | 
 | 133 |         " definitions ::= definition " | 
 | 134 |         return definition | 
 | 135 |  | 
 | 136 |     def p_definition_1(self, (definitions, definition)): | 
 | 137 |         " definitions ::= definition definitions " | 
 | 138 |         return definitions + definition | 
 | 139 |  | 
 | 140 |     def p_definition(self, (id, _, type)): | 
 | 141 |         " definition ::= Id = type " | 
 | 142 |         return [Type(id, type)] | 
 | 143 |  | 
 | 144 |     def p_type_0(self, (product,)): | 
 | 145 |         " type ::= product " | 
 | 146 |         return product | 
 | 147 |  | 
 | 148 |     def p_type_1(self, (sum,)): | 
 | 149 |         " type ::= sum " | 
 | 150 |         return Sum(sum) | 
 | 151 |  | 
 | 152 |     def p_type_2(self, (sum, id, _0, attributes, _1)): | 
 | 153 |         " type ::= sum Id ( fields ) " | 
 | 154 |         if id.value != "attributes": | 
 | 155 |             raise ASDLSyntaxError(id.lineno, | 
 | 156 |                                   msg="expected attributes, found %s" % id) | 
| Martin v. Löwis | 49c5da1 | 2006-03-01 22:49:05 +0000 | [diff] [blame] | 157 |         if attributes: | 
 | 158 |             attributes.reverse() | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 159 |         return Sum(sum, attributes) | 
 | 160 |  | 
 | 161 |     def p_product(self, (_0, fields, _1)): | 
 | 162 |         " product ::= ( fields ) " | 
 | 163 |         # XXX can't I just construct things in the right order? | 
| Tim Peters | 536cf99 | 2005-12-25 23:18:31 +0000 | [diff] [blame] | 164 |         fields.reverse() | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 165 |         return Product(fields) | 
 | 166 |  | 
 | 167 |     def p_sum_0(self, (constructor,)): | 
| Georg Brandl | bc13092 | 2009-01-03 13:45:15 +0000 | [diff] [blame] | 168 |         " sum ::= constructor " | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 169 |         return [constructor] | 
 | 170 |  | 
 | 171 |     def p_sum_1(self, (constructor, _, sum)): | 
 | 172 |         " sum ::= constructor | sum " | 
 | 173 |         return [constructor] + sum | 
 | 174 |  | 
 | 175 |     def p_sum_2(self, (constructor, _, sum)): | 
 | 176 |         " sum ::= constructor | sum " | 
 | 177 |         return [constructor] + sum | 
 | 178 |  | 
 | 179 |     def p_constructor_0(self, (id,)): | 
 | 180 |         " constructor ::= Id " | 
 | 181 |         return Constructor(id) | 
 | 182 |  | 
 | 183 |     def p_constructor_1(self, (id, _0, fields, _1)): | 
 | 184 |         " constructor ::= Id ( fields ) " | 
 | 185 |         # XXX can't I just construct things in the right order? | 
| Tim Peters | 536cf99 | 2005-12-25 23:18:31 +0000 | [diff] [blame] | 186 |         fields.reverse() | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 187 |         return Constructor(id, fields) | 
 | 188 |  | 
 | 189 |     def p_fields_0(self, (field,)): | 
 | 190 |         " fields ::= field " | 
 | 191 |         return [field] | 
 | 192 |  | 
 | 193 |     def p_fields_1(self, (field, _, fields)): | 
 | 194 |         " fields ::= field , fields " | 
 | 195 |         return fields + [field] | 
 | 196 |  | 
 | 197 |     def p_field_0(self, (type,)): | 
 | 198 |         " field ::= Id " | 
 | 199 |         return Field(type) | 
 | 200 |  | 
 | 201 |     def p_field_1(self, (type, name)): | 
 | 202 |         " field ::= Id Id " | 
 | 203 |         return Field(type, name) | 
 | 204 |  | 
 | 205 |     def p_field_2(self, (type, _, name)): | 
 | 206 |         " field ::= Id * Id " | 
| Benjamin Peterson | 5c33d86 | 2009-06-07 22:54:35 +0000 | [diff] [blame] | 207 |         return Field(type, name, seq=True) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 208 |  | 
 | 209 |     def p_field_3(self, (type, _, name)): | 
 | 210 |         " field ::= Id ? Id " | 
| Benjamin Peterson | 5c33d86 | 2009-06-07 22:54:35 +0000 | [diff] [blame] | 211 |         return Field(type, name, opt=True) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 212 |  | 
 | 213 |     def p_field_4(self, (type, _)): | 
 | 214 |         " field ::= Id * " | 
| Benjamin Peterson | 5c33d86 | 2009-06-07 22:54:35 +0000 | [diff] [blame] | 215 |         return Field(type, seq=True) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 216 |  | 
 | 217 |     def p_field_5(self, (type, _)): | 
 | 218 |         " field ::= Id ? " | 
| Benjamin Peterson | 5c33d86 | 2009-06-07 22:54:35 +0000 | [diff] [blame] | 219 |         return Field(type, opt=True) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 220 |  | 
 | 221 | builtin_types = ("identifier", "string", "int", "bool", "object") | 
 | 222 |  | 
 | 223 | # below is a collection of classes to capture the AST of an AST :-) | 
 | 224 | # not sure if any of the methods are useful yet, but I'm adding them | 
 | 225 | # piecemeal as they seem helpful | 
 | 226 |  | 
| Benjamin Peterson | bd9508a | 2009-06-07 22:33:11 +0000 | [diff] [blame] | 227 | class AST(object): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 228 |     pass # a marker class | 
 | 229 |  | 
 | 230 | class Module(AST): | 
| Martin v. Löwis | eae93b7 | 2006-02-28 00:12:47 +0000 | [diff] [blame] | 231 |     def __init__(self, name, dfns, version): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 232 |         self.name = name | 
 | 233 |         self.dfns = dfns | 
| Martin v. Löwis | eae93b7 | 2006-02-28 00:12:47 +0000 | [diff] [blame] | 234 |         self.version = version | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 235 |         self.types = {} # maps type name to value (from dfns) | 
 | 236 |         for type in dfns: | 
 | 237 |             self.types[type.name.value] = type.value | 
 | 238 |  | 
 | 239 |     def __repr__(self): | 
 | 240 |         return "Module(%s, %s)" % (self.name, self.dfns) | 
 | 241 |  | 
 | 242 | class Type(AST): | 
 | 243 |     def __init__(self, name, value): | 
 | 244 |         self.name = name | 
 | 245 |         self.value = value | 
 | 246 |  | 
 | 247 |     def __repr__(self): | 
 | 248 |         return "Type(%s, %s)" % (self.name, self.value) | 
 | 249 |  | 
 | 250 | class Constructor(AST): | 
 | 251 |     def __init__(self, name, fields=None): | 
 | 252 |         self.name = name | 
 | 253 |         self.fields = fields or [] | 
 | 254 |  | 
 | 255 |     def __repr__(self): | 
 | 256 |         return "Constructor(%s, %s)" % (self.name, self.fields) | 
 | 257 |  | 
 | 258 | class Field(AST): | 
| Benjamin Peterson | 5c33d86 | 2009-06-07 22:54:35 +0000 | [diff] [blame] | 259 |     def __init__(self, type, name=None, seq=False, opt=False): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 260 |         self.type = type | 
 | 261 |         self.name = name | 
 | 262 |         self.seq = seq | 
 | 263 |         self.opt = opt | 
 | 264 |  | 
 | 265 |     def __repr__(self): | 
 | 266 |         if self.seq: | 
| Benjamin Peterson | 5c33d86 | 2009-06-07 22:54:35 +0000 | [diff] [blame] | 267 |             extra = ", seq=True" | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 268 |         elif self.opt: | 
| Benjamin Peterson | 5c33d86 | 2009-06-07 22:54:35 +0000 | [diff] [blame] | 269 |             extra = ", opt=True" | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 270 |         else: | 
 | 271 |             extra = "" | 
 | 272 |         if self.name is None: | 
 | 273 |             return "Field(%s%s)" % (self.type, extra) | 
 | 274 |         else: | 
 | 275 |             return "Field(%s, %s%s)" % (self.type, self.name, extra) | 
 | 276 |  | 
 | 277 | class Sum(AST): | 
 | 278 |     def __init__(self, types, attributes=None): | 
 | 279 |         self.types = types | 
 | 280 |         self.attributes = attributes or [] | 
 | 281 |  | 
 | 282 |     def __repr__(self): | 
 | 283 |         if self.attributes is None: | 
 | 284 |             return "Sum(%s)" % self.types | 
 | 285 |         else: | 
 | 286 |             return "Sum(%s, %s)" % (self.types, self.attributes) | 
 | 287 |  | 
 | 288 | class Product(AST): | 
 | 289 |     def __init__(self, fields): | 
 | 290 |         self.fields = fields | 
 | 291 |  | 
 | 292 |     def __repr__(self): | 
 | 293 |         return "Product(%s)" % self.fields | 
 | 294 |  | 
 | 295 | class VisitorBase(object): | 
 | 296 |  | 
| Benjamin Peterson | 5c33d86 | 2009-06-07 22:54:35 +0000 | [diff] [blame] | 297 |     def __init__(self, skip=False): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 298 |         self.cache = {} | 
 | 299 |         self.skip = skip | 
 | 300 |  | 
 | 301 |     def visit(self, object, *args): | 
 | 302 |         meth = self._dispatch(object) | 
 | 303 |         if meth is None: | 
 | 304 |             return | 
 | 305 |         try: | 
 | 306 |             meth(object, *args) | 
 | 307 |         except Exception, err: | 
 | 308 |             print "Error visiting", repr(object) | 
 | 309 |             print err | 
 | 310 |             traceback.print_exc() | 
 | 311 |             # XXX hack | 
 | 312 |             if hasattr(self, 'file'): | 
 | 313 |                 self.file.flush() | 
 | 314 |             os._exit(1) | 
 | 315 |  | 
 | 316 |     def _dispatch(self, object): | 
 | 317 |         assert isinstance(object, AST), repr(object) | 
 | 318 |         klass = object.__class__ | 
 | 319 |         meth = self.cache.get(klass) | 
 | 320 |         if meth is None: | 
 | 321 |             methname = "visit" + klass.__name__ | 
 | 322 |             if self.skip: | 
 | 323 |                 meth = getattr(self, methname, None) | 
 | 324 |             else: | 
 | 325 |                 meth = getattr(self, methname) | 
 | 326 |             self.cache[klass] = meth | 
 | 327 |         return meth | 
 | 328 |  | 
 | 329 | class Check(VisitorBase): | 
 | 330 |  | 
 | 331 |     def __init__(self): | 
| Benjamin Peterson | 5c33d86 | 2009-06-07 22:54:35 +0000 | [diff] [blame] | 332 |         super(Check, self).__init__(skip=True) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 333 |         self.cons = {} | 
 | 334 |         self.errors = 0 | 
 | 335 |         self.types = {} | 
 | 336 |  | 
 | 337 |     def visitModule(self, mod): | 
 | 338 |         for dfn in mod.dfns: | 
 | 339 |             self.visit(dfn) | 
 | 340 |  | 
 | 341 |     def visitType(self, type): | 
 | 342 |         self.visit(type.value, str(type.name)) | 
 | 343 |  | 
 | 344 |     def visitSum(self, sum, name): | 
 | 345 |         for t in sum.types: | 
 | 346 |             self.visit(t, name) | 
 | 347 |  | 
 | 348 |     def visitConstructor(self, cons, name): | 
 | 349 |         key = str(cons.name) | 
 | 350 |         conflict = self.cons.get(key) | 
 | 351 |         if conflict is None: | 
 | 352 |             self.cons[key] = name | 
 | 353 |         else: | 
 | 354 |             print "Redefinition of constructor %s" % key | 
 | 355 |             print "Defined in %s and %s" % (conflict, name) | 
 | 356 |             self.errors += 1 | 
 | 357 |         for f in cons.fields: | 
 | 358 |             self.visit(f, key) | 
 | 359 |  | 
 | 360 |     def visitField(self, field, name): | 
 | 361 |         key = str(field.type) | 
 | 362 |         l = self.types.setdefault(key, []) | 
 | 363 |         l.append(name) | 
 | 364 |  | 
 | 365 |     def visitProduct(self, prod, name): | 
 | 366 |         for f in prod.fields: | 
 | 367 |             self.visit(f, name) | 
 | 368 |  | 
 | 369 | def check(mod): | 
 | 370 |     v = Check() | 
 | 371 |     v.visit(mod) | 
 | 372 |  | 
 | 373 |     for t in v.types: | 
| Benjamin Peterson | b4347a2 | 2009-06-07 22:55:36 +0000 | [diff] [blame] | 374 |         if t not in mod.types and not t in builtin_types: | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 375 |             v.errors += 1 | 
 | 376 |             uses = ", ".join(v.types[t]) | 
 | 377 |             print "Undefined type %s, used in %s" % (t, uses) | 
| Tim Peters | 536cf99 | 2005-12-25 23:18:31 +0000 | [diff] [blame] | 378 |  | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 379 |     return not v.errors | 
 | 380 |  | 
 | 381 | def parse(file): | 
 | 382 |     scanner = ASDLScanner() | 
 | 383 |     parser = ASDLParser() | 
 | 384 |  | 
 | 385 |     buf = open(file).read() | 
 | 386 |     tokens = scanner.tokenize(buf) | 
 | 387 |     try: | 
 | 388 |         return parser.parse(tokens) | 
 | 389 |     except ASDLSyntaxError, err: | 
 | 390 |         print err | 
 | 391 |         lines = buf.split("\n") | 
 | 392 |         print lines[err.lineno - 1] # lines starts at 0, files at 1 | 
 | 393 |  | 
 | 394 | if __name__ == "__main__": | 
 | 395 |     import glob | 
 | 396 |     import sys | 
 | 397 |  | 
 | 398 |     if len(sys.argv) > 1: | 
 | 399 |         files = sys.argv[1:] | 
 | 400 |     else: | 
 | 401 |         testdir = "tests" | 
 | 402 |         files = glob.glob(testdir + "/*.asdl") | 
| Tim Peters | 536cf99 | 2005-12-25 23:18:31 +0000 | [diff] [blame] | 403 |  | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 404 |     for file in files: | 
 | 405 |         print file | 
 | 406 |         mod = parse(file) | 
 | 407 |         print "module", mod.name | 
 | 408 |         print len(mod.dfns), "definitions" | 
 | 409 |         if not check(mod): | 
 | 410 |             print "Check failed" | 
 | 411 |         else: | 
 | 412 |             for dfn in mod.dfns: | 
 | 413 |                 print dfn.type |