From 9dca36432e4526da9c5885e86782e7dfa5432c42 Mon Sep 17 00:00:00 2001 From: Jeremy Hylton Date: Mon, 17 Sep 2001 21:02:51 +0000 Subject: 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. --- Lib/compiler/__init__.py | 9 ++- Lib/compiler/pycodegen.py | 100 +++++++++++++++++++++++++++++++-- Lib/compiler/transformer.py | 10 +++- Tools/compiler/compiler/__init__.py | 9 ++- Tools/compiler/compiler/pycodegen.py | 100 +++++++++++++++++++++++++++++++-- Tools/compiler/compiler/transformer.py | 10 +++- 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("", 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("", 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("", 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("", 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 = [] -- cgit v0.12