]> granicus.if.org Git - python/commitdiff
API change:
authorJeremy Hylton <jeremy@alum.mit.edu>
Mon, 17 Sep 2001 21:02:51 +0000 (21:02 +0000)
committerJeremy Hylton <jeremy@alum.mit.edu>
Mon, 17 Sep 2001 21:02:51 +0000 (21:02 +0000)
compile() becomes replacement for builtin compile()
compileFile() generates a .pyc from a .py
both are exported in __init__

compiler.parse() gets optional second argument to specify compilation
mode, e.g. single, eval, exec

Add AbstractCompileMode as parent class and Module, Expression, and
Interactive as concrete subclasses.  Each corresponds to a compilation
mode.

THe AbstractCompileMode instances in turn delegate to CodeGeneration
subclasses specialized for their particular functions --
ModuleCodeGenerator, ExpressionCodeGeneration,
InteractiveCodeGenerator.

Lib/compiler/__init__.py
Lib/compiler/pycodegen.py
Lib/compiler/transformer.py
Tools/compiler/compiler/__init__.py
Tools/compiler/compiler/pycodegen.py
Tools/compiler/compiler/transformer.py

index 13855f948f50f6c9581296bb7630cadf08770db1..97d9c76dc0cf3be39dc9c6d5052df13f6b8dd8fb 100644 (file)
@@ -3,7 +3,7 @@
 There are several functions defined at the top level that are imported
 from modules contained in the package.
 
-parse(buf) -> AST
+parse(buf, mode="exec") -> AST
     Converts a string containing Python source code to an abstract
     syntax tree (AST).  The AST is defined in compiler.ast.
 
@@ -14,11 +14,14 @@ walk(ast, visitor, verbose=None)
     Does a pre-order walk over the ast using the visitor instance.
     See compiler.visitor for details.
 
