[Cython] Some small phase refactorings
Dag Sverre Seljebotn
dagss at student.matnat.uio.no
Fri May 2 13:22:35 CEST 2008
This isn't much, but it is a start.
Phase refactoring seems like it will become a bit difficult and I think
it is better left for dev1 if possible; I need to work with someone who
know the source more intimately. It appears that some parts must almost
be "rebuilt" or at least control flow heavily altered between
statements, it is all about keeping the changes to a minimum... the good
news is that a certain amount of spaghetti will disappear through the
process (you know -- the things that break in a different part of the
code when you change another part in the code; while not necesarrily the
root of all evil, it does make it harder to get to know a codebase).
But I have patch for some trivial stuff at the "top" of the call chain
that at least is a good point for discussion (if somebody else cares how
this is done). It can be found here:
http://wiki.cython.org/DagSverreSeljebotn/patches?action=AttachFile&do=get&target=phaserefactoring1.diff
and succeeds the testcases; I consider it ready for inclusion.
Basically, what it does is turn this (psuedo-code describing overall
structure, you won't find this anywhere):
for each function in module:
construct_function_scope
analyse_control_flow
analyse_declarations
analyse_expressions
generate_code
into
for each function in module: construct_function_scope
for each function in module: analyse_control_flow
for each function in module: analyse_declarations
for each function in module: analyse_expressions
for each function in module: generate_code
However, each of these are in turn run as recursive calls just like
before. In particular, analyse_expressions is still one phase and not
easily seperateable (it should be split in three I think: analyse types,
coercion, allocate temps).
Also, these are all "function-level"; on module-level things happen like
before, i.e. analyse_declarations in the module level is run at another
time (and for the nearest future it should remain this way; just
consider module-level and function-level analysis different phases).
The new code is implemented using visitor transforms. One could argue
about this, but I do think it leads to pretty neat code. The third
for-loop in the psuedo-code above is this implemented like this:
Cython/Compiler/Transforms/Analysis.py [is this source structure ok?]:
class AnalyseFunctionBodyDeclarations(VisitorTransform):
def pre_FuncDefNode(self, node):
node.body.analyse_declarations(node.scope)
return False # do not recurse beyond first function level
Cython/Compiler/ModuleNode.py:
class ModuleNode:
def generate_c_code(self, env, options, result):
...
import Cython.Compiler.Transforms.Analysis as Analysis
...
Analysis.AnalyseFunctionBodyDeclarations()(self, env=env)
...
self.body.generate_function_definitions(env, code,
options.transforms)
...
The only non-trivial part is that the function scope is constructed by a
tree transform that adds the "scope" and "scopenode" attributes in the
following way: The FuncDefNodes and ModuleNodes gets their "scope"
attribute set to the object that was previously passed around everywhere
as the "env" parameter (this is then read back in order to pass the
"env" correctly). All nodes also have their "scopenode" attribute set to
the node that caused creation of the enclosing scope. I.e., rather than
relying on a passed in env passed recursively from the function/module,
it is possible for nodes to look up self.scopenode.scope. This will aid
seperation of phases.
--
Dag Sverre
More information about the Cython-dev
mailing list