# HG changeset patch # User paulb@localhost.localdomain # Date 1165014873 -3600 # Node ID 24ac3f8de5993825d35ca736737b29f84a301972 # Parent 7185f75492b3f36bd8770fbc8b25de7f62256542 Reordered methods. diff -r 7185f75492b3 -r 24ac3f8de599 simplify.py --- a/simplify.py Fri Dec 01 00:32:06 2006 +0100 +++ b/simplify.py Sat Dec 02 00:14:33 2006 +0100 @@ -94,17 +94,6 @@ else: return LoadName(node, name="None") - # Placeholder or deletion transformations. - - def visitDiscard(self, discard): - return self.dispatch(discard.expr) - - def visitPass(self, pass_): - return Pass(pass_, 1) - - def visitStmt(self, stmt): - return self.dispatches(stmt.nodes) - # Top-level transformation. def visitModule(self, module, name=None): @@ -139,380 +128,10 @@ result.code = init_code + module_code return result - # Relatively trivial transformations. - - def _visitBuiltin(self, builtin, name): - result = InvokeFunction(builtin, 1, expr=LoadName(name=name), args=self.dispatches(builtin.nodes), star=None, dstar=None) - return result - - def visitBreak(self, break_): - result = ReturnFromBlock(break_, 1) - return result - - def visitConst(self, const): - if not self.constants.has_key(const.value): - self.constants[const.value] = Constant(name=repr(const.value), value=const.value) - result = LoadRef(const, 1, ref=self.constants[const.value]) - return result - - def visitContinue(self, continue_): - result = InvokeBlock(continue_, 1, - expr=LoadRef(ref=self.current_subprograms[-1]) - ) - return result - - def visitDict(self, dict): - result = InvokeFunction(dict, 1, expr=LoadName(name="dict"), star=None, dstar=None) - args = [] - for key, value in dict.items: - tuple = InvokeFunction(expr=LoadName(name="tuple"), star=None, dstar=None) - tuple.set_args([self.dispatch(key), self.dispatch(value)]) - args.append(tuple) - result.set_args(args) - return result - - def visitFrom(self, from_): - result = Assign(from_, 1) - code = [] - code.append(StoreTemp(expr=Import(name=from_.modname))) - for name, alias in from_.names: - code.append( - StoreName( - expr=LoadAttr( - expr=LoadTemp(), - name=name), - name=(alias or name) - ) - ) - code.append(ReleaseTemp()) - result.code = code - return result - - def visitGetattr(self, getattr): - result = LoadAttr(getattr, 1, - name=getattr.attrname, - expr=self.dispatch(getattr.expr) - ) - return result - - def visitGlobal(self, global_): - result = Global(global_, 1, - names=global_.names - ) - return result - - def visitImport(self, import_): - result = Assign(import_, 1) - code = [] - for path, alias in import_.names: - importer = Import(name=path) - top = alias or path.split(".")[0] - code.append(StoreName(expr=importer, name=top)) - result.code = code - return result - - def visitKeyword(self, keyword): - result = Keyword(keyword, 1, - name=keyword.name, - expr=self.dispatch(keyword.expr) - ) - return result - - def visitList(self, list): - return self._visitBuiltin(list, "list") - - def visitName(self, name): - result = LoadName(name, 1, name=name.name) - return result - - def visitRaise(self, raise_): - result = Raise(raise_, 1) - if raise_.expr2 is None: - result.expr = self.dispatch(raise_.expr1) - else: - result.expr = InvokeFunction( - expr=self.dispatch(raise_.expr1), - args=[self.dispatch(raise_.expr2)], - star=None, - dstar=None - ) - if raise_.expr3 is not None: - result.traceback = self.dispatch(raise_.expr3) - else: - result.traceback = None - return result - - def visitReturn(self, return_): - result = ReturnFromFunction(return_, 1, - expr=self.dispatch(return_.value) - ) - return result - - def visitTuple(self, tuple): - return self._visitBuiltin(tuple, "tuple") - - # Logical and comparison operations plus chained statements. - - def visitIf(self, if_): - - """ - Make conditionals for each test from an 'if_' AST node, adding the body - and putting each subsequent test as part of the conditional's else - section. - - Convert... - - If (test/body) - (test/body) - ... - (else/body) - - ...to: - - Conditional (test) -> (body) - (else) -> Conditional (test) -> (body) - (else) -> ... - """ - - - results = nodes = [] - - # Produce something like... - # expr.__bool__() ? body - - first = 1 - for compare, stmt in if_.tests: - - # Set the first as the defining node. - - test = Conditional(if_, first, - test=InvokeFunction( - expr=LoadAttr( - expr=self.dispatch(compare), - name="__bool__" - ), - args=[], - star=None, - dstar=None) - ) - test.body = self.dispatch(stmt) - nodes.append(test) - nodes = test.else_ = [] - first = 0 - - # Add the compound statement from any else clause to the end. - - if if_.else_ is not None: - nodes += self.dispatch(if_.else_) - - result = results[0] - return result - - def visitTryExcept(self, tryexcept): - - """ - Make conditionals for each handler associated with a 'tryexcept' node. - - Convert... - - TryExcept (body) - (else) - (spec/assign/stmt) - ... - - ...to: + # Node transformations. - Try (body) - (else) - (handler) -> Conditional (test) -> (stmt) - (body) -> ... - (else) -> Conditional (test) -> (stmt) - (body) -> ... - (else) -> ... - """ - - result = Try(tryexcept, 1, body=[], else_=[], finally_=[]) - - if tryexcept.body is not None: - result.body = self.dispatch(tryexcept.body) - if tryexcept.else_ is not None: - result.else_ = self.dispatch(tryexcept.else_) - - results = nodes = [] - catch_all = 0 - - for spec, assign, stmt in tryexcept.handlers: - - # If no specification exists, produce an unconditional block. - - if spec is None: - nodes += self.dispatch(stmt) - catch_all = 1 - - # Produce an exception value check. - - else: - test = Conditional( - isolate_test=1, - test=CheckExc(expr=LoadExc(), choices=self._visitTryExcept(spec)) - ) - test.body = [] - - if assign is not None: - test.body.append( - Assign( - code=[ - StoreTemp(expr=LoadExc()), - self.dispatch(assign), - ReleaseTemp() - ] - ) - ) - - # Always return from conditional sections. - - test.body += self.dispatch(stmt) + [ReturnFromBlock()] - nodes.append(test) - nodes = test.else_ = [] - - # Add a raise operation to deal with unhandled exceptions. - - if not catch_all: - nodes.append( - Raise( - expr=LoadExc()) - ) - - result.handler = results - return result - - def _visitTryExcept(self, spec): - - "Return a list of nodes for the given exception type 'spec'." - - if isinstance(spec, compiler.ast.Tuple): - nodes = [] - for node in spec.nodes: - nodes += self._visitTryExcept(node) - else: - nodes = [self.dispatch(spec)] - return nodes - - comparison_methods = { - "==" : "__eq__", "!=" : "__ne__", "<" : "__lt__", "<=" : "__le__", - ">=" : "__ge__", ">" : "__gt__", "is" : None, "is not" : None - } - - def visitCompare(self, compare): - - """ - Make a subprogram for the 'compare' node and record its contents inside - the subprogram. Convert... - - Compare (expr) - (name/node) - ... - - ...to: - - InvokeBlock -> Subprogram -> Conditional (test) -> (body) - (else) -> Conditional (test) -> (body) - (else) -> ... - """ - - subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None) - self.current_subprograms.append(subprogram) - - # In the subprogram, make instructions which invoke a method on the - # first operand of each operand pair and, if appropriate, return with - # the value from that method. - - last = compare.ops[-1] - previous = self.dispatch(compare.expr) - results = nodes = [] - - # For viewing purposes, record invocations on the AST node. - - compare._ops = [] - - for op in compare.ops: - op_name, node = op - expr = self.dispatch(node) - - # Identify the operation and produce the appropriate method call. - - method_name = self.comparison_methods[op_name] - if method_name: - invocation = InvokeFunction( - expr=LoadAttr( - expr=previous, - name=method_name), - args=[expr], - star=None, - dstar=None) - - elif op_name == "is": - invocation = InvokeFunction( - expr=LoadName(name="__is__"), - args=[previous, expr], - star=None, - dstar=None) - - elif op_name == "is not": - invocation = Not( - expr=InvokeFunction( - expr=LoadName(name="__is__"), - args=[previous, expr], - star=None, - dstar=None) - ) - else: - raise NotImplementedError, op_name - - nodes.append(StoreTemp(expr=invocation)) - compare._ops.append(invocation) - - # Return from the subprogram where the test is not satisfied. - - if op is not last: - nodes.append( - Conditional( - test=self._visitNot(LoadTemp()), - body=[ - ReturnFromBlock(expr=LoadTemp()) - ], - else_=[ - ReleaseTemp() - # Subsequent operations go here! - ] - ) - ) - - # Put subsequent operations in the else section of this conditional. - - nodes = nodes[-1].else_ - - # For the last operation, return the result. - - else: - nodes.append( - ReturnFromBlock(expr=LoadTemp(release=1)) - ) - - previous = expr - - # Finish the subprogram definition. - - subprogram.code = results - - self.current_subprograms.pop() - self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram - - # Make an invocation of the subprogram. - - result = InvokeBlock(compare, 1, produces_result=1) - result.expr = LoadRef(ref=subprogram) - return result + def visitAdd(self, add): + return self._visitBinary(add, "__add__", "__radd__") def visitAnd(self, and_): @@ -585,187 +204,44 @@ result.expr = LoadRef(ref=subprogram) return result - def visitOr(self, or_): - - """ - Make a subprogram for the 'or_' node and record its contents inside the - subprogram. Convert... - - Or (test) - (test) - ... - - ...to: - - Subprogram -> Conditional (test) -> ReturnFromBlock ... - (else) -> Conditional (test) -> ReturnFromBlock ... - (else) -> ... - """ - - subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None) - self.current_subprograms.append(subprogram) - - # In the subprogram, make instructions which store each operand, test - # for each operand's truth status, and if appropriate return from the - # subprogram with the value of the operand. - - last = or_.nodes[-1] - results = nodes = [] - - for node in or_.nodes: - expr = self.dispatch(node) + # Assignments. - # Return from the subprogram where the test is satisfied. - - if node is not last: - nodes.append(StoreTemp(expr=expr)) - invocation = InvokeFunction(expr=LoadAttr(expr=LoadTemp(), name="__bool__"), args=[], star=None, dstar=None) - test = Conditional(test=invocation, body=[ReturnFromBlock(expr=LoadTemp())]) - nodes.append(test) - - # Put subsequent operations in the else section of this conditional. - - nodes = test.else_ = [ReleaseTemp()] - - # For the last operation, return the result. - - else: - nodes.append( - ReturnFromBlock(expr=expr) - ) - - # Finish the subprogram definition. - - subprogram.code = results - - self.current_subprograms.pop() - self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram - - # Make an invocation of the subprogram. - - result = InvokeBlock(or_, 1, produces_result=1) - result.expr = LoadRef(ref=subprogram) + def visitAssAttr(self, assattr, in_sequence=0): + expr = self._visitAssNameOrAttr(assattr, in_sequence) + lvalue = self.dispatch(assattr.expr) + result = StoreAttr(assattr, 1, name=assattr.attrname, lvalue=lvalue, expr=expr) return result - def _visitNot(self, expr, not_=None): - invocation = InvokeFunction( - expr=LoadAttr( - expr=expr, - name="__bool__" - ), - args=[], - star=None, - dstar=None - ) - if not_ is not None: - result = Not(not_, 1, expr=invocation) - else: - result = Not(expr=invocation) + def visitAssign(self, assign): + result = Assign(assign, 1) + store = StoreTemp(expr=self.dispatch(assign.expr)) + release = ReleaseTemp() + result.code = [store] + self.dispatches(assign.nodes, 0) + [release] return result - def visitNot(self, not_): - return self._visitNot(self.dispatch(not_.expr), not_) - - # Operators. - - def _visitBinary(self, binary, left_name, right_name): - - """ - Emulate the current mechanisms by producing nodes as follows: - - InvokeBlock -> Subprogram -> Try (body) -> ReturnFromBlock (expr) -> x.__add__(y) - (else) - (handler) -> Conditional (test) -> CheckExc (expr) -> LoadExc - (choices) -> LoadName TypeError - (body) -> ReturnFromBlock (expr) -> y.__radd__(x) - (else) - """ - - subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None) - self.current_subprograms.append(subprogram) - - subprogram.code = [ - Try(binary, 1, - body=[ - ReturnFromBlock( - expr=InvokeFunction( - expr=LoadAttr(expr=self.dispatch(binary.left), name=left_name), - args=[self.dispatch(binary.right)], - star=None, - dstar=None) - ) - ], - else_=[], - finally_=[], - handler=[ - Conditional( - test=CheckExc(expr=LoadExc(), choices=[LoadName(name="TypeError")]), - body=[ - ReturnFromBlock( - expr=InvokeFunction( - expr=LoadAttr(expr=self.dispatch(binary.right), name=right_name), - args=[self.dispatch(binary.left)], - star=None, - dstar=None) - ) - ], - else_=[] - ) - ] - ) - ] - - self.current_subprograms.pop() - self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram - - result = InvokeBlock(produces_result=1) - result.expr = LoadRef(ref=subprogram) + def visitAssList(self, asslist, in_sequence=0): + if not in_sequence: + expr = LoadTemp() + else: + expr = InvokeFunction(expr=LoadAttr(expr=LoadTemp(), name="next"), star=None, dstar=None, args=[]) + result = Assign(asslist, 1) + store = StoreTemp(expr=InvokeFunction(expr=LoadAttr(name="__iter__", expr=expr), star=None, dstar=None, args=[])) + release = ReleaseTemp() + result.code = [store] + self.dispatches(asslist.nodes, 1) + [release] return result - def visitAdd(self, add): - return self._visitBinary(add, "__add__", "__radd__") - - def visitDiv(self, div): - return self._visitBinary(div, "__div__", "__rdiv__") - - def visitFloorDiv(self, floordiv): - return self._visitBinary(floordiv, "__floordiv__", "__rfloordiv__") - - def visitMul(self, mul): - return self._visitBinary(mul, "__mul__", "__rmul__") - - def visitSub(self, sub): - return self._visitBinary(sub, "__sub__", "__rsub__") + visitAssTuple = visitAssList - def visitInvert(self, invert): - return InvokeFunction(invert, 1, - expr=LoadAttr( - expr=self.dispatch(invert.expr), - name="__invert__" - ), - args=[], - star=None, - dstar=None - ) + def _visitAssNameOrAttr(self, node, in_sequence): + if not in_sequence: + return LoadTemp() + else: + return InvokeFunction(expr=LoadAttr(expr=LoadTemp(), name="next"), star=None, dstar=None, args=[]) - def _visitUnary(self, unary, name): - return InvokeFunction(unary, 1, - expr=LoadAttr( - expr=self.dispatch(unary.expr), - name=name - ), - args=[], - star=None, - dstar=None - ) - - def visitUnaryAdd(self, unaryadd): - return self._visitUnary(unaryadd, "__pos__") - - def visitUnarySub(self, unarysub): - return self._visitUnary(unarysub, "__neg__") - - # Assignments. + def visitAssName(self, assname, in_sequence=0): + expr = self._visitAssNameOrAttr(assname, in_sequence) + result = StoreName(assname, 1, name=assname.name, expr=expr) + return result augassign_methods = { "+=" : "__iadd__", "-=" : "__isub__", "*=" : "__imul__", "/=" : "__idiv__", @@ -934,142 +410,19 @@ return result - def visitAssign(self, assign): - result = Assign(assign, 1) - store = StoreTemp(expr=self.dispatch(assign.expr)) - release = ReleaseTemp() - result.code = [store] + self.dispatches(assign.nodes, 0) + [release] - return result - - def visitAssList(self, asslist, in_sequence=0): - if not in_sequence: - expr = LoadTemp() - else: - expr = InvokeFunction(expr=LoadAttr(expr=LoadTemp(), name="next"), star=None, dstar=None, args=[]) - result = Assign(asslist, 1) - store = StoreTemp(expr=InvokeFunction(expr=LoadAttr(name="__iter__", expr=expr), star=None, dstar=None, args=[])) - release = ReleaseTemp() - result.code = [store] + self.dispatches(asslist.nodes, 1) + [release] - return result - - visitAssTuple = visitAssList - - def _visitAssNameOrAttr(self, node, in_sequence): - if not in_sequence: - return LoadTemp() - else: - return InvokeFunction(expr=LoadAttr(expr=LoadTemp(), name="next"), star=None, dstar=None, args=[]) - - def visitAssName(self, assname, in_sequence=0): - expr = self._visitAssNameOrAttr(assname, in_sequence) - result = StoreName(assname, 1, name=assname.name, expr=expr) - return result - - def visitAssAttr(self, assattr, in_sequence=0): - expr = self._visitAssNameOrAttr(assattr, in_sequence) - lvalue = self.dispatch(assattr.expr) - result = StoreAttr(assattr, 1, name=assattr.attrname, lvalue=lvalue, expr=expr) + def visitBreak(self, break_): + result = ReturnFromBlock(break_, 1) return result - def _visitSlice(self, slice, expr, lower, upper, flags, value=None): - if flags == "OP_ASSIGN": - result = InvokeFunction(slice, 1, - expr=LoadAttr( - expr=expr, - name="__setslice__" - ), - star=None, - dstar=None, - args=[lower, upper, value] - ) - elif flags == "OP_APPLY": - args = [] - result = InvokeFunction(slice, 1, - expr=LoadAttr( - expr=expr, - name="__getslice__" - ), - star=None, - dstar=None, - args=[lower, upper] - ) - elif flags == "OP_DELETE": - args = [] - result = InvokeFunction(slice, 1, - expr=LoadAttr( - expr=expr, - name="__delslice__" - ), - star=None, - dstar=None, - args=[lower, upper] - ) - else: - raise NotImplementedError, flags - + def visitCallFunc(self, callfunc): + result = InvokeFunction(callfunc, 1, star=None, dstar=None, args=self.dispatches(callfunc.args)) + if callfunc.star_args is not None: + result.star = self.dispatch(callfunc.star_args) + if callfunc.dstar_args is not None: + result.dstar = self.dispatch(callfunc.dstar_args) + result.expr = self.dispatch(callfunc.node) return result - def visitSlice(self, slice, in_sequence=0): - return self._visitSlice(slice, self.dispatch(slice.expr), self.dispatch_or_none(slice.lower), - self.dispatch_or_none(slice.upper), slice.flags, self._visitAssNameOrAttr(slice, in_sequence)) - - def _visitSubscript(self, subscript, expr, subs, flags, value=None): - if flags == "OP_ASSIGN": - result = InvokeFunction(subscript, 1, - expr=LoadAttr( - expr=expr, - name="__setitem__" - ), - star=None, - dstar=None, - args=[subs, value] - ) - elif flags == "OP_APPLY": - args = [] - result = InvokeFunction(subscript, 1, - expr=LoadAttr( - expr=expr, - name="__getitem__" - ), - star=None, - dstar=None, - args=[subs] - ) - elif flags == "OP_DELETE": - args = [] - result = InvokeFunction(subscript, 1, - expr=LoadAttr( - expr=expr, - name="__delitem__" - ), - star=None, - dstar=None, - args=[subs] - ) - else: - raise NotImplementedError, flags - - return result - - def _visitSubscriptSubs(self, node, subs): - if len(subs) == 1: - return self.dispatch(subs[0]) - else: - return InvokeFunction(node, 1, - expr=LoadName(name="tuple"), - args=self.dispatches(subs), - star=None, - dstar=None - ) - - def visitSubscript(self, subscript, in_sequence=0): - return self._visitSubscript( - subscript, self.dispatch(subscript.expr), self._visitSubscriptSubs(subscript, subscript.subs), subscript.flags, - self._visitAssNameOrAttr(subscript, in_sequence) - ) - - # Invocation and subprogram transformations. - def visitClass(self, class_): # Add "object" if the class is not "object" and has an empty bases list. @@ -1112,165 +465,153 @@ ) return result - def _visitFunction(self, function, subprogram): + comparison_methods = { + "==" : "__eq__", "!=" : "__ne__", "<" : "__lt__", "<=" : "__le__", + ">=" : "__ge__", ">" : "__gt__", "is" : None, "is not" : None + } + + def visitCompare(self, compare): """ - A common function generator which transforms the given 'function' node - and initialises the given 'subprogram' appropriately. - """ - - # Discover star and dstar parameters. - - if function.flags & 4 != 0: - has_star = 1 - else: - has_star = 0 - if function.flags & 8 != 0: - has_dstar = 1 - else: - has_dstar = 0 - - # Discover the number of defaults and positional parameters. - - ndefaults = len(function.defaults) - npositional = len(function.argnames) - has_star - has_dstar - - # Produce star and dstar parameters with appropriate defaults. - - if has_star: - star = ( - function.argnames[npositional], - InvokeFunction(expr=LoadName(name="list"), args=[], star=None, dstar=None) - ) - else: - star = None - if has_dstar: - dstar = ( - function.argnames[npositional + has_star], - InvokeFunction(expr=LoadName(name="dict"), args=[], star=None, dstar=None) - ) - else: - dstar = None - - params = [] - for i in range(0, npositional - ndefaults): - params.append((function.argnames[i], None)) - - # Process defaults. - - for i in range(0, ndefaults): - default = function.defaults[i] - if default is not None: - params.append((function.argnames[npositional - ndefaults + i], self.dispatch(default))) - else: - params.append((function.argnames[npositional - ndefaults + i], None)) - - subprogram.params = params - subprogram.star = star - subprogram.dstar = dstar - self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram + Make a subprogram for the 'compare' node and record its contents inside + the subprogram. Convert... - def visitFunction(self, function): - - """ - Make a subprogram for the 'function' and record it outside the main - tree. Produce something like the following: - - StoreName (name) - (expr) -> Subprogram (params) - (star) - (dstar) - """ - - subprogram = Subprogram(name=function.name, module=self.module, structures=self.current_structures[:], - internal=0, returns_value=1, star=None, dstar=None) - - self.current_subprograms.append(subprogram) - subprogram.code = self.dispatch(function.code) + [ReturnFromFunction()] - self.current_subprograms.pop() - self._visitFunction(function, subprogram) - - # Make a definition of the function associating it with a name. - - result = StoreName(function, 1, name=function.name, expr=LoadRef(ref=subprogram)) - return result - - def visitLambda(self, lambda_): - - # Make a subprogram for the function and record it outside the main - # tree. - - subprogram = Subprogram(name=None, module=self.module, internal=0, returns_value=1, star=None, dstar=None) - self.current_subprograms.append(subprogram) - subprogram.code = [ReturnFromFunction(expr=self.dispatch(lambda_.code))] - self.current_subprograms.pop() - self._visitFunction(lambda_, subprogram) - - # Get the subprogram reference to the lambda. - - return LoadRef(lambda_, 1, ref=subprogram) - - def visitCallFunc(self, callfunc): - result = InvokeFunction(callfunc, 1, star=None, dstar=None, args=self.dispatches(callfunc.args)) - if callfunc.star_args is not None: - result.star = self.dispatch(callfunc.star_args) - if callfunc.dstar_args is not None: - result.dstar = self.dispatch(callfunc.dstar_args) - result.expr = self.dispatch(callfunc.node) - return result - - def visitWhile(self, while_): - - """ - Make a subprogram for the 'while' node and record its contents inside the - subprogram. Convert... - - While (test) -> (body) - (else) + Compare (expr) + (name/node) + ... ...to: - Subprogram -> Conditional (test) -> (body) -> Invoke subprogram - (else) -> Conditional (test) -> ReturnFromBlock ... - (else) -> ... + InvokeBlock -> Subprogram -> Conditional (test) -> (body) + (else) -> Conditional (test) -> (body) + (else) -> ... """ - subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=0, params=[], star=None, dstar=None) + subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None) self.current_subprograms.append(subprogram) - # Include a conditional statement in the subprogram. + # In the subprogram, make instructions which invoke a method on the + # first operand of each operand pair and, if appropriate, return with + # the value from that method. + + last = compare.ops[-1] + previous = self.dispatch(compare.expr) + results = nodes = [] + + # For viewing purposes, record invocations on the AST node. + + compare._ops = [] + + for op in compare.ops: + op_name, node = op + expr = self.dispatch(node) - test = Conditional(else_=[]) - test.test = InvokeFunction(expr=LoadAttr(expr=self.dispatch(while_.test), name="__bool__"), args=[], star=None, dstar=None) + # Identify the operation and produce the appropriate method call. - # Inside the conditional, add a recursive invocation to the subprogram - # if the test condition was satisfied. + method_name = self.comparison_methods[op_name] + if method_name: + invocation = InvokeFunction( + expr=LoadAttr( + expr=previous, + name=method_name), + args=[expr], + star=None, + dstar=None) + + elif op_name == "is": + invocation = InvokeFunction( + expr=LoadName(name="__is__"), + args=[previous, expr], + star=None, + dstar=None) - continuation = InvokeBlock() - continuation.expr = LoadRef(ref=subprogram) + elif op_name == "is not": + invocation = Not( + expr=InvokeFunction( + expr=LoadName(name="__is__"), + args=[previous, expr], + star=None, + dstar=None) + ) + else: + raise NotImplementedError, op_name - # Return within the main section of the loop. + nodes.append(StoreTemp(expr=invocation)) + compare._ops.append(invocation) + + # Return from the subprogram where the test is not satisfied. - test.body = self.dispatch(while_.body) + [continuation, ReturnFromBlock()] + if op is not last: + nodes.append( + Conditional( + test=self._visitNot(LoadTemp()), + body=[ + ReturnFromBlock(expr=LoadTemp()) + ], + else_=[ + ReleaseTemp() + # Subsequent operations go here! + ] + ) + ) - # Provide the else section, if present, along with an explicit return. + # Put subsequent operations in the else section of this conditional. + + nodes = nodes[-1].else_ + + # For the last operation, return the result. - if while_.else_ is not None: - test.else_ = self.dispatch(while_.else_) + [ReturnFromBlock()] + else: + nodes.append( + ReturnFromBlock(expr=LoadTemp(release=1)) + ) + + previous = expr # Finish the subprogram definition. - subprogram.code = [test] + subprogram.code = results self.current_subprograms.pop() self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram # Make an invocation of the subprogram. - result = InvokeBlock(while_, 1) + result = InvokeBlock(compare, 1, produces_result=1) result.expr = LoadRef(ref=subprogram) return result + def visitConst(self, const): + if not self.constants.has_key(const.value): + self.constants[const.value] = Constant(name=repr(const.value), value=const.value) + result = LoadRef(const, 1, ref=self.constants[const.value]) + return result + + def visitContinue(self, continue_): + result = InvokeBlock(continue_, 1, + expr=LoadRef(ref=self.current_subprograms[-1]) + ) + return result + + def visitDict(self, dict): + result = InvokeFunction(dict, 1, expr=LoadName(name="dict"), star=None, dstar=None) + args = [] + for key, value in dict.items: + tuple = InvokeFunction(expr=LoadName(name="tuple"), star=None, dstar=None) + tuple.set_args([self.dispatch(key), self.dispatch(value)]) + args.append(tuple) + result.set_args(args) + return result + + def visitDiscard(self, discard): + return self.dispatch(discard.expr) + + def visitDiv(self, div): + return self._visitBinary(div, "__div__", "__rdiv__") + + def visitFloorDiv(self, floordiv): + return self._visitBinary(floordiv, "__floordiv__", "__rfloordiv__") + def visitFor(self, for_): """ @@ -1361,7 +702,518 @@ ] return result - # Exception node transformations. + def visitFrom(self, from_): + result = Assign(from_, 1) + code = [] + code.append(StoreTemp(expr=Import(name=from_.modname))) + for name, alias in from_.names: + code.append( + StoreName( + expr=LoadAttr( + expr=LoadTemp(), + name=name), + name=(alias or name) + ) + ) + code.append(ReleaseTemp()) + result.code = code + return result + + def _visitFunction(self, function, subprogram): + + """ + A common function generator which transforms the given 'function' node + and initialises the given 'subprogram' appropriately. + """ + + # Discover star and dstar parameters. + + if function.flags & 4 != 0: + has_star = 1 + else: + has_star = 0 + if function.flags & 8 != 0: + has_dstar = 1 + else: + has_dstar = 0 + + # Discover the number of defaults and positional parameters. + + ndefaults = len(function.defaults) + npositional = len(function.argnames) - has_star - has_dstar + + # Produce star and dstar parameters with appropriate defaults. + + if has_star: + star = ( + function.argnames[npositional], + InvokeFunction(expr=LoadName(name="list"), args=[], star=None, dstar=None) + ) + else: + star = None + if has_dstar: + dstar = ( + function.argnames[npositional + has_star], + InvokeFunction(expr=LoadName(name="dict"), args=[], star=None, dstar=None) + ) + else: + dstar = None + + params = [] + for i in range(0, npositional - ndefaults): + params.append((function.argnames[i], None)) + + # Process defaults. + + for i in range(0, ndefaults): + default = function.defaults[i] + if default is not None: + params.append((function.argnames[npositional - ndefaults + i], self.dispatch(default))) + else: + params.append((function.argnames[npositional - ndefaults + i], None)) + + subprogram.params = params + subprogram.star = star + subprogram.dstar = dstar + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram + + def visitFunction(self, function): + + """ + Make a subprogram for the 'function' and record it outside the main + tree. Produce something like the following: + + StoreName (name) + (expr) -> Subprogram (params) + (star) + (dstar) + """ + + subprogram = Subprogram(name=function.name, module=self.module, structures=self.current_structures[:], + internal=0, returns_value=1, star=None, dstar=None) + + self.current_subprograms.append(subprogram) + subprogram.code = self.dispatch(function.code) + [ReturnFromFunction()] + self.current_subprograms.pop() + self._visitFunction(function, subprogram) + + # Make a definition of the function associating it with a name. + + result = StoreName(function, 1, name=function.name, expr=LoadRef(ref=subprogram)) + return result + + def visitGetattr(self, getattr): + result = LoadAttr(getattr, 1, + name=getattr.attrname, + expr=self.dispatch(getattr.expr) + ) + return result + + def visitGlobal(self, global_): + result = Global(global_, 1, + names=global_.names + ) + return result + + def visitIf(self, if_): + + """ + Make conditionals for each test from an 'if_' AST node, adding the body + and putting each subsequent test as part of the conditional's else + section. + + Convert... + + If (test/body) + (test/body) + ... + (else/body) + + ...to: + + Conditional (test) -> (body) + (else) -> Conditional (test) -> (body) + (else) -> ... + """ + + + results = nodes = [] + + # Produce something like... + # expr.__bool__() ? body + + first = 1 + for compare, stmt in if_.tests: + + # Set the first as the defining node. + + test = Conditional(if_, first, + test=InvokeFunction( + expr=LoadAttr( + expr=self.dispatch(compare), + name="__bool__" + ), + args=[], + star=None, + dstar=None) + ) + test.body = self.dispatch(stmt) + nodes.append(test) + nodes = test.else_ = [] + first = 0 + + # Add the compound statement from any else clause to the end. + + if if_.else_ is not None: + nodes += self.dispatch(if_.else_) + + result = results[0] + return result + + def visitImport(self, import_): + result = Assign(import_, 1) + code = [] + for path, alias in import_.names: + importer = Import(name=path) + top = alias or path.split(".")[0] + code.append(StoreName(expr=importer, name=top)) + result.code = code + return result + + def visitInvert(self, invert): + return self._visitUnary(invert, "__invert__") + + def visitKeyword(self, keyword): + result = Keyword(keyword, 1, + name=keyword.name, + expr=self.dispatch(keyword.expr) + ) + return result + + def visitLambda(self, lambda_): + + # Make a subprogram for the function and record it outside the main + # tree. + + subprogram = Subprogram(name=None, module=self.module, internal=0, returns_value=1, star=None, dstar=None) + self.current_subprograms.append(subprogram) + subprogram.code = [ReturnFromFunction(expr=self.dispatch(lambda_.code))] + self.current_subprograms.pop() + self._visitFunction(lambda_, subprogram) + + # Get the subprogram reference to the lambda. + + return LoadRef(lambda_, 1, ref=subprogram) + + def visitList(self, list): + return self._visitBuiltin(list, "list") + + def visitMul(self, mul): + return self._visitBinary(mul, "__mul__", "__rmul__") + + def visitName(self, name): + result = LoadName(name, 1, name=name.name) + return result + + def _visitNot(self, expr, not_=None): + invocation = InvokeFunction( + expr=LoadAttr( + expr=expr, + name="__bool__" + ), + args=[], + star=None, + dstar=None + ) + if not_ is not None: + result = Not(not_, 1, expr=invocation) + else: + result = Not(expr=invocation) + return result + + def visitNot(self, not_): + return self._visitNot(self.dispatch(not_.expr), not_) + + def visitOr(self, or_): + + """ + Make a subprogram for the 'or_' node and record its contents inside the + subprogram. Convert... + + Or (test) + (test) + ... + + ...to: + + Subprogram -> Conditional (test) -> ReturnFromBlock ... + (else) -> Conditional (test) -> ReturnFromBlock ... + (else) -> ... + """ + + subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None) + self.current_subprograms.append(subprogram) + + # In the subprogram, make instructions which store each operand, test + # for each operand's truth status, and if appropriate return from the + # subprogram with the value of the operand. + + last = or_.nodes[-1] + results = nodes = [] + + for node in or_.nodes: + expr = self.dispatch(node) + + # Return from the subprogram where the test is satisfied. + + if node is not last: + nodes.append(StoreTemp(expr=expr)) + invocation = InvokeFunction(expr=LoadAttr(expr=LoadTemp(), name="__bool__"), args=[], star=None, dstar=None) + test = Conditional(test=invocation, body=[ReturnFromBlock(expr=LoadTemp())]) + nodes.append(test) + + # Put subsequent operations in the else section of this conditional. + + nodes = test.else_ = [ReleaseTemp()] + + # For the last operation, return the result. + + else: + nodes.append( + ReturnFromBlock(expr=expr) + ) + + # Finish the subprogram definition. + + subprogram.code = results + + self.current_subprograms.pop() + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram + + # Make an invocation of the subprogram. + + result = InvokeBlock(or_, 1, produces_result=1) + result.expr = LoadRef(ref=subprogram) + return result + + def visitPass(self, pass_): + return Pass(pass_, 1) + + def visitRaise(self, raise_): + result = Raise(raise_, 1) + if raise_.expr2 is None: + result.expr = self.dispatch(raise_.expr1) + else: + result.expr = InvokeFunction( + expr=self.dispatch(raise_.expr1), + args=[self.dispatch(raise_.expr2)], + star=None, + dstar=None + ) + if raise_.expr3 is not None: + result.traceback = self.dispatch(raise_.expr3) + else: + result.traceback = None + return result + + def visitReturn(self, return_): + result = ReturnFromFunction(return_, 1, + expr=self.dispatch(return_.value) + ) + return result + + def _visitSlice(self, slice, expr, lower, upper, flags, value=None): + if flags == "OP_ASSIGN": + result = InvokeFunction(slice, 1, + expr=LoadAttr( + expr=expr, + name="__setslice__" + ), + star=None, + dstar=None, + args=[lower, upper, value] + ) + elif flags == "OP_APPLY": + args = [] + result = InvokeFunction(slice, 1, + expr=LoadAttr( + expr=expr, + name="__getslice__" + ), + star=None, + dstar=None, + args=[lower, upper] + ) + elif flags == "OP_DELETE": + args = [] + result = InvokeFunction(slice, 1, + expr=LoadAttr( + expr=expr, + name="__delslice__" + ), + star=None, + dstar=None, + args=[lower, upper] + ) + else: + raise NotImplementedError, flags + + return result + + def visitSlice(self, slice, in_sequence=0): + return self._visitSlice(slice, self.dispatch(slice.expr), self.dispatch_or_none(slice.lower), + self.dispatch_or_none(slice.upper), slice.flags, self._visitAssNameOrAttr(slice, in_sequence)) + + def visitStmt(self, stmt): + return self.dispatches(stmt.nodes) + + def visitSub(self, sub): + return self._visitBinary(sub, "__sub__", "__rsub__") + + def _visitSubscript(self, subscript, expr, subs, flags, value=None): + if flags == "OP_ASSIGN": + result = InvokeFunction(subscript, 1, + expr=LoadAttr( + expr=expr, + name="__setitem__" + ), + star=None, + dstar=None, + args=[subs, value] + ) + elif flags == "OP_APPLY": + args = [] + result = InvokeFunction(subscript, 1, + expr=LoadAttr( + expr=expr, + name="__getitem__" + ), + star=None, + dstar=None, + args=[subs] + ) + elif flags == "OP_DELETE": + args = [] + result = InvokeFunction(subscript, 1, + expr=LoadAttr( + expr=expr, + name="__delitem__" + ), + star=None, + dstar=None, + args=[subs] + ) + else: + raise NotImplementedError, flags + + return result + + def _visitSubscriptSubs(self, node, subs): + if len(subs) == 1: + return self.dispatch(subs[0]) + else: + return InvokeFunction(node, 1, + expr=LoadName(name="tuple"), + args=self.dispatches(subs), + star=None, + dstar=None + ) + + def visitSubscript(self, subscript, in_sequence=0): + return self._visitSubscript( + subscript, self.dispatch(subscript.expr), self._visitSubscriptSubs(subscript, subscript.subs), subscript.flags, + self._visitAssNameOrAttr(subscript, in_sequence) + ) + + def visitTryExcept(self, tryexcept): + + """ + Make conditionals for each handler associated with a 'tryexcept' node. + + Convert... + + TryExcept (body) + (else) + (spec/assign/stmt) + ... + + ...to: + + Try (body) + (else) + (handler) -> Conditional (test) -> (stmt) + (body) -> ... + (else) -> Conditional (test) -> (stmt) + (body) -> ... + (else) -> ... + """ + + result = Try(tryexcept, 1, body=[], else_=[], finally_=[]) + + if tryexcept.body is not None: + result.body = self.dispatch(tryexcept.body) + if tryexcept.else_ is not None: + result.else_ = self.dispatch(tryexcept.else_) + + results = nodes = [] + catch_all = 0 + + for spec, assign, stmt in tryexcept.handlers: + + # If no specification exists, produce an unconditional block. + + if spec is None: + nodes += self.dispatch(stmt) + catch_all = 1 + + # Produce an exception value check. + + else: + test = Conditional( + isolate_test=1, + test=CheckExc(expr=LoadExc(), choices=self._visitTryExcept(spec)) + ) + test.body = [] + + if assign is not None: + test.body.append( + Assign( + code=[ + StoreTemp(expr=LoadExc()), + self.dispatch(assign), + ReleaseTemp() + ] + ) + ) + + # Always return from conditional sections. + + test.body += self.dispatch(stmt) + [ReturnFromBlock()] + nodes.append(test) + nodes = test.else_ = [] + + # Add a raise operation to deal with unhandled exceptions. + + if not catch_all: + nodes.append( + Raise( + expr=LoadExc()) + ) + + result.handler = results + return result + + def _visitTryExcept(self, spec): + + "Return a list of nodes for the given exception type 'spec'." + + if isinstance(spec, compiler.ast.Tuple): + nodes = [] + for node in spec.nodes: + nodes += self._visitTryExcept(node) + else: + nodes = [self.dispatch(spec)] + return nodes def visitTryFinally(self, tryfinally): result = Try(tryfinally, 1, body=[], else_=[], finally_=[]) @@ -1371,6 +1223,138 @@ result.finally_ = self.dispatch(tryfinally.final) return result + def visitTuple(self, tuple): + return self._visitBuiltin(tuple, "tuple") + + def visitUnaryAdd(self, unaryadd): + return self._visitUnary(unaryadd, "__pos__") + + def visitUnarySub(self, unarysub): + return self._visitUnary(unarysub, "__neg__") + + def visitWhile(self, while_): + + """ + Make a subprogram for the 'while' node and record its contents inside the + subprogram. Convert... + + While (test) -> (body) + (else) + + ...to: + + Subprogram -> Conditional (test) -> (body) -> Invoke subprogram + (else) -> Conditional (test) -> ReturnFromBlock ... + (else) -> ... + """ + + subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=0, params=[], star=None, dstar=None) + self.current_subprograms.append(subprogram) + + # Include a conditional statement in the subprogram. + + test = Conditional(else_=[]) + test.test = InvokeFunction(expr=LoadAttr(expr=self.dispatch(while_.test), name="__bool__"), args=[], star=None, dstar=None) + + # Inside the conditional, add a recursive invocation to the subprogram + # if the test condition was satisfied. + + continuation = InvokeBlock() + continuation.expr = LoadRef(ref=subprogram) + + # Return within the main section of the loop. + + test.body = self.dispatch(while_.body) + [continuation, ReturnFromBlock()] + + # Provide the else section, if present, along with an explicit return. + + if while_.else_ is not None: + test.else_ = self.dispatch(while_.else_) + [ReturnFromBlock()] + + # Finish the subprogram definition. + + subprogram.code = [test] + + self.current_subprograms.pop() + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram + + # Make an invocation of the subprogram. + + result = InvokeBlock(while_, 1) + result.expr = LoadRef(ref=subprogram) + return result + + # Convenience methods. + + def _visitBinary(self, binary, left_name, right_name): + + """ + Emulate the current mechanisms by producing nodes as follows: + + InvokeBlock -> Subprogram -> Try (body) -> ReturnFromBlock (expr) -> x.__add__(y) + (else) + (handler) -> Conditional (test) -> CheckExc (expr) -> LoadExc + (choices) -> LoadName TypeError + (body) -> ReturnFromBlock (expr) -> y.__radd__(x) + (else) + """ + + subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None) + self.current_subprograms.append(subprogram) + + subprogram.code = [ + Try(binary, 1, + body=[ + ReturnFromBlock( + expr=InvokeFunction( + expr=LoadAttr(expr=self.dispatch(binary.left), name=left_name), + args=[self.dispatch(binary.right)], + star=None, + dstar=None) + ) + ], + else_=[], + finally_=[], + handler=[ + Conditional( + test=CheckExc(expr=LoadExc(), choices=[LoadName(name="TypeError")]), + body=[ + ReturnFromBlock( + expr=InvokeFunction( + expr=LoadAttr(expr=self.dispatch(binary.right), name=right_name), + args=[self.dispatch(binary.left)], + star=None, + dstar=None) + ) + ], + else_=[] + ) + ] + ) + ] + + self.current_subprograms.pop() + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram + + result = InvokeBlock(produces_result=1) + result.expr = LoadRef(ref=subprogram) + return result + + def _visitBuiltin(self, builtin, name): + result = InvokeFunction(builtin, 1, expr=LoadName(name=name), args=self.dispatches(builtin.nodes), star=None, dstar=None) + return result + + def _visitUnary(self, unary, name): + return InvokeFunction(unary, 1, + expr=LoadAttr( + expr=self.dispatch(unary.expr), + name=name + ), + args=[], + star=None, + dstar=None + ) + # Convenience functions. def simplify(filename, builtins=0):