2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/micropython/syspython.py Tue Mar 12 00:09:48 2013 +0100
2.3 @@ -0,0 +1,938 @@
2.4 +#!/usr/bin/env python
2.5 +
2.6 +"""
2.7 +Produce syspython code from an inspected program.
2.8 +
2.9 +Copyright (C) 2006, 2007, 2010, 2011, 2012, 2013 Paul Boddie <paul@boddie.org.uk>
2.10 +
2.11 +This program is free software; you can redistribute it and/or modify it under
2.12 +the terms of the GNU General Public License as published by the Free Software
2.13 +Foundation; either version 3 of the License, or (at your option) any later
2.14 +version.
2.15 +
2.16 +This program is distributed in the hope that it will be useful, but WITHOUT
2.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
2.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
2.19 +details.
2.20 +
2.21 +You should have received a copy of the GNU General Public License along with
2.22 +this program. If not, see <http://www.gnu.org/licenses/>.
2.23 +"""
2.24 +
2.25 +from micropython.common import *
2.26 +from micropython.data import *
2.27 +from micropython.errors import *
2.28 +from os.path import exists, extsep, join
2.29 +import compiler.ast
2.30 +import sys
2.31 +import os
2.32 +
2.33 +try:
2.34 + set
2.35 +except NameError:
2.36 + from sets import Set as set
2.37 +
2.38 +# Convenience definitions.
2.39 +
2.40 +module_attribute = compiler.ast.Getattr
2.41 +special_name = compiler.ast.Name
2.42 +quoted_name = compiler.ast.Const
2.43 +
2.44 +# Source code classes.
2.45 +
2.46 +class ConvertedSource(ASTVisitor):
2.47 +
2.48 + "A conversion of module source code to syspython."
2.49 +
2.50 + def __init__(self, module, program):
2.51 + self.visitor = self
2.52 + self.module = module
2.53 + self.program = program
2.54 + self.in_main = False
2.55 + self.units = []
2.56 +
2.57 + def get_unit(self):
2.58 + return self.units[-1]
2.59 +
2.60 + def get_module(self):
2.61 + return self.units[0]
2.62 +
2.63 + def to_stream(self, stream):
2.64 +
2.65 + "Write the converted code to the given 'stream'."
2.66 +
2.67 + module = self.dispatch(self.module.astnode)
2.68 + stream.write(str(module))
2.69 +
2.70 + def NOP(self, node):
2.71 + return node
2.72 +
2.73 + def visitModule(self, node):
2.74 + module = node.unit
2.75 + self.units.append(module)
2.76 +
2.77 + definitions = self._findDefinitions(node)
2.78 +
2.79 + # __globalnames__(name, ...)
2.80 +
2.81 + globalnames = module.module_attribute_names() and [
2.82 + compiler.ast.CallFunc(
2.83 + special_name("__globalnames__"),
2.84 + [special_name(name) for name in module.module_attribute_names()]
2.85 + )
2.86 + ] or []
2.87 +
2.88 + # def __main__():
2.89 + # ...
2.90 +
2.91 + self.in_main = True
2.92 +
2.93 + main = compiler.ast.Function(
2.94 + [], "__main__", [], [], 0, "Module initialisation.",
2.95 + compiler.ast.Stmt(globalnames + self.dispatch(node.node).nodes)
2.96 + )
2.97 +
2.98 + self.in_main = False
2.99 + self.units.pop()
2.100 +
2.101 + return compiler.ast.Module(node.doc, compiler.ast.Stmt(definitions + [main]))
2.102 +
2.103 + def _findDefinitions(self, node):
2.104 + definitions = []
2.105 + for n in node.getChildNodes():
2.106 + if isinstance(n, (compiler.ast.Class, compiler.ast.Function)):
2.107 + definitions.append(self.dispatch(n))
2.108 + else:
2.109 + definitions += self._findDefinitions(n)
2.110 + return definitions
2.111 +
2.112 + # Statements.
2.113 +
2.114 + def visitAssert(self, node):
2.115 + return compiler.ast.Assert(self.dispatch(node.test), node.fail and self.dispatch(node.fail))
2.116 +
2.117 + def visitAssign(self, node):
2.118 + expr = self.dispatch(node.expr)
2.119 + return compiler.ast.Stmt([self.dispatch(n, expr) for n in node.nodes])
2.120 +
2.121 + def visitAugAssign(self, node):
2.122 +
2.123 + # lvalue = op(lvalue, expr)
2.124 + # -> __fn__(lvalue, op(lvalue, expr))
2.125 +
2.126 + op_name = operator_functions[node.op]
2.127 +
2.128 + return self.dispatch(node.node, compiler.ast.CallFunc(
2.129 + module_attribute("operator", op_name),
2.130 + [self.dispatch(node.node), self.dispatch(node.expr)]
2.131 + ))
2.132 +
2.133 + visitBreak = NOP
2.134 +
2.135 + def visitClass(self, node):
2.136 + if not used_by_unit(node):
2.137 + return compiler.ast.Stmt([])
2.138 +
2.139 + self.units.append(node.unit)
2.140 + try:
2.141 + # Incorporate class body code in the main function.
2.142 +
2.143 + if self.in_main:
2.144 + return self.dispatch(node.code)
2.145 + else:
2.146 + return self._visitClassDefinition(node)
2.147 +
2.148 + finally:
2.149 + self.units.pop()
2.150 +
2.151 + def _visitClassDefinition(self, node):
2.152 + cls = node.unit
2.153 +
2.154 + # __instattrs__(name, ...)
2.155 + # __clsattrs__(name, ...)
2.156 +
2.157 + instattrs = cls.instance_attribute_names() and [
2.158 + compiler.ast.CallFunc(
2.159 + special_name("__instattrs__"),
2.160 + [special_name(name) for name in cls.instance_attribute_names()]
2.161 + )
2.162 + ] or []
2.163 +
2.164 + clsattrs = cls.class_attribute_names() and [
2.165 + compiler.ast.CallFunc(
2.166 + special_name("__clsattrs__"),
2.167 + [special_name(name) for name in cls.class_attribute_names()]
2.168 + )
2.169 + ] or []
2.170 +
2.171 + # __inherited__(superclass, name, ...)
2.172 + # ...
2.173 +
2.174 + attrs_by_cls = {}
2.175 + for attrname, attr in cls.all_class_attributes().items():
2.176 + supercls = attr.parent
2.177 + if supercls is cls:
2.178 + continue
2.179 + if not attrs_by_cls.has_key(supercls):
2.180 + attrs_by_cls[supercls] = []
2.181 + attrs_by_cls[supercls].append(attrname)
2.182 +
2.183 + inherited = []
2.184 +
2.185 + for supercls, attrnames in attrs_by_cls.items():
2.186 + inherited.append(
2.187 + compiler.ast.CallFunc(
2.188 + special_name("__inherited__"),
2.189 + [special_name(supercls.full_name())] + [special_name(name) for name in attrnames]
2.190 + ))
2.191 +
2.192 + # __descendants__(name, ...)
2.193 +
2.194 + descendants = cls.all_descendants() and [
2.195 + compiler.ast.CallFunc(
2.196 + special_name("__descendants__"),
2.197 + [special_name(name) for name in cls.all_descendants().keys()]
2.198 + )
2.199 + ] or []
2.200 +
2.201 + # Process all the definitions defined inside the class.
2.202 +
2.203 + definitions = self._findDefinitions(node)
2.204 +
2.205 + return compiler.ast.Class(node.name, [], node.doc,
2.206 + compiler.ast.Stmt(instattrs + clsattrs + inherited + descendants + definitions)
2.207 + )
2.208 +
2.209 + visitContinue = NOP
2.210 +
2.211 + def visitDiscard(self, node):
2.212 + return compiler.ast.Discard(self.dispatch(node.expr))
2.213 +
2.214 + def visitFor(self, node):
2.215 +
2.216 + """
2.217 + Convert from...
2.218 +
2.219 + for <assign> in <list>:
2.220 + <body>
2.221 + [ else:
2.222 + <else_> ]
2.223 +
2.224 + ...to...
2.225 +
2.226 + _it = iter(<list>)
2.227 + while True:
2.228 + try:
2.229 + <assign> = _it.next()
2.230 + except StopIteration:
2.231 + [ <else_> ]
2.232 + break
2.233 + else:
2.234 + <body>
2.235 + """
2.236 +
2.237 + unit = self.get_unit()
2.238 + temp = quoted_name(unit.temp_usage)
2.239 + unit.temp_usage += 1
2.240 +
2.241 + else_nodes = node.else_ and self.dispatch(node.else_).nodes or []
2.242 +
2.243 + return compiler.ast.Stmt([
2.244 + # __storetemp__(_it, __loadaddress__(__builtins__, iter)(<list>))
2.245 + compiler.ast.CallFunc(special_name("__storetemp__"), [
2.246 + temp,
2.247 + compiler.ast.CallFunc(
2.248 + compiler.ast.CallFunc(special_name("__loadaddress__"),
2.249 + [special_name("__builtins__"), special_name("iter")]
2.250 + ),
2.251 + [self.dispatch(node.list)]
2.252 + )
2.253 + ]),
2.254 + # while True: ...
2.255 + compiler.ast.While(
2.256 + special_name("True"),
2.257 + # try: ...
2.258 + compiler.ast.TryExcept(
2.259 + compiler.ast.Stmt([
2.260 + # <assign> = ...
2.261 + self.dispatch(node.assign,
2.262 + # _it.next()
2.263 + compiler.ast.CallFunc(
2.264 + compiler.ast.CallFunc(special_name("__loadattr__"), [
2.265 + compiler.ast.CallFunc(special_name("__loadtemp__"), [temp]),
2.266 + special_name("next")
2.267 + ]),
2.268 + []
2.269 + )
2.270 + )
2.271 + ]),
2.272 + # except StopIteration: ...
2.273 + [(special_name("StopIteration"), None, compiler.ast.Stmt(else_nodes + [compiler.ast.Break()]))],
2.274 + # else: ...
2.275 + self.dispatch(node.body)
2.276 + ),
2.277 + None
2.278 + )
2.279 + ])
2.280 +
2.281 + def visitFrom(self, node):
2.282 +
2.283 + # Generate __main__ function calls for each step in the imported module
2.284 + # hierarchy.
2.285 +
2.286 + statements = []
2.287 +
2.288 + for modname in self.module.get_module_paths(node.modname):
2.289 + statements.append(
2.290 + compiler.ast.CallFunc(special_name("%s.__main__" % modname ), [])
2.291 + )
2.292 +
2.293 + for name, alias in node.names:
2.294 + statements.append(
2.295 + compiler.ast.Assign(
2.296 + [special_name(alias or name)],
2.297 + compiler.ast.CallFunc(
2.298 + special_name("__loadattribute__"),
2.299 + [special_name(node.modname), special_name(name)]
2.300 + )
2.301 + )
2.302 + )
2.303 +
2.304 + return compiler.ast.Stmt(statements)
2.305 +
2.306 + def visitFunction(self, node):
2.307 + if not used_by_unit(node):
2.308 + return compiler.ast.Stmt([])
2.309 +
2.310 + self.units.append(node.unit)
2.311 +
2.312 + try:
2.313 + # Ignore functions when generating the main function.
2.314 +
2.315 + if self.in_main:
2.316 + return compiler.ast.Stmt([])
2.317 + else:
2.318 + return self._visitFunctionDefinition(node)
2.319 + finally:
2.320 + self.units.pop()
2.321 +
2.322 + def _visitFunctionDefinition(self, node):
2.323 + fn = node.unit
2.324 +
2.325 + # __localnames__(name, ...)
2.326 + # __globalnames__(name, ...)
2.327 +
2.328 + localnames = fn.locals() and [
2.329 + compiler.ast.CallFunc(
2.330 + special_name("__localnames__"),
2.331 + [special_name(name) for name in fn.locals().keys()]
2.332 + )
2.333 + ] or []
2.334 +
2.335 + globalnames = fn.globals and [
2.336 + compiler.ast.CallFunc(
2.337 + special_name("__globalnames__"),
2.338 + [special_name(name) for name in fn.globals]
2.339 + )
2.340 + ] or []
2.341 +
2.342 + defaults = [self.dispatch(n) for n in node.defaults]
2.343 +
2.344 + code = self.dispatch(node.code)
2.345 +
2.346 + return compiler.ast.Function(node.decorators, node.name, node.argnames, defaults, node.flags, node.doc,
2.347 + compiler.ast.Stmt(localnames + globalnames + code.nodes))
2.348 +
2.349 + visitGlobal = NOP
2.350 +
2.351 + def visitIf(self, node):
2.352 + return compiler.ast.If(
2.353 + [(self.dispatch(compare), self.dispatch(stmt)) for (compare, stmt) in node.tests],
2.354 + node.else_ and self.dispatch(node.else_)
2.355 + )
2.356 +
2.357 + def visitImport(self, node):
2.358 +
2.359 + # Generate __main__ function calls for each step in the imported module
2.360 + # hierarchy.
2.361 +
2.362 + statements = []
2.363 +
2.364 + for name, alias in node.names:
2.365 + for modname in self.module.get_module_paths(name):
2.366 + statements.append(
2.367 + compiler.ast.CallFunc(compiler.ast.Getattr(modname, "__main__"), [])
2.368 + )
2.369 +
2.370 + statements.append(
2.371 + compiler.ast.Assign(
2.372 + [special_name(alias or name.split(".")[0])],
2.373 + compiler.ast.CallFunc(
2.374 + special_name("__static__"),
2.375 + [special_name(name)]
2.376 + )
2.377 + )
2.378 + )
2.379 +
2.380 + return compiler.ast.Stmt(statements)
2.381 +
2.382 + visitPass = NOP
2.383 +
2.384 + def visitPrint(self, node):
2.385 + return compiler.ast.Print(
2.386 + [self.dispatch(n) for n in node.nodes],
2.387 + node.dest and self.dispatch(node.dest)
2.388 + )
2.389 +
2.390 + def visitPrintnl(self, node):
2.391 + return compiler.ast.Print(
2.392 + [self.dispatch(n) for n in node.nodes],
2.393 + node.dest and self.dispatch(node.dest)
2.394 + )
2.395 +
2.396 + def visitRaise(self, node):
2.397 + return compiler.ast.Raise(
2.398 + node.expr1 and self.dispatch(node.expr1),
2.399 + node.expr2 and self.dispatch(node.expr2),
2.400 + node.expr3 and self.dispatch(node.expr3)
2.401 + )
2.402 +
2.403 + def visitReturn(self, node):
2.404 + return compiler.ast.Return(self.dispatch(node.value))
2.405 +
2.406 + def visitStmt(self, node):
2.407 + return compiler.ast.Stmt([self.dispatch(n) for n in node.nodes])
2.408 +
2.409 + def visitTryExcept(self, node):
2.410 + # NOTE: Need to dispatch to the assignment with the exception.
2.411 + return compiler.ast.TryExcept(
2.412 + self.dispatch(node.body),
2.413 + [(spec and self.dispatch(spec), assign and self.dispatch(assign), self.dispatch(statement))
2.414 + for spec, assign, statement in node.handlers],
2.415 + node.else_ and self.dispatch(node.else_)
2.416 + )
2.417 +
2.418 + def visitTryFinally(self, node):
2.419 + return compiler.ast.TryFinally(
2.420 + self.dispatch(node.body),
2.421 + self.dispatch(node.final)
2.422 + )
2.423 +
2.424 + def visitWhile(self, node):
2.425 + return compiler.ast.While(
2.426 + self.dispatch(node.test),
2.427 + self.dispatch(node.body),
2.428 + node.else_ and self.dispatch(node.else_)
2.429 + )
2.430 +
2.431 + def visitYield(self, node):
2.432 + return compiler.ast.Yield(self.dispatch(node.value))
2.433 +
2.434 + # Expression-related helper methods.
2.435 +
2.436 + def _visitBitBinary(self, node):
2.437 + op_name = operator_functions[node.__class__.__name__]
2.438 + last = self.dispatch(node.nodes[0])
2.439 +
2.440 + for n in node.nodes[1:]:
2.441 + last = compiler.ast.CallFunc(
2.442 + module_attribute("operator", op_name),
2.443 + [last, self.dispatch(n)]
2.444 + )
2.445 +
2.446 + return last
2.447 +
2.448 + def _visitBinary(self, node):
2.449 + op_name = operator_functions[node.__class__.__name__]
2.450 +
2.451 + return compiler.ast.CallFunc(
2.452 + module_attribute("operator", op_name),
2.453 + [self.dispatch(node.left), self.dispatch(node.right)]
2.454 + )
2.455 +
2.456 + def _visitUnary(self, node):
2.457 + op_name = operator_functions[node.__class__.__name__]
2.458 +
2.459 + return compiler.ast.CallFunc(
2.460 + module_attribute("operator", op_name),
2.461 + [self.dispatch(node.expr)]
2.462 + )
2.463 +
2.464 + # Expressions.
2.465 +
2.466 + def visitAdd(self, node):
2.467 + return self._visitBinary(node)
2.468 +
2.469 + def visitAnd(self, node):
2.470 + return compiler.ast.And([self.dispatch(n) for n in node.nodes])
2.471 +
2.472 + def visitAssAttr(self, node, expr):
2.473 + possible_types = self.possible_accessor_types(node, defining_users=0)
2.474 +
2.475 + # NOTE: Derived from Getattr support.
2.476 +
2.477 + accessor = self.dispatch(node.expr)
2.478 +
2.479 + # NOTE: Replicate the _generateAttr logic.
2.480 + # NOTE: Should be able to store concrete value details on generated
2.481 + # NOTE: nodes, such as whether an expression yields a constant.
2.482 +
2.483 + # NOTE: Known targets:
2.484 + # NOTE: __storeaddress__ and __storeaddresscontext__
2.485 +
2.486 + # NOTE: Attributes of self.
2.487 +
2.488 + # Usage observations.
2.489 +
2.490 + possible_types = self.possible_accessor_types(node, defining_users=0)
2.491 +
2.492 + # Record whether types were already deduced. If not, get types using
2.493 + # only this attribute.
2.494 +
2.495 + if not possible_types:
2.496 + possible_types = self.get_possible_types(node.attrname)
2.497 +
2.498 + attributes = self.get_attributes(possible_types, node.attrname)
2.499 +
2.500 + # Generate optimisations where only a single attribute applies.
2.501 +
2.502 + if len(attributes) == 1:
2.503 + value, target, target_name = attributes[0]
2.504 +
2.505 + # Static attributes.
2.506 +
2.507 + if value is not None:
2.508 +
2.509 + # Static attributes may be accompanied by a different context
2.510 + # depending on the accessor.
2.511 + # NOTE: Should determine whether the context is always replaced.
2.512 +
2.513 + return compiler.ast.CallFunc(
2.514 + special_name("__storeaddresscontextcond__"),
2.515 + [accessor, special_name(node.attrname), expr]
2.516 + )
2.517 +
2.518 + # Non-static attributes.
2.519 +
2.520 + return compiler.ast.CallFunc(
2.521 + special_name("__storeattr__"),
2.522 + [accessor, special_name(node.attrname), expr]
2.523 + )
2.524 +
2.525 + # With no usable deductions, generate a table-based access.
2.526 +
2.527 + return compiler.ast.CallFunc(
2.528 + special_name("__storeattrindex__"),
2.529 + [accessor, special_name(node.attrname), expr]
2.530 + )
2.531 +
2.532 + def visitAssList(self, node, expr):
2.533 + return compiler.ast.Stmt([
2.534 + self.dispatch(n, compiler.ast.CallFunc(
2.535 + module_attribute("operator", "getitem"),
2.536 + [expr, i]
2.537 + ))
2.538 + for (i, n) in enumerate(node.nodes)
2.539 + ])
2.540 +
2.541 + def visitAssName(self, node, expr):
2.542 + unit = self.get_unit()
2.543 +
2.544 + # Generate appropriate name access operation.
2.545 +
2.546 + scope = getattr(node, "_scope", None)
2.547 + if not scope:
2.548 + attr, scope, from_name = self.get_unit()._get_with_scope(node.name)
2.549 +
2.550 + if scope == "constant":
2.551 + return node
2.552 + elif scope == "local":
2.553 +
2.554 + # Function locals are stored using a function.
2.555 +
2.556 + if isinstance(unit, Function):
2.557 + return compiler.ast.CallFunc(
2.558 + special_name("__storelocal__"),
2.559 + [special_name(node.name), expr]
2.560 + )
2.561 +
2.562 + # Class locals are class attribute references.
2.563 +
2.564 + elif isinstance(unit, Class):
2.565 + return compiler.ast.CallFunc(
2.566 + special_name("__storeaddresscontext__"),
2.567 + [quoted_name(unit.full_name()), special_name(node.name), expr]
2.568 + )
2.569 +
2.570 + # Module locals are module attribute references.
2.571 +
2.572 + elif isinstance(unit, Module):
2.573 + return compiler.ast.CallFunc(
2.574 + special_name("__storeaddress__"),
2.575 + [quoted_name(unit.full_name()), special_name(node.name), expr]
2.576 + )
2.577 + else:
2.578 + raise TranslateError("Program unit has no local %r." % name)
2.579 +
2.580 + elif scope == "global":
2.581 +
2.582 + # Globals are references to module attributes.
2.583 +
2.584 + return compiler.ast.CallFunc(
2.585 + special_name("__storeaddress__"),
2.586 + [quoted_name(self.get_module().full_name()), special_name(node.name), expr]
2.587 + )
2.588 +
2.589 + elif scope == "builtin":
2.590 +
2.591 + # Builtins are accessed via the __builtins__ module.
2.592 +
2.593 + return compiler.ast.CallFunc(
2.594 + special_name("__storeaddress__"),
2.595 + [special_name("__builtins__"), special_name(node.name), expr]
2.596 + )
2.597 +
2.598 + else:
2.599 + # NOTE: This may happen because a class attribute is optimised away.
2.600 + return compiler.ast.CallFunc(
2.601 + special_name("__storeunknown__"),
2.602 + [special_name(node.name), expr]
2.603 + )
2.604 +
2.605 + visitAssTuple = visitAssList
2.606 +
2.607 + def visitBitand(self, node):
2.608 + self._visitBitBinary(node)
2.609 +
2.610 + def visitBitor(self, node):
2.611 + self._visitBitBinary(node)
2.612 +
2.613 + def visitBitxor(self, node):
2.614 + self._visitBitBinary(node)
2.615 +
2.616 + def visitCallFunc(self, node):
2.617 + return compiler.ast.CallFunc(
2.618 + self.dispatch(node.node),
2.619 + [self.dispatch(arg) for arg in node.args],
2.620 + node.star_args and [self.dispatch(arg) for arg in node.star_args],
2.621 + node.dstar_args and [self.dispatch(arg) for arg in node.dstar_args]
2.622 + )
2.623 +
2.624 + def visitCompare(self, node):
2.625 + nodes = []
2.626 + left = node.expr
2.627 + for op_name, right in node.ops:
2.628 + nodes.append(
2.629 + compiler.ast.CallFunc(
2.630 + module_attribute("operator", operator_functions.get(op_name)),
2.631 + [self.dispatch(left), self.dispatch(right)]
2.632 + )
2.633 + )
2.634 + left = right
2.635 + return compiler.ast.And(nodes)
2.636 +
2.637 + visitConst = NOP
2.638 +
2.639 + def visitDict(self, node):
2.640 + return compiler.ast.Dict([(self.dispatch(key), self.dispatch(value)) for (key, value) in node.items])
2.641 +
2.642 + def visitDiv(self, node):
2.643 + return self._visitBinary(node)
2.644 +
2.645 + def visitFloorDiv(self, node):
2.646 + return self._visitBinary(node)
2.647 +
2.648 + def visitGetattr(self, node, expr=None):
2.649 + if expr:
2.650 + return self.visitAssAttr(node, expr)
2.651 +
2.652 + accessor = self.dispatch(node.expr)
2.653 +
2.654 + # NOTE: Replicate the _generateAttr logic.
2.655 + # NOTE: Should be able to store concrete value details on generated
2.656 + # NOTE: nodes, such as whether an expression yields a constant.
2.657 +
2.658 + # NOTE: Known targets:
2.659 + # NOTE: class.__class__ => __builtins__.type
2.660 + # NOTE: __loadaddress__ and __loadaddresscontext__
2.661 +
2.662 + # NOTE: Attributes of self.
2.663 +
2.664 + # Usage observations.
2.665 +
2.666 + possible_types = self.possible_accessor_types(node, defining_users=0)
2.667 +
2.668 + # Record whether types were already deduced. If not, get types using
2.669 + # only this attribute.
2.670 +
2.671 + if not possible_types:
2.672 + possible_types = self.get_possible_types(node.attrname)
2.673 +
2.674 + attributes = self.get_attributes(possible_types, node.attrname)
2.675 +
2.676 + # Generate optimisations where only a single attribute applies.
2.677 +
2.678 + if len(attributes) == 1:
2.679 + value, target, target_name = attributes[0]
2.680 +
2.681 + # Static attributes.
2.682 +
2.683 + if value is not None:
2.684 +
2.685 + # class.__class__ => __builtins__.type
2.686 +
2.687 + if node.attrname == "__class__":
2.688 + return compiler.ast.CallFunc(
2.689 + special_name("__loadaddress__"),
2.690 + [special_name("__builtins__"), special_name("type")]
2.691 + )
2.692 +
2.693 + # Static attributes may be accompanied by a different context
2.694 + # depending on the accessor.
2.695 + # NOTE: Should determine whether the context is always replaced.
2.696 +
2.697 + return compiler.ast.CallFunc(
2.698 + special_name("__loadaddresscontextcond__"),
2.699 + [accessor, special_name(node.attrname)]
2.700 + )
2.701 +
2.702 + # Non-static attributes.
2.703 +
2.704 + return compiler.ast.CallFunc(
2.705 + special_name("__loadattr__"),
2.706 + [accessor, special_name(node.attrname)]
2.707 + )
2.708 +
2.709 + # With no usable deductions, generate a table-based access.
2.710 +
2.711 + return compiler.ast.CallFunc(
2.712 + special_name("__loadattrindex__"),
2.713 + [accessor, special_name(node.attrname)]
2.714 + )
2.715 +
2.716 + def visitGenExpr(self, node):
2.717 + return compiler.ast.GenExpr(self.dispatch(node.code))
2.718 +
2.719 + def visitGenExprFor(self, node):
2.720 + return compiler.ast.GenExprFor(
2.721 + self.dispatch(node.assign), # NOTE: Needs to dispatch to AssName/AssTuple/AssList with an expression.
2.722 + self.dispatch(node.iter),
2.723 + [self.dispatch(n) for n in node.ifs]
2.724 + )
2.725 +
2.726 + def visitGenExprIf(self, node):
2.727 + return compiler.ast.GenExprIf(self.dispatch(node.test))
2.728 +
2.729 + def visitGenExprInner(self, node):
2.730 + return compiler.ast.GenExprInner(
2.731 + self.dispatch(node.expr),
2.732 + [self.dispatch(n) for n in node.quals]
2.733 + )
2.734 +
2.735 + def visitIfExp(self, node):
2.736 + return compiler.ast.IfExp(
2.737 + self.dispatch(node.then),
2.738 + self.dispatch(node.test),
2.739 + self.dispatch(node.else_)
2.740 + )
2.741 +
2.742 + def visitInvert(self, node):
2.743 + return self._visitUnary(node)
2.744 +
2.745 + def visitKeyword(self, node):
2.746 + return compiler.ast.Keyword(
2.747 + node.name,
2.748 + self.dispatch(node.expr)
2.749 + )
2.750 +
2.751 + def visitLambda(self, node):
2.752 + self.units.append(node.unit)
2.753 +
2.754 + try:
2.755 + return compiler.ast.Lambda(
2.756 + node.argnames,
2.757 + [self.dispatch(n) for n in node.defaults],
2.758 + node.flags,
2.759 + self.dispatch(node.code)
2.760 + )
2.761 + finally:
2.762 + self.units.pop()
2.763 +
2.764 + def visitLeftShift(self, node):
2.765 + return self._visitBinary(node)
2.766 +
2.767 + def visitList(self, node, expr=None):
2.768 + if expr:
2.769 + return self.visitAssList(node, expr)
2.770 + return compiler.ast.List([self.dispatch(n) for n in node.nodes])
2.771 +
2.772 + def visitListComp(self, node):
2.773 + return compiler.ast.ListComp(
2.774 + self.dispatch(node.expr),
2.775 + [self.dispatch(n) for n in node.quals]
2.776 + )
2.777 +
2.778 + def visitListCompFor(self, node):
2.779 + return compiler.ast.ListCompFor(
2.780 + self.dispatch(node.assign), # NOTE: Needs to dispatch to AssName/AssTuple/AssList with an expression.
2.781 + self.dispatch(node.list),
2.782 + [self.dispatch(n) for n in node.ifs]
2.783 + )
2.784 +
2.785 + def visitListCompIf(self, node):
2.786 + return compiler.ast.ListCompIf(
2.787 + self.dispatch(node.test)
2.788 + )
2.789 +
2.790 + def visitMod(self, node):
2.791 + return self._visitBinary(node)
2.792 +
2.793 + def visitMul(self, node):
2.794 + return self._visitBinary(node)
2.795 +
2.796 + def visitName(self, node, expr=None):
2.797 + if expr:
2.798 + return self.visitAssName(node, expr)
2.799 +
2.800 + unit = self.get_unit()
2.801 +
2.802 + # Generate appropriate name access operation.
2.803 +
2.804 + scope = getattr(node, "_scope", None)
2.805 + if not scope:
2.806 + attr, scope, from_name = self.get_unit()._get_with_scope(node.name)
2.807 +
2.808 + if scope == "constant":
2.809 + return node
2.810 + elif scope == "local":
2.811 +
2.812 + # Function locals are referenced normally.
2.813 +
2.814 + if isinstance(unit, Function):
2.815 + return node
2.816 +
2.817 + # Class locals are class attribute references.
2.818 + # Module locals are module attribute references.
2.819 +
2.820 + elif isinstance(unit, (Class, Module)):
2.821 + return compiler.ast.CallFunc(
2.822 + special_name("__loadaddress__"),
2.823 + [quoted_name(unit.full_name()), special_name(node.name)]
2.824 + )
2.825 + else:
2.826 + raise TranslateError("Program unit has no local %r." % name)
2.827 +
2.828 + elif scope == "global":
2.829 +
2.830 + # Globals are references to module attributes.
2.831 +
2.832 + return compiler.ast.CallFunc(
2.833 + special_name("__loadaddress__"),
2.834 + [quoted_name(self.get_module().full_name()), special_name(node.name)]
2.835 + )
2.836 +
2.837 + elif scope == "builtin":
2.838 +
2.839 + # Builtins are accessed via the __builtins__ module.
2.840 +
2.841 + return compiler.ast.CallFunc(
2.842 + special_name("__loadaddress__"),
2.843 + [special_name("__builtins__"), special_name(node.name)]
2.844 + )
2.845 +
2.846 + else:
2.847 + # NOTE: This may happen because a class attribute is optimised away.
2.848 + return compiler.ast.CallFunc(
2.849 + special_name("__loadunknown__"),
2.850 + [special_name(node.name)]
2.851 + )
2.852 +
2.853 + def visitNot(self, node):
2.854 + return compiler.ast.Not(self.dispatch(node.expr))
2.855 +
2.856 + def visitOr(self, node):
2.857 + return compiler.ast.Or([self.dispatch(n) for n in node.nodes])
2.858 +
2.859 + def visitPower(self, node):
2.860 + return self._visitBinary(node)
2.861 +
2.862 + def visitRightShift(self, node):
2.863 + return self._visitBinary(node)
2.864 +
2.865 + def visitSlice(self, node, expr=None):
2.866 + return compiler.ast.CallFunc(
2.867 + module_attribute("operator", expr and "setslice" or "getslice"),
2.868 + [self.dispatch(node.expr), node.lower and self.dispatch(node.lower), node.upper and self.dispatch(node.upper)]
2.869 + + (expr and [expr] or [])
2.870 + )
2.871 +
2.872 + def visitSliceobj(self, node):
2.873 + return compiler.ast.Sliceobj([self.dispatch(n) for n in node.nodes])
2.874 +
2.875 + def visitSub(self, node):
2.876 + return self._visitBinary(node)
2.877 +
2.878 + def visitSubscript(self, node, expr=None):
2.879 + return compiler.ast.CallFunc(
2.880 + module_attribute("operator", expr and "setitem" or "getitem"),
2.881 + [self.dispatch(node.expr), compiler.ast.Tuple([self.dispatch(sub) for sub in node.subs])]
2.882 + + (expr and [expr] or [])
2.883 + )
2.884 +
2.885 + def visitTuple(self, node, expr=None):
2.886 + if expr:
2.887 + return self.visitAssTuple(node, expr)
2.888 + return compiler.ast.Tuple([self.dispatch(n) for n in node.nodes])
2.889 +
2.890 + def visitUnaryAdd(self, node):
2.891 + return self._visitUnary(node)
2.892 +
2.893 + def visitUnarySub(self, node):
2.894 + return self._visitUnary(node)
2.895 +
2.896 + # Type-related methods.
2.897 +
2.898 + def possible_accessor_types(self, node, defining_users=1):
2.899 + return set([tn for (tn, st) in ASTVisitor.possible_accessor_types(self, node, defining_users)])
2.900 +
2.901 + def get_possible_types(self, attrname):
2.902 + objtable = self.program.get_object_table()
2.903 + return objtable.any_possible_objects([attrname])
2.904 +
2.905 + def get_attributes(self, possible_types, attrname):
2.906 + objtable = self.program.get_object_table()
2.907 + attributes = []
2.908 + for target_name in possible_types:
2.909 + target = objtable.get_object(target_name)
2.910 + try:
2.911 + attr = objtable.access(target_name, attrname)
2.912 + except TableError:
2.913 + continue
2.914 + if attr.is_static_attribute():
2.915 + for v in attr.get_values():
2.916 + attributes.append((v, target, target_name))
2.917 + else:
2.918 + attributes.append((None, target, target_name))
2.919 +
2.920 + return attributes
2.921 +
2.922 +# Convenience functions.
2.923 +
2.924 +def convert(module, program, filename):
2.925 + stream = open(filename, "wb")
2.926 + try:
2.927 + source = ConvertedSource(module, program)
2.928 + source.to_stream(stream)
2.929 + finally:
2.930 + stream.close()
2.931 +
2.932 +def translate(program, directory):
2.933 + if not exists(directory):
2.934 + os.mkdir(directory)
2.935 +
2.936 + # NOTE: Add constants here.
2.937 +
2.938 + for module in program.get_importer().get_modules():
2.939 + convert(module, program, join(directory, "%s%spy" % (module.full_name(), extsep)))
2.940 +
2.941 +# vim: tabstop=4 expandtab shiftwidth=4