File indexing completed on 2024-04-28 03:40:39
0001 /************************************************************************************* 0002 * Copyright (C) 2007-2009 by Aleix Pol <aleixpol@kde.org> * 0003 * Copyright (C) 2014 by Percy Camilo T. Aucahuasi <percy.camilo.ta@gmail.com> * 0004 * * 0005 * This program is free software; you can redistribute it and/or * 0006 * modify it under the terms of the GNU General Public License * 0007 * as published by the Free Software Foundation; either version 2 * 0008 * of the License, or (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program; if not, write to the Free Software * 0017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 0018 *************************************************************************************/ 0019 0020 #include "analitzautils.h" 0021 0022 #include "abstractexpressionvisitor.h" 0023 #include "vector.h" 0024 #include "value.h" 0025 #include "list.h" 0026 #include "variable.h" 0027 #include "container.h" 0028 #include "variables.h" 0029 #include "expression.h" 0030 #include "apply.h" 0031 #include <QVariant> 0032 #include "customobject.h" 0033 #include "matrix.h" 0034 0035 using namespace Analitza; 0036 namespace AnalitzaUtils 0037 { 0038 0039 QStringList dependencies(const Object* o, const QStringList& scope) 0040 { 0041 Q_ASSERT(o); 0042 0043 QSet<QString> ret; 0044 switch(o->type()) { 0045 case Object::variable: { 0046 Ci *i = (Ci*) o; 0047 if(!scope.contains(i->name())) 0048 ret += i->name(); 0049 } break; 0050 case Object::matrix: { 0051 const Matrix *v=(const Matrix*) o; 0052 for(Matrix::const_iterator it=v->constBegin(); it!=v->constEnd(); ++it) { 0053 const auto &dep = dependencies(*it, scope); 0054 ret += QSet<QString>(dep.begin(), dep.end()); 0055 } 0056 } break; 0057 case Object::vector: { 0058 const Vector *v=(const Vector*) o; 0059 for(Vector::const_iterator it=v->constBegin(); it!=v->constEnd(); ++it) { 0060 const auto &dep = dependencies(*it, scope); 0061 ret += QSet<QString>(dep.begin(), dep.end()); 0062 } 0063 } break; 0064 case Object::list: { 0065 const List *v=(const List*) o; 0066 for(List::const_iterator it=v->constBegin(); it!=v->constEnd(); ++it) { 0067 const auto &dep = dependencies(*it, scope); 0068 ret += QSet<QString>(dep.begin(), dep.end()); 0069 } 0070 } break; 0071 case Object::matrixrow: { 0072 const MatrixRow *v=(const MatrixRow*) o; 0073 for(MatrixRow::const_iterator it=v->constBegin(); it!=v->constEnd(); ++it) { 0074 const auto &dep = dependencies(*it, scope); 0075 ret += QSet<QString>(dep.begin(), dep.end()); 0076 } 0077 } break; 0078 case Object::container: { 0079 const Container *c = static_cast<const Container*>(o); 0080 int skip=c->bvarCount(); 0081 QStringList newScope=scope+c->bvarStrings(); 0082 if(c->containerType()==Container::declare) { 0083 newScope.append(static_cast<const Ci*>(*c->constBegin())->name()); 0084 skip++; 0085 } 0086 0087 for(Container::const_iterator it=c->constBegin()+skip, itEnd=c->constEnd(); it!=itEnd; ++it) { 0088 const auto &dep = dependencies(*it, newScope); 0089 ret += QSet<QString>(dep.begin(), dep.end()); 0090 } 0091 } break; 0092 case Object::apply: { 0093 const Apply* c = static_cast<const Apply*>(o); 0094 Apply::const_iterator it = c->firstValue()/*, first = c->firstValue()*/; 0095 0096 Object* ul=c->ulimit(), *dl=c->dlimit(), *domain=c->domain(); 0097 0098 //uplimit and downlimit are in the parent scope 0099 if(ul) { 0100 const auto &dep = dependencies(ul, scope); 0101 ret += QSet<QString>(dep.begin(), dep.end()); 0102 } 0103 if(dl) { 0104 const auto &dep = dependencies(dl, scope); 0105 ret += QSet<QString>(dep.begin(), dep.end()); 0106 } 0107 if(domain) { 0108 const auto &dep = dependencies(domain, scope); 0109 ret += QSet<QString>(dep.begin(), dep.end()); 0110 } 0111 0112 if(c->firstOperator()==Operator::function) { 0113 const auto &dep = dependencies(c->m_params[0], scope); 0114 ret += QSet<QString>(dep.begin(), dep.end()); 0115 } 0116 0117 QStringList newScope=scope+c->bvarStrings(); 0118 for(; it!=c->constEnd(); ++it) { 0119 const auto &dep = dependencies(*it, newScope); 0120 ret += QSet<QString>(dep.begin(), dep.end()); 0121 } 0122 } break; 0123 case Object::none: 0124 case Object::custom: 0125 case Object::value: 0126 case Object::oper: 0127 break; 0128 } 0129 0130 return ret.values(); 0131 } 0132 0133 bool hasTheVar(const QSet<QString> & vars, const Object * o) 0134 { 0135 if(!o) 0136 return false; 0137 0138 bool found=false; 0139 const Ci* cand; 0140 switch(o->type()) { 0141 case Object::vector: { 0142 const Vector *v=static_cast<const Vector*>(o); 0143 Vector::const_iterator it, itEnd=v->constEnd(); 0144 for(it=v->constBegin(); it!=itEnd; ++it) { 0145 found |= hasTheVar(vars, *it); 0146 } 0147 } break; 0148 case Object::matrix: { 0149 const Matrix *v=static_cast<const Matrix*>(o); 0150 Matrix::const_iterator it, itEnd=v->constEnd(); 0151 for(it=v->constBegin(); it!=itEnd; ++it) { 0152 found |= hasTheVar(vars, *it); 0153 } 0154 } break; 0155 case Object::matrixrow: { 0156 const MatrixRow *v=static_cast<const MatrixRow*>(o); 0157 MatrixRow::const_iterator it, itEnd=v->constEnd(); 0158 for(it=v->constBegin(); it!=itEnd; ++it) { 0159 found |= hasTheVar(vars, *it); 0160 } 0161 } break; 0162 case Object::list: { 0163 const List *v=static_cast<const List*>(o); 0164 List::const_iterator it, itEnd=v->constEnd(); 0165 for(it=v->constBegin(); it!=itEnd; ++it) { 0166 found |= hasTheVar(vars, *it); 0167 } 0168 } break; 0169 case Object::container: { 0170 const Container *c=static_cast<const Container*>(o); 0171 const auto &bvarString = c->bvarStrings(); 0172 QSet<QString> bvars=QSet<QString>(bvarString.begin(), bvarString.end()); 0173 QSet<QString> varsCopy=vars; 0174 foreach(const QString &var, bvars) { 0175 varsCopy.remove(var); 0176 } 0177 found=hasTheVar(varsCopy, c); 0178 } break; 0179 case Object::apply: { 0180 const Apply *c=static_cast<const Apply*>(o); 0181 const auto &bvarString = c->bvarStrings(); 0182 QSet<QString> bvars=QSet<QString>(bvarString.begin(), bvarString.end()); 0183 QSet<QString> varsCopy=vars; 0184 foreach(const QString &var, bvars) { 0185 varsCopy.remove(var); 0186 } 0187 found=hasTheVar(varsCopy, c); 0188 } break; 0189 case Object::variable: 0190 cand=static_cast<const Ci*>(o); 0191 found=vars.contains(cand->name()); 0192 break; 0193 case Object::value: 0194 case Object::custom: 0195 case Object::oper: 0196 case Object::none: 0197 found=false; 0198 break; 0199 } 0200 return found; 0201 } 0202 0203 bool hasTheVar(const QSet<QString> & vars, const Container* c) 0204 { 0205 bool found=false; 0206 if(c->containerType()!=Container::bvar) { 0207 Container::const_iterator it=c->constBegin(), itEnd=c->constEnd(); 0208 for(; !found && it!=itEnd; ++it) { 0209 found=hasTheVar(vars, *it); 0210 } 0211 } 0212 return found; 0213 } 0214 0215 bool hasTheVar(const QSet<QString> & vars, const Apply* a) 0216 { 0217 bool found=hasTheVar(vars, a->ulimit()) || hasTheVar(vars, a->dlimit()) || hasTheVar(vars, a->domain()); 0218 Apply::const_iterator it=a->firstValue(), itEnd=a->constEnd(); 0219 for(; !found && it!=itEnd; ++it) { 0220 found=hasTheVar(vars, *it); 0221 } 0222 return found; 0223 } 0224 0225 bool isLambda(const Object* o) 0226 { 0227 return o->isContainer() && static_cast<const Container*>(o)->containerType()==Container::lambda; 0228 } 0229 0230 bool hasVars(const Analitza::Object* o, const QStringList& bvars) 0231 { 0232 Q_ASSERT(o); 0233 0234 bool r=false; 0235 switch(o->type()) { 0236 case Object::variable: { 0237 Ci *i = (Ci*) o; 0238 r=!bvars.contains(i->name()); 0239 0240 } break; 0241 case Object::vector: { 0242 Vector *v=(Vector*) o; 0243 for(Vector::const_iterator it=v->constBegin(); it!=v->constEnd(); ++it) { 0244 r |= hasVars(*it, bvars); 0245 } 0246 } break; 0247 case Object::matrix: { 0248 Matrix *v=(Matrix*) o; 0249 for(Matrix::const_iterator it=v->constBegin(); it!=v->constEnd(); ++it) { 0250 r |= hasVars(*it, bvars); 0251 } 0252 } break; 0253 case Object::matrixrow: { 0254 MatrixRow *v=(MatrixRow*) o; 0255 for(MatrixRow::const_iterator it=v->constBegin(); it!=v->constEnd(); ++it) { 0256 r |= hasVars(*it, bvars); 0257 } 0258 } break; 0259 case Object::list: { 0260 List *v=(List*) o; 0261 for(List::const_iterator it=v->constBegin(); it!=v->constEnd(); ++it) { 0262 r |= hasVars(*it, bvars); 0263 } 0264 } break; 0265 case Object::container: { 0266 const Container *c = (const Container*) o; 0267 0268 QStringList newScope=bvars+c->bvarStrings(); 0269 Container::const_iterator it=c->m_params.constBegin(), itEnd=c->m_params.constEnd(); 0270 if(c->containerType()==Container::declare) { 0271 newScope += static_cast<const Ci*>(*c->constBegin())->name(); 0272 ++it; 0273 } 0274 0275 for(; it!=itEnd; ++it) { 0276 r |= hasVars(*it, newScope); 0277 } 0278 } break; 0279 case Object::apply: { 0280 const Apply *c = (const Apply*) o; 0281 0282 const QStringList scope=bvars+c->bvarStrings(); 0283 Object* ul=c->ulimit(), *dl=c->dlimit(), *dn=c->domain(); 0284 0285 //uplimit and downlimit are in the parent scope 0286 if(ul) r |= hasVars(ul, bvars); 0287 if(dl) r |= hasVars(dl, bvars); 0288 if(dn) r |= hasVars(dn, bvars); 0289 0290 Apply::const_iterator it = c->firstValue(); 0291 for(; !r && it!=c->constEnd(); ++it) { 0292 r |= hasVars(*it, scope); 0293 } 0294 } break; 0295 case Object::none: 0296 case Object::value: 0297 case Object::oper: 0298 case Object::custom: 0299 r=false; 0300 } 0301 return r; 0302 } 0303 0304 struct ObjectWalker : public AbstractExpressionVisitor 0305 { 0306 ObjectWalker(const QByteArray& pref) : ind(0), m_prefix(pref) {} 0307 0308 virtual QVariant visit(const None* var) override 0309 { qDebug() << prefix().constData() << "| none: " << var->toString(); return QString(); } 0310 0311 virtual QVariant visit(const Operator* root) override 0312 { qDebug() << prefix().constData() << "| operator: " << root->toString(); return QString(); } 0313 0314 virtual QVariant visit(const Ci* var) override 0315 { 0316 QString value; 0317 if(var->depth()>=0) 0318 value="stack("+QString::number(var->depth())+')'; 0319 else 0320 value=QStringLiteral("symbols"); 0321 0322 qDebug() << prefix().constData() << "| variable: " << var->name() << "depth:" << var->depth() << "Val:" << value; 0323 return QString(); 0324 } 0325 0326 virtual QVariant visit(const Cn* num) override 0327 { qDebug() << prefix().constData() << "| num: " << num->value() << " format: " << num->format(); return QString(); } 0328 0329 virtual QVariant visit(const CustomObject* c) override 0330 { qDebug() << prefix().constData() << "| custom " << c; return QString(); } 0331 0332 0333 virtual QVariant visit(const Container* c) override 0334 { 0335 qDebug() << prefix().constData() << "| cont: " << c->tagName();// << "=" << c->toString(); 0336 ind++; 0337 for(Container::const_iterator it=c->m_params.constBegin(); it<c->constEnd(); ++it) 0338 visitNow(*it); 0339 ind--; 0340 return QString(); 0341 } 0342 0343 virtual QVariant visit(const Apply* c) override 0344 { 0345 qDebug() << prefix().constData() << "| apply op:" << c->firstOperator().toString(); 0346 ind++; 0347 if(c->ulimit()) { qDebug() << prefix().constData() << "ul: "; visitNow(c->ulimit()); } 0348 if(c->dlimit()) { qDebug() << prefix().constData() << "dl: "; visitNow(c->dlimit()); } 0349 if(!c->bvarCi().isEmpty()) { qDebug() << prefix().constData() << "bvars: " << c->bvarStrings(); } 0350 0351 for(Apply::const_iterator it=c->m_params.constBegin(); it<c->constEnd(); ++it) 0352 visitNow(*it); 0353 ind--; 0354 return QString(); 0355 } 0356 0357 virtual QVariant visit(const Vector* v) override 0358 { 0359 qDebug() << prefix().constData() << "| vector: " << v->size(); 0360 ind++; 0361 for(Vector::const_iterator it=v->constBegin(); it!=v->constEnd(); ++it) 0362 visitNow(*it); 0363 ind--; 0364 return QString(); 0365 } 0366 0367 virtual QVariant visit(const List* v) override 0368 { 0369 qDebug() << prefix().constData() << "| list: " << v->size(); 0370 ind++; 0371 for(List::const_iterator it=v->constBegin(); it!=v->constEnd(); ++it) 0372 visitNow(*it); 0373 ind--; 0374 return QString(); 0375 } 0376 0377 virtual QVariant visit(const Matrix* m) override { 0378 qDebug() << prefix().constData() << "| matrix: "; 0379 ind++; 0380 for(Matrix::const_iterator it=m->constBegin(); it!=m->constEnd(); ++it) 0381 visitNow(*it); 0382 ind--; 0383 return QString(); 0384 } 0385 0386 virtual QVariant visit(const MatrixRow* m) override { 0387 qDebug() << prefix().constData() << "| matrix: "; 0388 ind++; 0389 for(MatrixRow::const_iterator it=m->constBegin(); it!=m->constEnd(); ++it) 0390 visitNow(*it); 0391 ind--; 0392 return QString(); 0393 } 0394 0395 QByteArray prefix() 0396 { 0397 QByteArray ret(m_prefix); 0398 for(int i=0; i<ind; i++) 0399 ret += " |_____"; 0400 return ret; 0401 } 0402 0403 void visitNow(const Object* o) { if(o) o->accept(this); else qDebug() << prefix().constData() << "Null" ;} 0404 0405 QVariant result() const override { return QString(); } 0406 0407 int ind; 0408 QByteArray m_prefix; 0409 }; 0410 0411 void objectWalker(const Analitza::Expression& o, const QByteArray& prefix) 0412 { 0413 objectWalker(o.tree(), prefix); 0414 } 0415 0416 void objectWalker(const Object* root, const QByteArray& prefix) 0417 { 0418 ObjectWalker o(prefix); 0419 o.visitNow(root); 0420 0421 qDebug() << prefix.constData() << ';'; 0422 } 0423 0424 bool equalTree(const Object * o1, const Object * o2) 0425 { 0426 Q_ASSERT((o1 && o2) || (!o1 && !o2)); 0427 if(o1==o2) 0428 return true; 0429 else if(o1->type()!=o2->type()) 0430 return false; 0431 0432 bool eq = false; 0433 switch(o2->type()) { 0434 case Object::variable: 0435 eq = *static_cast<const Ci*>(o1)==*static_cast<const Ci*>(o2); 0436 break; 0437 case Object::value: 0438 eq = *static_cast<const Cn*>(o1)==*static_cast<const Cn*>(o2); 0439 break; 0440 case Object::container: 0441 eq = *static_cast<const Container*>(o1)==*static_cast<const Container*>(o2); 0442 break; 0443 case Object::oper: 0444 eq = *static_cast<const Operator*>(o1)==*static_cast<const Operator*>(o2); 0445 break; 0446 case Object::vector: 0447 eq = *static_cast<const Vector*>(o1)==*static_cast<const Vector*>(o2); 0448 break; 0449 case Object::list: 0450 eq = *static_cast<const List*>(o1)==*static_cast<const List*>(o2); 0451 break; 0452 case Object::apply: 0453 eq = *static_cast<const Apply*>(o1)==*static_cast<const Apply*>(o2); 0454 break; 0455 case Object::custom: 0456 eq = *static_cast<const CustomObject*>(o1)==*static_cast<const CustomObject*>(o2); 0457 break; 0458 case Object::matrix: 0459 eq = *static_cast<const Matrix*>(o1)==*static_cast<const Matrix*>(o2); 0460 break; 0461 case Object::matrixrow: 0462 eq = *static_cast<const MatrixRow*>(o1)==*static_cast<const MatrixRow*>(o2); 0463 break; 0464 case Object::none: 0465 eq=false; 0466 Q_ASSERT(false && "Should not get here"); 0467 break; 0468 } 0469 return eq; 0470 } 0471 0472 QVariant expressionToVariant(const Analitza::Expression& res) 0473 { 0474 QVariant ret; 0475 if(res.isString()) { 0476 ret = res.stringValue(); 0477 } else if(res.isVector() || res.isList()) { 0478 QVariantList vals; 0479 0480 QList<Analitza::Expression> expressions = res.toExpressionList(); 0481 foreach(const Analitza::Expression& exp, expressions) { 0482 vals << expressionToVariant(exp); 0483 } 0484 0485 ret = vals; 0486 } else if(res.isReal()) { 0487 Analitza::Cn val = res.toReal(); 0488 switch(val.format()) { 0489 case Analitza::Cn::Boolean: 0490 ret = val.isTrue(); 0491 break; 0492 case Analitza::Cn::Integer: 0493 ret = int(val.value()); 0494 break; 0495 case Analitza::Cn::Char: 0496 ret = val.character(); 0497 break; 0498 case Analitza::Cn::Complex: //TODO: figure out complex numbers on QVariant 0499 case Analitza::Cn::Real: 0500 ret = val.value(); 0501 break; 0502 } 0503 } else 0504 ret = res.toString(); 0505 0506 return ret; 0507 } 0508 0509 Analitza::Expression variantToExpression(const QVariant& v) 0510 { 0511 if(v.type() == QVariant::String) 0512 return Analitza::Expression(v.toString()); 0513 else if(v.canConvert(QVariant::Double)) 0514 return Analitza::Expression(Analitza::Cn(v.toReal())); 0515 else if(v.canConvert(QVariant::List)) { 0516 QVariantList list = v.toList(); 0517 QList<Analitza::Expression> expressionList; 0518 0519 foreach(const QVariant& elem, list) { 0520 expressionList << variantToExpression(elem); 0521 } 0522 0523 return Analitza::Expression::constructList(expressionList); 0524 } else if(v.canConvert<QObject*>()) { 0525 return Analitza::Expression::constructCustomObject(v, nullptr); 0526 } 0527 0528 Q_ASSERT(false && "couldn't figure out the type"); 0529 return Analitza::Expression(); 0530 } 0531 0532 QString listToString(const List* list) 0533 { 0534 QString ret; 0535 for(List::const_iterator it=list->constBegin(), itEnd=list->constEnd(); it!=itEnd; ++it) 0536 ret += static_cast<const Cn*>(*it)->character(); 0537 return ret; 0538 } 0539 0540 template<class T, class Tit, class Tcontained = Object> 0541 T* replaceDepthTemplate(int depth, T* tree, Object* towhat) 0542 { 0543 Tit it=tree->begin(), itEnd=tree->end(); 0544 for(; it!=itEnd; ++it) 0545 *it = static_cast<Tcontained*>(replaceDepth(depth, *it, towhat)); 0546 return tree; 0547 } 0548 0549 Object* replaceDepth(int depth, Object* tree, Object* towhat) 0550 { 0551 if(!tree) 0552 return nullptr; 0553 0554 Q_ASSERT(depth>=0); 0555 switch(tree->type()) { 0556 case Object::value: 0557 case Object::custom: 0558 case Object::none: 0559 case Object::oper: 0560 break; 0561 case Object::list: 0562 return replaceDepthTemplate<List, List::iterator>(depth, static_cast<List*>(tree), towhat); 0563 case Object::vector: 0564 return replaceDepthTemplate<Vector, Vector::iterator>(depth, static_cast<Vector*>(tree), towhat); 0565 case Object::matrix: 0566 return replaceDepthTemplate<Matrix, Matrix::iterator, MatrixRow>(depth, static_cast<Matrix*>(tree), towhat); 0567 case Object::matrixrow: 0568 return replaceDepthTemplate<MatrixRow, MatrixRow::iterator>(depth, static_cast<MatrixRow*>(tree), towhat); 0569 case Object::container: 0570 return replaceDepthTemplate<Container, Container::iterator>(depth, static_cast<Container*>(tree), towhat); 0571 case Object::variable: { 0572 Ci* var=(Ci*) tree; 0573 if(var->depth()==depth) { 0574 delete tree; 0575 tree=towhat->copy(); 0576 } 0577 } break; 0578 case Object::apply: { 0579 Apply* a=static_cast<Apply*>(tree); 0580 Apply::iterator it=a->firstValue(), itEnd=a->end(); 0581 for(; it!=itEnd; ++it) 0582 *it=replaceDepth(depth, *it, towhat); 0583 0584 a->domain()=replaceDepth(depth, a->domain(), towhat); 0585 a->dlimit()=replaceDepth(depth, a->ulimit(), towhat); 0586 a->ulimit()=replaceDepth(depth, a->dlimit(), towhat); 0587 return a; 0588 } break; 0589 } 0590 return tree; 0591 } 0592 0593 template<class T, class Tit> 0594 int countDepthTemplate(int depth, const T* tree) 0595 { 0596 int ret=0; 0597 Tit it=tree->constBegin(), itEnd=tree->constEnd(); 0598 for(; it!=itEnd; ++it) 0599 ret += countDepth(depth, *it); 0600 return ret; 0601 } 0602 0603 int countDepth(int depth, const Object* tree) 0604 { 0605 if(!tree) 0606 return 0; 0607 0608 Q_ASSERT(depth>=0); 0609 switch(tree->type()) { 0610 case Object::value: 0611 case Object::custom: 0612 case Object::none: 0613 case Object::oper: 0614 break; 0615 case Object::list: 0616 return countDepthTemplate<List, List::const_iterator>(depth, static_cast<const List*>(tree)); 0617 case Object::vector: 0618 return countDepthTemplate<Vector, Vector::const_iterator>(depth, static_cast<const Vector*>(tree)); 0619 case Object::matrix: 0620 return countDepthTemplate<Matrix, Matrix::const_iterator>(depth, static_cast<const Matrix*>(tree)); 0621 case Object::matrixrow: 0622 return countDepthTemplate<MatrixRow, MatrixRow::const_iterator>(depth, static_cast<const MatrixRow*>(tree)); 0623 case Object::container: 0624 return countDepthTemplate<Container, Container::const_iterator>(depth, static_cast<const Container*>(tree)); 0625 case Object::variable: { 0626 Ci* var=(Ci*) tree; 0627 return var->depth()==depth; 0628 } break; 0629 case Object::apply: { 0630 const Apply* a=static_cast<const Apply*>(tree); 0631 Apply::const_iterator it=a->firstValue(), itEnd=a->constEnd(); 0632 int ret=0; 0633 for(; it!=itEnd; ++it) 0634 ret+=countDepth(depth, *it); 0635 0636 ret+=countDepth(depth, a->domain()); 0637 ret+=countDepth(depth, a->ulimit()); 0638 ret+=countDepth(depth, a->dlimit()); 0639 return ret; 0640 } break; 0641 } 0642 return 0; 0643 } 0644 0645 QString generateDependencyGraph(const Variables* v) 0646 { 0647 QStringList special=QStringList() << QStringLiteral("check"); 0648 QString ret; 0649 ret += QLatin1String("digraph G {\n"); 0650 0651 foreach(const QString& n, special) { 0652 ret += '\t'+n+" [shape=doublecircle];\n"; 0653 } 0654 ret += '\n'; 0655 0656 for(Variables::const_iterator it=v->constBegin(), itEnd=v->constEnd(); it!=itEnd; ++it) { 0657 QString current = it.key(); 0658 QStringList deps = dependencies(it.value(), QStringList()); 0659 0660 foreach(const QString& d, deps) { 0661 const Object* o=v->value(d); 0662 if(o && isLambda(o)) { 0663 ret += '\t'+current+" -> "+d+";\n"; 0664 } 0665 } 0666 } 0667 0668 ret += QLatin1String("}\n"); 0669 return ret; 0670 } 0671 0672 }