blob: ef0151656b1dd68ebea3071adbe0fdd3abe66dd8 [file] [log] [blame]
/**
* Provides a depth-first statement visitor.
*
* Copyright: Copyright (C) 1999-2023 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/src/dmd/sparse.d, _sparse.d)
* Documentation: https://dlang.org/phobos/dmd_sapply.html
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/sapply.d
*/
module dmd.sapply;
import dmd.statement;
import dmd.visitor;
bool walkPostorder(Statement s, StoppableVisitor v)
{
scope PostorderStatementVisitor pv = new PostorderStatementVisitor(v);
s.accept(pv);
return v.stop;
}
/**************************************
* 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.
*/
private extern (C++) final class PostorderStatementVisitor : StoppableVisitor
{
alias visit = typeof(super).visit;
public:
StoppableVisitor v;
extern (D) this(StoppableVisitor v) scope
{
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);
}
}