OK, this seems like a stupid question, and maybe it is. What should be
considered a "child" of an expression in the AST? Imagine a node that
holds both a rewritten tree (that will be used for code-gen purposes) as
well as the original AST as the user wrote it. (This is the
PropertyAccessOperator node as suggested by John McCall.) Clearly, the
rewritten node is a child. But is the original expression? What does is
really mean to be a child?
I don’t know about the specific case you’re referring to, but in general, a child of an expression is some other expression of which the parent is composed. I think an example explains it best: “x + y” is an expression, the binary operator “+”. It contains two child expressions, “x” and “y”.
I wouldn’t expect the rewritten node and the original node to have any parent / child relationship. That relationship should be reserved for nodes that are part of the same tree structure. IE, what a consumer (say codegen) would walk to get a “complete” view of the program, whether that view is semantic or syntax oriented in nature.
Look at the relationship of a template specialization’s AST nodes and the template definition’s AST nodes – neither is the child of the other, but we create a separate connection between them so we can navigate from a definition to all specializations and from a particular specialization back to the definition.
Thanks. I wasn't suggesting a parent/child relationship between the
original expression and the rewritten one. I was asking whether there
is/should be a sibling relationship between them (the parent being
PropertyAccessOperator which holds them both). They are both AST
representations of the same thing. One is more like what the user wrote,
and other other is more like what will be generated. I imagine that,
with the exception of error reporting, most AST consumers would be more
interested in the transformed AST. But some may be interested in the
other, or both.
The answer to my question depends on whether the AST mainly represents
the surface syntax of the program, or the semantics of it.
The specifics, if it helps, is that property access like:
obj.property += value;
will be evaluated as:
obj.set_property( obj.get_property() + value );
With my change, the AST for *both* will be stored under a new node type.
So, what should child_begin and child_end iterate over for this node
type? (My hunch is that only the rewritten node is really a child.)
Thanks in advance,
Yes, I think only the nodes that will actually be executed should be
"children" in that sense; thus the rewritten tree and any tree whose
values will be bound to OpaqueValueExprs, but not the OVEs
Ah, interesting. Thanks, John. Let's take the example AST you posted in
a previous thread:
# The original operand, for source fidelity
(MemberExpr int lvalue property
(DeclRefExpr "obj" Obj lvalue))
# The opaque value expression
(OpaqueValueExpr 0xabcdef Obj lvalue)
# The expression whose result the OpaqueValueExpr will be bound to
(DeclRefExpr "obj" Obj lvalue)
# The expression to evaluate, expressed in terms of the OVE
(MemberExpr void(int) .setBase
(OpaqueValueExpr 0xabcdef Obj lvalue))
(MemberExpr PropTy() .getBase
(OpaqueValueExpr 0xabcdef Obj lvalue)))))
I was thinking that only the last subexpr of PAO (the "expression to
evaluate") should be a logical "child" of PAO. But you seem to be saying
that the third subexpr above (the "expression whose result the
OpaqueValueExpr will be bound to") should also be a logical child.
This seems reasonable, but I just want to make sure that's really what
you are suggesting.
Yes. The rules are pretty imprecise, but — basically, anything that gets executed should be considered a child.