-compile(filename)
+compile(source, filename, mode, flags=None, dont_inherit=None)
+    Returns a code object.  A replacement for the builtin compile() function. 
+
+compileFile(filename)
     Generates a .pyc file by compilining filename.
 """
 
 from transformer import parse, parseFile
 from visitor import walk
-from pycodegen import compile
+from pycodegen import compile, compileFile
 
index 7bc17958cf542edc323e97a1f052963444729a82..3cdf108badd9f9726bcfc657948f438cf113b5f0 100644 (file)
@@ -41,7 +41,7 @@ class BlockStack(misc.Stack):
         self.__super_init(self)
         self.loop = None
 
-def compile(filename, display=0):
+def compileFile(filename, display=0):
     f = open(filename)
     buf = f.read()
     f.close()
@@ -55,16 +55,68 @@ def compile(filename, display=0):
         mod.dump(f)
         f.close()
 
-class Module:
+def compile(source, filename, mode, flags=None, dont_inherit=None):
+    """Replacement for builtin compile() function"""
+    if flags is not None or dont_inherit is not None:
+        raise RuntimeError, "not implemented yet"
+    
+    if mode == "single":
+        gen = Interactive(source, filename)
+    elif mode == "exec":
+        gen = Module(source, filename)
+    elif mode == "eval":
+        gen = Expression(source, filename)
+    else:
+        raise ValueError("compile() 3rd arg must be 'exec' or "
+                         "'eval' or 'single'")
+    gen.compile()
+    return gen.code
+
+class AbstractCompileMode:
+
+    mode = None # defined by subclass
+
     def __init__(self, source, filename):
-        self.filename = os.path.abspath(filename)
         self.source = source
+        self.filename = filename
         self.code = None
 
-    def compile(self, display=0):
-        tree = parse(self.source)
+    def _get_tree(self):
+        tree = parse(self.source, self.mode)
         misc.set_filename(self.filename, tree)
         syntax.check(tree)
+        return tree
+
+    def compile(self):
+        pass # implemented by subclass
+
+    def getCode(self):
+        return self.code
+
+class Expression(AbstractCompileMode):
+
+    mode = "eval"
+
+    def compile(self):
+        tree = self._get_tree()
+        gen = ExpressionCodeGenerator(tree)
+        self.code = gen.getCode()
+
+class Interactive(AbstractCompileMode):
+
+    mode = "single"
+
+    def compile(self):
+        tree = self._get_tree()
+        gen = InteractiveCodeGenerator(tree)
+        self.code = gen.getCode()
+
+class Module(AbstractCompileMode):
+
+    mode = "exec"
+
+    def compile(self, display=0):
+        tree = self._get_tree()
         gen = ModuleCodeGenerator(tree)
         if display:
             import pprint
@@ -1097,6 +1149,44 @@ class ModuleCodeGenerator(NestedScopeMixin, CodeGenerator):
     def get_module(self):
         return self
 
+class ExpressionCodeGenerator(NestedScopeMixin, CodeGenerator):
+    __super_init = CodeGenerator.__init__
+
+    scopes = None
+    futures = ()
+    
+    def __init__(self, tree):
+        self.graph = pyassem.PyFlowGraph("<expression>", tree.filename)
+        self.__super_init()
+        self.set_lineno(tree)
+        walk(tree, self)
+        self.emit('RETURN_VALUE')
+
+    def get_module(self):
+        return self
+
+class InteractiveCodeGenerator(NestedScopeMixin, CodeGenerator):
+
+    __super_init = CodeGenerator.__init__
+
+    scopes = None
+    futures = ()
+    
+    def __init__(self, tree):
+        self.graph = pyassem.PyFlowGraph("<interactive>", tree.filename)
+        self.__super_init()
+        self.set_lineno(tree)
+        walk(tree, self)
+        self.emit('RETURN_VALUE')
+
+    def get_module(self):
+        return self
+    def visitDiscard(self, node):
+        # XXX Discard means it's an expression.  Perhaps this is a bad
+        # name.
+        self.visit(node.expr)
+        self.emit('PRINT_EXPR')
+
 class AbstractFunctionCode:
     optimized = 1
     lambdaCount = 0
index 3607af11cb5535aa17a4870e2618e26b06fd2c3a..c2a3b9648fbc81a78a1dd1137693f15f6d7094d8 100644 (file)
@@ -42,8 +42,14 @@ def parseFile(path):
     f.close()
     return parse(src)
 
-def parse(buf):
-    return Transformer().parsesuite(buf)
+def parse(buf, mode="exec"):
+    if mode == "exec" or mode == "single":
+        return Transformer().parsesuite(buf)
+    elif mode == "eval":
+        return Transformer().parseexpr(buf)
+    else:
+        raise ValueError("compile() arg 3 must be"
+                         " 'exec' or 'eval' or 'single'")
 
 def asList(nodes):
     l = []
index 13855f948f50f6c9581296bb7630cadf08770db1..97d9c76dc0cf3be39dc9c6d5052df13f6b8dd8fb 100644 (file)
@@ -3,7 +3,7 @@
 There are several functions defined at the top level that are imported
 from modules contained in the package.
 
-parse(buf) -> AST
+parse(buf, mode="exec") -> AST
     Converts a string containing Python source code to an abstract
     syntax tree (AST).  The AST is defined in compiler.ast.
 
@@ -14,11 +14,14 @@ walk(ast, visitor, verbose=None)
     Does a pre-order walk over the ast using the visitor instance.
     See compiler.visitor for details.
 
-compile(filename)
+compile(source, filename, mode, flags=None, dont_inherit=None)
+    Returns a code object.  A replacement for the builtin compile() function. 
+
+compileFile(filename)
     Generates a .pyc file by compilining filename.
 """
 
 from transformer import parse, parseFile
 from visitor import walk
-from pycodegen import compile
+from pycodegen import compile, compileFile
 
index 7bc17958cf542edc323e97a1f052963444729a82..3cdf108badd9f9726bcfc657948f438cf113b5f0 100644 (file)
@@ -41,7 +41,7 @@ class BlockStack(misc.Stack):
         self.__super_init(self)
         self.loop = None
 
-def compile(filename, display=0):
+def compileFile(filename, display=0):
     f = open(filename)
     buf = f.read()
     f.close()
