Alright it's been a number of months since I've dabbled in D, but my
spare time is slowly increasing... for now. Fingers crossed.
So I'm going to attack this property lowering thing again.
Here is a reminder of what I'm talking about:
http://prowiki.org/wiki4d/wiki.cgi?DocComments/Property
When I did this first I got 95% of the way there and hit a corner-case
in DMD's code. This chicken-and-egg problem is what happened:
(1) e->semantic(sc) is called. (e is an Expression)
- This will call e's children's semantic.
(2) resolveProperties must come after e->semantic(sc).
- It needs e->semantic to get the type info and
- to know if e contains properties (recursively).
(3) If e has side effects and the mutated value(s) contain properties,
then resolveProperties turns the mutated value(s) into multiple
expressions within a comma expression such that no properties are in a
side-effectful expression.
(4) The resulting CommaExp's (and other generated Exps) must have
semantic(sc) run on them to create type information.
- This will call e's children's semantic(sc), again.
(5) semantic(sc) must not be run on an Expression more than once.
- This is why my 95%-of-the-way-there code would work perfectly most
of the time and then fail in very rare instances.
4 and 5 contradict each other.
I'm wondering if there is some canonically accepted way of dealing with
this kind of stuff in DMD. I'd hate to write this and have it go to
waste because I missed an idiom or coding convention.
I've considered these possibilities:
- I could guard the execution of semantic to make sure it is never done
more than once:
Expression *FooExp::semantic( Scope *sc )
{
if ( semanticAlreadyCalledOnThis )
return this;
... etc
}
- I could do the above, but place that in a non-virtual semantic so that
the code isn't duplicated everywhere. I would have to make all calls to
semantic point to the non-virtual version. For sake of description,
I'll call the non-virtual one "semantic" and the current virtual one
"onSemantic".
Expression *FooExp::semantic( Scope *sc )
{
if ( semanticAlreadyCalledOnThis )
return this;
return onSemantic(sc)
}
Expression *FooExp::onSemantic( Scope *sc )
{
... (previous semantic code for FooExp) ...
}
- I write a "shallowSemantic" method for the CommaExp, VarDeclaration,
DeclarationExp, AssignExp, and anything else generated by the property
rewrite. This would have to be called manually as its generated. This
may not touch as many things as the above possibilities, but I suspect
it will be much uglier.
Please advise.
- Chad