| 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 | 2b80fa6 | 2010-05-18 13:48:45 +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 | 
| Guido van Rossum | 805365e | 2007-05-07 22:24:25 +0000 | [diff] [blame] | 14 | import sys | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 15 | import traceback | 
|  | 16 |  | 
|  | 17 | import spark | 
|  | 18 |  | 
| Guido van Rossum | 805365e | 2007-05-07 22:24:25 +0000 | [diff] [blame] | 19 | def output(string): | 
|  | 20 | sys.stdout.write(string + "\n") | 
|  | 21 |  | 
|  | 22 |  | 
| Benjamin Peterson | 87c8d87 | 2009-06-11 22:54:11 +0000 | [diff] [blame] | 23 | class Token(object): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 24 | # 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 |  | 
|  | 36 | class 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 Peters | 710ab3b | 2006-02-28 18:30:36 +0000 | [diff] [blame] | 44 |  | 
| Martin v. Löwis | eae93b7 | 2006-02-28 00:12:47 +0000 | [diff] [blame] | 45 | class String(Token): | 
|  | 46 | def __init__(self, value, lineno): | 
|  | 47 | self.type = 'String' | 
|  | 48 | self.value = value | 
|  | 49 | self.lineno = lineno | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 50 |  | 
| Guido van Rossum | 805365e | 2007-05-07 22:24:25 +0000 | [diff] [blame] | 51 | class ASDLSyntaxError(Exception): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 52 |  | 
|  | 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 |  | 
|  | 64 | class 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 Peters | 710ab3b | 2006-02-28 18:30:36 +0000 | [diff] [blame] | 77 |  | 
| Martin v. Löwis | eae93b7 | 2006-02-28 00:12:47 +0000 | [diff] [blame] | 78 | def t_string(self, s): | 
|  | 79 | r'"[^"]*"' | 
|  | 80 | self.rv.append(String(s, self.lineno)) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 81 |  | 
|  | 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 Winter | 4902e69 | 2007-08-30 18:18:27 +0000 | [diff] [blame] | 104 | raise ValueError("unmatched input: %r" % s) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 105 |  | 
|  | 106 | class 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 Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 116 | def p_module_0(self, info): | 
| Benjamin Peterson | 6cb2b92 | 2011-03-12 18:28:16 -0600 | [diff] [blame] | 117 | " module ::= Id Id { } " | 
|  | 118 | module, name, _0, _1 = info | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 119 | if module.value != "module": | 
|  | 120 | raise ASDLSyntaxError(module.lineno, | 
|  | 121 | msg="expected 'module', found %s" % module) | 
| Benjamin Peterson | 6cb2b92 | 2011-03-12 18:28:16 -0600 | [diff] [blame] | 122 | return Module(name, None) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 123 |  | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 124 | def p_module(self, info): | 
| Benjamin Peterson | 6cb2b92 | 2011-03-12 18:28:16 -0600 | [diff] [blame] | 125 | " module ::= Id Id { definitions } " | 
|  | 126 | module, name, _0, definitions, _1 = info | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 127 | if module.value != "module": | 
|  | 128 | raise ASDLSyntaxError(module.lineno, | 
|  | 129 | msg="expected 'module', found %s" % module) | 
| Benjamin Peterson | 6cb2b92 | 2011-03-12 18:28:16 -0600 | [diff] [blame] | 130 | return Module(name, definitions) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 131 |  | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 132 | def p_definition_0(self, definition): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 133 | " definitions ::= definition " | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 134 | return definition[0] | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 135 |  | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 136 | def p_definition_1(self, definitions): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 137 | " definitions ::= definition definitions " | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 138 | return definitions[0] + definitions[1] | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 139 |  | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 140 | def p_definition(self, info): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 141 | " definition ::= Id = type " | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 142 | id, _, type = info | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 143 | return [Type(id, type)] | 
|  | 144 |  | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 145 | def p_type_0(self, product): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 146 | " type ::= product " | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 147 | return product[0] | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 148 |  | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 149 | def p_type_1(self, sum): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 150 | " type ::= sum " | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 151 | return Sum(sum[0]) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 152 |  | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 153 | def p_type_2(self, info): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 154 | " type ::= sum Id ( fields ) " | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 155 | sum, id, _0, attributes, _1 = info | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 156 | if id.value != "attributes": | 
|  | 157 | raise ASDLSyntaxError(id.lineno, | 
|  | 158 | msg="expected attributes, found %s" % id) | 
|  | 159 | return Sum(sum, attributes) | 
|  | 160 |  | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 161 | def p_product(self, info): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 162 | " product ::= ( fields ) " | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 163 | _0, fields, _1 = info | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 164 | return Product(fields) | 
|  | 165 |  | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 166 | def p_sum_0(self, constructor): | 
| Georg Brandl | 1f01deb | 2009-01-03 22:47:39 +0000 | [diff] [blame] | 167 | " sum ::= constructor " | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 168 | return [constructor[0]] | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 169 |  | 
| Neal Norwitz | bda355f | 2008-03-17 18:03:56 +0000 | [diff] [blame] | 170 | def p_sum_1(self, info): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 171 | " sum ::= constructor | sum " | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 172 | constructor, _, sum = info | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 173 | return [constructor] + sum | 
|  | 174 |  | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 175 | def p_sum_2(self, info): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 176 | " sum ::= constructor | sum " | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 177 | constructor, _, sum = info | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 178 | return [constructor] + sum | 
|  | 179 |  | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 180 | def p_constructor_0(self, id): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 181 | " constructor ::= Id " | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 182 | return Constructor(id[0]) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 183 |  | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 184 | def p_constructor_1(self, info): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 185 | " constructor ::= Id ( fields ) " | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 186 | id, _0, fields, _1 = info | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 187 | return Constructor(id, fields) | 
|  | 188 |  | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 189 | def p_fields_0(self, field): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 190 | " fields ::= field " | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 191 | return [field[0]] | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 192 |  | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 193 | def p_fields_1(self, info): | 
| Benjamin Peterson | 481ae50 | 2012-07-31 21:41:56 -0700 | [diff] [blame] | 194 | " fields ::= fields , field " | 
|  | 195 | fields, _, field = info | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 196 | return fields + [field] | 
|  | 197 |  | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 198 | def p_field_0(self, type_): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 199 | " field ::= Id " | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 200 | return Field(type_[0]) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 201 |  | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 202 | def p_field_1(self, info): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 203 | " field ::= Id Id " | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 204 | type, name = info | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 205 | return Field(type, name) | 
|  | 206 |  | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 207 | def p_field_2(self, info): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 208 | " field ::= Id * Id " | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 209 | type, _, name = info | 
| Benjamin Peterson | 87c8d87 | 2009-06-11 22:54:11 +0000 | [diff] [blame] | 210 | return Field(type, name, seq=True) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 211 |  | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 212 | def p_field_3(self, info): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 213 | " field ::= Id ? Id " | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 214 | type, _, name = info | 
| Benjamin Peterson | 87c8d87 | 2009-06-11 22:54:11 +0000 | [diff] [blame] | 215 | return Field(type, name, opt=True) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 216 |  | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 217 | def p_field_4(self, type_): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 218 | " field ::= Id * " | 
| Benjamin Peterson | 87c8d87 | 2009-06-11 22:54:11 +0000 | [diff] [blame] | 219 | return Field(type_[0], seq=True) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 220 |  | 
| Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 221 | def p_field_5(self, type_): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 222 | " field ::= Id ? " | 
| Benjamin Peterson | 87c8d87 | 2009-06-11 22:54:11 +0000 | [diff] [blame] | 223 | return Field(type[0], opt=True) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 224 |  | 
| Benjamin Peterson | 4dc6499 | 2011-08-09 16:10:09 -0500 | [diff] [blame] | 225 | builtin_types = ("identifier", "string", "bytes", "int", "object") | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 226 |  | 
|  | 227 | # below is a collection of classes to capture the AST of an AST :-) | 
|  | 228 | # not sure if any of the methods are useful yet, but I'm adding them | 
|  | 229 | # piecemeal as they seem helpful | 
|  | 230 |  | 
| Benjamin Peterson | 87c8d87 | 2009-06-11 22:54:11 +0000 | [diff] [blame] | 231 | class AST(object): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 232 | pass # a marker class | 
|  | 233 |  | 
|  | 234 | class Module(AST): | 
| Benjamin Peterson | 6cb2b92 | 2011-03-12 18:28:16 -0600 | [diff] [blame] | 235 | def __init__(self, name, dfns): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 236 | self.name = name | 
|  | 237 | self.dfns = dfns | 
|  | 238 | self.types = {} # maps type name to value (from dfns) | 
|  | 239 | for type in dfns: | 
|  | 240 | self.types[type.name.value] = type.value | 
|  | 241 |  | 
|  | 242 | def __repr__(self): | 
|  | 243 | return "Module(%s, %s)" % (self.name, self.dfns) | 
|  | 244 |  | 
|  | 245 | class Type(AST): | 
|  | 246 | def __init__(self, name, value): | 
|  | 247 | self.name = name | 
|  | 248 | self.value = value | 
|  | 249 |  | 
|  | 250 | def __repr__(self): | 
|  | 251 | return "Type(%s, %s)" % (self.name, self.value) | 
|  | 252 |  | 
|  | 253 | class Constructor(AST): | 
|  | 254 | def __init__(self, name, fields=None): | 
|  | 255 | self.name = name | 
|  | 256 | self.fields = fields or [] | 
|  | 257 |  | 
|  | 258 | def __repr__(self): | 
|  | 259 | return "Constructor(%s, %s)" % (self.name, self.fields) | 
|  | 260 |  | 
|  | 261 | class Field(AST): | 
| Benjamin Peterson | 87c8d87 | 2009-06-11 22:54:11 +0000 | [diff] [blame] | 262 | def __init__(self, type, name=None, seq=False, opt=False): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 263 | self.type = type | 
|  | 264 | self.name = name | 
|  | 265 | self.seq = seq | 
|  | 266 | self.opt = opt | 
|  | 267 |  | 
|  | 268 | def __repr__(self): | 
|  | 269 | if self.seq: | 
| Benjamin Peterson | 87c8d87 | 2009-06-11 22:54:11 +0000 | [diff] [blame] | 270 | extra = ", seq=True" | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 271 | elif self.opt: | 
| Benjamin Peterson | 87c8d87 | 2009-06-11 22:54:11 +0000 | [diff] [blame] | 272 | extra = ", opt=True" | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 273 | else: | 
|  | 274 | extra = "" | 
|  | 275 | if self.name is None: | 
|  | 276 | return "Field(%s%s)" % (self.type, extra) | 
|  | 277 | else: | 
|  | 278 | return "Field(%s, %s%s)" % (self.type, self.name, extra) | 
|  | 279 |  | 
|  | 280 | class Sum(AST): | 
|  | 281 | def __init__(self, types, attributes=None): | 
|  | 282 | self.types = types | 
|  | 283 | self.attributes = attributes or [] | 
|  | 284 |  | 
|  | 285 | def __repr__(self): | 
|  | 286 | if self.attributes is None: | 
|  | 287 | return "Sum(%s)" % self.types | 
|  | 288 | else: | 
|  | 289 | return "Sum(%s, %s)" % (self.types, self.attributes) | 
|  | 290 |  | 
|  | 291 | class Product(AST): | 
|  | 292 | def __init__(self, fields): | 
|  | 293 | self.fields = fields | 
|  | 294 |  | 
|  | 295 | def __repr__(self): | 
|  | 296 | return "Product(%s)" % self.fields | 
|  | 297 |  | 
|  | 298 | class VisitorBase(object): | 
|  | 299 |  | 
| Benjamin Peterson | 87c8d87 | 2009-06-11 22:54:11 +0000 | [diff] [blame] | 300 | def __init__(self, skip=False): | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 301 | self.cache = {} | 
|  | 302 | self.skip = skip | 
|  | 303 |  | 
|  | 304 | def visit(self, object, *args): | 
|  | 305 | meth = self._dispatch(object) | 
|  | 306 | if meth is None: | 
|  | 307 | return | 
|  | 308 | try: | 
|  | 309 | meth(object, *args) | 
| Guido van Rossum | 805365e | 2007-05-07 22:24:25 +0000 | [diff] [blame] | 310 | except Exception: | 
| Alexandre Vassalotti | df6f3fd | 2009-07-17 05:35:59 +0000 | [diff] [blame] | 311 | output("Error visiting" + repr(object)) | 
|  | 312 | output(str(sys.exc_info()[1])) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 313 | traceback.print_exc() | 
|  | 314 | # XXX hack | 
|  | 315 | if hasattr(self, 'file'): | 
|  | 316 | self.file.flush() | 
|  | 317 | os._exit(1) | 
|  | 318 |  | 
|  | 319 | def _dispatch(self, object): | 
|  | 320 | assert isinstance(object, AST), repr(object) | 
|  | 321 | klass = object.__class__ | 
|  | 322 | meth = self.cache.get(klass) | 
|  | 323 | if meth is None: | 
|  | 324 | methname = "visit" + klass.__name__ | 
|  | 325 | if self.skip: | 
|  | 326 | meth = getattr(self, methname, None) | 
|  | 327 | else: | 
|  | 328 | meth = getattr(self, methname) | 
|  | 329 | self.cache[klass] = meth | 
|  | 330 | return meth | 
|  | 331 |  | 
|  | 332 | class Check(VisitorBase): | 
|  | 333 |  | 
|  | 334 | def __init__(self): | 
| Benjamin Peterson | 87c8d87 | 2009-06-11 22:54:11 +0000 | [diff] [blame] | 335 | super(Check, self).__init__(skip=True) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 336 | self.cons = {} | 
|  | 337 | self.errors = 0 | 
|  | 338 | self.types = {} | 
|  | 339 |  | 
|  | 340 | def visitModule(self, mod): | 
|  | 341 | for dfn in mod.dfns: | 
|  | 342 | self.visit(dfn) | 
|  | 343 |  | 
|  | 344 | def visitType(self, type): | 
|  | 345 | self.visit(type.value, str(type.name)) | 
|  | 346 |  | 
|  | 347 | def visitSum(self, sum, name): | 
|  | 348 | for t in sum.types: | 
|  | 349 | self.visit(t, name) | 
|  | 350 |  | 
|  | 351 | def visitConstructor(self, cons, name): | 
|  | 352 | key = str(cons.name) | 
|  | 353 | conflict = self.cons.get(key) | 
|  | 354 | if conflict is None: | 
|  | 355 | self.cons[key] = name | 
|  | 356 | else: | 
| Guido van Rossum | 805365e | 2007-05-07 22:24:25 +0000 | [diff] [blame] | 357 | output("Redefinition of constructor %s" % key) | 
|  | 358 | output("Defined in %s and %s" % (conflict, name)) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 359 | self.errors += 1 | 
|  | 360 | for f in cons.fields: | 
|  | 361 | self.visit(f, key) | 
|  | 362 |  | 
|  | 363 | def visitField(self, field, name): | 
|  | 364 | key = str(field.type) | 
|  | 365 | l = self.types.setdefault(key, []) | 
|  | 366 | l.append(name) | 
|  | 367 |  | 
|  | 368 | def visitProduct(self, prod, name): | 
|  | 369 | for f in prod.fields: | 
|  | 370 | self.visit(f, name) | 
|  | 371 |  | 
|  | 372 | def check(mod): | 
|  | 373 | v = Check() | 
|  | 374 | v.visit(mod) | 
|  | 375 |  | 
|  | 376 | for t in v.types: | 
| Fred Drake | 34e4f52 | 2006-12-29 04:42:48 +0000 | [diff] [blame] | 377 | if t not in mod.types and not t in builtin_types: | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 378 | v.errors += 1 | 
|  | 379 | uses = ", ".join(v.types[t]) | 
| Guido van Rossum | 805365e | 2007-05-07 22:24:25 +0000 | [diff] [blame] | 380 | output("Undefined type %s, used in %s" % (t, uses)) | 
| Tim Peters | 536cf99 | 2005-12-25 23:18:31 +0000 | [diff] [blame] | 381 |  | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 382 | return not v.errors | 
|  | 383 |  | 
|  | 384 | def parse(file): | 
|  | 385 | scanner = ASDLScanner() | 
|  | 386 | parser = ASDLParser() | 
|  | 387 |  | 
|  | 388 | buf = open(file).read() | 
|  | 389 | tokens = scanner.tokenize(buf) | 
|  | 390 | try: | 
|  | 391 | return parser.parse(tokens) | 
| Guido van Rossum | 805365e | 2007-05-07 22:24:25 +0000 | [diff] [blame] | 392 | except ASDLSyntaxError: | 
| Georg Brandl | 8a73278 | 2009-04-12 11:34:13 +0000 | [diff] [blame] | 393 | err = sys.exc_info()[1] | 
|  | 394 | output(str(err)) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 395 | lines = buf.split("\n") | 
| Guido van Rossum | 805365e | 2007-05-07 22:24:25 +0000 | [diff] [blame] | 396 | output(lines[err.lineno - 1]) # lines starts at 0, files at 1 | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 397 |  | 
|  | 398 | if __name__ == "__main__": | 
|  | 399 | import glob | 
|  | 400 | import sys | 
|  | 401 |  | 
|  | 402 | if len(sys.argv) > 1: | 
|  | 403 | files = sys.argv[1:] | 
|  | 404 | else: | 
|  | 405 | testdir = "tests" | 
|  | 406 | files = glob.glob(testdir + "/*.asdl") | 
| Tim Peters | 536cf99 | 2005-12-25 23:18:31 +0000 | [diff] [blame] | 407 |  | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 408 | for file in files: | 
| Guido van Rossum | 805365e | 2007-05-07 22:24:25 +0000 | [diff] [blame] | 409 | output(file) | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 410 | mod = parse(file) | 
| Georg Brandl | 8a73278 | 2009-04-12 11:34:13 +0000 | [diff] [blame] | 411 | if not mod: | 
|  | 412 | break | 
| Guido van Rossum | 805365e | 2007-05-07 22:24:25 +0000 | [diff] [blame] | 413 | output("module", mod.name) | 
|  | 414 | output(len(mod.dfns), "definitions") | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 415 | if not check(mod): | 
| Guido van Rossum | 805365e | 2007-05-07 22:24:25 +0000 | [diff] [blame] | 416 | output("Check failed") | 
| Jeremy Hylton | 3e0055f | 2005-10-20 19:59:25 +0000 | [diff] [blame] | 417 | else: | 
|  | 418 | for dfn in mod.dfns: | 
| Guido van Rossum | 805365e | 2007-05-07 22:24:25 +0000 | [diff] [blame] | 419 | output(dfn.type) |