/* "CodeWorker": a scripting language for parsing and generating text. Copyright (C) 1996-1997, 1999-2002 Cédric Lemaire This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA To contact the author: codeworker@free.fr */ #ifdef WIN32 #pragma warning (disable : 4786) #endif #include "DtaScriptVariable.h" #include "DtaArrayIterator.h" #include "ExprScriptVariable.h" #include "ScpStream.h" #include "CppCompilerEnvironment.h" #include "GrfForeach.h" namespace CodeWorker { class DtaVectorIterator : public DtaArrayIterator { private: const std::vector& _list; std::vector::const_iterator i; public: inline DtaVectorIterator(const DtaVectorIterator& copy) : DtaArrayIterator(copy), _list(copy._list), i(copy.i) {} inline DtaVectorIterator(const std::vector& listOfNodes) : _list(listOfNodes), i(listOfNodes.begin()) {} virtual ~DtaVectorIterator() {} virtual DtaArrayIterator* clone() const { return new DtaVectorIterator(*this); } virtual int size() const { return _list.size(); } virtual bool end() const { return i == _list.end(); } virtual const char* key() const { return (*i)->getName(); } virtual DtaScriptVariable* item() const { return *i; } virtual bool prec() { if (i == _list.begin()) return false; --_iCurrentPosition; --i; _pItemNoRef = NULL; return true; } virtual bool next() { ++_iCurrentPosition; ++i; _pItemNoRef = NULL; return i != _list.end(); } }; class DtaReverseVectorIterator : public DtaArrayIterator { private: const std::vector& _list; std::vector::const_reverse_iterator i; public: inline DtaReverseVectorIterator(const DtaReverseVectorIterator& copy) : DtaArrayIterator(copy), _list(copy._list), i(copy.i) {} inline DtaReverseVectorIterator(const std::vector& listOfNodes) : _list(listOfNodes), i(listOfNodes.rbegin()) {} virtual ~DtaReverseVectorIterator() {} virtual DtaArrayIterator* clone() const { return new DtaReverseVectorIterator(*this); } virtual int size() const { return _list.size(); } virtual bool end() const { return i == _list.rend(); } virtual const char* key() const { return (*i)->getName(); } virtual DtaScriptVariable* item() const { return *i; } virtual bool prec() { if (i == _list.rbegin()) return false; --_iCurrentPosition; --i; _pItemNoRef = NULL; return true; } virtual bool next() { ++_iCurrentPosition; ++i; _pItemNoRef = NULL; return i != _list.rend(); } }; class DtaMapIterator : public DtaArrayIterator { private: const std::map& _map; std::map::const_iterator i; public: inline DtaMapIterator(const DtaMapIterator& copy) : DtaArrayIterator(copy), _map(copy._map), i(copy.i) {} inline DtaMapIterator(const std::map& mapOfNodes) : _map(mapOfNodes), i(mapOfNodes.begin()) {} virtual ~DtaMapIterator() {} virtual DtaArrayIterator* clone() const { return new DtaMapIterator(*this); } virtual int size() const { return _map.size(); } virtual bool end() const { return i == _map.end(); } virtual const char* key() const { return i->second->getName(); } virtual DtaScriptVariable* item() const { return i->second; } virtual bool prec() { if (i == _map.begin()) return false; --_iCurrentPosition; --i; _pItemNoRef = NULL; return true; } virtual bool next() { ++_iCurrentPosition; ++i; _pItemNoRef = NULL; return i != _map.end(); } }; class DtaReverseMapIterator : public DtaArrayIterator { private: const std::map& _map; std::map::const_reverse_iterator i; public: inline DtaReverseMapIterator(const DtaReverseMapIterator& copy) : DtaArrayIterator(copy), _map(copy._map), i(copy.i) {} inline DtaReverseMapIterator(const std::map& mapOfNodes) : _map(mapOfNodes), i(mapOfNodes.rbegin()) {} virtual ~DtaReverseMapIterator() {} virtual DtaArrayIterator* clone() const { return new DtaReverseMapIterator(*this); } virtual int size() const { return _map.size(); } virtual bool end() const { return i == _map.rend(); } virtual const char* key() const { return i->second->getName(); } virtual DtaScriptVariable* item() const { return i->second; } virtual bool prec() { if (i == _map.rbegin()) return false; --_iCurrentPosition; --i; _pItemNoRef = NULL; return true; } virtual bool next() { ++_iCurrentPosition; ++i; _pItemNoRef = NULL; return i != _map.rend(); } }; GrfForeach::~GrfForeach() { delete _pIndexExpr; delete _pListExpr; } void GrfForeach::setIndex(ExprScriptVariable* pIndexExpr) { _pIndexExpr = pIndexExpr; addLocalVariable(pIndexExpr->getName(), ITERATOR_EXPRTYPE); } void GrfForeach::setSortedNoCase(bool bSortedNoCase) { if (bSortedNoCase) _bSorted = true; _bSortedNoCase = bSortedNoCase; } void GrfForeach::setReverse(bool bReverse) { _bReverse = bReverse; } SEQUENCE_INTERRUPTION_LIST GrfForeach::executeInternal(DtaScriptVariable& visibility) { SEQUENCE_INTERRUPTION_LIST result = NO_INTERRUPTION; DtaScriptVariable* pVariable = visibility.getExistingVariable(*_pListExpr); if (pVariable != NULL) { const std::list* pArray = pVariable->getArray(); if ((pArray != NULL) && !pArray->empty()) { DtaScriptVariable stackForeach(&visibility, "##stack## foreach"); stackForeach.createIterator(_pIndexExpr->getName().c_str(), &_pArrayIteratorData); if (_iCascading != NO_CASCADING) _sCascadedName = pVariable->getName(); result = executeCorrectForeach(*pVariable, stackForeach); if (result == BREAK_INTERRUPTION) result = NO_INTERRUPTION; } } return result; } SEQUENCE_INTERRUPTION_LIST GrfForeach::executeCorrectForeach(DtaScriptVariable& theVariable, DtaScriptVariable& stackForeach) { SEQUENCE_INTERRUPTION_LIST result = NO_INTERRUPTION; if (_bSorted) { if (_bSortedNoCase) { if (_bReverse) result = executeReverseSortedIndirectForeach(theVariable, stackForeach); else result = executeSortedIndirectForeach(theVariable, stackForeach); } else { if (_bSortOnValue) result = executeSortedIndirectForeach(theVariable, stackForeach); else if (_bReverse) result = executeReverseSortedForeach(theVariable, stackForeach); else result = executeSortedForeach(theVariable, stackForeach); } } else { if (_bReverse) result = executeReverseForeach(theVariable, stackForeach); else result = executeForeach(theVariable, stackForeach); } return result; } SEQUENCE_INTERRUPTION_LIST GrfForeach::executeForeach(DtaScriptVariable& theVariable, DtaScriptVariable& stackForeach) { const std::list* list = theVariable.getArray(); if (list == NULL) return NO_INTERRUPTION; DtaListIterator iteratorData(*list); return iterate(iteratorData, stackForeach); } SEQUENCE_INTERRUPTION_LIST GrfForeach::executeReverseForeach(DtaScriptVariable& theVariable, DtaScriptVariable& stackForeach) { const std::list* list = theVariable.getArray(); if (list == NULL) return NO_INTERRUPTION; DtaReverseListIterator iteratorData(*list); return iterate(iteratorData, stackForeach); } SEQUENCE_INTERRUPTION_LIST GrfForeach::executeSortedForeach(DtaScriptVariable& theVariable, DtaScriptVariable& stackForeach) { const std::map* mapOfElements = theVariable.getSortedArray(); if (mapOfElements == NULL) return NO_INTERRUPTION; DtaMapIterator iteratorData(*mapOfElements); return iterate(iteratorData, stackForeach); } SEQUENCE_INTERRUPTION_LIST GrfForeach::executeSortedIndirectForeach(DtaScriptVariable& theVariable, DtaScriptVariable& stackForeach) { std::auto_ptr > listOfElements; if (_bSortedNoCase) { if (_bSortOnValue) { listOfElements = std::auto_ptr >(theVariable.getSortedNoCaseArrayOnValue()); } else { listOfElements = std::auto_ptr >(theVariable.getSortedNoCaseArray()); } } else if (_bSortOnValue) { listOfElements = std::auto_ptr >(theVariable.getSortedArrayOnValue()); } DtaVectorIterator iteratorData(*listOfElements); return iterate(iteratorData, stackForeach); } SEQUENCE_INTERRUPTION_LIST GrfForeach::executeReverseSortedForeach(DtaScriptVariable& theVariable, DtaScriptVariable& stackForeach) { const std::map* mapOfElements = theVariable.getSortedArray(); if (mapOfElements == NULL) return NO_INTERRUPTION; DtaReverseMapIterator iteratorData(*mapOfElements); return iterate(iteratorData, stackForeach); } SEQUENCE_INTERRUPTION_LIST GrfForeach::executeReverseSortedIndirectForeach(DtaScriptVariable& theVariable, DtaScriptVariable& stackForeach) { std::auto_ptr > listOfElements; if (_bSortedNoCase) { if (_bSortOnValue) { listOfElements = std::auto_ptr >(theVariable.getSortedNoCaseArrayOnValue()); } else { listOfElements = std::auto_ptr >(theVariable.getSortedNoCaseArray()); } } else if (_bSortOnValue) { listOfElements = std::auto_ptr >(theVariable.getSortedArrayOnValue()); } DtaReverseVectorIterator iteratorData(*listOfElements); return iterate(iteratorData, stackForeach); } SEQUENCE_INTERRUPTION_LIST GrfForeach::iterate(DtaArrayIterator& iteratorData, DtaScriptVariable& stackForeach) { SEQUENCE_INTERRUPTION_LIST result; DtaArrayIterator* pOldArrayIteratorData = _pArrayIteratorData; _pArrayIteratorData = &iteratorData; if (!iteratorData.end()) { do { if (_iCascading == CASCADING_FIRST) { DtaScriptVariable* pNext = iteratorData.item()->getNode(_sCascadedName.c_str()); if (pNext != NULL) { result = executeCorrectForeach(*pNext, stackForeach); if ((result != CONTINUE_INTERRUPTION) && (result != NO_INTERRUPTION)) return result; } } result = GrfBlock::executeInternal(stackForeach); if ((result != CONTINUE_INTERRUPTION) && (result != NO_INTERRUPTION)) return result; if (_iCascading == CASCADING_LAST) { DtaScriptVariable* pNext = iteratorData.item()->getNode(_sCascadedName.c_str()); if (pNext != NULL) { result = executeCorrectForeach(*pNext, stackForeach); if ((result != CONTINUE_INTERRUPTION) && (result != NO_INTERRUPTION)) return result; } } } while (iteratorData.next()); } _pArrayIteratorData = pOldArrayIteratorData; return NO_INTERRUPTION; } void GrfForeach::compileCpp(CppCompilerEnvironment& theCompilerEnvironment) const { std::string sIndex = _pIndexExpr->getName(); std::string sIndex2Cpp = theCompilerEnvironment.convertToCppVariable(sIndex); theCompilerEnvironment.addVariable(sIndex); theCompilerEnvironment.pushForeach(const_cast(this)); if (_bSorted) { if (_bSortedNoCase) { if (theCompilerEnvironment.addVariable("_compilerMapSortedNoCaseForeach_" + sIndex)) { CW_BODY_INDENT << "std::vector::const_iterator _compilerIndexSortedNoCaseForeach_" << sIndex << ";"; CW_BODY_ENDL; CW_BODY_INDENT << "std::auto_ptr > _compilerMapSortedNoCaseForeach_" << sIndex << "("; _pListExpr->compileCpp(theCompilerEnvironment); CW_BODY_STREAM << ".getSortedNoCaseArray());"; CW_BODY_ENDL; } else { CW_BODY_INDENT << "_compilerMapSortedNoCaseForeach_" << sIndex << " = "; _pListExpr->compileCpp(theCompilerEnvironment); CW_BODY_STREAM << ".getSortedNoCaseArray();"; CW_BODY_ENDL; } CW_BODY_INDENT << "for (_compilerIndexSortedNoCaseForeach_" << sIndex << " = _compilerMapSortedNoCaseForeach_" << sIndex << "->begin(); _compilerIndexSortedNoCaseForeach_" << sIndex << " != _compilerMapSortedNoCaseForeach_" << sIndex << "->end(); ++_compilerIndexSortedNoCaseForeach_" << sIndex << ") {"; CW_BODY_ENDL; theCompilerEnvironment.incrementIndentation(); CW_BODY_INDENT << "CppParsingTree_var " << sIndex2Cpp << "(*_compilerIndexSortedNoCaseForeach_" << sIndex << ");"; CW_BODY_ENDL; CW_BODY_INDENT << "std::string _compilerKeyForeach_" << sIndex << "(" << sIndex2Cpp << ".getName());"; CW_BODY_ENDL; } else { if (theCompilerEnvironment.addVariable("_compilerMapSortedForeach_" + sIndex)) { CW_BODY_INDENT << "std::map::const_iterator _compilerIndexSortedForeach_" << sIndex << ";"; CW_BODY_ENDL; CW_BODY_INDENT << "const std::map* _compilerMapSortedForeach_" << sIndex << " = "; _pListExpr->compileCpp(theCompilerEnvironment); CW_BODY_STREAM << ".getSortedArray();"; CW_BODY_ENDL; } else { CW_BODY_INDENT << "_compilerMapSortedForeach_" << sIndex << " = "; _pListExpr->compileCpp(theCompilerEnvironment); CW_BODY_STREAM << ".getSortedArray()"; CW_BODY_ENDL; } CW_BODY_INDENT << "if (_compilerMapSortedForeach_" << sIndex << " != 0) for (_compilerIndexSortedForeach_" << sIndex << " = _compilerMapSortedForeach_" << sIndex << "->begin(); _compilerIndexSortedForeach_" << sIndex << " != _compilerMapSortedForeach_" << sIndex << "->end(); ++_compilerIndexSortedForeach_" << sIndex << ") {"; CW_BODY_ENDL; theCompilerEnvironment.incrementIndentation(); CW_BODY_INDENT << "CppParsingTree_var " << sIndex2Cpp << "(_compilerIndexSortedForeach_" << sIndex << "->second);"; CW_BODY_ENDL; CW_BODY_INDENT << "std::string _compilerKeyForeach_" << sIndex << "(_compilerIndexSortedForeach_" << sIndex << "->first);"; CW_BODY_ENDL; } } else { if (theCompilerEnvironment.addVariable("_compilerMapForeach_" + sIndex)) { CW_BODY_INDENT << "std::list::const_iterator _compilerIndexForeach_" << sIndex << ";"; CW_BODY_ENDL; CW_BODY_INDENT << "const std::list* _compilerMapForeach_" << sIndex << " = "; _pListExpr->compileCpp(theCompilerEnvironment); CW_BODY_STREAM << ".getArray();";CW_BODY_ENDL; } else { CW_BODY_INDENT << "_compilerMapForeach_" << sIndex << " = "; _pListExpr->compileCpp(theCompilerEnvironment); CW_BODY_STREAM << ".getArray();";CW_BODY_ENDL; } if (_iCascading != NO_CASCADING) { CW_BODY_INDENT << "{";CW_BODY_ENDL; theCompilerEnvironment.incrementIndentation(); CW_BODY_INDENT << "struct _COMPILER_INDEX_FOREACH_STACK {";CW_BODY_ENDL; CW_BODY_INDENT << "\tstd::list::const_iterator i_;";CW_BODY_ENDL; CW_BODY_INDENT << "\tconst std::list* pList_;";CW_BODY_ENDL; CW_BODY_INDENT << "\t_COMPILER_INDEX_FOREACH_STACK* pParent_;";CW_BODY_ENDL; CW_BODY_INDENT << "\t_COMPILER_INDEX_FOREACH_STACK(std::list::const_iterator& i, const std::list* pList, _COMPILER_INDEX_FOREACH_STACK* pParent) : i_(i), pList_(pList), pParent_(pParent) {}";CW_BODY_ENDL; CW_BODY_INDENT << "} *_compilerIndexForeach_stack = NULL;";CW_BODY_ENDL; CW_BODY_INDENT << "if (_compilerMapForeach_" << sIndex << " != NULL) _compilerIndexForeach_" << sIndex << " = _compilerMapForeach_" << sIndex << "->begin();";CW_BODY_ENDL; CW_BODY_INDENT << "bool _compilerForeach_realBreak;";CW_BODY_ENDL; if (_iCascading == CASCADING_FIRST) { CW_BODY_INDENT << "bool _compilerForeach_firstDone = false;";CW_BODY_ENDL; } CW_BODY_INDENT << "do {";CW_BODY_ENDL; theCompilerEnvironment.incrementIndentation(); CW_BODY_INDENT << "_compilerForeach_realBreak = true;";CW_BODY_ENDL; CW_BODY_INDENT << "if (_compilerMapForeach_" << sIndex << " != 0) for (; _compilerIndexForeach_" << sIndex << " != _compilerMapForeach_" << sIndex << "->end(); ++_compilerIndexForeach_" << sIndex << ") {";CW_BODY_ENDL; theCompilerEnvironment.incrementIndentation(); if (_iCascading == CASCADING_FIRST) { CW_BODY_INDENT << "CppParsingTree_var _compilerForeachNext(CppParsingTree_var(*_compilerIndexForeach_" << sIndex << ").getNode(\"" << _sCascadedName << "\"));";CW_BODY_ENDL; CW_BODY_INDENT << "if (!_compilerForeach_firstDone && !_compilerForeachNext.isNull() && (_compilerForeachNext.getArray() != NULL)) {";CW_BODY_ENDL; CW_BODY_INDENT << "\t_compilerIndexForeach_stack = new _COMPILER_INDEX_FOREACH_STACK(_compilerIndexForeach_" << sIndex << ", _compilerMapForeach_" << sIndex << ", _compilerIndexForeach_stack);";CW_BODY_ENDL; CW_BODY_INDENT << "\t_compilerMapForeach_" << sIndex << " = _compilerForeachNext.getArray();";CW_BODY_ENDL; CW_BODY_INDENT << "\t_compilerIndexForeach_" << sIndex << " = _compilerMapForeach_" << sIndex << "->begin();";CW_BODY_ENDL; CW_BODY_INDENT << "\t_compilerForeach_realBreak = false;";CW_BODY_ENDL; CW_BODY_INDENT << "\tbreak;";CW_BODY_ENDL; CW_BODY_INDENT << "} else {";CW_BODY_ENDL; CW_BODY_INDENT << "\t_compilerForeach_firstDone = false;";CW_BODY_ENDL; CW_BODY_INDENT << "}";CW_BODY_ENDL; } } else { CW_BODY_INDENT << "if (_compilerMapForeach_" << sIndex << " != 0) for (_compilerIndexForeach_" << sIndex << " = _compilerMapForeach_" << sIndex << "->begin(); _compilerIndexForeach_" << sIndex << " != _compilerMapForeach_" << sIndex << "->end(); ++_compilerIndexForeach_" << sIndex << ") {"; CW_BODY_ENDL; theCompilerEnvironment.incrementIndentation(); } CW_BODY_INDENT << "CppParsingTree_var " << sIndex2Cpp << "(*_compilerIndexForeach_" << sIndex << ");"; CW_BODY_ENDL; CW_BODY_INDENT << "std::string _compilerKeyForeach_" << sIndex << "(" << sIndex2Cpp << ".getName());"; CW_BODY_ENDL; } theCompilerEnvironment.bracketsToNextBlock(false); GrfBlock::compileCpp(theCompilerEnvironment); if (_iCascading != NO_CASCADING) { if (_iCascading == CASCADING_LAST) { CW_BODY_INDENT << "CppParsingTree_var _compilerForeachNext(CppParsingTree_var(*_compilerIndexForeach_" << sIndex << ").getNode(\"" << _sCascadedName << "\"));";CW_BODY_ENDL; CW_BODY_INDENT << "if (!_compilerForeachNext.isNull() && (_compilerForeachNext.getArray() != NULL)) {";CW_BODY_ENDL; CW_BODY_INDENT << "\t++_compilerIndexForeach_" << sIndex << ";";CW_BODY_ENDL; CW_BODY_INDENT << "\t_compilerIndexForeach_stack = new _COMPILER_INDEX_FOREACH_STACK(_compilerIndexForeach_" << sIndex << ", _compilerMapForeach_" << sIndex << ", _compilerIndexForeach_stack);";CW_BODY_ENDL; CW_BODY_INDENT << "\t_compilerMapForeach_" << sIndex << " = _compilerForeachNext.getArray();";CW_BODY_ENDL; CW_BODY_INDENT << "\t_compilerIndexForeach_" << sIndex << " = _compilerMapForeach_" << sIndex << "->begin();";CW_BODY_ENDL; CW_BODY_INDENT << "\t_compilerForeach_realBreak = false;";CW_BODY_ENDL; CW_BODY_INDENT << "\tbreak;";CW_BODY_ENDL; CW_BODY_INDENT << "}";CW_BODY_ENDL; } theCompilerEnvironment.decrementIndentation(); CW_BODY_INDENT << "}";CW_BODY_ENDL; CW_BODY_INDENT << "if ((_compilerMapForeach_" << sIndex << " == NULL) || (_compilerIndexForeach_" << sIndex << " == _compilerMapForeach_" << sIndex << "->end())) {";CW_BODY_ENDL; CW_BODY_INDENT << "\tif (_compilerIndexForeach_stack == NULL) _compilerForeach_realBreak = true;";CW_BODY_ENDL; CW_BODY_INDENT << "\telse {";CW_BODY_ENDL; CW_BODY_INDENT << "\t\t_compilerForeach_realBreak = false;";CW_BODY_ENDL; CW_BODY_INDENT << "\t\t_compilerIndexForeach_" << sIndex << " = _compilerIndexForeach_stack->i_;";CW_BODY_ENDL; CW_BODY_INDENT << "\t\t_compilerMapForeach_" << sIndex << " = _compilerIndexForeach_stack->pList_;";CW_BODY_ENDL; CW_BODY_INDENT << "\t\t_COMPILER_INDEX_FOREACH_STACK* pTemp = _compilerIndexForeach_stack;";CW_BODY_ENDL; CW_BODY_INDENT << "\t\t_compilerIndexForeach_stack = pTemp->pParent_;";CW_BODY_ENDL; CW_BODY_INDENT << "\t\tdelete pTemp;";CW_BODY_ENDL; if (_iCascading == CASCADING_FIRST) { CW_BODY_INDENT << "\t\t_compilerForeach_firstDone = true;";CW_BODY_ENDL; } CW_BODY_INDENT << "\t}";CW_BODY_ENDL; CW_BODY_INDENT << "}";CW_BODY_ENDL; theCompilerEnvironment.decrementIndentation(); CW_BODY_INDENT << "} while (!_compilerForeach_realBreak);";CW_BODY_ENDL; theCompilerEnvironment.decrementIndentation(); CW_BODY_INDENT << "}";CW_BODY_ENDL; } else { theCompilerEnvironment.decrementIndentation(); CW_BODY_INDENT << "}";CW_BODY_ENDL; } theCompilerEnvironment.popForeach(); } }