micropython

Changeset

333:676798ee996f
2010-06-11 Paul Boddie raw files shortlog changelog graph Merged dynamic/nested function and general development branches.
micropython/__init__.py (file)
     1.1 --- a/docs/invocation.txt	Fri Jun 11 00:56:08 2010 +0200
     1.2 +++ b/docs/invocation.txt	Fri Jun 11 00:58:42 2010 +0200
     1.3 @@ -163,13 +163,31 @@
     1.4  
     1.5    Approach #2 - add arguments, add defaults while checking frame
     1.6  
     1.7 -Defaults for lambda functions:
     1.8 +Dynamic functions:
     1.9  
    1.10 -  f = lambda x, y=default: ...
    1.11 +  def f(x):
    1.12 +    def g(y=x):         # dynamic: y depends on non-constant value
    1.13 +      ...
    1.14 +    def h(y=2):         # static: y depends on constant value
    1.15 +      ...
    1.16 +
    1.17 +  def f(x):
    1.18 +    g = lambda y=x: ... # dynamic: y depends on non-constant value
    1.19 +    h = lambda y=2: ... # static: y depends on constant value
    1.20  
    1.21 -  Defines instance of f with method:
    1.22 +Representation of dynamic functions:
    1.23 +
    1.24 +  f = lambda x, y=nonconst: ...
    1.25 +
    1.26 +  def f(x, y=nonconst):
    1.27 +    ...
    1.28  
    1.29 -    def <lambda>(<context>, x, y=default):
    1.30 +  Defines instance with method:
    1.31 +
    1.32 +    def <lambda>(<context>, x, y=nonconst):
    1.33 +      ...
    1.34 +
    1.35 +    def f(<context>, x, y=nonconst):
    1.36        ...
    1.37  
    1.38    Where default is attribute #1.
     2.1 --- a/micropython/__init__.py	Fri Jun 11 00:56:08 2010 +0200
     2.2 +++ b/micropython/__init__.py	Fri Jun 11 00:58:42 2010 +0200
     2.3 @@ -167,9 +167,9 @@
     2.4                      self.code.append(obj)
     2.5  
     2.6                      # Append any default values to the image.
     2.7 -                    # Only do this for named functions (not lambdas).
     2.8 +                    # Only do this for functions which are not dynamic.
     2.9  
    2.10 -                    if obj.name is not None:
    2.11 +                    if not obj.is_dynamic():
    2.12                          self.code += obj.default_attrs
    2.13  
    2.14                      # Omit built-in function code where requested.
     3.1 --- a/micropython/ast.py	Fri Jun 11 00:56:08 2010 +0200
     3.2 +++ b/micropython/ast.py	Fri Jun 11 00:58:42 2010 +0200
     3.3 @@ -586,70 +586,20 @@
     3.4          # Only store the name when visiting this node from outside.
     3.5  
     3.6          if self.unit is not node.unit:
     3.7 -            self.new_op(LoadFunction(node.unit))
     3.8 +            self._visitFunctionDeclaration(node)
     3.9 +
    3.10 +            # Record the declared function.
    3.11 +
    3.12              self.record_value()
    3.13  
    3.14              self._visitName(node, self.name_store_instructions) # AssName equivalent
    3.15              self.set_source()
    3.16              self.discard_value()
    3.17  
    3.18 -            self._generateFunctionDefaults(node.unit)
    3.19 -
    3.20          # Visiting of the code occurs when get_code is invoked on this node.
    3.21  
    3.22          else:
    3.23 -            # Check frames using the function's details.
    3.24 -
    3.25 -            fn = node.unit
    3.26 -            nparams = len(fn.positional_names)
    3.27 -            ndefaults = len(fn.defaults)
    3.28 -
    3.29 -            fn.body_block = self.new_block()
    3.30 -
    3.31 -            # Check the number of parameters and defaults.
    3.32 -
    3.33 -            self.new_op(CheckFrame((nparams, ndefaults)))
    3.34 -            if ndefaults > 0:
    3.35 -                self.new_op(LoadFunction(fn))
    3.36 -                self.new_op(FillDefaults((nparams, ndefaults)))
    3.37 -
    3.38 -            # Produce the body.
    3.39 -
    3.40 -            self.set_block(fn.body_block)
    3.41 -
    3.42 -            extend = ExtendFrame()
    3.43 -            self.new_op(extend)
    3.44 -
    3.45 -            # For functions with star parameters, make a special list for the
    3.46 -            # extra arguments and re-map the parameter.
    3.47 -
    3.48 -            if fn.has_star:
    3.49 -                self.new_op(CopyExtra(nparams))
    3.50 -
    3.51 -                # Ensure that the star parameter has a slot in the frame.
    3.52 -
    3.53 -                self.new_op(CheckExtra(nparams))
    3.54 -                self.new_op(StoreTemp(nparams))
    3.55 -
    3.56 -            # Add any attribute usage guards.
    3.57 -
    3.58 -            if self.optimiser.should_optimise_accesses_by_attribute_usage() and hasattr(node, "_attrnames"):
    3.59 -                self._generateGuards(node)
    3.60 -
    3.61 -            # Visit the actual code.
    3.62 -
    3.63 -            self.dispatch(node.code)
    3.64 -
    3.65 -            # Add a return statement where one is not already produced.
    3.66 -
    3.67 -            if not isinstance(self.last_op(), Return):
    3.68 -                self.dispatch(compiler.ast.Name("None"))
    3.69 -                self.new_op(StoreResult())
    3.70 -                self.new_op(Return())
    3.71 -
    3.72 -            # Make sure that enough frame space is reserved from the start.
    3.73 -
    3.74 -            self.set_frame_usage(node, extend)
    3.75 +            self._visitFunctionDefinition(node)
    3.76  
    3.77      def visitGlobal(self, node): pass
    3.78  
    3.79 @@ -675,58 +625,15 @@
    3.80          # outside.
    3.81  
    3.82          if self.unit is not node.unit:
    3.83 -            fn = node.unit
    3.84 -            ndefaults = len(fn.defaults)
    3.85 -            temp = self._generateFunctionDefaults(fn)
    3.86 -
    3.87 -            if ndefaults > 0:
    3.88 -                self.new_op(LoadConst(fn))
    3.89 -            else:
    3.90 -                self.new_op(LoadFunction(fn))
    3.91  
    3.92 -            # Populate the new object required for the function.
    3.93 +            # Provide the declared function.
    3.94  
    3.95 -            if temp is not None:
    3.96 -                self.new_op(LoadCallable())
    3.97 -                self.new_op(temp)
    3.98 -                self.new_op(StoreCallable())
    3.99 -
   3.100 -                self.new_op(temp)
   3.101 -                #self.discard_temp(temp)
   3.102 +            self._visitFunctionDeclaration(node)
   3.103  
   3.104          # Visiting of the code occurs when get_code is invoked on this node.
   3.105  
   3.106          else:
   3.107 -            # Check frames using the function's details.
   3.108 -
   3.109 -            fn = node.unit
   3.110 -            nparams = len(fn.positional_names)
   3.111 -            ndefaults = len(fn.defaults)
   3.112 -
   3.113 -            fn.body_block = self.new_block()
   3.114 -
   3.115 -            # Check the number of parameters and defaults.
   3.116 -
   3.117 -            self.new_op(CheckFrame((nparams, ndefaults)))
   3.118 -            if ndefaults > 0:
   3.119 -                self.new_op(LoadTemp(0)) # context provides storage
   3.120 -                self.new_op(FillDefaults((nparams, ndefaults)))
   3.121 -
   3.122 -            # Produce the body.
   3.123 -
   3.124 -            self.set_block(fn.body_block)
   3.125 -
   3.126 -            extend = ExtendFrame()
   3.127 -            self.new_op(extend)
   3.128 -
   3.129 -            self.dispatch(node.code)
   3.130 -
   3.131 -            self.new_op(StoreResult())
   3.132 -            self.new_op(Return())
   3.133 -
   3.134 -            # Make sure that enough frame space is reserved from the start.
   3.135 -
   3.136 -            self.set_frame_usage(node, extend)
   3.137 +            self._visitFunctionDefinition(node)
   3.138  
   3.139      def visitModule(self, node):
   3.140          extend = ExtendFrame()
     4.1 --- a/micropython/data.py	Fri Jun 11 00:56:08 2010 +0200
     4.2 +++ b/micropython/data.py	Fri Jun 11 00:58:42 2010 +0200
     4.3 @@ -206,6 +206,9 @@
     4.4              self.namespace[name] = Attr(None, self, name)
     4.5  
     4.6          attr = self.namespace[name]
     4.7 +        self._set_using_attr(attr, attr_or_value, single_assignment)
     4.8 +
     4.9 +    def _set_using_attr(self, attr, attr_or_value, single_assignment=1):
    4.10  
    4.11          # Handle attribute assignment as well as assignment of basic objects.
    4.12          # Attempt to fix the context if not explicitly defined.
    4.13 @@ -557,6 +560,25 @@
    4.14  
    4.15          self.context_values.update(context_values)
    4.16  
    4.17 +    def is_constant(self):
    4.18 +
    4.19 +        """
    4.20 +        Return whether this attribute references something that can be regarded
    4.21 +        as being constant within a particular scope.
    4.22 +        """
    4.23 +
    4.24 +        return self.assignments == 1
    4.25 +
    4.26 +    def is_strict_constant(self):
    4.27 +
    4.28 +        """
    4.29 +        Return whether this attribute references something that can be regarded
    4.30 +        as being constant.
    4.31 +        """
    4.32 +
    4.33 +        value = self.get_value()
    4.34 +        return not (value is None or isinstance(value, Instance))
    4.35 +
    4.36      def is_static_attribute(self):
    4.37  
    4.38          """
    4.39 @@ -643,11 +665,16 @@
    4.40              return 0
    4.41  
    4.42      def __repr__(self):
    4.43 -        return "Attr(%r, %s, %r) # [%s], %r" % (
    4.44 +        return "Attr(%r, %s, %r) # {[%s] (%r)}" % (
    4.45              self.position, shortrepr(self.parent), self.name,
    4.46              self._context_values_str(), self.assignments
    4.47              )
    4.48  
    4.49 +    def __shortrepr__(self):
    4.50 +        return "Attr(%r, %s, %r)" % (
    4.51 +            self.position, shortrepr(self.parent), self.name
    4.52 +            )
    4.53 +
    4.54      def _context_values_str(self):
    4.55          l = []
    4.56          for (c, v) in self.context_values:
    4.57 @@ -1075,7 +1102,8 @@
    4.58  
    4.59      "An inspected function."
    4.60  
    4.61 -    def __init__(self, name, parent, argnames, defaults, has_star, has_dstar, module=None, node=None):
    4.62 +    def __init__(self, name, parent, argnames, defaults, has_star, has_dstar,
    4.63 +        dynamic_def=0, module=None, node=None):
    4.64  
    4.65          """
    4.66          Initialise the function with the given 'name', 'parent', list of
    4.67 @@ -1091,14 +1119,10 @@
    4.68          self.defaults = defaults
    4.69          self.has_star = has_star
    4.70          self.has_dstar = has_dstar
    4.71 +        self.dynamic_def = dynamic_def
    4.72          self.astnode = node
    4.73          node._def = self
    4.74  
    4.75 -        # For lambda functions with defaults, add a context argument.
    4.76 -
    4.77 -        if name is None and defaults:
    4.78 -            self.argnames.insert(0, "<context>")
    4.79 -
    4.80          # Initialise the positional names.
    4.81  
    4.82          self.positional_names = self.argnames[:]
    4.83 @@ -1139,6 +1163,7 @@
    4.84  
    4.85          # Image generation details.
    4.86  
    4.87 +        self.dynamic = None
    4.88          self.location = None
    4.89          self.code_location = None
    4.90          self.code_body_location = None
    4.91 @@ -1157,7 +1182,7 @@
    4.92              if isinstance(name, tuple):
    4.93                  self._add_parameters(name)
    4.94              else:
    4.95 -                self.set(name, None)
    4.96 +                self.set(name, Instance())
    4.97  
    4.98      def __repr__(self):
    4.99          if self.location is not None:
   4.100 @@ -1177,12 +1202,46 @@
   4.101      def get_body_block(self):
   4.102          return self.body_block
   4.103  
   4.104 -    # Namespace-related methods.
   4.105 +    # Defaults-related methods.
   4.106 +
   4.107 +    def store_default(self, attr_or_value):
   4.108 +
   4.109 +        """
   4.110 +        Reserve space for defaults, set outside the function, potentially on a
   4.111 +        dynamic basis, using the 'attr_or_value'.
   4.112 +        """
   4.113 +
   4.114 +        attr = Attr(None, self, None)
   4.115 +        self._set_using_attr(attr, attr_or_value)
   4.116 +        self.default_attrs.append(attr)
   4.117 +
   4.118 +    def make_dynamic(self):
   4.119 +
   4.120 +        "Return whether this function must be handled using a dynamic object."
   4.121  
   4.122 -    def store_default(self, value):
   4.123 -        attr = Attr(None, self, None)
   4.124 -        attr.update([self.get_context_and_value(value)], 1)
   4.125 -        self.default_attrs.append(attr)
   4.126 +        if self.dynamic is None:
   4.127 +            for attr in self.default_attrs:
   4.128 +                if not attr.is_strict_constant() and self.dynamic_def:
   4.129 +                    self.dynamic = 1
   4.130 +                    self._make_dynamic()
   4.131 +                    break
   4.132 +            else:
   4.133 +                self.dynamic = 0
   4.134 +
   4.135 +        return self.dynamic
   4.136 +
   4.137 +    is_dynamic = make_dynamic
   4.138 +
   4.139 +    def _make_dynamic(self):
   4.140 +
   4.141 +        "Where functions have dynamic defaults, add a context argument."
   4.142 +
   4.143 +        name = "<context>"
   4.144 +        self.argnames.insert(0, name)
   4.145 +        self.positional_names.insert(0, name)
   4.146 +        self.set(name, Instance())
   4.147 +
   4.148 +    # Namespace-related methods.
   4.149  
   4.150      def make_global(self, name):
   4.151          if name not in self.argnames and not self.has_key(name):
   4.152 @@ -1285,7 +1344,7 @@
   4.153          "Make an instantiator function from a method, keeping all arguments."
   4.154  
   4.155          function = Function(self.parent.name, self.parent.parent, self.argnames, self.defaults,
   4.156 -            self.has_star, self.has_dstar, self.module, self.astnode)
   4.157 +            self.has_star, self.has_dstar, self.dynamic_def, self.module, self.astnode)
   4.158          function.default_attrs = self.default_attrs
   4.159          return function
   4.160  
     5.1 --- a/micropython/inspect.py	Fri Jun 11 00:56:08 2010 +0200
     5.2 +++ b/micropython/inspect.py	Fri Jun 11 00:58:42 2010 +0200
     5.3 @@ -67,8 +67,9 @@
     5.4  
     5.5  Assignments to names within functions are not generally considered to cause the
     5.6  targets of such assignments to provide constant values since functions can be
     5.7 -invoked many times with different inputs. However, there may be benefits in
     5.8 -considering a local to be constant within a single invocation.
     5.9 +invoked many times with different inputs. This affects particularly the
    5.10 +definition of functions or lambdas within functions. However, there may be
    5.11 +benefits in considering a local to be constant within a single invocation.
    5.12  """
    5.13  
    5.14  from micropython.common import *
    5.15 @@ -111,6 +112,7 @@
    5.16  
    5.17          self.in_init = 0        # Find instance attributes in __init__ methods.
    5.18          self.in_method = 0      # Find instance attributes in all methods.
    5.19 +        self.in_function = 0    # Note function presence, affecting definitions.
    5.20          self.in_loop = 0        # Note loop "membership", affecting assignments.
    5.21          self.namespaces = []
    5.22          self.module = None
    5.23 @@ -261,6 +263,10 @@
    5.24  
    5.25      # Namespace methods.
    5.26  
    5.27 +    def in_class(self, namespaces=None):
    5.28 +        namespaces = namespaces or self.namespaces
    5.29 +        return len(namespaces) > 1 and isinstance(namespaces[-2], Class)
    5.30 +
    5.31      def store(self, name, obj):
    5.32  
    5.33          "Record attribute or local 'name', storing 'obj'."
    5.34 @@ -436,6 +442,7 @@
    5.35              node.defaults,
    5.36              (node.flags & 4 != 0),
    5.37              (node.flags & 8 != 0),
    5.38 +            self.in_loop or self.in_function,
    5.39              self,
    5.40              node
    5.41              )
    5.42 @@ -454,18 +461,16 @@
    5.43  
    5.44          self.functions.append((node, self.namespaces + [function]))
    5.45  
    5.46 +        # Store the function.
    5.47 +
    5.48          if name is not None:
    5.49              self.store(name, function)
    5.50          else:
    5.51              self.store_lambda(function)
    5.52  
    5.53 -            # Where defaults exist, an instance needs creating. Thus, it makes
    5.54 -            # no sense to return a reference to the function here, since the
    5.55 -            # recipient will not be referencing the function itself.
    5.56 +        # Test the defaults and assess whether an dynamic object will result.
    5.57  
    5.58 -            if node.defaults:
    5.59 -                return Instance() # indicates no known target
    5.60 -
    5.61 +        function.make_dynamic()
    5.62          return function
    5.63  
    5.64      def _visitFunctionBody(self, node, namespaces):
    5.65 @@ -475,14 +480,21 @@
    5.66          # Current namespace is the function.
    5.67          # Previous namespace is the class.
    5.68  
    5.69 -        if len(namespaces) > 1 and isinstance(namespaces[-2], Class):
    5.70 +        if self.in_class(namespaces):
    5.71              if namespaces[-1].name == "__init__":
    5.72                  self.in_init = 1
    5.73              self.in_method = 1
    5.74  
    5.75 +        in_function = self.in_function
    5.76 +        in_loop = self.in_loop
    5.77 +        self.in_function = 1
    5.78 +        self.in_loop = 0
    5.79 +
    5.80          self.namespaces = namespaces
    5.81          self.dispatch(node.code)
    5.82  
    5.83 +        self.in_loop = in_loop
    5.84 +        self.in_function = in_function
    5.85          self.in_init = 0
    5.86          self.in_method = 0
    5.87  
    5.88 @@ -597,6 +609,9 @@
    5.89              print "Class %r in %r is not global: ignored." % (node.name, self.namespaces[-1].full_name())
    5.90              return None
    5.91          else:
    5.92 +            if self.in_loop:
    5.93 +                print "Warning: class %r in %r defined in a loop." % (node.name, self.full_name())
    5.94 +
    5.95              cls = Class(node.name, self.get_namespace(), self, node)
    5.96  
    5.97              # Visit the base class expressions, attempting to find concrete
    5.98 @@ -698,6 +713,7 @@
    5.99          self.use_name("__iter__", node.list)
   5.100          self.use_name("next")
   5.101  
   5.102 +        in_loop = self.in_loop
   5.103          self.in_loop = 1
   5.104          self.dispatch(node.assign)
   5.105          self.dispatch(node.list)
   5.106 @@ -708,7 +724,7 @@
   5.107          self.new_branch()
   5.108          self.dispatch(node.body)
   5.109          self.shelve_branch()
   5.110 -        self.in_loop = 0
   5.111 +        self.in_loop = in_loop
   5.112  
   5.113          # Maintain a branch for the else clause or the current retained usage
   5.114          # where execution avoids the conditional clauses.
   5.115 @@ -987,12 +1003,13 @@
   5.116  
   5.117          # Propagate attribute usage to branches.
   5.118  
   5.119 +        in_loop = self.in_loop
   5.120          self.in_loop = 1
   5.121          self.dispatch(node.test)
   5.122          self.new_branch(node)
   5.123          self.dispatch(node.body)
   5.124          self.shelve_branch()
   5.125 -        self.in_loop = 0
   5.126 +        self.in_loop = in_loop
   5.127  
   5.128          # Maintain a branch for the else clause or the current retained usage
   5.129          # where execution avoids the conditional clauses.
     6.1 --- a/micropython/rsvp.py	Fri Jun 11 00:56:08 2010 +0200
     6.2 +++ b/micropython/rsvp.py	Fri Jun 11 00:58:42 2010 +0200
     6.3 @@ -177,12 +177,12 @@
     6.4          if not self.is_generated(with_builtins):
     6.5              item.code_location = item.full_name()
     6.6  
     6.7 -        # Skip any defaults for named functions.
     6.8 +        # Skip any defaults for static functions.
     6.9  
    6.10 -        elif item.name is not None:
    6.11 +        elif not item.is_dynamic():
    6.12              item.code_location = location + len(item.defaults)
    6.13  
    6.14 -        # Skip any defaults for lambda functions.
    6.15 +        # Skip any defaults for dynamic functions.
    6.16  
    6.17          else:
    6.18              item.code_location = location
     7.1 --- a/micropython/trans.py	Fri Jun 11 00:56:08 2010 +0200
     7.2 +++ b/micropython/trans.py	Fri Jun 11 00:58:42 2010 +0200
     7.3 @@ -619,7 +619,10 @@
     7.4          t = self.optimiser.optimise_known_target()
     7.5          if t:
     7.6              target, context = t
     7.7 -            if isinstance(target, Instance): # lambda object
     7.8 +
     7.9 +            # Detect dynamic functions acting like instances.
    7.10 +
    7.11 +            if isinstance(target, Function) and target.is_dynamic():
    7.12                  target, context = None, None
    7.13          else:
    7.14              target, context = None, None
    7.15 @@ -904,10 +907,9 @@
    7.16          'employed_positions' collection.
    7.17          """
    7.18  
    7.19 -        # Where a lambda is involved, construct a dynamic object to hold the
    7.20 -        # defaults.
    7.21 +        # Where appropriate, construct a dynamic object to hold the defaults.
    7.22  
    7.23 -        dynamic = target.name is None
    7.24 +        dynamic = target.is_dynamic()
    7.25  
    7.26          # Here, we use negative index values to visit the right hand end of
    7.27          # the defaults list.
    7.28 @@ -1019,6 +1021,103 @@
    7.29          if temp_context is not None:
    7.30              self.discard_temp(temp_context)
    7.31  
    7.32 +    def _visitFunctionDeclaration(self, node):
    7.33 +
    7.34 +        """
    7.35 +        Visit the function declaration at 'node', which can be a lambda or a
    7.36 +        named function. As a consequence an instruction will be generated which
    7.37 +        provides a reference to the function.
    7.38 +        """
    7.39 +
    7.40 +        fn = node.unit
    7.41 +        ndefaults = len(fn.defaults)
    7.42 +        temp = self._generateFunctionDefaults(fn)
    7.43 +
    7.44 +        # Populate the new object required for the function.
    7.45 +
    7.46 +        if temp is not None:
    7.47 +            self.new_op(LoadConst(fn))
    7.48 +            self.new_op(LoadCallable())
    7.49 +            self.new_op(temp)
    7.50 +            self.new_op(StoreCallable())
    7.51 +
    7.52 +            self.new_op(temp)
    7.53 +            #self.discard_temp(temp)
    7.54 +        else:
    7.55 +            self.new_op(LoadFunction(fn))
    7.56 +
    7.57 +    def _visitFunctionDefinition(self, node):
    7.58 +
    7.59 +        """
    7.60 +        Visit the function definition at 'node', which can be a lambda or a
    7.61 +        named function, generating the prelude with argument and default
    7.62 +        checking, plus the body of the function itself.
    7.63 +        """
    7.64 +
    7.65 +        # Check frames using the function's details.
    7.66 +
    7.67 +        fn = node.unit
    7.68 +        nparams = len(fn.positional_names)
    7.69 +        ndefaults = len(fn.defaults)
    7.70 +
    7.71 +        fn.body_block = self.new_block()
    7.72 +
    7.73 +        # Check the number of parameters and defaults.
    7.74 +
    7.75 +        self.new_op(CheckFrame((nparams, ndefaults)))
    7.76 +
    7.77 +        if fn.is_dynamic():
    7.78 +            self.new_op(LoadTemp(0)) # context provides storage
    7.79 +        else:
    7.80 +            self.new_op(LoadFunction(fn))
    7.81 +
    7.82 +        if ndefaults > 0:
    7.83 +            self.new_op(FillDefaults((nparams, ndefaults)))
    7.84 +
    7.85 +        # Produce the body.
    7.86 +
    7.87 +        self.set_block(fn.body_block)
    7.88 +
    7.89 +        extend = ExtendFrame()
    7.90 +        self.new_op(extend)
    7.91 +
    7.92 +        # For functions with star parameters, make a special list for the
    7.93 +        # extra arguments and re-map the parameter.
    7.94 +
    7.95 +        if fn.has_star:
    7.96 +            self.new_op(CopyExtra(nparams))
    7.97 +
    7.98 +            # Ensure that the star parameter has a slot in the frame.
    7.99 +
   7.100 +            self.new_op(CheckExtra(nparams))
   7.101 +            self.new_op(StoreTemp(nparams))
   7.102 +
   7.103 +        # Add any attribute usage guards.
   7.104 +
   7.105 +        if self.optimiser.should_optimise_accesses_by_attribute_usage() and hasattr(node, "_attrnames"):
   7.106 +            self._generateGuards(node)
   7.107 +
   7.108 +        # Visit the actual code.
   7.109 +
   7.110 +        self.dispatch(node.code)
   7.111 +
   7.112 +        # Add a return statement where one is not already produced.
   7.113 +
   7.114 +        if not isinstance(self.last_op(), Return):
   7.115 +
   7.116 +            # Return None for normal functions without explicit return
   7.117 +            # statements.
   7.118 +
   7.119 +            if fn.name is not None:
   7.120 +                self.dispatch(compiler.ast.Name("None"))
   7.121 +
   7.122 +            self.new_op(StoreResult())
   7.123 +            self.new_op(Return())
   7.124 +
   7.125 +        # Make sure that enough frame space is reserved from the start.
   7.126 +
   7.127 +        self.set_frame_usage(node, extend)
   7.128 +
   7.129      def _generateFunctionDefaults(self, function):
   7.130  
   7.131          """
   7.132 @@ -1031,10 +1130,10 @@
   7.133          if not attr_to_default:
   7.134              return None
   7.135  
   7.136 -        # Where a lambda is involved, construct a dynamic object to hold the
   7.137 -        # defaults.
   7.138 +        # Where non-constant defaults are involved, construct a dynamic object
   7.139 +        # to hold the defaults.
   7.140  
   7.141 -        dynamic = function.name is None
   7.142 +        dynamic = function.is_dynamic()
   7.143  
   7.144          if dynamic:
   7.145              self.make_instance(self.get_builtin_class("function", function), len(attr_to_default))
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/tests/call_func_default_global.py	Fri Jun 11 00:58:42 2010 +0200
     8.3 @@ -0,0 +1,11 @@
     8.4 +#!/usr/bin/env python
     8.5 +
     8.6 +d = 4
     8.7 +
     8.8 +def f(a, b, c=d):
     8.9 +    return c
    8.10 +
    8.11 +result_3 = f(1, 2, 3)
    8.12 +result_4 = f(1, 2)
    8.13 +
    8.14 +# vim: tabstop=4 expandtab shiftwidth=4
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/tests/call_func_default_global_multiple.py	Fri Jun 11 00:58:42 2010 +0200
     9.3 @@ -0,0 +1,25 @@
     9.4 +#!/usr/bin/env python
     9.5 +
     9.6 +d = 4
     9.7 +
     9.8 +i = 0
     9.9 +l = []
    9.10 +
    9.11 +while i < 3:
    9.12 +    def f(a, b, c=d):
    9.13 +        return c
    9.14 +    l.append(f)
    9.15 +    i += 1
    9.16 +
    9.17 +f0 = l[0]
    9.18 +f1 = l[1]
    9.19 +f2 = l[2]
    9.20 +
    9.21 +result0_3 = f0(1, 2, 3)
    9.22 +result1_3 = f1(1, 2, 3)
    9.23 +result2_3 = f2(1, 2, 3)
    9.24 +result0_4 = f0(1, 2)
    9.25 +result1_4 = f1(1, 2)
    9.26 +result2_4 = f2(1, 2)
    9.27 +
    9.28 +# vim: tabstop=4 expandtab shiftwidth=4
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/tests/call_func_default_global_non_constant.py	Fri Jun 11 00:58:42 2010 +0200
    10.3 @@ -0,0 +1,12 @@
    10.4 +#!/usr/bin/env python
    10.5 +
    10.6 +d = 2
    10.7 +d = 4 # make non-constant
    10.8 +
    10.9 +def f(a, b, c=d):
   10.10 +    return c
   10.11 +
   10.12 +result_3 = f(1, 2, 3)
   10.13 +result_4 = f(1, 2)
   10.14 +
   10.15 +# vim: tabstop=4 expandtab shiftwidth=4
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/tests/lambda_defaults_local_non_constant.py	Fri Jun 11 00:58:42 2010 +0200
    11.3 @@ -0,0 +1,18 @@
    11.4 +#!/usr/bin/env python
    11.5 +
    11.6 +def make_add(x):
    11.7 +    return lambda a, b=x: a + b
    11.8 +
    11.9 +def g(f, x):
   11.10 +    return f(x)
   11.11 +
   11.12 +add_2 = make_add(2)
   11.13 +add_3 = make_add(3)
   11.14 +
   11.15 +result_3 = add_2(1)
   11.16 +result_4 = g(add_2, 2)
   11.17 +
   11.18 +result_5 = add_3(2)
   11.19 +result_6 = g(add_3, 3)
   11.20 +
   11.21 +# vim: tabstop=4 expandtab shiftwidth=4
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/tests/lambda_defaults_non_constant.py	Fri Jun 11 00:58:42 2010 +0200
    12.3 @@ -0,0 +1,16 @@
    12.4 +#!/usr/bin/env python
    12.5 +
    12.6 +x = 1
    12.7 +x = 2
    12.8 +
    12.9 +def make_add():
   12.10 +    return lambda a, b=x: a + x
   12.11 +
   12.12 +def g(f, x):
   12.13 +    return f(x)
   12.14 +
   12.15 +add_2 = make_add()
   12.16 +result_3 = add_2(1)
   12.17 +result2_3 = g(add_2, 1)
   12.18 +
   12.19 +# vim: tabstop=4 expandtab shiftwidth=4
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/tests/nested_functions_using_defaults.py	Fri Jun 11 00:58:42 2010 +0200
    13.3 @@ -0,0 +1,14 @@
    13.4 +#!/usr/bin/env python
    13.5 +
    13.6 +def a(x):
    13.7 +    def b(p=x):
    13.8 +        return p
    13.9 +    return b
   13.10 +
   13.11 +f2 = a(2)
   13.12 +f3 = a(3)
   13.13 +
   13.14 +result_2 = f2()
   13.15 +result_3 = f3()
   13.16 +
   13.17 +# vim: tabstop=4 expandtab shiftwidth=4