# HG changeset patch # User Paul Boddie # Date 1205105857 -3600 # Node ID 47656b7fd26725cf9de821c0efc6398e20827b52 # Parent b830830c253490b83bda4afa5c218384fbcd919c Added optimisation of constant assignments. Added support for the display of unpositioned attributes. diff -r b830830c2534 -r 47656b7fd267 micropython/ast.py --- a/micropython/ast.py Sun Mar 09 02:46:57 2008 +0100 +++ b/micropython/ast.py Mon Mar 10 00:37:37 2008 +0100 @@ -136,19 +136,27 @@ self.code[-1] = op + def remove_ops(self, n): + + "Remove the last 'n' instructions." + + del self.code[-n:] + + def last_ops(self, n): + + "Return the last 'n' added instructions in reverse chronological order." + + ops = self.code[-n:] + ops.reverse() + return ops + def last_op(self): "Return the last added instruction." return self.code[-1] - # Visitor methods. - - def default(self, node, *args): - raise TranslateError(self.module.full_name(), node, "Node class %r is not supported." % node.__class__) - - def dispatch(self, node, *args): - return ASTVisitor.dispatch(self, node, *args) + # Internal helper methods. def _visitAttr(self, node, classes): @@ -171,10 +179,14 @@ last = self.last_op() - # Where the last operation yields a constant... + # Where the last operation (defining the attribute owner) yields a + # constant... if isinstance(last, (LoadName, LoadAttr)) and last.attr.assignments == 1: + if self._optimise_constant_storage(AttrInstruction, 1): + return + # Get the details of the access. target = last.attr.value @@ -196,106 +208,6 @@ index = self.objtable.get_index(attrname) self.new_op(AttrIndexInstruction(index)) - def _visitName(self, node, classes): - - """ - Visit the name-related 'node', generating instructions based on the - given 'classes'. - """ - - name = node.name - scope = self.get_scope(name) - #print self.module.name, node.lineno, name, scope - self._generateName(name, scope, classes, node) - - def _generateName(self, name, scope, classes, node): - - """ - Generate code for the access to 'name' in 'scope' using the given - 'classes', and using the given 'node' as the source of the access. - """ - - NameInstruction, AttrInstruction = classes - - if scope == "local": - unit = self.unit - if isinstance(unit, micropython.inspect.Function): - self.new_op(NameInstruction(unit.all_locals()[name])) - elif isinstance(unit, micropython.inspect.Class): - self.new_op(AttrInstruction(unit.all_class_attributes()[name])) - elif isinstance(unit, micropython.inspect.Module): - self.new_op(AttrInstruction(unit.module_attributes()[name])) - else: - raise TranslateError(self.module.full_name(), node, "Program unit %r has no local %r" % (unit, name)) - - elif scope == "global": - globals = self.module.module_attributes() - if globals.has_key(name): - self.new_op(AttrInstruction(globals[name])) - else: - raise TranslateError(self.module.full_name(), node, "Module %r has no attribute %r" % (self.module, name)) - - else: - builtins = micropython.inspect.builtins.module_attributes() - self.new_op(AttrInstruction(builtins[name])) - - def visitAdd(self, node): - - """ - _t1 = node.left - _t2 = node.right - try: - _t1.__add__(_t2) - except AttributeError: - _t2.__radd__(_t1) - """ - - def visitAnd(self, node): pass - - def visitAssert(self, node): pass - - def visitAssign(self, node): - self.dispatch(node.expr) - for n in node.nodes: - self.dispatch(n) - - def visitAssAttr(self, node): - self._visitAttr(node, (StoreAttr, StoreAttrIndex)) - - def visitAssList(self, node): pass - - def visitAssName(self, node): - self._visitName(node, (StoreName, StoreAttr)) - - visitAssTuple = visitAssList - - def visitAugAssign(self, node): pass - - def visitBackquote(self, node): pass - - def visitBitand(self, node): pass - - def visitBitor(self, node): pass - - def visitBitxor(self, node): pass - - def visitBreak(self, node): - next_label, exit_label = self.loop_labels[-1] - self.new_op(Jump(exit_label)) - - def visitCallFunc(self, node): - - """ - Evaluate positional arguments, evaluate and store keyword arguments in - the correct location, then invoke the function. - """ - - # Mark the frame, evaluate the target, generate the call. - - self._startCallFunc() - self.dispatch(node.node) - self._generateCallFunc(node.args, node) - def _startCallFunc(self): "Record the location of the invocation." @@ -324,7 +236,7 @@ self.new_op(LoadContext()) self.new_op(CheckContext()) self.new_op(JumpIfTrue(continue_label)) - self.new_op(LoadConst(Const("TypeError"))) # NOTE: Do this properly! + self.new_op(LoadAttr(self._get_builtin("TypeError"))) self.new_op(RaiseException()) self.set_label(continue_label) @@ -394,6 +306,140 @@ self.new_op(DropFrame()) + def _visitName(self, node, classes): + + """ + Visit the name-related 'node', generating instructions based on the + given 'classes'. + """ + + name = node.name + scope = self.get_scope(name) + #print self.module.name, node.lineno, name, scope + self._generateName(name, scope, classes, node) + + def _generateName(self, name, scope, classes, node): + + """ + Generate code for the access to 'name' in 'scope' using the given + 'classes', and using the given 'node' as the source of the access. + """ + + NameInstruction, AttrInstruction = classes + + if self._optimise_constant_storage(NameInstruction, 0): + return + + if scope == "local": + unit = self.unit + if isinstance(unit, micropython.inspect.Function): + self.new_op(NameInstruction(unit.all_locals()[name])) + elif isinstance(unit, micropython.inspect.Class): + self.new_op(AttrInstruction(unit.all_class_attributes()[name])) + elif isinstance(unit, micropython.inspect.Module): + self.new_op(AttrInstruction(unit.module_attributes()[name])) + else: + raise TranslateError(self.module.full_name(), node, "Program unit %r has no local %r" % (unit, name)) + + elif scope == "global": + globals = self.module.module_attributes() + if globals.has_key(name): + self.new_op(AttrInstruction(globals[name])) + else: + raise TranslateError(self.module.full_name(), node, "Module %r has no attribute %r" % (self.module, name)) + + else: + self.new_op(AttrInstruction(self._get_builtin(name))) + + def _get_builtin(self, name): + builtins = micropython.inspect.builtins.module_attributes() + return builtins[name] + + # Optimisation methods. + + def _optimise_constant_storage(self, cls, n): + + """ + Where this operation should store a constant into a target which is + also constant, optimise away both operations. + """ + + last = self.last_ops(n+1) + + if cls in (StoreAttr, StoreName) and len(last) > n and \ + (isinstance(last[n], LoadAttr) and last[n].attr.assignments == 1 or + isinstance(last[n], LoadConst)): + + self.remove_ops(n+1) + return 1 + else: + return 0 + + # Visitor methods. + + def default(self, node, *args): + raise TranslateError(self.module.full_name(), node, "Node class %r is not supported." % node.__class__) + + def dispatch(self, node, *args): + return ASTVisitor.dispatch(self, node, *args) + + def visitAdd(self, node): + + """ + _t1 = node.left + _t2 = node.right + try: + _t1.__add__(_t2) + except AttributeError: + _t2.__radd__(_t1) + """ + + def visitAnd(self, node): pass + + def visitAssert(self, node): pass + + def visitAssign(self, node): + self.dispatch(node.expr) + for n in node.nodes: + self.dispatch(n) + + def visitAssAttr(self, node): + self._visitAttr(node, (StoreAttr, StoreAttrIndex)) + + def visitAssList(self, node): pass + + def visitAssName(self, node): + self._visitName(node, (StoreName, StoreAttr)) + + visitAssTuple = visitAssList + + def visitAugAssign(self, node): pass + + def visitBackquote(self, node): pass + + def visitBitand(self, node): pass + + def visitBitor(self, node): pass + + def visitBitxor(self, node): pass + + def visitBreak(self, node): + next_label, exit_label = self.loop_labels[-1] + self.new_op(Jump(exit_label)) + + def visitCallFunc(self, node): + + """ + Evaluate positional arguments, evaluate and store keyword arguments in + the correct location, then invoke the function. + """ + + # Mark the frame, evaluate the target, generate the call. + + self._startCallFunc() + self.dispatch(node.node) + self._generateCallFunc(node.args, node) + def visitClass(self, node): unit = self.unit self.unit = node.unit diff -r b830830c2534 -r 47656b7fd267 micropython/rsvp.py --- a/micropython/rsvp.py Sun Mar 09 02:46:57 2008 +0100 +++ b/micropython/rsvp.py Mon Mar 10 00:37:37 2008 +0100 @@ -54,7 +54,15 @@ result = position else: location = self.attr.parent.location - result = location + position + 1 + + # NOTE: Unpositioned attributes are handled here. + + if location is not None and position is not None: + result = location + position + 1 + else: + location = self.attr.parent.name + position = self.attr.name + result = None return "%s(%r, %r -> %r)" % (self.__class__.__name__, location, position, result) AR = AddressRelativeInstruction