/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #pragma once #include #include namespace MiniZinc { /** * \brief Bottom-up iterator for expressions */ template class BottomUpIterator { protected: /// The visitor to call back during iteration T& _t; /// Stack item struct C { /// Expression on the stack Expression* e; /// Whether this expression has been visited before bool done; /// If part of a generator expression, which one it is int genNumber; /// Constructor C(Expression* e0) : e(e0), done(false), genNumber(-1) {} /// Constructor for generator expression C(Expression* e0, int genNumber0) : e(e0), done(true), genNumber(genNumber0) {} }; /// Push all elements of \a v onto \a stack template void pushVec(std::vector& stack, ASTExprVec v) { for (unsigned int i = 0; i < v.size(); i++) { stack.push_back(C(v[i])); } } public: /// Constructor BottomUpIterator(T& t) : _t(t) {} /// Run iterator on expression \a e void run(Expression* root); }; template void bottom_up(T& t, Expression* e) { BottomUpIterator(t).run(e); } /** * \brief Leaf iterator for expressions */ template class TopDownIterator { protected: /// The visitor to call back during iteration T& _t; /// Push all elements of \a v onto \a stack template static void pushVec(std::vector& stack, ASTExprVec v) { for (unsigned int i = 0; i < v.size(); i++) { stack.push_back(v[i]); } } public: /// Constructor TopDownIterator(T& t) : _t(t) {} /// Run iterator on expression \a e void run(Expression* root); }; template void top_down(T& t, Expression* root) { TopDownIterator(t).run(root); } /* IMPLEMENTATION */ template void BottomUpIterator::run(Expression* root) { std::vector stack; if (_t.enter(root)) { stack.push_back(C(root)); } while (!stack.empty()) { C& c = stack.back(); if (c.e == nullptr) { stack.pop_back(); continue; } if (c.done) { switch (c.e->eid()) { case Expression::E_INTLIT: _t.vIntLit(*c.e->template cast()); break; case Expression::E_FLOATLIT: _t.vFloatLit(*c.e->template cast()); break; case Expression::E_SETLIT: _t.vSetLit(*c.e->template cast()); break; case Expression::E_BOOLLIT: _t.vBoolLit(*c.e->template cast()); break; case Expression::E_STRINGLIT: _t.vStringLit(*c.e->template cast()); break; case Expression::E_ID: _t.vId(*c.e->template cast()); break; case Expression::E_ANON: _t.vAnonVar(*c.e->template cast()); break; case Expression::E_ARRAYLIT: _t.vArrayLit(*c.e->template cast()); break; case Expression::E_ARRAYACCESS: _t.vArrayAccess(*c.e->template cast()); break; case Expression::E_COMP: if (c.genNumber >= 0) { _t.vComprehensionGenerator(*c.e->template cast(), c.genNumber); } else { _t.vComprehension(*c.e->template cast()); } break; case Expression::E_ITE: _t.vITE(*c.e->template cast()); break; case Expression::E_BINOP: _t.vBinOp(*c.e->template cast()); break; case Expression::E_UNOP: _t.vUnOp(*c.e->template cast()); break; case Expression::E_CALL: _t.vCall(*c.e->template cast()); break; case Expression::E_VARDECL: _t.vVarDecl(*c.e->template cast()); break; case Expression::E_LET: _t.vLet(*c.e->template cast()); break; case Expression::E_TI: _t.vTypeInst(*c.e->template cast()); break; case Expression::E_TIID: _t.vTIId(*c.e->template cast()); break; } _t.exit(c.e); stack.pop_back(); } else { c.done = true; Expression* ce = c.e; for (ExpressionSetIter it = ce->ann().begin(); it != ce->ann().end(); ++it) { if (_t.enter(*it)) { stack.push_back(C(*it)); } } if (_t.enter(ce)) { switch (ce->eid()) { case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_BOOLLIT: case Expression::E_STRINGLIT: case Expression::E_ANON: case Expression::E_ID: case Expression::E_TIID: break; case Expression::E_SETLIT: pushVec(stack, ce->template cast()->v()); break; case Expression::E_ARRAYLIT: { for (unsigned int i = 0; i < ce->cast()->size(); i++) { stack.push_back((*ce->cast())[i]); } } break; case Expression::E_ARRAYACCESS: pushVec(stack, ce->template cast()->idx()); stack.push_back(C(ce->template cast()->v())); break; case Expression::E_COMP: { auto* comp = ce->template cast(); stack.push_back(C(comp->e())); for (unsigned int i = comp->numberOfGenerators(); (i--) != 0U;) { for (unsigned int j = comp->numberOfDecls(i); (j--) != 0U;) { stack.push_back(C(comp->decl(i, j))); } if (comp->in(i) != nullptr) { stack.push_back(C(comp->where(i))); stack.push_back(C(comp, i)); stack.push_back(C(comp->in(i))); } else { stack.push_back(C(comp, i)); stack.push_back(C(comp->where(i))); } } } break; case Expression::E_ITE: { ITE* ite = ce->template cast(); stack.push_back(C(ite->elseExpr())); for (int i = 0; i < ite->size(); i++) { stack.push_back(C(ite->ifExpr(i))); stack.push_back(C(ite->thenExpr(i))); } } break; case Expression::E_BINOP: stack.push_back(C(ce->template cast()->rhs())); stack.push_back(C(ce->template cast()->lhs())); break; case Expression::E_UNOP: stack.push_back(C(ce->template cast()->e())); break; case Expression::E_CALL: for (unsigned int i = 0; i < ce->template cast()->argCount(); i++) { stack.push_back(ce->template cast()->arg(i)); } break; case Expression::E_VARDECL: stack.push_back(C(ce->template cast()->e())); stack.push_back(C(ce->template cast()->ti())); break; case Expression::E_LET: stack.push_back(C(ce->template cast()->in())); pushVec(stack, ce->template cast()->let()); break; case Expression::E_TI: stack.push_back(C(ce->template cast()->domain())); pushVec(stack, ce->template cast()->ranges()); break; } } else { c.e = nullptr; } } } } template void TopDownIterator::run(Expression* root) { std::vector stack; if (_t.enter(root)) { stack.push_back(root); } while (!stack.empty()) { Expression* e = stack.back(); stack.pop_back(); if (e == nullptr) { continue; } if (!_t.enter(e)) { continue; } for (ExpressionSetIter it = e->ann().begin(); it != e->ann().end(); ++it) { stack.push_back(*it); } switch (e->eid()) { case Expression::E_INTLIT: _t.vIntLit(*e->template cast()); break; case Expression::E_FLOATLIT: _t.vFloatLit(*e->template cast()); break; case Expression::E_SETLIT: _t.vSetLit(*e->template cast()); pushVec(stack, e->template cast()->v()); break; case Expression::E_BOOLLIT: _t.vBoolLit(*e->template cast()); break; case Expression::E_STRINGLIT: _t.vStringLit(*e->template cast()); break; case Expression::E_ID: _t.vId(*e->template cast()); break; case Expression::E_ANON: _t.vAnonVar(*e->template cast()); break; case Expression::E_ARRAYLIT: _t.vArrayLit(*e->template cast()); for (unsigned int i = 0; i < e->cast()->size(); i++) { stack.push_back((*e->cast())[i]); } break; case Expression::E_ARRAYACCESS: _t.vArrayAccess(*e->template cast()); pushVec(stack, e->template cast()->idx()); stack.push_back(e->template cast()->v()); break; case Expression::E_COMP: _t.vComprehension(*e->template cast()); { auto* comp = e->template cast(); for (unsigned int i = comp->numberOfGenerators(); (i--) != 0U;) { stack.push_back(comp->where(i)); stack.push_back(comp->in(i)); for (unsigned int j = comp->numberOfDecls(i); (j--) != 0U;) { stack.push_back(comp->decl(i, j)); } } stack.push_back(comp->e()); } break; case Expression::E_ITE: _t.vITE(*e->template cast()); { ITE* ite = e->template cast(); stack.push_back(ite->elseExpr()); for (int i = 0; i < ite->size(); i++) { stack.push_back(ite->ifExpr(i)); stack.push_back(ite->thenExpr(i)); } } break; case Expression::E_BINOP: _t.vBinOp(*e->template cast()); stack.push_back(e->template cast()->rhs()); stack.push_back(e->template cast()->lhs()); break; case Expression::E_UNOP: _t.vUnOp(*e->template cast()); stack.push_back(e->template cast()->e()); break; case Expression::E_CALL: _t.vCall(*e->template cast()); for (unsigned int i = 0; i < e->template cast()->argCount(); i++) { stack.push_back(e->template cast()->arg(i)); } break; case Expression::E_VARDECL: _t.vVarDecl(*e->template cast()); stack.push_back(e->template cast()->e()); stack.push_back(e->template cast()->ti()); break; case Expression::E_LET: _t.vLet(*e->template cast()); stack.push_back(e->template cast()->in()); pushVec(stack, e->template cast()->let()); break; case Expression::E_TI: _t.vTypeInst(*e->template cast()); stack.push_back(e->template cast()->domain()); pushVec(stack, e->template cast()->ranges()); break; case Expression::E_TIID: _t.vTIId(*e->template cast()); break; } } } } // namespace MiniZinc