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@638 | 26 | import compiler.ast |
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 | module_attribute = compiler.ast.Getattr |
paul@638 | 38 | special_name = compiler.ast.Name |
paul@645 | 39 | |
paul@645 | 40 | def quoted_ref(obj): |
paul@645 | 41 | return compiler.ast.CallFunc("__static__", [compiler.ast.Const(obj.full_name())]) |
paul@645 | 42 | |
paul@645 | 43 | def quoted_name(s): |
paul@645 | 44 | return compiler.ast.Const(s) |
paul@638 | 45 | |
paul@638 | 46 | # Source code classes. |
paul@638 | 47 | |
paul@638 | 48 | class ConvertedSource(ASTVisitor): |
paul@638 | 49 | |
paul@638 | 50 | "A conversion of module source code to syspython." |
paul@638 | 51 | |
paul@638 | 52 | def __init__(self, module, program): |
paul@638 | 53 | self.visitor = self |
paul@638 | 54 | self.module = module |
paul@638 | 55 | self.program = program |
paul@645 | 56 | self.objtable = program.get_object_table() |
paul@638 | 57 | self.in_main = False |
paul@638 | 58 | self.units = [] |
paul@638 | 59 | |
paul@638 | 60 | def get_unit(self): |
paul@638 | 61 | return self.units[-1] |
paul@638 | 62 | |
paul@638 | 63 | def get_module(self): |
paul@638 | 64 | return self.units[0] |
paul@638 | 65 | |
paul@638 | 66 | def to_stream(self, stream): |
paul@638 | 67 | |
paul@638 | 68 | "Write the converted code to the given 'stream'." |
paul@638 | 69 | |
paul@638 | 70 | module = self.dispatch(self.module.astnode) |
paul@638 | 71 | stream.write(str(module)) |
paul@638 | 72 | |
paul@638 | 73 | def NOP(self, node): |
paul@638 | 74 | return node |
paul@638 | 75 | |
paul@638 | 76 | def visitModule(self, node): |
paul@638 | 77 | module = node.unit |
paul@638 | 78 | self.units.append(module) |
paul@638 | 79 | |
paul@645 | 80 | definitions = self.process_definitions(node) |
paul@638 | 81 | |
paul@638 | 82 | # __globalnames__(name, ...) |
paul@638 | 83 | |
paul@638 | 84 | globalnames = module.module_attribute_names() and [ |
paul@638 | 85 | compiler.ast.CallFunc( |
paul@638 | 86 | special_name("__globalnames__"), |
paul@638 | 87 | [special_name(name) for name in module.module_attribute_names()] |
paul@638 | 88 | ) |
paul@638 | 89 | ] or [] |
paul@638 | 90 | |
paul@638 | 91 | # def __main__(): |
paul@638 | 92 | # ... |
paul@638 | 93 | |
paul@638 | 94 | self.in_main = True |
paul@638 | 95 | |
paul@638 | 96 | main = compiler.ast.Function( |
paul@638 | 97 | [], "__main__", [], [], 0, "Module initialisation.", |
paul@638 | 98 | compiler.ast.Stmt(globalnames + self.dispatch(node.node).nodes) |
paul@638 | 99 | ) |
paul@638 | 100 | |
paul@638 | 101 | self.in_main = False |
paul@638 | 102 | self.units.pop() |
paul@638 | 103 | |
paul@638 | 104 | return compiler.ast.Module(node.doc, compiler.ast.Stmt(definitions + [main])) |
paul@638 | 105 | |
paul@638 | 106 | # Statements. |
paul@638 | 107 | |
paul@638 | 108 | def visitAssert(self, node): |
paul@638 | 109 | return compiler.ast.Assert(self.dispatch(node.test), node.fail and self.dispatch(node.fail)) |
paul@638 | 110 | |
paul@638 | 111 | def visitAssign(self, node): |
paul@638 | 112 | expr = self.dispatch(node.expr) |
paul@638 | 113 | return compiler.ast.Stmt([self.dispatch(n, expr) for n in node.nodes]) |
paul@638 | 114 | |
paul@638 | 115 | def visitAugAssign(self, node): |
paul@638 | 116 | |
paul@638 | 117 | # lvalue = op(lvalue, expr) |
paul@638 | 118 | # -> __fn__(lvalue, op(lvalue, expr)) |
paul@638 | 119 | |
paul@638 | 120 | op_name = operator_functions[node.op] |
paul@638 | 121 | |
paul@638 | 122 | return self.dispatch(node.node, compiler.ast.CallFunc( |
paul@638 | 123 | module_attribute("operator", op_name), |
paul@638 | 124 | [self.dispatch(node.node), self.dispatch(node.expr)] |
paul@638 | 125 | )) |
paul@638 | 126 | |
paul@638 | 127 | visitBreak = NOP |
paul@638 | 128 | |
paul@638 | 129 | def visitClass(self, node): |
paul@638 | 130 | if not used_by_unit(node): |
paul@638 | 131 | return compiler.ast.Stmt([]) |
paul@638 | 132 | |
paul@638 | 133 | self.units.append(node.unit) |
paul@638 | 134 | try: |
paul@638 | 135 | # Incorporate class body code in the main function. |
paul@638 | 136 | |
paul@638 | 137 | if self.in_main: |
paul@638 | 138 | return self.dispatch(node.code) |
paul@638 | 139 | else: |
paul@638 | 140 | return self._visitClassDefinition(node) |
paul@638 | 141 | |
paul@638 | 142 | finally: |
paul@638 | 143 | self.units.pop() |
paul@638 | 144 | |
paul@638 | 145 | def _visitClassDefinition(self, node): |
paul@638 | 146 | cls = node.unit |
paul@638 | 147 | |
paul@638 | 148 | # __instattrs__(name, ...) |
paul@638 | 149 | # __clsattrs__(name, ...) |
paul@638 | 150 | |
paul@638 | 151 | instattrs = cls.instance_attribute_names() and [ |
paul@638 | 152 | compiler.ast.CallFunc( |
paul@638 | 153 | special_name("__instattrs__"), |
paul@638 | 154 | [special_name(name) for name in cls.instance_attribute_names()] |
paul@638 | 155 | ) |
paul@638 | 156 | ] or [] |
paul@638 | 157 | |
paul@638 | 158 | clsattrs = cls.class_attribute_names() and [ |
paul@638 | 159 | compiler.ast.CallFunc( |
paul@638 | 160 | special_name("__clsattrs__"), |
paul@638 | 161 | [special_name(name) for name in cls.class_attribute_names()] |
paul@638 | 162 | ) |
paul@638 | 163 | ] or [] |
paul@638 | 164 | |
paul@638 | 165 | # __inherited__(superclass, name, ...) |
paul@638 | 166 | # ... |
paul@638 | 167 | |
paul@638 | 168 | attrs_by_cls = {} |
paul@638 | 169 | for attrname, attr in cls.all_class_attributes().items(): |
paul@638 | 170 | supercls = attr.parent |
paul@638 | 171 | if supercls is cls: |
paul@638 | 172 | continue |
paul@638 | 173 | if not attrs_by_cls.has_key(supercls): |
paul@638 | 174 | attrs_by_cls[supercls] = [] |
paul@638 | 175 | attrs_by_cls[supercls].append(attrname) |
paul@638 | 176 | |
paul@638 | 177 | inherited = [] |
paul@638 | 178 | |
paul@638 | 179 | for supercls, attrnames in attrs_by_cls.items(): |
paul@638 | 180 | inherited.append( |
paul@638 | 181 | compiler.ast.CallFunc( |
paul@638 | 182 | special_name("__inherited__"), |
paul@645 | 183 | [quoted_ref(supercls)] + [special_name(name) for name in attrnames] |
paul@638 | 184 | )) |
paul@638 | 185 | |
paul@638 | 186 | # __descendants__(name, ...) |
paul@638 | 187 | |
paul@638 | 188 | descendants = cls.all_descendants() and [ |
paul@638 | 189 | compiler.ast.CallFunc( |
paul@638 | 190 | special_name("__descendants__"), |
paul@638 | 191 | [special_name(name) for name in cls.all_descendants().keys()] |
paul@638 | 192 | ) |
paul@638 | 193 | ] or [] |
paul@638 | 194 | |
paul@638 | 195 | # Process all the definitions defined inside the class. |
paul@638 | 196 | |
paul@645 | 197 | definitions = self.process_definitions(node) |
paul@638 | 198 | |
paul@638 | 199 | return compiler.ast.Class(node.name, [], node.doc, |
paul@638 | 200 | compiler.ast.Stmt(instattrs + clsattrs + inherited + descendants + definitions) |
paul@638 | 201 | ) |
paul@638 | 202 | |
paul@638 | 203 | visitContinue = NOP |
paul@638 | 204 | |
paul@638 | 205 | def visitDiscard(self, node): |
paul@638 | 206 | return compiler.ast.Discard(self.dispatch(node.expr)) |
paul@638 | 207 | |
paul@638 | 208 | def visitFor(self, node): |
paul@638 | 209 | |
paul@638 | 210 | """ |
paul@638 | 211 | Convert from... |
paul@638 | 212 | |
paul@638 | 213 | for <assign> in <list>: |
paul@638 | 214 | <body> |
paul@638 | 215 | [ else: |
paul@638 | 216 | <else_> ] |
paul@638 | 217 | |
paul@638 | 218 | ...to... |
paul@638 | 219 | |
paul@638 | 220 | _it = iter(<list>) |
paul@638 | 221 | while True: |
paul@638 | 222 | try: |
paul@638 | 223 | <assign> = _it.next() |
paul@638 | 224 | except StopIteration: |
paul@638 | 225 | [ <else_> ] |
paul@638 | 226 | break |
paul@638 | 227 | else: |
paul@638 | 228 | <body> |
paul@638 | 229 | """ |
paul@638 | 230 | |
paul@638 | 231 | unit = self.get_unit() |
paul@638 | 232 | temp = quoted_name(unit.temp_usage) |
paul@638 | 233 | unit.temp_usage += 1 |
paul@638 | 234 | |
paul@638 | 235 | else_nodes = node.else_ and self.dispatch(node.else_).nodes or [] |
paul@638 | 236 | |
paul@638 | 237 | return compiler.ast.Stmt([ |
paul@645 | 238 | # __storetemp__(_it, __loadattr__(__builtins__, iter)(<list>)) |
paul@638 | 239 | compiler.ast.CallFunc(special_name("__storetemp__"), [ |
paul@638 | 240 | temp, |
paul@638 | 241 | compiler.ast.CallFunc( |
paul@645 | 242 | compiler.ast.CallFunc(special_name("__loadattr__"), |
paul@638 | 243 | [special_name("__builtins__"), special_name("iter")] |
paul@638 | 244 | ), |
paul@638 | 245 | [self.dispatch(node.list)] |
paul@638 | 246 | ) |
paul@638 | 247 | ]), |
paul@638 | 248 | # while True: ... |
paul@638 | 249 | compiler.ast.While( |
paul@638 | 250 | special_name("True"), |
paul@638 | 251 | # try: ... |
paul@638 | 252 | compiler.ast.TryExcept( |
paul@638 | 253 | compiler.ast.Stmt([ |
paul@638 | 254 | # <assign> = ... |
paul@638 | 255 | self.dispatch(node.assign, |
paul@638 | 256 | # _it.next() |
paul@638 | 257 | compiler.ast.CallFunc( |
paul@638 | 258 | compiler.ast.CallFunc(special_name("__loadattr__"), [ |
paul@638 | 259 | compiler.ast.CallFunc(special_name("__loadtemp__"), [temp]), |
paul@638 | 260 | special_name("next") |
paul@638 | 261 | ]), |
paul@638 | 262 | [] |
paul@638 | 263 | ) |
paul@638 | 264 | ) |
paul@638 | 265 | ]), |
paul@638 | 266 | # except StopIteration: ... |
paul@638 | 267 | [(special_name("StopIteration"), None, compiler.ast.Stmt(else_nodes + [compiler.ast.Break()]))], |
paul@638 | 268 | # else: ... |
paul@638 | 269 | self.dispatch(node.body) |
paul@638 | 270 | ), |
paul@638 | 271 | None |
paul@638 | 272 | ) |
paul@638 | 273 | ]) |
paul@638 | 274 | |
paul@638 | 275 | def visitFrom(self, node): |
paul@638 | 276 | |
paul@638 | 277 | # Generate __main__ function calls for each step in the imported module |
paul@638 | 278 | # hierarchy. |
paul@638 | 279 | |
paul@638 | 280 | statements = [] |
paul@638 | 281 | |
paul@638 | 282 | for modname in self.module.get_module_paths(node.modname): |
paul@638 | 283 | statements.append( |
paul@638 | 284 | compiler.ast.CallFunc(special_name("%s.__main__" % modname ), []) |
paul@638 | 285 | ) |
paul@638 | 286 | |
paul@638 | 287 | for name, alias in node.names: |
paul@638 | 288 | statements.append( |
paul@638 | 289 | compiler.ast.Assign( |
paul@638 | 290 | [special_name(alias or name)], |
paul@638 | 291 | compiler.ast.CallFunc( |
paul@638 | 292 | special_name("__loadattribute__"), |
paul@638 | 293 | [special_name(node.modname), special_name(name)] |
paul@638 | 294 | ) |
paul@638 | 295 | ) |
paul@638 | 296 | ) |
paul@638 | 297 | |
paul@638 | 298 | return compiler.ast.Stmt(statements) |
paul@638 | 299 | |
paul@638 | 300 | def visitFunction(self, node): |
paul@638 | 301 | if not used_by_unit(node): |
paul@638 | 302 | return compiler.ast.Stmt([]) |
paul@638 | 303 | |
paul@638 | 304 | self.units.append(node.unit) |
paul@638 | 305 | |
paul@638 | 306 | try: |
paul@638 | 307 | # Ignore functions when generating the main function. |
paul@638 | 308 | |
paul@638 | 309 | if self.in_main: |
paul@638 | 310 | return compiler.ast.Stmt([]) |
paul@638 | 311 | else: |
paul@638 | 312 | return self._visitFunctionDefinition(node) |
paul@638 | 313 | finally: |
paul@638 | 314 | self.units.pop() |
paul@638 | 315 | |
paul@638 | 316 | def _visitFunctionDefinition(self, node): |
paul@638 | 317 | fn = node.unit |
paul@638 | 318 | |
paul@638 | 319 | # __localnames__(name, ...) |
paul@638 | 320 | # __globalnames__(name, ...) |
paul@638 | 321 | |
paul@645 | 322 | localnames = fn.all_locals() and [ |
paul@638 | 323 | compiler.ast.CallFunc( |
paul@638 | 324 | special_name("__localnames__"), |
paul@645 | 325 | [special_name(name) for name in fn.all_locals().keys()] |
paul@638 | 326 | ) |
paul@638 | 327 | ] or [] |
paul@638 | 328 | |
paul@638 | 329 | globalnames = fn.globals and [ |
paul@638 | 330 | compiler.ast.CallFunc( |
paul@638 | 331 | special_name("__globalnames__"), |
paul@638 | 332 | [special_name(name) for name in fn.globals] |
paul@638 | 333 | ) |
paul@638 | 334 | ] or [] |
paul@638 | 335 | |
paul@638 | 336 | defaults = [self.dispatch(n) for n in node.defaults] |
paul@638 | 337 | |
paul@645 | 338 | # NOTE: Should generate guards for attribute usage operations. |
paul@645 | 339 | |
paul@638 | 340 | code = self.dispatch(node.code) |
paul@638 | 341 | |
paul@638 | 342 | return compiler.ast.Function(node.decorators, node.name, node.argnames, defaults, node.flags, node.doc, |
paul@638 | 343 | compiler.ast.Stmt(localnames + globalnames + code.nodes)) |
paul@638 | 344 | |
paul@638 | 345 | visitGlobal = NOP |
paul@638 | 346 | |
paul@638 | 347 | def visitIf(self, node): |
paul@638 | 348 | return compiler.ast.If( |
paul@638 | 349 | [(self.dispatch(compare), self.dispatch(stmt)) for (compare, stmt) in node.tests], |
paul@638 | 350 | node.else_ and self.dispatch(node.else_) |
paul@638 | 351 | ) |
paul@638 | 352 | |
paul@638 | 353 | def visitImport(self, node): |
paul@638 | 354 | |
paul@638 | 355 | # Generate __main__ function calls for each step in the imported module |
paul@638 | 356 | # hierarchy. |
paul@638 | 357 | |
paul@638 | 358 | statements = [] |
paul@638 | 359 | |
paul@638 | 360 | for name, alias in node.names: |
paul@638 | 361 | for modname in self.module.get_module_paths(name): |
paul@638 | 362 | statements.append( |
paul@638 | 363 | compiler.ast.CallFunc(compiler.ast.Getattr(modname, "__main__"), []) |
paul@638 | 364 | ) |
paul@638 | 365 | |
paul@638 | 366 | statements.append( |
paul@638 | 367 | compiler.ast.Assign( |
paul@638 | 368 | [special_name(alias or name.split(".")[0])], |
paul@638 | 369 | compiler.ast.CallFunc( |
paul@638 | 370 | special_name("__static__"), |
paul@638 | 371 | [special_name(name)] |
paul@638 | 372 | ) |
paul@638 | 373 | ) |
paul@638 | 374 | ) |
paul@638 | 375 | |
paul@638 | 376 | return compiler.ast.Stmt(statements) |
paul@638 | 377 | |
paul@645 | 378 | def visitPass(self, node): |
paul@645 | 379 | if not isinstance(self.get_unit(), Class): |
paul@645 | 380 | return compiler.ast.Pass() |
paul@645 | 381 | else: |
paul@645 | 382 | return compiler.ast.Stmt([]) |
paul@638 | 383 | |
paul@638 | 384 | def visitPrint(self, node): |
paul@638 | 385 | return compiler.ast.Print( |
paul@638 | 386 | [self.dispatch(n) for n in node.nodes], |
paul@638 | 387 | node.dest and self.dispatch(node.dest) |
paul@638 | 388 | ) |
paul@638 | 389 | |
paul@638 | 390 | def visitPrintnl(self, node): |
paul@638 | 391 | return compiler.ast.Print( |
paul@638 | 392 | [self.dispatch(n) for n in node.nodes], |
paul@638 | 393 | node.dest and self.dispatch(node.dest) |
paul@638 | 394 | ) |
paul@638 | 395 | |
paul@638 | 396 | def visitRaise(self, node): |
paul@638 | 397 | return compiler.ast.Raise( |
paul@638 | 398 | node.expr1 and self.dispatch(node.expr1), |
paul@638 | 399 | node.expr2 and self.dispatch(node.expr2), |
paul@638 | 400 | node.expr3 and self.dispatch(node.expr3) |
paul@638 | 401 | ) |
paul@638 | 402 | |
paul@638 | 403 | def visitReturn(self, node): |
paul@638 | 404 | return compiler.ast.Return(self.dispatch(node.value)) |
paul@638 | 405 | |
paul@638 | 406 | def visitStmt(self, node): |
paul@638 | 407 | return compiler.ast.Stmt([self.dispatch(n) for n in node.nodes]) |
paul@638 | 408 | |
paul@638 | 409 | def visitTryExcept(self, node): |
paul@638 | 410 | # NOTE: Need to dispatch to the assignment with the exception. |
paul@638 | 411 | return compiler.ast.TryExcept( |
paul@638 | 412 | self.dispatch(node.body), |
paul@638 | 413 | [(spec and self.dispatch(spec), assign and self.dispatch(assign), self.dispatch(statement)) |
paul@638 | 414 | for spec, assign, statement in node.handlers], |
paul@638 | 415 | node.else_ and self.dispatch(node.else_) |
paul@638 | 416 | ) |
paul@638 | 417 | |
paul@638 | 418 | def visitTryFinally(self, node): |
paul@638 | 419 | return compiler.ast.TryFinally( |
paul@638 | 420 | self.dispatch(node.body), |
paul@638 | 421 | self.dispatch(node.final) |
paul@638 | 422 | ) |
paul@638 | 423 | |
paul@638 | 424 | def visitWhile(self, node): |
paul@638 | 425 | return compiler.ast.While( |
paul@638 | 426 | self.dispatch(node.test), |
paul@638 | 427 | self.dispatch(node.body), |
paul@638 | 428 | node.else_ and self.dispatch(node.else_) |
paul@638 | 429 | ) |
paul@638 | 430 | |
paul@638 | 431 | def visitYield(self, node): |
paul@638 | 432 | return compiler.ast.Yield(self.dispatch(node.value)) |
paul@638 | 433 | |
paul@638 | 434 | # Expression-related helper methods. |
paul@638 | 435 | |
paul@638 | 436 | def _visitBitBinary(self, node): |
paul@638 | 437 | op_name = operator_functions[node.__class__.__name__] |
paul@638 | 438 | last = self.dispatch(node.nodes[0]) |
paul@638 | 439 | |
paul@638 | 440 | for n in node.nodes[1:]: |
paul@638 | 441 | last = compiler.ast.CallFunc( |
paul@638 | 442 | module_attribute("operator", op_name), |
paul@638 | 443 | [last, self.dispatch(n)] |
paul@638 | 444 | ) |
paul@638 | 445 | |
paul@638 | 446 | return last |
paul@638 | 447 | |
paul@638 | 448 | def _visitBinary(self, node): |
paul@638 | 449 | op_name = operator_functions[node.__class__.__name__] |
paul@638 | 450 | |
paul@638 | 451 | return compiler.ast.CallFunc( |
paul@638 | 452 | module_attribute("operator", op_name), |
paul@638 | 453 | [self.dispatch(node.left), self.dispatch(node.right)] |
paul@638 | 454 | ) |
paul@638 | 455 | |
paul@638 | 456 | def _visitUnary(self, node): |
paul@638 | 457 | op_name = operator_functions[node.__class__.__name__] |
paul@638 | 458 | |
paul@638 | 459 | return compiler.ast.CallFunc( |
paul@638 | 460 | module_attribute("operator", op_name), |
paul@638 | 461 | [self.dispatch(node.expr)] |
paul@638 | 462 | ) |
paul@638 | 463 | |
paul@645 | 464 | def _generateValue(self, value): |
paul@645 | 465 | |
paul@645 | 466 | # Literal constants. |
paul@645 | 467 | |
paul@645 | 468 | if isinstance(value, Const): |
paul@645 | 469 | return compiler.ast.Const(value.get_value()) |
paul@645 | 470 | |
paul@645 | 471 | # Other constant structures. |
paul@645 | 472 | |
paul@645 | 473 | if isinstance(value, Constant): |
paul@645 | 474 | return quoted_ref(value) |
paul@645 | 475 | |
paul@645 | 476 | return None |
paul@645 | 477 | |
paul@638 | 478 | # Expressions. |
paul@638 | 479 | |
paul@638 | 480 | def visitAdd(self, node): |
paul@638 | 481 | return self._visitBinary(node) |
paul@638 | 482 | |
paul@638 | 483 | def visitAnd(self, node): |
paul@638 | 484 | return compiler.ast.And([self.dispatch(n) for n in node.nodes]) |
paul@638 | 485 | |
paul@638 | 486 | def visitAssAttr(self, node, expr): |
paul@638 | 487 | |
paul@638 | 488 | # NOTE: Derived from Getattr support. |
paul@638 | 489 | |
paul@638 | 490 | accessor = self.dispatch(node.expr) |
paul@638 | 491 | |
paul@638 | 492 | # NOTE: Replicate the _generateAttr logic. |
paul@638 | 493 | # NOTE: Should be able to store concrete value details on generated |
paul@638 | 494 | # NOTE: nodes, such as whether an expression yields a constant. |
paul@638 | 495 | |
paul@638 | 496 | # NOTE: Known targets: |
paul@645 | 497 | # NOTE: __storeattr__ and __storeattrcontext__ |
paul@638 | 498 | |
paul@638 | 499 | # NOTE: Attributes of self. |
paul@638 | 500 | |
paul@638 | 501 | # Usage observations. |
paul@638 | 502 | |
paul@645 | 503 | targets = self.possible_accessors_from_usage(node, defining_users=0) |
paul@638 | 504 | |
paul@638 | 505 | # Record whether types were already deduced. If not, get types using |
paul@638 | 506 | # only this attribute. |
paul@638 | 507 | |
paul@645 | 508 | if not targets: |
paul@645 | 509 | targets = self.possible_accessors_for_attribute(node.attrname) |
paul@638 | 510 | |
paul@645 | 511 | attrs = self.get_attributes(targets, node.attrname) |
paul@638 | 512 | |
paul@638 | 513 | # Generate optimisations where only a single attribute applies. |
paul@638 | 514 | |
paul@645 | 515 | if len(attrs) == 1: |
paul@645 | 516 | attr = attrs[0] |
paul@638 | 517 | |
paul@638 | 518 | # Static attributes. |
paul@638 | 519 | |
paul@645 | 520 | if attr.is_static_attribute(): |
paul@638 | 521 | |
paul@638 | 522 | # Static attributes may be accompanied by a different context |
paul@638 | 523 | # depending on the accessor. |
paul@638 | 524 | # NOTE: Should determine whether the context is always replaced. |
paul@638 | 525 | |
paul@638 | 526 | return compiler.ast.CallFunc( |
paul@645 | 527 | special_name("__storeattrcontextcond__"), |
paul@638 | 528 | [accessor, special_name(node.attrname), expr] |
paul@638 | 529 | ) |
paul@638 | 530 | |
paul@638 | 531 | # Non-static attributes. |
paul@638 | 532 | |
paul@638 | 533 | return compiler.ast.CallFunc( |
paul@638 | 534 | special_name("__storeattr__"), |
paul@638 | 535 | [accessor, special_name(node.attrname), expr] |
paul@638 | 536 | ) |
paul@638 | 537 | |
paul@638 | 538 | # With no usable deductions, generate a table-based access. |
paul@638 | 539 | |
paul@638 | 540 | return compiler.ast.CallFunc( |
paul@638 | 541 | special_name("__storeattrindex__"), |
paul@638 | 542 | [accessor, special_name(node.attrname), expr] |
paul@638 | 543 | ) |
paul@638 | 544 | |
paul@638 | 545 | def visitAssList(self, node, expr): |
paul@638 | 546 | return compiler.ast.Stmt([ |
paul@638 | 547 | self.dispatch(n, compiler.ast.CallFunc( |
paul@638 | 548 | module_attribute("operator", "getitem"), |
paul@638 | 549 | [expr, i] |
paul@638 | 550 | )) |
paul@638 | 551 | for (i, n) in enumerate(node.nodes) |
paul@638 | 552 | ]) |
paul@638 | 553 | |
paul@638 | 554 | def visitAssName(self, node, expr): |
paul@638 | 555 | unit = self.get_unit() |
paul@638 | 556 | |
paul@638 | 557 | # Generate appropriate name access operation. |
paul@645 | 558 | # NOTE: Should generate guards for attribute usage operations. |
paul@638 | 559 | |
paul@638 | 560 | scope = getattr(node, "_scope", None) |
paul@638 | 561 | if not scope: |
paul@638 | 562 | attr, scope, from_name = self.get_unit()._get_with_scope(node.name) |
paul@638 | 563 | |
paul@638 | 564 | if scope == "constant": |
paul@638 | 565 | return node |
paul@638 | 566 | elif scope == "local": |
paul@638 | 567 | |
paul@638 | 568 | # Function locals are stored using a function. |
paul@638 | 569 | |
paul@638 | 570 | if isinstance(unit, Function): |
paul@638 | 571 | return compiler.ast.CallFunc( |
paul@638 | 572 | special_name("__storelocal__"), |
paul@638 | 573 | [special_name(node.name), expr] |
paul@638 | 574 | ) |
paul@638 | 575 | |
paul@638 | 576 | # Class locals are class attribute references. |
paul@638 | 577 | |
paul@638 | 578 | elif isinstance(unit, Class): |
paul@638 | 579 | return compiler.ast.CallFunc( |
paul@645 | 580 | special_name("__storeattrcontext__"), |
paul@645 | 581 | [quoted_ref(unit), special_name(node.name), expr] |
paul@638 | 582 | ) |
paul@638 | 583 | |
paul@638 | 584 | # Module locals are module attribute references. |
paul@638 | 585 | |
paul@638 | 586 | elif isinstance(unit, Module): |
paul@638 | 587 | return compiler.ast.CallFunc( |
paul@645 | 588 | special_name("__storeattr__"), |
paul@645 | 589 | [quoted_ref(unit), special_name(node.name), expr] |
paul@638 | 590 | ) |
paul@638 | 591 | else: |
paul@638 | 592 | raise TranslateError("Program unit has no local %r." % name) |
paul@638 | 593 | |
paul@638 | 594 | elif scope == "global": |
paul@638 | 595 | |
paul@638 | 596 | # Globals are references to module attributes. |
paul@638 | 597 | |
paul@638 | 598 | return compiler.ast.CallFunc( |
paul@645 | 599 | special_name("__storeattr__"), |
paul@645 | 600 | [quoted_ref(self.get_module()), special_name(node.name), expr] |
paul@638 | 601 | ) |
paul@638 | 602 | |
paul@638 | 603 | elif scope == "builtin": |
paul@638 | 604 | |
paul@638 | 605 | # Builtins are accessed via the __builtins__ module. |
paul@638 | 606 | |
paul@638 | 607 | return compiler.ast.CallFunc( |
paul@645 | 608 | special_name("__storeattr__"), |
paul@638 | 609 | [special_name("__builtins__"), special_name(node.name), expr] |
paul@638 | 610 | ) |
paul@638 | 611 | |
paul@638 | 612 | else: |
paul@638 | 613 | # NOTE: This may happen because a class attribute is optimised away. |
paul@638 | 614 | return compiler.ast.CallFunc( |
paul@638 | 615 | special_name("__storeunknown__"), |
paul@638 | 616 | [special_name(node.name), expr] |
paul@638 | 617 | ) |
paul@638 | 618 | |
paul@638 | 619 | visitAssTuple = visitAssList |
paul@638 | 620 | |
paul@638 | 621 | def visitBitand(self, node): |
paul@638 | 622 | self._visitBitBinary(node) |
paul@638 | 623 | |
paul@638 | 624 | def visitBitor(self, node): |
paul@638 | 625 | self._visitBitBinary(node) |
paul@638 | 626 | |
paul@638 | 627 | def visitBitxor(self, node): |
paul@638 | 628 | self._visitBitBinary(node) |
paul@638 | 629 | |
paul@638 | 630 | def visitCallFunc(self, node): |
paul@638 | 631 | return compiler.ast.CallFunc( |
paul@638 | 632 | self.dispatch(node.node), |
paul@638 | 633 | [self.dispatch(arg) for arg in node.args], |
paul@638 | 634 | node.star_args and [self.dispatch(arg) for arg in node.star_args], |
paul@638 | 635 | node.dstar_args and [self.dispatch(arg) for arg in node.dstar_args] |
paul@638 | 636 | ) |
paul@638 | 637 | |
paul@638 | 638 | def visitCompare(self, node): |
paul@638 | 639 | nodes = [] |
paul@638 | 640 | left = node.expr |
paul@638 | 641 | for op_name, right in node.ops: |
paul@638 | 642 | nodes.append( |
paul@638 | 643 | compiler.ast.CallFunc( |
paul@638 | 644 | module_attribute("operator", operator_functions.get(op_name)), |
paul@638 | 645 | [self.dispatch(left), self.dispatch(right)] |
paul@638 | 646 | ) |
paul@638 | 647 | ) |
paul@638 | 648 | left = right |
paul@638 | 649 | return compiler.ast.And(nodes) |
paul@638 | 650 | |
paul@638 | 651 | visitConst = NOP |
paul@638 | 652 | |
paul@638 | 653 | def visitDict(self, node): |
paul@638 | 654 | return compiler.ast.Dict([(self.dispatch(key), self.dispatch(value)) for (key, value) in node.items]) |
paul@638 | 655 | |
paul@638 | 656 | def visitDiv(self, node): |
paul@638 | 657 | return self._visitBinary(node) |
paul@638 | 658 | |
paul@638 | 659 | def visitFloorDiv(self, node): |
paul@638 | 660 | return self._visitBinary(node) |
paul@638 | 661 | |
paul@638 | 662 | def visitGetattr(self, node, expr=None): |
paul@638 | 663 | if expr: |
paul@638 | 664 | return self.visitAssAttr(node, expr) |
paul@638 | 665 | |
paul@645 | 666 | unit = self.get_unit() |
paul@645 | 667 | |
paul@638 | 668 | accessor = self.dispatch(node.expr) |
paul@638 | 669 | |
paul@645 | 670 | # The target, on which the access is performed, may influence the effect |
paul@645 | 671 | # on the context. We can only reliably assume that a literal constant is |
paul@645 | 672 | # an instance: all other "instances" may actually be classes in certain |
paul@645 | 673 | # cases. |
paul@645 | 674 | |
paul@645 | 675 | target = node._expr |
paul@645 | 676 | instance_target = isinstance(target, Const) |
paul@645 | 677 | |
paul@645 | 678 | # Attempt to deduce attributes from explicit annotations. |
paul@645 | 679 | |
paul@645 | 680 | attrs = self.possible_attributes_from_annotation(node) |
paul@645 | 681 | |
paul@645 | 682 | if len(attrs) == 1: |
paul@645 | 683 | attr, value = attrs[0] |
paul@645 | 684 | |
paul@645 | 685 | # Constant values can be obtained directly. |
paul@645 | 686 | |
paul@645 | 687 | v = self._generateValue(value) |
paul@645 | 688 | if v: return v |
paul@645 | 689 | |
paul@645 | 690 | # Static attributes can be obtained via their parent. |
paul@645 | 691 | |
paul@645 | 692 | if attr.is_static_attribute(): |
paul@645 | 693 | return compiler.ast.CallFunc( |
paul@645 | 694 | special_name(instance_target and "__loadattrcontext__" or "__loadattr__"), |
paul@645 | 695 | [self._generateValue(attr.parent), special_name(node.attrname)]) |
paul@645 | 696 | |
paul@645 | 697 | # Attributes of self, which is by definition an instance. |
paul@645 | 698 | |
paul@645 | 699 | if self.provides_self_access(node, unit): |
paul@645 | 700 | |
paul@645 | 701 | # Find instance attributes. |
paul@645 | 702 | |
paul@645 | 703 | attr = unit.parent.instance_attributes().get(node.attrname) |
paul@645 | 704 | |
paul@645 | 705 | if attr: |
paul@645 | 706 | |
paul@645 | 707 | # Emit self.attrname without context overriding. |
paul@638 | 708 | |
paul@645 | 709 | return compiler.ast.CallFunc( |
paul@645 | 710 | special_name("__loadattr__"), [ |
paul@645 | 711 | accessor, special_name(node.attrname) |
paul@645 | 712 | ]) |
paul@645 | 713 | |
paul@645 | 714 | # Find class attributes. |
paul@645 | 715 | # The context will be overridden for compatible class attributes |
paul@645 | 716 | # only. |
paul@645 | 717 | |
paul@645 | 718 | attr = unit.parent.get(node.attrname) |
paul@645 | 719 | |
paul@645 | 720 | if attr: |
paul@645 | 721 | |
paul@645 | 722 | # Constant attributes. |
paul@645 | 723 | |
paul@645 | 724 | if attr.is_strict_constant(): |
paul@645 | 725 | v = self._generateValue(attr.get_value()) |
paul@645 | 726 | if v: return v |
paul@645 | 727 | |
paul@645 | 728 | # Compatible class attributes. |
paul@638 | 729 | |
paul@645 | 730 | if attr.defined_within_hierarchy(): |
paul@645 | 731 | return compiler.ast.CallFunc( |
paul@645 | 732 | special_name("__loadattrcontext__"), [ |
paul@645 | 733 | self._generateValue(attr.parent), special_name(node.attrname) |
paul@645 | 734 | ]) |
paul@645 | 735 | |
paul@645 | 736 | # Incompatible class attributes. |
paul@645 | 737 | |
paul@645 | 738 | elif attr.defined_outside_hierarchy(): |
paul@645 | 739 | return compiler.ast.CallFunc( |
paul@645 | 740 | special_name("__loadattr__"), [ |
paul@645 | 741 | self._generateValue(attr.parent), special_name(node.attrname) |
paul@645 | 742 | ]) |
paul@645 | 743 | |
paul@645 | 744 | # Unknown or mixed compatibility. |
paul@645 | 745 | |
paul@645 | 746 | return compiler.ast.CallFunc( |
paul@645 | 747 | special_name("__loadattrcontextcond__"), [ |
paul@645 | 748 | self._generateValue(attr.parent), special_name(node.attrname) |
paul@645 | 749 | ]) |
paul@638 | 750 | |
paul@638 | 751 | # Usage observations. |
paul@638 | 752 | |
paul@645 | 753 | targets = self.possible_accessors_from_usage(node, defining_users=0) |
paul@638 | 754 | |
paul@638 | 755 | # Record whether types were already deduced. If not, get types using |
paul@638 | 756 | # only this attribute. |
paul@638 | 757 | |
paul@645 | 758 | if not targets: |
paul@645 | 759 | targets = self.possible_accessors_for_attribute(node.attrname) |
paul@638 | 760 | |
paul@645 | 761 | attrs = self.get_attributes(targets, node.attrname) |
paul@638 | 762 | |
paul@638 | 763 | # Generate optimisations where only a single attribute applies. |
paul@638 | 764 | |
paul@645 | 765 | if len(attrs) == 1: |
paul@645 | 766 | attr = attrs[0] |
paul@638 | 767 | |
paul@645 | 768 | # Static attributes, but potentially non-static targets. |
paul@638 | 769 | |
paul@645 | 770 | if attr.is_static_attribute(): |
paul@638 | 771 | |
paul@638 | 772 | # Static attributes may be accompanied by a different context |
paul@638 | 773 | # depending on the accessor. |
paul@638 | 774 | # NOTE: Should determine whether the context is always replaced. |
paul@638 | 775 | |
paul@638 | 776 | return compiler.ast.CallFunc( |
paul@645 | 777 | special_name(instance_target and "__loadattrcontext__" or "__loadattrcontextcond__"), |
paul@638 | 778 | [accessor, special_name(node.attrname)] |
paul@638 | 779 | ) |
paul@638 | 780 | |
paul@638 | 781 | # Non-static attributes. |
paul@638 | 782 | |
paul@638 | 783 | return compiler.ast.CallFunc( |
paul@638 | 784 | special_name("__loadattr__"), |
paul@638 | 785 | [accessor, special_name(node.attrname)] |
paul@638 | 786 | ) |
paul@638 | 787 | |
paul@638 | 788 | # With no usable deductions, generate a table-based access. |
paul@638 | 789 | |
paul@645 | 790 | access = compiler.ast.CallFunc( |
paul@645 | 791 | special_name("__loadattrindexcontextcond__"), |
paul@638 | 792 | [accessor, special_name(node.attrname)] |
paul@638 | 793 | ) |
paul@638 | 794 | |
paul@645 | 795 | # class.__class__ => __builtins__.type |
paul@645 | 796 | |
paul@645 | 797 | if node.attrname == "__class__": |
paul@645 | 798 | |
paul@645 | 799 | # __storetemp__(n, <accessor>) |
paul@645 | 800 | # __isclass__(n) and __loadattr__(__builtins__, type) or <access> |
paul@645 | 801 | |
paul@645 | 802 | temp = quoted_name(unit.temp_usage) |
paul@645 | 803 | unit.temp_usage += 1 |
paul@645 | 804 | |
paul@645 | 805 | return compiler.ast.Stmt([ |
paul@645 | 806 | compiler.ast.CallFunc(special_name("__storetemp__"), [temp, access]), |
paul@645 | 807 | compiler.ast.Or([ |
paul@645 | 808 | compiler.ast.And([ |
paul@645 | 809 | compiler.ast.CallFunc( |
paul@645 | 810 | special_name("__isclass__"), |
paul@645 | 811 | [compiler.ast.CallFunc(special_name("__loadtemp__"), [temp])] |
paul@645 | 812 | ), |
paul@645 | 813 | compiler.ast.CallFunc( |
paul@645 | 814 | special_name("__loadattr__"), |
paul@645 | 815 | [special_name("__builtins__"), special_name("type")] |
paul@645 | 816 | ) |
paul@645 | 817 | ]), |
paul@645 | 818 | access |
paul@645 | 819 | ]) |
paul@645 | 820 | ]) |
paul@645 | 821 | |
paul@645 | 822 | # General accesses. |
paul@645 | 823 | |
paul@645 | 824 | else: |
paul@645 | 825 | return access |
paul@645 | 826 | |
paul@638 | 827 | def visitGenExpr(self, node): |
paul@638 | 828 | return compiler.ast.GenExpr(self.dispatch(node.code)) |
paul@638 | 829 | |
paul@638 | 830 | def visitGenExprFor(self, node): |
paul@638 | 831 | return compiler.ast.GenExprFor( |
paul@638 | 832 | self.dispatch(node.assign), # NOTE: Needs to dispatch to AssName/AssTuple/AssList with an expression. |
paul@638 | 833 | self.dispatch(node.iter), |
paul@638 | 834 | [self.dispatch(n) for n in node.ifs] |
paul@638 | 835 | ) |
paul@638 | 836 | |
paul@638 | 837 | def visitGenExprIf(self, node): |
paul@638 | 838 | return compiler.ast.GenExprIf(self.dispatch(node.test)) |
paul@638 | 839 | |
paul@638 | 840 | def visitGenExprInner(self, node): |
paul@638 | 841 | return compiler.ast.GenExprInner( |
paul@638 | 842 | self.dispatch(node.expr), |
paul@638 | 843 | [self.dispatch(n) for n in node.quals] |
paul@638 | 844 | ) |
paul@638 | 845 | |
paul@638 | 846 | def visitIfExp(self, node): |
paul@638 | 847 | return compiler.ast.IfExp( |
paul@638 | 848 | self.dispatch(node.then), |
paul@638 | 849 | self.dispatch(node.test), |
paul@638 | 850 | self.dispatch(node.else_) |
paul@638 | 851 | ) |
paul@638 | 852 | |
paul@638 | 853 | def visitInvert(self, node): |
paul@638 | 854 | return self._visitUnary(node) |
paul@638 | 855 | |
paul@638 | 856 | def visitKeyword(self, node): |
paul@638 | 857 | return compiler.ast.Keyword( |
paul@638 | 858 | node.name, |
paul@638 | 859 | self.dispatch(node.expr) |
paul@638 | 860 | ) |
paul@638 | 861 | |
paul@638 | 862 | def visitLambda(self, node): |
paul@638 | 863 | self.units.append(node.unit) |
paul@638 | 864 | |
paul@638 | 865 | try: |
paul@638 | 866 | return compiler.ast.Lambda( |
paul@638 | 867 | node.argnames, |
paul@638 | 868 | [self.dispatch(n) for n in node.defaults], |
paul@638 | 869 | node.flags, |
paul@638 | 870 | self.dispatch(node.code) |
paul@638 | 871 | ) |
paul@638 | 872 | finally: |
paul@638 | 873 | self.units.pop() |
paul@638 | 874 | |
paul@638 | 875 | def visitLeftShift(self, node): |
paul@638 | 876 | return self._visitBinary(node) |
paul@638 | 877 | |
paul@638 | 878 | def visitList(self, node, expr=None): |
paul@638 | 879 | if expr: |
paul@638 | 880 | return self.visitAssList(node, expr) |
paul@638 | 881 | return compiler.ast.List([self.dispatch(n) for n in node.nodes]) |
paul@638 | 882 | |
paul@638 | 883 | def visitListComp(self, node): |
paul@638 | 884 | return compiler.ast.ListComp( |
paul@638 | 885 | self.dispatch(node.expr), |
paul@638 | 886 | [self.dispatch(n) for n in node.quals] |
paul@638 | 887 | ) |
paul@638 | 888 | |
paul@638 | 889 | def visitListCompFor(self, node): |
paul@638 | 890 | return compiler.ast.ListCompFor( |
paul@638 | 891 | self.dispatch(node.assign), # NOTE: Needs to dispatch to AssName/AssTuple/AssList with an expression. |
paul@638 | 892 | self.dispatch(node.list), |
paul@638 | 893 | [self.dispatch(n) for n in node.ifs] |
paul@638 | 894 | ) |
paul@638 | 895 | |
paul@638 | 896 | def visitListCompIf(self, node): |
paul@638 | 897 | return compiler.ast.ListCompIf( |
paul@638 | 898 | self.dispatch(node.test) |
paul@638 | 899 | ) |
paul@638 | 900 | |
paul@638 | 901 | def visitMod(self, node): |
paul@638 | 902 | return self._visitBinary(node) |
paul@638 | 903 | |
paul@638 | 904 | def visitMul(self, node): |
paul@638 | 905 | return self._visitBinary(node) |
paul@638 | 906 | |
paul@638 | 907 | def visitName(self, node, expr=None): |
paul@638 | 908 | if expr: |
paul@638 | 909 | return self.visitAssName(node, expr) |
paul@638 | 910 | |
paul@638 | 911 | unit = self.get_unit() |
paul@645 | 912 | attr = node._attr |
paul@645 | 913 | scope = node._scope |
paul@638 | 914 | |
paul@638 | 915 | # Generate appropriate name access operation. |
paul@638 | 916 | |
paul@638 | 917 | if scope == "constant": |
paul@638 | 918 | return node |
paul@638 | 919 | |
paul@645 | 920 | # Function locals are referenced normally. |
paul@638 | 921 | |
paul@645 | 922 | elif scope == "local" and isinstance(unit, Function): |
paul@645 | 923 | return node |
paul@638 | 924 | |
paul@645 | 925 | # Other attributes should already be resolved. |
paul@638 | 926 | |
paul@645 | 927 | elif attr is not None: |
paul@638 | 928 | return compiler.ast.CallFunc( |
paul@645 | 929 | special_name("__loadattr__"), |
paul@645 | 930 | [quoted_ref(attr.parent), special_name(node.name)] |
paul@638 | 931 | ) |
paul@638 | 932 | |
paul@645 | 933 | # NOTE: Unknown attributes may arise because a class attribute has been |
paul@645 | 934 | # NOTE: optimised away. |
paul@638 | 935 | |
paul@638 | 936 | else: |
paul@638 | 937 | return compiler.ast.CallFunc( |
paul@638 | 938 | special_name("__loadunknown__"), |
paul@638 | 939 | [special_name(node.name)] |
paul@638 | 940 | ) |
paul@638 | 941 | |
paul@638 | 942 | def visitNot(self, node): |
paul@638 | 943 | return compiler.ast.Not(self.dispatch(node.expr)) |
paul@638 | 944 | |
paul@638 | 945 | def visitOr(self, node): |
paul@638 | 946 | return compiler.ast.Or([self.dispatch(n) for n in node.nodes]) |
paul@638 | 947 | |
paul@638 | 948 | def visitPower(self, node): |
paul@638 | 949 | return self._visitBinary(node) |
paul@638 | 950 | |
paul@638 | 951 | def visitRightShift(self, node): |
paul@638 | 952 | return self._visitBinary(node) |
paul@638 | 953 | |
paul@638 | 954 | def visitSlice(self, node, expr=None): |
paul@638 | 955 | return compiler.ast.CallFunc( |
paul@638 | 956 | module_attribute("operator", expr and "setslice" or "getslice"), |
paul@638 | 957 | [self.dispatch(node.expr), node.lower and self.dispatch(node.lower), node.upper and self.dispatch(node.upper)] |
paul@638 | 958 | + (expr and [expr] or []) |
paul@638 | 959 | ) |
paul@638 | 960 | |
paul@638 | 961 | def visitSliceobj(self, node): |
paul@638 | 962 | return compiler.ast.Sliceobj([self.dispatch(n) for n in node.nodes]) |
paul@638 | 963 | |
paul@638 | 964 | def visitSub(self, node): |
paul@638 | 965 | return self._visitBinary(node) |
paul@638 | 966 | |
paul@638 | 967 | def visitSubscript(self, node, expr=None): |
paul@638 | 968 | return compiler.ast.CallFunc( |
paul@638 | 969 | module_attribute("operator", expr and "setitem" or "getitem"), |
paul@638 | 970 | [self.dispatch(node.expr), compiler.ast.Tuple([self.dispatch(sub) for sub in node.subs])] |
paul@638 | 971 | + (expr and [expr] or []) |
paul@638 | 972 | ) |
paul@638 | 973 | |
paul@638 | 974 | def visitTuple(self, node, expr=None): |
paul@638 | 975 | if expr: |
paul@638 | 976 | return self.visitAssTuple(node, expr) |
paul@638 | 977 | return compiler.ast.Tuple([self.dispatch(n) for n in node.nodes]) |
paul@638 | 978 | |
paul@638 | 979 | def visitUnaryAdd(self, node): |
paul@638 | 980 | return self._visitUnary(node) |
paul@638 | 981 | |
paul@638 | 982 | def visitUnarySub(self, node): |
paul@638 | 983 | return self._visitUnary(node) |
paul@638 | 984 | |
paul@638 | 985 | # Type-related methods. |
paul@638 | 986 | |
paul@638 | 987 | def possible_accessor_types(self, node, defining_users=1): |
paul@638 | 988 | return set([tn for (tn, st) in ASTVisitor.possible_accessor_types(self, node, defining_users)]) |
paul@638 | 989 | |
paul@645 | 990 | def get_possible_accessors(self, attrname): |
paul@645 | 991 | |
paul@645 | 992 | "Return a list of accessors supporting 'attrname'." |
paul@645 | 993 | |
paul@645 | 994 | targets = [] |
paul@638 | 995 | |
paul@645 | 996 | for target_name in self.objtable.any_possible_objects([attrname]): |
paul@645 | 997 | targets.append(self.objtable.get_object(target_name)) |
paul@645 | 998 | |
paul@645 | 999 | return targets |
paul@645 | 1000 | |
paul@645 | 1001 | def get_attributes(self, targets, attrname): |
paul@645 | 1002 | |
paul@645 | 1003 | "Return a list of attributes for 'targets' supporting 'attrname'." |
paul@645 | 1004 | |
paul@638 | 1005 | attributes = [] |
paul@645 | 1006 | |
paul@645 | 1007 | for target in targets: |
paul@645 | 1008 | attributes.append(self.objtable.access(target.full_name(), attrname)) |
paul@638 | 1009 | |
paul@638 | 1010 | return attributes |
paul@638 | 1011 | |
paul@638 | 1012 | # Convenience functions. |
paul@638 | 1013 | |
paul@638 | 1014 | def convert(module, program, filename): |
paul@638 | 1015 | stream = open(filename, "wb") |
paul@638 | 1016 | try: |
paul@638 | 1017 | source = ConvertedSource(module, program) |
paul@638 | 1018 | source.to_stream(stream) |
paul@638 | 1019 | finally: |
paul@638 | 1020 | stream.close() |
paul@638 | 1021 | |
paul@638 | 1022 | def translate(program, directory): |
paul@638 | 1023 | if not exists(directory): |
paul@638 | 1024 | os.mkdir(directory) |
paul@638 | 1025 | |
paul@638 | 1026 | # NOTE: Add constants here. |
paul@638 | 1027 | |
paul@638 | 1028 | for module in program.get_importer().get_modules(): |
paul@638 | 1029 | convert(module, program, join(directory, "%s%spy" % (module.full_name(), extsep))) |
paul@638 | 1030 | |
paul@638 | 1031 | # vim: tabstop=4 expandtab shiftwidth=4 |