1.1 --- a/README.txt Tue Dec 11 00:55:23 2007 +0100
1.2 +++ b/README.txt Sun Jan 13 02:14:46 2008 +0100
1.3 @@ -97,3 +97,73 @@
1.4 --------------------
1.5
1.6 Attribute access needs to go through the attribute lookup table.
1.7 +
1.8 +Instruction Evaluation Model
1.9 +============================
1.10 +
1.11 +Programs use a value stack where evaluated instructions may save their
1.12 +results. A value stack pointer indicates the top of this stack. In addition, a
1.13 +separate stack is used to record the invocation frames. All stack pointers
1.14 +refer to the next address to be used by the stack, not the address of the
1.15 +uppermost element.
1.16 +
1.17 + Frame Stack Value Stack
1.18 + ----------- ----------- Address of Callable
1.19 + -------------------
1.20 + previous ...
1.21 + current ------> callable -----> identifier
1.22 + arg1 reference to code
1.23 + arg2
1.24 + arg3
1.25 + local4
1.26 + local5
1.27 + ...
1.28 +
1.29 +Loading local names is a matter of performing frame-relative accesses to the
1.30 +value stack.
1.31 +
1.32 +Invocations and Argument Evaluation
1.33 +-----------------------------------
1.34 +
1.35 +When preparing for an invocation, the caller first sets the invocation frame
1.36 +pointer. Then, positional arguments are added to the stack such that the first
1.37 +argument positions are filled. A number of stack locations for the remaining
1.38 +arguments specified in the program are then reserved. The names of keyword
1.39 +arguments are used (in the form of table index values) to consult the
1.40 +parameter table and to find the location in which such arguments are to be
1.41 +stored.
1.42 +
1.43 + fn(a, b, d=1, e=2, c=3) -> fn(a, b, c, d, e)
1.44 +
1.45 + Value Stack
1.46 + -----------
1.47 +
1.48 + ... ... ... ...
1.49 + fn fn fn fn
1.50 + a a a a
1.51 + b b b b
1.52 + ___ ___ ___ --> 3
1.53 + ___ --> 1 1 | 1
1.54 + ___ | ___ --> 2 | 2
1.55 + 1 ----------- 2 ----------- 3 -----------
1.56 +
1.57 +Conceptually, the frame can be considered as a collection of attributes, as
1.58 +seen in other kinds of structures:
1.59 +
1.60 +Frame for invocation of fn:
1.61 +
1.62 + 0 1 2 3 4 5
1.63 + code a b c d e
1.64 + reference
1.65 +
1.66 +However, where arguments are specified positionally, such "attributes" are not
1.67 +set using a comparable approach to that employed with other structures.
1.68 +Keyword arguments are set using an attribute-like mechanism, though, where the
1.69 +position of each argument discovered using the parameter table.
1.70 +
1.71 +Tuples, Frames and Allocation
1.72 +-----------------------------
1.73 +
1.74 +Using the approach where arguments are treated like attributes in some kind of
1.75 +structure, we could choose to allocate frames in places other than a stack.
1.76 +This would produce something somewhat similar to a plain tuple object.
2.1 --- a/micropython/__init__.py Tue Dec 11 00:55:23 2007 +0100
2.2 +++ b/micropython/__init__.py Sun Jan 13 02:14:46 2008 +0100
2.3 @@ -73,10 +73,13 @@
2.4
2.5 return self.modules.values()
2.6
2.7 - def get_image(self):
2.8 + def get_image(self, objtable=None, paramtable=None):
2.9
2.10 "Return a dictionary mapping modules to structures."
2.11
2.12 + objtable = objtable or self.get_object_table()
2.13 + paramtable = paramtable or self.get_parameter_table()
2.14 +
2.15 image = []
2.16
2.17 for module_name, module in self.modules.items():
2.18 @@ -85,7 +88,14 @@
2.19 # Position the module in the image and make a translation.
2.20
2.21 module.location = pos
2.22 - trans = micropython.ast.Translation(module)
2.23 + trans = micropython.ast.Translation(module, objtable, paramtable)
2.24 +
2.25 + # Append constants to the image.
2.26 +
2.27 + for const in module.constants:
2.28 + const.location = pos
2.29 + image.append(const)
2.30 + pos += 1
2.31
2.32 # Append module attributes to the image.
2.33
3.1 --- a/micropython/ast.py Tue Dec 11 00:55:23 2007 +0100
3.2 +++ b/micropython/ast.py Sun Jan 13 02:14:46 2008 +0100
3.3 @@ -51,14 +51,20 @@
3.4
3.5 "A translated module."
3.6
3.7 - def __init__(self, module):
3.8 + def __init__(self, module, objtable, paramtable):
3.9
3.10 - "Initialise the translation with an inspected 'module'."
3.11 + """
3.12 + Initialise the translation with an inspected 'module' and an attribute
3.13 + table 'objtable' and parameter table 'paramtable'.
3.14 + """
3.15
3.16 ASTVisitor.__init__(self)
3.17 self.visitor = self
3.18 self.module = module
3.19 + self.objtable = objtable
3.20 + self.paramtable = paramtable
3.21 self.unit = None
3.22 + self.constants = {}
3.23
3.24 # Wiring within the code.
3.25
3.26 @@ -114,7 +120,9 @@
3.27 label.location = len(self.code) + self.unit.code_location
3.28
3.29 def new_op(self, op):
3.30 + print self.module.name, len(self.code) + self.unit.code_location,
3.31 self.code.append(op)
3.32 + print op
3.33
3.34 # Visitor methods.
3.35
3.36 @@ -151,16 +159,16 @@
3.37 builtins = micropython.inspect.builtins.module_attributes()
3.38 self.new_op(AttrInstruction(builtins[name]))
3.39
3.40 - def visitAdd(self, node): pass
3.41 + def visitAdd(self, node):
3.42
3.43 - """
3.44 - _t1 = node.left
3.45 - _t2 = node.right
3.46 - try:
3.47 - _t1.__add__(_t2)
3.48 - except AttributeError:
3.49 - _t2.__radd__(_t1)
3.50 - """
3.51 + """
3.52 + _t1 = node.left
3.53 + _t2 = node.right
3.54 + try:
3.55 + _t1.__add__(_t2)
3.56 + except AttributeError:
3.57 + _t2.__radd__(_t1)
3.58 + """
3.59
3.60 def visitAnd(self, node): pass
3.61
3.62 @@ -192,11 +200,61 @@
3.63
3.64 def visitBreak(self, node): pass
3.65
3.66 - def visitCallFunc(self, node): pass
3.67 + def visitCallFunc(self, node):
3.68 +
3.69 + """
3.70 + Evaluate positional arguments, evaluate and store keyword arguments in
3.71 + the correct location, then invoke the function.
3.72 + """
3.73 +
3.74 + # Record the location of the invocation.
3.75 +
3.76 + self.new_op(MakeFrame()) # records the start of the frame
3.77 +
3.78 + # Evaluate the target.
3.79 +
3.80 + self.dispatch(node.node)
3.81 +
3.82 + # Evaluate the arguments.
3.83 +
3.84 + for i, arg in enumerate(node.args):
3.85 + if isinstance(arg, compiler.ast.Keyword):
3.86 + self.dispatch(arg.expr)
3.87 +
3.88 + # Combine the target details with the name to get the location.
3.89 + # See the access method on the Table class.
3.90 +
3.91 + paramindex = self.paramtable.get_index(arg.name)
3.92 + self.new_op(StoreFrame(paramindex))
3.93 +
3.94 + # use (callable+0)+paramindex+table
3.95 + # checks embedded offset against (callable+0)
3.96 + # moves the top of stack to frame+position
3.97 +
3.98 + else:
3.99 + self.dispatch(arg)
3.100 +
3.101 + self.new_op(LoadCallable()) # uses the start of the frame to get the callable
3.102 + self.new_op(Jump())
3.103 +
3.104 + # NOTE: Exception handling required.
3.105 +
3.106 + self.new_op(DropFrame())
3.107
3.108 def visitClass(self, node): pass
3.109
3.110 - def visitCompare(self, node): pass
3.111 + def visitCompare(self, node):
3.112 +
3.113 + """
3.114 + self.dispatch(node.expr)
3.115 + for op_name, next_node in compare.ops:
3.116 + methods = self.comparison_methods[op_name]
3.117 + if methods is not None:
3.118 + # Generate method call using evaluated argument and next node.
3.119 + else:
3.120 + # Deal with the special operators.
3.121 + # Provide short-circuiting.
3.122 + """
3.123
3.124 def visitConst(self, node): pass
3.125
3.126 @@ -228,9 +286,11 @@
3.127 # Only store the name when visiting this node from outside.
3.128
3.129 if self.unit is self.module:
3.130 + self.new_op(LoadConst(node.function))
3.131 self._visitName(node, (StoreName, StoreAttr))
3.132 else:
3.133 self.dispatch(node.code)
3.134 + self.new_op(Return())
3.135
3.136 def visitGenExpr(self, node): pass
3.137
3.138 @@ -305,7 +365,10 @@
3.139
3.140 def visitRaise(self, node): pass
3.141
3.142 - def visitReturn(self, node): pass
3.143 + def visitReturn(self, node):
3.144 + if node.value is not None:
3.145 + self.dispatch(node.value)
3.146 + self.new_op(Return())
3.147
3.148 def visitRightShift(self, node): pass
3.149
3.150 @@ -335,4 +398,19 @@
3.151
3.152 def visitYield(self, node): pass
3.153
3.154 + # Useful data.
3.155 +
3.156 + comparison_methods = {
3.157 + "==" : ("__eq__", "__ne__"),
3.158 + "!=" : ("__ne__", "__eq__"),
3.159 + "<" : ("__lt__", "__gt__"),
3.160 + "<=" : ("__le__", "__ge__"),
3.161 + ">=" : ("__ge__", "__le__"),
3.162 + ">" : ("__gt__", "__lt__"),
3.163 + "is" : None,
3.164 + "is not" : None,
3.165 + "in" : None,
3.166 + "not in" : None
3.167 + }
3.168 +
3.169 # vim: tabstop=4 expandtab shiftwidth=4
4.1 --- a/micropython/inspect.py Tue Dec 11 00:55:23 2007 +0100
4.2 +++ b/micropython/inspect.py Sun Jan 13 02:14:46 2008 +0100
4.3 @@ -123,6 +123,26 @@
4.4 def __repr__(self):
4.5 return "Attr(%d, %r, %r)" % (self.position, self.parent, self.value)
4.6
4.7 +class Const:
4.8 +
4.9 + "A constant object."
4.10 +
4.11 + def __init__(self, value):
4.12 + self.value = value
4.13 +
4.14 + # Image generation details.
4.15 +
4.16 + self.location = None
4.17 +
4.18 + def __repr__(self):
4.19 + return "Const(%r, location=%d)" % (self.value, self.location)
4.20 +
4.21 + def __eq__(self, other):
4.22 + return self.value == other.value
4.23 +
4.24 + def __hash__(self):
4.25 + return hash(self.value)
4.26 +
4.27 class Class(NamespaceDict, Naming):
4.28
4.29 "An inspected class."
4.30 @@ -354,8 +374,6 @@
4.31 def __repr__(self):
4.32 return "UnresolvedName(%r, %r)" % (self.name, self.parent_name)
4.33
4.34 -# Program visitors.
4.35 -
4.36 class Module(NamespaceDict):
4.37
4.38 "An inspected module's core details."
4.39 @@ -410,6 +428,8 @@
4.40
4.41 return self.modattr
4.42
4.43 +# Program visitors.
4.44 +
4.45 class InspectedModule(ASTVisitor, Module):
4.46
4.47 """
4.48 @@ -434,6 +454,7 @@
4.49 self.in_init = 0
4.50 self.namespaces = []
4.51 self.module = None
4.52 + self.constants = []
4.53
4.54 def parse(self, filename):
4.55
4.56 @@ -507,6 +528,8 @@
4.57 return ASTVisitor.dispatch(self, node, *args)
4.58
4.59 def NOP(self, node):
4.60 + for n in node.getChildNodes():
4.61 + self.dispatch(n)
4.62 return None
4.63
4.64 visitAdd = NOP
4.65 @@ -563,6 +586,10 @@
4.66 raise InspectError, "Base class %r for class %r in %r is not found: it may be hidden in some way." % (base, self, cls)
4.67 cls.add_base(base_ref)
4.68
4.69 + # Make a back reference from the node for code generation.
4.70 +
4.71 + node.cls = cls
4.72 +
4.73 # Make an entry for the class.
4.74
4.75 self.store(node.name, cls)
4.76 @@ -575,7 +602,10 @@
4.77
4.78 visitCompare = NOP
4.79
4.80 - visitConst = NOP
4.81 + def visitConst(self, node):
4.82 + const = Const(node.value)
4.83 + if not const in self.constants:
4.84 + self.constants.append(const)
4.85
4.86 visitContinue = NOP
4.87
4.88 @@ -633,6 +663,10 @@
4.89 node
4.90 )
4.91
4.92 + # Make a back reference from the node for code generation.
4.93 +
4.94 + node.function = function
4.95 +
4.96 self.namespaces.append(function)
4.97
4.98 # Current namespace is the function.
5.1 --- a/micropython/rsvp.py Tue Dec 11 00:55:23 2007 +0100
5.2 +++ b/micropython/rsvp.py Sun Jan 13 02:14:46 2008 +0100
5.3 @@ -23,16 +23,38 @@
5.4
5.5 "A generic instruction."
5.6
5.7 - def __init__(self, attr):
5.8 + def __init__(self, attr=None):
5.9 self.attr = attr
5.10
5.11 def __repr__(self):
5.12 return "%s(%r)" % (self.__class__.__name__, self.attr)
5.13
5.14 +# Instructions operating on the value stack.
5.15 +
5.16 +class LoadConst(Instruction): pass
5.17 +
5.18 +# Access within an invocation frame.
5.19 +
5.20 class LoadName(Instruction): pass
5.21 -class LoadAttr(Instruction): pass
5.22 class StoreName(Instruction): pass
5.23 +
5.24 +# Access to address-relative data.
5.25 +
5.26 +class MakeObject(Instruction): pass
5.27 +# ... DropObject not defined: assume garbage collection.
5.28 +class LoadAttr(Instruction): pass
5.29 class StoreAttr(Instruction): pass
5.30 +
5.31 +# Access to invocation frames in preparation.
5.32 +
5.33 +class MakeFrame(Instruction): pass
5.34 +class DropFrame(Instruction): pass
5.35 +class StoreFrame(Instruction): pass
5.36 +
5.37 +# Invocation-related instructions.
5.38 +
5.39 class Jump(Instruction): pass
5.40 +class LoadCallable(Instruction): pass
5.41 +class Return(Instruction): pass
5.42
5.43 # vim: tabstop=4 expandtab shiftwidth=4
6.1 --- a/micropython/table.py Tue Dec 11 00:55:23 2007 +0100
6.2 +++ b/micropython/table.py Sun Jan 13 02:14:46 2008 +0100
6.3 @@ -159,6 +159,12 @@
6.4 self.names = self.names or list(self.attributes)
6.5 return self.names
6.6
6.7 + def get_index(self, name):
6.8 +
6.9 + "Return the index of the given 'name'."
6.10 +
6.11 + return self.attribute_names().index(name)
6.12 +
6.13 def as_matrix(self):
6.14
6.15 """
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/tests/call_func.py Sun Jan 13 02:14:46 2008 +0100
7.3 @@ -0,0 +1,10 @@
7.4 +#!/usr/bin/env python
7.5 +
7.6 +def f(a, b, c):
7.7 + pass
7.8 +
7.9 +f(1, 2, 3)
7.10 +f(1, b=2, c=3)
7.11 +f(c=3, b=2, a=1)
7.12 +
7.13 +# vim: tabstop=4 expandtab shiftwidth=4