[phc-general] Why isn't Tree_transform::pre_statement()implemented
Edsko de Vries
edsko at phpcompiler.org
Tue Aug 1 11:09:36 CEST 2006
> What do you mean by 'generic'? How would I know which are 'generic' methods
> and which aren't? After all, they are all declared. It could be useful if
> those that do not work were not declared.
"Generic" methods correspond to abstract classes; so, "pre_statement" is
a generic method, but "pre_if" is not. In ast.h, class AST_statement is
abstract (it has pure virtual methods, with that strange "= 0" syntax),
but class AST_if is concrete. Or, alternatively, if you prefer to look
at the grammar, a "generic" method is one that corresponds to a
"disjunctive" rule in the grammar such as
statement ::= if | .. | ..
(so, a rule that lists alternatives), and a non-generic method corresponds to a "compound" rule in the grammar, for example
if ::= expr statement* statement*
(one that lists the "contents" of the node). However, I would think it
is intuitively clear anyway: and "if" is a "real" node in some sense,
there really are "if" nodes in the tree; a "statement" is a more
abstract notion; there are never "statements" in the tree (only ifs, or
whiles, or whatever).
To understand why we don't support things like pre_statement in
transforms, consider pre_node. Suppose we would support transforming
nodes generically in a pre_node method. What would it return? The only
thing it could return would be another AST_node*. But that would mean
that the transform could replace any node by another other node,
resulting in non-sensical trees. (For example, it could replace a
classname by a statement.) The tree_transformation API is carefully
defined so that all signatures guarantee that the tree remains
meaningful (or, in C++, typable).
The reason that things like pre_statement etc. are declared in the AST
classes (in ast.h) is rather technical and has to do with the C++ type
checker. We want to keep the types on the user-level as easy as
possible. For that reason, we introduced wildcards and the strange
Wildcard class with all its parent classes. For the same reason, the
abstract classes do have pre_ and post_ transform methods declared.
They are pure virtual, and they serve only to make covariant typing
work. That means for example that calling "transform" on an AST_if, say,
AST_statement_list* transform(Tree_transform* transform)
AST_node* transform(Tree_transform* transform)
which is less helpful and requires more dynamic casts in the user code.
(Hmmmm. Interesting. I was going to say that you won't find a
"pre_statement" in Tree_transform.h, but as a matter of fact, you will.
That is a (harmless but potentially confusing) bug and we will need to
look at that.)
> >So, it is
> > not possible to define a transformation that would replace all
> > statements by something else. (It is not clear how that would be
> > useful, anyway.)
> Well, I can tell you why it would be useful to me. I actually need to
> insert a statement whenever I find a certain method_invocation, that is,
> when I find a particular call, I need to insert some other statement. I
> cannot modify the called method since it might be in an include file. The
> pre and post method_invocation give me a one to one replacement, I get one,
> I can replace it by another, but can't replace them by two. So, I went up
> one level in the tree and pre and post statement (supposedly) take one
> statement and allows me to return a statement list, so there I can pick my
> method invocation and return my preparatory statement and then let the
> original method go through. Now, what I am doing is taking a
> statement_list, looping through the statements, matching them against the
> method_invocation I'm looking for and returning a longer list, with added
> statements. So, there is some usefulness to it.
Actually, the best way to solve that problem is to go up one level to
AST_eval_expr instead. You can replace a AST_method_invocation only by a
single other expression, but every AST_method_invocation is a statement
through an AST_eval_expr node, and an AST_eval_expr node can be replaced
by a list of statements. (It's analogous to the problem discussed in
tutorial 6, really.)
> Nevertheless, I do find a problem which I'm after right now and it is that
> the tree-traversal algorithm seems to keep traveling over the original
> tree, not the modified one. Not sure on this one, I'm looking into it, so
> far I am looking into some strange behavior, but I'm not clear what is it,
> so don't trouble yourself with it.
If that is true, something is seriously amiss. If you can find a small
transform that shows that behaviour, please send it to us.
More information about the phc-general