@@ -55,16 +55,68 @@ def compile(filename, display=0):
         mod.dump(f)
         f.close()
 
-class Module:
+def compile(source, filename, mode, flags=None, dont_inherit=None):
+    """Replacement for builtin compile() function"""
+    if flags is not None or dont_inherit is not None:
+        raise RuntimeError, "not implemented yet"
+    
+    if mode == "single":
+        gen = Interactive(source, filename)
+    elif mode == "exec":
+        gen = Module(source, filename)
+    elif mode == "eval":
+        gen = Expression(source, filename)
+    else:
+        raise ValueError("compile() 3rd arg must be 'exec' or "
+                         "'eval' or 'single'")
+    gen.compile()
+    return gen.code
+
+class AbstractCompileMode:
+
+    mode = None # defined by subclass
+
     def __init__(self, source, filename):
-        self.filename = os.path.abspath(filename)
         self.source = source
+        self.filename = filename
         self.code = None
 
-    def compile(self, display=0):
-        tree = parse(self.source)
+    def _get_tree(self):
+        tree = parse(self.source, self.mode)
         misc.set_filename(self.filename, tree)
         syntax.check(tree)
+        return tree
+
+    def compile(self):
+        pass # implemented by subclass
+
+    def getCode(self):
+        return self.code
+
+class Expression(AbstractCompileMode):
+
+    mode = "eval"
+
+    def compile(self):
+        tree = self._get_tree()
+        gen = ExpressionCodeGenerator(tree)
+        self.code = gen.getCode()
+
+class Interactive(AbstractCompileMode):
+
+    mode = "single"
+
+    def compile(self):
+        tree = self._get_tree()
+        gen = InteractiveCodeGenerator(tree)
+        self.code = gen.getCode()
+
+class Module(AbstractCompileMode):
+
+    mode = "exec"
+
+    def compile(self, display=0):
+        tree = self._get_tree()
         gen = ModuleCodeGenerator(tree)
         if display:
             import pprint
@@ -1097,6 +1149,44 @@ class ModuleCodeGenerator(NestedScopeMixin, CodeGenerator):
     def get_module(self):
         return self
 
+class ExpressionCodeGenerator(NestedScopeMixin, CodeGenerator):
+    __super_init = CodeGenerator.__init__
+
+    scopes = None
+    futures = ()
+    
+    def __init__(self, tree):
+        self.graph = pyassem.PyFlowGraph("<expression>", tree.filename)
+        self.__super_init()
+        self.set_lineno(tree)
+        walk(tree, self)
+        self.emit('RETURN_VALUE')
+
+    def get_module(self):
+        return self
+
+class InteractiveCodeGenerator(NestedScopeMixin, CodeGenerator):
+
+    __super_init = CodeGenerator.__init__
+
+    scopes = None
+    futures = ()
+    
+    def __init__(self, tree):
+        self.graph = pyassem.PyFlowGraph("<interactive>", tree.filename)
+        self.__super_init()
+        self.set_lineno(tree)
+        walk(tree, self)
+        self.emit('RETURN_VALUE')
+
+    def get_module(self):
+        return self
+    def visitDiscard(self, node):
+        # XXX Discard means it's an expression.  Perhaps this is a bad
+        # name.
+        self.visit(node.expr)
+        self.emit('PRINT_EXPR')
+
 class AbstractFunctionCode:
     optimized = 1
     lambdaCount = 0
index 3607af11cb5535aa17a4870e2618e26b06fd2c3a..c2a3b9648fbc81a78a1dd1137693f15f6d7094d8 100644 (file)
@@ -42,8 +42,14 @@ def parseFile(path):
     f.close()
     return parse(src)
 
-def parse(buf):
-    return Transformer().parsesuite(buf)
+def parse(buf, mode="exec"):
+    if mode == "exec" or mode == "single":
+        return Transformer().parsesuite(buf)
+    elif mode == "eval":
+        return Transformer().parseexpr(buf)
+    else:
+        raise ValueError("compile() arg 3 must be"
+                         " 'exec' or 'eval' or 'single'")
 
 def asList(nodes):
     l = []