/* -*- 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/. */ #ifndef __MINIZINC_ASTITERATOR_HH__ #define __MINIZINC_ASTITERATOR_HH__ #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 _gen_i; /// Constructor C(Expression* e) : _e(e), _done(false), _gen_i(-1) {} /// Constructor for generator expression C(Expression* e, int gen_i) : _e(e), _done(true), _gen_i(gen_i) {} }; /// 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* e); }; template void bottomUp(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* e); }; template void topDown(T& t, Expression* e) { TopDownIterator(t).run(e); } /* 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 == NULL) { 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._gen_i >= 0) { _t.vComprehensionGenerator(*c._e->template cast(), c._gen_i); } 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: { Comprehension* comp = ce->template cast(); stack.push_back(C(comp->e())); for (unsigned int i = comp->n_generators(); i--;) { for (unsigned int j = comp->n_decls(i); j--;) { stack.push_back(C(comp->decl(i, j))); } if (comp->in(i)) { 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->e_else())); for (int i = 0; i < ite->size(); i++) { stack.push_back(C(ite->e_if(i))); stack.push_back(C(ite->e_then(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()->n_args(); 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 = NULL; } } } } 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 == NULL) { 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()); { Comprehension* comp = e->template cast(); for (unsigned int i = comp->n_generators(); i--;) { stack.push_back(comp->where(i)); stack.push_back(comp->in(i)); for (unsigned int j = comp->n_decls(i); j--;) { 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->e_else()); for (int i = 0; i < ite->size(); i++) { stack.push_back(ite->e_if(i)); stack.push_back(ite->e_then(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()->n_args(); 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 #endif