micropython

Changeset

562:205ff83aa4f6
2012-06-30 Paul Boddie raw files shortlog changelog graph Introduced missing support for module code invocation upon first import.
micropython/__init__.py (file) micropython/ast.py (file) micropython/inspect.py (file) micropython/raw.py (file) micropython/rsvp.py (file) tests/class_init_code.py (file) tests/initialised/__init__.py (file) tests/module_init.py (file)
     1.1 --- a/micropython/__init__.py	Sat Jun 30 00:15:09 2012 +0200
     1.2 +++ b/micropython/__init__.py	Sat Jun 30 17:06:37 2012 +0200
     1.3 @@ -254,8 +254,9 @@
     1.4              # Get the raw version for the architecture.
     1.5  
     1.6              if arch_item is not None:
     1.7 +                arch_item.finalise_location(with_builtins)
     1.8                  self.raw_code += arch_item.as_raw(objtable, paramtable, with_builtins)
     1.9 -                arch_item.finalise_location(with_builtins)
    1.10 +                arch_item.finalise_body_location(with_builtins)
    1.11              else:
    1.12                  self.raw_code.append(item)
    1.13  
    1.14 @@ -266,8 +267,6 @@
    1.15              if not with_builtins and module.name in ("__builtins__", "native"):
    1.16                  continue
    1.17  
    1.18 -            module.code_location = module.blocks[0].location
    1.19 -
    1.20          self.code_location = self.importer.modules["__main__"].code_location
    1.21          return self.raw_code
    1.22  
    1.23 @@ -415,6 +414,10 @@
    1.24          self.modules_ordered = []
    1.25          self.loading = set()
    1.26  
    1.27 +        # Importers responsible for initially importing modules.
    1.28 +
    1.29 +        self.importers = {}
    1.30 +
    1.31          # Constant records.
    1.32  
    1.33          self.constant_values = {}
    1.34 @@ -948,12 +951,16 @@
    1.35          else:
    1.36              return None
    1.37  
    1.38 -    def load(self, name, return_leaf=0):
    1.39 +    def load(self, name, return_leaf=0, importer=None):
    1.40  
    1.41          """
    1.42          Load the module or package with the given 'name'. Return an object
    1.43          referencing the loaded module or package, or None if no such module or
    1.44          package exists.
    1.45 +
    1.46 +        If the given 'importer' is specified, it will be associated with the
    1.47 +        imported module if it is responsible for importing the module for the
    1.48 +        first time.
    1.49          """
    1.50  
    1.51          if return_leaf:
    1.52 @@ -961,7 +968,7 @@
    1.53          else:
    1.54              name_for_return = name.split(".")[0]
    1.55  
    1.56 -        if self.modules.has_key(name) and self.modules[name].loaded:
    1.57 +        if self.modules.has_key(name):
    1.58              #print >>sys.stderr, "Cached (%s)" % name
    1.59              return self.modules[name_for_return]
    1.60  
    1.61 @@ -982,7 +989,7 @@
    1.62          # Either acquire a reference to an already-imported module, or load the
    1.63          # module from a file.
    1.64  
    1.65 -        top = module = self.load_from_file(filename, path[0])
    1.66 +        top = module = self.load_from_file(filename, path[0], importer)
    1.67  
    1.68          # For hierarchical names, traverse each path component...
    1.69  
    1.70 @@ -1010,7 +1017,7 @@
    1.71  
    1.72                  # Either reference an imported module or load one from a file.
    1.73  
    1.74 -                submodule = self.load_from_file(filename, module_name)
    1.75 +                submodule = self.load_from_file(filename, module_name, importer)
    1.76  
    1.77                  if d:
    1.78                      self.add_submodules(d, module)
    1.79 @@ -1032,10 +1039,14 @@
    1.80          else:
    1.81              return top
    1.82  
    1.83 -    def load_from_file(self, name, module_name=None):
    1.84 +    def load_from_file(self, name, module_name=None, importer=None):
    1.85  
    1.86          """
    1.87          Load the module with the given 'name' (which may be a full module path).
    1.88 +
    1.89 +        If the given 'importer' is specified, it will be associated with the
    1.90 +        imported module if it is responsible for importing the module for the
    1.91 +        first time.
    1.92          """
    1.93  
    1.94          if module_name is None:
    1.95 @@ -1052,6 +1063,13 @@
    1.96              self.loading.remove(module)
    1.97              module.loaded = 1
    1.98  
    1.99 +            # Record each module as imported by any importer.
   1.100 +
   1.101 +            if importer:
   1.102 +                if not self.importers.has_key(importer):
   1.103 +                    self.importers[importer] = []
   1.104 +                self.importers[importer].append(module)
   1.105 +
   1.106          # Record the module.
   1.107  
   1.108          self.use_object(module.full_name())
     2.1 --- a/micropython/ast.py	Sat Jun 30 00:15:09 2012 +0200
     2.2 +++ b/micropython/ast.py	Sat Jun 30 17:06:37 2012 +0200
     2.3 @@ -106,7 +106,12 @@
     2.4          if self.module.name == "__main__":
     2.5              self.set_block(handler_block)
     2.6              self.new_op(PopHandler(1))
     2.7 -            self.new_op(Return())
     2.8 +        else:
     2.9 +            self.new_op(DropFrame())
    2.10 +
    2.11 +        # All modules return if invoked.
    2.12 +
    2.13 +        self.new_op(Return())
    2.14  
    2.15          self.drop_exception_unit()
    2.16          self.unit.temp_usage = self.max_temp_position + 1
    2.17 @@ -155,7 +160,7 @@
    2.18  
    2.19          self.new_op(LoadFunction(init_method))
    2.20          self.new_op(LoadCallable())
    2.21 -        self.new_op(JumpInFrame())
    2.22 +        self.new_op(JumpWithFrame())
    2.23  
    2.24          # Store the object as the result.
    2.25  
    2.26 @@ -614,7 +619,20 @@
    2.27  
    2.28      def visitDecorators(self, node): raise TranslationNotImplementedError("Decorators")
    2.29  
    2.30 -    def visitFrom(self, node): pass
    2.31 +    def visitFrom(self, node):
    2.32 +
    2.33 +        """
    2.34 +        Although imported code already resides in any generated image, the
    2.35 +        code must be invoked.
    2.36 +        """
    2.37 +
    2.38 +        modules = self.importer.importers.get(node)
    2.39 +        if modules:
    2.40 +            for module in modules:
    2.41 +                self.new_op(MakeFrame(0))
    2.42 +                self.new_op(LoadConst(module))
    2.43 +                self.new_op(LoadCallable())
    2.44 +                self.new_op(JumpWithFrame())
    2.45  
    2.46      def visitFunction(self, node):
    2.47          if not used_by_unit(node):
    2.48 @@ -641,7 +659,7 @@
    2.49  
    2.50      def visitGlobal(self, node): pass
    2.51  
    2.52 -    def visitImport(self, node): pass
    2.53 +    visitImport = visitFrom
    2.54  
    2.55      def visitKeyword(self, node): pass
    2.56  
     3.1 --- a/micropython/inspect.py	Sat Jun 30 00:15:09 2012 +0200
     3.2 +++ b/micropython/inspect.py	Sat Jun 30 17:06:37 2012 +0200
     3.3 @@ -991,7 +991,7 @@
     3.4          self.resume_broken_branches()
     3.5  
     3.6      def visitFrom(self, node):
     3.7 -        module = self.importer.load(node.modname, 1)
     3.8 +        module = self.importer.load(node.modname, 1, importer=node)
     3.9          if module and not module.loaded:
    3.10              print >>sys.stderr, "Warning: a circular import of %s is being attempted in %s" % (node.modname, self.full_name())
    3.11  
    3.12 @@ -1005,7 +1005,7 @@
    3.13                      # Missing names may refer to submodules.
    3.14  
    3.15                      if not module.has_key(name):
    3.16 -                        submodule = self.importer.load(node.modname + "." + name, 1)
    3.17 +                        submodule = self.importer.load(node.modname + "." + name, 1, importer=node)
    3.18                          if submodule:
    3.19                              if not submodule.loaded:
    3.20                                  print >>sys.stderr, "Warning: a circular import of %s.%s is being attempted in %s" % (
    3.21 @@ -1020,7 +1020,7 @@
    3.22                          self.store(alias or name, attr)
    3.23                          self.use_specific_attribute(module.full_name(), name)
    3.24                          if isinstance(attr.get_value(), Module) and not attr.get_value().loaded:
    3.25 -                            self.importer.load(attr.get_value().name)
    3.26 +                            self.importer.load(attr.get_value().name, importer=node)
    3.27                          continue
    3.28  
    3.29                  # Support the import of names from missing modules.
    3.30 @@ -1034,7 +1034,7 @@
    3.31                          self.store(n, attr)
    3.32                          self.use_specific_attribute(module.full_name(), n)
    3.33                          if isinstance(attr.get_value(), Module) and not attr.get_value().loaded:
    3.34 -                            self.importer.load(attr.get_value().name)
    3.35 +                            self.importer.load(attr.get_value().name, importer=node)
    3.36  
    3.37      def visitFunction(self, node):
    3.38          return self._visitFunction(node, node.name)
    3.39 @@ -1106,10 +1106,10 @@
    3.40      def visitImport(self, node):
    3.41          for name, alias in node.names:
    3.42              if alias is not None:
    3.43 -                module = self.importer.load(name, 1) or UnresolvedName(None, name, self)
    3.44 +                module = self.importer.load(name, 1, importer=node) or UnresolvedName(None, name, self)
    3.45                  self.store(alias, module)
    3.46              else:
    3.47 -                module = self.importer.load(name) or UnresolvedName(None, name.split(".")[0], self)
    3.48 +                module = self.importer.load(name, importer=node) or UnresolvedName(None, name.split(".")[0], self)
    3.49                  self.store(name.split(".")[0], module)
    3.50  
    3.51      visitInvert = _visitUnary
     4.1 --- a/micropython/raw.py	Sat Jun 30 00:15:09 2012 +0200
     4.2 +++ b/micropython/raw.py	Sat Jun 30 17:06:37 2012 +0200
     4.3 @@ -3,7 +3,7 @@
     4.4  """
     4.5  Classes used to help with the generation of raw image data.
     4.6  
     4.7 -Copyright (C) 2009, 2010, 2011 Paul Boddie <paul@boddie.org.uk>
     4.8 +Copyright (C) 2009, 2010, 2011, 2012 Paul Boddie <paul@boddie.org.uk>
     4.9  
    4.10  This program is free software; you can redistribute it and/or modify it under
    4.11  the terms of the GNU General Public License as published by the Free Software
    4.12 @@ -33,6 +33,9 @@
    4.13      def finalise_location(self, with_builtins):
    4.14          pass
    4.15  
    4.16 +    def finalise_body_location(self, with_builtins):
    4.17 +        pass
    4.18 +
    4.19      def is_generated(self, with_builtins):
    4.20          return with_builtins or self.item.module.name not in ("__builtins__", "native") or self.item.astnode.doc is not None
    4.21  
     5.1 --- a/micropython/rsvp.py	Sat Jun 30 00:15:09 2012 +0200
     5.2 +++ b/micropython/rsvp.py	Sat Jun 30 17:06:37 2012 +0200
     5.3 @@ -3,7 +3,7 @@
     5.4  """
     5.5  RSVP instruction and serialisation classes.
     5.6  
     5.7 -Copyright (C) 2007, 2008, 2009, 2010, 2011 Paul Boddie <paul@boddie.org.uk>
     5.8 +Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Paul Boddie <paul@boddie.org.uk>
     5.9  
    5.10  This program is free software; you can redistribute it and/or modify it under
    5.11  the terms of the GNU General Public License as published by the Free Software
    5.12 @@ -87,7 +87,7 @@
    5.13  
    5.14          return RSVPObject.set_location(self, location + 1, objtable, with_builtins)
    5.15  
    5.16 -    def finalise_location(self, with_builtins):
    5.17 +    def finalise_body_location(self, with_builtins):
    5.18          self._finalise_location(with_builtins)
    5.19  
    5.20      def as_raw(self, objtable, paramtable, with_builtins):
    5.21 @@ -235,7 +235,7 @@
    5.22  
    5.23          return location
    5.24  
    5.25 -    def finalise_location(self, with_builtins):
    5.26 +    def finalise_body_location(self, with_builtins):
    5.27          self._finalise_location(with_builtins)
    5.28  
    5.29      def as_raw(self, objtable, paramtable, with_builtins):
    5.30 @@ -256,13 +256,18 @@
    5.31  
    5.32      "A wrapper for modules."
    5.33  
    5.34 +    def finalise_location(self, with_builtins):
    5.35 +        item = self.item
    5.36 +        if item.blocks:
    5.37 +            item.code_location = item.blocks[0].location
    5.38 +
    5.39      def as_raw(self, objtable, paramtable, with_builtins):
    5.40          item = self.item
    5.41          return [
    5.42              DataObject(
    5.43                  objtable.as_list().get_code(item.full_name()),
    5.44                  None, # modules treated like classes
    5.45 -                None,
    5.46 +                item.code_location,
    5.47                  item.full_name(),
    5.48                  len(item.module_attributes()) + 1 # size
    5.49                  )
    5.50 @@ -409,7 +414,7 @@
    5.51  
    5.52  class TargetInstruction(Instruction):
    5.53  
    5.54 -    "An instruction loading the address of an invocation target."
    5.55 +    "An instruction loading the address of a direct invocation target."
    5.56  
    5.57      def format_operand(self):
    5.58          return Instruction.format_operand(self) + ["name=%r" % name(self.attr)]
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/tests/class_init_code.py	Sat Jun 30 17:06:37 2012 +0200
     6.3 @@ -0,0 +1,8 @@
     6.4 +#!/usr/bin/env python
     6.5 +
     6.6 +class C:
     6.7 +    x = 1 + 2
     6.8 +
     6.9 +result_3 = C.x
    6.10 +
    6.11 +# vim: tabstop=4 expandtab shiftwidth=4
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/tests/initialised/__init__.py	Sat Jun 30 17:06:37 2012 +0200
     7.3 @@ -0,0 +1,5 @@
     7.4 +#!/usr/bin/env python
     7.5 +
     7.6 +x = 100 + 20 + 3
     7.7 +
     7.8 +# vim: tabstop=4 expandtab shiftwidth=4
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/tests/module_init.py	Sat Jun 30 17:06:37 2012 +0200
     8.3 @@ -0,0 +1,7 @@
     8.4 +#!/usr/bin/env python
     8.5 +
     8.6 +import initialised
     8.7 +
     8.8 +result_123 = initialised.x
     8.9 +
    8.10 +# vim: tabstop=4 expandtab shiftwidth=4