File indexing completed on 2024-04-28 03:40:46

0001 /*************************************************************************************
0002  *  Copyright (C) 2008 by Aleix Pol <aleixpol@kde.org>                               *
0003  *                                                                                   *
0004  *  This program is free software; you can redistribute it and/or                    *
0005  *  modify it under the terms of the GNU General Public License                      *
0006  *  as published by the Free Software Foundation; either version 2                   *
0007  *  of the License, or (at your option) any later version.                           *
0008  *                                                                                   *
0009  *  This program is distributed in the hope that it will be useful,                  *
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of                   *
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                    *
0012  *  GNU General Public License for more details.                                     *
0013  *                                                                                   *
0014  *  You should have received a copy of the GNU General Public License                *
0015  *  along with this program; if not, write to the Free Software                      *
0016  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA   *
0017  *************************************************************************************/
0018 
0019 #include "stringexpressionwriter.h"
0020 #include "value.h"
0021 #include "vector.h"
0022 #include "container.h"
0023 #include <QStringList>
0024 #include "list.h"
0025 #include "variable.h"
0026 #include "apply.h"
0027 #include "analitzautils.h"
0028 #include "matrix.h"
0029 
0030 using namespace Analitza;
0031 
0032 const double StringExpressionWriter::MIN_PRINTABLE_VALUE = 0.0000000000001; // since the precision we choose for 'G' is 12
0033 
0034 template <class T>
0035 QStringList StringExpressionWriter::allValues(T it, const T& itEnd, AbstractExpressionVisitor* writer)
0036 {
0037     QStringList elements;
0038     for(; it!=itEnd; ++it)
0039         elements += (*it)->accept(writer).toString();
0040     
0041     return elements;
0042 }
0043 
0044 
0045 QMap<Operator::OperatorType, QString> initOperators()
0046 {
0047     QMap<Operator::OperatorType, QString> ret;
0048     ret.insert(Operator::plus, QStringLiteral("+"));
0049     ret.insert(Operator::times, QStringLiteral("*"));
0050     ret.insert(Operator::divide, QStringLiteral("/"));
0051     ret.insert(Operator::eq, QStringLiteral("="));
0052     ret.insert(Operator::neq, QStringLiteral("!="));
0053     ret.insert(Operator::lt, QStringLiteral("<"));
0054     ret.insert(Operator::leq, QStringLiteral("<="));
0055     ret.insert(Operator::gt, QStringLiteral(">"));
0056     ret.insert(Operator::geq, QStringLiteral(">="));
0057     ret.insert(Operator::power, QStringLiteral("^"));
0058     ret.insert(Operator::minus, QStringLiteral("-"));
0059     return ret;
0060 }
0061 
0062 const QMap<Operator::OperatorType, QString> StringExpressionWriter::s_operators=initOperators();
0063 
0064 StringExpressionWriter::StringExpressionWriter(const Object* o)
0065 {
0066     if (o)
0067         m_result=o->accept(this);
0068 }
0069 
0070 QVariant StringExpressionWriter::visit(const Ci* var)
0071 {
0072     return var->name();
0073 }
0074 
0075 QVariant StringExpressionWriter::visit(const Operator* op)
0076 {
0077     return op->name();
0078 }
0079 
0080 QVariant StringExpressionWriter::visit(const Vector* vec)
0081 {
0082     return QStringLiteral("vector { %1 }").arg(allValues<Vector::const_iterator>(vec->constBegin(), vec->constEnd(), this).join(QStringLiteral(", ")));
0083 }
0084 
0085 QVariant StringExpressionWriter::visit(const Matrix* m)
0086 {
0087     return QStringLiteral("matrix { %1 }").arg(allValues(m->constBegin(), m->constEnd(), this).join(QStringLiteral(", ")));
0088 }
0089 
0090 QVariant StringExpressionWriter::visit(const MatrixRow* mr)
0091 {
0092     return QStringLiteral("matrixrow { %1 }").arg(allValues(mr->constBegin(), mr->constEnd(), this).join(QStringLiteral(", ")));
0093 }
0094 
0095 QVariant StringExpressionWriter::visit(const List* vec)
0096 {
0097     if(!vec->isEmpty() && vec->at(0)->type()==Object::value && static_cast<Cn*>(vec->at(0))->format()==Cn::Char)
0098         return QVariant::fromValue<QString>(QStringLiteral("\"")+AnalitzaUtils::listToString(vec)+'\"');
0099     else
0100         return QVariant::fromValue<QString>(QStringLiteral("list { %1 }").arg(allValues<List::const_iterator>(vec->constBegin(), vec->constEnd(), this).join(QStringLiteral(", "))));
0101 }
0102 
0103 QVariant StringExpressionWriter::visit(const Cn* var)
0104 {
0105     if(var->isBoolean())
0106         return var->isTrue() ? "true" : "false";
0107     else if(var->isCharacter())
0108         return QString(var->character());
0109     else if(var->isComplex()) {
0110         QString realpart;
0111         QString imagpart;
0112         bool realiszero = false;
0113         const auto complex = var->complexValue();
0114         if (qAbs(complex.real()) > MIN_PRINTABLE_VALUE)
0115             realpart = QString::number(complex.real(), 'g', 12);
0116         else
0117             realiszero = true;
0118 
0119         if (!qFuzzyCompare(qAbs(complex.imag()), 1)) {
0120             if (qAbs(complex.imag()) > MIN_PRINTABLE_VALUE) {
0121                 if (!realiszero && complex.imag()>0.)
0122                     realpart += QLatin1Char('+');
0123                 imagpart = QString::number(complex.imag(), 'g', 12);
0124                 imagpart += QStringLiteral("*i");
0125             }
0126         } else {
0127             if (!realiszero)
0128                 realpart += QLatin1Char('+');
0129             if (qFuzzyCompare(complex.imag(), 1))
0130                 imagpart = QStringLiteral("i");
0131             else
0132                 imagpart = QStringLiteral("-i");
0133         }
0134 
0135         return QVariant::fromValue<QString>(realpart+imagpart);
0136     }
0137     else
0138         return QString::number(var->value(), 'g', 12);
0139 }
0140 
0141 int StringExpressionWriter::weight(const Operator* op, int size, int pos)
0142 {
0143     switch(op->operatorType()) {
0144         case Operator::lt:
0145         case Operator::gt:
0146         case Operator::eq:
0147         case Operator::neq:
0148         case Operator::leq:
0149         case Operator::geq:
0150             return 1;
0151         case Operator::plus:
0152             return 2;
0153         case Operator::minus:
0154             return size==1 ? 8 : 3;
0155         case Operator::times:
0156             return 4;
0157         case Operator::divide:
0158             return 5 + (pos>0 ? 0 : 1);
0159         case Operator::_and:
0160         case Operator::_or:
0161         case Operator::_xor:
0162             return 6;
0163         case Operator::power:
0164             return 7 + (pos>0 ? 0 : 1);
0165         default:
0166             return 1000;
0167     }
0168 }
0169 
0170 QVariant StringExpressionWriter::visit(const Analitza::Apply* a)
0171 {
0172     Operator op=a->firstOperator();
0173     QStringList ret;
0174     QString toret;
0175     QString bounds;
0176     QStringList bvars=a->bvarStrings();
0177     
0178     if(a->ulimit() || a->dlimit()) {
0179         bounds += '=';
0180         if(a->dlimit())
0181             bounds += a->dlimit()->accept(this).toString();
0182         bounds += QLatin1String("..");
0183         if(a->ulimit())
0184             bounds += a->ulimit()->accept(this).toString();
0185     }
0186     else if(a->domain())
0187         bounds += '@'+a->domain()->accept(this).toString();
0188     
0189     int i = 0;
0190     foreach(Object* o, a->m_params) {
0191         Object::ObjectType type=o->type();
0192         switch(type) {
0193             case Object::oper:
0194                 Q_ASSERT(false);
0195                 break;
0196             case Object::variable:
0197                 ret << static_cast<const Ci*>(o)->accept(this).toString();
0198                 break;
0199             case Object::apply: {
0200                 const Apply *c = (const Apply*) o;
0201                 QString s = c->accept(this).toString();
0202                 if(s_operators.contains(op.operatorType()) && !c->isUnary()) {
0203                     Operator child_op = c->firstOperator();
0204                     
0205                     if(child_op.operatorType() && weight(&op, c->countValues(), -1)>weight(&child_op, c->countValues(), i))
0206                         s=QStringLiteral("(%1)").arg(s);
0207                 }
0208                 ret << s;
0209             }    break;
0210             default:
0211                 ret << o->accept(this).toString();
0212                 break;
0213         }
0214         ++i;
0215     }
0216     
0217     bool func=op.operatorType()==Operator::function;
0218     if(func) {
0219         QString n = ret.takeFirst();
0220         if(a->m_params.first()->type()!=Object::variable)
0221             n='('+n+')';
0222         
0223         toret += QStringLiteral("%1(%2)").arg(n, ret.join(QStringLiteral(", ")));
0224     } else if(op.operatorType()==Operator::selector) {
0225         if(a->m_params.last()->isApply()) {
0226             const Apply* a1=static_cast<const Apply*>(a->m_params.last());
0227             if(s_operators.contains(a1->firstOperator().operatorType()))
0228                 ret.last()='('+ret.last()+')';
0229         }
0230         
0231         toret += QStringLiteral("%1[%2]").arg(ret.last(), ret.first());
0232     } else if(ret.count()>1 && s_operators.contains(op.operatorType())) {
0233         toret += ret.join(s_operators.value(op.operatorType()));
0234     } else if(ret.count()==1 && op.operatorType()==Operator::minus)
0235         toret += '-'+ret[0];
0236     else {
0237         QString bounding;
0238         if(!bounds.isEmpty() || !bvars.isEmpty()) {
0239             if(bvars.count()!=1) bounding +='(';
0240             bounding += bvars.join(QStringLiteral(", "));
0241             if(bvars.count()!=1) bounding +=')';
0242             
0243             bounding = ':'+bounding +bounds;
0244         }
0245             
0246         toret += QStringLiteral("%1(%2%3)").arg(op.accept(this).toString(), ret.join(QStringLiteral(", ")), bounding);
0247     }
0248     
0249     return toret;
0250 }
0251 
0252 QVariant StringExpressionWriter::visit(const Container* var)
0253 {
0254     QStringList ret = allValues(var->constBegin(), var->constEnd(), this);
0255     
0256     QString toret;
0257     switch(var->containerType()) {
0258         case Container::declare:
0259             toret += ret.join(QStringLiteral(":="));
0260             break;
0261         case Container::lambda: {
0262             QString last=ret.takeLast();
0263             QStringList bvars = var->bvarStrings();
0264             if(bvars.count()!=1) toret +='(';
0265             toret += bvars.join(QStringLiteral(", "));
0266             if(bvars.count()!=1) toret +=')';
0267             toret += "->" + last;
0268         }    break;
0269         case Container::math:
0270             toret += ret.join(QStringLiteral("; "));
0271             break;
0272         case Container::uplimit: //x->(n1..n2) is put at the same time
0273         case Container::downlimit:
0274             break;
0275         case Container::bvar:
0276             if(ret.count()>1) toret += '(';
0277             toret += ret.join(QStringLiteral(", "));
0278             if(ret.count()>1) toret += ')';
0279             break;
0280         case Container::piece:
0281             toret += ret[1]+" ? "+ret[0];
0282             break;
0283         case Container::otherwise:
0284             toret += "? "+ret[0];
0285             break;
0286         default:
0287             toret += var->tagName()+" { "+ret.join(QStringLiteral(", "))+" }";
0288             break;
0289     }
0290     return toret;
0291 }
0292 
0293 QVariant StringExpressionWriter::visit(const CustomObject*)
0294 {
0295     return "CustomObject";
0296 }
0297 
0298 QVariant StringExpressionWriter::visit(const None* )
0299 {
0300     return QString();
0301 }