1.1 --- a/docs/assignment.txt Sun Feb 22 02:04:30 2009 +0100
1.2 +++ b/docs/assignment.txt Sun Feb 22 22:31:21 2009 +0100
1.3 @@ -51,3 +51,18 @@
1.4 instance preserved LoadAttr LoadAttrIndex
1.5
1.6 Access to a namespace may not preserve the stored context
1.7 +
1.8 +Access to class attributes via instances:
1.9 +
1.10 + Access to stored value with... Effect on context
1.11 + ------------------------------ -----------------
1.12 + compatible class as context overridden
1.13 + incompatible class as context preserved
1.14 + null context preserved
1.15 + other context (instance) preserved
1.16 +
1.17 + LoadAttrIndex must therefore check whether the context must be overridden
1.18 +
1.19 + Since the object table encodes sufficient information (an instance must be
1.20 + compatible to access the class attribute, and compatibility information is
1.21 + stored), an explicit compatibility test is not required at run-time
2.1 --- a/docs/structures.txt Sun Feb 22 02:04:30 2009 +0100
2.2 +++ b/docs/structures.txt Sun Feb 22 22:31:21 2009 +0100
2.3 @@ -20,112 +20,28 @@
2.4 Stored Values and Contexts
2.5 --------------------------
2.6
2.7 -In a program image, generated attribute data will employ values, and these
2.8 -values will generally have the following context definitions according to the
2.9 -type of the referenced objects:
2.10 -
2.11 - Referenced Object Type Context
2.12 - ---------------------- -------
2.13 -
2.14 - Function None
2.15 -
2.16 - Method Parent object (class)
2.17 -
2.18 - Class None
2.19 -
2.20 -Value and Context Transformations
2.21 ----------------------------------
2.22 -
2.23 -Values are acquired through name lookups and attribute access, yielding
2.24 -the appropriate object reference together with a context reference as
2.25 -indicated in the following table:
2.26 -
2.27 - Type of Access Context Notes
2.28 - -------------- ------- -----
2.29 -
2.30 - Local name Preserved Functions provide no context
2.31 -
2.32 - Global name Preserved Modules provide no context
2.33 -
2.34 - Class-originating Accessor Class accessor preserves the stored
2.35 - attribute -or- context; instance accessor overrides
2.36 - Preserved the stored context if it is null or
2.37 - belongs to the instance's class
2.38 - hierarchy
2.39 -
2.40 - Instance-originating Preserved Methods retain their original context
2.41 - attribute
2.42 -
2.43 -There may be some scope for simplifying the above, to the detriment of Python
2.44 -compatibility, since the unbound vs. bound methods situation can be confusing.
2.45 +See assignment.txt for information about contexts and transformations.
2.46
2.47 Acquiring Values
2.48 ----------------
2.49
2.50 -According to the table describing value acquisition, different instructions
2.51 -must implement different operations when acquiring values:
2.52 -
2.53 - Instruction Purpose Context Operations
2.54 - ----------- ------- ------------------
2.55 -
2.56 - LoadConst Load class, function, Combine null context with loaded
2.57 - module, constant object
2.58 +There are two classes of instructions which provide values:
2.59
2.60 - LoadAddress Load attribute from Classes, functions and modules
2.61 - known object cause the loaded attribute to be
2.62 - (typically classes and retrieved unchanged; whereas
2.63 - modules) constants (representing instances)
2.64 - cause the constant to override the
2.65 - attribute's own context (since all
2.66 - attributes should belong to the
2.67 - constant's class hierarchy)
2.68 -
2.69 - LoadAddressContext Load attribute Override loaded context with a
2.70 - from known object predetermined object (provided
2.71 - (typically classes) that the object and context are
2.72 - for an instance compatible, which can be tested at
2.73 - compile-time)
2.74 + Instruction Purpose Context Operations
2.75 + ----------- ------- ------------------
2.76
2.77 - LoadAttr Load attribute from Contexts are preserved (since only
2.78 - instance values stored on instances can be
2.79 - accessed in this way, and their
2.80 - contexts would never be overridden
2.81 - upon access
2.82 -
2.83 - LoadAttrIndex Load attribute from Classes, functions and modules as
2.84 - object (can be the unknown object accessor cause
2.85 - classes, modules, the loaded attribute to be
2.86 - instances...) retrieved unchanged; instances
2.87 - cause the LoadAttr rules to apply
2.88 - (class compatibility applies)
2.89 -
2.90 -A certain amount of run-time testing might be required for both LoadAttr and
2.91 -LoadAttrIndex instructions. However, with certain restrictions in place around
2.92 -class attributes, some simplifications are possible:
2.93 + LoadConst Load class, function, Combine null context with
2.94 + module, constant loaded object
2.95
2.96 - * Since only class-originating attributes may cause context overriding, and
2.97 - since class attributes may only be defined within class definitions, the
2.98 - attributes whose context may be modified should be known at compile-time.
2.99 - (These will be those attributes whose context agrees with their parent
2.100 - class.)
2.101 -
2.102 - * By recording a special context value for attributes whose context can be
2.103 - overridden, this value can be tested efficiently at run-time where the
2.104 - appropriate conditions are satisfied. (This special context value or
2.105 - indicator will be present in the object table record for the attribute.)
2.106 -
2.107 - * It should be possible to move the instance compatibility condition testing
2.108 - to compile-time by testing the compatibility of the origin of an attribute
2.109 - with the class on which it is stored. However, some compatibility testing
2.110 - will still be required if invoking methods via classes, since the instance
2.111 - will be specified in the argument list instead of being presented in an
2.112 - attribute lookup instruction.
2.113 + LoadAddress Load attribute from Preserve or override stored
2.114 + LoadAddressContext class, module, context (as described in
2.115 + LoadAttr instance assignment.txt)
2.116 + LoadAttrIndex
2.117
2.118 Storing Values
2.119 --------------
2.120
2.121 -According to the table describing value acquisition, different instructions
2.122 -must implement different operations when acquiring values:
2.123 +There is only one class of instruction for storing values:
2.124
2.125 Instruction Purpose Context Operations
2.126 ----------- ------- ------------------
2.127 @@ -150,6 +66,7 @@
2.128 assignments to classes
2.129
2.130 Note that contexts are never changed in the stored value: they are preserved.
2.131 +See assignment.txt for more information.
2.132
2.133 Objects
2.134 -------
3.1 --- a/micropython/__init__.py Sun Feb 22 02:04:30 2009 +0100
3.2 +++ b/micropython/__init__.py Sun Feb 22 22:31:21 2009 +0100
3.3 @@ -29,8 +29,14 @@
3.4 importer.load_from_file(filename)
3.5 importer.vacuum()
3.6
3.7 -Such importer objects are the most convenient mechanism through which the
3.8 -functionality of the micropython package may be accessed.
3.9 +To generate programs, the above importer should be supplied in the
3.10 +initialisation of a program instance, and then various methods are called:
3.11 +
3.12 +program = Program(importer)
3.13 +image = program.get_raw_image()
3.14 +
3.15 +Such importer and program objects are the most convenient mechanism through
3.16 +which the functionality of the micropython package may be accessed.
3.17 """
3.18
3.19 from micropython.common import *
3.20 @@ -242,7 +248,7 @@
3.21 item.code_location = pos + len(item.defaults)
3.22
3.23 elif isinstance(item, micropython.data.Const):
3.24 - pos += len(self.raw_data(item))
3.25 + pos += len(item.raw_data())
3.26
3.27 else:
3.28 pos += 1
3.29 @@ -254,97 +260,26 @@
3.30 for item in self.code:
3.31
3.32 if isinstance(item, micropython.data.Attr):
3.33 - self.raw_code.append((
3.34 - item.context and item.context.location,
3.35 - item.value and item.value.location # no useful context is provided
3.36 - ))
3.37 + self.raw_code += item.as_raw(objtable)
3.38
3.39 elif isinstance(item, Block):
3.40 - self.raw_code += self.raw_block(item)
3.41 + assert item.location == len(self.raw_code)
3.42 + self.raw_code += item.as_raw(objtable)
3.43
3.44 # Using classcode, attrcode, codeaddr, codedetails, instance.
3.45
3.46 elif isinstance(item, micropython.data.Class):
3.47 assert item.instance_template_location == len(self.raw_code)
3.48 -
3.49 - classcode = objtable.as_list().get_code(item.full_name())
3.50 - attrcode = objtable.get_index(item.full_name())
3.51 -
3.52 - # Append a template of an instance for use when
3.53 - # instantiating classes.
3.54 -
3.55 - call_method = item.get("__call__")
3.56 - call_method_code_location = call_method and call_method.value.code_location
3.57 -
3.58 - self.raw_code.append(
3.59 - DataObject(
3.60 - classcode,
3.61 - attrcode,
3.62 - call_method_code_location,
3.63 - (
3.64 - call_method and len(call_method.value.positional_names),
3.65 - call_method and len(call_method.value.defaults)
3.66 - ),
3.67 - 1,
3.68 - item.full_name()
3.69 - )
3.70 - )
3.71 -
3.72 - assert item.location == len(self.raw_code)
3.73 -
3.74 - # NOTE: The instantiator code is the first block of the class.
3.75 -
3.76 - instantiator_code_location = item.get_instantiator().blocks[0].location
3.77 -
3.78 - # NOTE: Need initialiser details!
3.79 - self.raw_code.append(
3.80 - DataObject(
3.81 - classcode,
3.82 - attrcode,
3.83 - instantiator_code_location,
3.84 - (
3.85 - len(item.get_instantiator().positional_names),
3.86 - len(item.get_instantiator().defaults)
3.87 - ),
3.88 - 0,
3.89 - item.full_name()
3.90 - )
3.91 - )
3.92 + self.raw_code += item.as_raw(objtable)
3.93 + assert item.location == len(self.raw_code) - 1
3.94
3.95 elif isinstance(item, micropython.data.Const):
3.96 assert item.location == len(self.raw_code)
3.97 -
3.98 - # NOTE: Need class details!
3.99 - self.raw_code.append(
3.100 - DataObject(
3.101 - objtable.as_list().get_code(item.value_type_name()),
3.102 - objtable.get_index(item.value_type_name()),
3.103 - None,
3.104 - None,
3.105 - 1,
3.106 - item.value_type_name()
3.107 - )
3.108 - )
3.109 -
3.110 - self.raw_code += self.raw_data(item)
3.111 + self.raw_code += item.as_raw(objtable)
3.112
3.113 elif isinstance(item, micropython.data.Function):
3.114 assert item.location == len(self.raw_code)
3.115 -
3.116 - # NOTE: Need class and parameter details! Should arguably be types.FunctionType.
3.117 - self.raw_code.append(
3.118 - DataObject(
3.119 - objtable.as_list().get_code("__builtins__.function"),
3.120 - objtable.get_index("__builtins__.function"),
3.121 - item.code_location,
3.122 - (
3.123 - len(item.positional_names),
3.124 - len(item.defaults)
3.125 - ),
3.126 - 0,
3.127 - "__builtins__.function"
3.128 - )
3.129 - )
3.130 + self.raw_code += item.as_raw(objtable)
3.131
3.132 # Check the code location only where the code has been generated.
3.133
3.134 @@ -353,17 +288,7 @@
3.135
3.136 elif isinstance(item, micropython.data.Module):
3.137 assert item.location == len(self.raw_code)
3.138 -
3.139 - self.raw_code.append(
3.140 - DataObject(
3.141 - objtable.as_list().get_code(item.full_name()),
3.142 - None, # module name not used as an attribute
3.143 - None,
3.144 - None,
3.145 - 0,
3.146 - item.full_name()
3.147 - )
3.148 - )
3.149 + self.raw_code += item.as_raw(objtable)
3.150
3.151 else:
3.152 self.raw_code.append(item)
3.153 @@ -380,29 +305,6 @@
3.154 self.code_location = self.importer.modules["__main__"].code_location
3.155 return self.raw_code
3.156
3.157 - def raw_block(self, block):
3.158 -
3.159 - "Return the code for the given 'block'."
3.160 -
3.161 - assert block.location == len(self.raw_code)
3.162 - for i, item in enumerate(block.code):
3.163 - if hasattr(item, "location"):
3.164 - item.location = location + i
3.165 - return block.code
3.166 -
3.167 - def raw_data(self, item):
3.168 -
3.169 - "Return the data for the given 'item'."
3.170 -
3.171 - datatype = item.value_type_name()
3.172 -
3.173 - # NOTE: Start simple and use single entries for most types.
3.174 -
3.175 - if datatype in ("__builtins__.tuple", "__builtins__.list"):
3.176 - return [len(item.value)] + list(item.value)
3.177 - else:
3.178 - return [item.value]
3.179 -
3.180 def get_object_table(self):
3.181
3.182 "Return a table with details of attributes for classes and modules."
4.1 --- a/micropython/ast.py Sun Feb 22 02:04:30 2009 +0100
4.2 +++ b/micropython/ast.py Sun Feb 22 22:31:21 2009 +0100
4.3 @@ -581,7 +581,7 @@
4.4 # 5. Invocation of the target
4.5 # 6. Discarding of the frame
4.6 #
4.7 - # In order to support nested invocations - eg. a(b(c)) - use of the
4.8 + # In order to support nested invocations - such as a(b(c)) - use of the
4.9 # temporary storage is essential.
4.10
4.11 def _startCallFunc(self):
4.12 @@ -855,9 +855,6 @@
4.13 self._endCallFuncArgs(nargs_max)
4.14
4.15 # Or generate instructions to do this at run-time.
4.16 - # NOTE: CheckFrame has to check the number of arguments and to fill in
4.17 - # NOTE: defaults; it also has to shift the invocation frame according to
4.18 - # NOTE: the context in use.
4.19
4.20 else:
4.21 max_pos = max(max(employed_positions or [-1]), max_keyword_pos, frame_pos - 1)
5.1 --- a/micropython/common.py Sun Feb 22 02:04:30 2009 +0100
5.2 +++ b/micropython/common.py Sun Feb 22 22:31:21 2009 +0100
5.3 @@ -84,6 +84,15 @@
5.4 def __repr__(self):
5.5 return "Block(%r, location=%r)" % (id(self), self.location)
5.6
5.7 + def as_raw(self, objtable):
5.8 +
5.9 + "Return the code for the given 'block'."
5.10 +
5.11 + for i, item in enumerate(self.code):
5.12 + if hasattr(item, "location"):
5.13 + item.location = location + i
5.14 + return self.code
5.15 +
5.16 # Program data representations.
5.17
5.18 class DataObject:
6.1 --- a/micropython/data.py Sun Feb 22 02:04:30 2009 +0100
6.2 +++ b/micropython/data.py Sun Feb 22 22:31:21 2009 +0100
6.3 @@ -310,6 +310,14 @@
6.4 self.name, shortrepr(self.value), self.assignments
6.5 )
6.6
6.7 + def as_raw(self, objtable):
6.8 + return [
6.9 + (
6.10 + self.context and self.context.location,
6.11 + self.value and self.value.location
6.12 + )
6.13 + ]
6.14 +
6.15 # Instances are special in that they need to be wrapped together with context in
6.16 # a running program, but they are not generally constant.
6.17
6.18 @@ -357,6 +365,26 @@
6.19
6.20 __shortrepr__ = __repr__
6.21
6.22 + def as_raw(self, objtable):
6.23 + # NOTE: Need class details!
6.24 + return [
6.25 + DataObject(
6.26 + objtable.as_list().get_code(self.value_type_name()),
6.27 + objtable.get_index(self.value_type_name()),
6.28 + None,
6.29 + None,
6.30 + 1,
6.31 + self.value_type_name()
6.32 + )
6.33 + ] + self.raw_data()
6.34 +
6.35 + def raw_data(self):
6.36 + # NOTE: Start simple and use single entries for most types.
6.37 + if self.value_type_name() in ("__builtins__.tuple", "__builtins__.list"):
6.38 + return [len(self.value)] + list(self.value)
6.39 + else:
6.40 + return [self.value]
6.41 +
6.42 # Support constants as dictionary keys in order to build constant tables.
6.43
6.44 def __eq__(self, other):
6.45 @@ -433,6 +461,42 @@
6.46 def __shortrepr__(self):
6.47 return "Class(%r, %s)" % (self.name, shortrepr(self.parent))
6.48
6.49 + def as_raw(self, objtable):
6.50 + classcode = objtable.as_list().get_code(self.full_name())
6.51 + attrcode = objtable.get_index(self.full_name())
6.52 +
6.53 + # Append a template of an instance for use when instantiating classes.
6.54 +
6.55 + call_method = self.get("__call__")
6.56 + call_method_code_location = call_method and call_method.value.code_location
6.57 +
6.58 + # NOTE: The instantiator code is the first block of the class.
6.59 +
6.60 + instantiator_code_location = self.get_instantiator().blocks[0].location
6.61 +
6.62 + return [
6.63 + DataObject(
6.64 + classcode, attrcode, call_method_code_location,
6.65 + (
6.66 + call_method and len(call_method.value.positional_names),
6.67 + call_method and len(call_method.value.defaults)
6.68 + ),
6.69 + 1,
6.70 + self.full_name()
6.71 + ),
6.72 + DataObject(
6.73 + classcode, attrcode, instantiator_code_location,
6.74 + (
6.75 + len(self.get_instantiator().positional_names),
6.76 + len(self.get_instantiator().defaults)
6.77 + ),
6.78 + 0,
6.79 + self.full_name()
6.80 + )
6.81 + ]
6.82 +
6.83 + # Namespace-related methods.
6.84 +
6.85 def _context(self, value):
6.86
6.87 """
6.88 @@ -797,6 +861,24 @@
6.89 self.name, shortrepr(self.parent)
6.90 )
6.91
6.92 + def as_raw(self, objtable):
6.93 + # NOTE: Need class and parameter details! Should arguably be types.FunctionType.
6.94 + return [
6.95 + DataObject(
6.96 + objtable.as_list().get_code("__builtins__.function"),
6.97 + objtable.get_index("__builtins__.function"),
6.98 + self.code_location,
6.99 + (
6.100 + len(self.positional_names),
6.101 + len(self.defaults)
6.102 + ),
6.103 + 0,
6.104 + "__builtins__.function"
6.105 + )
6.106 + ]
6.107 +
6.108 + # Namespace-related methods.
6.109 +
6.110 def store_default(self, value):
6.111 attr = Attr(None, self, None, None, value)
6.112 attr.update(value, 1)
6.113 @@ -983,6 +1065,18 @@
6.114 def __shortrepr__(self):
6.115 return "Module(%r)" % self.name
6.116
6.117 + def as_raw(self, objtable):
6.118 + return [
6.119 + DataObject(
6.120 + objtable.as_list().get_code(self.full_name()),
6.121 + None, # module name not used as an attribute
6.122 + None,
6.123 + None,
6.124 + 0,
6.125 + self.full_name()
6.126 + )
6.127 + ]
6.128 +
6.129 # Attribute methods.
6.130
6.131 "Return the module attribute names provided by the module."
7.1 --- a/tests/call_func_default.py Sun Feb 22 02:04:30 2009 +0100
7.2 +++ b/tests/call_func_default.py Sun Feb 22 22:31:21 2009 +0100
7.3 @@ -1,29 +1,9 @@
7.4 #!/usr/bin/env python
7.5
7.6 -x = 123
7.7 -
7.8 def f(a, b, c=4):
7.9 pass
7.10
7.11 f(1, 2, 3)
7.12 -f(1, b=2, c=3)
7.13 -f(c=3, b=2, a=1)
7.14 f(1, 2)
7.15
7.16 -g = f
7.17 -g(1, c=3, b=2)
7.18 -g(1, 2)
7.19 -
7.20 -def g(a, c, b=5):
7.21 - pass
7.22 -
7.23 -g(1, c=3, b=2)
7.24 -g(1, 3)
7.25 -
7.26 -def h(a, b, c=f(1, 2, 3)):
7.27 - pass
7.28 -
7.29 -h(1, 2, 3)
7.30 -h(1, 2)
7.31 -
7.32 # vim: tabstop=4 expandtab shiftwidth=4
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/tests/call_func_default_dynamic.py Sun Feb 22 22:31:21 2009 +0100
8.3 @@ -0,0 +1,12 @@
8.4 +#!/usr/bin/env python
8.5 +
8.6 +def f(a, b, c):
8.7 + return c
8.8 +
8.9 +def h(a, b, c=f(1, 2, 3)):
8.10 + return c
8.11 +
8.12 +h(1, 2, 3)
8.13 +h(1, 2)
8.14 +
8.15 +# 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_keyword.py Sun Feb 22 22:31:21 2009 +0100
9.3 @@ -0,0 +1,11 @@
9.4 +#!/usr/bin/env python
9.5 +
9.6 +def f(a, b, c=4):
9.7 + pass
9.8 +
9.9 +f(1, 2, 3)
9.10 +f(1, b=2, c=3)
9.11 +f(c=3, b=2, a=1)
9.12 +f(1, 2)
9.13 +
9.14 +# 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_redefine.py Sun Feb 22 22:31:21 2009 +0100
10.3 @@ -0,0 +1,16 @@
10.4 +#!/usr/bin/env python
10.5 +
10.6 +def f(a, b, c=4):
10.7 + pass
10.8 +
10.9 +g = f
10.10 +g(1, c=3, b=2)
10.11 +g(1, 2)
10.12 +
10.13 +def g(a, c, b=5):
10.14 + pass
10.15 +
10.16 +g(1, c=3, b=2)
10.17 +g(1, 3)
10.18 +
10.19 +# vim: tabstop=4 expandtab shiftwidth=4