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