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 }