File indexing completed on 2024-12-22 04:17:54

0001 /***************************************************************************
0002                                  enodes.cpp
0003                                  ----------      
0004     begin                : Feb 12 2004
0005     copyright            : (C) 2004 The University of Toronto
0006     email                : netterfield@astro.utoronto.ca
0007  ***************************************************************************/
0008 
0009 /***************************************************************************
0010  *                                                                         *
0011  *   This program is free software; you can redistribute it and/or modify  *
0012  *   it under the terms of the GNU General Public License as published by  *
0013  *   the Free Software Foundation; either version 2 of the License, or     *
0014  *   (at your option) any later version.                                   *
0015  *                                                                         *
0016  ***************************************************************************/
0017 
0018 #include "enodes.h"
0019 
0020 #include <assert.h>
0021 #include <math.h>
0022 #include <stdlib.h>
0023 #include <string.h>
0024 #include <qnamespace.h>
0025 #ifndef Q_OS_WIN32
0026 #include <unistd.h>
0027 #else
0028 #define strcasecmp _stricmp
0029 #endif
0030 
0031 
0032 
0033 #include <QMutex>
0034 #include <QRegExp>
0035 
0036 #include "datacollection.h"
0037 #include "debug.h"
0038 #include "math_kst.h"
0039 #include "objectstore.h"
0040 #include "doublecompare.h"
0041 
0042 KSTMATH_EXPORT int yyparse(Kst::ObjectStore *store);
0043 KSTMATH_EXPORT extern void *ParsedEquation;
0044 KSTMATH_EXPORT/*"C"*/ struct yy_buffer_state *yy_scan_string(const char*);
0045 KSTMATH_EXPORT struct yy_buffer_state *yy_scan_bytes(const char*, int);
0046 typedef struct yy_buffer_state *YY_BUFFER_STATE;
0047 KSTMATH_EXPORT void yy_delete_buffer(YY_BUFFER_STATE);
0048 
0049 using namespace Equations;
0050 using namespace Kst;
0051 
0052 static QMutex _mutex;
0053 
0054 QMutex& Equations::mutex() {
0055   return _mutex;
0056 }
0057 
0058 
0059 double Equations::interpret(ObjectStore *store, const char *txt, bool *ok, int len) {
0060   if (!txt || !*txt) {
0061     if (ok) {
0062       *ok = false;
0063     }
0064     return 0.0;
0065   }
0066 
0067   mutex().lock();
0068   YY_BUFFER_STATE b;
0069   if (len > 0) {
0070     b = yy_scan_bytes(txt, len);
0071   } else {
0072     b = yy_scan_string(txt);
0073   }
0074   int rc = yyparse(store);
0075   yy_delete_buffer(b);
0076   if (rc == 0) {
0077     Equations::Node *eq = static_cast<Equations::Node*>(ParsedEquation);
0078     ParsedEquation = 0L;
0079     mutex().unlock();
0080     Equations::Context ctx;
0081     ctx.sampleCount = 2;
0082     ctx.noPoint = Kst::NOPOINT;
0083     ctx.x = 0.0;
0084     ctx.xVector = 0L;
0085     Equations::FoldVisitor vis(&ctx, &eq);
0086     double v = eq->value(&ctx);
0087     delete eq;
0088     if (ok) {
0089       *ok = true;
0090     }
0091     return v;
0092   } else {
0093     ParsedEquation = 0L;
0094     mutex().unlock();
0095     if (ok) {
0096       *ok = false;
0097     }
0098     return 0.0;
0099   }
0100 }
0101 
0102 
0103 Node::Node() {
0104   _parentheses = false;
0105 }
0106 
0107 
0108 Node::~Node() {
0109 }
0110 
0111 
0112 bool Node::collectObjects(Kst::VectorMap&, Kst::ScalarMap&, Kst::StringMap&) {
0113   return true;
0114 }
0115 
0116 
0117 bool Node::takeVectors(const Kst::VectorMap&) {
0118   return true;
0119 }
0120 
0121 
0122 void Node::visit(NodeVisitor* v) {
0123   v->visitNode(this);
0124 }
0125 
0126 
0127 Kst::Object::UpdateType Node::update(Context *ctx) {
0128   Q_UNUSED(ctx)
0129   return Kst::Object::NoChange;
0130 }
0131 
0132 
0133 /////////////////////////////////////////////////////////////////
0134 BinaryNode::BinaryNode(Node *left, Node *right)
0135 : Node(), _left(left), _right(right) {
0136 }
0137 
0138 
0139 BinaryNode::~BinaryNode() {
0140   delete _left;
0141   _left = 0L;
0142   delete _right;
0143   _right = 0L;
0144 }
0145 
0146 
0147 bool BinaryNode::collectObjects(Kst::VectorMap& v, Kst::ScalarMap& s, Kst::StringMap& t) {
0148   bool ok = true;
0149   ok = _left->collectObjects(v, s, t) ? ok : false;
0150   ok = _right->collectObjects(v, s, t) ? ok : false;
0151   return ok;
0152 }
0153 
0154 
0155 bool BinaryNode::takeVectors(const Kst::VectorMap& c) {
0156   bool rc = _left->takeVectors(c);
0157   rc = _right->takeVectors(c) && rc;
0158   return rc;
0159 }
0160 
0161 
0162 void BinaryNode::visit(NodeVisitor* v) {
0163   v->visitBinaryNode(this);
0164 }
0165 
0166 
0167 Node *& BinaryNode::left() {
0168   return _left;
0169 }
0170 
0171 
0172 Node *& BinaryNode::right() {
0173   return _right;
0174 }
0175 
0176 
0177 Kst::Object::UpdateType BinaryNode::update(Context *ctx) {
0178   Kst::Object::UpdateType l = _left->update(ctx);
0179   Kst::Object::UpdateType r = _right->update(ctx);
0180 
0181   return (l == Kst::Object::Updated || r == Kst::Object::Updated) ? Kst::Object::Updated : Kst::Object::NoChange;
0182 }
0183 
0184 
0185 /////////////////////////////////////////////////////////////////
0186 Addition::Addition(Node *left, Node *right)
0187 : BinaryNode(left, right) {
0188   //printf("%p: New Addition: %p + %p\n", (void*)this, (void*)left, (void*)right);
0189 }
0190 
0191 
0192 Addition::~Addition() {
0193 }
0194 
0195 
0196 double Addition::value(Context *ctx) {
0197   return _left->value(ctx) + _right->value(ctx);
0198 }
0199 
0200 
0201 bool Addition::isConst() {
0202   return _left->isConst() && _right->isConst();
0203 }
0204 
0205 
0206 QString Addition::text() const {
0207   if (_parentheses) {
0208     return QString('(') + _left->text() + '+' + _right->text() + ')';
0209   } else {
0210     return _left->text() + '+' + _right->text();
0211   }
0212 }
0213 
0214 
0215 /////////////////////////////////////////////////////////////////
0216 Subtraction::Subtraction(Node *left, Node *right)
0217 : BinaryNode(left, right) {
0218   //printf("%p: New Subtraction: %p - %p\n", (void*)this, (void*)left, (void*)right);
0219 }
0220 
0221 
0222 Subtraction::~Subtraction() {
0223 }
0224 
0225 
0226 double Subtraction::value(Context *ctx) {
0227   return _left->value(ctx) - _right->value(ctx);
0228 }
0229 
0230 
0231 bool Subtraction::isConst() {
0232   return _left->isConst() && _right->isConst();
0233 }
0234 
0235 
0236 QString Subtraction::text() const {
0237   if (_parentheses) {
0238     return QString('(') + _left->text() + '-' + _right->text() + ')';
0239   } else {
0240     return _left->text() + '-' + _right->text();
0241   }
0242 }
0243 
0244 
0245 /////////////////////////////////////////////////////////////////
0246 Multiplication::Multiplication(Node *left, Node *right)
0247 : BinaryNode(left, right) {
0248   //printf("%p: New Multiplication: %p - %p\n", (void*)this, (void*)left, (void*)right);
0249 }
0250 
0251 
0252 Multiplication::~Multiplication() {
0253 }
0254 
0255 
0256 double Multiplication::value(Context *ctx) {
0257   return _left->value(ctx) * _right->value(ctx);
0258 }
0259 
0260 
0261 bool Multiplication::isConst() {
0262   return _left->isConst() && _right->isConst();
0263 }
0264 
0265 
0266 QString Multiplication::text() const {
0267   if (_parentheses) {
0268     return QString('(') + _left->text() + '*' + _right->text() + ')';
0269   } else {
0270     return _left->text() + '*' + _right->text();
0271   }
0272 }
0273 
0274 
0275 /////////////////////////////////////////////////////////////////
0276 Division::Division(Node *left, Node *right)
0277 : BinaryNode(left, right) {
0278   //printf("%p: New Division: %p - %p\n", (void*)this, (void*)left, (void*)right);
0279 }
0280 
0281 
0282 Division::~Division() {
0283 }
0284 
0285 
0286 double Division::value(Context *ctx) {
0287   return _left->value(ctx) / _right->value(ctx);
0288 }
0289 
0290 
0291 bool Division::isConst() {
0292   return _left->isConst() && _right->isConst();
0293 }
0294 
0295 
0296 QString Division::text() const {
0297   if (_parentheses) {
0298     return QString('(') + _left->text() + '/' + _right->text() + ')';
0299   } else {
0300     return _left->text() + '/' + _right->text();
0301   }
0302 }
0303 
0304 
0305 /////////////////////////////////////////////////////////////////
0306 Modulo::Modulo(Node *left, Node *right)
0307 : BinaryNode(left, right) {
0308   //printf("%p: New Modulo: %p - %p\n", (void*)this, (void*)left, (void*)right);
0309 }
0310 
0311 
0312 Modulo::~Modulo() {
0313 }
0314 
0315 
0316 double Modulo::value(Context *ctx) {
0317   return fmod(_left->value(ctx), _right->value(ctx));
0318 }
0319 
0320 
0321 bool Modulo::isConst() {
0322   return _left->isConst() && _right->isConst();
0323 }
0324 
0325 
0326 QString Modulo::text() const {
0327   if (_parentheses) {
0328     return QString('(') + _left->text() + '%' + _right->text() + ')';
0329   } else {
0330     return _left->text() + '%' + _right->text();
0331   }
0332 }
0333 
0334 
0335 /////////////////////////////////////////////////////////////////
0336 Power::Power(Node *left, Node *right)
0337 : BinaryNode(left, right) {
0338   //printf("%p: New Power: %p - %p\n", (void*)this, (void*)left, (void*)right);
0339 }
0340 
0341 
0342 Power::~Power() {
0343 }
0344 
0345 
0346 double Power::value(Context *ctx) {
0347   return pow(_left->value(ctx), _right->value(ctx));
0348 }
0349 
0350 
0351 bool Power::isConst() {
0352   return _left->isConst() && _right->isConst();
0353 }
0354 
0355 
0356 QString Power::text() const {
0357   if (_parentheses) {
0358     return QString('(') + _left->text() + '^' + _right->text() + ')';
0359   } else {
0360     return _left->text() + '^' + _right->text();
0361   }
0362 }
0363 
0364 
0365 /////////////////////////////////////////////////////////////////
0366 
0367 static double cot(double x) {
0368   return 1.0/tan(x);
0369 }
0370 
0371 
0372 static double csc(double x) {
0373   return 1.0/sin(x);
0374 }
0375 
0376 
0377 static double sec(double x) {
0378   return 1.0/cos(x);
0379 }
0380 
0381 static double acosd(double x) {
0382   return 180.0/M_PI*acos(x);
0383 }
0384 
0385 static double asind(double x) {
0386   return 180.0/M_PI*asin(x);
0387 }
0388 
0389 static double atand(double x) {
0390   return 180.0/M_PI*atan(x);
0391 }
0392 
0393 static double cosd(double x) {
0394   return cos(fmod(x, 360.0)*M_PI/180.0);
0395 }
0396 
0397 static double cotd(double x) {
0398   return cot(fmod(x, 360.0)*M_PI/180.0);
0399 }
0400 
0401 static double cscd(double x) {
0402   return csc(fmod(x, 360.0)*M_PI/180.0);
0403 }
0404 
0405 static double secd(double x) {
0406   return sec(fmod(x, 360.0)*M_PI/180.0);
0407 }
0408 
0409 static double sind(double x) {
0410   return sin(fmod(x, 360.0)*M_PI/180.0);
0411 }
0412 
0413 static double tand(double x) {
0414   return tan(fmod(x, 360.0)*M_PI/180.0);
0415 }
0416 
0417 static double atanx(double *x) {
0418   return atan2(x[0],x[1]);
0419 }
0420 
0421 static double step(double x) {
0422   if (x>0.0) {
0423     return 1.0;
0424   } else {
0425     return 0.0;
0426   }
0427 }
0428 
0429 
0430 static struct {
0431   const char *name;
0432   double (*func)(double);
0433 } FTable[] = {
0434   {"abs",   &fabs},
0435   {"acos",  &acos},
0436   {"acosd", &acosd},
0437   {"asin",  &asin},
0438   {"asind", &asind},
0439   {"atan",  &atan},
0440   {"atand", &atand},
0441 #ifndef Q_OS_WIN32
0442   {"cbrt", &cbrt},
0443 #endif
0444   {"cos",  &cos},
0445   {"cosd", &cosd},
0446   {"cosh", &cosh},
0447   {"cot",  &cot},
0448   {"cotd", &cotd},
0449   {"csc",  &csc},
0450   {"cscd", &cscd},
0451   {"exp",  &exp},
0452   {"log",  &log10},
0453   {"ln",   &log},
0454   {"sec",  &sec},
0455   {"secd", &secd},
0456   {"sin",  &sin},
0457   {"sind", &sind},
0458   {"sinh", &sinh},
0459   {"sqrt", &sqrt},
0460   {"step", &step},
0461   {"tan",  &tan},
0462   {"tand", &tand},
0463   {"tanh", &tanh},
0464   {0, 0}
0465 };
0466 
0467 static struct {
0468   const char *name;
0469   double (*func)(double*);
0470 } F2Table[] = {
0471 
0472   {"atanx", &atanx},
0473   //{"atan2d", &atand2d},
0474   {0, 0}
0475 };
0476 
0477 Function::Function(char *name, ArgumentList *args)
0478 : Node(), _name(name), _args(args), _f(0L) {
0479   _argCount = 1; // Presently no functions take != 1 argument
0480   _inPid = 0L;
0481   _inScalars = 0L;
0482   _inVectors = 0L;
0483   _outScalars = 0L;
0484   _outVectors = 0L;
0485   _inArrayLens = 0L;
0486   _outArrayLens = 0L;
0487   _outputIndex = -424242;
0488   _localData = 0L;
0489   _outputVectorCnt = 0;
0490   _inputVectorCnt = 0;
0491   //printf("%p: New Function: %s - %p\n", (void*)this, name, (void*)args);
0492   for (int i = 0; FTable[i].name; ++i) {
0493     if (strcasecmp(FTable[i].name, name) == 0) {
0494       _f = (void*)FTable[i].func;
0495       break;
0496     }
0497   }
0498   if (!_f) {
0499     for (int i = 0; F2Table[i].name; ++i) {
0500       if (strcasecmp(F2Table[i].name, name) == 0) {
0501         _f = (void*)F2Table[i].func;
0502         _argCount = 2;
0503         break;
0504       }
0505     }
0506   }
0507 }
0508 
0509 
0510 Function::~Function() {
0511   free(_name);
0512   _name = 0L;
0513   delete _args;
0514   _args = 0L;
0515   _f = 0L;
0516   delete[] _inScalars;
0517   delete[] _inVectors;
0518   delete[] _outScalars;
0519   for (int i = 0; i < _outputVectorCnt; ++i) {
0520     free(_outVectors[i]);
0521   }
0522   delete[] _outVectors;
0523   delete[] _inArrayLens;
0524   delete[] _outArrayLens;
0525 }
0526 
0527 
0528 Kst::Object::UpdateType Function::update(Context *ctx) {
0529   _args->update(ctx);
0530   return Kst::Object::NoChange;
0531 }
0532 
0533 
0534 double Function::value(Context *ctx) {
0535   if (!_f) {
0536     return ctx->noPoint;
0537   }
0538 
0539   if (_argCount == 1) {
0540     double x = _args->at(0, ctx);
0541     return ((double (*)(double))_f)(x);
0542   } else if (_argCount > 1) {
0543     double *x = new double[_argCount];
0544     for (int i = 0; i < _argCount; ++i) {
0545       x[i] = _args->at(i, ctx);
0546     }
0547     double r = ((double (*)(double*))_f)(x);
0548     delete[] x;
0549     return r;
0550   } else {
0551     return ((double (*)())_f)();
0552   }
0553 }
0554 
0555 
0556 bool Function::isConst() {
0557   return _args->isConst();
0558 }
0559 
0560 
0561 bool Function::collectObjects(Kst::VectorMap& v, Kst::ScalarMap& s, Kst::StringMap& t) {
0562   return _args->collectObjects(v, s, t);
0563 }
0564 
0565 
0566 bool Function::takeVectors(const Kst::VectorMap& c) {
0567   return _args->takeVectors(c);
0568 }
0569 
0570 
0571 QString Function::text() const {
0572   return QString::fromLatin1(_name) + '(' + _args->text() + ')';
0573 }
0574 
0575 
0576 /////////////////////////////////////////////////////////////////
0577 ArgumentList::ArgumentList()
0578 : Node() {
0579   //printf("%p: New Argument List\n", (void*)this);
0580 }
0581 
0582 
0583 ArgumentList::~ArgumentList() {
0584   qDeleteAll(_args);
0585 }
0586 
0587 
0588 void ArgumentList::appendArgument(Node *arg) {
0589   _args.append(arg);
0590 }
0591 
0592 
0593 double ArgumentList::at(int arg, Context *ctx) {
0594   Node *n = _args.value(arg); // catches out-of-bounds
0595   if (n) {
0596     return n->value(ctx);
0597   }
0598   return ctx->noPoint;
0599 }
0600 
0601 
0602 bool ArgumentList::isConst() {
0603   foreach (Node *i, _args) {
0604     if (!i->isConst()) {
0605       return false;
0606     }
0607   }
0608   return true;
0609 }
0610 
0611 
0612 bool ArgumentList::collectObjects(Kst::VectorMap& v, Kst::ScalarMap& s, Kst::StringMap& t) {
0613   bool ok = true;
0614   foreach (Node *i, _args) {
0615     ok = i->collectObjects(v, s, t) ? ok : false;
0616   }
0617   return ok;
0618 }
0619 
0620 
0621 bool ArgumentList::takeVectors(const Kst::VectorMap& c) {
0622   bool rc = true;
0623   foreach (Node *i, _args) {
0624     rc = i->takeVectors(c) && rc;
0625   }
0626   return rc;
0627 }
0628 
0629 
0630 Node *ArgumentList::node(int idx) {
0631   return _args.at(idx);
0632 }
0633 
0634 
0635 Kst::Object::UpdateType ArgumentList::update(Context *ctx) {
0636   bool updated = false;
0637   foreach (Node *i, _args) {
0638     updated = updated || Kst::Object::Updated == i->update(ctx);
0639   }
0640   return updated ? Kst::Object::Updated : Kst::Object::NoChange;
0641 }
0642 
0643 
0644 QString ArgumentList::text() const {
0645   QString rc;
0646   bool first = true;
0647   QListIterator<Node*> it(_args);
0648   while (it.hasNext()) {
0649     if (!first) {
0650       rc += ", ";
0651     } else {
0652       first = false;
0653     }
0654     rc += it.next()->text();
0655   }
0656   return rc;
0657 }
0658 
0659 
0660 /////////////////////////////////////////////////////////////////
0661 static struct {
0662   const char *name;
0663   double value;
0664 } ITable[] = {
0665   {"e", 2.7128182846},
0666   {"pi", 3.1415926536},
0667   {0, 0.0}
0668 };
0669 
0670 Identifier::Identifier(char *name)
0671 : Node(), _name(name), _const(0L) {
0672   //printf("%p: New Identifier: %s\n", (void*)this, name);
0673   for (int i = 0; ITable[i].name; ++i) {
0674     if (strcasecmp(ITable[i].name, name) == 0) {
0675       _const = &ITable[i].value;
0676       break;
0677     }
0678   }
0679 }
0680 
0681 
0682 Identifier::~Identifier() {
0683   free(_name);
0684   _name = 0L;
0685 }
0686 
0687 
0688 const char *Identifier::name() const {
0689   return _name;
0690 }
0691 
0692 
0693 double Identifier::value(Context *ctx) {
0694   if (_const) {
0695     return *_const;
0696   } else if (_name[0] == 'x' && _name[1] == 0) {
0697     return ctx->x;
0698   } else {
0699     return ctx->noPoint;
0700   }
0701 }
0702 
0703 
0704 bool Identifier::isConst() {
0705   return _const != 0L || !(_name[0] == 'x' && _name[1] == 0);
0706 }
0707 
0708 
0709 QString Identifier::text() const {
0710   return _name;
0711 }
0712 
0713 
0714 /////////////////////////////////////////////////////////////////
0715 DataNode::DataNode(ObjectStore *store, char *name)
0716 : Node(), _store(store), _isEquation(false), _equation(0L) {
0717   //printf("%p: New Data Object: [%s]\n", (void*)this, name);
0718 //  ObjectStore *store = 0L; // FIXME: initialize this
0719   Q_ASSERT(store);
0720   if (name[0] == '=') {
0721     _tagName = QString(&name[1]).trimmed();
0722     _isEquation = true;
0723   } else if (strchr(name, '[')) {
0724     _tagName = QString(name).trimmed();
0725     QRegExp re("(.*)\\[(.*)\\]");
0726     int hit = re.indexIn(_tagName);
0727 #ifdef QT5
0728     if (hit > -1 && re.captureCount() == 2) {
0729 #else
0730     if (hit > -1 && re.numCaptures() == 2) {
0731 #endif
0732       _vector = kst_cast<Vector>(store->retrieveObject(re.cap(1)));
0733       if (_vector) {
0734         _vectorIndex = re.cap(2);
0735       }
0736     }
0737   } else {
0738     _tagName = QString(name).trimmed();
0739     ObjectPtr o = store->retrieveObject(_tagName);
0740     if (kst_cast<Vector>(o)) {
0741       _vector = kst_cast<Vector>(o);
0742     } else if (kst_cast<Scalar>(o)) {
0743       _scalar = kst_cast<Scalar>(o);
0744     }
0745   }
0746   free(name);
0747   name = 0L;
0748 }
0749 
0750 
0751 DataNode::~DataNode() {
0752   delete _equation;
0753   _equation = 0L;
0754 }
0755 
0756 
0757 double DataNode::value(Context *ctx) {
0758   if (_isEquation) {
0759     if (!_equation) {
0760       mutex().lock();
0761       YY_BUFFER_STATE b = yy_scan_bytes(_tagName.toLatin1(), _tagName.length());
0762       int rc = yyparse(_store);
0763       yy_delete_buffer(b);
0764       if (rc == 0 && ParsedEquation) {
0765         _equation = static_cast<Equations::Node*>(ParsedEquation);
0766         ParsedEquation = 0L;
0767         mutex().unlock();
0768         Equations::Context ctx;
0769         ctx.sampleCount = 2;
0770         ctx.noPoint = Kst::NOPOINT;
0771         ctx.x = 0.0;
0772         ctx.xVector = 0L;
0773         Equations::FoldVisitor vis(&ctx, &_equation);
0774       } else {
0775         ParsedEquation = 0L;
0776         mutex().unlock();
0777         _isEquation = false;
0778         return ctx->noPoint;
0779       }
0780     }
0781     return _equation->value(ctx);
0782   } else if (_vector) {
0783     if (!_equation && !_vectorIndex.isEmpty()) {
0784       mutex().lock();
0785       YY_BUFFER_STATE b = yy_scan_bytes(_vectorIndex.toLatin1(), _vectorIndex.length());
0786       int rc = yyparse(_store);
0787       yy_delete_buffer(b);
0788       if (rc == 0 && ParsedEquation) {
0789         _equation = static_cast<Equations::Node*>(ParsedEquation);
0790         ParsedEquation = 0L;
0791         mutex().unlock();
0792         Equations::Context ctx;
0793         ctx.sampleCount = 2;
0794         ctx.noPoint = Kst::NOPOINT;
0795         ctx.x = 0.0;
0796         ctx.xVector = 0L;
0797         Equations::FoldVisitor vis(&ctx, &_equation);
0798       } else {
0799         ParsedEquation = 0L;
0800         mutex().unlock();
0801         _vectorIndex.clear();
0802         _vector = 0L;
0803         return ctx->noPoint;
0804       }
0805     }
0806     if (_equation) {
0807       // Note: should we use a fresh context here?
0808       return _vector->value(int(_equation->value(ctx)));
0809     }
0810     return _vector->interpolate(ctx->i, ctx->sampleCount);
0811   } else if (_scalar) {
0812     return _scalar->value();
0813   } else {
0814     return ctx->noPoint;
0815   }
0816 }
0817 
0818 
0819 bool DataNode::isConst() {
0820   return (_isEquation && _equation) ? _equation->isConst() : false;
0821 }
0822 
0823 
0824 bool DataNode::collectObjects(Kst::VectorMap& v, Kst::ScalarMap& s, Kst::StringMap& t) {
0825   if (_isEquation) {
0826     if (_equation) {
0827       _equation->collectObjects(v, s, t);
0828     }
0829   } else if (_vector && !v.contains(_tagName)) {
0830     v.insert(_tagName, _vector);
0831   } else if (_scalar && !s.contains(_tagName)) {
0832     s.insert(_tagName, _scalar);
0833   } else if (!_scalar && !_vector) {
0834     Kst::Debug::self()->log(Kst::Debug::tr("Equation has unknown object [%1].").arg(_tagName), Kst::Debug::Error);
0835     return false;
0836   }
0837   return true;
0838 }
0839 
0840 
0841 bool DataNode::takeVectors(const Kst::VectorMap& c) {
0842   if (_isEquation) {
0843     if (_equation) {
0844       return _equation->takeVectors(c);
0845     }
0846     return false;
0847   }
0848   if (!_scalar) {
0849     if (c.contains(_tagName)) {
0850       _vector = c[_tagName];
0851     } else {
0852       return false;
0853     }
0854   }
0855   return true;
0856 }
0857 
0858 
0859 Kst::Object::UpdateType DataNode::update(Context *ctx) {
0860   Q_UNUSED(ctx)
0861   if (_isEquation) {
0862     if (_equation) {
0863       //return _equation->update(ctx);
0864     }
0865   } else if (_vector) {
0866     KstWriteLocker l(_vector);
0867     //return _vector->update();
0868   } else if (_scalar) {
0869     KstWriteLocker l(_scalar);
0870     //return _scalar->registerChange();
0871   }
0872   //return Kst::Object::NoChange;
0873   return Kst::Object::Updated;
0874 }
0875 
0876 
0877 // Hack alert: [ and ] in names confuse the parser, so strip them out.
0878 QString DataNode::text() const {
0879   if (_isEquation) {
0880     return QString("[=") + _tagName + ']';
0881   } else if (_vector) {
0882     QString Name = _vector->Name();
0883     Name.remove("\\[").remove("\\]");
0884     return QString('[') + Name.remove('[').remove(']') + QString(']');
0885   } else if (_scalar) {
0886     QString Name = _scalar->Name();
0887     Name.remove("\\[").remove("\\]");
0888     return QString('[') + Name.remove('[').remove(']') + QString(']');
0889   } else {
0890     return QString();
0891   }
0892 }
0893 
0894 /////////////////////////////////////////////////////////////////
0895 Number::Number(double n)
0896 : Node(), _n(n) {
0897 }
0898 
0899 
0900 Number::~Number() {
0901 }
0902 
0903 
0904 double Number::value(Context*) {
0905   return _n;
0906 }
0907 
0908 
0909 bool Number::isConst() {
0910   return true;
0911 }
0912 
0913 
0914 QString Number::text() const {
0915   if (_parentheses) {
0916     return QString('(') + QString::number(_n, 'g', 15) + ')';
0917   } else {
0918     return QString::number(_n, 'g', 15);
0919   }
0920 }
0921 
0922 
0923 /////////////////////////////////////////////////////////////////
0924 Negation::Negation(Node *node)
0925 : Node(), _n(node) {
0926   //printf("%p: New Negation: %p\n", (void*)this, (void*)n);
0927 }
0928 
0929 
0930 Negation::~Negation() {
0931   delete _n;
0932   _n = 0L;
0933 }
0934 
0935 
0936 double Negation::value(Context *ctx) {
0937   double v = _n->value(ctx);
0938   return (v == v) ? -v : v;
0939 }
0940 
0941 bool Negation::collectObjects(Kst::VectorMap& v, Kst::ScalarMap& s, Kst::StringMap& t) {
0942   bool ok = _n->collectObjects(v, s, t);
0943   return ok;
0944 }
0945 
0946 
0947 
0948 bool Negation::isConst() {
0949   return _n->isConst();
0950 }
0951 
0952 
0953 QString Negation::text() const {
0954   if (_parentheses) {
0955     return QString("(-") + _n->text() + ')';
0956   } else {
0957     return QString('-') + _n->text();
0958   }
0959 }
0960 
0961 
0962 /////////////////////////////////////////////////////////////////
0963 LogicalNot::LogicalNot(Node *node)
0964 : Node(), _n(node) {
0965   //printf("%p: New LogicalNot: %p\n", (void*)this, (void*)n);
0966 }
0967 
0968 
0969 LogicalNot::~LogicalNot() {
0970   delete _n;
0971   _n = 0L;
0972 }
0973 
0974 
0975 double LogicalNot::value(Context *ctx) {
0976   double v = _n->value(ctx);
0977   return (v == v) ? (v == 0.0) : 1.0;
0978 }
0979 
0980 
0981 bool LogicalNot::isConst() {
0982   return _n->isConst();
0983 }
0984 
0985 
0986 QString LogicalNot::text() const {
0987   if (_parentheses) {
0988     return QString("(!") + _n->text() + ')';
0989   } else {
0990     return QString('!') + _n->text();
0991   }
0992 }
0993 
0994 
0995 /////////////////////////////////////////////////////////////////
0996 BitwiseAnd::BitwiseAnd(Node *left, Node *right)
0997 : BinaryNode(left, right) {
0998   //printf("%p: New And: %p & %p\n", (void*)this, (void*)left, (void*)right);
0999 }
1000 
1001 
1002 BitwiseAnd::~BitwiseAnd() {
1003 }
1004 
1005 
1006 double BitwiseAnd::value(Context *ctx) {
1007   return long(_left->value(ctx)) & long(_right->value(ctx));
1008 }
1009 
1010 
1011 bool BitwiseAnd::isConst() {
1012   return _left->isConst() && _right->isConst();
1013 }
1014 
1015 
1016 QString BitwiseAnd::text() const {
1017   if (_parentheses) {
1018     return QString('(') + _left->text() + QString('&') + _right->text() + ')';
1019   } else {
1020     return _left->text() + QString('&') + _right->text();
1021   }
1022 }
1023 
1024 
1025 /////////////////////////////////////////////////////////////////
1026 BitwiseOr::BitwiseOr(Node *left, Node *right)
1027 : BinaryNode(left, right) {
1028   //printf("%p: New Or: %p | %p\n", (void*)this, (void*)left, (void*)right);
1029 }
1030 
1031 
1032 BitwiseOr::~BitwiseOr() {
1033 }
1034 
1035 
1036 double BitwiseOr::value(Context *ctx) {
1037   return long(_left->value(ctx)) | long(_right->value(ctx));
1038 }
1039 
1040 
1041 bool BitwiseOr::isConst() {
1042   return _left->isConst() && _right->isConst();
1043 }
1044 
1045 
1046 QString BitwiseOr::text() const {
1047   if (_parentheses) {
1048     return QString('(') + _left->text() + QString('|') + _right->text() + ')';
1049   } else {
1050     return _left->text() + QString('|') + _right->text();
1051   }
1052 }
1053 
1054 
1055 /////////////////////////////////////////////////////////////////
1056 LogicalAnd::LogicalAnd(Node *left, Node *right)
1057 : BinaryNode(left, right) {
1058   //printf("%p: New And: %p && %p\n", (void*)this, (void*)left, (void*)right);
1059 }
1060 
1061 
1062 LogicalAnd::~LogicalAnd() {
1063 }
1064 
1065 
1066 double LogicalAnd::value(Context *ctx) {
1067   return (_left->value(ctx) && _right->value(ctx)) ? EQ_TRUE : EQ_FALSE;
1068 }
1069 
1070 
1071 bool LogicalAnd::isConst() {
1072   return _left->isConst() && _right->isConst();
1073 }
1074 
1075 
1076 QString LogicalAnd::text() const {
1077   if (_parentheses) {
1078     return QString('(') + _left->text() + QString("&&") + _right->text() + ')';
1079   } else {
1080     return _left->text() + QString("&&") + _right->text();
1081   }
1082 }
1083 
1084 
1085 /////////////////////////////////////////////////////////////////
1086 LogicalOr::LogicalOr(Node *left, Node *right)
1087 : BinaryNode(left, right) {
1088   //printf("%p: New Or: %p || %p\n", (void*)this, (void*)left, (void*)right);
1089 }
1090 
1091 
1092 LogicalOr::~LogicalOr() {
1093 }
1094 
1095 
1096 double LogicalOr::value(Context *ctx) {
1097   return (_left->value(ctx) || _right->value(ctx)) ? EQ_TRUE : EQ_FALSE;
1098 }
1099 
1100 
1101 bool LogicalOr::isConst() {
1102   return _left->isConst() && _right->isConst();
1103 }
1104 
1105 
1106 QString LogicalOr::text() const {
1107   if (_parentheses) {
1108     return QString('(') + _left->text() + QString("||") + _right->text() + ')';
1109   } else {
1110     return _left->text() + QString("||") + _right->text();
1111   }
1112 }
1113 
1114 
1115 /////////////////////////////////////////////////////////////////
1116 LessThan::LessThan(Node *left, Node *right)
1117 : BinaryNode(left, right) {
1118   //printf("%p: New LessThan: %p < %p\n", (void*)this, (void*)left, (void*)right);
1119 }
1120 
1121 
1122 LessThan::~LessThan() {
1123 }
1124 
1125 
1126 double LessThan::value(Context *ctx) {
1127   return doubleLessThan(_left->value(ctx), _right->value(ctx)) ? EQ_TRUE : EQ_FALSE;
1128 }
1129 
1130 
1131 bool LessThan::isConst() {
1132   return _left->isConst() && _right->isConst();
1133 }
1134 
1135 
1136 QString LessThan::text() const {
1137   if (_parentheses) {
1138     return QString('(') + _left->text() + QString('<') + _right->text() + ')';
1139   } else {
1140     return _left->text() + QString('<') + _right->text();
1141   }
1142 }
1143 
1144 
1145 /////////////////////////////////////////////////////////////////
1146 LessThanEqual::LessThanEqual(Node *left, Node *right)
1147 : BinaryNode(left, right) {
1148   //printf("%p: New LessThanEqual: %p <= %p\n", (void*)this, (void*)left, (void*)right);
1149 }
1150 
1151 
1152 LessThanEqual::~LessThanEqual() {
1153 }
1154 
1155 
1156 double LessThanEqual::value(Context *ctx) {
1157   return doubleLessThanEqual(_left->value(ctx), _right->value(ctx)) ? EQ_TRUE : EQ_FALSE;
1158 }
1159 
1160 
1161 bool LessThanEqual::isConst() {
1162   return _left->isConst() && _right->isConst();
1163 }
1164 
1165 
1166 QString LessThanEqual::text() const {
1167   if (_parentheses) {
1168     return QString('(') + _left->text() + QString("<=") + _right->text() + ')';
1169   } else {
1170     return _left->text() + QString("<=") + _right->text();
1171   }
1172 }
1173 
1174 
1175 /////////////////////////////////////////////////////////////////
1176 GreaterThan::GreaterThan(Node *left, Node *right)
1177 : BinaryNode(left, right) {
1178   //printf("%p: New GreaterThan: %p > %p\n", (void*)this, (void*)left, (void*)right);
1179 }
1180 
1181 
1182 GreaterThan::~GreaterThan() {
1183 }
1184 
1185 
1186 double GreaterThan::value(Context *ctx) {
1187   return doubleGreaterThan(_left->value(ctx), _right->value(ctx)) ? EQ_TRUE : EQ_FALSE;
1188 }
1189 
1190 
1191 bool GreaterThan::isConst() {
1192   return _left->isConst() && _right->isConst();
1193 }
1194 
1195 
1196 QString GreaterThan::text() const {
1197   if (_parentheses) {
1198     return QString('(') + _left->text() + QString('>') + _right->text() + ')';
1199   } else {
1200     return _left->text() + QString('>') + _right->text();
1201   }
1202 }
1203 
1204 
1205 /////////////////////////////////////////////////////////////////
1206 GreaterThanEqual::GreaterThanEqual(Node *left, Node *right)
1207 : BinaryNode(left, right) {
1208   //printf("%p: New GreaterThanEqual: %p >= %p\n", (void*)this, (void*)left, (void*)right);
1209 }
1210 
1211 
1212 GreaterThanEqual::~GreaterThanEqual() {
1213 }
1214 
1215 
1216 double GreaterThanEqual::value(Context *ctx) {
1217   return doubleGreaterThanEqual(_left->value(ctx), _right->value(ctx)) ? EQ_TRUE : EQ_FALSE;
1218 }
1219 
1220 
1221 bool GreaterThanEqual::isConst() {
1222   return _left->isConst() && _right->isConst();
1223 }
1224 
1225 
1226 QString GreaterThanEqual::text() const {
1227   if (_parentheses) {
1228     return QString('(') + _left->text() + QString(">=") + _right->text() + ')';
1229   } else {
1230     return _left->text() + QString(">=") + _right->text();
1231   }
1232 }
1233 
1234 
1235 /////////////////////////////////////////////////////////////////
1236 EqualTo::EqualTo(Node *left, Node *right)
1237 : BinaryNode(left, right) {
1238   //printf("%p: New EqualTo: %p == %p\n", (void*)this, (void*)left, (void*)right);
1239 }
1240 
1241 
1242 EqualTo::~EqualTo() {
1243 }
1244 
1245 
1246 double EqualTo::value(Context *ctx) {
1247   return doubleEqual(_left->value(ctx), _right->value(ctx)) ? EQ_TRUE : EQ_FALSE;
1248 }
1249 
1250 
1251 bool EqualTo::isConst() {
1252   return _left->isConst() && _right->isConst();
1253 }
1254 
1255 
1256 QString EqualTo::text() const {
1257   if (_parentheses) {
1258     return QString('(') + _left->text() + QString("==") + _right->text() + ')';
1259   } else {
1260     return _left->text() + QString("==") + _right->text();
1261   }
1262 }
1263 
1264 
1265 /////////////////////////////////////////////////////////////////
1266 NotEqualTo::NotEqualTo(Node *left, Node *right)
1267 : BinaryNode(left, right) {
1268   //printf("%p: New NotEqualTo: %p != %p\n", (void*)this, (void*)left, (void*)right);
1269 }
1270 
1271 
1272 NotEqualTo::~NotEqualTo() {
1273 }
1274 
1275 
1276 double NotEqualTo::value(Context *ctx) {
1277   return (!doubleEqual(_left->value(ctx), _right->value(ctx))) ? EQ_TRUE : EQ_FALSE;
1278 }
1279 
1280 
1281 bool NotEqualTo::isConst() {
1282   return _left->isConst() && _right->isConst();
1283 }
1284 
1285 
1286 QString NotEqualTo::text() const {
1287   if (_parentheses) {
1288     return QString('(') + _left->text() + QString("!=") + _right->text() + ')';
1289   } else {
1290     return _left->text() + QString("!=") + _right->text();
1291   }
1292 }
1293 
1294 
1295 /////////////////////////////////////////////////////////////////
1296 
1297 NodeVisitor::NodeVisitor() {
1298 }
1299 
1300 
1301 NodeVisitor::~NodeVisitor() {
1302 }
1303 
1304 
1305 /////////////////////////////////////////////////////////////////
1306 
1307 FoldVisitor::FoldVisitor(Context* ctxIn, Node** rootNode) : NodeVisitor(), _ctx(ctxIn) {
1308   if ((*rootNode)->isConst() && dynamic_cast<Number*>(*rootNode) == 0L) {
1309     double v = (*rootNode)->value(ctxIn);
1310     delete *rootNode;
1311     *rootNode = new Number(v);
1312   } else {
1313     (*rootNode)->visit(this);
1314   }
1315   _ctx = 0L; // avoids context being marked as 'still reachable'
1316 }
1317 
1318 
1319 FoldVisitor::~FoldVisitor() {
1320 }
1321 
1322 
1323 void FoldVisitor::visitNode(Node*) {
1324   // useful?
1325 }
1326 
1327 
1328 void FoldVisitor::visitBinaryNode(BinaryNode *n) {
1329   if (n->left()->isConst() && dynamic_cast<Number*>(n->left()) == 0L) {
1330     double v = n->left()->value(_ctx);
1331     delete n->left();
1332     n->left() = new Number(v);
1333   } else {
1334     n->left()->visit(this);
1335   }
1336 
1337   if (n->right()->isConst() && dynamic_cast<Number*>(n->right()) == 0L) {
1338     double v = n->right()->value(_ctx);
1339     delete n->right();
1340     n->right() = new Number(v);
1341   } else {
1342     n->right()->visit(this);
1343   }
1344 }
1345 
1346 // vim: ts=2 sw=2 et