1.1 --- a/docs/concepts.txt Sat May 16 01:34:03 2009 +0200
1.2 +++ b/docs/concepts.txt Sun May 17 00:58:27 2009 +0200
1.3 @@ -189,16 +189,14 @@
1.4 certain common features and operations are supported in the same way for all
1.5 of these things. To permit this, a common data structure format is used.
1.6
1.7 - Header............................................................................ Attributes.....
1.8 + Header.................................................... Attributes.................
1.9
1.10 - Identifier Identifier Address Details Identifier Size Object Object ...
1.11 + Identifier Identifier Address Identifier Size Object Object ...
1.12
1.13 - 0 1 2 3 4 5 6 7 8
1.14 - classcode attrcode/ invocation invocation funccode size __class__ attribute ...
1.15 - instance reference #args, reference reference
1.16 - status defaults,
1.17 - * parameter
1.18 - details
1.19 + 0 1 2 3 4 5 6 7
1.20 + classcode attrcode/ invocation funccode size __class__ attribute ...
1.21 + instance reference reference reference
1.22 + status
1.23
1.24 Classcode
1.25 ---------
1.26 @@ -221,7 +219,8 @@
1.27 removed and the attrcode is not specified for classes: the presence of an
1.28 attrcode indicates that a given object is an instance.
1.29
1.30 -See below for details of attrcodes.
1.31 +See the "Testing Instance Compatibility with Classes (Attrcode)" section below
1.32 +for details of attrcodes.
1.33
1.34 Invocation Reference
1.35 --------------------
1.36 @@ -231,15 +230,20 @@
1.37 This is the address of the code to be executed when an invocation is performed
1.38 on the object.
1.39
1.40 -Invocation Arguments
1.41 ---------------------
1.42 +Funccode
1.43 +--------
1.44
1.45 -Used when an object is called.
1.46 +Used to look up argument positions by name.
1.47
1.48 -The argument details consist of the number of positional arguments involved in
1.49 -an invocation, the number of defaults available to compensate for missing
1.50 -arguments, and whether a star (*) parameter is available to accept superfluous
1.51 -arguments.
1.52 +The strategy with keyword arguments in micropython is to attempt to position
1.53 +such arguments in the invocation frame as it is being constructed.
1.54 +
1.55 +See the "Parameters and Lookups" section for more information.
1.56 +
1.57 +Size
1.58 +----
1.59 +
1.60 +Used to indicate the number of attributes associated with an object.
1.61
1.62 Attributes
1.63 ----------
1.64 @@ -254,37 +258,31 @@
1.65
1.66 Class C:
1.67
1.68 - 0 1 2 3 4 5 6 7 8
1.69 - classcode (unused) __new__ __new__ funccode size class type attribute ...
1.70 - for C reference #args, for reference reference
1.71 - defaults, instantiator
1.72 - * parameter
1.73 - details
1.74 + 0 1 2 3 4 5 6 7
1.75 + classcode (unused) __new__ funccode size class type attribute ...
1.76 + for C reference for reference reference
1.77 + instantiator
1.78
1.79 Instance of C:
1.80
1.81 - 0 1 2 3 4 5 6 7 8
1.82 - classcode attrcode C.__call__ C.__call__ funccode size class C attribute ...
1.83 - for C for C reference #args, for reference reference
1.84 - (if exists) defaults, C.__call__
1.85 - * parameter
1.86 - details
1.87 + 0 1 2 3 4 5 6 7
1.88 + classcode attrcode C.__call__ funccode size class C attribute ...
1.89 + for C for C reference for reference reference
1.90 + (if exists) C.__call__
1.91
1.92 Function f:
1.93
1.94 - 0 1 2 3 4 5 6 7 8
1.95 - classcode attrcode code code funccode size class attribute ...
1.96 - for for reference #args, function (default)
1.97 - function function defaults, reference reference
1.98 - * parameter
1.99 - details
1.100 + 0 1 2 3 4 5 6 7
1.101 + classcode attrcode code funccode size class attribute ...
1.102 + for for reference function (default)
1.103 + function function reference reference
1.104
1.105 Module m:
1.106
1.107 - 0 1 2 3 4 5 6 7 8
1.108 - classcode attrcode (unused) (unused) module type attribute ...
1.109 - for m for m reference (global)
1.110 - reference
1.111 + 0 1 2 3 4 5 6 7
1.112 + classcode attrcode (unused) module type attribute ...
1.113 + for m for m reference (global)
1.114 + reference
1.115
1.116 The __class__ Attribute
1.117 -----------------------
2.1 --- a/micropython/__init__.py Sat May 16 01:34:03 2009 +0200
2.2 +++ b/micropython/__init__.py Sun May 17 00:58:27 2009 +0200
2.3 @@ -210,6 +210,8 @@
2.4 # Position the objects.
2.5
2.6 pos = 0
2.7 + current_function = None
2.8 +
2.9 for item in self.code:
2.10
2.11 # Blocks are positioned leaving space for their expansion.
2.12 @@ -218,6 +220,14 @@
2.13 item.location = pos
2.14 pos += len(item.code)
2.15
2.16 + # Set code body information on functions, assuming that the
2.17 + # first block is for argument checks.
2.18 +
2.19 + if current_function is not None:
2.20 + current_function.code_body_location = pos
2.21 +
2.22 + current_function = None
2.23 +
2.24 # Other multi-location objects.
2.25
2.26 elif isinstance(item, (
2.27 @@ -253,8 +263,14 @@
2.28 else:
2.29 item.code_location = pos + len(item.defaults)
2.30
2.31 + current_function = item
2.32 +
2.33 elif isinstance(item, micropython.data.Const):
2.34 pos += len(item.raw_data())
2.35 + current_function = None
2.36 +
2.37 + else:
2.38 + current_function = None
2.39
2.40 else:
2.41 pos += 1
3.1 --- a/micropython/ast.py Sat May 16 01:34:03 2009 +0200
3.2 +++ b/micropython/ast.py Sun May 17 00:58:27 2009 +0200
3.3 @@ -593,15 +593,32 @@
3.4 # Visiting of the code occurs when get_code is invoked on this node.
3.5
3.6 else:
3.7 + body_block = self.new_block()
3.8 +
3.9 + # Check frames using the function's details.
3.10 +
3.11 + fn = node.unit
3.12 + nparams = len(fn.positional_names)
3.13 + ndefaults = len(fn.defaults)
3.14 +
3.15 + self.new_op(CheckFrame((nparams, ndefaults, fn.has_star)))
3.16 + self.new_op(FillDefaults((nparams, ndefaults)))
3.17 +
3.18 + # Produce the body.
3.19 +
3.20 + self.set_block(body_block)
3.21 +
3.22 extend = ExtendFrame()
3.23 self.new_op(extend)
3.24
3.25 self.dispatch(node.code)
3.26 +
3.27 if not isinstance(self.last_op(), Return):
3.28 self.dispatch(compiler.ast.Name("None"))
3.29 self.new_op(StoreResult())
3.30 + self.new_op(Return())
3.31
3.32 - self.new_op(Return())
3.33 + # Make sure that enough frame space is reserved from the start.
3.34
3.35 self.set_frame_usage(node, extend)
3.36
3.37 @@ -645,10 +662,33 @@
3.38 # Visiting of the code occurs when get_code is invoked on this node.
3.39
3.40 else:
3.41 + body_block = self.new_block()
3.42 +
3.43 + # Check frames using the function's details.
3.44 +
3.45 + fn = node.unit
3.46 + nparams = len(fn.positional_names)
3.47 + ndefaults = len(fn.defaults)
3.48 +
3.49 + self.new_op(CheckFrame((nparams, ndefaults, fn.has_star)))
3.50 + self.new_op(FillDefaults((nparams, ndefaults)))
3.51 +
3.52 + # Produce the body.
3.53 +
3.54 + self.set_block(body_block)
3.55 +
3.56 + extend = ExtendFrame()
3.57 + self.new_op(extend)
3.58 +
3.59 self.dispatch(node.code)
3.60 +
3.61 self.new_op(StoreResult())
3.62 self.new_op(Return())
3.63
3.64 + # Make sure that enough frame space is reserved from the start.
3.65 +
3.66 + self.set_frame_usage(node, extend)
3.67 +
3.68 def visitModule(self, node):
3.69 extend = ExtendFrame()
3.70 self.new_op(extend)
4.1 --- a/micropython/data.py Sat May 16 01:34:03 2009 +0200
4.2 +++ b/micropython/data.py Sun May 17 00:58:27 2009 +0200
4.3 @@ -605,6 +605,9 @@
4.4 )
4.5 ]
4.6
4.7 + def get_direct_invocation_location(self):
4.8 + return self.get_instantiator().blocks[0].location
4.9 +
4.10 # Namespace-related methods.
4.11
4.12 def get_updated_context_values(self, context_values):
4.13 @@ -935,6 +938,7 @@
4.14
4.15 self.location = None
4.16 self.code_location = None
4.17 + self.code_body_location = None
4.18
4.19 # Program-related details.
4.20
4.21 @@ -955,8 +959,9 @@
4.22
4.23 def __repr__(self):
4.24 if self.location is not None:
4.25 - return "Function(%r, %s, %r, location=%r, code_location=%r)" % (
4.26 - self.name, shortrepr(self.parent), self.argnames, self.location, self.code_location
4.27 + return "Function(%r, %s, %r, location=%r, code_location=%r, code_body_location=%r)" % (
4.28 + self.name, shortrepr(self.parent), self.argnames, self.location, self.code_location,
4.29 + self.code_body_location
4.30 )
4.31 else:
4.32 return "Function(%r, %s, %r)" % (
4.33 @@ -986,6 +991,9 @@
4.34 )
4.35 ]
4.36
4.37 + def get_direct_invocation_location(self):
4.38 + return self.code_body_location
4.39 +
4.40 # Namespace-related methods.
4.41
4.42 def store_default(self, value):
5.1 --- a/micropython/rsvp.py Sat May 16 01:34:03 2009 +0200
5.2 +++ b/micropython/rsvp.py Sun May 17 00:58:27 2009 +0200
5.3 @@ -128,6 +128,18 @@
5.4
5.5 Address = AddressInstruction
5.6
5.7 +class TargetInstruction(Instruction):
5.8 +
5.9 + "An instruction loading the address of an invocation target."
5.10 +
5.11 + def __repr__(self):
5.12 + return "%s(%r) # %r" % (self.__class__.__name__, self.get_operand(), name(self.attr))
5.13 +
5.14 + def get_operand(self):
5.15 + return self.attr.get_direct_invocation_location()
5.16 +
5.17 +Target = TargetInstruction
5.18 +
5.19 class ImmediateInstruction(Instruction):
5.20
5.21 "An instruction employing a constant."
5.22 @@ -187,12 +199,17 @@
5.23 class StoreFrame(Immediate): "Store the current value as an argument for the parameter with the given position."
5.24 class StoreFrameIndex(Immediate): "Store the source value as an argument of the current value for the parameter with the given index."
5.25 class LoadContext(Instruction): "Load the context of an invocation."
5.26 +class CheckSelf(Instruction): "Check the first argument of an invocation against the target."
5.27 +
5.28 +# Access to invocation frames upon dispatch.
5.29 +
5.30 class CheckFrame(Immediate): "Check the invocation frame and context for the target."
5.31 -class CheckSelf(Instruction): "Check the first argument of an invocation against the target."
5.32 +class FillDefaults(Immediate): "Fill frame positions with defaults, if appropriate."
5.33
5.34 # Invocation-related instructions, using a special result "register".
5.35
5.36 class JumpWithFrame(Instruction): "Jump, adopting the invocation frame, to the current callable."
5.37 +class JumpWithFrameDirect(Target): "Jump to the specified address, adopting the invocation frame."
5.38 class ExtendFrame(Immediate): "Extend the current frame for temporary storage use."
5.39 class AdjustFrame(Immediate): "Adjust the current frame for corrected invocations."
5.40 class Return(Instruction): "Return from a subprogram."
6.1 --- a/micropython/trans.py Sat May 16 01:34:03 2009 +0200
6.2 +++ b/micropython/trans.py Sun May 17 00:58:27 2009 +0200
6.3 @@ -740,19 +740,10 @@
6.4
6.5 self._endCallFuncArgs(frame_size)
6.6
6.7 - # Or generate instructions to do this at run-time.
6.8 + # Or just set the frame size and have the function check the arguments.
6.9
6.10 else:
6.11 max_pos = max(max(employed_positions or [-1]), max_keyword_pos, frame_pos - 1)
6.12 -
6.13 - # Only check non-empty frames (using the callable's details).
6.14 -
6.15 - if employed_positions or max_pos >= 0:
6.16 - self.new_op(temp)
6.17 - self.new_op(CheckFrame(max_pos + 1))
6.18 -
6.19 - # Set the frame size.
6.20 -
6.21 self._endCallFuncArgs(max_pos + 1)
6.22
6.23 def _generateCallFuncDefaultArgs(self, target, temp, nargs_min, nargs_max, employed_positions):
6.24 @@ -788,13 +779,12 @@
6.25 # For classes, the target itself is used, since the instantiator will be
6.26 # obtained via the class.
6.27
6.28 - if isinstance(target, Class):
6.29 - self.new_op(LoadConst(target))
6.30 + if isinstance(target, (Class, Function)):
6.31 + self.new_op(JumpWithFrameDirect(target))
6.32 else:
6.33 self.new_op(instruction)
6.34 -
6.35 - self.new_op(LoadCallable())
6.36 - self.new_op(JumpWithFrame())
6.37 + self.new_op(LoadCallable())
6.38 + self.new_op(JumpWithFrame())
6.39
6.40 def _endCallFuncArgs(self, nargs):
6.41
7.1 --- a/rsvp.py Sat May 16 01:34:03 2009 +0200
7.2 +++ b/rsvp.py Sun May 17 00:58:27 2009 +0200
7.3 @@ -486,40 +486,51 @@
7.4 self.value = None, context # context of context is not interesting
7.5
7.6 def CheckFrame(self):
7.7 - operand = self.operand
7.8 - frame = self.invocation_sp_stack[-1]
7.9 - context, ref = self.value
7.10 - data = self.load(ref)
7.11 + (nargs, ndefaults, has_star) = self.operand
7.12 +
7.13 + # The frame is actually installed as the locals.
7.14 + # Retrieve the context from the first local.
7.15 +
7.16 + frame = self.local_sp_stack[-1]
7.17 + context, ref = self.frame_stack[frame] # + 0
7.18 + nlocals = len(self.frame_stack[frame:])
7.19
7.20 # Support sliding of the frame to exclude any inappropriate context.
7.21
7.22 if context is None:
7.23 - self.invocation_sp_stack[-1] += 1
7.24 - operand -= 1
7.25 + self.local_sp_stack[-1] += 1
7.26 + nlocals -= 1
7.27 else:
7.28 context_data = self.load(context)
7.29 if context_data.attrcode is None: # absent attrcode == class
7.30 - self.invocation_sp_stack[-1] += 1
7.31 - operand -= 1
7.32 + self.local_sp_stack[-1] += 1
7.33 + nlocals -= 1
7.34
7.35 # Test the frame size.
7.36 + # NOTE: Raise a proper exception here.
7.37
7.38 - nargs, ndefaults = data.codedetails
7.39 - if not ((nargs - ndefaults) <= operand <= nargs):
7.40 - raise Exception, "CheckFrame %r (%r <= %r <= %r)" % (self.operand, nargs - ndefaults, operand, nargs)
7.41 + if not ((nargs - ndefaults) <= nlocals and (nlocals <= nargs or has_star)):
7.42 + raise Exception, "CheckFrame %r (%r <= %r <= %r)" % (self.operand, nargs - ndefaults, nlocals, nargs)
7.43 +
7.44 + def FillDefaults(self):
7.45 + (nargs, ndefaults) = self.operand
7.46 +
7.47 + # The frame is actually installed as the locals.
7.48 +
7.49 + frame = self.local_sp_stack[-1]
7.50 + nlocals = len(self.frame_stack[frame:])
7.51
7.52 # Support population of defaults.
7.53 # This involves copying the "attributes" of a function into the frame.
7.54
7.55 - default = operand - (nargs - ndefaults)
7.56 - self.frame_stack.extend([None] * (nargs - operand))
7.57 - pos = self.operand
7.58 + default = nlocals - (nargs - ndefaults)
7.59 + self.frame_stack.extend([None] * (nargs - nlocals))
7.60 + pos = nlocals
7.61
7.62 - while operand < nargs:
7.63 + while pos < nargs:
7.64 self.frame_stack[frame + pos] = self.load(ref + default + 1) # skip header
7.65 default += 1
7.66 pos += 1
7.67 - operand += 1
7.68
7.69 def CheckSelf(self):
7.70 context, ref = self.value
7.71 @@ -534,6 +545,11 @@
7.72 self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame
7.73 return self.jump(codeaddr, self.pc + 1) # return to the instruction after this one
7.74
7.75 + def JumpWithFrameDirect(self):
7.76 + operand = self.operand
7.77 + self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame
7.78 + return self.jump(operand, self.pc + 1) # return to the instruction after this one
7.79 +
7.80 def ExtendFrame(self):
7.81 self.frame_stack.extend([None] * self.operand)
7.82
8.1 --- a/tests/call_func.py Sat May 16 01:34:03 2009 +0200
8.2 +++ b/tests/call_func.py Sun May 17 00:58:27 2009 +0200
8.3 @@ -1,10 +1,10 @@
8.4 #!/usr/bin/env python
8.5
8.6 def f(a, b, c):
8.7 - pass
8.8 + return c
8.9
8.10 -f(1, 2, 3)
8.11 -f(1, b=2, c=3)
8.12 -f(c=3, b=2, a=1)
8.13 +x = f(1, 2, 3)
8.14 +y = f(1, b=2, c=3)
8.15 +z = f(c=3, b=2, a=1)
8.16
8.17 # vim: tabstop=4 expandtab shiftwidth=4
9.1 --- a/tests/call_func_uncertain.py Sat May 16 01:34:03 2009 +0200
9.2 +++ b/tests/call_func_uncertain.py Sun May 17 00:58:27 2009 +0200
9.3 @@ -1,14 +1,14 @@
9.4 #!/usr/bin/env python
9.5
9.6 def f(a, b, c):
9.7 - pass
9.8 + return c
9.9
9.10 g = f
9.11 -g(1, c=3, b=2)
9.12 +x = g(1, c=3, b=2)
9.13
9.14 def g(a, c, b):
9.15 - pass
9.16 + return c
9.17
9.18 -g(1, c=3, b=2)
9.19 +y = g(1, c=3, b=2)
9.20
9.21 # vim: tabstop=4 expandtab shiftwidth=4
10.1 --- a/tests/failure/argument_surplus.py Sat May 16 01:34:03 2009 +0200
10.2 +++ b/tests/failure/argument_surplus.py Sun May 17 00:58:27 2009 +0200
10.3 @@ -3,14 +3,6 @@
10.4 def f(a, b, c):
10.5 pass
10.6
10.7 -g = f
10.8 -g(1, 2, 3, 4) # uncertain target - not detected
10.9 -
10.10 -def g(a, c, b):
10.11 - pass
10.12 -
10.13 -g(1, a=3, b=2)
10.14 -
10.15 f(1, 2, 3)
10.16 f(1, 2, 3, 4)
10.17
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/tests/failure/argument_surplus_uncertain.py Sun May 17 00:58:27 2009 +0200
11.3 @@ -0,0 +1,14 @@
11.4 +#!/usr/bin/env python
11.5 +
11.6 +def f():
11.7 + pass
11.8 +
11.9 +g = f
11.10 +
11.11 +def g(a, c, b):
11.12 + pass
11.13 +
11.14 +g(1, a=3, b=2)
11.15 +g(1, 2, 3, 4) # uncertain target - not detected
11.16 +
11.17 +# vim: tabstop=4 expandtab shiftwidth=4