# HG changeset patch # User Paul Boddie # Date 1283040204 -7200 # Node ID 70692e257878fd27b8e90e0ef3d16c89337a9832 # Parent aaf23d3b2bcd4c77c6e07154df4a1bdefbf08198 Added support for tuple parameters. Optimised tuple/list assignment. diff -r aaf23d3b2bcd -r 70692e257878 TO_DO.txt --- a/TO_DO.txt Mon Aug 23 00:15:03 2010 +0200 +++ b/TO_DO.txt Sun Aug 29 02:03:24 2010 +0200 @@ -1,4 +1,9 @@ -Fix the attribute names in the report. +Fix object table entries for attributes not provided by any known object, or provide an +error, potentially overridden by options. For example, the augmented assignment methods +are not supported by the built-in objects and thus the operator module functions cause +the compilation to fail. + +Support tuple parameters. Consider type deduction and its consequences where types belong to the same hierarchy and where a guard could be generated for the most general type. diff -r aaf23d3b2bcd -r 70692e257878 lib/builtins.py --- a/lib/builtins.py Mon Aug 23 00:15:03 2010 +0200 +++ b/lib/builtins.py Sun Aug 29 02:03:24 2010 +0200 @@ -4,7 +4,7 @@ Simple built-in classes and functions. Objects which provide code that shall always be compiled should provide docstrings. -Copyright (C) 2005, 2006, 2007, 2008, 2009 Paul Boddie +Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software diff -r aaf23d3b2bcd -r 70692e257878 micropython/ast.py --- a/micropython/ast.py Mon Aug 23 00:15:03 2010 +0200 +++ b/micropython/ast.py Sun Aug 29 02:03:24 2010 +0200 @@ -479,10 +479,13 @@ found within the given 'node'. """ + self.new_op(self.expr_temp[-1]) + self._generateAttr(node, "__getitem__", self.attribute_load_instructions) + temp_getitem = self.optimiser.optimise_temp_storage() + for i, n in enumerate(node.nodes): self._startCallFunc() - self.new_op(self.expr_temp[-1]) - self._generateAttr(node, "__getitem__", self.attribute_load_instructions) + self.new_op(temp_getitem) temp_target, target, temp_context = self._generateCallFunc([compiler.ast.Const(i)], node) self._doCallFunc(temp_target, target) self._endCallFunc(temp_target, target, temp_context) @@ -496,6 +499,8 @@ self.dispatch(n) self.discard_value() + self.discard_temp(temp_getitem) + def visitAssName(self, node): "Assign the assignment expression to the recipient 'node'." diff -r aaf23d3b2bcd -r 70692e257878 micropython/data.py --- a/micropython/data.py Mon Aug 23 00:15:03 2010 +0200 +++ b/micropython/data.py Sun Aug 29 02:03:24 2010 +0200 @@ -1405,11 +1405,24 @@ self.all_local_usage = 0 def _add_parameters(self, argnames): + + "Add 'argnames' to the namespace." + + for name in argnames: + self.set(name, Instance()) + + for name, top_level in self._flattened_parameters(argnames): + if not top_level: + self.set(name, Instance()) + + def _flattened_parameters(self, argnames, top_level=1): + l = [] for name in argnames: if isinstance(name, tuple): - self._add_parameters(name) + l += self._flattened_parameters(name, 0) else: - self.set(name, Instance()) + l.append((name, top_level)) + return l def __repr__(self): if self.location is not None: @@ -1495,6 +1508,24 @@ parameters[name] = i return parameters + def tuple_parameters(self, argnames=None): + + """ + Return a list of (position, parameter) entries corresponding to tuple + parameters, where each parameter may either be a string or another such + list of entries. + """ + + names = argnames or self.argnames + + l = [] + for i, name in enumerate(names): + if isinstance(name, tuple): + l.append((i, self.tuple_parameters(name))) + elif argnames: + l.append((i, name)) + return l + def all_locals(self): "Return a dictionary mapping names to local and parameter details." @@ -1556,17 +1587,17 @@ for i, default in enumerate(self.default_attrs): default.position = i - # Locals. + # Parameters. - i = None - for i, name in enumerate(self.argnames): - self[name].position = i + i = self._finalise_parameters() if i is not None: nparams = i + 1 else: nparams = 0 + # Locals (and tuple parameter names). + i = None for i, attr in enumerate(self.locals().values()): attr.position = i + nparams @@ -1580,6 +1611,15 @@ self.all_local_usage = nparams + nothers self.finalised = 1 + def _finalise_parameters(self): + if not self.argnames: + return None + + for i, name in enumerate(self.argnames): + self[name].position = i + + return i + def as_instantiator(self): "Make an instantiator function from a method, keeping all arguments." diff -r aaf23d3b2bcd -r 70692e257878 micropython/inspect.py --- a/micropython/inspect.py Mon Aug 23 00:15:03 2010 +0200 +++ b/micropython/inspect.py Sun Aug 29 02:03:24 2010 +0200 @@ -461,6 +461,13 @@ self.expr = self.dispatch(n) function.store_default(self.expr) + # Note attribute usage where tuple parameters are involved. + + if function.tuple_parameters(): + self.use_name("__getitem__", node) + + # Record the namespace context of the function for later processing. + self.functions.append((node, self.namespaces + [function])) # Store the function. diff -r aaf23d3b2bcd -r 70692e257878 micropython/opt.py --- a/micropython/opt.py Mon Aug 23 00:15:03 2010 +0200 +++ b/micropython/opt.py Sun Aug 29 02:03:24 2010 +0200 @@ -367,9 +367,9 @@ """ Where the next operation would involve storing a value into temporary - storage at 'temp_position', record and remove any simple instruction - which produced the value to be stored such that instead of subsequently - accessing the temporary storage, that instruction is substituted. + storage, record and remove any simple instruction which produced the + value to be stored such that instead of subsequently accessing the + temporary storage, that instruction is substituted. If no optimisation can be achieved, a StoreTemp instruction is produced and the appropriate LoadTemp instruction is returned. diff -r aaf23d3b2bcd -r 70692e257878 micropython/trans.py --- a/micropython/trans.py Mon Aug 23 00:15:03 2010 +0200 +++ b/micropython/trans.py Sun Aug 29 02:03:24 2010 +0200 @@ -1072,6 +1072,10 @@ extend = ExtendFrame() self.new_op(extend) + # Perform tuple assignment for any tuple parameters. + + self._visitFunctionTupleParameters(fn, node) + # For functions with star parameters, make a special list for the # extra arguments and re-map the parameter. @@ -1109,6 +1113,48 @@ self.set_frame_usage(node, extend) + def _visitFunctionTupleParameters(self, fn, node, parameters=None): + + """ + Visit the tuple parameters for function 'fn', obtaining the appropriate + elements from each supplied argument and assigning them to the specified + names for each parameter. + """ + + if parameters is not None: + self._generateAttr(node, "__getitem__", self.attribute_load_instructions) + temp_getitem = self.optimiser.optimise_temp_storage() + + for i, parameter in parameters or fn.tuple_parameters(): + + # Either load the parameter from the frame. + + if parameters is None: + self.new_op(LoadName(Attr(i, None, None))) + + # Or load a value from the current collection. + + else: + self._startCallFunc() + self.new_op(temp_getitem) + temp_target, target, temp_context = self._generateCallFunc([compiler.ast.Const(i)], node) + self._doCallFunc(temp_target, target) + self._endCallFunc(temp_target, target, temp_context) + + # Where a tuple is the target, attempt to descend into the value + # obtained. + + if isinstance(parameter, list): + self._visitFunctionTupleParameters(fn, node, parameter) + + # Store the item in the namespace entry for the given name. + + else: + self.new_op(StoreName(fn[parameter])) + + if parameters is not None: + self.discard_temp(temp_getitem) + def _generateFunctionDefaults(self, function): """ diff -r aaf23d3b2bcd -r 70692e257878 tests/call_func_tuple_parameters.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/call_func_tuple_parameters.py Sun Aug 29 02:03:24 2010 +0200 @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +def f((a, b), c): + return b + +def g((a, b), c): + return c + +result_2 = f((1, 2), 3) +result1_3 = g((1, 2), 3) +result2_3 = f(((1, 2), 3), 4) +result_4 = g(((1, 2), 3), 4) + +# vim: tabstop=4 expandtab shiftwidth=4