1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/micropython/syspython.py Tue Mar 12 00:09:48 2013 +0100
1.3 @@ -0,0 +1,938 @@
1.4 +#!/usr/bin/env python
1.5 +
1.6 +"""
1.7 +Produce syspython code from an inspected program.
1.8 +
1.9 +Copyright (C) 2006, 2007, 2010, 2011, 2012, 2013 Paul Boddie <paul@boddie.org.uk>
1.10 +
1.11 +This program is free software; you can redistribute it and/or modify it under
1.12 +the terms of the GNU General Public License as published by the Free Software
1.13 +Foundation; either version 3 of the License, or (at your option) any later
1.14 +version.
1.15 +
1.16 +This program is distributed in the hope that it will be useful, but WITHOUT
1.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.19 +details.
1.20 +
1.21 +You should have received a copy of the GNU General Public License along with
1.22 +this program. If not, see <http://www.gnu.org/licenses/>.
1.23 +"""
1.24 +
1.25 +from micropython.common import *
1.26 +from micropython.data import *
1.27 +from micropython.errors import *
1.28 +from os.path import exists, extsep, join
1.29 +import compiler.ast
1.30 +import sys
1.31 +import os
1.32 +
1.33 +try:
1.34 + set
1.35 +except NameError:
1.36 + from sets import Set as set
1.37 +
1.38 +# Convenience definitions.
1.39 +
1.40 +module_attribute = compiler.ast.Getattr
1.41 +special_name = compiler.ast.Name
1.42 +quoted_name = compiler.ast.Const
1.43 +
1.44 +# Source code classes.
1.45 +
1.46 +class ConvertedSource(ASTVisitor):
1.47 +
1.48 + "A conversion of module source code to syspython."
1.49 +
1.50 + def __init__(self, module, program):
1.51 + self.visitor = self
1.52 + self.module = module
1.53 + self.program = program
1.54 + self.in_main = False
1.55 + self.units = []
1.56 +
1.57 + def get_unit(self):
1.58 + return self.units[-1]
1.59 +
1.60 + def get_module(self):
1.61 + return self.units[0]
1.62 +
1.63 + def to_stream(self, stream):
1.64 +
1.65 + "Write the converted code to the given 'stream'."
1.66 +
1.67 + module = self.dispatch(self.module.astnode)
1.68 + stream.write(str(module))
1.69 +
1.70 + def NOP(self, node):
1.71 + return node
1.72 +
1.73 + def visitModule(self, node):
1.74 + module = node.unit
1.75 + self.units.append(module)
1.76 +
1.77 + definitions = self._findDefinitions(node)
1.78 +
1.79 + # __globalnames__(name, ...)
1.80 +
1.81 + globalnames = module.module_attribute_names() and [
1.82 + compiler.ast.CallFunc(
1.83 + special_name("__globalnames__"),
1.84 + [special_name(name) for name in module.module_attribute_names()]
1.85 + )
1.86 + ] or []
1.87 +
1.88 + # def __main__():
1.89 + # ...
1.90 +
1.91 + self.in_main = True
1.92 +
1.93 + main = compiler.ast.Function(
1.94 + [], "__main__", [], [], 0, "Module initialisation.",
1.95 + compiler.ast.Stmt(globalnames + self.dispatch(node.node).nodes)
1.96 + )
1.97 +
1.98 + self.in_main = False
1.99 + self.units.pop()
1.100 +
1.101 + return compiler.ast.Module(node.doc, compiler.ast.Stmt(definitions + [main]))
1.102 +
1.103 + def _findDefinitions(self, node):
1.104 + definitions = []
1.105 + for n in node.getChildNodes():
1.106 + if isinstance(n, (compiler.ast.Class, compiler.ast.Function)):
1.107 + definitions.append(self.dispatch(n))
1.108 + else:
1.109 + definitions += self._findDefinitions(n)
1.110 + return definitions
1.111 +
1.112 + # Statements.
1.113 +
1.114 + def visitAssert(self, node):
1.115 + return compiler.ast.Assert(self.dispatch(node.test), node.fail and self.dispatch(node.fail))
1.116 +
1.117 + def visitAssign(self, node):
1.118 + expr = self.dispatch(node.expr)
1.119 + return compiler.ast.Stmt([self.dispatch(n, expr) for n in node.nodes])
1.120 +
1.121 + def visitAugAssign(self, node):
1.122 +
1.123 + # lvalue = op(lvalue, expr)
1.124 + # -> __fn__(lvalue, op(lvalue, expr))
1.125 +
1.126 + op_name = operator_functions[node.op]
1.127 +
1.128 + return self.dispatch(node.node, compiler.ast.CallFunc(
1.129 + module_attribute("operator", op_name),
1.130 + [self.dispatch(node.node), self.dispatch(node.expr)]
1.131 + ))
1.132 +
1.133 + visitBreak = NOP
1.134 +
1.135 + def visitClass(self, node):
1.136 + if not used_by_unit(node):
1.137 + return compiler.ast.Stmt([])
1.138 +
1.139 + self.units.append(node.unit)
1.140 + try:
1.141 + # Incorporate class body code in the main function.
1.142 +
1.143 + if self.in_main:
1.144 + return self.dispatch(node.code)
1.145 + else:
1.146 + return self._visitClassDefinition(node)
1.147 +
1.148 + finally:
1.149 + self.units.pop()
1.150 +
1.151 + def _visitClassDefinition(self, node):
1.152 + cls = node.unit
1.153 +
1.154 + # __instattrs__(name, ...)
1.155 + # __clsattrs__(name, ...)
1.156 +
1.157 + instattrs = cls.instance_attribute_names() and [
1.158 + compiler.ast.CallFunc(
1.159 + special_name("__instattrs__"),
1.160 + [special_name(name) for name in cls.instance_attribute_names()]
1.161 + )
1.162 + ] or []
1.163 +
1.164 + clsattrs = cls.class_attribute_names() and [
1.165 + compiler.ast.CallFunc(
1.166 + special_name("__clsattrs__"),
1.167 + [special_name(name) for name in cls.class_attribute_names()]
1.168 + )
1.169 + ] or []
1.170 +
1.171 + # __inherited__(superclass, name, ...)
1.172 + # ...
1.173 +
1.174 + attrs_by_cls = {}
1.175 + for attrname, attr in cls.all_class_attributes().items():
1.176 + supercls = attr.parent
1.177 + if supercls is cls:
1.178 + continue
1.179 + if not attrs_by_cls.has_key(supercls):
1.180 + attrs_by_cls[supercls] = []
1.181 + attrs_by_cls[supercls].append(attrname)
1.182 +
1.183 + inherited = []
1.184 +
1.185 + for supercls, attrnames in attrs_by_cls.items():
1.186 + inherited.append(
1.187 + compiler.ast.CallFunc(
1.188 + special_name("__inherited__"),
1.189 + [special_name(supercls.full_name())] + [special_name(name) for name in attrnames]
1.190 + ))
1.191 +
1.192 + # __descendants__(name, ...)
1.193 +
1.194 + descendants = cls.all_descendants() and [
1.195 + compiler.ast.CallFunc(
1.196 + special_name("__descendants__"),
1.197 + [special_name(name) for name in cls.all_descendants().keys()]
1.198 + )
1.199 + ] or []
1.200 +
1.201 + # Process all the definitions defined inside the class.
1.202 +
1.203 + definitions = self._findDefinitions(node)
1.204 +
1.205 + return compiler.ast.Class(node.name, [], node.doc,
1.206 + compiler.ast.Stmt(instattrs + clsattrs + inherited + descendants + definitions)
1.207 + )
1.208 +
1.209 + visitContinue = NOP
1.210 +
1.211 + def visitDiscard(self, node):
1.212 + return compiler.ast.Discard(self.dispatch(node.expr))
1.213 +
1.214 + def visitFor(self, node):
1.215 +
1.216 + """
1.217 + Convert from...
1.218 +
1.219 + for <assign> in <list>:
1.220 + <body>
1.221 + [ else:
1.222 + <else_> ]
1.223 +
1.224 + ...to...
1.225 +
1.226 + _it = iter(<list>)
1.227 + while True:
1.228 + try:
1.229 + <assign> = _it.next()
1.230 + except StopIteration:
1.231 + [ <else_> ]
1.232 + break
1.233 + else:
1.234 + <body>
1.235 + """
1.236 +
1.237 + unit = self.get_unit()
1.238 + temp = quoted_name(unit.temp_usage)
1.239 + unit.temp_usage += 1
1.240 +
1.241 + else_nodes = node.else_ and self.dispatch(node.else_).nodes or []
1.242 +
1.243 + return compiler.ast.Stmt([
1.244 + # __storetemp__(_it, __loadaddress__(__builtins__, iter)(<list>))
1.245 + compiler.ast.CallFunc(special_name("__storetemp__"), [
1.246 + temp,
1.247 + compiler.ast.CallFunc(
1.248 + compiler.ast.CallFunc(special_name("__loadaddress__"),
1.249 + [special_name("__builtins__"), special_name("iter")]
1.250 + ),
1.251 + [self.dispatch(node.list)]
1.252 + )
1.253 + ]),
1.254 + # while True: ...
1.255 + compiler.ast.While(
1.256 + special_name("True"),
1.257 + # try: ...
1.258 + compiler.ast.TryExcept(
1.259 + compiler.ast.Stmt([
1.260 + # <assign> = ...
1.261 + self.dispatch(node.assign,
1.262 + # _it.next()
1.263 + compiler.ast.CallFunc(
1.264 + compiler.ast.CallFunc(special_name("__loadattr__"), [
1.265 + compiler.ast.CallFunc(special_name("__loadtemp__"), [temp]),
1.266 + special_name("next")
1.267 + ]),
1.268 + []
1.269 + )
1.270 + )
1.271 + ]),
1.272 + # except StopIteration: ...
1.273 + [(special_name("StopIteration"), None, compiler.ast.Stmt(else_nodes + [compiler.ast.Break()]))],
1.274 + # else: ...
1.275 + self.dispatch(node.body)
1.276 + ),
1.277 + None
1.278 + )
1.279 + ])
1.280 +
1.281 + def visitFrom(self, node):
1.282 +
1.283 + # Generate __main__ function calls for each step in the imported module
1.284 + # hierarchy.
1.285 +
1.286 + statements = []
1.287 +
1.288 + for modname in self.module.get_module_paths(node.modname):
1.289 + statements.append(
1.290 + compiler.ast.CallFunc(special_name("%s.__main__" % modname ), [])
1.291 + )
1.292 +
1.293 + for name, alias in node.names:
1.294 + statements.append(
1.295 + compiler.ast.Assign(
1.296 + [special_name(alias or name)],
1.297 + compiler.ast.CallFunc(
1.298 + special_name("__loadattribute__"),
1.299 + [special_name(node.modname), special_name(name)]
1.300 + )
1.301 + )
1.302 + )
1.303 +
1.304 + return compiler.ast.Stmt(statements)
1.305 +
1.306 + def visitFunction(self, node):
1.307 + if not used_by_unit(node):
1.308 + return compiler.ast.Stmt([])
1.309 +
1.310 + self.units.append(node.unit)
1.311 +
1.312 + try:
1.313 + # Ignore functions when generating the main function.
1.314 +
1.315 + if self.in_main:
1.316 + return compiler.ast.Stmt([])
1.317 + else:
1.318 + return self._visitFunctionDefinition(node)
1.319 + finally:
1.320 + self.units.pop()
1.321 +
1.322 + def _visitFunctionDefinition(self, node):
1.323 + fn = node.unit
1.324 +
1.325 + # __localnames__(name, ...)
1.326 + # __globalnames__(name, ...)
1.327 +
1.328 + localnames = fn.locals() and [
1.329 + compiler.ast.CallFunc(
1.330 + special_name("__localnames__"),
1.331 + [special_name(name) for name in fn.locals().keys()]
1.332 + )
1.333 + ] or []
1.334 +
1.335 + globalnames = fn.globals and [
1.336 + compiler.ast.CallFunc(
1.337 + special_name("__globalnames__"),
1.338 + [special_name(name) for name in fn.globals]
1.339 + )
1.340 + ] or []
1.341 +
1.342 + defaults = [self.dispatch(n) for n in node.defaults]
1.343 +
1.344 + code = self.dispatch(node.code)
1.345 +
1.346 + return compiler.ast.Function(node.decorators, node.name, node.argnames, defaults, node.flags, node.doc,
1.347 + compiler.ast.Stmt(localnames + globalnames + code.nodes))
1.348 +
1.349 + visitGlobal = NOP
1.350 +
1.351 + def visitIf(self, node):
1.352 + return compiler.ast.If(
1.353 + [(self.dispatch(compare), self.dispatch(stmt)) for (compare, stmt) in node.tests],
1.354 + node.else_ and self.dispatch(node.else_)
1.355 + )
1.356 +
1.357 + def visitImport(self, node):
1.358 +
1.359 + # Generate __main__ function calls for each step in the imported module
1.360 + # hierarchy.
1.361 +
1.362 + statements = []
1.363 +
1.364 + for name, alias in node.names:
1.365 + for modname in self.module.get_module_paths(name):
1.366 + statements.append(
1.367 + compiler.ast.CallFunc(compiler.ast.Getattr(modname, "__main__"), [])
1.368 + )
1.369 +
1.370 + statements.append(
1.371 + compiler.ast.Assign(
1.372 + [special_name(alias or name.split(".")[0])],
1.373 + compiler.ast.CallFunc(
1.374 + special_name("__static__"),
1.375 + [special_name(name)]
1.376 + )
1.377 + )
1.378 + )
1.379 +
1.380 + return compiler.ast.Stmt(statements)
1.381 +
1.382 + visitPass = NOP
1.383 +
1.384 + def visitPrint(self, node):
1.385 + return compiler.ast.Print(
1.386 + [self.dispatch(n) for n in node.nodes],
1.387 + node.dest and self.dispatch(node.dest)
1.388 + )
1.389 +
1.390 + def visitPrintnl(self, node):
1.391 + return compiler.ast.Print(
1.392 + [self.dispatch(n) for n in node.nodes],
1.393 + node.dest and self.dispatch(node.dest)
1.394 + )
1.395 +
1.396 + def visitRaise(self, node):
1.397 + return compiler.ast.Raise(
1.398 + node.expr1 and self.dispatch(node.expr1),
1.399 + node.expr2 and self.dispatch(node.expr2),
1.400 + node.expr3 and self.dispatch(node.expr3)
1.401 + )
1.402 +
1.403 + def visitReturn(self, node):
1.404 + return compiler.ast.Return(self.dispatch(node.value))
1.405 +
1.406 + def visitStmt(self, node):
1.407 + return compiler.ast.Stmt([self.dispatch(n) for n in node.nodes])
1.408 +
1.409 + def visitTryExcept(self, node):
1.410 + # NOTE: Need to dispatch to the assignment with the exception.
1.411 + return compiler.ast.TryExcept(
1.412 + self.dispatch(node.body),
1.413 + [(spec and self.dispatch(spec), assign and self.dispatch(assign), self.dispatch(statement))
1.414 + for spec, assign, statement in node.handlers],
1.415 + node.else_ and self.dispatch(node.else_)
1.416 + )
1.417 +
1.418 + def visitTryFinally(self, node):
1.419 + return compiler.ast.TryFinally(
1.420 + self.dispatch(node.body),
1.421 + self.dispatch(node.final)
1.422 + )
1.423 +
1.424 + def visitWhile(self, node):
1.425 + return compiler.ast.While(
1.426 + self.dispatch(node.test),
1.427 + self.dispatch(node.body),
1.428 + node.else_ and self.dispatch(node.else_)
1.429 + )
1.430 +
1.431 + def visitYield(self, node):
1.432 + return compiler.ast.Yield(self.dispatch(node.value))
1.433 +
1.434 + # Expression-related helper methods.
1.435 +
1.436 + def _visitBitBinary(self, node):
1.437 + op_name = operator_functions[node.__class__.__name__]
1.438 + last = self.dispatch(node.nodes[0])
1.439 +
1.440 + for n in node.nodes[1:]:
1.441 + last = compiler.ast.CallFunc(
1.442 + module_attribute("operator", op_name),
1.443 + [last, self.dispatch(n)]
1.444 + )
1.445 +
1.446 + return last
1.447 +
1.448 + def _visitBinary(self, node):
1.449 + op_name = operator_functions[node.__class__.__name__]
1.450 +
1.451 + return compiler.ast.CallFunc(
1.452 + module_attribute("operator", op_name),
1.453 + [self.dispatch(node.left), self.dispatch(node.right)]
1.454 + )
1.455 +
1.456 + def _visitUnary(self, node):
1.457 + op_name = operator_functions[node.__class__.__name__]
1.458 +
1.459 + return compiler.ast.CallFunc(
1.460 + module_attribute("operator", op_name),
1.461 + [self.dispatch(node.expr)]
1.462 + )
1.463 +
1.464 + # Expressions.
1.465 +
1.466 + def visitAdd(self, node):
1.467 + return self._visitBinary(node)
1.468 +
1.469 + def visitAnd(self, node):
1.470 + return compiler.ast.And([self.dispatch(n) for n in node.nodes])
1.471 +
1.472 + def visitAssAttr(self, node, expr):
1.473 + possible_types = self.possible_accessor_types(node, defining_users=0)
1.474 +
1.475 + # NOTE: Derived from Getattr support.
1.476 +
1.477 + accessor = self.dispatch(node.expr)
1.478 +
1.479 + # NOTE: Replicate the _generateAttr logic.
1.480 + # NOTE: Should be able to store concrete value details on generated
1.481 + # NOTE: nodes, such as whether an expression yields a constant.
1.482 +
1.483 + # NOTE: Known targets:
1.484 + # NOTE: __storeaddress__ and __storeaddresscontext__
1.485 +
1.486 + # NOTE: Attributes of self.
1.487 +
1.488 + # Usage observations.
1.489 +
1.490 + possible_types = self.possible_accessor_types(node, defining_users=0)
1.491 +
1.492 + # Record whether types were already deduced. If not, get types using
1.493 + # only this attribute.
1.494 +
1.495 + if not possible_types:
1.496 + possible_types = self.get_possible_types(node.attrname)
1.497 +
1.498 + attributes = self.get_attributes(possible_types, node.attrname)
1.499 +
1.500 + # Generate optimisations where only a single attribute applies.
1.501 +
1.502 + if len(attributes) == 1:
1.503 + value, target, target_name = attributes[0]
1.504 +
1.505 + # Static attributes.
1.506 +
1.507 + if value is not None:
1.508 +
1.509 + # Static attributes may be accompanied by a different context
1.510 + # depending on the accessor.
1.511 + # NOTE: Should determine whether the context is always replaced.
1.512 +
1.513 + return compiler.ast.CallFunc(
1.514 + special_name("__storeaddresscontextcond__"),
1.515 + [accessor, special_name(node.attrname), expr]
1.516 + )
1.517 +
1.518 + # Non-static attributes.
1.519 +
1.520 + return compiler.ast.CallFunc(
1.521 + special_name("__storeattr__"),
1.522 + [accessor, special_name(node.attrname), expr]
1.523 + )
1.524 +
1.525 + # With no usable deductions, generate a table-based access.
1.526 +
1.527 + return compiler.ast.CallFunc(
1.528 + special_name("__storeattrindex__"),
1.529 + [accessor, special_name(node.attrname), expr]
1.530 + )
1.531 +
1.532 + def visitAssList(self, node, expr):
1.533 + return compiler.ast.Stmt([
1.534 + self.dispatch(n, compiler.ast.CallFunc(
1.535 + module_attribute("operator", "getitem"),
1.536 + [expr, i]
1.537 + ))
1.538 + for (i, n) in enumerate(node.nodes)
1.539 + ])
1.540 +
1.541 + def visitAssName(self, node, expr):
1.542 + unit = self.get_unit()
1.543 +
1.544 + # Generate appropriate name access operation.
1.545 +
1.546 + scope = getattr(node, "_scope", None)
1.547 + if not scope:
1.548 + attr, scope, from_name = self.get_unit()._get_with_scope(node.name)
1.549 +
1.550 + if scope == "constant":
1.551 + return node
1.552 + elif scope == "local":
1.553 +
1.554 + # Function locals are stored using a function.
1.555 +
1.556 + if isinstance(unit, Function):
1.557 + return compiler.ast.CallFunc(
1.558 + special_name("__storelocal__"),
1.559 + [special_name(node.name), expr]
1.560 + )
1.561 +
1.562 + # Class locals are class attribute references.
1.563 +
1.564 + elif isinstance(unit, Class):
1.565 + return compiler.ast.CallFunc(
1.566 + special_name("__storeaddresscontext__"),
1.567 + [quoted_name(unit.full_name()), special_name(node.name), expr]
1.568 + )
1.569 +
1.570 + # Module locals are module attribute references.
1.571 +
1.572 + elif isinstance(unit, Module):
1.573 + return compiler.ast.CallFunc(
1.574 + special_name("__storeaddress__"),
1.575 + [quoted_name(unit.full_name()), special_name(node.name), expr]
1.576 + )
1.577 + else:
1.578 + raise TranslateError("Program unit has no local %r." % name)
1.579 +
1.580 + elif scope == "global":
1.581 +
1.582 + # Globals are references to module attributes.
1.583 +
1.584 + return compiler.ast.CallFunc(
1.585 + special_name("__storeaddress__"),
1.586 + [quoted_name(self.get_module().full_name()), special_name(node.name), expr]
1.587 + )
1.588 +
1.589 + elif scope == "builtin":
1.590 +
1.591 + # Builtins are accessed via the __builtins__ module.
1.592 +
1.593 + return compiler.ast.CallFunc(
1.594 + special_name("__storeaddress__"),
1.595 + [special_name("__builtins__"), special_name(node.name), expr]
1.596 + )
1.597 +
1.598 + else:
1.599 + # NOTE: This may happen because a class attribute is optimised away.
1.600 + return compiler.ast.CallFunc(
1.601 + special_name("__storeunknown__"),
1.602 + [special_name(node.name), expr]
1.603 + )
1.604 +
1.605 + visitAssTuple = visitAssList
1.606 +
1.607 + def visitBitand(self, node):
1.608 + self._visitBitBinary(node)
1.609 +
1.610 + def visitBitor(self, node):
1.611 + self._visitBitBinary(node)
1.612 +
1.613 + def visitBitxor(self, node):
1.614 + self._visitBitBinary(node)
1.615 +
1.616 + def visitCallFunc(self, node):
1.617 + return compiler.ast.CallFunc(
1.618 + self.dispatch(node.node),
1.619 + [self.dispatch(arg) for arg in node.args],
1.620 + node.star_args and [self.dispatch(arg) for arg in node.star_args],
1.621 + node.dstar_args and [self.dispatch(arg) for arg in node.dstar_args]
1.622 + )
1.623 +
1.624 + def visitCompare(self, node):
1.625 + nodes = []
1.626 + left = node.expr
1.627 + for op_name, right in node.ops:
1.628 + nodes.append(
1.629 + compiler.ast.CallFunc(
1.630 + module_attribute("operator", operator_functions.get(op_name)),
1.631 + [self.dispatch(left), self.dispatch(right)]
1.632 + )
1.633 + )
1.634 + left = right
1.635 + return compiler.ast.And(nodes)
1.636 +
1.637 + visitConst = NOP
1.638 +
1.639 + def visitDict(self, node):
1.640 + return compiler.ast.Dict([(self.dispatch(key), self.dispatch(value)) for (key, value) in node.items])
1.641 +
1.642 + def visitDiv(self, node):
1.643 + return self._visitBinary(node)
1.644 +
1.645 + def visitFloorDiv(self, node):
1.646 + return self._visitBinary(node)
1.647 +
1.648 + def visitGetattr(self, node, expr=None):
1.649 + if expr:
1.650 + return self.visitAssAttr(node, expr)
1.651 +
1.652 + accessor = self.dispatch(node.expr)
1.653 +
1.654 + # NOTE: Replicate the _generateAttr logic.
1.655 + # NOTE: Should be able to store concrete value details on generated
1.656 + # NOTE: nodes, such as whether an expression yields a constant.
1.657 +
1.658 + # NOTE: Known targets:
1.659 + # NOTE: class.__class__ => __builtins__.type
1.660 + # NOTE: __loadaddress__ and __loadaddresscontext__
1.661 +
1.662 + # NOTE: Attributes of self.
1.663 +
1.664 + # Usage observations.
1.665 +
1.666 + possible_types = self.possible_accessor_types(node, defining_users=0)
1.667 +
1.668 + # Record whether types were already deduced. If not, get types using
1.669 + # only this attribute.
1.670 +
1.671 + if not possible_types:
1.672 + possible_types = self.get_possible_types(node.attrname)
1.673 +
1.674 + attributes = self.get_attributes(possible_types, node.attrname)
1.675 +
1.676 + # Generate optimisations where only a single attribute applies.
1.677 +
1.678 + if len(attributes) == 1:
1.679 + value, target, target_name = attributes[0]
1.680 +
1.681 + # Static attributes.
1.682 +
1.683 + if value is not None:
1.684 +
1.685 + # class.__class__ => __builtins__.type
1.686 +
1.687 + if node.attrname == "__class__":
1.688 + return compiler.ast.CallFunc(
1.689 + special_name("__loadaddress__"),
1.690 + [special_name("__builtins__"), special_name("type")]
1.691 + )
1.692 +
1.693 + # Static attributes may be accompanied by a different context
1.694 + # depending on the accessor.
1.695 + # NOTE: Should determine whether the context is always replaced.
1.696 +
1.697 + return compiler.ast.CallFunc(
1.698 + special_name("__loadaddresscontextcond__"),
1.699 + [accessor, special_name(node.attrname)]
1.700 + )
1.701 +
1.702 + # Non-static attributes.
1.703 +
1.704 + return compiler.ast.CallFunc(
1.705 + special_name("__loadattr__"),
1.706 + [accessor, special_name(node.attrname)]
1.707 + )
1.708 +
1.709 + # With no usable deductions, generate a table-based access.
1.710 +
1.711 + return compiler.ast.CallFunc(
1.712 + special_name("__loadattrindex__"),
1.713 + [accessor, special_name(node.attrname)]
1.714 + )
1.715 +
1.716 + def visitGenExpr(self, node):
1.717 + return compiler.ast.GenExpr(self.dispatch(node.code))
1.718 +
1.719 + def visitGenExprFor(self, node):
1.720 + return compiler.ast.GenExprFor(
1.721 + self.dispatch(node.assign), # NOTE: Needs to dispatch to AssName/AssTuple/AssList with an expression.
1.722 + self.dispatch(node.iter),
1.723 + [self.dispatch(n) for n in node.ifs]
1.724 + )
1.725 +
1.726 + def visitGenExprIf(self, node):
1.727 + return compiler.ast.GenExprIf(self.dispatch(node.test))
1.728 +
1.729 + def visitGenExprInner(self, node):
1.730 + return compiler.ast.GenExprInner(
1.731 + self.dispatch(node.expr),
1.732 + [self.dispatch(n) for n in node.quals]
1.733 + )
1.734 +
1.735 + def visitIfExp(self, node):
1.736 + return compiler.ast.IfExp(
1.737 + self.dispatch(node.then),
1.738 + self.dispatch(node.test),
1.739 + self.dispatch(node.else_)
1.740 + )
1.741 +
1.742 + def visitInvert(self, node):
1.743 + return self._visitUnary(node)
1.744 +
1.745 + def visitKeyword(self, node):
1.746 + return compiler.ast.Keyword(
1.747 + node.name,
1.748 + self.dispatch(node.expr)
1.749 + )
1.750 +
1.751 + def visitLambda(self, node):
1.752 + self.units.append(node.unit)
1.753 +
1.754 + try:
1.755 + return compiler.ast.Lambda(
1.756 + node.argnames,
1.757 + [self.dispatch(n) for n in node.defaults],
1.758 + node.flags,
1.759 + self.dispatch(node.code)
1.760 + )
1.761 + finally:
1.762 + self.units.pop()
1.763 +
1.764 + def visitLeftShift(self, node):
1.765 + return self._visitBinary(node)
1.766 +
1.767 + def visitList(self, node, expr=None):
1.768 + if expr:
1.769 + return self.visitAssList(node, expr)
1.770 + return compiler.ast.List([self.dispatch(n) for n in node.nodes])
1.771 +
1.772 + def visitListComp(self, node):
1.773 + return compiler.ast.ListComp(
1.774 + self.dispatch(node.expr),
1.775 + [self.dispatch(n) for n in node.quals]
1.776 + )
1.777 +
1.778 + def visitListCompFor(self, node):
1.779 + return compiler.ast.ListCompFor(
1.780 + self.dispatch(node.assign), # NOTE: Needs to dispatch to AssName/AssTuple/AssList with an expression.
1.781 + self.dispatch(node.list),
1.782 + [self.dispatch(n) for n in node.ifs]
1.783 + )
1.784 +
1.785 + def visitListCompIf(self, node):
1.786 + return compiler.ast.ListCompIf(
1.787 + self.dispatch(node.test)
1.788 + )
1.789 +
1.790 + def visitMod(self, node):
1.791 + return self._visitBinary(node)
1.792 +
1.793 + def visitMul(self, node):
1.794 + return self._visitBinary(node)
1.795 +
1.796 + def visitName(self, node, expr=None):
1.797 + if expr:
1.798 + return self.visitAssName(node, expr)
1.799 +
1.800 + unit = self.get_unit()
1.801 +
1.802 + # Generate appropriate name access operation.
1.803 +
1.804 + scope = getattr(node, "_scope", None)
1.805 + if not scope:
1.806 + attr, scope, from_name = self.get_unit()._get_with_scope(node.name)
1.807 +
1.808 + if scope == "constant":
1.809 + return node
1.810 + elif scope == "local":
1.811 +
1.812 + # Function locals are referenced normally.
1.813 +
1.814 + if isinstance(unit, Function):
1.815 + return node
1.816 +
1.817 + # Class locals are class attribute references.
1.818 + # Module locals are module attribute references.
1.819 +
1.820 + elif isinstance(unit, (Class, Module)):
1.821 + return compiler.ast.CallFunc(
1.822 + special_name("__loadaddress__"),
1.823 + [quoted_name(unit.full_name()), special_name(node.name)]
1.824 + )
1.825 + else:
1.826 + raise TranslateError("Program unit has no local %r." % name)
1.827 +
1.828 + elif scope == "global":
1.829 +
1.830 + # Globals are references to module attributes.
1.831 +
1.832 + return compiler.ast.CallFunc(
1.833 + special_name("__loadaddress__"),
1.834 + [quoted_name(self.get_module().full_name()), special_name(node.name)]
1.835 + )
1.836 +
1.837 + elif scope == "builtin":
1.838 +
1.839 + # Builtins are accessed via the __builtins__ module.
1.840 +
1.841 + return compiler.ast.CallFunc(
1.842 + special_name("__loadaddress__"),
1.843 + [special_name("__builtins__"), special_name(node.name)]
1.844 + )
1.845 +
1.846 + else:
1.847 + # NOTE: This may happen because a class attribute is optimised away.
1.848 + return compiler.ast.CallFunc(
1.849 + special_name("__loadunknown__"),
1.850 + [special_name(node.name)]
1.851 + )
1.852 +
1.853 + def visitNot(self, node):
1.854 + return compiler.ast.Not(self.dispatch(node.expr))
1.855 +
1.856 + def visitOr(self, node):
1.857 + return compiler.ast.Or([self.dispatch(n) for n in node.nodes])
1.858 +
1.859 + def visitPower(self, node):
1.860 + return self._visitBinary(node)
1.861 +
1.862 + def visitRightShift(self, node):
1.863 + return self._visitBinary(node)
1.864 +
1.865 + def visitSlice(self, node, expr=None):
1.866 + return compiler.ast.CallFunc(
1.867 + module_attribute("operator", expr and "setslice" or "getslice"),
1.868 + [self.dispatch(node.expr), node.lower and self.dispatch(node.lower), node.upper and self.dispatch(node.upper)]
1.869 + + (expr and [expr] or [])
1.870 + )
1.871 +
1.872 + def visitSliceobj(self, node):
1.873 + return compiler.ast.Sliceobj([self.dispatch(n) for n in node.nodes])
1.874 +
1.875 + def visitSub(self, node):
1.876 + return self._visitBinary(node)
1.877 +
1.878 + def visitSubscript(self, node, expr=None):
1.879 + return compiler.ast.CallFunc(
1.880 + module_attribute("operator", expr and "setitem" or "getitem"),
1.881 + [self.dispatch(node.expr), compiler.ast.Tuple([self.dispatch(sub) for sub in node.subs])]
1.882 + + (expr and [expr] or [])
1.883 + )
1.884 +
1.885 + def visitTuple(self, node, expr=None):
1.886 + if expr:
1.887 + return self.visitAssTuple(node, expr)
1.888 + return compiler.ast.Tuple([self.dispatch(n) for n in node.nodes])
1.889 +
1.890 + def visitUnaryAdd(self, node):
1.891 + return self._visitUnary(node)
1.892 +
1.893 + def visitUnarySub(self, node):
1.894 + return self._visitUnary(node)
1.895 +
1.896 + # Type-related methods.
1.897 +
1.898 + def possible_accessor_types(self, node, defining_users=1):
1.899 + return set([tn for (tn, st) in ASTVisitor.possible_accessor_types(self, node, defining_users)])
1.900 +
1.901 + def get_possible_types(self, attrname):
1.902 + objtable = self.program.get_object_table()
1.903 + return objtable.any_possible_objects([attrname])
1.904 +
1.905 + def get_attributes(self, possible_types, attrname):
1.906 + objtable = self.program.get_object_table()
1.907 + attributes = []
1.908 + for target_name in possible_types:
1.909 + target = objtable.get_object(target_name)
1.910 + try:
1.911 + attr = objtable.access(target_name, attrname)
1.912 + except TableError:
1.913 + continue
1.914 + if attr.is_static_attribute():
1.915 + for v in attr.get_values():
1.916 + attributes.append((v, target, target_name))
1.917 + else:
1.918 + attributes.append((None, target, target_name))
1.919 +
1.920 + return attributes
1.921 +
1.922 +# Convenience functions.
1.923 +
1.924 +def convert(module, program, filename):
1.925 + stream = open(filename, "wb")
1.926 + try:
1.927 + source = ConvertedSource(module, program)
1.928 + source.to_stream(stream)
1.929 + finally:
1.930 + stream.close()
1.931 +
1.932 +def translate(program, directory):
1.933 + if not exists(directory):
1.934 + os.mkdir(directory)
1.935 +
1.936 + # NOTE: Add constants here.
1.937 +
1.938 + for module in program.get_importer().get_modules():
1.939 + convert(module, program, join(directory, "%s%spy" % (module.full_name(), extsep)))
1.940 +
1.941 +# vim: tabstop=4 expandtab shiftwidth=4