1.1 --- a/README.txt Sun Apr 06 21:26:06 2008 +0200
1.2 +++ b/README.txt Mon Apr 07 02:20:21 2008 +0200
1.3 @@ -284,6 +284,14 @@
1.4
1.5 2. That no keyword argument overwrites an existing positional parameter.
1.6
1.7 +Default Arguments
1.8 +-----------------
1.9 +
1.10 +Some arguments may have default values which are used if no value is provided
1.11 +in an invocation. Such defaults are initialised when the function itself is
1.12 +initialised, and are used to fill in any invocation frames that are known at
1.13 +compile-time.
1.14 +
1.15 Tuples, Frames and Allocation
1.16 -----------------------------
1.17
2.1 --- a/micropython/__init__.py Sun Apr 06 21:26:06 2008 +0200
2.2 +++ b/micropython/__init__.py Mon Apr 07 02:20:21 2008 +0200
2.3 @@ -175,6 +175,11 @@
2.4 image.append(obj)
2.5 pos += 1
2.6
2.7 + # Append any default values to the image.
2.8 +
2.9 + image += obj.default_attrs
2.10 + pos += len(obj.default_attrs)
2.11 +
2.12 # Append the function code to the image.
2.13
2.14 obj.code_location = pos
2.15 @@ -182,6 +187,12 @@
2.16 image += code
2.17 pos += len(code)
2.18
2.19 + # Generate the default initialisation code.
2.20 +
2.21 + code = trans.get_default_code(obj)
2.22 + image += code
2.23 + pos += len(code)
2.24 +
2.25 # Remember the position of the module code.
2.26
2.27 module.code_location = pos
3.1 --- a/micropython/ast.py Sun Apr 06 21:26:06 2008 +0200
3.2 +++ b/micropython/ast.py Mon Apr 07 02:20:21 2008 +0200
3.3 @@ -103,6 +103,17 @@
3.4 self.dispatch(unit.node)
3.5 return self.code
3.6
3.7 + def get_default_code(self, unit):
3.8 +
3.9 + "Return the code for the defaults in the given 'unit'."
3.10 +
3.11 + self.code = []
3.12 + for attr, default in zip(unit.default_attrs, unit.defaults):
3.13 + self.dispatch(default)
3.14 + self.new_op(LoadConst(unit))
3.15 + self.new_op(StoreAttr(attr))
3.16 + return self.code
3.17 +
3.18 def __repr__(self):
3.19 return "Translation(%r)" % self.module
3.20
3.21 @@ -290,11 +301,17 @@
3.22 employed_keywords = set()
3.23 extra_keywords = []
3.24
3.25 - for i, arg in enumerate(args):
3.26 + for frame_pos, arg in enumerate(args):
3.27 +
3.28 + # Handle positional and keyword arguments separately.
3.29 +
3.30 if isinstance(arg, compiler.ast.Keyword):
3.31 +
3.32 + # Note the start of keyword arguments.
3.33 +
3.34 if positional:
3.35 - #self.new_op(ReserveFrame(len(args) - i))
3.36 - start_keywords = i
3.37 + #self.new_op(ReserveFrame(len(args) - frame_pos))
3.38 + start_keywords = frame_pos
3.39 positional = 0
3.40
3.41 # Optimise where the target is known now.
3.42 @@ -336,7 +353,12 @@
3.43 # operation.
3.44
3.45 self.dispatch(arg.expr)
3.46 - self.new_op(StoreFrame(pos))
3.47 +
3.48 + # If the position corresponds to the current frame element,
3.49 + # skip generating the instruction.
3.50 +
3.51 + if frame_pos != pos:
3.52 + self.new_op(StoreFrame(pos))
3.53
3.54 # Otherwise, generate the code needed to obtain the details of
3.55 # the parameter location.
3.56 @@ -369,28 +391,57 @@
3.57 else:
3.58 self.dispatch(arg)
3.59
3.60 + frame_pos = len(args)
3.61 +
3.62 # If any extra keywords were identified, generate them now.
3.63
3.64 for arg in extra_keywords:
3.65 const = self.module.constant_values[arg.name]
3.66 self.new_op(LoadConst(const))
3.67 self.dispatch(arg.expr)
3.68 + frame_pos += 1
3.69
3.70 # NOTE: Somehow, the above needs to be combined with * and ** arguments.
3.71
3.72 # Either test for a complete set of arguments.
3.73
3.74 if target is not None:
3.75 +
3.76 + # Make sure that enough arguments have been given.
3.77 +
3.78 + ndefaults = len(target.defaults)
3.79 nargs_max = len(target.positional_names)
3.80 - nargs_min = nargs_max - len(target.defaults)
3.81 - if len(args) < nargs_min:
3.82 + nargs_min = nargs_max - ndefaults
3.83 + nargs = len(args)
3.84 +
3.85 + if nargs < nargs_min:
3.86 raise TranslateError(self.module.full_name(), node,
3.87 "Insufficient arguments for %r: need at least %d arguments." % (target.name, nargs_min))
3.88 - elif len(args) > nargs_max and not target.has_star and not target.has_dstar:
3.89 + elif nargs > nargs_max and not target.has_star and not target.has_dstar:
3.90 raise TranslateError(self.module.full_name(), node,
3.91 - "Too many arguments for %r: need at most %d arguments." % (target.name, nargs))
3.92 + "Too many arguments for %r: need at most %d arguments." % (target.name, nargs_max))
3.93 +
3.94 + # Where defaults are involved, put them into the frame.
3.95 + # Here, we use negative index values to visit the right hand end of
3.96 + # the defaults list.
3.97 +
3.98 + for i in range(nargs - nargs_max, 0):
3.99 + self.new_op(LoadConst(target))
3.100 + self.new_op(LoadAttr(target.default_attrs[ndefaults + i]))
3.101 +
3.102 + # If the position corresponds to the current frame element,
3.103 + # skip generating the instruction.
3.104 +
3.105 + pos = nargs_max + i
3.106 +
3.107 + if frame_pos != pos:
3.108 + self.new_op(StoreFrame(pos))
3.109 +
3.110 + frame_pos += 1
3.111
3.112 # Or generate instructions to do this at run-time.
3.113 + # NOTE: CheckFrame has to check the number of arguments and to fill in
3.114 + # NOTE: defaults.
3.115
3.116 else:
3.117 self.new_op(CheckFrame())
4.1 --- a/micropython/inspect.py Sun Apr 06 21:26:06 2008 +0200
4.2 +++ b/micropython/inspect.py Mon Apr 07 02:20:21 2008 +0200
4.3 @@ -576,11 +576,26 @@
4.4 "An inspected function."
4.5
4.6 def __init__(self, name, parent, argnames, defaults, has_star, has_dstar, global_namespace=None, node=None):
4.7 +
4.8 + """
4.9 + Initialise the function with the given 'name', 'parent', list of
4.10 + 'argnames', list of 'defaults', the 'has_star' flag (indicating the
4.11 + presence of a * parameter), the 'has_dstar' flag (indicating the
4.12 + presence of a ** parameter), optional 'global_namespace', and optional
4.13 + AST 'node'.
4.14 + """
4.15 +
4.16 NamespaceDict.__init__(self, global_namespace)
4.17 self.name = name
4.18 self.parent = parent
4.19 self.argnames = argnames
4.20 self.defaults = defaults
4.21 + self.has_star = has_star
4.22 + self.has_dstar = has_dstar
4.23 + self.node = node
4.24 +
4.25 + # Initialise the positional names.
4.26 +
4.27 self.positional_names = self.argnames[:]
4.28 if has_dstar:
4.29 self.dstar_name = self.positional_names[-1]
4.30 @@ -588,9 +603,10 @@
4.31 if has_star:
4.32 self.star_name = self.positional_names[-1]
4.33 del self.positional_names[-1]
4.34 - self.has_star = has_star
4.35 - self.has_dstar = has_dstar
4.36 - self.node = node
4.37 +
4.38 + # Initialise default storage.
4.39 +
4.40 + self.default_attrs = []
4.41
4.42 # Caches.
4.43
4.44 @@ -622,6 +638,11 @@
4.45 self.name, self.parent, self.argnames, self.defaults, self.has_star, self.has_dstar
4.46 )
4.47
4.48 + def store_default(self, value):
4.49 + attr = Attr(None, self, None, value)
4.50 + attr.update(value, 1)
4.51 + self.default_attrs.append(attr)
4.52 +
4.53 def make_global(self, name):
4.54 if name not in self.argnames and not self.has_key(name):
4.55 self.globals.add(name)
4.56 @@ -677,7 +698,14 @@
4.57
4.58 def finalise_attributes(self):
4.59
4.60 - "Make sure all attributes are fully defined."
4.61 + """
4.62 + Make sure all attributes (locals) are fully defined. Note that locals
4.63 + are not attributes in the sense of class, module or instance attributes.
4.64 + Defaults are also finalised by this method.
4.65 + """
4.66 +
4.67 + for i, default in enumerate(self.default_attrs):
4.68 + default.position = i
4.69
4.70 i = None
4.71 for i, name in enumerate(self.argnames):
4.72 @@ -688,6 +716,8 @@
4.73 for i, attr in enumerate(self.locals().values()):
4.74 attr.position = i + j
4.75
4.76 + # NOTE: May also have temporary variables.
4.77 +
4.78 def function_from_method(self):
4.79
4.80 "Make a function from a method."
4.81 @@ -1055,6 +1085,17 @@
4.82
4.83 node.unit = function
4.84
4.85 + # Process the defaults.
4.86 +
4.87 + for n in node.defaults:
4.88 + self.expr = self.dispatch(n)
4.89 + if isinstance(self.expr, Attr):
4.90 + function.store_default(self.expr.value)
4.91 + else:
4.92 + function.store_default(self.expr)
4.93 +
4.94 + # Enter the function.
4.95 +
4.96 self.namespaces.append(function)
4.97
4.98 # Current namespace is the function.
5.1 --- a/tests/call_func_default.py Sun Apr 06 21:26:06 2008 +0200
5.2 +++ b/tests/call_func_default.py Mon Apr 07 02:20:21 2008 +0200
5.3 @@ -1,5 +1,7 @@
5.4 #!/usr/bin/env python
5.5
5.6 +x = 123
5.7 +
5.8 def f(a, b, c=4):
5.9 pass
5.10
5.11 @@ -18,4 +20,10 @@
5.12 g(1, c=3, b=2)
5.13 g(1, 3)
5.14
5.15 +def h(a, b, c=f(1, 2, 3)):
5.16 + pass
5.17 +
5.18 +h(1, 2, 3)
5.19 +h(1, 2)
5.20 +
5.21 # vim: tabstop=4 expandtab shiftwidth=4