1.1 --- a/micropython/ast.py Sun May 11 21:50:30 2008 +0200
1.2 +++ b/micropython/ast.py Mon May 12 23:54:16 2008 +0200
1.3 @@ -265,44 +265,50 @@
1.4
1.5 if isinstance(target, Const):
1.6 target_name = target.value_type_name()
1.7 + elif isinstance(target, Instance):
1.8 + target_name = None # skip production of optimised code
1.9 else:
1.10 target_name = target.full_name()
1.11
1.12 - # Access the object table to get the attribute position.
1.13 + # Only try and discover the position if the target can be resolved.
1.14
1.15 - try:
1.16 - table_entry = self.objtable.table[target_name]
1.17 - except KeyError:
1.18 - raise TranslateError(self.module.full_name(), node,
1.19 - "No object entry exists for target %r." % target_name)
1.20 + if target_name is not None:
1.21 +
1.22 + # Access the object table to get the attribute position.
1.23
1.24 - try:
1.25 - pos = table_entry[attrname]
1.26 - except KeyError:
1.27 - raise TranslateError(self.module.full_name(), node,
1.28 - "No attribute entry exists for name %r in target %r." % (attrname, target_name))
1.29 + try:
1.30 + table_entry = self.objtable.table[target_name]
1.31 + except KeyError:
1.32 + raise TranslateError(self.module.full_name(), node,
1.33 + "No object entry exists for target %r." % target_name)
1.34
1.35 - # Produce a suitable instruction.
1.36 + try:
1.37 + pos = table_entry[attrname]
1.38 + except KeyError:
1.39 + raise TranslateError(self.module.full_name(), node,
1.40 + "No attribute entry exists for name %r in target %r." % (attrname, target_name))
1.41
1.42 - self.replace_op(AddressInstruction(pos))
1.43 + # Produce a suitable instruction.
1.44 +
1.45 + self.replace_op(AddressInstruction(pos))
1.46 + return
1.47
1.48 # Where the last operation involves the special 'self' name, check to
1.49 # see if the attribute is acceptably positioned and produce a direct
1.50 # access to the attribute.
1.51
1.52 - elif self._optimise_self_access(attrname, AttrInstruction):
1.53 - pass
1.54 + elif self._optimise_self_access(attrname, (AddressInstruction, AttrInstruction)):
1.55 + return
1.56
1.57 # Otherwise, perform a normal operation.
1.58
1.59 - else:
1.60 - try:
1.61 - index = self.objtable.get_index(attrname)
1.62 - except self.objtable.TableError:
1.63 - raise TranslateError(self.module.full_name(), node,
1.64 - "No attribute entry exists for name %r." % attrname)
1.65 + try:
1.66 + index = self.objtable.get_index(attrname)
1.67 + except self.objtable.TableError:
1.68 + raise TranslateError(self.module.full_name(), node,
1.69 + "No attribute entry exists for name %r." % attrname)
1.70
1.71 - self.new_op(AttrIndexInstruction(index))
1.72 + self.new_op(AttrIndexInstruction(index))
1.73
1.74 def _startCallFunc(self):
1.75
1.76 @@ -312,7 +318,30 @@
1.77
1.78 def _generateCallFunc(self, args, node):
1.79
1.80 - # NOTE: Only simple cases are used for optimisations.
1.81 + """
1.82 + Support a generic function invocation using the given 'args', occurring
1.83 + on the given 'node', where the expression providing the invocation
1.84 + target has just been generated.
1.85 +
1.86 + In other situations, the invocation is much simpler and does not need to
1.87 + handle the full flexibility of a typical Python invocation. Internal
1.88 + invocations, such as those employed by operators and certain
1.89 + control-flow mechanisms, use predetermined arguments and arguably do not
1.90 + need to support the same things as the more general invocations.
1.91 + """
1.92 +
1.93 + target, context, temp = self._generateCallFuncContext()
1.94 + self._generateCallFuncArgs(target, context, args, node)
1.95 + return temp
1.96 +
1.97 + def _generateCallFuncContext(self):
1.98 +
1.99 + """
1.100 + Produce code which loads and checks the context of the current
1.101 + invocation, the instructions for whose target have already been
1.102 + produced, returning a list of instructions which reference the
1.103 + invocation target.
1.104 + """
1.105
1.106 t = self._optimise_known_target()
1.107 if t:
1.108 @@ -334,17 +363,39 @@
1.109 self.new_op(LoadContext())
1.110 self.new_op(CheckContext())
1.111 self.new_op(JumpIfTrue(continue_label))
1.112 +
1.113 + # Where the context is inappropriate, drop the incomplete frame and
1.114 + # raise an exception.
1.115 +
1.116 + self.new_op(DropFrame())
1.117 self.dispatch(compiler.ast.Name("TypeError"))
1.118 self.new_op(RaiseException())
1.119 self.set_label(continue_label)
1.120 else:
1.121 pass # NOTE: Class methods should be supported.
1.122
1.123 + return target, context, temp
1.124 +
1.125 + def _generateCallFuncArgs(self, target, context, args, node):
1.126 +
1.127 + """
1.128 + Given invocation 'target' and 'context' information, a list of nodes
1.129 + representing the 'args' (arguments), generate instructions which load
1.130 + the arguments for the invocation defined by the given 'node'.
1.131 + """
1.132 +
1.133 # Evaluate the arguments.
1.134
1.135 employed_positions = set()
1.136 extra_keywords = []
1.137
1.138 + # NOTE: Fix context for self-accessed methods.
1.139 +
1.140 + if context is not None and isinstance(context, Instance):
1.141 + ncontext = 1
1.142 + else:
1.143 + ncontext = 0
1.144 +
1.145 for frame_pos, arg in enumerate(args):
1.146
1.147 # Handle positional and keyword arguments separately.
1.148 @@ -385,8 +436,8 @@
1.149
1.150 # Add space for arguments appearing before this one.
1.151
1.152 - if frame_pos < pos:
1.153 - self.new_op(ReserveFrame(pos - frame_pos))
1.154 + if frame_pos + ncontext < pos:
1.155 + self.new_op(ReserveFrame(pos - frame_pos - ncontext))
1.156
1.157 # Generate code for the keyword and the positioning
1.158 # operation.
1.159 @@ -396,7 +447,7 @@
1.160 # If the position corresponds to the current frame element,
1.161 # skip generating the store instruction.
1.162
1.163 - if frame_pos > pos:
1.164 + if frame_pos + ncontext > pos:
1.165 self.new_op(StoreFrame(pos))
1.166
1.167 # Otherwise, generate the code needed to obtain the details of
1.168 @@ -429,9 +480,9 @@
1.169
1.170 else:
1.171 self.dispatch(arg)
1.172 - employed_positions.add(frame_pos)
1.173 + employed_positions.add(frame_pos + ncontext)
1.174
1.175 - frame_pos = len(args)
1.176 + frame_pos = len(args) + ncontext
1.177
1.178 # NOTE: Extra keywords are not supported.
1.179 # NOTE: Somehow, the above needs to be combined with * arguments.
1.180 @@ -446,7 +497,7 @@
1.181 ndefaults = len(target.defaults)
1.182 nargs_min = nargs_max - ndefaults
1.183
1.184 - for i in range(0, nargs_min):
1.185 + for i in range(ncontext, nargs_min):
1.186 if i not in employed_positions:
1.187 raise TranslateError(self.module.full_name(), node,
1.188 "Argument %r not supplied for %r: need at least %d arguments." % (i+1, target.name, nargs_min))
1.189 @@ -481,8 +532,6 @@
1.190 else:
1.191 self.new_op(CheckFrame())
1.192
1.193 - return temp
1.194 -
1.195 def _endCallFunc(self, temp):
1.196
1.197 "Make the invocation and tidy up afterwards."
1.198 @@ -659,7 +708,7 @@
1.199 if self._should_optimise_known_target() and self._have_known_target():
1.200 last = self.last_op()
1.201 target = last.attr.value
1.202 - context = last.attr.parent
1.203 + context = last.context
1.204
1.205 # Handle calls to classes.
1.206
1.207 @@ -674,19 +723,25 @@
1.208 else:
1.209 return None
1.210
1.211 - def _optimise_self_access(self, attrname, instruction):
1.212 + def _optimise_self_access(self, attrname, classes):
1.213
1.214 """
1.215 Where the provided 'attrname' accesses an attribute which occupies the
1.216 same position in all possible objects which can be accessed, generate an
1.217 - 'instruction' accessing the attribute directly.
1.218 + instruction using one of the given 'classes', accessing the attribute
1.219 + directly.
1.220 """
1.221
1.222 + AddressInstruction, AttrInstruction = classes
1.223 +
1.224 if self._should_optimise_self_access() and self._have_self_input() and \
1.225 not self.unit.is_relocated(attrname):
1.226
1.227 attr = self.unit.parent.all_attributes()[attrname]
1.228 - self.new_op(instruction(attr))
1.229 + if isinstance(attr.parent, Instance):
1.230 + self.new_op(AttrInstruction(attr))
1.231 + else:
1.232 + self.new_op(AddressInstruction(attr, Instance()))
1.233 return 1
1.234 else:
1.235 return 0
1.236 @@ -737,6 +792,7 @@
1.237 temp_method = self._optimise_temp_storage()
1.238
1.239 # Add arguments.
1.240 + # NOTE: No support for defaults.
1.241
1.242 self.new_ops(temp) # Explicit context as first argument.
1.243 self._endCallFunc(temp_method)
1.244 @@ -812,6 +868,7 @@
1.245 temp_method = self._optimise_temp_storage()
1.246
1.247 # Add arguments.
1.248 + # NOTE: No support for defaults.
1.249
1.250 self.new_ops(temp1) # Explicit context as first argument.
1.251 self.new_ops(temp2)
1.252 @@ -852,6 +909,7 @@
1.253 temp_method = self._optimise_temp_storage()
1.254
1.255 # Add arguments.
1.256 + # NOTE: No support for defaults.
1.257
1.258 self.new_ops(temp2) # Explicit context as first argument.
1.259 self.new_ops(temp1)