Permalink
Browse files

More simplification of the compiler architecture.

- Move FlowGraph instantiation to compile(), which then returns
  graph.getCode().
- Removed NestedScopesMixin.  It was used everywhere, so we can just
  hard-code it.
  • Loading branch information...
Andy Chu
Andy Chu committed Mar 18, 2018
1 parent 8cf2341 commit 01fc053fb48422b1a0acdf0b3885d2f6b55cf30a
Showing with 36 additions and 52 deletions.
  1. +36 −52 opy/compiler2/pycodegen.py
View
@@ -61,24 +61,30 @@ def compile(as_tree, filename, mode):
syntax.check(as_tree)
if mode == "single":
gen = InteractiveCodeGenerator(as_tree.filename)
graph = pyassem.PyFlowGraph("<interactive>", as_tree.filename)
gen = InteractiveCodeGenerator(graph)
gen.set_lineno(as_tree)
elif mode == "exec":
graph = pyassem.PyFlowGraph("<module>", as_tree.filename)
futures = future.find_futures(as_tree)
gen = ModuleCodeGenerator(as_tree.filename, futures)
gen = ModuleCodeGenerator(futures, graph)
elif mode == "eval":
gen = ExpressionCodeGenerator(as_tree.filename)
graph = pyassem.PyFlowGraph("<expression>", as_tree.filename)
gen = ExpressionCodeGenerator(graph)
else:
raise ValueError("compile() 3rd arg must be 'exec' or "
"'eval' or 'single'")
# This has a side effect of populating the gen.graph data structure?
# The multiple inheritance implements some weird double-dispatch.
walk(as_tree, gen)
# Not sure why I need this, copied from InteractiveCodeGenerator
if mode == "single":
gen.emit('RETURN_VALUE')
return gen.getCode()
return graph.getCode()
class LocalNameFinder(object):
@@ -156,14 +162,17 @@ class CodeGenerator(object):
"""
optimized = 0 # is namespace access optimized?
__initialized = None
class_name = None # provide default for instance variable
NameFinder = LocalNameFinder
FunctionGen = None
ClassGen = None
def __init__(self):
if self.__initialized is None:
self.initClass()
self.__class__.__initialized = 1
self.checkClass()
# Initialize after defined
self.FunctionGen = FunctionCodeGenerator
self.ClassGen = ClassCodeGenerator
self.locals = Stack()
self.setups = Stack()
self.last_lineno = None
@@ -183,20 +192,6 @@ def __init__(self):
elif feature == "print_function":
self.graph.setFlag(CO_FUTURE_PRINT_FUNCTION)
def initClass(self):
"""This method is called once for each class"""
def checkClass(self):
"""Verify that class is constructed correctly"""
try:
assert hasattr(self, 'graph')
assert getattr(self, 'NameFinder')
assert getattr(self, 'FunctionGen')
assert getattr(self, 'ClassGen')
except AssertionError, msg:
intro = "Bad class construction for %s" % self.__class__.__name__
raise AssertionError, intro
def _setupGraphDelegation(self):
self.emit = self.graph.emit
self.newBlock = self.graph.newBlock
@@ -205,7 +200,12 @@ def _setupGraphDelegation(self):
self.setDocstring = self.graph.setDocstring
def getCode(self):
"""Return a code object"""
"""Called by _convert_LOAD_CONST in pyassem in a weird way.
It checks hasattr(arg, 'getCode'). I guess that is the ad-hoc
polymorphism of things that can be serialized to code objects. Consts
can be code objects!
"""
return self.graph.getCode()
def mangle(self, name):
@@ -296,14 +296,6 @@ def set_lineno(self, node, force=False):
return True
return False
# The first few visitor methods handle nodes that generator new
# code objects. They use class attributes to determine what
# specialized code generators to use.
NameFinder = LocalNameFinder
FunctionGen = None
ClassGen = None
def visitModule(self, node):
self.scopes = self.parseSymbols(node)
self.scope = self.scopes[node]
@@ -1234,48 +1226,41 @@ def visitDict(self, node):
self.emit('ROT_THREE')
self.emit('STORE_SUBSCR')
class NestedScopeMixin(object):
"""Defines initClass() for nested scoping (Python 2.2-compatible)"""
def initClass(self):
self.__class__.NameFinder = LocalNameFinder
self.__class__.FunctionGen = FunctionCodeGenerator
self.__class__.ClassGen = ClassCodeGenerator
class ModuleCodeGenerator(NestedScopeMixin, CodeGenerator):
class ModuleCodeGenerator(CodeGenerator):
__super_init = CodeGenerator.__init__
scopes = None
def __init__(self, filename, futures):
self.graph = pyassem.PyFlowGraph("<module>", filename)
def __init__(self, futures, graph):
self.futures = futures
self.graph = graph
self.__super_init()
def get_module(self):
return self
class ExpressionCodeGenerator(NestedScopeMixin, CodeGenerator):
class ExpressionCodeGenerator(CodeGenerator):
__super_init = CodeGenerator.__init__
scopes = None
futures = ()
def __init__(self, filename):
self.graph = pyassem.PyFlowGraph("<expression>", filename)
def __init__(self, graph):
self.graph = graph
self.__super_init()
def get_module(self):
return self
class InteractiveCodeGenerator(NestedScopeMixin, CodeGenerator):
class InteractiveCodeGenerator(CodeGenerator):
__super_init = CodeGenerator.__init__
scopes = None
futures = ()
def __init__(self, filename):
self.graph = pyassem.PyFlowGraph("<interactive>", filename)
def __init__(self, graph):
self.graph = graph
self.__super_init()
def get_module(self):
@@ -1346,8 +1331,7 @@ def unpackSequence(self, tup):
unpackTuple = unpackSequence
class FunctionCodeGenerator(NestedScopeMixin, AbstractFunctionCode,
CodeGenerator):
class FunctionCodeGenerator(AbstractFunctionCode, CodeGenerator):
super_init = CodeGenerator.__init__ # call be other init
scopes = None
@@ -1362,7 +1346,7 @@ def __init__(self, func, scopes, isLambda, class_name, mod):
if self.scope.generator is not None:
self.graph.setFlag(CO_GENERATOR)
class GenExprCodeGenerator(NestedScopeMixin, AbstractFunctionCode,
class GenExprCodeGenerator(AbstractFunctionCode,
CodeGenerator):
super_init = CodeGenerator.__init__ # call be other init
scopes = None
@@ -1404,7 +1388,7 @@ def finish(self):
self.emit('LOAD_LOCALS')
self.emit('RETURN_VALUE')
class ClassCodeGenerator(NestedScopeMixin, AbstractClassCode, CodeGenerator):
class ClassCodeGenerator(AbstractClassCode, CodeGenerator):
super_init = CodeGenerator.__init__
scopes = None

0 comments on commit 01fc053

Please sign in to comment.