summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Hylton <jeremy@alum.mit.edu>2001-09-17 21:02:51 (GMT)
committerJeremy Hylton <jeremy@alum.mit.edu>2001-09-17 21:02:51 (GMT)
commit9dca36432e4526da9c5885e86782e7dfa5432c42 (patch)
treea30bc1744590e05b731eb077d1d261b544270ccf
parentc8ed18a4e3756f0cccbcddd10323ef536ad003ec (diff)
downloadcpython-9dca36432e4526da9c5885e86782e7dfa5432c42.zip
cpython-9dca36432e4526da9c5885e86782e7dfa5432c42.tar.gz
cpython-9dca36432e4526da9c5885e86782e7dfa5432c42.tar.bz2
API change:
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.
-rw-r--r--Lib/compiler/__init__.py9
-rw-r--r--Lib/compiler/pycodegen.py100
-rw-r--r--Lib/compiler/transformer.py10
-rw-r--r--Tools/compiler/compiler/__init__.py9
-rw-r--r--Tools/compiler/compiler/pycodegen.py100
-rw-r--r--Tools/compiler/compiler/transformer.py10
6 files changed, 218 insertions, 20 deletions
diff --git a/Lib/compiler/__init__.py b/Lib/compiler/__init__.py
index 13855f9..97d9c76 100644
--- a/Lib/compiler/__init__.py
+++ b/Lib/compiler/__init__.py
@@ -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
diff --git a/Lib/compiler/pycodegen.py b/Lib/compiler/pycodegen.py
index 7bc1795..3cdf108 100644
--- a/Lib/compiler/pycodegen.py
+++ b/Lib/compiler/pycodegen.py
@@ -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
diff --git a/Lib/compiler/transformer.py b/Lib/compiler/transformer.py
index 3607af1..c2a3b96 100644
--- a/Lib/compiler/transformer.py
+++ b/Lib/compiler/transformer.py
@@ -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 = []
diff --git a/Tools/compiler/compiler/__init__.py b/Tools/compiler/compiler/__init__.py
index 13855f9..97d9c76 100644
--- a/Tools/compiler/compiler/__init__.py
+++ b/Tools/compiler/compiler/__init__.py
@@ -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
diff --git a/Tools/compiler/compiler/pycodegen.py b/Tools/compiler/compiler/pycodegen.py
index 7bc1795..3cdf108 100644
--- a/Tools/compiler/compiler/pycodegen.py
+++ b/Tools/compiler/compiler/pycodegen.py
@@ -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
diff --git a/Tools/compiler/compiler/transformer.py b/Tools/compiler/compiler/transformer.py
index 3607af1..c2a3b96 100644
--- a/Tools/compiler/compiler/transformer.py
+++ b/Tools/compiler/compiler/transformer.py
@@ -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 = []