1.1 --- a/micropython/ast.py Sun Mar 09 02:46:57 2008 +0100
1.2 +++ b/micropython/ast.py Mon Mar 10 00:37:37 2008 +0100
1.3 @@ -136,19 +136,27 @@
1.4
1.5 self.code[-1] = op
1.6
1.7 + def remove_ops(self, n):
1.8 +
1.9 + "Remove the last 'n' instructions."
1.10 +
1.11 + del self.code[-n:]
1.12 +
1.13 + def last_ops(self, n):
1.14 +
1.15 + "Return the last 'n' added instructions in reverse chronological order."
1.16 +
1.17 + ops = self.code[-n:]
1.18 + ops.reverse()
1.19 + return ops
1.20 +
1.21 def last_op(self):
1.22
1.23 "Return the last added instruction."
1.24
1.25 return self.code[-1]
1.26
1.27 - # Visitor methods.
1.28 -
1.29 - def default(self, node, *args):
1.30 - raise TranslateError(self.module.full_name(), node, "Node class %r is not supported." % node.__class__)
1.31 -
1.32 - def dispatch(self, node, *args):
1.33 - return ASTVisitor.dispatch(self, node, *args)
1.34 + # Internal helper methods.
1.35
1.36 def _visitAttr(self, node, classes):
1.37
1.38 @@ -171,10 +179,14 @@
1.39
1.40 last = self.last_op()
1.41
1.42 - # Where the last operation yields a constant...
1.43 + # Where the last operation (defining the attribute owner) yields a
1.44 + # constant...
1.45
1.46 if isinstance(last, (LoadName, LoadAttr)) and last.attr.assignments == 1:
1.47
1.48 + if self._optimise_constant_storage(AttrInstruction, 1):
1.49 + return
1.50 +
1.51 # Get the details of the access.
1.52
1.53 target = last.attr.value
1.54 @@ -196,106 +208,6 @@
1.55 index = self.objtable.get_index(attrname)
1.56 self.new_op(AttrIndexInstruction(index))
1.57
1.58 - def _visitName(self, node, classes):
1.59 -
1.60 - """
1.61 - Visit the name-related 'node', generating instructions based on the
1.62 - given 'classes'.
1.63 - """
1.64 -
1.65 - name = node.name
1.66 - scope = self.get_scope(name)
1.67 - #print self.module.name, node.lineno, name, scope
1.68 - self._generateName(name, scope, classes, node)
1.69 -
1.70 - def _generateName(self, name, scope, classes, node):
1.71 -
1.72 - """
1.73 - Generate code for the access to 'name' in 'scope' using the given
1.74 - 'classes', and using the given 'node' as the source of the access.
1.75 - """
1.76 -
1.77 - NameInstruction, AttrInstruction = classes
1.78 -
1.79 - if scope == "local":
1.80 - unit = self.unit
1.81 - if isinstance(unit, micropython.inspect.Function):
1.82 - self.new_op(NameInstruction(unit.all_locals()[name]))
1.83 - elif isinstance(unit, micropython.inspect.Class):
1.84 - self.new_op(AttrInstruction(unit.all_class_attributes()[name]))
1.85 - elif isinstance(unit, micropython.inspect.Module):
1.86 - self.new_op(AttrInstruction(unit.module_attributes()[name]))
1.87 - else:
1.88 - raise TranslateError(self.module.full_name(), node, "Program unit %r has no local %r" % (unit, name))
1.89 -
1.90 - elif scope == "global":
1.91 - globals = self.module.module_attributes()
1.92 - if globals.has_key(name):
1.93 - self.new_op(AttrInstruction(globals[name]))
1.94 - else:
1.95 - raise TranslateError(self.module.full_name(), node, "Module %r has no attribute %r" % (self.module, name))
1.96 -
1.97 - else:
1.98 - builtins = micropython.inspect.builtins.module_attributes()
1.99 - self.new_op(AttrInstruction(builtins[name]))
1.100 -
1.101 - def visitAdd(self, node):
1.102 -
1.103 - """
1.104 - _t1 = node.left
1.105 - _t2 = node.right
1.106 - try:
1.107 - _t1.__add__(_t2)
1.108 - except AttributeError:
1.109 - _t2.__radd__(_t1)
1.110 - """
1.111 -
1.112 - def visitAnd(self, node): pass
1.113 -
1.114 - def visitAssert(self, node): pass
1.115 -
1.116 - def visitAssign(self, node):
1.117 - self.dispatch(node.expr)
1.118 - for n in node.nodes:
1.119 - self.dispatch(n)
1.120 -
1.121 - def visitAssAttr(self, node):
1.122 - self._visitAttr(node, (StoreAttr, StoreAttrIndex))
1.123 -
1.124 - def visitAssList(self, node): pass
1.125 -
1.126 - def visitAssName(self, node):
1.127 - self._visitName(node, (StoreName, StoreAttr))
1.128 -
1.129 - visitAssTuple = visitAssList
1.130 -
1.131 - def visitAugAssign(self, node): pass
1.132 -
1.133 - def visitBackquote(self, node): pass
1.134 -
1.135 - def visitBitand(self, node): pass
1.136 -
1.137 - def visitBitor(self, node): pass
1.138 -
1.139 - def visitBitxor(self, node): pass
1.140 -
1.141 - def visitBreak(self, node):
1.142 - next_label, exit_label = self.loop_labels[-1]
1.143 - self.new_op(Jump(exit_label))
1.144 -
1.145 - def visitCallFunc(self, node):
1.146 -
1.147 - """
1.148 - Evaluate positional arguments, evaluate and store keyword arguments in
1.149 - the correct location, then invoke the function.
1.150 - """
1.151 -
1.152 - # Mark the frame, evaluate the target, generate the call.
1.153 -
1.154 - self._startCallFunc()
1.155 - self.dispatch(node.node)
1.156 - self._generateCallFunc(node.args, node)
1.157 -
1.158 def _startCallFunc(self):
1.159
1.160 "Record the location of the invocation."
1.161 @@ -324,7 +236,7 @@
1.162 self.new_op(LoadContext())
1.163 self.new_op(CheckContext())
1.164 self.new_op(JumpIfTrue(continue_label))
1.165 - self.new_op(LoadConst(Const("TypeError"))) # NOTE: Do this properly!
1.166 + self.new_op(LoadAttr(self._get_builtin("TypeError")))
1.167 self.new_op(RaiseException())
1.168 self.set_label(continue_label)
1.169
1.170 @@ -394,6 +306,140 @@
1.171
1.172 self.new_op(DropFrame())
1.173
1.174 + def _visitName(self, node, classes):
1.175 +
1.176 + """
1.177 + Visit the name-related 'node', generating instructions based on the
1.178 + given 'classes'.
1.179 + """
1.180 +
1.181 + name = node.name
1.182 + scope = self.get_scope(name)
1.183 + #print self.module.name, node.lineno, name, scope
1.184 + self._generateName(name, scope, classes, node)
1.185 +
1.186 + def _generateName(self, name, scope, classes, node):
1.187 +
1.188 + """
1.189 + Generate code for the access to 'name' in 'scope' using the given
1.190 + 'classes', and using the given 'node' as the source of the access.
1.191 + """
1.192 +
1.193 + NameInstruction, AttrInstruction = classes
1.194 +
1.195 + if self._optimise_constant_storage(NameInstruction, 0):
1.196 + return
1.197 +
1.198 + if scope == "local":
1.199 + unit = self.unit
1.200 + if isinstance(unit, micropython.inspect.Function):
1.201 + self.new_op(NameInstruction(unit.all_locals()[name]))
1.202 + elif isinstance(unit, micropython.inspect.Class):
1.203 + self.new_op(AttrInstruction(unit.all_class_attributes()[name]))
1.204 + elif isinstance(unit, micropython.inspect.Module):
1.205 + self.new_op(AttrInstruction(unit.module_attributes()[name]))
1.206 + else:
1.207 + raise TranslateError(self.module.full_name(), node, "Program unit %r has no local %r" % (unit, name))
1.208 +
1.209 + elif scope == "global":
1.210 + globals = self.module.module_attributes()
1.211 + if globals.has_key(name):
1.212 + self.new_op(AttrInstruction(globals[name]))
1.213 + else:
1.214 + raise TranslateError(self.module.full_name(), node, "Module %r has no attribute %r" % (self.module, name))
1.215 +
1.216 + else:
1.217 + self.new_op(AttrInstruction(self._get_builtin(name)))
1.218 +
1.219 + def _get_builtin(self, name):
1.220 + builtins = micropython.inspect.builtins.module_attributes()
1.221 + return builtins[name]
1.222 +
1.223 + # Optimisation methods.
1.224 +
1.225 + def _optimise_constant_storage(self, cls, n):
1.226 +
1.227 + """
1.228 + Where this operation should store a constant into a target which is
1.229 + also constant, optimise away both operations.
1.230 + """
1.231 +
1.232 + last = self.last_ops(n+1)
1.233 +
1.234 + if cls in (StoreAttr, StoreName) and len(last) > n and \
1.235 + (isinstance(last[n], LoadAttr) and last[n].attr.assignments == 1 or
1.236 + isinstance(last[n], LoadConst)):
1.237 +
1.238 + self.remove_ops(n+1)
1.239 + return 1
1.240 + else:
1.241 + return 0
1.242 +
1.243 + # Visitor methods.
1.244 +
1.245 + def default(self, node, *args):
1.246 + raise TranslateError(self.module.full_name(), node, "Node class %r is not supported." % node.__class__)
1.247 +
1.248 + def dispatch(self, node, *args):
1.249 + return ASTVisitor.dispatch(self, node, *args)
1.250 +
1.251 + def visitAdd(self, node):
1.252 +
1.253 + """
1.254 + _t1 = node.left
1.255 + _t2 = node.right
1.256 + try:
1.257 + _t1.__add__(_t2)
1.258 + except AttributeError:
1.259 + _t2.__radd__(_t1)
1.260 + """
1.261 +
1.262 + def visitAnd(self, node): pass
1.263 +
1.264 + def visitAssert(self, node): pass
1.265 +
1.266 + def visitAssign(self, node):
1.267 + self.dispatch(node.expr)
1.268 + for n in node.nodes:
1.269 + self.dispatch(n)
1.270 +
1.271 + def visitAssAttr(self, node):
1.272 + self._visitAttr(node, (StoreAttr, StoreAttrIndex))
1.273 +
1.274 + def visitAssList(self, node): pass
1.275 +
1.276 + def visitAssName(self, node):
1.277 + self._visitName(node, (StoreName, StoreAttr))
1.278 +
1.279 + visitAssTuple = visitAssList
1.280 +
1.281 + def visitAugAssign(self, node): pass
1.282 +
1.283 + def visitBackquote(self, node): pass
1.284 +
1.285 + def visitBitand(self, node): pass
1.286 +
1.287 + def visitBitor(self, node): pass
1.288 +
1.289 + def visitBitxor(self, node): pass
1.290 +
1.291 + def visitBreak(self, node):
1.292 + next_label, exit_label = self.loop_labels[-1]
1.293 + self.new_op(Jump(exit_label))
1.294 +
1.295 + def visitCallFunc(self, node):
1.296 +
1.297 + """
1.298 + Evaluate positional arguments, evaluate and store keyword arguments in
1.299 + the correct location, then invoke the function.
1.300 + """
1.301 +
1.302 + # Mark the frame, evaluate the target, generate the call.
1.303 +
1.304 + self._startCallFunc()
1.305 + self.dispatch(node.node)
1.306 + self._generateCallFunc(node.args, node)
1.307 +
1.308 def visitClass(self, node):
1.309 unit = self.unit
1.310 self.unit = node.unit