# HG changeset patch # User Paul Boddie # Date 1255221620 -7200 # Node ID 5c26eb35251e1107f357ea2930fc8a25967d1fd2 # Parent f76003d45947d5489161186cce2a2b7f2d47624e Moved raw image generation code from the Program class to the micropython.rsvp module. Improved the string representations for objects and values in program images. diff -r f76003d45947 -r 5c26eb35251e micropython/__init__.py --- a/micropython/__init__.py Sat Oct 10 03:09:29 2009 +0200 +++ b/micropython/__init__.py Sun Oct 11 02:40:20 2009 +0200 @@ -39,8 +39,7 @@ which the functionality of the micropython package may be accessed. """ -from micropython.common import * -from micropython.program import Block +from micropython.common import TableGenerationError import micropython.ast import micropython.data import micropython.opt @@ -89,7 +88,10 @@ def get_image(self, with_builtins=0): - "Return a dictionary mapping modules to structures." + """ + Return the program image including built-in objects if 'with_builtins' + is specified and set to a true value. + """ if self.code is not None: return self.code @@ -102,13 +104,12 @@ # Append constants to the image. - for pos, const in enumerate(self.importer.constants()): + for const in self.importer.constants(): self.code.append(const) last_module = self.importer.modules_ordered[-1] for module in self.importer.modules_ordered: - pos = len(self.code) suppress_builtins = not with_builtins and module.name == "__builtins__" # Position the module in the image and make a translation. @@ -118,13 +119,11 @@ # Add header details. self.code.append(module) - pos += 1 # Append module attributes to the image. attributes = module.module_attributes() self.code += module.attributes_as_list() - pos += len(attributes.keys()) # Append classes and functions to the image. @@ -134,13 +133,11 @@ # Add header details. self.code.append(obj) - pos += 1 # Append class attributes to the image. attributes = obj.class_attributes() self.code += obj.attributes_as_list() - pos += len(attributes.keys()) # Omit built-in function code where requested. @@ -153,7 +150,6 @@ instantiator = obj.get_instantiator() code = trans.get_instantiator_code(obj) self.code += code - pos += len(code) # Class-level code is generated separately at the module # level, and the code location is set within the code @@ -164,14 +160,12 @@ # Add header details. self.code.append(obj) - pos += 1 # Append any default values to the image. # Only do this for named functions (not lambdas). if obj.name is not None: self.code += obj.default_attrs - pos += len(obj.default_attrs) # Omit built-in function code where requested. @@ -183,7 +177,6 @@ else: code = trans.get_code(obj) self.code += code - pos += len(code) # Omit built-in module code where requested. @@ -195,14 +188,15 @@ else: code = trans.get_module_code() self.code += code - pos += len(code) return self.code - def get_raw_image(self, with_builtins=0): + def get_raw_image(self, architecture=None, with_builtins=0): "Return the raw image representation of the program." + architecture = architecture or micropython.rsvp + self.get_image(with_builtins) objtable = self.get_object_table() @@ -213,56 +207,12 @@ pos = 0 for item in self.code: - - # Blocks are positioned leaving space for their expansion. - - if isinstance(item, Block): - item.location = pos - pos += len(item.code) - - # Other multi-location objects. - - elif isinstance(item, ( - micropython.data.Class, micropython.data.Const, - micropython.data.Function, micropython.data.Module - )): - - if isinstance(item, micropython.data.Class): - - # Append a template of an instance for use when - # instantiating classes. - - item.instance_template_location = pos - pos += 1 - - # Record the location of the object. + arch_item = architecture.get_object(item) - item.location = pos - pos += 1 - - # Code and details are associated with certain objects. - - if isinstance(item, micropython.data.Function): - - # Set the code location only where the code has been - # generated. - - if not with_builtins and item.module.name == "__builtins__" and item.astnode.doc is None: - item.code_location = item.full_name() + # Get the raw version for the architecture. - # Skip any defaults for named functions. - - elif item.name is not None: - item.code_location = pos + len(item.defaults) - - # Skip any defaults for lambda functions. - - else: - item.code_location = pos - - elif isinstance(item, micropython.data.Const): - pos += len(item.raw_data()) - + if arch_item is not None: + pos = arch_item.set_location(pos, with_builtins) else: pos += 1 @@ -271,50 +221,16 @@ self.raw_code = [] for item in self.code: - - if isinstance(item, micropython.data.Attr): - self.raw_code += item.as_raw(objtable, paramtable) + arch_item = architecture.get_object(item) - elif isinstance(item, Block): - assert item.location == len(self.raw_code) - self.raw_code += item.as_raw(objtable, paramtable) - - elif isinstance(item, micropython.data.Class): - assert item.instance_template_location == len(self.raw_code) - self.raw_code += item.as_raw(objtable, paramtable, - with_builtins or item.module.name != "__builtins__" or item.astnode.doc is not None) - assert item.location == len(self.raw_code) - 1 + # Get the raw version for the architecture. - elif isinstance(item, micropython.data.Const): - assert item.location == len(self.raw_code) - self.raw_code += item.as_raw(objtable, paramtable) - - elif isinstance(item, micropython.data.Function): - assert item.location == len(self.raw_code) - self.raw_code += item.as_raw(objtable, paramtable) - - # Check the code location only where the code has been generated. - - assert (not with_builtins and item.module.name == "__builtins__" and item.astnode.doc is None) or \ - item.name is not None and item.code_location == len(self.raw_code) + len(item.defaults) or \ - item.name is None and item.code_location == len(self.raw_code) - - elif isinstance(item, micropython.data.Module): - assert item.location == len(self.raw_code) - self.raw_code += item.as_raw(objtable, paramtable) - + if arch_item is not None: + self.raw_code += arch_item.as_raw(objtable, paramtable, with_builtins) + arch_item.finalise_location(with_builtins) else: self.raw_code.append(item) - # Set the code body location for items now that the code blocks have - # been positioned. - - if isinstance(item, (micropython.data.Class, micropython.data.Function)): - if not with_builtins and item.module.name == "__builtins__" and item.astnode.doc is None: - item.code_body_location = item.full_name() - else: - item.code_body_location = item.get_body_block().location - # Fix the module locations. for module in self.importer.modules_ordered: diff -r f76003d45947 -r 5c26eb35251e micropython/data.py --- a/micropython/data.py Sat Oct 10 03:09:29 2009 +0200 +++ b/micropython/data.py Sun Oct 11 02:40:20 2009 +0200 @@ -431,14 +431,6 @@ l.append("(c=%s, v=%s)" % (shortrepr(c), shortrepr(v))) return ", ".join(l) - def as_raw(self, objtable, paramtable): - return [ - DataValue( - self.get_context() and self.get_context().location, - self.get_value() and self.get_value().location - ) - ] - # Instances are special in that they need to be wrapped together with context in # a running program, but they are not generally constant. @@ -475,7 +467,7 @@ self.value = value def get_value(self): - return value + return self.value def __repr__(self): if self.location is not None: @@ -485,25 +477,6 @@ __shortrepr__ = __repr__ - def as_raw(self, objtable, paramtable): - # NOTE: Need class details! - return [ - DataObject( - objtable.as_list().get_code(self.value_type_name()), - objtable.get_index(self.value_type_name()), # is instance - None, - self.value_type_name(), - 1 # size - ) - ] + self.raw_data() - - def raw_data(self): - # NOTE: Start simple and use single entries for most types. - if self.value_type_name() in ("__builtins__.tuple", "__builtins__.list"): - return [len(self.value)] + list(self.value) - else: - return [self.value] - # Support constants as dictionary keys in order to build constant tables. def __eq__(self, other): @@ -578,51 +551,6 @@ def __shortrepr__(self): return "Class(%r, %s)" % (self.name, shortrepr(self.parent)) - def as_raw(self, objtable, paramtable, with_instantiator=1): - classcode = objtable.as_list().get_code(self.full_name()) - attrcode = objtable.get_index(self.full_name()) - - # Include a template of an instance for use when instantiating classes. - - call_method = self.all_class_attributes().get("__call__") - call_method_value = call_method and call_method.get_value() - call_method_code_location = call_method_value and call_method_value.code_location - call_method_funccode = call_method_value and paramtable.as_list().get_code(call_method_value.full_name()) - - instantiator_funccode = paramtable.as_list().get_code(self.get_instantiator().full_name()) - - # NOTE: The instantiator code is the first block of the class. - - if not with_instantiator: - instantiator_code_location = self.full_name() - else: - instantiator_code_location = self.get_instantiator().blocks[0].location - - return [ - - # Template instance... - - DataObject( - classcode, - attrcode, # is instance - call_method_code_location, - self.full_name(), - len(self.instance_attributes()) + 1, # size - call_method_funccode # funccode - ), - - # Class... - - DataObject( - classcode, - None, # is not instance - instantiator_code_location, - self.full_name(), - len(self.class_attributes()) + 1, # size - instantiator_funccode # funccode - ) - ] - def get_body_block(self): return self.get_instantiator().blocks[0] @@ -995,19 +923,6 @@ self.name, shortrepr(self.parent) ) - def as_raw(self, objtable, paramtable): - # NOTE: Need class and parameter details! Should arguably be an instance of types.FunctionType. - return [ - DataObject( - objtable.as_list().get_code("__builtins__.function"), - objtable.get_index("__builtins__.function"), # is instance - self.code_location, - "__builtins__.function", - len(self.defaults) + 1, # size (not accurate for lambda functions before instantiation) - paramtable.as_list().get_code(self.full_name()) # funccode - ) - ] - def get_body_block(self): return self.body_block @@ -1200,17 +1115,6 @@ def __shortrepr__(self): return "Module(%r)" % self.name - def as_raw(self, objtable, paramtable): - return [ - DataObject( - objtable.as_list().get_code(self.full_name()), - None, # modules treated like classes - None, - self.full_name(), - len(self.module_attributes()) + 1 # size - ) - ] - # Attribute methods. "Return the module attribute names provided by the module." diff -r f76003d45947 -r 5c26eb35251e micropython/program.py --- a/micropython/program.py Sat Oct 10 03:09:29 2009 +0200 +++ b/micropython/program.py Sun Oct 11 02:40:20 2009 +0200 @@ -30,12 +30,6 @@ def __repr__(self): return "Block(%r, location=%r)" % (id(self), self.location) - def as_raw(self, objtable, paramtable): - for i, item in enumerate(self.code): - if hasattr(item, "location"): - item.location = location + i - return self.code - class DataValue: "A representation of a raw program value." @@ -45,7 +39,7 @@ self.ref = ref def __repr__(self): - return "%r, %r" % ( + return "value: (%r, %r)" % ( self.context, self.ref ) @@ -68,7 +62,7 @@ return DataObject(self.classcode, self.attrcode, codeaddr, self.name, self.size, self.funccode) def __repr__(self): - return "%r # %s" % ( + return "object: %r # %s" % ( (self.classcode, self.attrcode, self.codeaddr, self.funccode, self.size), self.name ) diff -r f76003d45947 -r 5c26eb35251e micropython/rsvp.py --- a/micropython/rsvp.py Sat Oct 10 03:09:29 2009 +0200 +++ b/micropython/rsvp.py Sun Oct 11 02:40:20 2009 +0200 @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -RSVP instruction classes. +RSVP instruction and serialisation classes. Copyright (C) 2007, 2008, 2009 Paul Boddie @@ -19,8 +19,8 @@ this program. If not, see . """ -from micropython.data import Attr, Const -from micropython.program import Block +from micropython.data import Attr, Const, Class, Function, Module +from micropython.program import Block, DataObject, DataValue def name(attr): if isinstance(attr, Attr): @@ -30,6 +30,234 @@ else: return attr.full_name() or "" +# Serialisation-related classes. + +class RSVPObject: + + "A generic data object wrapper." + + def __init__(self, item): + self.item = item + + def set_location(self, location, with_builtins): + self.item.location = location + return location + 1 + + def finalise_location(self, with_builtins): + pass + + def _finalise_location(self, with_builtins): + + """ + Set the code body location for items now that the code blocks have been + positioned. + """ + + item = self.item + + if not with_builtins and item.module.name == "__builtins__" and item.astnode.doc is None: + item.code_body_location = item.full_name() + else: + item.code_body_location = item.get_body_block().location + +class RSVPAttr(RSVPObject): + + "A wrapper for attributes/values." + + def as_raw(self, objtable, paramtable, with_builtins): + item = self.item + return [ + DataValue( + item.get_context() and item.get_context().location, + item.get_value() and item.get_value().location + ) + ] + +class RSVPBlock(RSVPObject): + + "A wrapper for blocks." + + def set_location(self, location, with_builtins): + item = self.item + item.location = location + return location + len(item.code) + + def as_raw(self, objtable, paramtable, with_builtins): + return self.item.code + +class RSVPClass(RSVPObject): + + "A wrapper for classes." + + def set_location(self, location, with_builtins): + self.item.instance_template_location = location + return RSVPObject.set_location(self, location + 1, with_builtins) + + def finalise_location(self, with_builtins): + self._finalise_location(with_builtins) + + def as_raw(self, objtable, paramtable, with_builtins): + item = self.item + classcode = objtable.as_list().get_code(item.full_name()) + attrcode = objtable.get_index(item.full_name()) + + # Include a template of an instance for use when instantiating classes. + + call_method = item.all_class_attributes().get("__call__") + call_method_value = call_method and call_method.get_value() + call_method_code_location = call_method_value and call_method_value.code_location + call_method_funccode = call_method_value and paramtable.as_list().get_code(call_method_value.full_name()) + + instantiator_funccode = paramtable.as_list().get_code(item.get_instantiator().full_name()) + + # NOTE: The instantiator code is the first block of the class. + + with_instantiator = with_builtins or item.module.name != "__builtins__" or item.astnode.doc is not None + + if not with_instantiator: + instantiator_code_location = item.full_name() + else: + instantiator_code_location = item.get_instantiator().blocks[0].location + + return [ + + # Template instance... + + DataObject( + classcode, + attrcode, # is instance + call_method_code_location, + item.full_name(), + len(item.instance_attributes()) + 1, # size + call_method_funccode # funccode + ), + + # Class... + + DataObject( + classcode, + None, # is not instance + instantiator_code_location, + item.full_name(), + len(item.class_attributes()) + 1, # size + instantiator_funccode # funccode + ) + ] + +class RSVPConst(RSVPObject): + + "A wrapper for constants." + + def set_location(self, location, with_builtins): + location = RSVPObject.set_location(self, location, with_builtins) + return location + len(self.raw_data()) + + def as_raw(self, objtable, paramtable, with_builtins): + item = self.item + # NOTE: Need class details! + return [ + DataObject( + objtable.as_list().get_code(item.value_type_name()), + objtable.get_index(item.value_type_name()), # is instance + None, + item.value_type_name(), + 1 # size + ) + ] + self.raw_data() + + def raw_data(self): + item = self.item + value = item.get_value() + # NOTE: Start simple and use single entries for most types. + if item.value_type_name() in ("__builtins__.tuple", "__builtins__.list"): + return [len(value)] + list(value) + else: + return [value] + +class RSVPFunction(RSVPObject): + + "A wrapper for functions." + + def set_location(self, location, with_builtins): + item = self.item + location = RSVPObject.set_location(self, location, with_builtins) + + # Set the code location only where the code has been + # generated. + + if not with_builtins and item.module.name == "__builtins__" and item.astnode.doc is None: + item.code_location = item.full_name() + + # Skip any defaults for named functions. + + elif item.name is not None: + item.code_location = location + len(item.defaults) + + # Skip any defaults for lambda functions. + + else: + item.code_location = location + + return location + + def finalise_location(self, with_builtins): + self._finalise_location(with_builtins) + + def as_raw(self, objtable, paramtable, with_builtins): + item = self.item + # NOTE: Need class and parameter details! Should arguably be an instance of types.FunctionType. + return [ + DataObject( + objtable.as_list().get_code("__builtins__.function"), + objtable.get_index("__builtins__.function"), # is instance + item.code_location, + "__builtins__.function", + len(item.defaults) + 1, # size (not accurate for lambda functions before instantiation) + paramtable.as_list().get_code(item.full_name()) # funccode + ) + ] + +class RSVPModule(RSVPObject): + + "A wrapper for modules." + + def as_raw(self, objtable, paramtable, with_builtins): + item = self.item + return [ + DataObject( + objtable.as_list().get_code(item.full_name()), + None, # modules treated like classes + None, + item.full_name(), + len(item.module_attributes()) + 1 # size + ) + ] + +# Serialisation-related data and functions. + +def get_object(item): + if isinstance(item, Attr): + cls = RSVPAttr + elif isinstance(item, Block): + cls = RSVPBlock + elif isinstance(item, Class): + cls = RSVPClass + elif isinstance(item, Const): + cls = RSVPConst + elif isinstance(item, Function): + cls = RSVPFunction + elif isinstance(item, Module): + cls = RSVPModule + else: + cls = None + + if cls is not None: + return cls(item) + else: + return None + +# Instruction-related classes. + class Instruction: "A generic instruction."