paul@638 | 1 | #!/usr/bin/env python |
paul@638 | 2 | |
paul@638 | 3 | """ |
paul@638 | 4 | Produce syspython code from an inspected program. |
paul@638 | 5 | |
paul@638 | 6 | Copyright (C) 2006, 2007, 2010, 2011, 2012, 2013 Paul Boddie <paul@boddie.org.uk> |
paul@638 | 7 | |
paul@638 | 8 | This program is free software; you can redistribute it and/or modify it under |
paul@638 | 9 | the terms of the GNU General Public License as published by the Free Software |
paul@638 | 10 | Foundation; either version 3 of the License, or (at your option) any later |
paul@638 | 11 | version. |
paul@638 | 12 | |
paul@638 | 13 | This program is distributed in the hope that it will be useful, but WITHOUT |
paul@638 | 14 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
paul@638 | 15 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
paul@638 | 16 | details. |
paul@638 | 17 | |
paul@638 | 18 | You should have received a copy of the GNU General Public License along with |
paul@638 | 19 | this program. If not, see <http://www.gnu.org/licenses/>. |
paul@638 | 20 | """ |
paul@638 | 21 | |
paul@638 | 22 | from micropython.common import * |
paul@638 | 23 | from micropython.data import * |
paul@638 | 24 | from micropython.errors import * |
paul@638 | 25 | from os.path import exists, extsep, join |
paul@738 | 26 | from micropython.stdcompiler import compiler |
paul@638 | 27 | import sys |
paul@638 | 28 | import os |
paul@638 | 29 | |
paul@638 | 30 | try: |
paul@638 | 31 | set |
paul@638 | 32 | except NameError: |
paul@638 | 33 | from sets import Set as set |
paul@638 | 34 | |
paul@638 | 35 | # Convenience definitions. |
paul@638 | 36 | |
paul@638 | 37 | special_name = compiler.ast.Name |
paul@645 | 38 | |
paul@645 | 39 | def quoted_name(s): |
paul@645 | 40 | return compiler.ast.Const(s) |
paul@638 | 41 | |
paul@664 | 42 | def quoted_ref(obj): |
paul@670 | 43 | return compiler.ast.CallFunc("static", [quoted_name(obj.full_name())]) |
paul@664 | 44 | |
paul@664 | 45 | def module_attribute(module_name, attrname): |
paul@670 | 46 | return special_name(module_name + "." + attrname) |
paul@664 | 47 | |
paul@676 | 48 | def constant_attribute(parent, attrname): |
paul@676 | 49 | return compiler.ast.CallFunc("static", [quoted_name(parent.full_name() + "." + attrname)]) |
paul@676 | 50 | |
paul@646 | 51 | # Special function names. |
paul@666 | 52 | # Some of the assignment operations cannot be supported unless attribute usage |
paul@666 | 53 | # observations are being made. |
paul@646 | 54 | |
paul@678 | 55 | assattr_functions = ("storeattrcontext", "storeattrcontext", |
paul@711 | 56 | "storeattr", "storeattrindexcontextcond", |
paul@711 | 57 | None) |
paul@678 | 58 | getattr_functions = ("loadattrcontext", "loadattrcontextcond", |
paul@711 | 59 | "loadattr", "loadattrindexcontextcond", |
paul@711 | 60 | "loadconstant") |
paul@646 | 61 | |
paul@638 | 62 | # Source code classes. |
paul@638 | 63 | |
paul@638 | 64 | class ConvertedSource(ASTVisitor): |
paul@638 | 65 | |
paul@638 | 66 | "A conversion of module source code to syspython." |
paul@638 | 67 | |
paul@638 | 68 | def __init__(self, module, program): |
paul@638 | 69 | self.visitor = self |
paul@638 | 70 | self.module = module |
paul@638 | 71 | self.program = program |
paul@645 | 72 | self.objtable = program.get_object_table() |
paul@748 | 73 | self.current_definition = None |
paul@638 | 74 | self.units = [] |
paul@638 | 75 | |
paul@638 | 76 | def get_unit(self): |
paul@638 | 77 | return self.units[-1] |
paul@638 | 78 | |
paul@638 | 79 | def get_module(self): |
paul@638 | 80 | return self.units[0] |
paul@638 | 81 | |
paul@638 | 82 | def to_stream(self, stream): |
paul@638 | 83 | |
paul@638 | 84 | "Write the converted code to the given 'stream'." |
paul@638 | 85 | |
paul@638 | 86 | module = self.dispatch(self.module.astnode) |
paul@638 | 87 | stream.write(str(module)) |
paul@638 | 88 | |
paul@755 | 89 | def store_value(self, unit, scope, name, value): |
paul@755 | 90 | |
paul@755 | 91 | """ |
paul@755 | 92 | In the given 'unit' and for the given 'scope', store for the given |
paul@755 | 93 | 'name' the given 'value'. |
paul@755 | 94 | """ |
paul@755 | 95 | |
paul@755 | 96 | if scope == "local": |
paul@755 | 97 | |
paul@755 | 98 | # Function locals are stored using a function. |
paul@755 | 99 | |
paul@755 | 100 | if isinstance(unit, Function): |
paul@755 | 101 | return compiler.ast.CallFunc( |
paul@755 | 102 | special_name("storelocal"), |
paul@755 | 103 | [special_name(name), value] |
paul@755 | 104 | ) |
paul@755 | 105 | |
paul@755 | 106 | # Class locals are class attribute references. |
paul@755 | 107 | |
paul@755 | 108 | elif isinstance(unit, Class): |
paul@755 | 109 | return compiler.ast.CallFunc( |
paul@755 | 110 | special_name("storeattrcontext"), |
paul@755 | 111 | [quoted_ref(unit), special_name(name), value] |
paul@755 | 112 | ) |
paul@755 | 113 | |
paul@755 | 114 | # Module locals are module attribute references. |
paul@748 | 115 | |
paul@755 | 116 | elif isinstance(unit, Module): |
paul@755 | 117 | return compiler.ast.CallFunc( |
paul@755 | 118 | special_name("storeattr"), |
paul@755 | 119 | [quoted_ref(unit), special_name(name), value] |
paul@755 | 120 | ) |
paul@755 | 121 | else: |
paul@755 | 122 | raise TranslateError("Program unit has no local %r." % name) |
paul@755 | 123 | |
paul@755 | 124 | elif scope == "global": |
paul@755 | 125 | |
paul@755 | 126 | # Globals are references to module attributes. |
paul@748 | 127 | |
paul@755 | 128 | return compiler.ast.CallFunc( |
paul@755 | 129 | special_name("storeattr"), |
paul@755 | 130 | [quoted_ref(self.get_module()), special_name(name), value] |
paul@755 | 131 | ) |
paul@755 | 132 | |
paul@755 | 133 | elif scope == "builtin": |
paul@755 | 134 | |
paul@755 | 135 | # Builtins are accessed via the __builtins__ module. |
paul@755 | 136 | |
paul@755 | 137 | return compiler.ast.CallFunc( |
paul@755 | 138 | special_name("storeattr"), |
paul@755 | 139 | [special_name("__builtins__"), special_name(name), value] |
paul@755 | 140 | ) |
paul@755 | 141 | |
paul@748 | 142 | else: |
paul@755 | 143 | # NOTE: This may happen because a class attribute is optimised away. |
paul@755 | 144 | return compiler.ast.CallFunc( |
paul@755 | 145 | special_name("storeunknown"), |
paul@755 | 146 | [special_name(name), value] |
paul@755 | 147 | ) |
paul@748 | 148 | |
paul@638 | 149 | def NOP(self, node): |
paul@638 | 150 | return node |
paul@638 | 151 | |
paul@638 | 152 | def visitModule(self, node): |
paul@638 | 153 | module = node.unit |
paul@638 | 154 | self.units.append(module) |
paul@638 | 155 | |
paul@645 | 156 | definitions = self.process_definitions(node) |
paul@748 | 157 | self.current_definition = None |
paul@638 | 158 | |
paul@675 | 159 | # keywords(name, ...) |
paul@675 | 160 | |
paul@675 | 161 | keywords = module.keyword_names and [ |
paul@675 | 162 | compiler.ast.CallFunc( |
paul@675 | 163 | special_name("keywords"), |
paul@675 | 164 | [special_name(name) for name in module.keyword_names] |
paul@675 | 165 | ) |
paul@675 | 166 | ] or [] |
paul@675 | 167 | |
paul@670 | 168 | # globalnames(name, ...) |
paul@638 | 169 | |
paul@638 | 170 | globalnames = module.module_attribute_names() and [ |
paul@638 | 171 | compiler.ast.CallFunc( |
paul@670 | 172 | special_name("globalnames"), |
paul@667 | 173 | [special_name(attr.name) for attr in module.attributes_as_list()] |
paul@638 | 174 | ) |
paul@638 | 175 | ] or [] |
paul@638 | 176 | |
paul@638 | 177 | # def __main__(): |
paul@638 | 178 | # ... |
paul@638 | 179 | |
paul@638 | 180 | main = compiler.ast.Function( |
paul@638 | 181 | [], "__main__", [], [], 0, "Module initialisation.", |
paul@638 | 182 | compiler.ast.Stmt(globalnames + self.dispatch(node.node).nodes) |
paul@638 | 183 | ) |
paul@638 | 184 | |
paul@638 | 185 | self.units.pop() |
paul@638 | 186 | |
paul@675 | 187 | return compiler.ast.Module(node.doc, compiler.ast.Stmt(keywords + definitions + [main])) |
paul@638 | 188 | |
paul@638 | 189 | # Statements. |
paul@638 | 190 | |
paul@638 | 191 | def visitAssert(self, node): |
paul@638 | 192 | return compiler.ast.Assert(self.dispatch(node.test), node.fail and self.dispatch(node.fail)) |
paul@638 | 193 | |
paul@638 | 194 | def visitAssign(self, node): |
paul@638 | 195 | expr = self.dispatch(node.expr) |
paul@734 | 196 | return compiler.ast.Stmt( |
paul@736 | 197 | [compiler.ast.Assign([compiler.ast.AssName("expr", "OP_ASSIGN")], expr)] + |
paul@736 | 198 | [self.dispatch(n, compiler.ast.Name("expr")) for n in node.nodes] |
paul@734 | 199 | ) |
paul@638 | 200 | |
paul@638 | 201 | def visitAugAssign(self, node): |
paul@638 | 202 | |
paul@638 | 203 | # lvalue = op(lvalue, expr) |
paul@670 | 204 | # -> fn(lvalue, op(lvalue, expr)) |
paul@638 | 205 | |
paul@638 | 206 | op_name = operator_functions[node.op] |
paul@638 | 207 | |
paul@638 | 208 | return self.dispatch(node.node, compiler.ast.CallFunc( |
paul@671 | 209 | special_name("apply"), |
paul@671 | 210 | [module_attribute("operator", op_name), |
paul@671 | 211 | self.dispatch(node.node), self.dispatch(node.expr)] |
paul@638 | 212 | )) |
paul@638 | 213 | |
paul@638 | 214 | visitBreak = NOP |
paul@638 | 215 | |
paul@638 | 216 | def visitClass(self, node): |
paul@638 | 217 | if not used_by_unit(node): |
paul@638 | 218 | return compiler.ast.Stmt([]) |
paul@638 | 219 | |
paul@638 | 220 | self.units.append(node.unit) |
paul@638 | 221 | try: |
paul@638 | 222 | # Incorporate class body code in the main function. |
paul@638 | 223 | |
paul@748 | 224 | if not self.processing_definition(node): |
paul@638 | 225 | return self.dispatch(node.code) |
paul@638 | 226 | else: |
paul@638 | 227 | return self._visitClassDefinition(node) |
paul@638 | 228 | |
paul@638 | 229 | finally: |
paul@638 | 230 | self.units.pop() |
paul@638 | 231 | |
paul@638 | 232 | def _visitClassDefinition(self, node): |
paul@638 | 233 | cls = node.unit |
paul@638 | 234 | |
paul@670 | 235 | # instattrs(name, ...) |
paul@670 | 236 | # clsattrs(name, ...) |
paul@638 | 237 | |
paul@638 | 238 | instattrs = cls.instance_attribute_names() and [ |
paul@638 | 239 | compiler.ast.CallFunc( |
paul@670 | 240 | special_name("instattrs"), |
paul@667 | 241 | [special_name(attr.name) for attr in cls.instance_attributes_as_list()] |
paul@638 | 242 | ) |
paul@638 | 243 | ] or [] |
paul@638 | 244 | |
paul@638 | 245 | clsattrs = cls.class_attribute_names() and [ |
paul@638 | 246 | compiler.ast.CallFunc( |
paul@670 | 247 | special_name("clsattrs"), |
paul@667 | 248 | [special_name(attr.name) for attr in cls.attributes_as_list()] |
paul@638 | 249 | ) |
paul@638 | 250 | ] or [] |
paul@638 | 251 | |
paul@670 | 252 | # inherited(superclass, name, ...) |
paul@638 | 253 | # ... |
paul@638 | 254 | |
paul@638 | 255 | attrs_by_cls = {} |
paul@638 | 256 | for attrname, attr in cls.all_class_attributes().items(): |
paul@638 | 257 | supercls = attr.parent |
paul@638 | 258 | if supercls is cls: |
paul@638 | 259 | continue |
paul@638 | 260 | if not attrs_by_cls.has_key(supercls): |
paul@638 | 261 | attrs_by_cls[supercls] = [] |
paul@638 | 262 | attrs_by_cls[supercls].append(attrname) |
paul@638 | 263 | |
paul@638 | 264 | inherited = [] |
paul@638 | 265 | |
paul@638 | 266 | for supercls, attrnames in attrs_by_cls.items(): |
paul@638 | 267 | inherited.append( |
paul@638 | 268 | compiler.ast.CallFunc( |
paul@670 | 269 | special_name("inherited"), |
paul@645 | 270 | [quoted_ref(supercls)] + [special_name(name) for name in attrnames] |
paul@638 | 271 | )) |
paul@638 | 272 | |
paul@670 | 273 | # descendants(name, ...) |
paul@638 | 274 | |
paul@638 | 275 | descendants = cls.all_descendants() and [ |
paul@638 | 276 | compiler.ast.CallFunc( |
paul@670 | 277 | special_name("descendants"), |
paul@638 | 278 | [special_name(name) for name in cls.all_descendants().keys()] |
paul@638 | 279 | ) |
paul@638 | 280 | ] or [] |
paul@638 | 281 | |
paul@638 | 282 | # Process all the definitions defined inside the class. |
paul@638 | 283 | |
paul@645 | 284 | definitions = self.process_definitions(node) |
paul@638 | 285 | |
paul@638 | 286 | return compiler.ast.Class(node.name, [], node.doc, |
paul@638 | 287 | compiler.ast.Stmt(instattrs + clsattrs + inherited + descendants + definitions) |
paul@638 | 288 | ) |
paul@638 | 289 | |
paul@638 | 290 | visitContinue = NOP |
paul@638 | 291 | |
paul@638 | 292 | def visitDiscard(self, node): |
paul@638 | 293 | return compiler.ast.Discard(self.dispatch(node.expr)) |
paul@638 | 294 | |
paul@638 | 295 | def visitFor(self, node): |
paul@638 | 296 | |
paul@638 | 297 | """ |
paul@638 | 298 | Convert from... |
paul@638 | 299 | |
paul@638 | 300 | for <assign> in <list>: |
paul@638 | 301 | <body> |
paul@638 | 302 | [ else: |
paul@638 | 303 | <else_> ] |
paul@638 | 304 | |
paul@638 | 305 | ...to... |
paul@638 | 306 | |
paul@638 | 307 | _it = iter(<list>) |
paul@638 | 308 | while True: |
paul@638 | 309 | try: |
paul@638 | 310 | <assign> = _it.next() |
paul@638 | 311 | except StopIteration: |
paul@638 | 312 | [ <else_> ] |
paul@638 | 313 | break |
paul@638 | 314 | else: |
paul@638 | 315 | <body> |
paul@638 | 316 | """ |
paul@638 | 317 | |
paul@638 | 318 | unit = self.get_unit() |
paul@638 | 319 | temp = quoted_name(unit.temp_usage) |
paul@638 | 320 | unit.temp_usage += 1 |
paul@638 | 321 | |
paul@638 | 322 | else_nodes = node.else_ and self.dispatch(node.else_).nodes or [] |
paul@638 | 323 | |
paul@638 | 324 | return compiler.ast.Stmt([ |
paul@670 | 325 | # storetemp(_it, __builtins__.iter(<list>)) |
paul@670 | 326 | compiler.ast.CallFunc(special_name("storetemp"), [ |
paul@638 | 327 | temp, |
paul@638 | 328 | compiler.ast.CallFunc( |
paul@671 | 329 | special_name("apply"), |
paul@671 | 330 | [module_attribute("__builtins__", "iter"), self.dispatch(node.list)] |
paul@638 | 331 | ) |
paul@638 | 332 | ]), |
paul@638 | 333 | # while True: ... |
paul@638 | 334 | compiler.ast.While( |
paul@638 | 335 | special_name("True"), |
paul@638 | 336 | # try: ... |
paul@638 | 337 | compiler.ast.TryExcept( |
paul@638 | 338 | compiler.ast.Stmt([ |
paul@638 | 339 | # <assign> = ... |
paul@638 | 340 | self.dispatch(node.assign, |
paul@638 | 341 | # _it.next() |
paul@638 | 342 | compiler.ast.CallFunc( |
paul@670 | 343 | compiler.ast.CallFunc(special_name("loadattrindex"), [ |
paul@670 | 344 | compiler.ast.CallFunc(special_name("loadtemp"), [temp]), |
paul@638 | 345 | special_name("next") |
paul@638 | 346 | ]), |
paul@638 | 347 | [] |
paul@638 | 348 | ) |
paul@638 | 349 | ) |
paul@638 | 350 | ]), |
paul@638 | 351 | # except StopIteration: ... |
paul@638 | 352 | [(special_name("StopIteration"), None, compiler.ast.Stmt(else_nodes + [compiler.ast.Break()]))], |
paul@638 | 353 | # else: ... |
paul@638 | 354 | self.dispatch(node.body) |
paul@638 | 355 | ), |
paul@638 | 356 | None |
paul@638 | 357 | ) |
paul@638 | 358 | ]) |
paul@638 | 359 | |
paul@638 | 360 | def visitFrom(self, node): |
paul@638 | 361 | |
paul@638 | 362 | # Generate __main__ function calls for each step in the imported module |
paul@638 | 363 | # hierarchy. |
paul@638 | 364 | |
paul@638 | 365 | statements = [] |
paul@638 | 366 | |
paul@638 | 367 | for modname in self.module.get_module_paths(node.modname): |
paul@638 | 368 | statements.append( |
paul@638 | 369 | compiler.ast.CallFunc(special_name("%s.__main__" % modname ), []) |
paul@638 | 370 | ) |
paul@638 | 371 | |
paul@638 | 372 | for name, alias in node.names: |
paul@638 | 373 | statements.append( |
paul@670 | 374 | compiler.ast.CallFunc( |
paul@670 | 375 | special_name("storelocal"), |
paul@670 | 376 | [special_name(alias or name), |
paul@638 | 377 | compiler.ast.CallFunc( |
paul@670 | 378 | special_name("loadattr"), |
paul@638 | 379 | [special_name(node.modname), special_name(name)] |
paul@638 | 380 | ) |
paul@670 | 381 | ]) |
paul@638 | 382 | ) |
paul@638 | 383 | |
paul@638 | 384 | return compiler.ast.Stmt(statements) |
paul@638 | 385 | |
paul@638 | 386 | def visitFunction(self, node): |
paul@638 | 387 | if not used_by_unit(node): |
paul@638 | 388 | return compiler.ast.Stmt([]) |
paul@638 | 389 | |
paul@761 | 390 | if not self.processing_definition(node): |
paul@638 | 391 | |
paul@761 | 392 | # Generate rebindings of functions where multiple definitions |
paul@761 | 393 | # exist within a scope. Also generate dynamic function object |
paul@761 | 394 | # initialisation. |
paul@638 | 395 | |
paul@761 | 396 | fn = node.unit |
paul@761 | 397 | if fn.is_dynamic(): |
paul@761 | 398 | ref = compiler.ast.CallFunc( |
paul@761 | 399 | special_name("makedynamic"), |
paul@761 | 400 | [quoted_ref(fn)] + [self.dispatch(n) for n in fn.defaults] |
paul@761 | 401 | ) |
paul@761 | 402 | elif fn.defaults: |
paul@761 | 403 | ref = compiler.ast.CallFunc( |
paul@761 | 404 | special_name("setdefaults"), |
paul@761 | 405 | [quoted_ref(fn)] + [self.dispatch(n) for n in fn.defaults] |
paul@761 | 406 | ) |
paul@761 | 407 | if fn.name == fn.original_name: |
paul@761 | 408 | return ref |
paul@761 | 409 | elif fn.name == fn.original_name: |
paul@761 | 410 | return compiler.ast.Stmt([]) |
paul@761 | 411 | else: |
paul@761 | 412 | ref = quoted_ref(fn) |
paul@755 | 413 | |
paul@761 | 414 | return self.store_value(fn.parent, "local", fn.original_name, ref) |
paul@761 | 415 | |
paul@761 | 416 | # Where this function is being processed, visit the definition in its |
paul@761 | 417 | # entirety. |
paul@761 | 418 | |
paul@761 | 419 | else: |
paul@761 | 420 | self.units.append(node.unit) |
paul@761 | 421 | try: |
paul@638 | 422 | return self._visitFunctionDefinition(node) |
paul@761 | 423 | finally: |
paul@761 | 424 | self.units.pop() |
paul@638 | 425 | |
paul@638 | 426 | def _visitFunctionDefinition(self, node): |
paul@638 | 427 | fn = node.unit |
paul@638 | 428 | |
paul@670 | 429 | # localnames(name, ...) |
paul@670 | 430 | # globalnames(name, ...) |
paul@638 | 431 | |
paul@645 | 432 | localnames = fn.all_locals() and [ |
paul@638 | 433 | compiler.ast.CallFunc( |
paul@670 | 434 | special_name("localnames"), |
paul@645 | 435 | [special_name(name) for name in fn.all_locals().keys()] |
paul@638 | 436 | ) |
paul@638 | 437 | ] or [] |
paul@638 | 438 | |
paul@638 | 439 | globalnames = fn.globals and [ |
paul@638 | 440 | compiler.ast.CallFunc( |
paul@670 | 441 | special_name("globalnames"), |
paul@638 | 442 | [special_name(name) for name in fn.globals] |
paul@638 | 443 | ) |
paul@638 | 444 | ] or [] |
paul@638 | 445 | |
paul@755 | 446 | # Process any local class or function definitions. |
paul@755 | 447 | |
paul@755 | 448 | current = self.current_definition |
paul@755 | 449 | definitions = self.process_definitions(node) |
paul@755 | 450 | self.current_definition = current |
paul@755 | 451 | |
paul@755 | 452 | # NOTE: Any required defaults should be copied into the local namespace |
paul@755 | 453 | # NOTE: using the __context__ reference to the instance of the function. |
paul@755 | 454 | |
paul@645 | 455 | # NOTE: Should generate guards for attribute usage operations. |
paul@645 | 456 | |
paul@638 | 457 | code = self.dispatch(node.code) |
paul@638 | 458 | |
paul@761 | 459 | return compiler.ast.Function(node.decorators, node.name, node.argnames, node.defaults, node.flags, node.doc, |
paul@755 | 460 | compiler.ast.Stmt(localnames + globalnames + definitions + code.nodes)) |
paul@638 | 461 | |
paul@638 | 462 | visitGlobal = NOP |
paul@638 | 463 | |
paul@638 | 464 | def visitIf(self, node): |
paul@638 | 465 | return compiler.ast.If( |
paul@638 | 466 | [(self.dispatch(compare), self.dispatch(stmt)) for (compare, stmt) in node.tests], |
paul@638 | 467 | node.else_ and self.dispatch(node.else_) |
paul@638 | 468 | ) |
paul@638 | 469 | |
paul@638 | 470 | def visitImport(self, node): |
paul@638 | 471 | |
paul@638 | 472 | # Generate __main__ function calls for each step in the imported module |
paul@638 | 473 | # hierarchy. |
paul@638 | 474 | |
paul@638 | 475 | statements = [] |
paul@638 | 476 | |
paul@638 | 477 | for name, alias in node.names: |
paul@638 | 478 | for modname in self.module.get_module_paths(name): |
paul@638 | 479 | statements.append( |
paul@638 | 480 | compiler.ast.CallFunc(compiler.ast.Getattr(modname, "__main__"), []) |
paul@638 | 481 | ) |
paul@638 | 482 | |
paul@638 | 483 | statements.append( |
paul@670 | 484 | compiler.ast.CallFunc( |
paul@670 | 485 | special_name("storelocal"), |
paul@670 | 486 | [special_name(alias or name.split(".")[0]), |
paul@638 | 487 | compiler.ast.CallFunc( |
paul@670 | 488 | special_name("static"), |
paul@638 | 489 | [special_name(name)] |
paul@638 | 490 | ) |
paul@670 | 491 | ]) |
paul@638 | 492 | ) |
paul@638 | 493 | |
paul@638 | 494 | return compiler.ast.Stmt(statements) |
paul@638 | 495 | |
paul@645 | 496 | def visitPass(self, node): |
paul@645 | 497 | if not isinstance(self.get_unit(), Class): |
paul@645 | 498 | return compiler.ast.Pass() |
paul@645 | 499 | else: |
paul@645 | 500 | return compiler.ast.Stmt([]) |
paul@638 | 501 | |
paul@638 | 502 | def visitPrint(self, node): |
paul@671 | 503 | return compiler.ast.CallFunc( |
paul@671 | 504 | special_name("apply"), |
paul@671 | 505 | [module_attribute("__builtins__", "_print"), |
paul@671 | 506 | node.dest and self.dispatch(node.dest) or special_name("None")] |
paul@671 | 507 | + [self.dispatch(n) for n in node.nodes] |
paul@638 | 508 | ) |
paul@638 | 509 | |
paul@638 | 510 | def visitPrintnl(self, node): |
paul@671 | 511 | return compiler.ast.CallFunc( |
paul@671 | 512 | special_name("apply"), |
paul@671 | 513 | [module_attribute("__builtins__", "_println"), |
paul@671 | 514 | node.dest and self.dispatch(node.dest) or special_name("None")] |
paul@671 | 515 | + [self.dispatch(n) for n in node.nodes] |
paul@638 | 516 | ) |
paul@638 | 517 | |
paul@638 | 518 | def visitRaise(self, node): |
paul@638 | 519 | return compiler.ast.Raise( |
paul@638 | 520 | node.expr1 and self.dispatch(node.expr1), |
paul@638 | 521 | node.expr2 and self.dispatch(node.expr2), |
paul@638 | 522 | node.expr3 and self.dispatch(node.expr3) |
paul@638 | 523 | ) |
paul@638 | 524 | |
paul@638 | 525 | def visitReturn(self, node): |
paul@638 | 526 | return compiler.ast.Return(self.dispatch(node.value)) |
paul@638 | 527 | |
paul@638 | 528 | def visitStmt(self, node): |
paul@638 | 529 | return compiler.ast.Stmt([self.dispatch(n) for n in node.nodes]) |
paul@638 | 530 | |
paul@638 | 531 | def visitTryExcept(self, node): |
paul@638 | 532 | # NOTE: Need to dispatch to the assignment with the exception. |
paul@638 | 533 | return compiler.ast.TryExcept( |
paul@638 | 534 | self.dispatch(node.body), |
paul@638 | 535 | [(spec and self.dispatch(spec), assign and self.dispatch(assign), self.dispatch(statement)) |
paul@638 | 536 | for spec, assign, statement in node.handlers], |
paul@638 | 537 | node.else_ and self.dispatch(node.else_) |
paul@638 | 538 | ) |
paul@638 | 539 | |
paul@638 | 540 | def visitTryFinally(self, node): |
paul@638 | 541 | return compiler.ast.TryFinally( |
paul@638 | 542 | self.dispatch(node.body), |
paul@638 | 543 | self.dispatch(node.final) |
paul@638 | 544 | ) |
paul@638 | 545 | |
paul@638 | 546 | def visitWhile(self, node): |
paul@638 | 547 | return compiler.ast.While( |
paul@638 | 548 | self.dispatch(node.test), |
paul@638 | 549 | self.dispatch(node.body), |
paul@638 | 550 | node.else_ and self.dispatch(node.else_) |
paul@638 | 551 | ) |
paul@638 | 552 | |
paul@638 | 553 | def visitYield(self, node): |
paul@638 | 554 | return compiler.ast.Yield(self.dispatch(node.value)) |
paul@638 | 555 | |
paul@638 | 556 | # Expression-related helper methods. |
paul@638 | 557 | |
paul@638 | 558 | def _visitBitBinary(self, node): |
paul@764 | 559 | attr = self._visitAttr(node, special_name(node._module.full_name()), node._attr.name) |
paul@638 | 560 | last = self.dispatch(node.nodes[0]) |
paul@638 | 561 | |
paul@638 | 562 | for n in node.nodes[1:]: |
paul@764 | 563 | last = self._visitCallFunc( |
paul@764 | 564 | node._attr, |
paul@764 | 565 | [attr, last, self.dispatch(n)] |
paul@638 | 566 | ) |
paul@638 | 567 | |
paul@638 | 568 | return last |
paul@638 | 569 | |
paul@638 | 570 | def _visitBinary(self, node): |
paul@764 | 571 | attr = self._visitAttr(node, special_name(node._module.full_name()), node._attr.name) |
paul@638 | 572 | |
paul@764 | 573 | return self._visitCallFunc( |
paul@764 | 574 | node._attr, |
paul@764 | 575 | [attr, self.dispatch(node.left), self.dispatch(node.right)] |
paul@638 | 576 | ) |
paul@638 | 577 | |
paul@638 | 578 | def _visitUnary(self, node): |
paul@764 | 579 | attr = self._visitAttr(node, special_name(node._module.full_name()), node._attr.name) |
paul@638 | 580 | |
paul@764 | 581 | return self._visitCallFunc( |
paul@764 | 582 | node._attr, |
paul@764 | 583 | [attr, self.dispatch(node.expr)] |
paul@638 | 584 | ) |
paul@638 | 585 | |
paul@645 | 586 | def _generateValue(self, value): |
paul@645 | 587 | |
paul@645 | 588 | # Literal constants. |
paul@645 | 589 | |
paul@645 | 590 | if isinstance(value, Const): |
paul@645 | 591 | return compiler.ast.Const(value.get_value()) |
paul@645 | 592 | |
paul@645 | 593 | # Other constant structures. |
paul@645 | 594 | |
paul@645 | 595 | if isinstance(value, Constant): |
paul@645 | 596 | return quoted_ref(value) |
paul@645 | 597 | |
paul@645 | 598 | return None |
paul@645 | 599 | |
paul@764 | 600 | def _visitAttr(self, node, accessor, attrname, expr=None): |
paul@646 | 601 | unit = self.get_unit() |
paul@646 | 602 | |
paul@646 | 603 | # Choose the appropriate special functions. |
paul@646 | 604 | |
paul@711 | 605 | (opattrcontext, opattrcontextcond, opattr, opattrindexcontextcond, opconstant) = \ |
paul@678 | 606 | expr and assattr_functions or getattr_functions |
paul@646 | 607 | |
paul@646 | 608 | # Generate already-deduced accesses. |
paul@646 | 609 | |
paul@646 | 610 | if node._access_type == "constant": |
paul@711 | 611 | value = self._generateValue(node._value_deduced) |
paul@711 | 612 | |
paul@711 | 613 | # Where constant attributes are accessed via instances, a special |
paul@711 | 614 | # operation setting the context is needed. |
paul@711 | 615 | |
paul@711 | 616 | if node._set_context == "set": |
paul@746 | 617 | return compiler.ast.CallFunc(special_name(opconstant), [value, accessor]) |
paul@711 | 618 | else: |
paul@711 | 619 | return value |
paul@646 | 620 | |
paul@646 | 621 | # Generate accesses via static objects and instances. |
paul@646 | 622 | |
paul@646 | 623 | if node._attr_deduced: |
paul@676 | 624 | |
paul@676 | 625 | # Static attributes may cause context replacement. |
paul@676 | 626 | |
paul@676 | 627 | if node._access_type == "static": |
paul@676 | 628 | if node._set_context == "set": |
paul@678 | 629 | op = opattrcontext |
paul@676 | 630 | elif node._set_context == "cond": |
paul@678 | 631 | op = opattrcontextcond |
paul@676 | 632 | else: |
paul@678 | 633 | op = opattr |
paul@676 | 634 | |
paul@676 | 635 | parent = self._generateValue(node._attr_deduced.parent) |
paul@676 | 636 | |
paul@676 | 637 | # Non-static attributes. |
paul@676 | 638 | |
paul@646 | 639 | else: |
paul@646 | 640 | op = opattr |
paul@676 | 641 | parent = None |
paul@646 | 642 | |
paul@646 | 643 | # Handle unsupported operations. |
paul@646 | 644 | |
paul@646 | 645 | if not op: |
paul@764 | 646 | raise TranslateError("Storing of class attribute %r via self not permitted." % attrname) |
paul@646 | 647 | |
paul@646 | 648 | # Define the arguments: accessor, attribute name and optional value. |
paul@646 | 649 | |
paul@646 | 650 | args = [ |
paul@676 | 651 | parent or accessor, |
paul@764 | 652 | special_name(attrname) |
paul@646 | 653 | ] |
paul@646 | 654 | |
paul@646 | 655 | if expr: |
paul@646 | 656 | args.append(expr) |
paul@646 | 657 | |
paul@670 | 658 | # Append any context to be set. |
paul@670 | 659 | |
paul@670 | 660 | if node._set_context and args[0] is not accessor: |
paul@670 | 661 | args.append(accessor) |
paul@670 | 662 | |
paul@646 | 663 | return compiler.ast.CallFunc(special_name(op), args) |
paul@646 | 664 | |
paul@646 | 665 | # Positioned accesses are normal accesses via instances. |
paul@646 | 666 | |
paul@646 | 667 | if node._access_type == "positioned": |
paul@764 | 668 | args = [accessor, special_name(attrname)] |
paul@646 | 669 | if expr: |
paul@646 | 670 | args.append(expr) |
paul@646 | 671 | return compiler.ast.CallFunc(special_name(opattr), args) |
paul@646 | 672 | |
paul@646 | 673 | # With no usable deductions, generate a table-based access. |
paul@646 | 674 | |
paul@764 | 675 | args = [accessor, special_name(attrname)] |
paul@646 | 676 | if expr: |
paul@646 | 677 | args.append(expr) |
paul@646 | 678 | access = compiler.ast.CallFunc(special_name(opattrindexcontextcond), args) |
paul@646 | 679 | |
paul@646 | 680 | # class.__class__ => __builtins__.type |
paul@646 | 681 | |
paul@764 | 682 | if attrname == "__class__": |
paul@646 | 683 | |
paul@670 | 684 | # storetemp(n, <accessor>) |
paul@670 | 685 | # isclass(n) and __builtins__.type or <access> |
paul@646 | 686 | |
paul@646 | 687 | temp = quoted_name(unit.temp_usage) |
paul@646 | 688 | unit.temp_usage += 1 |
paul@646 | 689 | |
paul@646 | 690 | return compiler.ast.Stmt([ |
paul@670 | 691 | compiler.ast.CallFunc(special_name("storetemp"), [temp, access]), |
paul@646 | 692 | compiler.ast.Or([ |
paul@646 | 693 | compiler.ast.And([ |
paul@646 | 694 | compiler.ast.CallFunc( |
paul@670 | 695 | special_name("isclass"), |
paul@670 | 696 | [compiler.ast.CallFunc(special_name("loadtemp"), [temp])] |
paul@646 | 697 | ), |
paul@664 | 698 | module_attribute("__builtins__", "type") |
paul@646 | 699 | ]), |
paul@646 | 700 | access |
paul@646 | 701 | ]) |
paul@646 | 702 | ]) |
paul@646 | 703 | |
paul@646 | 704 | # General accesses. |
paul@646 | 705 | |
paul@646 | 706 | else: |
paul@646 | 707 | return access |
paul@646 | 708 | |
paul@638 | 709 | # Expressions. |
paul@638 | 710 | |
paul@638 | 711 | def visitAdd(self, node): |
paul@638 | 712 | return self._visitBinary(node) |
paul@638 | 713 | |
paul@638 | 714 | def visitAnd(self, node): |
paul@638 | 715 | return compiler.ast.And([self.dispatch(n) for n in node.nodes]) |
paul@638 | 716 | |
paul@663 | 717 | def visitAssAttr(self, node, expr=None): |
paul@663 | 718 | |
paul@663 | 719 | # Handle deletion. |
paul@663 | 720 | |
paul@663 | 721 | if compiler.ast.is_deletion(node): |
paul@663 | 722 | return compiler.ast.Stmt([]) |
paul@663 | 723 | |
paul@764 | 724 | return self._visitAttr(node, self.dispatch(node.expr), node.attrname, expr) |
paul@638 | 725 | |
paul@663 | 726 | def visitAssList(self, node, expr=None): |
paul@663 | 727 | |
paul@663 | 728 | # Handle deletion. |
paul@663 | 729 | |
paul@663 | 730 | if compiler.ast.is_deletion(compiler.ast.flatten_assignment(node)): |
paul@663 | 731 | return compiler.ast.Stmt([]) |
paul@663 | 732 | |
paul@638 | 733 | return compiler.ast.Stmt([ |
paul@638 | 734 | self.dispatch(n, compiler.ast.CallFunc( |
paul@671 | 735 | special_name("apply"), |
paul@671 | 736 | [module_attribute("operator", "getitem"), expr, i] |
paul@638 | 737 | )) |
paul@638 | 738 | for (i, n) in enumerate(node.nodes) |
paul@638 | 739 | ]) |
paul@638 | 740 | |
paul@663 | 741 | def visitAssName(self, node, expr=None): |
paul@663 | 742 | |
paul@663 | 743 | # Handle deletion. |
paul@663 | 744 | |
paul@663 | 745 | if compiler.ast.is_deletion(node): |
paul@663 | 746 | return compiler.ast.Stmt([]) |
paul@663 | 747 | |
paul@638 | 748 | unit = self.get_unit() |
paul@638 | 749 | |
paul@638 | 750 | # Generate appropriate name access operation. |
paul@645 | 751 | # NOTE: Should generate guards for attribute usage operations. |
paul@638 | 752 | |
paul@638 | 753 | scope = getattr(node, "_scope", None) |
paul@638 | 754 | if not scope: |
paul@638 | 755 | attr, scope, from_name = self.get_unit()._get_with_scope(node.name) |
paul@638 | 756 | |
paul@638 | 757 | if scope == "constant": |
paul@638 | 758 | return node |
paul@638 | 759 | else: |
paul@755 | 760 | return self.store_value(unit, scope, node.name, expr) |
paul@638 | 761 | |
paul@638 | 762 | visitAssTuple = visitAssList |
paul@638 | 763 | |
paul@764 | 764 | visitBitand = _visitBitBinary |
paul@638 | 765 | |
paul@764 | 766 | visitBitor = _visitBitBinary |
paul@638 | 767 | |
paul@764 | 768 | visitBitxor = _visitBitBinary |
paul@638 | 769 | |
paul@638 | 770 | def visitCallFunc(self, node): |
paul@679 | 771 | |
paul@679 | 772 | # Determine whether the invocation target is known. |
paul@679 | 773 | |
paul@679 | 774 | args = [self.dispatch(node.node)] + [self.dispatch(arg) for arg in node.args] |
paul@764 | 775 | return self._visitCallFunc(node.node, args, node.star_args, node.dstar_args) |
paul@679 | 776 | |
paul@764 | 777 | def _visitCallFunc(self, target, args, star_args=None, dstar_args=None): |
paul@741 | 778 | |
paul@741 | 779 | # Attribute information is only known for specific accessors. |
paul@741 | 780 | |
paul@741 | 781 | if isinstance(target, compiler.ast.AttributeAccessor): |
paul@741 | 782 | attr = target._attr |
paul@741 | 783 | else: |
paul@741 | 784 | attr = None |
paul@741 | 785 | |
paul@741 | 786 | if not attr or isinstance(attr, (Instance, UnresolvedName)): |
paul@679 | 787 | op = "apply" |
paul@679 | 788 | |
paul@679 | 789 | # Invocations with some knowledge available. |
paul@679 | 790 | |
paul@679 | 791 | else: |
paul@679 | 792 | context = attr.get_context() |
paul@679 | 793 | value = attr.get_value() |
paul@679 | 794 | |
paul@679 | 795 | # Class invocations. |
paul@679 | 796 | |
paul@679 | 797 | if isinstance(value, Class): |
paul@679 | 798 | op = "applyclass" |
paul@679 | 799 | if value: |
paul@679 | 800 | args[0] = quoted_ref(value) |
paul@679 | 801 | else: |
paul@679 | 802 | |
paul@679 | 803 | # Function invocations. |
paul@679 | 804 | |
paul@679 | 805 | if context is ReplaceableContext: |
paul@679 | 806 | op = "applyfunction" |
paul@679 | 807 | |
paul@679 | 808 | # Method invocations via classes. |
paul@679 | 809 | |
paul@679 | 810 | elif isinstance(context, Class) and value: |
paul@679 | 811 | op = "applystaticmethod" |
paul@757 | 812 | args[0] = quoted_ref(value) |
paul@757 | 813 | args.insert(1, quoted_ref(context)) |
paul@679 | 814 | |
paul@679 | 815 | # Plain method invocations. |
paul@679 | 816 | |
paul@679 | 817 | elif context: |
paul@679 | 818 | op = "applymethod" |
paul@679 | 819 | |
paul@679 | 820 | # Unknown invocations. |
paul@679 | 821 | |
paul@679 | 822 | else: |
paul@679 | 823 | op = "apply" |
paul@679 | 824 | |
paul@638 | 825 | return compiler.ast.CallFunc( |
paul@679 | 826 | special_name(op), |
paul@679 | 827 | args, |
paul@764 | 828 | star_args and self.dispatch(star_args), |
paul@764 | 829 | dstar_args and self.dispatch(dstar_args) |
paul@638 | 830 | ) |
paul@638 | 831 | |
paul@638 | 832 | def visitCompare(self, node): |
paul@638 | 833 | nodes = [] |
paul@638 | 834 | left = node.expr |
paul@638 | 835 | for op_name, right in node.ops: |
paul@670 | 836 | if op_name == "is": |
paul@670 | 837 | nodes.append( |
paul@670 | 838 | compiler.ast.CallFunc( |
paul@670 | 839 | special_name("__is__"), |
paul@670 | 840 | [self.dispatch(left), self.dispatch(right)] |
paul@670 | 841 | ) |
paul@638 | 842 | ) |
paul@670 | 843 | elif op_name == "is not": |
paul@670 | 844 | nodes.append( |
paul@670 | 845 | compiler.ast.CallFunc( |
paul@670 | 846 | special_name("__is_not__"), |
paul@670 | 847 | [self.dispatch(left), self.dispatch(right)] |
paul@670 | 848 | ) |
paul@670 | 849 | ) |
paul@670 | 850 | else: |
paul@670 | 851 | nodes.append( |
paul@670 | 852 | compiler.ast.CallFunc( |
paul@671 | 853 | special_name("apply"), |
paul@671 | 854 | [module_attribute("operator", operator_functions.get(op_name)), |
paul@671 | 855 | self.dispatch(left), self.dispatch(right)] |
paul@670 | 856 | ) |
paul@670 | 857 | ) |
paul@638 | 858 | left = right |
paul@638 | 859 | return compiler.ast.And(nodes) |
paul@638 | 860 | |
paul@638 | 861 | visitConst = NOP |
paul@638 | 862 | |
paul@638 | 863 | def visitDict(self, node): |
paul@638 | 864 | return compiler.ast.Dict([(self.dispatch(key), self.dispatch(value)) for (key, value) in node.items]) |
paul@638 | 865 | |
paul@638 | 866 | def visitDiv(self, node): |
paul@638 | 867 | return self._visitBinary(node) |
paul@638 | 868 | |
paul@741 | 869 | def visitExec(self, node): |
paul@741 | 870 | |
paul@741 | 871 | # NOTE: Return the statement for now. |
paul@741 | 872 | |
paul@741 | 873 | return node |
paul@741 | 874 | |
paul@638 | 875 | def visitFloorDiv(self, node): |
paul@638 | 876 | return self._visitBinary(node) |
paul@638 | 877 | |
paul@638 | 878 | def visitGetattr(self, node, expr=None): |
paul@764 | 879 | return self._visitAttr(node, self.dispatch(node.expr), node.attrname, expr) |
paul@645 | 880 | |
paul@638 | 881 | def visitGenExpr(self, node): |
paul@638 | 882 | return compiler.ast.GenExpr(self.dispatch(node.code)) |
paul@638 | 883 | |
paul@638 | 884 | def visitGenExprFor(self, node): |
paul@663 | 885 | expr = self.dispatch(node.iter) |
paul@638 | 886 | return compiler.ast.GenExprFor( |
paul@663 | 887 | self.dispatch(node.assign, expr), # NOTE: Needs to dispatch to AssName/AssTuple/AssList with an expression. |
paul@663 | 888 | expr, |
paul@638 | 889 | [self.dispatch(n) for n in node.ifs] |
paul@638 | 890 | ) |
paul@638 | 891 | |
paul@638 | 892 | def visitGenExprIf(self, node): |
paul@638 | 893 | return compiler.ast.GenExprIf(self.dispatch(node.test)) |
paul@638 | 894 | |
paul@638 | 895 | def visitGenExprInner(self, node): |
paul@638 | 896 | return compiler.ast.GenExprInner( |
paul@638 | 897 | self.dispatch(node.expr), |
paul@638 | 898 | [self.dispatch(n) for n in node.quals] |
paul@638 | 899 | ) |
paul@638 | 900 | |
paul@638 | 901 | def visitIfExp(self, node): |
paul@638 | 902 | return compiler.ast.IfExp( |
paul@638 | 903 | self.dispatch(node.then), |
paul@638 | 904 | self.dispatch(node.test), |
paul@638 | 905 | self.dispatch(node.else_) |
paul@638 | 906 | ) |
paul@638 | 907 | |
paul@638 | 908 | def visitInvert(self, node): |
paul@638 | 909 | return self._visitUnary(node) |
paul@638 | 910 | |
paul@638 | 911 | def visitKeyword(self, node): |
paul@638 | 912 | return compiler.ast.Keyword( |
paul@638 | 913 | node.name, |
paul@638 | 914 | self.dispatch(node.expr) |
paul@638 | 915 | ) |
paul@638 | 916 | |
paul@638 | 917 | def visitLambda(self, node): |
paul@638 | 918 | self.units.append(node.unit) |
paul@638 | 919 | |
paul@755 | 920 | # NOTE: Need to initialise any defaults. Lambdas should probably be |
paul@755 | 921 | # NOTE: expanded to be "real" function definitions. |
paul@748 | 922 | |
paul@638 | 923 | try: |
paul@638 | 924 | return compiler.ast.Lambda( |
paul@755 | 925 | node.argnames, |
paul@638 | 926 | [self.dispatch(n) for n in node.defaults], |
paul@638 | 927 | node.flags, |
paul@638 | 928 | self.dispatch(node.code) |
paul@638 | 929 | ) |
paul@638 | 930 | finally: |
paul@638 | 931 | self.units.pop() |
paul@638 | 932 | |
paul@638 | 933 | def visitLeftShift(self, node): |
paul@638 | 934 | return self._visitBinary(node) |
paul@638 | 935 | |
paul@638 | 936 | def visitList(self, node, expr=None): |
paul@638 | 937 | if expr: |
paul@638 | 938 | return self.visitAssList(node, expr) |
paul@638 | 939 | return compiler.ast.List([self.dispatch(n) for n in node.nodes]) |
paul@638 | 940 | |
paul@638 | 941 | def visitListComp(self, node): |
paul@663 | 942 | |
paul@663 | 943 | """ |
paul@663 | 944 | Convert from... |
paul@663 | 945 | |
paul@663 | 946 | [<expr> for <assign> in <list> [ for <assign> in <list> ]... [ if <test> ]... ] |
paul@663 | 947 | |
paul@663 | 948 | ...to... |
paul@663 | 949 | |
paul@663 | 950 | _out = [] |
paul@663 | 951 | ... |
paul@663 | 952 | """ |
paul@663 | 953 | |
paul@663 | 954 | unit = self.get_unit() |
paul@663 | 955 | temp = quoted_name(unit.temp_usage) |
paul@663 | 956 | unit.temp_usage += 1 |
paul@663 | 957 | |
paul@663 | 958 | return compiler.ast.Stmt([ |
paul@670 | 959 | # storetemp(_out, __builtins__.list()) |
paul@670 | 960 | compiler.ast.CallFunc(special_name("storetemp"), [ |
paul@663 | 961 | temp, |
paul@663 | 962 | compiler.ast.CallFunc( |
paul@671 | 963 | special_name("apply"), |
paul@671 | 964 | [module_attribute("__builtins__", "list")] |
paul@663 | 965 | ) |
paul@663 | 966 | ]), |
paul@663 | 967 | # ... |
paul@663 | 968 | self.dispatch(node.quals[0], temp, node.expr, node.quals[1:]) |
paul@663 | 969 | ]) |
paul@663 | 970 | |
paul@663 | 971 | def visitListCompFor(self, node, out_temp, expr, quals): |
paul@663 | 972 | |
paul@663 | 973 | """ |
paul@663 | 974 | Convert from... |
paul@663 | 975 | |
paul@663 | 976 | [<expr> for <assign> in <list> ...] |
paul@663 | 977 | |
paul@663 | 978 | ...to... |
paul@663 | 979 | |
paul@663 | 980 | _it = iter(<list>) |
paul@663 | 981 | while True: |
paul@663 | 982 | try: |
paul@663 | 983 | <assign> = _it.next() |
paul@663 | 984 | except StopIteration: |
paul@663 | 985 | break |
paul@663 | 986 | else: |
paul@663 | 987 | ... |
paul@663 | 988 | _out.append(<expr>) |
paul@663 | 989 | """ |
paul@663 | 990 | |
paul@663 | 991 | unit = self.get_unit() |
paul@663 | 992 | temp = quoted_name(unit.temp_usage) |
paul@663 | 993 | unit.temp_usage += 1 |
paul@663 | 994 | |
paul@663 | 995 | # Either generate more "for" or "if" constructs. |
paul@663 | 996 | |
paul@663 | 997 | if node.ifs or quals: |
paul@663 | 998 | nodes = node.ifs + quals |
paul@663 | 999 | body = self.dispatch(nodes[0], out_temp, expr, nodes[1:]) |
paul@663 | 1000 | |
paul@663 | 1001 | # Or generate the append statement. |
paul@663 | 1002 | |
paul@663 | 1003 | else: |
paul@663 | 1004 | body = self._visitListCompExpr(out_temp, expr) |
paul@663 | 1005 | |
paul@663 | 1006 | # Wrap the above body in the loop construct. |
paul@663 | 1007 | |
paul@663 | 1008 | return compiler.ast.Stmt([ |
paul@670 | 1009 | # storetemp(_it, __builtins__.iter(<list>)) |
paul@670 | 1010 | compiler.ast.CallFunc(special_name("storetemp"), [ |
paul@663 | 1011 | temp, |
paul@663 | 1012 | compiler.ast.CallFunc( |
paul@671 | 1013 | special_name("apply"), |
paul@671 | 1014 | [module_attribute("__builtins__", "iter"), self.dispatch(node.list)] |
paul@663 | 1015 | ) |
paul@663 | 1016 | ]), |
paul@663 | 1017 | # while True: ... |
paul@663 | 1018 | compiler.ast.While( |
paul@663 | 1019 | special_name("True"), |
paul@663 | 1020 | # try: ... |
paul@663 | 1021 | compiler.ast.TryExcept( |
paul@663 | 1022 | compiler.ast.Stmt([ |
paul@663 | 1023 | # <assign> = ... |
paul@663 | 1024 | self.dispatch(node.assign, |
paul@663 | 1025 | # _it.next() |
paul@663 | 1026 | compiler.ast.CallFunc( |
paul@670 | 1027 | compiler.ast.CallFunc(special_name("loadattrindex"), [ |
paul@670 | 1028 | compiler.ast.CallFunc(special_name("loadtemp"), [temp]), |
paul@663 | 1029 | special_name("next") |
paul@663 | 1030 | ]), |
paul@663 | 1031 | [] |
paul@663 | 1032 | ) |
paul@663 | 1033 | ) |
paul@663 | 1034 | ]), |
paul@663 | 1035 | # except StopIteration: ... |
paul@663 | 1036 | [(special_name("StopIteration"), None, compiler.ast.Stmt([compiler.ast.Break()]))], |
paul@663 | 1037 | # else: ... |
paul@663 | 1038 | body |
paul@663 | 1039 | ), |
paul@663 | 1040 | None |
paul@663 | 1041 | ) |
paul@663 | 1042 | ]) |
paul@663 | 1043 | |
paul@663 | 1044 | def visitListCompIf(self, node, out_temp, expr, quals): |
paul@663 | 1045 | |
paul@663 | 1046 | # Either generate more "for" or "if" constructs. |
paul@663 | 1047 | |
paul@663 | 1048 | if quals: |
paul@663 | 1049 | body = self.dispatch(quals[0], out_temp, expr, quals[1:]) |
paul@663 | 1050 | |
paul@663 | 1051 | # Or generate the append statement. |
paul@663 | 1052 | |
paul@663 | 1053 | else: |
paul@663 | 1054 | body = self._visitListCompExpr(out_temp, expr) |
paul@663 | 1055 | |
paul@663 | 1056 | return compiler.ast.If( |
paul@663 | 1057 | [(self.dispatch(node.test), body)], |
paul@663 | 1058 | None |
paul@638 | 1059 | ) |
paul@638 | 1060 | |
paul@663 | 1061 | def _visitListCompExpr(self, out_temp, expr): |
paul@663 | 1062 | |
paul@663 | 1063 | "To the 'out_temp' object, append the result of 'expr'." |
paul@638 | 1064 | |
paul@663 | 1065 | return compiler.ast.Stmt([ |
paul@663 | 1066 | # _out.append(<expr>) |
paul@663 | 1067 | compiler.ast.CallFunc( |
paul@670 | 1068 | compiler.ast.CallFunc(special_name("loadattrindex"), [ |
paul@670 | 1069 | compiler.ast.CallFunc(special_name("loadtemp"), [out_temp]), |
paul@663 | 1070 | special_name("append") |
paul@663 | 1071 | ]), |
paul@663 | 1072 | [self.dispatch(expr)] |
paul@663 | 1073 | ) |
paul@663 | 1074 | ]) |
paul@638 | 1075 | |
paul@638 | 1076 | def visitMod(self, node): |
paul@638 | 1077 | return self._visitBinary(node) |
paul@638 | 1078 | |
paul@638 | 1079 | def visitMul(self, node): |
paul@638 | 1080 | return self._visitBinary(node) |
paul@638 | 1081 | |
paul@638 | 1082 | def visitName(self, node, expr=None): |
paul@638 | 1083 | if expr: |
paul@638 | 1084 | return self.visitAssName(node, expr) |
paul@638 | 1085 | |
paul@638 | 1086 | unit = self.get_unit() |
paul@645 | 1087 | attr = node._attr |
paul@645 | 1088 | scope = node._scope |
paul@638 | 1089 | |
paul@638 | 1090 | # Generate appropriate name access operation. |
paul@638 | 1091 | |
paul@638 | 1092 | if scope == "constant": |
paul@638 | 1093 | return node |
paul@638 | 1094 | |
paul@645 | 1095 | # Function locals are referenced normally. |
paul@638 | 1096 | |
paul@645 | 1097 | elif scope == "local" and isinstance(unit, Function): |
paul@645 | 1098 | return node |
paul@638 | 1099 | |
paul@645 | 1100 | # Other attributes should already be resolved. |
paul@638 | 1101 | |
paul@663 | 1102 | elif attr is not None and not isinstance(attr, Instance): |
paul@664 | 1103 | if attr.is_constant(): |
paul@676 | 1104 | return constant_attribute(attr.parent, node.name) |
paul@664 | 1105 | else: |
paul@664 | 1106 | return compiler.ast.CallFunc( |
paul@670 | 1107 | special_name("loadattr"), |
paul@664 | 1108 | [quoted_ref(attr.parent), special_name(node.name)] |
paul@664 | 1109 | ) |
paul@638 | 1110 | |
paul@663 | 1111 | # Function globals are referenced via the module. |
paul@663 | 1112 | |
paul@663 | 1113 | elif scope == "global": |
paul@663 | 1114 | return compiler.ast.CallFunc( |
paul@670 | 1115 | special_name("loadattr"), |
paul@663 | 1116 | [quoted_ref(self.get_module()), special_name(node.name)] |
paul@663 | 1117 | ) |
paul@663 | 1118 | |
paul@645 | 1119 | # NOTE: Unknown attributes may arise because a class attribute has been |
paul@645 | 1120 | # NOTE: optimised away. |
paul@638 | 1121 | |
paul@638 | 1122 | else: |
paul@638 | 1123 | return compiler.ast.CallFunc( |
paul@670 | 1124 | special_name("loadunknown"), |
paul@638 | 1125 | [special_name(node.name)] |
paul@638 | 1126 | ) |
paul@638 | 1127 | |
paul@638 | 1128 | def visitNot(self, node): |
paul@638 | 1129 | return compiler.ast.Not(self.dispatch(node.expr)) |
paul@638 | 1130 | |
paul@638 | 1131 | def visitOr(self, node): |
paul@638 | 1132 | return compiler.ast.Or([self.dispatch(n) for n in node.nodes]) |
paul@638 | 1133 | |
paul@638 | 1134 | def visitPower(self, node): |
paul@638 | 1135 | return self._visitBinary(node) |
paul@638 | 1136 | |
paul@638 | 1137 | def visitRightShift(self, node): |
paul@638 | 1138 | return self._visitBinary(node) |
paul@638 | 1139 | |
paul@699 | 1140 | def visitSet(self, node): |
paul@699 | 1141 | return compiler.ast.Set([self.dispatch(n) for n in node.nodes]) |
paul@699 | 1142 | |
paul@638 | 1143 | def visitSlice(self, node, expr=None): |
paul@638 | 1144 | return compiler.ast.CallFunc( |
paul@671 | 1145 | special_name("apply"), |
paul@671 | 1146 | [module_attribute("operator", expr and "setslice" or "getslice"), |
paul@671 | 1147 | self.dispatch(node.expr), |
paul@671 | 1148 | node.lower and self.dispatch(node.lower), |
paul@671 | 1149 | node.upper and self.dispatch(node.upper)] |
paul@671 | 1150 | + (expr and [expr] or []) |
paul@638 | 1151 | ) |
paul@638 | 1152 | |
paul@638 | 1153 | def visitSliceobj(self, node): |
paul@675 | 1154 | return compiler.ast.CallFunc( |
paul@675 | 1155 | special_name("apply"), |
paul@675 | 1156 | [module_attribute("__builtins__", "slice")] |
paul@675 | 1157 | + [self.dispatch(n) for n in node.nodes] |
paul@675 | 1158 | ) |
paul@638 | 1159 | |
paul@638 | 1160 | def visitSub(self, node): |
paul@638 | 1161 | return self._visitBinary(node) |
paul@638 | 1162 | |
paul@638 | 1163 | def visitSubscript(self, node, expr=None): |
paul@638 | 1164 | return compiler.ast.CallFunc( |
paul@671 | 1165 | special_name("apply"), |
paul@671 | 1166 | [module_attribute("operator", expr and "setitem" or "getitem"), |
paul@671 | 1167 | self.dispatch(node.expr), |
paul@671 | 1168 | compiler.ast.Tuple([self.dispatch(sub) for sub in node.subs])] |
paul@671 | 1169 | + (expr and [expr] or []) |
paul@638 | 1170 | ) |
paul@638 | 1171 | |
paul@638 | 1172 | def visitTuple(self, node, expr=None): |
paul@638 | 1173 | if expr: |
paul@638 | 1174 | return self.visitAssTuple(node, expr) |
paul@638 | 1175 | return compiler.ast.Tuple([self.dispatch(n) for n in node.nodes]) |
paul@638 | 1176 | |
paul@638 | 1177 | def visitUnaryAdd(self, node): |
paul@638 | 1178 | return self._visitUnary(node) |
paul@638 | 1179 | |
paul@638 | 1180 | def visitUnarySub(self, node): |
paul@638 | 1181 | return self._visitUnary(node) |
paul@638 | 1182 | |
paul@741 | 1183 | def visitWith(self, node): |
paul@741 | 1184 | |
paul@741 | 1185 | """ |
paul@741 | 1186 | Convert from... |
paul@741 | 1187 | |
paul@741 | 1188 | with <expr> as <var>: |
paul@741 | 1189 | ... |
paul@741 | 1190 | |
paul@741 | 1191 | ...to... |
paul@741 | 1192 | |
paul@741 | 1193 | _manager = <var> = <expr> # <var> may be absent |
paul@741 | 1194 | _exit = _manager.__exit__ |
paul@741 | 1195 | _manager.__enter__() |
paul@741 | 1196 | try: |
paul@741 | 1197 | ... |
paul@741 | 1198 | except Exception, exc: |
paul@741 | 1199 | if not _exit(exc.type, exc.value, exc.tb): |
paul@741 | 1200 | raise |
paul@741 | 1201 | else: |
paul@741 | 1202 | _exit(None, None, None) |
paul@741 | 1203 | """ |
paul@741 | 1204 | |
paul@741 | 1205 | # NOTE: For now, not adding this exuberance to the output. |
paul@741 | 1206 | |
paul@741 | 1207 | return node |
paul@741 | 1208 | |
paul@638 | 1209 | # Convenience functions. |
paul@638 | 1210 | |
paul@638 | 1211 | def convert(module, program, filename): |
paul@638 | 1212 | stream = open(filename, "wb") |
paul@638 | 1213 | try: |
paul@638 | 1214 | source = ConvertedSource(module, program) |
paul@638 | 1215 | source.to_stream(stream) |
paul@638 | 1216 | finally: |
paul@638 | 1217 | stream.close() |
paul@638 | 1218 | |
paul@638 | 1219 | def translate(program, directory): |
paul@638 | 1220 | if not exists(directory): |
paul@638 | 1221 | os.mkdir(directory) |
paul@638 | 1222 | |
paul@638 | 1223 | # NOTE: Add constants here. |
paul@638 | 1224 | |
paul@638 | 1225 | for module in program.get_importer().get_modules(): |
paul@638 | 1226 | convert(module, program, join(directory, "%s%spy" % (module.full_name(), extsep))) |
paul@638 | 1227 | |
paul@638 | 1228 | # vim: tabstop=4 expandtab shiftwidth=4 |