blob: 1a45e61d56553d47bd865a29d56b22f6584a24df [file] [log] [blame]
/**
* A depth-first visitor for expressions and statements.
*
* Copyright: Copyright (C) 1999-2026 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/visitor/postorder.d, _apply.d)
* Documentation: https://dlang.org/phobos/dmd_apply.html
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/visitor/postorder.d
*/
module dmd.visitor.postorder;
import dmd.dtemplate;
import dmd.expression;
import dmd.root.array;
import dmd.statement;
import dmd.visitor;
bool walkPostorder(Expression e, StoppableVisitor v)
{
scope PostorderExpressionVisitor pv = new PostorderExpressionVisitor(v);
e.accept(pv);
return v.stop;
}
bool walkPostorder(Statement s, StoppableVisitor v)
{
scope PostorderStatementVisitor pv = new PostorderStatementVisitor(v);
s.accept(pv);
return v.stop;
}
private:
/**************************************
* An Expression tree walker that will visit each Expression e in the tree,
* in depth-first evaluation order, and call fp(e,param) on it.
* fp() signals whether the walking continues with its return value:
* Returns:
* 0 continue
* 1 done
* It's a bit slower than using virtual functions, but more encapsulated and less brittle.
* Creating an iterator for this would be much more complex.
*/
extern (C++) final class PostorderExpressionVisitor : StoppableVisitor
{
alias visit = typeof(super).visit;
public:
StoppableVisitor v;
extern (D) this(StoppableVisitor v) scope @safe
{
this.v = v;
}
bool doCond(Expression e)
{
if (!stop && e)
e.accept(this);
return stop;
}
extern(D) bool doCond(Expression[] e)
{
for (size_t i = 0; i < e.length && !stop; i++)
doCond(e[i]);
return stop;
}
bool applyTo(Expression e)
{
e.accept(v);
stop = v.stop;
return true;
}
override void visit(Expression e)
{
applyTo(e);
}
override void visit(NewExp e)
{
//printf("NewExp::apply(): %s\n", toChars());
doCond(e.placement) || doCond(e.thisexp) || doCond(e.arguments.peekSlice()) || applyTo(e);
}
override void visit(NewAnonClassExp e)
{
//printf("NewAnonClassExp::apply(): %s\n", toChars());
doCond(e.placement) || doCond(e.thisexp) || doCond(e.arguments.peekSlice()) || applyTo(e);
}
override void visit(TypeidExp e)
{
doCond(isExpression(e.obj)) || applyTo(e);
}
override void visit(UnaExp e)
{
doCond(e.e1) || applyTo(e);
}
override void visit(BinExp e)
{
doCond(e.e1) || doCond(e.e2) || applyTo(e);
}
override void visit(CatExp e)
{
if (auto lowering = e.lowering)
{
doCond(lowering) || applyTo(e);
}
else
{
visit(cast(BinExp)e);
}
}
override void visit(CatAssignExp e)
{
if (auto lowering = e.lowering)
{
doCond(lowering) || applyTo(e);
}
else
{
visit(cast(BinExp)e);
}
}
override void visit(EqualExp e)
{
if (auto lowering = e.lowering)
{
doCond(lowering) || applyTo(e);
}
else
{
visit(cast(BinExp)e);
}
}
override void visit(AssertExp e)
{
//printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
doCond(e.e1) || doCond(e.msg) || applyTo(e);
}
override void visit(CallExp e)
{
//printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
doCond(e.e1) || doCond(e.arguments.peekSlice()) || applyTo(e);
}
override void visit(ArrayExp e)
{
//printf("ArrayExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
doCond(e.e1) || doCond(e.arguments.peekSlice()) || applyTo(e);
}
override void visit(SliceExp e)
{
doCond(e.e1) || doCond(e.lwr) || doCond(e.upr) || applyTo(e);
}
override void visit(ArrayLiteralExp e)
{
doCond(e.basis) || doCond(e.elements.peekSlice()) || applyTo(e);
}
override void visit(AssocArrayLiteralExp e)
{
doCond(e.keys.peekSlice()) || doCond(e.values.peekSlice()) || applyTo(e);
}
override void visit(StructLiteralExp e)
{
if (e.stageflags & StructLiteralExp.StageFlags.apply)
return;
const old = e.stageflags;
e.stageflags |= StructLiteralExp.StageFlags.apply;
doCond(e.elements.peekSlice()) || applyTo(e);
e.stageflags = old;
}
override void visit(TupleExp e)
{
doCond(e.e0) || doCond(e.exps.peekSlice()) || applyTo(e);
}
override void visit(CondExp e)
{
doCond(e.econd) || doCond(e.e1) || doCond(e.e2) || applyTo(e);
}
}
/**************************************
* A Statement tree walker that will visit each Statement s in the tree,
* in depth-first evaluation order, and call fp(s,param) on it.
* fp() signals whether the walking continues with its return value:
* Returns:
* 0 continue
* 1 done
* It's a bit slower than using virtual functions, but more encapsulated and less brittle.
* Creating an iterator for this would be much more complex.
*/
extern (C++) final class PostorderStatementVisitor : StoppableVisitor
{
alias visit = typeof(super).visit;
public:
StoppableVisitor v;
extern (D) this(StoppableVisitor v) scope @safe
{
this.v = v;
}
bool doCond(Statement s)
{
if (!stop && s)
s.accept(this);
return stop;
}
bool applyTo(Statement s)
{
s.accept(v);
stop = v.stop;
return true;
}
override void visit(Statement s)
{
applyTo(s);
}
override void visit(PeelStatement s)
{
doCond(s.s) || applyTo(s);
}
override void visit(CompoundStatement s)
{
for (size_t i = 0; i < s.statements.length; i++)
if (doCond((*s.statements)[i]))
return;
applyTo(s);
}
override void visit(UnrolledLoopStatement s)
{
for (size_t i = 0; i < s.statements.length; i++)
if (doCond((*s.statements)[i]))
return;
applyTo(s);
}
override void visit(ScopeStatement s)
{
doCond(s.statement) || applyTo(s);
}
override void visit(WhileStatement s)
{
doCond(s._body) || applyTo(s);
}
override void visit(DoStatement s)
{
doCond(s._body) || applyTo(s);
}
override void visit(ForStatement s)
{
doCond(s._init) || doCond(s._body) || applyTo(s);
}
override void visit(ForeachStatement s)
{
doCond(s._body) || applyTo(s);
}
override void visit(ForeachRangeStatement s)
{
doCond(s._body) || applyTo(s);
}
override void visit(IfStatement s)
{
doCond(s.ifbody) || doCond(s.elsebody) || applyTo(s);
}
override void visit(PragmaStatement s)
{
doCond(s._body) || applyTo(s);
}
override void visit(SwitchStatement s)
{
doCond(s._body) || applyTo(s);
}
override void visit(CaseStatement s)
{
doCond(s.statement) || applyTo(s);
}
override void visit(DefaultStatement s)
{
doCond(s.statement) || applyTo(s);
}
override void visit(SynchronizedStatement s)
{
doCond(s._body) || applyTo(s);
}
override void visit(WithStatement s)
{
doCond(s._body) || applyTo(s);
}
override void visit(TryCatchStatement s)
{
if (doCond(s._body))
return;
for (size_t i = 0; i < s.catches.length; i++)
if (doCond((*s.catches)[i].handler))
return;
applyTo(s);
}
override void visit(TryFinallyStatement s)
{
doCond(s._body) || doCond(s.finalbody) || applyTo(s);
}
override void visit(ScopeGuardStatement s)
{
doCond(s.statement) || applyTo(s);
}
override void visit(DebugStatement s)
{
doCond(s.statement) || applyTo(s);
}
override void visit(LabelStatement s)
{
doCond(s.statement) || applyTo(s);
}
}