# HG changeset patch # User Paul Boddie # Date 1243982937 -7200 # Node ID 31c5526286ba05d9f6c4a856b384638c907f0fb3 # Parent 6ba10a65eddd00ed0a9c0e092c598638555079ff Introduced replaceable and placeholder contexts, replacing the null context (None) with ReplaceableContext and introducing PlaceholderContext for class value contexts via a new LoadClass instruction, thus permitting instantiators to be called with such contexts. diff -r 6ba10a65eddd -r 31c5526286ba docs/concepts.txt --- a/docs/concepts.txt Tue Jun 02 20:17:59 2009 +0200 +++ b/docs/concepts.txt Wed Jun 03 00:48:57 2009 +0200 @@ -67,21 +67,47 @@ See invocation.txt for details. +Context Value Types +------------------- + +The following types of context value exist: + + Type Usage Transformations + ---- ----- --------------- + + Replaceable With functions (not methods) May be replaced with an + instance or a class when a + value is stored on an + instance or class + + Placeholder With classes May not be replaced + + Instance With instances (and constants) May not be replaced + or functions as methods + + Class With functions as methods May be replaced when a + value is loaded from a + class attribute via an + instance + Contexts in Acquired Values --------------------------- -There are three classes of instructions which provide values: +There are four classes of instructions which provide values: Instruction Purpose Context Operations ----------- ------- ------------------ -1) LoadConst Load class, module, Use loaded object with itself - constant as context +1) LoadConst Load module, constant Use loaded object with itself + as context -2) LoadFunction Load function Combine null context with - loaded object +2) LoadFunction Load function Combine replaceable context + with loaded object -3) LoadAddress* Load attribute from Preserve or override stored +3) LoadClass Load class Combine placeholder context + with loaded object + +4) LoadAddress* Load attribute from Preserve or override stored LoadAttr* class, module, context (as described in instance assignment.txt) @@ -118,9 +144,9 @@ assignments to classes 2) StoreAddressContext Store attribute in a Override context if appropriate; - known object if the value has a null context, - permit the target to take - ownership of the value + known object if the value has a replaceable + context, permit the target to + take ownership of the value See assignment.txt for details. diff -r 6ba10a65eddd -r 31c5526286ba micropython/ast.py --- a/micropython/ast.py Tue Jun 02 20:17:59 2009 +0200 +++ b/micropython/ast.py Wed Jun 03 00:48:57 2009 +0200 @@ -552,7 +552,7 @@ # Store the name. - self.new_op(LoadConst(node.unit)) + self.new_op(LoadClass(node.unit)) self.record_value() self._visitName(node, self.name_store_instructions) self.set_source() diff -r 6ba10a65eddd -r 31c5526286ba micropython/data.py --- a/micropython/data.py Tue Jun 02 20:17:59 2009 +0200 +++ b/micropython/data.py Wed Jun 03 00:48:57 2009 +0200 @@ -44,7 +44,7 @@ where each such object is defined. """ -from micropython.program import DataObject +from micropython.program import DataObject, ReplaceableContext, PlaceholderContext def shortrepr(obj): if obj is None: @@ -184,17 +184,34 @@ attr = self.namespace[name] # Handle attribute assignment as well as assignment of basic objects. + # Attempt to fix the context if not explicitly defined. if isinstance(attr_or_value, Attr): + context_values = self.get_updated_context_values(attr_or_value.context_values) + else: + context_values = self.get_updated_context_values([self.get_context_and_value(attr_or_value)]) - # Attempt to fix the context if not explicitly defined. + attr.update(context_values, single_assignment) + + def get_context_and_value(self, value): + + "Return a context, value tuple for the given 'value'." + + # Functions have a replaceable context. - context_values = self.get_updated_context_values(attr_or_value.context_values) + if isinstance(value, Function): + return (ReplaceableContext, value) + + # Classes use placeholder contexts which cannot be replaced but which + # do not communicate useful contextual information. + + elif isinstance(value, Class): + return (PlaceholderContext, value) + + # Other values employ themselves as the context. else: - context_values = self.get_updated_context_values([(None, attr_or_value)]) - - attr.update(context_values, single_assignment) + return (value, value) def get_updated_context_values(self, context_values): @@ -293,10 +310,16 @@ return [v for (c, v) in self.context_values] def get_context(self): - return len(self.context_values) == 1 and self.get_contexts()[0] or None + if len(self.context_values) == 1: + return self.get_contexts()[0] + else: + return None def get_value(self): - return len(self.context_values) == 1 and self.get_values()[0] or None + if len(self.context_values) == 1: + return self.get_values()[0] + else: + return None def update(self, context_values, single_assignment): @@ -623,7 +646,7 @@ # Change the ownership of functions. - if context is None and value is not None and isinstance(value, Function): + if context is ReplaceableContext and value is not None and isinstance(value, Function): results.add((self, value)) else: results.add((context, value)) @@ -999,7 +1022,7 @@ def store_default(self, value): attr = Attr(None, self, None) - attr.update([(None, value)], 1) + attr.update([self.get_context_and_value(value)], 1) self.default_attrs.append(attr) def make_global(self, name): diff -r 6ba10a65eddd -r 31c5526286ba micropython/opt.py --- a/micropython/opt.py Tue Jun 02 20:17:59 2009 +0200 +++ b/micropython/opt.py Wed Jun 03 00:48:57 2009 +0200 @@ -153,7 +153,7 @@ "Return whether 'instruction' provides a constant input." return isinstance(instruction, LoadAddress) and instruction.attr.assignments == 1 or \ - isinstance(instruction, (LoadConst, LoadFunction)) + isinstance(instruction, (LoadConst, LoadClass, LoadFunction)) def is_constant_target(self, instruction): @@ -173,7 +173,7 @@ a load operation from a CPU register or special memory location. """ - return isinstance(instruction, (LoadConst, LoadFunction, LoadName, LoadTemp, LoadResult, LoadException, LoadAddress)) + return isinstance(instruction, (LoadConst, LoadClass, LoadFunction, LoadName, LoadTemp, LoadResult, LoadException, LoadAddress)) def is_simple_input_user(self, instruction): @@ -275,7 +275,7 @@ # LoadResult cannot be relied upon in general since the result register # could be updated since first being referenced. - return isinstance(self.active_value, (LoadName, LoadTemp, LoadAddress, LoadConst, LoadFunction)) or \ + return isinstance(self.active_value, (LoadName, LoadTemp, LoadAddress, LoadConst, LoadClass, LoadFunction)) or \ isinstance(self.active_value, LoadResult) and self.active_value is self.active or \ isinstance(self.active_value, LoadException) and self.active_value is self.active diff -r 6ba10a65eddd -r 31c5526286ba micropython/program.py --- a/micropython/program.py Tue Jun 02 20:17:59 2009 +0200 +++ b/micropython/program.py Wed Jun 03 00:48:57 2009 +0200 @@ -44,4 +44,32 @@ (self.classcode, self.attrcode, self.codeaddr, self.funccode, self.size), self.name ) +class Context: + + """ + A representation of a context used in a program, providing the special + context value types. + """ + + def __init__(self, truth_value, repr): + self.truth_value = truth_value + self.repr = repr + + def __repr__(self): + return self.repr + + def __nonzero__(self): + return self.truth_value + +# A representation of a context that is replaced upon certain assignment +# operations. + +ReplaceableContext = Context(0, "Replace") + +# A representation of a context that is employed by classes so that +# instantiators have enough slots in the invocation frame, yet does not cause +# testing of the context or adjustment of the frame. + +PlaceholderContext = Context(0, "Placeholder") + # vim: tabstop=4 expandtab shiftwidth=4 diff -r 6ba10a65eddd -r 31c5526286ba micropython/rsvp.py --- a/micropython/rsvp.py Tue Jun 02 20:17:59 2009 +0200 +++ b/micropython/rsvp.py Wed Jun 03 00:48:57 2009 +0200 @@ -154,7 +154,8 @@ # Access to stored constant data. -class LoadConst(Address): "Load the constant, class, module from the specified location." +class LoadConst(Address): "Load the constant or module from the specified location." +class LoadClass(Address): "Load the class from the specified location." class LoadFunction(Address): "Load the function from the specified location." # Access within an invocation frame. @@ -245,7 +246,7 @@ # Instructions which affect the current value. (LoadAttrIndexContext not defined.) current_value_instructions = ( - LoadConst, LoadFunction, LoadName, LoadTemp, + LoadConst, LoadClass, LoadFunction, LoadName, LoadTemp, LoadAddress, LoadAddressContext, LoadAddressContextCond, LoadAttr, LoadAttrIndex, LoadAttrIndexContextCond, LoadCallable, LoadContext, LoadResult, diff -r 6ba10a65eddd -r 31c5526286ba micropython/trans.py --- a/micropython/trans.py Tue Jun 02 20:17:59 2009 +0200 +++ b/micropython/trans.py Wed Jun 03 00:48:57 2009 +0200 @@ -826,19 +826,16 @@ if target is None: - # Skip adjustment and tests if a class is being invoked. - - self.new_op(temp_target) - self.new_op(CheckClass()) - self.new_op(JumpIfTrue(continue_block)) - - # Adjust the frame is no usable context is provided. + # Adjust the frame if a replaceable context is provided. self.new_op(temp_context) self.new_op(CheckContext()) self.new_op(JumpIfFalse(adjust_block)) # Skip adjustment and tests if the context is not a class. + # Classes themselves employ a placeholder context so that + # instantiators can be callable with a context which will be + # overwritten in the frame. self.new_op(temp_context) self.new_op(CheckClass()) diff -r 6ba10a65eddd -r 31c5526286ba rsvp.py --- a/rsvp.py Tue Jun 02 20:17:59 2009 +0200 +++ b/rsvp.py Wed Jun 03 00:48:57 2009 +0200 @@ -52,6 +52,7 @@ current callable """ +from micropython.program import ReplaceableContext, PlaceholderContext import operator class IllegalInstruction(Exception): @@ -386,8 +387,11 @@ def LoadConst(self): self.value = self.operand, self.operand + def LoadClass(self): + self.value = PlaceholderContext, self.operand + def LoadFunction(self): - self.value = None, self.operand + self.value = ReplaceableContext, self.operand def LoadName(self): frame = self.local_sp_stack[-1] @@ -425,7 +429,7 @@ # Overwrite context if null. context_context, context_ref = self.value source_context, source_ref = self.source - if source_context is None: + if source_context is ReplaceableContext: context = context_ref else: context = source_context @@ -546,10 +550,14 @@ self.value = context, context def CheckContext(self): - self.status = self.value[1] is not None + self.status = self.value[1] is not ReplaceableContext def CheckClass(self): context, ref = self.value + if ref in (ReplaceableContext, PlaceholderContext): + self.status = 0 + return + data = self.load(ref) # Classes are not themselves usable as the self argument. @@ -721,7 +729,7 @@ def _LoadAddressContextCond(self, context, ref, inst_ref): # Check the instance context against the target's context. # This provides the context overriding for methods. - if context is not None and self._CheckInstance(inst_ref, context): + if context is not ReplaceableContext and self._CheckInstance(inst_ref, context): # Replace the context with the instance. return inst_ref, ref else: