FreeCAD

Форк
0
/
Expression.cpp 
3867 строк · 111.1 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2015 Eivind Kvedalen <eivind@kvedalen.name>             *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
6
 *   This library is free software; you can redistribute it and/or         *
7
 *   modify it under the terms of the GNU Library General Public           *
8
 *   License as published by the Free Software Foundation; either          *
9
 *   version 2 of the License, or (at your option) any later version.      *
10
 *                                                                         *
11
 *   This library  is distributed in the hope that it will be useful,      *
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14
 *   GNU Library General Public License for more details.                  *
15
 *                                                                         *
16
 *   You should have received a copy of the GNU Library General Public     *
17
 *   License along with this library; see the file COPYING.LIB. If not,    *
18
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
19
 *   Suite 330, Boston, MA  02111-1307, USA                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23
#include "PreCompiled.h"
24
#ifdef __GNUC__
25
# include <unistd.h>
26
#endif
27

28
#if defined(__clang__)
29
# pragma clang diagnostic push
30
# pragma clang diagnostic ignored "-Wdelete-non-virtual-dtor"
31
#endif
32

33
#include <boost/algorithm/string/predicate.hpp>
34
#include <boost/math/special_functions/round.hpp>
35
#include <boost/math/special_functions/trunc.hpp>
36

37
#include <sstream>
38
#include <stack>
39
#include <string>
40

41
#include <App/Application.h>
42
#include <App/DocumentObject.h>
43
#include <App/ObjectIdentifier.h>
44
#include <App/PropertyUnits.h>
45
#include <Base/Interpreter.h>
46
#include <Base/MatrixPy.h>
47
#include <Base/PlacementPy.h>
48
#include <Base/QuantityPy.h>
49
#include <Base/RotationPy.h>
50
#include <Base/VectorPy.h>
51

52
#include "ExpressionParser.h"
53

54

55
/** \defgroup Expression Expressions framework
56
    \ingroup APP
57
    \brief The expression system allows users to write expressions and formulas that produce values
58
*/
59

60
using namespace Base;
61
using namespace App;
62

63
FC_LOG_LEVEL_INIT("Expression", true, true)
64

65
#ifndef M_PI
66
#define M_PI       3.14159265358979323846
67
#endif
68
#ifndef M_E
69
#define M_E        2.71828182845904523536
70
#endif
71
#ifndef  DOUBLE_MAX
72
# define DOUBLE_MAX 1.7976931348623157E+308    /* max decimal value of a "double"*/
73
#endif
74
#ifndef  DOUBLE_MIN
75
# define DOUBLE_MIN 2.2250738585072014E-308    /* min decimal value of a "double"*/
76
#endif
77

78
#if defined(_MSC_VER)
79
#define strtoll _strtoi64
80
#pragma warning(disable : 4003)
81
#pragma warning(disable : 4065)
82
#endif
83

84
#define __EXPR_THROW(_e,_msg,_expr) do {\
85
    std::ostringstream ss;\
86
    ss << _msg << (_expr);\
87
    throw _e(ss.str().c_str());\
88
}while(0)
89

90
#define _EXPR_THROW(_msg,_expr) __EXPR_THROW(ExpressionError,_msg,_expr)
91

92
#define __EXPR_SET_MSG(_e,_msg,_expr) do {\
93
    std::ostringstream ss;\
94
    ss << _msg << _e.what() << (_expr);\
95
    _e.setMessage(ss.str());\
96
}while(0)
97

98
#define _EXPR_RETHROW(_e,_msg,_expr) do {\
99
    __EXPR_SET_MSG(_e,_msg,_expr);\
100
    throw;\
101
}while(0)
102

103
#define _EXPR_PY_THROW(_msg,_expr) do {\
104
    Base::PyException _e;\
105
    __EXPR_SET_MSG(_e,_msg,_expr);\
106
    _e.raiseException();\
107
}while(0)
108

109
#define EXPR_PY_THROW(_expr) _EXPR_PY_THROW("", _expr)
110

111
#define EXPR_THROW(_msg) _EXPR_THROW(_msg, this)
112

113
#define ARGUMENT_THROW(_msg) EXPR_THROW("Invalid number of arguments: " _msg)
114

115
#define RUNTIME_THROW(_msg) __EXPR_THROW(Base::RuntimeError, _msg, static_cast<Expression*>(nullptr))
116

117
#define TYPE_THROW(_msg) __EXPR_THROW(Base::TypeError, _msg, static_cast<Expression*>(nullptr))
118

119
#define PARSER_THROW(_msg) __EXPR_THROW(Base::ParserError, _msg, static_cast<Expression*>(nullptr))
120

121
#define PY_THROW(_msg) __EXPR_THROW(Py::RuntimeError, _msg, static_cast<Expression*>(nullptr))
122

123
static inline std::ostream &operator<<(std::ostream &os, const App::Expression *expr) {
124
    if(expr) {
125
        os << "\nin expression: ";
126
        expr->toString(os);
127
    }
128
    return os;
129
}
130

131
template<typename T>
132
void copy_vector(T &dst, const T& src) {
133
    dst.clear();
134
    dst.reserve(src.size());
135
    for(auto &s : src) {
136
        if(s)
137
            dst.push_back(s->copy());
138
        else
139
            dst.emplace_back();
140
    }
141
}
142

143
////////////////////////////////////////////////////////////////////////////////
144

145
// WARNING! The following define enables slightly faster any type comparison which
146
// is not standard conforming, and may break in some rare cases (although not likely)
147
//
148
// #define USE_FAST_ANY
149

150
static inline bool is_type(const App::any &value, const std::type_info& t) {
151
#ifdef USE_FAST_ANY
152
    return &value.type() == &t;
153
#else
154
    return value.type() == t;
155
#endif
156
}
157

158
template<class T>
159
static inline const T &cast(const App::any &value) {
160
#ifdef USE_FAST_ANY
161
    return *value.cast<T>();
162
#else
163
    return App::any_cast<const T&>(value);
164
#endif
165
}
166

167
template<class T>
168
static inline T &cast(App::any &value) {
169
#ifdef USE_FAST_ANY
170
    return *value.cast<T>();
171
#else
172
    return App::any_cast<T&>(value);
173
#endif
174
}
175

176
template<class T>
177
static inline T &&cast(App::any &&value) {
178
#ifdef USE_FAST_ANY
179
    return std::move(*value.cast<T>());
180
#else
181
    return App::any_cast<T&&>(std::move(value));
182
#endif
183
}
184

185
std::string unquote(const std::string & input)
186
{
187
    assert(input.size() >= 4);
188

189
    std::string output;
190
    std::string::const_iterator cur = input.begin() + 2;
191
    std::string::const_iterator end = input.end() - 2;
192

193
    output.reserve(input.size());
194

195
    bool escaped = false;
196
    while (cur != end) {
197
        if (escaped) {
198
            switch (*cur) {
199
            case 't':
200
                output += '\t';
201
                break;
202
            case 'n':
203
                output += '\n';
204
                break;
205
            case 'r':
206
                output += '\r';
207
                break;
208
            case '\\':
209
                output += '\\';
210
                break;
211
            case '\'':
212
                output += '\'';
213
                break;
214
            case '"':
215
                output += '"';
216
                break;
217
            }
218
            escaped = false;
219
        }
220
        else {
221
            if (*cur == '\\')
222
                escaped = true;
223
            else
224
                output += *cur;
225
        }
226
        ++cur;
227
    }
228

229
    return output;
230
}
231

232
////////////////////////////////////////////////////////////////////////////////////
233
//
234
// ExpressionVistor
235
//
236
void ExpressionVisitor::getIdentifiers(Expression &e, std::map<App::ObjectIdentifier,bool> &ids) {
237
    e._getIdentifiers(ids);
238
}
239

240
bool ExpressionVisitor::adjustLinks(Expression &e, const std::set<App::DocumentObject*> &inList) {
241
    return e._adjustLinks(inList,*this);
242
}
243

244
void ExpressionVisitor::importSubNames(Expression &e, const ObjectIdentifier::SubNameMap &subNameMap) {
245
    e._importSubNames(subNameMap);
246
}
247

248
void ExpressionVisitor::updateLabelReference(Expression &e,
249
        DocumentObject *obj, const std::string &ref, const char *newLabel)
250
{
251
    e._updateLabelReference(obj,ref,newLabel);
252
}
253

254
bool ExpressionVisitor::updateElementReference(Expression &e, App::DocumentObject *feature, bool reverse) {
255
    return e._updateElementReference(feature,reverse,*this);
256
}
257

258
bool ExpressionVisitor::relabeledDocument(
259
        Expression &e, const std::string &oldName, const std::string &newName)
260
{
261
    return e._relabeledDocument(oldName,newName,*this);
262
}
263

264
bool ExpressionVisitor::renameObjectIdentifier(Expression &e,
265
        const std::map<ObjectIdentifier,ObjectIdentifier> &paths, const ObjectIdentifier &path)
266
{
267
    return e._renameObjectIdentifier(paths,path,*this);
268
}
269

270
void ExpressionVisitor::collectReplacement(Expression &e,
271
        std::map<ObjectIdentifier,ObjectIdentifier> &paths,
272
        const App::DocumentObject *parent, App::DocumentObject *oldObj, App::DocumentObject *newObj) const
273
{
274
    return e._collectReplacement(paths,parent,oldObj,newObj);
275
}
276

277
void ExpressionVisitor::moveCells(Expression &e, const CellAddress &address, int rowCount, int colCount) {
278
    e._moveCells(address,rowCount,colCount,*this);
279
}
280

281
void ExpressionVisitor::offsetCells(Expression &e, int rowOffset, int colOffset) {
282
    e._offsetCells(rowOffset,colOffset,*this);
283
}
284

285
/////////////////////////////////////////////////////////////////////////////////////
286
// Helper functions
287

288
/* The following definitions are from The art of computer programming by Knuth
289
 * (copied from http://stackoverflow.com/questions/17333/most-effective-way-for-float-and-double-comparison)
290
 */
291

292
/*
293
static bool approximatelyEqual(double a, double b, double epsilon)
294
{
295
    return fabs(a - b) <= ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon);
296
}
297
*/
298

299
template<class T>
300
static inline bool essentiallyEqual(T a, T b)
301
{
302
    static const T _epsilon = std::numeric_limits<T>::epsilon();
303
    return std::fabs(a - b) <= ( (std::fabs(a) > std::fabs(b) ? std::fabs(b) : std::fabs(a)) * _epsilon);
304
}
305

306
template<class T>
307
inline bool essentiallyZero(T a) {
308
    return !a;
309
}
310

311
template<>
312
inline bool essentiallyZero(double a) {
313
    return essentiallyEqual(a, 0.0);
314
}
315

316
template<>
317
inline bool essentiallyZero(float a) {
318
    return essentiallyEqual(a, 0.0f);
319
}
320

321
template<class T>
322
static inline bool definitelyGreaterThan(T a, T b)
323
{
324
    static const T _epsilon = std::numeric_limits<T>::epsilon();
325
    return (a - b) > ( (std::fabs(a) < std::fabs(b) ? std::fabs(b) : std::fabs(a)) * _epsilon);
326
}
327

328
template<class T>
329
static inline bool definitelyLessThan(T a, T b)
330
{
331
    static const T _epsilon = std::numeric_limits<T>::epsilon();
332
    return (b - a) > ( (std::fabs(a) < std::fabs(b) ? std::fabs(b) : std::fabs(a)) * _epsilon);
333
}
334

335
static inline int essentiallyInteger(double a, long &l, int &i) {
336
    double intpart;
337
    if (std::modf(a,&intpart) == 0.0) {
338
        if (intpart<0.0) {
339
            if (intpart >= INT_MIN) {
340
                i = static_cast<int>(intpart);
341
                l = i;
342
                return 1;
343
            }
344
            if (intpart >= LONG_MIN) {
345
                l = static_cast<long>(intpart);
346
                return 2;
347
            }
348
        }
349
        else if (intpart <= INT_MAX) {
350
            i = static_cast<int>(intpart);
351
            l = i;
352
            return 1;
353
        }
354
        else if (intpart <= static_cast<double>(LONG_MAX)) {
355
            l = static_cast<int>(intpart);
356
            return 2;
357
        }
358
    }
359
    return 0;
360
}
361

362
static inline bool essentiallyInteger(double a, long &l) {
363
    double intpart;
364
    if (std::modf(a,&intpart) == 0.0) {
365
        if (intpart<0.0) {
366
            if (intpart >= LONG_MIN) {
367
                l = static_cast<long>(intpart);
368
                return true;
369
            }
370
        }
371
        else if (intpart <= static_cast<double>(LONG_MAX)) {
372
            l = static_cast<long>(intpart);
373
            return true;
374
        }
375
    }
376
    return false;
377
}
378

379
// This class is intended to be contained inside App::any (via a shared_ptr)
380
// without holding Python global lock
381
struct PyObjectWrapper {
382
public:
383
    using Pointer = std::shared_ptr<PyObjectWrapper>;
384

385
    explicit PyObjectWrapper(PyObject *obj):pyobj(obj) {
386
        Py::_XINCREF(pyobj);
387
    }
388
    ~PyObjectWrapper() {
389
        if(pyobj) {
390
            Base::PyGILStateLocker lock;
391
            Py::_XDECREF(pyobj);
392
        }
393
    }
394
    PyObjectWrapper(const PyObjectWrapper &) = delete;
395
    PyObjectWrapper &operator=(const PyObjectWrapper &) = delete;
396

397
    Py::Object get() const {
398
        if(!pyobj)
399
            return Py::Object();
400
        return Py::Object(const_cast<PyObject*>(pyobj));
401
    }
402

403
private:
404
    PyObject *pyobj;
405
};
406

407
static inline PyObjectWrapper::Pointer pyObjectWrap(PyObject *obj) {
408
    return std::make_shared<PyObjectWrapper>(obj);
409
}
410

411
static inline bool isAnyPyObject(const App::any &value) {
412
    return is_type(value,typeid(PyObjectWrapper::Pointer));
413
}
414

415
static inline Py::Object __pyObjectFromAny(const App::any &value) {
416
    return cast<PyObjectWrapper::Pointer>(value)->get();
417
}
418

419
static Py::Object _pyObjectFromAny(const App::any &value, const Expression *e) {
420
    if(value.empty())
421
        return Py::Object();
422
    else if (isAnyPyObject(value))
423
        return __pyObjectFromAny(value);
424
    if (is_type(value,typeid(Quantity)))
425
        return Py::asObject(new QuantityPy(new Quantity(cast<Quantity>(value))));
426
    else if (is_type(value,typeid(double)))
427
        return Py::Float(cast<double>(value));
428
    else if (is_type(value,typeid(float)))
429
        return Py::Float(cast<float>(value));
430
    else if (is_type(value,typeid(int)))
431
        return Py::Long(cast<int>(value));
432
    else if (is_type(value,typeid(long))) {
433
        return Py::Long(cast<long>(value));
434
    } else if (is_type(value,typeid(bool)))
435
        return Py::Boolean(cast<bool>(value));
436
    else if (is_type(value,typeid(std::string)))
437
        return Py::String(cast<string>(value));
438
    else if (is_type(value,typeid(const char*)))
439
        return Py::String(cast<const char*>(value));
440

441
    _EXPR_THROW("Unknown type", e);
442
}
443

444
namespace App {
445
Py::Object pyObjectFromAny(const App::any &value) {
446
    return _pyObjectFromAny(value,nullptr);
447
}
448

449
App::any pyObjectToAny(Py::Object value, bool check) {
450

451
    if(value.isNone())
452
        return {};
453

454
    PyObject *pyvalue = value.ptr();
455

456
    if(!check)
457
        return {pyObjectWrap(pyvalue)};
458

459
    if (PyObject_TypeCheck(pyvalue, &Base::QuantityPy::Type)) {
460
        Base::QuantityPy * qp = static_cast<Base::QuantityPy*>(pyvalue);
461
        Base::Quantity * q = qp->getQuantityPtr();
462

463
        return App::any(*q);
464
    }
465
    if (PyFloat_Check(pyvalue))
466
        return App::any(PyFloat_AsDouble(pyvalue));
467
    if (PyLong_Check(pyvalue))
468
        return App::any(PyLong_AsLong(pyvalue));
469
    else if (PyUnicode_Check(pyvalue)) {
470
        const char* utf8value = PyUnicode_AsUTF8(pyvalue);
471
        if (!utf8value) {
472
            FC_THROWM(Base::ValueError, "Invalid unicode string");
473
        }
474
        return App::any(std::string(utf8value));
475
    }
476
    else {
477
        return App::any(pyObjectWrap(pyvalue));
478
    }
479
}
480

481
bool pyToQuantity(Quantity &q, const Py::Object &pyobj) {
482
    if (PyObject_TypeCheck(*pyobj, &Base::QuantityPy::Type))
483
        q = *static_cast<Base::QuantityPy*>(*pyobj)->getQuantityPtr();
484
    else if (PyFloat_Check(*pyobj))
485
        q = Quantity(PyFloat_AsDouble(*pyobj));
486
    else if (PyLong_Check(*pyobj))
487
        q = Quantity(PyLong_AsLong(*pyobj));
488
    else
489
        return false;
490
    return true;
491
}
492

493
static inline Quantity pyToQuantity(const Py::Object &pyobj,
494
        const Expression *e, const char *msg=nullptr)
495
{
496
    Quantity q;
497
    if(!pyToQuantity(q,pyobj)) {
498
        if(!msg)
499
            msg = "Failed to convert to Quantity.";
500
        __EXPR_THROW(TypeError,msg,e);
501
    }
502
    return q;
503
}
504

505
Py::Object pyFromQuantity(const Quantity &quantity) {
506
    if(!quantity.getUnit().isEmpty())
507
        return Py::asObject(new QuantityPy(new Quantity(quantity)));
508
    double v = quantity.getValue();
509
    long l;
510
    int i;
511
    switch(essentiallyInteger(v,l,i)) {
512
    case 1:
513
    case 2:
514
        return Py::Long(l);
515
    default:
516
        return Py::Float(v);
517
    }
518
}
519

520
Quantity anyToQuantity(const App::any &value, const char *msg) {
521
    if (is_type(value,typeid(Quantity))) {
522
        return cast<Quantity>(value);
523
    } else if (is_type(value,typeid(bool))) {
524
        return Quantity(cast<bool>(value)?1.0:0.0);
525
    } else if (is_type(value,typeid(int))) {
526
        return Quantity(cast<int>(value));
527
    } else if (is_type(value,typeid(long))) {
528
        return Quantity(cast<long>(value));
529
    } else if (is_type(value,typeid(float))) {
530
        return Quantity(cast<float>(value));
531
    } else if (is_type(value,typeid(double))) {
532
        return Quantity(cast<double>(value));
533
    }
534
    if(!msg)
535
        msg = "Failed to convert to Quantity";
536
    TYPE_THROW(msg);
537
}
538

539
static inline bool anyToLong(long &res, const App::any &value) {
540
    if (is_type(value,typeid(int))) {
541
        res = cast<int>(value);
542
    } else if (is_type(value,typeid(long))) {
543
        res = cast<long>(value);
544
    } else if (is_type(value,typeid(bool)))
545
        res = cast<bool>(value)?1:0;
546
    else
547
        return false;
548
    return true;
549
}
550

551
static inline bool anyToDouble(double &res, const App::any &value) {
552
    if (is_type(value,typeid(double)))
553
        res = cast<double>(value);
554
    else if (is_type(value,typeid(float)))
555
        res = cast<float>(value);
556
    else if (is_type(value,typeid(long)))
557
        res = cast<long>(value);
558
    else if (is_type(value,typeid(int)))
559
        res = cast<int>(value);
560
    else if (is_type(value,typeid(bool)))
561
        res = cast<bool>(value)?1:0;
562
    else
563
        return false;
564
    return true;
565
}
566

567
bool isAnyEqual(const App::any &v1, const App::any &v2) {
568
    if(v1.empty())
569
        return v2.empty();
570
    else if(v2.empty())
571
        return false;
572

573
    if(!is_type(v1,v2.type())) {
574
        if(is_type(v1,typeid(Quantity)))
575
            return cast<Quantity>(v1) == anyToQuantity(v2);
576
        else if(is_type(v2,typeid(Quantity)))
577
            return anyToQuantity(v1) == cast<Quantity>(v2);
578

579
        long l1,l2;
580
        double d1,d2;
581
        if(anyToLong(l1,v1)) {
582
            if(anyToLong(l2,v2))
583
                return l1==l2;
584
            else if(anyToDouble(d2,v2))
585
                return essentiallyEqual((double)l1,d2);
586
            else
587
                return false;
588
        }else if(anyToDouble(d1,v1))
589
           return anyToDouble(d2,v2) && essentiallyEqual(d1,d2);
590

591
        if(is_type(v1,typeid(std::string))) {
592
            if(is_type(v2,typeid(const char*))) {
593
                auto c = cast<const char*>(v2);
594
                return c && cast<std::string>(v1)==c;
595
            }
596
            return false;
597
        }else if(is_type(v1,typeid(const char*))) {
598
            if(is_type(v2,typeid(std::string))) {
599
                auto c = cast<const char*>(v1);
600
                return c && cast<std::string>(v2)==c;
601
            }
602
            return false;
603
        }
604
    }
605

606
    if (is_type(v1,typeid(int)))
607
        return cast<int>(v1) == cast<int>(v2);
608
    if (is_type(v1,typeid(long)))
609
        return cast<long>(v1) == cast<long>(v2);
610
    if (is_type(v1,typeid(std::string)))
611
        return cast<std::string>(v1) == cast<std::string>(v2);
612
    if (is_type(v1,typeid(const char*))) {
613
        auto c1 = cast<const char*>(v1);
614
        auto c2 = cast<const char*>(v2);
615
        return c1==c2 || (c1 && c2 && strcmp(c1,c2)==0);
616
    }
617
    if (is_type(v1,typeid(bool)))
618
        return cast<bool>(v1) == cast<bool>(v2);
619
    if (is_type(v1,typeid(double)))
620
        return essentiallyEqual(cast<double>(v1), cast<double>(v2));
621
    if (is_type(v1,typeid(float)))
622
        return essentiallyEqual(cast<float>(v1), cast<float>(v2));
623

624
    if (is_type(v1,typeid(Quantity)))
625
        return cast<Quantity>(v1) == cast<Quantity>(v2);
626

627
    if (!isAnyPyObject(v1))
628
        throw Base::TypeError("Unknown type");
629

630
    Base::PyGILStateLocker lock;
631
    Py::Object o1 = __pyObjectFromAny(v1);
632
    Py::Object o2 = __pyObjectFromAny(v2);
633
    if(!o1.isType(o2.type()))
634
        return false;
635
    int res = PyObject_RichCompareBool(o1.ptr(),o2.ptr(),Py_EQ);
636
    if(res<0)
637
        PyException::ThrowException();
638
    return !!res;
639
}
640

641
Expression* expressionFromPy(const DocumentObject *owner, const Py::Object &value) {
642
    if (value.isNone())
643
        return new PyObjectExpression(owner);
644
    if(value.isString()) {
645
        return new StringExpression(owner,value.as_string());
646
    } else if (PyObject_TypeCheck(value.ptr(),&QuantityPy::Type)) {
647
        return new NumberExpression(owner,
648
                *static_cast<QuantityPy*>(value.ptr())->getQuantityPtr());
649
    } else if (value.isBoolean()) {
650
        if(value.isTrue())
651
            return new ConstantExpression(owner,"True",Quantity(1.0));
652
        else
653
            return new ConstantExpression(owner,"False",Quantity(0.0));
654
    } else {
655
        Quantity q;
656
        if(pyToQuantity(q,value))
657
            return new NumberExpression(owner,q);
658
    }
659
    return new PyObjectExpression(owner,value.ptr());
660
}
661

662
} // namespace App
663

664
//
665
// Expression component
666
//
667
Expression::Component::Component(const std::string &n)
668
    :comp(ObjectIdentifier::SimpleComponent(n))
669
    ,e1(nullptr) ,e2(nullptr) ,e3(nullptr)
670
{}
671

672
Expression::Component::Component(Expression *_e1, Expression *_e2, Expression *_e3, bool isRange)
673
    :e1(_e1) ,e2(_e2) ,e3(_e3)
674
{
675
    if(isRange || e2 || e3)
676
        comp = ObjectIdentifier::RangeComponent(0);
677
}
678

679
Expression::Component::Component(const ObjectIdentifier::Component &comp)
680
    :comp(comp)
681
    ,e1(nullptr) ,e2(nullptr) ,e3(nullptr)
682
{}
683

684
Expression::Component::Component(const Component &other)
685
    :comp(other.comp)
686
    ,e1(other.e1?other.e1->copy():nullptr)
687
    ,e2(other.e2?other.e2->copy():nullptr)
688
    ,e3(other.e3?other.e3->copy():nullptr)
689
{}
690

691
Expression::Component::~Component()
692
{
693
    delete e1;
694
    delete e2;
695
    delete e3;
696
}
697

698
Expression::Component* Expression::Component::copy() const {
699
    return new Component(*this);
700
}
701

702
Expression::Component* Expression::Component::eval() const {
703
    auto res = new Component(comp);
704
    if(e1) res->e1 = e1->eval();
705
    if(e2) res->e2 = e2->eval();
706
    if(e3) res->e3 = e3->eval();
707
    return res;
708
}
709

710
Py::Object Expression::Component::get(const Expression *owner, const Py::Object &pyobj) const {
711
    try {
712
        if(!e1 && !e2 && !e3)
713
            return comp.get(pyobj);
714
        if(!comp.isRange() && !e2 && !e3) {
715
            auto index = e1->getPyValue();
716
            Py::Object res;
717
            if(pyobj.isMapping())
718
                res = Py::Mapping(pyobj).getItem(index);
719
            else {
720
                Py_ssize_t i = PyNumber_AsSsize_t(index.ptr(), PyExc_IndexError);
721
                if(PyErr_Occurred())
722
                    throw Py::Exception();
723
                res = Py::Sequence(pyobj).getItem(i);
724
            }
725
            if(!res.ptr())
726
                throw Py::Exception();
727
            return res;
728
        }else{
729
            Py::Object v1,v2,v3;
730
            if(e1) v1 = e1->getPyValue();
731
            if(e2) v2 = e2->getPyValue();
732
            if(e3) v3 = e3->getPyValue();
733
            PyObject *s = PySlice_New(e1?v1.ptr():nullptr,
734
                                      e2?v2.ptr():nullptr,
735
                                      e3?v3.ptr():nullptr);
736
            if(!s)
737
                throw Py::Exception();
738
            Py::Object slice(s,true);
739
            PyObject *res = PyObject_GetItem(pyobj.ptr(),slice.ptr());
740
            if(!res)
741
                throw Py::Exception();
742
            return Py::asObject(res);
743
        }
744
    }catch(Py::Exception &) {
745
        EXPR_PY_THROW(owner);
746
    }
747
    return Py::Object();
748
}
749

750
void Expression::Component::set(const Expression *owner, Py::Object &pyobj, const Py::Object &value) const
751
{
752
    if(!e1 && !e2 && !e3)
753
        return comp.set(pyobj,value);
754
    try {
755
        if(!comp.isRange() && !e2 && !e3) {
756
            auto index = e1->getPyValue();
757
            if(pyobj.isMapping())
758
                Py::Mapping(pyobj).setItem(index,value);
759
            else {
760
                Py_ssize_t i = PyNumber_AsSsize_t(pyobj.ptr(), PyExc_IndexError);
761
                if(PyErr_Occurred() || PySequence_SetItem(pyobj.ptr(),i,value.ptr())==-1)
762
                    throw Py::Exception();
763
            }
764
        }else{
765
            Py::Object v1,v2,v3;
766
            if(e1) v1 = e1->getPyValue();
767
            if(e2) v2 = e2->getPyValue();
768
            if(e3) v3 = e3->getPyValue();
769
            PyObject *s = PySlice_New(e1?v1.ptr():nullptr,
770
                                      e2?v2.ptr():nullptr,
771
                                      e3?v3.ptr():nullptr);
772
            if(!s)
773
                throw Py::Exception();
774
            Py::Object slice(s,true);
775
            if(PyObject_SetItem(pyobj.ptr(),slice.ptr(),value.ptr())<0)
776
                throw Py::Exception();
777
        }
778
    }catch(Py::Exception &) {
779
        EXPR_PY_THROW(owner);
780
    }
781
}
782

783
void Expression::Component::del(const Expression *owner, Py::Object &pyobj) const {
784
    try {
785
        if (!e1 && !e2 && !e3) {
786
            comp.del(pyobj);
787
        }
788
        else if (!comp.isRange() && !e2 && !e3) {
789
            auto index = e1->getPyValue();
790
            if (pyobj.isMapping()) {
791
                Py::Mapping(pyobj).delItem(index);
792
            }
793
            else {
794
                Py_ssize_t i = PyNumber_AsSsize_t(pyobj.ptr(), PyExc_IndexError);
795
                if (PyErr_Occurred() || PySequence_DelItem(pyobj.ptr(),i)==-1)
796
                    throw Py::Exception();
797
            }
798
        }
799
        else {
800
            Py::Object v1,v2,v3;
801
            if(e1) v1 = e1->getPyValue();
802
            if(e2) v2 = e2->getPyValue();
803
            if(e3) v3 = e3->getPyValue();
804
            PyObject *s = PySlice_New(e1?v1.ptr():nullptr,
805
                                      e2?v2.ptr():nullptr,
806
                                      e3?v3.ptr():nullptr);
807
            if (!s)
808
                throw Py::Exception();
809
            Py::Object slice(s,true);
810
            if (PyObject_DelItem(pyobj.ptr(),slice.ptr())<0)
811
                throw Py::Exception();
812
        }
813
    }
814
    catch(Py::Exception &) {
815
        EXPR_PY_THROW(owner);
816
    }
817
}
818

819
void Expression::Component::visit(ExpressionVisitor &v) {
820
    if(e1) e1->visit(v);
821
    if(e2) e2->visit(v);
822
    if(e3) e3->visit(v);
823
}
824

825
bool Expression::Component::isTouched() const {
826
    return (e1&&e1->isTouched()) ||
827
            (e2&&e2->isTouched()) ||
828
            (e3&&e3->isTouched());
829
}
830

831
void Expression::Component::toString(std::ostream &ss, bool persistent) const {
832
    if(!e1 && !e2 && !e3) {
833
        if(comp.isSimple())
834
            ss << '.';
835
        comp.toString(ss,!persistent);
836
        return;
837
    }
838
    ss << '[';
839
    if(e1)
840
        e1->toString(ss,persistent);
841
    if(e2 || comp.isRange())
842
        ss << ':';
843
    if(e2)
844
        e2->toString(ss,persistent);
845
    if(e3) {
846
        ss << ':';
847
        e3->toString(ss,persistent);
848
    }
849
    ss << ']';
850
}
851

852

853
//
854
// Expression base-class
855
//
856

857
TYPESYSTEM_SOURCE_ABSTRACT(App::Expression, Base::BaseClass)
858

859
Expression::Expression(const DocumentObject *_owner)
860
    : owner(const_cast<App::DocumentObject*>(_owner))
861
{
862

863
}
864

865
Expression::~Expression()
866
{
867
    for(auto c : components)
868
        delete c;
869
}
870

871
Expression::Component* Expression::createComponent(const std::string &n) {
872
    return new Component(n);
873
}
874

875
Expression::Component* Expression::createComponent(
876
        Expression* e1, Expression* e2, Expression* e3, bool isRange)
877
{
878
    return new Component(e1,e2,e3,isRange);
879
}
880

881

882
int Expression::priority() const {
883
    return 20;
884
}
885

886
Expression * Expression::parse(const DocumentObject *owner, const std::string &buffer)
887
{
888
    return ExpressionParser::parse(owner, buffer.c_str());
889
}
890

891
void Expression::getDeps(ExpressionDeps &deps, int option)  const {
892
    for(auto &v : getIdentifiers()) {
893
        bool hidden = v.second;
894
        const ObjectIdentifier &var = v.first;
895
        if((hidden && option==DepNormal)
896
                || (!hidden && option==DepHidden))
897
            continue;
898
        for(auto &dep : var.getDep(true)) {
899
            DocumentObject *obj = dep.first;
900
            for(auto &propName : dep.second) {
901
                deps[obj][propName].push_back(var);
902
            }
903
        }
904
    }
905
}
906

907
ExpressionDeps Expression::getDeps(int option)  const {
908
    ExpressionDeps deps;
909
    getDeps(deps, option);
910
    return deps;
911
}
912

913
void Expression::getDepObjects(
914
        std::map<App::DocumentObject*,bool> &deps, std::vector<std::string> *labels) const
915
{
916
    for(auto &v : getIdentifiers()) {
917
        bool hidden = v.second;
918
        const ObjectIdentifier &var = v.first;
919
        std::vector<std::string> strings;
920
        for(auto &dep : var.getDep(false, &strings)) {
921
            DocumentObject *obj = dep.first;
922
            if (!obj->testStatus(ObjectStatus::Remove)) {
923
                if (labels) {
924
                    std::copy(strings.begin(), strings.end(), std::back_inserter(*labels));
925
                }
926

927
                auto res = deps.insert(std::make_pair(obj, hidden));
928
                if (!hidden || res.second)
929
                    res.first->second = hidden;
930
            }
931

932
            strings.clear();
933
        }
934
    }
935
}
936

937
std::map<App::DocumentObject*,bool> Expression::getDepObjects(std::vector<std::string> *labels)  const {
938
    std::map<App::DocumentObject*,bool> deps;
939
    getDepObjects(deps,labels);
940
    return deps;
941
}
942

943
class GetIdentifiersExpressionVisitor : public ExpressionVisitor {
944
public:
945
    explicit GetIdentifiersExpressionVisitor(std::map<App::ObjectIdentifier,bool> &deps)
946
        :deps(deps)
947
    {}
948

949
    void visit(Expression &e) override {
950
        this->getIdentifiers(e,deps);
951
    }
952

953
    std::map<App::ObjectIdentifier,bool> &deps;
954
};
955

956
void Expression::getIdentifiers(std::map<App::ObjectIdentifier,bool> &deps)  const {
957
    GetIdentifiersExpressionVisitor v(deps);
958
    const_cast<Expression*>(this)->visit(v);
959
}
960

961
std::map<App::ObjectIdentifier,bool> Expression::getIdentifiers()  const {
962
    std::map<App::ObjectIdentifier,bool> deps;
963
    getIdentifiers(deps);
964
    return deps;
965
}
966

967
class AdjustLinksExpressionVisitor : public ExpressionVisitor {
968
public:
969
    explicit AdjustLinksExpressionVisitor(const std::set<App::DocumentObject*> &inList)
970
        :inList(inList)
971
    {}
972

973
    void visit(Expression &e) override {
974
        if(this->adjustLinks(e,inList))
975
            res = true;
976
    }
977

978
    const std::set<App::DocumentObject*> &inList;
979
    bool res{false};
980
};
981

982
bool Expression::adjustLinks(const std::set<App::DocumentObject*> &inList) {
983
    AdjustLinksExpressionVisitor v(inList);
984
    visit(v);
985
    return v.res;
986
}
987

988
class ImportSubNamesExpressionVisitor : public ExpressionVisitor {
989
public:
990
    explicit ImportSubNamesExpressionVisitor(const ObjectIdentifier::SubNameMap &subNameMap)
991
        :subNameMap(subNameMap)
992
    {}
993

994
    void visit(Expression &e) override {
995
        this->importSubNames(e,subNameMap);
996
    }
997

998
    const ObjectIdentifier::SubNameMap &subNameMap;
999
};
1000

1001
ExpressionPtr Expression::importSubNames(const std::map<std::string,std::string> &nameMap) const {
1002
    if(!owner || !owner->getDocument())
1003
        return nullptr;
1004
    ObjectIdentifier::SubNameMap subNameMap;
1005
    for(auto &dep : getDeps(DepAll)) {
1006
        for(auto &info : dep.second) {
1007
            for(auto &path : info.second) {
1008
                auto obj = path.getDocumentObject();
1009
                if(!obj)
1010
                    continue;
1011
                auto it = nameMap.find(obj->getExportName(true));
1012
                if(it!=nameMap.end())
1013
                    subNameMap.emplace(std::make_pair(obj,std::string()),it->second);
1014
                auto key = std::make_pair(obj,path.getSubObjectName());
1015
                if(key.second.empty() || subNameMap.count(key))
1016
                    continue;
1017
                std::string imported = PropertyLinkBase::tryImportSubName(
1018
                               obj,key.second.c_str(),owner->getDocument(), nameMap);
1019
                if(!imported.empty())
1020
                    subNameMap.emplace(std::move(key),std::move(imported));
1021
            }
1022
        }
1023
    }
1024
    if(subNameMap.empty())
1025
        return nullptr;
1026
    ImportSubNamesExpressionVisitor v(subNameMap);
1027
    auto res = copy();
1028
    res->visit(v);
1029
    return ExpressionPtr(res);
1030
}
1031

1032
class UpdateLabelExpressionVisitor : public ExpressionVisitor {
1033
public:
1034
    UpdateLabelExpressionVisitor(App::DocumentObject *obj, const std::string &ref, const char *newLabel)
1035
        :obj(obj),ref(ref),newLabel(newLabel)
1036
    {}
1037

1038
    void visit(Expression &e) override {
1039
        this->updateLabelReference(e,obj,ref,newLabel);
1040
    }
1041

1042
    App::DocumentObject *obj;
1043
    const std::string &ref;
1044
    const char *newLabel;
1045
};
1046

1047
ExpressionPtr Expression::updateLabelReference(
1048
        App::DocumentObject *obj, const std::string &ref, const char *newLabel) const
1049
{
1050
    if(ref.size()<=2)
1051
        return {};
1052
    std::vector<std::string> labels;
1053
    for(auto &v : getIdentifiers())
1054
        v.first.getDepLabels(labels);
1055
    for(auto &label : labels) {
1056
        // ref contains something like $label. and we need to strip '$' and '.'
1057
        if(ref.compare(1,ref.size()-2,label)==0) {
1058
            UpdateLabelExpressionVisitor v(obj,ref,newLabel);
1059
            auto expr = copy();
1060
            expr->visit(v);
1061
            return ExpressionPtr(expr);
1062
        }
1063
    }
1064
    return {};
1065
}
1066

1067
class ReplaceObjectExpressionVisitor : public ExpressionVisitor {
1068
public:
1069
    ReplaceObjectExpressionVisitor(const DocumentObject *parent,
1070
            DocumentObject *oldObj, DocumentObject *newObj)
1071
        : parent(parent),oldObj(oldObj),newObj(newObj)
1072
    {
1073
    }
1074

1075
    void visit(Expression &e) override {
1076
        if(collect)
1077
            this->collectReplacement(e,paths,parent,oldObj,newObj);
1078
        else
1079
            this->renameObjectIdentifier(e,paths,dummy);
1080
    }
1081

1082
    const DocumentObject *parent;
1083
    DocumentObject *oldObj;
1084
    DocumentObject *newObj;
1085
    ObjectIdentifier dummy;
1086
    std::map<ObjectIdentifier, ObjectIdentifier> paths;
1087
    bool collect = true;
1088
};
1089

1090
ExpressionPtr Expression::replaceObject(const DocumentObject *parent,
1091
        DocumentObject *oldObj, DocumentObject *newObj) const
1092
{
1093
    ReplaceObjectExpressionVisitor v(parent,oldObj,newObj);
1094

1095
    // First pass, collect any changes. We have to const_cast it, as visit() is
1096
    // not const. This is ugly...
1097
    const_cast<Expression*>(this)->visit(v);
1098

1099
    if(v.paths.empty())
1100
        return {};
1101

1102
    // Now make a copy and do the actual replacement
1103
    auto expr = copy();
1104
    v.collect = false;
1105
    expr->visit(v);
1106
    return ExpressionPtr(expr);
1107
}
1108

1109
App::any Expression::getValueAsAny() const {
1110
    Base::PyGILStateLocker lock;
1111
    return pyObjectToAny(getPyValue());
1112
}
1113

1114
Py::Object Expression::getPyValue() const {
1115
    try {
1116
        Py::Object pyobj = _getPyValue();
1117
        if(!components.empty()) {
1118
            for(auto &c : components)
1119
                pyobj = c->get(this,pyobj);
1120
        }
1121
        return pyobj;
1122
    }catch(Py::Exception &) {
1123
        EXPR_PY_THROW(this);
1124
    }
1125
    return Py::Object();
1126
}
1127

1128
void Expression::addComponent(Component *component) {
1129
    assert(component);
1130
    components.push_back(component);
1131
}
1132

1133
void Expression::visit(ExpressionVisitor &v) {
1134
    _visit(v);
1135
    for(auto &c : components)
1136
        c->visit(v);
1137
    v.visit(*this);
1138
}
1139

1140
Expression* Expression::eval() const {
1141
    Base::PyGILStateLocker lock;
1142
    return expressionFromPy(owner,getPyValue());
1143
}
1144

1145
bool Expression::isSame(const Expression &other, bool checkComment) const {
1146
    if(&other == this)
1147
        return true;
1148
    if(getTypeId()!=other.getTypeId())
1149
        return false;
1150
    return (!checkComment || comment==other.comment)
1151
        && toString(true,true) == other.toString(true,true);
1152
}
1153

1154
std::string Expression::toString(bool persistent, bool checkPriority, int indent) const {
1155
    std::ostringstream ss;
1156
    toString(ss,persistent,checkPriority,indent);
1157
    return ss.str();
1158
}
1159

1160
void Expression::toString(std::ostream &ss, bool persistent, bool checkPriority, int indent) const {
1161
    if(components.empty()) {
1162
        bool needsParens = checkPriority && priority()<20;
1163
        if(needsParens)
1164
            ss << '(';
1165
        _toString(ss,persistent,indent);
1166
        if(needsParens)
1167
            ss << ')';
1168
        return;
1169
    }
1170
    if(!_isIndexable()) {
1171
        ss << '(';
1172
        _toString(ss,persistent,indent);
1173
        ss << ')';
1174
    }else
1175
        _toString(ss,persistent,indent);
1176
    for(auto &c : components)
1177
        c->toString(ss,persistent);
1178
}
1179

1180
Expression* Expression::copy() const {
1181
    auto expr = _copy();
1182
    copy_vector(expr->components,components);
1183
    expr->comment = comment;
1184
    return expr;
1185
}
1186

1187

1188
//
1189
// UnitExpression class
1190
//
1191

1192
TYPESYSTEM_SOURCE(App::UnitExpression, App::Expression)
1193

1194
UnitExpression::UnitExpression(const DocumentObject *_owner, const Base::Quantity & _quantity, const std::string &_unitStr)
1195
    : Expression(_owner)
1196
    , quantity(_quantity)
1197
    , unitStr(_unitStr)
1198
{
1199
}
1200

1201
UnitExpression::~UnitExpression() {
1202
    if(cache) {
1203
        Base::PyGILStateLocker lock;
1204
        Py::_XDECREF(cache);
1205
    }
1206
}
1207

1208
void UnitExpression::setQuantity(const Quantity &_quantity)
1209
{
1210
    quantity = _quantity;
1211
    if(cache) {
1212
        Base::PyGILStateLocker lock;
1213
        Py::_XDECREF(cache);
1214
        cache = nullptr;
1215
    }
1216
}
1217

1218
/**
1219
  * Set unit information.
1220
  *
1221
  * @param _unit    A unit object
1222
  * @param _unitstr The unit expressed as a string
1223
  * @param _scaler  Scale factor to convert unit into internal unit.
1224
  */
1225

1226
void UnitExpression::setUnit(const Quantity &_quantity)
1227
{
1228
    quantity = _quantity;
1229
    if(cache) {
1230
        Base::PyGILStateLocker lock;
1231
        Py::_XDECREF(cache);
1232
        cache = nullptr;
1233
    }
1234
}
1235

1236
/**
1237
  * Simplify the expression. In this case, a NumberExpression is returned,
1238
  * as it cannot be simplified any more.
1239
  */
1240

1241
Expression *UnitExpression::simplify() const
1242
{
1243
    return new NumberExpression(owner, quantity);
1244
}
1245

1246
/**
1247
  * Return a string representation, in this case the unit string.
1248
  */
1249

1250
/**
1251
  * Return a string representation of the expression.
1252
  */
1253

1254
void UnitExpression::_toString(std::ostream &ss, bool,int) const
1255
{
1256
    ss << unitStr;
1257
}
1258

1259
/**
1260
  * Return a copy of the expression.
1261
  */
1262

1263
Expression *UnitExpression::_copy() const
1264
{
1265
    return new UnitExpression(owner, quantity, unitStr);
1266
}
1267

1268
Py::Object UnitExpression::_getPyValue() const {
1269
    if(!cache)
1270
        cache = Py::new_reference_to(pyFromQuantity(quantity));
1271
    return Py::Object(cache);
1272
}
1273

1274
//
1275
// NumberExpression class
1276
//
1277

1278
TYPESYSTEM_SOURCE(App::NumberExpression, App::Expression)
1279

1280
NumberExpression::NumberExpression(const DocumentObject *_owner, const Quantity &_quantity)
1281
    : UnitExpression(_owner, _quantity)
1282
{
1283
}
1284

1285
/**
1286
  * Simplify the expression. For NumberExpressions, we return a copy(), as it cannot
1287
  * be simplified any more.
1288
  */
1289

1290
Expression *NumberExpression::simplify() const
1291
{
1292
    return copy();
1293
}
1294

1295
/**
1296
  * Create and return a copy of the expression.
1297
  */
1298

1299
Expression *NumberExpression::_copy() const
1300
{
1301
    return new NumberExpression(owner, getQuantity());
1302
}
1303

1304
/**
1305
  * Negate the stored value.
1306
  */
1307

1308
void NumberExpression::negate()
1309
{
1310
    setQuantity(-getQuantity());
1311
}
1312

1313
void NumberExpression::_toString(std::ostream &ss, bool,int) const
1314
{
1315
    // Restore the old implementation because using digits10 + 2 causes
1316
    // undesired side-effects:
1317
    // https://forum.freecad.org/viewtopic.php?f=3&t=44057&p=375882#p375882
1318
    // See also:
1319
    // https://en.cppreference.com/w/cpp/types/numeric_limits/digits10
1320
    // https://en.cppreference.com/w/cpp/types/numeric_limits/max_digits10
1321
    // https://www.boost.org/doc/libs/1_63_0/libs/multiprecision/doc/html/boost_multiprecision/tut/limits/constants.html
1322
    boost::io::ios_flags_saver ifs(ss);
1323
    ss << std::setprecision(std::numeric_limits<double>::digits10) << getValue();
1324

1325
    /* Trim of any extra spaces */
1326
    //while (s.size() > 0 && s[s.size() - 1] == ' ')
1327
//        s.erase(s.size() - 1);
1328
}
1329

1330
bool NumberExpression::isInteger(long *l) const {
1331
    long _l;
1332
    if(!l)
1333
        l = &_l;
1334
    return essentiallyInteger(getValue(),*l);
1335
}
1336

1337
//
1338
// OperatorExpression class
1339
//
1340

1341
TYPESYSTEM_SOURCE(App::OperatorExpression, App::Expression)
1342

1343
OperatorExpression::OperatorExpression(const App::DocumentObject *_owner, Expression * _left, Operator _op, Expression * _right)
1344
    : UnitExpression(_owner)
1345
    , op(_op)
1346
    , left(_left)
1347
    , right(_right)
1348
{
1349

1350
}
1351

1352
OperatorExpression::~OperatorExpression()
1353
{
1354
    delete left;
1355
    delete right;
1356
}
1357

1358
/**
1359
  * Determine whether the expression is touched or not, i.e relies on properties that are touched.
1360
  */
1361

1362
bool OperatorExpression::isTouched() const
1363
{
1364
    return left->isTouched() || right->isTouched();
1365
}
1366

1367
static Py::Object calc(const Expression *expr, int op,
1368
                 const Expression *left, const Expression *right, bool inplace)
1369
{
1370
    Py::Object l = left->getPyValue();
1371

1372
    // For security reason, restrict supported types
1373
    if(!PyObject_TypeCheck(l.ptr(),&PyObjectBase::Type)
1374
            && !l.isNumeric() && !l.isString() && !l.isList() && !l.isDict())
1375
    {
1376
        __EXPR_THROW(Base::TypeError,"Unsupported operator", expr);
1377
    }
1378

1379
    // check possible unary operation first
1380
    switch(op) {
1381
    case OperatorExpression::POS:{
1382
        PyObject *res = PyNumber_Positive(l.ptr());
1383
        if(!res) EXPR_PY_THROW(expr);
1384
        return Py::asObject(res);
1385
    }
1386
    case OperatorExpression::NEG:{
1387
        PyObject *res = PyNumber_Negative(l.ptr());
1388
        if(!res) EXPR_PY_THROW(expr);
1389
        return Py::asObject(res);
1390
    } default:
1391
        break;
1392
    }
1393

1394
    Py::Object r = right->getPyValue();
1395
    // For security reason, restrict supported types
1396
    if((op!=OperatorExpression::MOD || !l.isString())
1397
            && !PyObject_TypeCheck(r.ptr(),&PyObjectBase::Type)
1398
                && !r.isNumeric()
1399
                && !r.isString()
1400
                && !r.isList()
1401
                && !r.isDict())
1402
    {
1403
        __EXPR_THROW(Base::TypeError,"Unsupported operator", expr);
1404
    }
1405

1406
    switch(op) {
1407
#define RICH_COMPARE(_op,_pyop) \
1408
    case OperatorExpression::_op: {\
1409
        int res = PyObject_RichCompareBool(l.ptr(),r.ptr(),Py_##_pyop);\
1410
        if(res<0) EXPR_PY_THROW(expr);\
1411
        return Py::Boolean(!!res);\
1412
    }
1413
    RICH_COMPARE(LT,LT)
1414
    RICH_COMPARE(LTE,LE)
1415
    RICH_COMPARE(GT,GT)
1416
    RICH_COMPARE(GTE,GE)
1417
    RICH_COMPARE(EQ,EQ)
1418
    RICH_COMPARE(NEQ,NE)
1419

1420
#define _BINARY_OP(_pyop) \
1421
        res = inplace?PyNumber_InPlace##_pyop(l.ptr(),r.ptr()):\
1422
                       PyNumber_##_pyop(l.ptr(),r.ptr());\
1423
        if(!res) EXPR_PY_THROW(expr);\
1424
        return Py::asObject(res);
1425

1426
#define BINARY_OP(_op,_pyop) \
1427
    case OperatorExpression::_op: {\
1428
        PyObject *res;\
1429
        _BINARY_OP(_pyop);\
1430
    }
1431

1432
    BINARY_OP(SUB,Subtract)
1433
    BINARY_OP(MUL,Multiply)
1434
    BINARY_OP(UNIT,Multiply)
1435
    BINARY_OP(DIV,TrueDivide)
1436
    case OperatorExpression::ADD: {
1437
        PyObject *res;
1438
        if (PyUnicode_CheckExact(*l) && PyUnicode_CheckExact(*r)) {
1439
            if(inplace) {
1440
                res = Py::new_reference_to(l);
1441
                // Try to make sure ob_refcnt is 1, although unlike
1442
                // PyString_Resize above, PyUnicode_Append can handle other
1443
                // cases.
1444
                l = Py::Object();
1445
                PyUnicode_Append(&res, r.ptr());
1446
            }else
1447
                res = PyUnicode_Concat(l.ptr(),r.ptr());
1448
            if(!res) EXPR_PY_THROW(expr);
1449
            return Py::asObject(res);
1450
        }
1451
        _BINARY_OP(Add);
1452
    }
1453
    case OperatorExpression::POW: {
1454
        PyObject *res;
1455
        if(inplace)
1456
            res = PyNumber_InPlacePower(l.ptr(),r.ptr(),Py::None().ptr());
1457
        else
1458
            res = PyNumber_Power(l.ptr(),r.ptr(),Py::None().ptr());
1459
        if(!res) EXPR_PY_THROW(expr);
1460
        return Py::asObject(res);
1461
    }
1462
    case OperatorExpression::MOD: {
1463
        PyObject *res;
1464
        if (PyUnicode_CheckExact(l.ptr()) &&
1465
                (!PyUnicode_Check(r.ptr()) || PyUnicode_CheckExact(r.ptr())))
1466
            res = PyUnicode_Format(l.ptr(), r.ptr());
1467
        else if(inplace)
1468
            res = PyNumber_InPlaceRemainder(l.ptr(),r.ptr());
1469
        else
1470
            res = PyNumber_InPlaceRemainder(l.ptr(),r.ptr());
1471
        if(!res) EXPR_PY_THROW(expr);
1472
        return Py::asObject(res);
1473
    }
1474
    default:
1475
        __EXPR_THROW(RuntimeError,"Unsupported operator",expr);
1476
    }
1477
}
1478

1479
Py::Object OperatorExpression::_getPyValue() const {
1480
    return calc(this,op,left,right,false);
1481
}
1482

1483
/**
1484
  * Simplify the expression. For OperatorExpressions, we return a NumberExpression if
1485
  * both the left and right side can be simplified to NumberExpressions. In this case
1486
  * we can calculate the final value of the expression.
1487
  *
1488
  * @returns Simplified expression.
1489
  */
1490

1491
Expression *OperatorExpression::simplify() const
1492
{
1493
    Expression * v1 = left->simplify();
1494
    Expression * v2 = right->simplify();
1495

1496
    // Both arguments reduced to numerics? Then evaluate and return answer
1497
    if (freecad_dynamic_cast<NumberExpression>(v1) && freecad_dynamic_cast<NumberExpression>(v2)) {
1498
        delete v1;
1499
        delete v2;
1500
        return eval();
1501
    }
1502
    else
1503
        return new OperatorExpression(owner, v1, op, v2);
1504
}
1505

1506
/**
1507
  * Create a string representation of the expression.
1508
  *
1509
  * @returns A string representing the expression.
1510
  */
1511

1512
void OperatorExpression::_toString(std::ostream &s, bool persistent,int) const
1513
{
1514
    bool needsParens;
1515
    Operator leftOperator(NONE), rightOperator(NONE);
1516

1517
    needsParens = false;
1518
    if (freecad_dynamic_cast<OperatorExpression>(left))
1519
        leftOperator = static_cast<OperatorExpression*>(left)->op;
1520
    if (left->priority() < priority()) // Check on operator priority first
1521
        needsParens = true;
1522
    else if (leftOperator == op) { // Same operator ?
1523
        if (!isLeftAssociative())
1524
            needsParens = true;
1525
        //else if (!isCommutative())
1526
        //    needsParens = true;
1527
    }
1528

1529
    switch (op) {
1530
    case NEG:
1531
        s << "-" << (needsParens ? "(" : "") << left->toString(persistent) << (needsParens ? ")" : "");
1532
        return;
1533
    case POS:
1534
        s << "+" << (needsParens ? "(" : "") << left->toString(persistent) << (needsParens ? ")" : "");
1535
        return;
1536
    default:
1537
        break;
1538
    }
1539

1540
    if (needsParens)
1541
        s << "(" << left->toString(persistent) << ")";
1542
    else
1543
        s << left->toString(persistent);
1544

1545
    switch (op) {
1546
    case ADD:
1547
        s << " + ";
1548
        break;
1549
    case SUB:
1550
        s << " - ";
1551
        break;
1552
    case MUL:
1553
        s << " * ";
1554
        break;
1555
    case DIV:
1556
        s << " / ";
1557
        break;
1558
    case MOD:
1559
        s << " % ";
1560
        break;
1561
    case POW:
1562
        s << " ^ ";
1563
        break;
1564
    case EQ:
1565
        s << " == ";
1566
        break;
1567
    case NEQ:
1568
        s << " != ";
1569
        break;
1570
    case LT:
1571
        s << " < ";
1572
        break;
1573
    case GT:
1574
        s << " > ";
1575
        break;
1576
    case LTE:
1577
        s << " <= ";
1578
        break;
1579
    case GTE:
1580
        s << " >= ";
1581
        break;
1582
    case UNIT:
1583
        s << " ";
1584
        break;
1585
    default:
1586
        assert(0);
1587
    }
1588

1589
    needsParens = false;
1590
    if (freecad_dynamic_cast<OperatorExpression>(right))
1591
        rightOperator = static_cast<OperatorExpression*>(right)->op;
1592
    if (right->priority() < priority()) // Check on operator priority first
1593
        needsParens = true;
1594
    else if (rightOperator == op) { // Same operator ?
1595
        if (!isRightAssociative())
1596
            needsParens = true;
1597
        else if (!isCommutative())
1598
            needsParens = true;
1599
    }
1600
    else if (right->priority() == priority()) { // Same priority ?
1601
        if (!isRightAssociative() || rightOperator == MOD)
1602
            needsParens = true;
1603
    }
1604

1605
    if (needsParens) {
1606
        s << "(";
1607
        right->toString(s,persistent);
1608
        s << ")";
1609
    }else
1610
        right->toString(s,persistent);
1611
}
1612

1613
/**
1614
  * A deep copy of the expression.
1615
  */
1616

1617
Expression *OperatorExpression::_copy() const
1618
{
1619
    return new OperatorExpression(owner, left->copy(), op, right->copy());
1620
}
1621

1622
/**
1623
  * Return the operators priority. This is used to add parentheses where
1624
  * needed when creating a string representation of the expression.
1625
  *
1626
  * @returns The operator's priority.
1627
  */
1628

1629
int OperatorExpression::priority() const
1630
{
1631
    switch (op) {
1632
    case EQ:
1633
    case NEQ:
1634
    case LT:
1635
    case GT:
1636
    case LTE:
1637
    case GTE:
1638
        return 1;
1639
    case ADD:
1640
    case SUB:
1641
        return 3;
1642
    case MUL:
1643
    case DIV:
1644
    case MOD:
1645
        return 4;
1646
    case POW:
1647
        return 5;
1648
    case UNIT:
1649
    case NEG:
1650
    case POS:
1651
        return 6;
1652
    default:
1653
        assert(false);
1654
        return 0;
1655
    }
1656
}
1657

1658
void OperatorExpression::_visit(ExpressionVisitor &v)
1659
{
1660
    if (left)
1661
        left->visit(v);
1662
    if (right)
1663
        right->visit(v);
1664
}
1665

1666
bool OperatorExpression::isCommutative() const
1667
{
1668
    switch (op) {
1669
    case EQ:
1670
    case NEQ:
1671
    case ADD:
1672
    case MUL:
1673
        return true;
1674
    default:
1675
        return false;
1676
    }
1677
}
1678

1679
bool OperatorExpression::isLeftAssociative() const
1680
{
1681
    return true;
1682
}
1683

1684
bool OperatorExpression::isRightAssociative() const
1685
{
1686
    switch (op) {
1687
    case ADD:
1688
    case MUL:
1689
        return true;
1690
    default:
1691
        return false;
1692
    }
1693
}
1694

1695
//
1696
// FunctionExpression class. This class handles functions with one or two parameters.
1697
//
1698

1699
TYPESYSTEM_SOURCE(App::FunctionExpression, App::UnitExpression)
1700

1701
static int _HiddenReference;
1702

1703
struct HiddenReference {
1704
    explicit HiddenReference(bool cond)
1705
        :cond(cond)
1706
    {
1707
        if(cond)
1708
            ++_HiddenReference;
1709
    }
1710
    ~HiddenReference() {
1711
        if(cond)
1712
            --_HiddenReference;
1713
    }
1714

1715
    static bool check(int option) {
1716
        return (option==Expression::DepNormal && _HiddenReference)
1717
            || (option==Expression::DepHidden && !_HiddenReference);
1718
    }
1719

1720
    static bool isHidden() {
1721
        return _HiddenReference!=0;
1722
    }
1723

1724
    bool cond;
1725
};
1726

1727
FunctionExpression::FunctionExpression(const DocumentObject *_owner, Function _f, std::string &&name, std::vector<Expression *> _args)
1728
    : UnitExpression(_owner)
1729
    , f(_f)
1730
    , fname(std::move(name))
1731
    , args(_args)
1732
{
1733
    switch (f) {
1734
    case ABS:
1735
    case ACOS:
1736
    case ASIN:
1737
    case ATAN:
1738
    case CBRT:
1739
    case CEIL:
1740
    case COS:
1741
    case COSH:
1742
    case EXP:
1743
    case FLOOR:
1744
    case HIDDENREF:
1745
    case HREF:
1746
    case LOG:
1747
    case LOG10:
1748
    case MINVERT:
1749
    case ROTATIONX:
1750
    case ROTATIONY:
1751
    case ROTATIONZ:
1752
    case ROUND:
1753
    case SIN:
1754
    case SINH:
1755
    case SQRT:
1756
    case STR:
1757
    case PARSEQUANT:
1758
    case TAN:
1759
    case TANH:
1760
    case TRUNC:
1761
    case VNORMALIZE:
1762
        if (args.size() != 1)
1763
            ARGUMENT_THROW("exactly one required.");
1764
        break;
1765
    case PLACEMENT:
1766
        if (args.size() > 3)
1767
            ARGUMENT_THROW("exactly one, two, or three required.");
1768
        break;
1769
    case TRANSLATIONM:
1770
        if (args.size() != 1 && args.size() != 3)
1771
            ARGUMENT_THROW("exactly one or three required.");
1772
        break;
1773
    case ATAN2:
1774
    case MOD:
1775
    case MROTATEX:
1776
    case MROTATEY:
1777
    case MROTATEZ:
1778
    case POW:
1779
    case VANGLE:
1780
    case VCROSS:
1781
    case VDOT:
1782
    case VSCALEX:
1783
    case VSCALEY:
1784
    case VSCALEZ:
1785
        if (args.size() != 2)
1786
            ARGUMENT_THROW("exactly two required.");
1787
        break;
1788
    case CATH:
1789
    case HYPOT:
1790
    case ROTATION:
1791
        if (args.size() < 2 || args.size() > 3)
1792
            ARGUMENT_THROW("exactly two, or three required.");
1793
        break;
1794
    case MTRANSLATE:
1795
    case MSCALE:
1796
        if (args.size() != 2 && args.size() != 4)
1797
            ARGUMENT_THROW("exactly two or four required.");
1798
        break;
1799
    case MROTATE:
1800
        if (args.size() < 2 || args.size() > 4)
1801
            ARGUMENT_THROW("exactly two, three, or four required.");
1802
        break;
1803
    case VECTOR:
1804
    case VLINEDIST:
1805
    case VLINESEGDIST:
1806
    case VLINEPROJ:
1807
    case VPLANEDIST:
1808
    case VPLANEPROJ:
1809
        if (args.size() != 3)
1810
            ARGUMENT_THROW("exactly three required.");
1811
        break;
1812
    case VSCALE:
1813
        if (args.size() != 4)
1814
            ARGUMENT_THROW("exactly four required.");
1815
        break;
1816
    case MATRIX:
1817
        if (args.size() > 16)
1818
            ARGUMENT_THROW("exactly 16 or less required.");
1819
        break;
1820
    case AVERAGE:
1821
    case COUNT:
1822
    case CREATE:
1823
    case MAX:
1824
    case MIN:
1825
    case STDDEV:
1826
    case SUM:
1827
        if (args.empty())
1828
            ARGUMENT_THROW("at least one required.");
1829
        break;
1830
    case LIST:
1831
    case TUPLE:
1832
        break;
1833
    case AGGREGATES:
1834
    case LAST:
1835
    case NONE:
1836
    default:
1837
        PARSER_THROW("Unknown function");
1838
        break;
1839
    }
1840
}
1841

1842
FunctionExpression::~FunctionExpression()
1843
{
1844
    std::vector<Expression*>::iterator i = args.begin();
1845

1846
    while (i != args.end()) {
1847
        delete *i;
1848
        ++i;
1849
    }
1850
}
1851

1852
/**
1853
  * Determine whether the expressions is considered touched, i.e one or both of its arguments
1854
  * are touched.
1855
  *
1856
  * @return True if touched, false if not.
1857
  */
1858

1859
bool FunctionExpression::isTouched() const
1860
{
1861
    std::vector<Expression*>::const_iterator i = args.begin();
1862

1863
    while (i != args.end()) {
1864
        if ((*i)->isTouched())
1865
            return true;
1866
        ++i;
1867
    }
1868
    return false;
1869
}
1870

1871
/* Various collectors for aggregate functions */
1872

1873
class Collector {
1874
public:
1875
    Collector() = default;
1876
    virtual ~Collector() = default;
1877
    virtual void collect(Quantity value) {
1878
        if (first)
1879
            q.setUnit(value.getUnit());
1880
    }
1881
    virtual Quantity getQuantity() const {
1882
        return q;
1883
    }
1884
protected:
1885
    bool first{true};
1886
    Quantity q;
1887
};
1888

1889
class SumCollector : public Collector {
1890
public:
1891
    SumCollector() : Collector() { }
1892

1893
    void collect(Quantity value) override {
1894
        Collector::collect(value);
1895
        q += value;
1896
        first = false;
1897
    }
1898

1899
};
1900

1901
class AverageCollector : public Collector {
1902
public:
1903
    AverageCollector() : Collector() { }
1904

1905
    void collect(Quantity value) override {
1906
        Collector::collect(value);
1907
        q += value;
1908
        ++n;
1909
        first = false;
1910
    }
1911

1912
    Quantity getQuantity() const override { return q/(double)n; }
1913

1914
private:
1915
    unsigned int n{0};
1916
};
1917

1918
class StdDevCollector : public Collector {
1919
public:
1920
    StdDevCollector() : Collector() { }
1921

1922
    void collect(Quantity value) override {
1923
        Collector::collect(value);
1924
        if (first) {
1925
            M2 = Quantity(0, value.getUnit() * value.getUnit());
1926
            mean = Quantity(0, value.getUnit());
1927
            n = 0;
1928
        }
1929

1930
        const Quantity delta = value - mean;
1931
        ++n;
1932
        mean = mean + delta / n;
1933
        M2 = M2 + delta * (value - mean);
1934
        first = false;
1935
    }
1936

1937
    Quantity getQuantity() const override {
1938
        if (n < 2)
1939
            throw ExpressionError("Invalid number of entries: at least two required.");
1940
        else
1941
            return Quantity((M2 / (n - 1.0)).pow(Quantity(0.5)).getValue(), mean.getUnit());
1942
    }
1943

1944
private:
1945
    unsigned int n{0};
1946
    Quantity mean;
1947
    Quantity M2;
1948
};
1949

1950
class CountCollector : public Collector {
1951
public:
1952
    CountCollector() : Collector() { }
1953

1954
    void collect(Quantity value) override {
1955
        Collector::collect(value);
1956
        ++n;
1957
        first = false;
1958
    }
1959

1960
    Quantity getQuantity() const override { return Quantity(n); }
1961

1962
private:
1963
    unsigned int n{0};
1964
};
1965

1966
class MinCollector : public Collector {
1967
public:
1968
    MinCollector() : Collector() { }
1969

1970
    void collect(Quantity value) override {
1971
        Collector::collect(value);
1972
        if (first || value < q)
1973
            q = value;
1974
        first = false;
1975
    }
1976
};
1977

1978
class MaxCollector : public Collector {
1979
public:
1980
    MaxCollector() : Collector() { }
1981

1982
    void collect(Quantity value) override {
1983
        Collector::collect(value);
1984
        if (first || value > q)
1985
            q = value;
1986
        first = false;
1987
    }
1988
};
1989

1990
Py::Object FunctionExpression::evalAggregate(
1991
        const Expression *owner, int f, const std::vector<Expression*> &args)
1992
{
1993
    std::unique_ptr<Collector> c;
1994

1995
    switch (f) {
1996
    case SUM:
1997
        c = std::make_unique<SumCollector>();
1998
        break;
1999
    case AVERAGE:
2000
        c = std::make_unique<AverageCollector>();
2001
        break;
2002
    case STDDEV:
2003
        c = std::make_unique<StdDevCollector>();
2004
        break;
2005
    case COUNT:
2006
        c = std::make_unique<CountCollector>();
2007
        break;
2008
    case MIN:
2009
        c = std::make_unique<MinCollector>();
2010
        break;
2011
    case MAX:
2012
        c = std::make_unique<MaxCollector>();
2013
        break;
2014
    default:
2015
        assert(false);
2016
    }
2017

2018
    for (auto &arg : args) {
2019
        if (arg->isDerivedFrom(RangeExpression::getClassTypeId())) {
2020
            Range range(static_cast<const RangeExpression&>(*arg).getRange());
2021

2022
            do {
2023
                Property * p = owner->getOwner()->getPropertyByName(range.address().c_str());
2024
                PropertyQuantity * qp;
2025
                PropertyFloat * fp;
2026
                PropertyInteger * ip;
2027

2028
                if (!p)
2029
                    continue;
2030

2031
                if ((qp = freecad_dynamic_cast<PropertyQuantity>(p)))
2032
                    c->collect(qp->getQuantityValue());
2033
                else if ((fp = freecad_dynamic_cast<PropertyFloat>(p)))
2034
                    c->collect(Quantity(fp->getValue()));
2035
                else if ((ip = freecad_dynamic_cast<PropertyInteger>(p)))
2036
                    c->collect(Quantity(ip->getValue()));
2037
                else
2038
                    _EXPR_THROW("Invalid property type for aggregate.", owner);
2039
            } while (range.next());
2040
        }
2041
        else {
2042
            Quantity q;
2043
            if(pyToQuantity(q,arg->getPyValue()))
2044
                c->collect(q);
2045
        }
2046
    }
2047

2048
    return pyFromQuantity(c->getQuantity());
2049
}
2050

2051
Base::Vector3d FunctionExpression::evaluateSecondVectorArgument(const Expression *expression, const std::vector<Expression*> &arguments)
2052
{
2053
    Py::Tuple vectorValues;
2054
    Py::Object secondParameter = arguments[1]->getPyValue();
2055

2056
    if (arguments.size() == 2) {
2057
        if (!secondParameter.isSequence())
2058
            _EXPR_THROW("Second parameter is not a sequence type: '" << secondParameter.as_string() << "'.", expression);
2059
        if (PySequence_Size(secondParameter.ptr()) != 3)
2060
            _EXPR_THROW("Second parameter provided has " << PySequence_Size(secondParameter.ptr()) << " elements instead of 3.", expression);
2061

2062
        vectorValues = Py::Tuple(Py::Sequence(secondParameter));
2063
    } else {
2064
        vectorValues = Py::Tuple(3);
2065
        vectorValues.setItem(0, secondParameter);
2066
        vectorValues.setItem(1, arguments[2]->getPyValue());
2067
        vectorValues.setItem(2, arguments[3]->getPyValue());
2068
    }
2069

2070
    Vector3d vector;
2071
    if (!PyArg_ParseTuple(vectorValues.ptr(), "ddd", &vector.x, &vector.y, &vector.z)) {
2072
        PyErr_Clear();
2073
        _EXPR_THROW("Error parsing scale values.", expression);
2074
    }
2075

2076
    return vector;
2077
}
2078

2079
void FunctionExpression::initialiseObject(const Py::Object *object, const std::vector<Expression*> &arguments, const unsigned long offset)
2080
{
2081
    if (arguments.size() > offset) {
2082
        Py::Tuple constructorArguments(arguments.size() - offset);
2083
        for (unsigned i = offset; i < arguments.size(); ++i)
2084
            constructorArguments.setItem(i - offset, arguments[i]->getPyValue());
2085
        Py::Dict kwd;
2086
        PyObjectBase::__PyInit(object->ptr(), constructorArguments.ptr(), kwd.ptr());
2087
    }
2088
}
2089

2090
Py::Object FunctionExpression::transformFirstArgument(
2091
    const Expression* expression,
2092
    const std::vector<Expression*> &arguments,
2093
    const Base::Matrix4D* transformationMatrix
2094
)
2095
{
2096
    Py::Object target = arguments[0]->getPyValue();
2097

2098
    if (PyObject_TypeCheck(target.ptr(), &Base::MatrixPy::Type)) {
2099
        Base::Matrix4D matrix = static_cast<Base::MatrixPy*>(target.ptr())->value();
2100
        return Py::asObject(new Base::MatrixPy(*transformationMatrix * matrix));
2101
    } else if (PyObject_TypeCheck(target.ptr(), &Base::PlacementPy::Type)) {
2102
        Base::Matrix4D placementMatrix =
2103
            static_cast<Base::PlacementPy*>(target.ptr())->getPlacementPtr()->toMatrix();
2104
        return Py::asObject(new Base::PlacementPy(Base::Placement(*transformationMatrix * placementMatrix)));
2105
    } else if (PyObject_TypeCheck(target.ptr(), &Base::RotationPy::Type)) {
2106
        Base::Matrix4D rotatioMatrix;
2107
        static_cast<Base::RotationPy*>(target.ptr())->getRotationPtr()->getValue(rotatioMatrix);
2108
        return Py::asObject(new Base::RotationPy(Base::Rotation(*transformationMatrix * rotatioMatrix)));
2109
    }
2110

2111
    _EXPR_THROW("Function requires the first argument to be either Matrix, Placement or Rotation.", expression);
2112
}
2113

2114
Py::Object FunctionExpression::translationMatrix(double x, double y, double z)
2115
{
2116
    Base::Matrix4D matrix;
2117
    matrix.move(x, y, z);
2118
    return Py::asObject(new Base::MatrixPy(matrix));
2119
}
2120

2121
double FunctionExpression::extractLengthValueArgument(
2122
    const Expression *expression,
2123
    const std::vector<Expression*> &arguments,
2124
    int argumentIndex
2125
)
2126
{
2127
    Quantity argumentQuantity = pyToQuantity(arguments[argumentIndex]->getPyValue(), expression);
2128

2129
    if (!(argumentQuantity.isDimensionlessOrUnit(Unit::Length))) {
2130
        _EXPR_THROW("Unit must be either empty or a length.", expression);
2131
    }
2132

2133
    return argumentQuantity.getValue();
2134
}
2135

2136
Base::Vector3d FunctionExpression::extractVectorArgument(
2137
    const Expression *expression,
2138
    const std::vector<Expression*> &arguments,
2139
    int argumentIndex
2140
)
2141
{
2142
    Py::Object argument = arguments[argumentIndex]->getPyValue();
2143

2144
    if (!PyObject_TypeCheck(argument.ptr(), &Base::VectorPy::Type)) {
2145
        _EXPR_THROW("Argument must be a vector.", expression);
2146
    }
2147

2148
    return static_cast<Base::VectorPy*>(argument.ptr())->value();
2149
}
2150

2151
Py::Object FunctionExpression::evaluate(const Expression *expr, int f, const std::vector<Expression*> &args)
2152
{
2153
    if(!expr || !expr->getOwner())
2154
        _EXPR_THROW("Invalid owner.", expr);
2155

2156
    // Handle aggregate functions
2157
    if (f > AGGREGATES)
2158
        return evalAggregate(expr, f, args);
2159

2160
    switch (f) {
2161
    case LIST: {
2162
        if (args.size() == 1 && args[0]->isDerivedFrom(RangeExpression::getClassTypeId()))
2163
            return args[0]->getPyValue();
2164
        Py::List list(args.size());
2165
        int i = 0;
2166
        for (auto &arg : args)
2167
            list.setItem(i++, arg->getPyValue());
2168
        return list;
2169
    }
2170
    case TUPLE: {
2171
        if (args.size() == 1 && args[0]->isDerivedFrom(RangeExpression::getClassTypeId()))
2172
            return Py::Tuple(args[0]->getPyValue());
2173
        Py::Tuple tuple(args.size());
2174
        int i = 0;
2175
        for (auto &arg : args)
2176
            tuple.setItem(i++, arg->getPyValue());
2177
        return tuple;
2178
    }
2179
    }
2180

2181
    if(args.empty())
2182
        _EXPR_THROW("Function requires at least one argument.",expr);
2183

2184
    switch (f) {
2185
    case MINVERT: {
2186
        Py::Object pyobj = args[0]->getPyValue();
2187
        if (PyObject_TypeCheck(pyobj.ptr(), &Base::MatrixPy::Type)) {
2188
            auto m = static_cast<Base::MatrixPy*>(pyobj.ptr())->value();
2189
            if (fabs(m.determinant()) <= DBL_EPSILON)
2190
                _EXPR_THROW("Cannot invert singular matrix.", expr);
2191
            m.inverseGauss();
2192
            return Py::asObject(new Base::MatrixPy(m));
2193
        } else if (PyObject_TypeCheck(pyobj.ptr(), &Base::PlacementPy::Type)) {
2194
            const auto &pla = *static_cast<Base::PlacementPy*>(pyobj.ptr())->getPlacementPtr();
2195
            return Py::asObject(new Base::PlacementPy(pla.inverse()));
2196
        } else if (PyObject_TypeCheck(pyobj.ptr(), &Base::RotationPy::Type)) {
2197
            const auto &rot = *static_cast<Base::RotationPy*>(pyobj.ptr())->getRotationPtr();
2198
            return Py::asObject(new Base::RotationPy(rot.inverse()));
2199
        }
2200
        _EXPR_THROW(
2201
            "Function requires the first argument to be either Matrix, Placement or Rotation.",
2202
            expr);
2203
        break;
2204
    }
2205
    case MROTATE: {
2206
        Py::Object rotationObject = args[1]->getPyValue();
2207
        if (!PyObject_TypeCheck(rotationObject.ptr(), &Base::RotationPy::Type))
2208
        {
2209
            rotationObject = Py::asObject(new Base::RotationPy(Base::Rotation()));
2210
            initialiseObject(&rotationObject, args, 1);
2211
        }
2212

2213
        Base::Matrix4D rotationMatrix;
2214
        static_cast<Base::RotationPy*>(rotationObject.ptr())->getRotationPtr()->getValue(rotationMatrix);
2215

2216
        return transformFirstArgument(expr, args, &rotationMatrix);
2217
    }
2218
    case MROTATEX:
2219
    case MROTATEY:
2220
    case MROTATEZ:
2221
    {
2222
        Py::Object rotationAngleParameter = args[1]->getPyValue();
2223
        Quantity rotationAngle = pyToQuantity(rotationAngleParameter, expr, "Invalid rotation angle.");
2224

2225
        if (!(rotationAngle.isDimensionlessOrUnit(Unit::Angle)))
2226
            _EXPR_THROW("Unit must be either empty or an angle.", expr);
2227

2228
        Rotation rotation = Base::Rotation(
2229
            Vector3d(static_cast<double>(f == MROTATEX), static_cast<double>(f == MROTATEY), static_cast<double>(f == MROTATEZ)),
2230
            rotationAngle.getValue() * M_PI / 180.0);
2231
        Base::Matrix4D rotationMatrix;
2232
        rotation.getValue(rotationMatrix);
2233

2234
        return transformFirstArgument(expr, args, &rotationMatrix);
2235
    }
2236
    case MSCALE: {
2237
        Vector3d scaleValues = evaluateSecondVectorArgument(expr, args);
2238

2239
        Base::Matrix4D scaleMatrix;
2240
        scaleMatrix.scale(scaleValues);
2241

2242
        return transformFirstArgument(expr, args, &scaleMatrix);
2243
    }
2244
    case MTRANSLATE: {
2245
        Vector3d translateValues = evaluateSecondVectorArgument(expr, args);
2246

2247
        Base::Matrix4D translateMatrix;
2248
        translateMatrix.move(translateValues);
2249

2250
        Py::Object target = args[0]->getPyValue();
2251
        if (PyObject_TypeCheck(target.ptr(), &Base::RotationPy::Type)) {
2252
            Base::Matrix4D targetRotatioMatrix;
2253
            static_cast<Base::RotationPy*>(target.ptr())->getRotationPtr()->getValue(targetRotatioMatrix);
2254
            return Py::asObject(new Base::PlacementPy(Base::Placement(translateMatrix * targetRotatioMatrix)));
2255
        }
2256

2257
        return transformFirstArgument(expr, args, &translateMatrix);
2258
    }
2259
    case CREATE: {
2260
        Py::Object pytype = args[0]->getPyValue();
2261
        if (!pytype.isString())
2262
            _EXPR_THROW("Function requires the first argument to be a string.", expr);
2263
        std::string type(pytype.as_string());
2264
        Py::Object res;
2265
        if (boost::iequals(type, "matrix"))
2266
            res = Py::asObject(new Base::MatrixPy(Base::Matrix4D()));
2267
        else if (boost::iequals(type, "vector"))
2268
            res = Py::asObject(new Base::VectorPy(Base::Vector3d()));
2269
        else if (boost::iequals(type, "placement"))
2270
            res = Py::asObject(new Base::PlacementPy(Base::Placement()));
2271
        else if (boost::iequals(type, "rotation"))
2272
            res = Py::asObject(new Base::RotationPy(Base::Rotation()));
2273
        else
2274
            _EXPR_THROW("Unknown type '" << type << "'.", expr);
2275
        initialiseObject(&res, args, 1);
2276
        return res;
2277
    }
2278
    case MATRIX: {
2279
        Py::Object matrix = Py::asObject(new Base::MatrixPy(Base::Matrix4D()));
2280
        initialiseObject(&matrix, args);
2281
        return matrix;
2282
    }
2283
    case PLACEMENT: {
2284
        Py::Object placement = Py::asObject(new Base::PlacementPy(Base::Placement()));
2285
        initialiseObject(&placement, args);
2286
        return placement;
2287
    }
2288
    case ROTATION: {
2289
        Py::Object rotation = Py::asObject(new Base::RotationPy(Base::Rotation()));
2290
        initialiseObject(&rotation, args);
2291
        return rotation;
2292
    }
2293
    case STR:
2294
        return Py::String(args[0]->getPyValue().as_string());
2295
    case PARSEQUANT: {
2296
        auto quantity_text = args[0]->getPyValue().as_string();
2297
        auto quantity_object =  Quantity::parse(QString::fromStdString(quantity_text));
2298
        return Py::asObject(new QuantityPy(new Quantity(quantity_object)));
2299
    }
2300
    case TRANSLATIONM: {
2301
        if (args.size() != 1)
2302
            break; // Break and proceed to 3 size version.
2303
        Py::Object parameter = args[0]->getPyValue();
2304
        if (!parameter.isSequence())
2305
            _EXPR_THROW("Not sequence type: '" << parameter.as_string() << "'.", expr);
2306
        if (PySequence_Size(parameter.ptr()) != 3)
2307
            _EXPR_THROW("Sequence provided has " << PySequence_Size(parameter.ptr()) << " elements instead of 3.", expr);
2308
        double x, y, z;
2309
        if (!PyArg_ParseTuple(Py::Tuple(Py::Sequence(parameter)).ptr(), "ddd", &x, &y, &z)) {
2310
            PyErr_Clear();
2311
            _EXPR_THROW("Error parsing sequence.", expr);
2312
        }
2313
        return translationMatrix(x, y, z);
2314
    }
2315
    case VECTOR: {
2316
        Py::Object vector = Py::asObject(new Base::VectorPy(Base::Vector3d()));
2317
        initialiseObject(&vector, args);
2318
        return vector;
2319
    }
2320
    case HIDDENREF:
2321
    case HREF:
2322
        return args[0]->getPyValue();
2323
    case VANGLE:
2324
    case VCROSS:
2325
    case VDOT:
2326
    case VLINEDIST:
2327
    case VLINESEGDIST:
2328
    case VLINEPROJ:
2329
    case VNORMALIZE:
2330
    case VPLANEDIST:
2331
    case VPLANEPROJ:
2332
    case VSCALE:
2333
    case VSCALEX:
2334
    case VSCALEY:
2335
    case VSCALEZ: {
2336
        Base::Vector3d vector1 = extractVectorArgument(expr, args, 0);
2337

2338
        switch (f) {
2339
        case VNORMALIZE:
2340
            return Py::asObject(new Base::VectorPy(vector1.Normalize()));
2341
        case VSCALE: {
2342
            double scaleX = extractLengthValueArgument(expr, args, 1);
2343
            double scaleY = extractLengthValueArgument(expr, args, 2);
2344
            double scaleZ = extractLengthValueArgument(expr, args, 3);
2345
            vector1.Scale(scaleX, scaleY, scaleZ);
2346
            return Py::asObject(new Base::VectorPy(vector1));
2347
        }
2348
        case VSCALEX: {
2349
            double scaleX = extractLengthValueArgument(expr, args, 1);
2350
            vector1.ScaleX(scaleX);
2351
            return Py::asObject(new Base::VectorPy(vector1));
2352
        }
2353
        case VSCALEY: {
2354
            double scaleY = extractLengthValueArgument(expr, args, 1);
2355
            vector1.ScaleY(scaleY);
2356
            return Py::asObject(new Base::VectorPy(vector1));
2357
        }
2358
        case VSCALEZ: {
2359
            double scaleZ = extractLengthValueArgument(expr, args, 1);
2360
            vector1.ScaleZ(scaleZ);
2361
            return Py::asObject(new Base::VectorPy(vector1));
2362
        }
2363
        }
2364

2365
        Base::Vector3d vector2 = extractVectorArgument(expr, args, 1);
2366

2367
        switch (f) {
2368
        case VANGLE:
2369
            return Py::asObject(new QuantityPy(new Quantity(vector1.GetAngle(vector2) * 180 / M_PI, Unit::Angle)));
2370
        case VCROSS:
2371
            return Py::asObject(new Base::VectorPy(vector1.Cross(vector2)));
2372
        case VDOT:
2373
            return Py::Float(vector1.Dot(vector2));
2374
        }
2375

2376
        Base::Vector3d vector3 = extractVectorArgument(expr, args, 2);
2377

2378
        switch (f) {
2379
        case VLINEDIST:
2380
            return Py::asObject(new QuantityPy(new Quantity(vector1.DistanceToLine(vector2, vector3), Unit::Length)));
2381
        case VLINESEGDIST:
2382
            return Py::asObject(new Base::VectorPy(vector1.DistanceToLineSegment(vector2, vector3)));
2383
        case VLINEPROJ:
2384
            vector1.ProjectToLine(vector2, vector3);
2385
            return Py::asObject(new Base::VectorPy(vector1));
2386
        case VPLANEDIST:
2387
            return Py::asObject(new QuantityPy(new Quantity(vector1.DistanceToPlane(vector2, vector3), Unit::Length)));
2388
        case VPLANEPROJ:
2389
            vector1.ProjectToPlane(vector2, vector3);
2390
            return Py::asObject(new Base::VectorPy(vector1));
2391
        }
2392
    }
2393
    }
2394

2395
    Py::Object e1 = args[0]->getPyValue();
2396
    Quantity v1 = pyToQuantity(e1,expr,"Invalid first argument.");
2397
    Py::Object e2;
2398
    Quantity v2;
2399
    if (args.size() > 1) {
2400
        e2 = args[1]->getPyValue();
2401
        v2 = pyToQuantity(e2,expr,"Invalid second argument.");
2402
    }
2403
    Py::Object e3;
2404
    Quantity v3;
2405
    if (args.size() > 2) {
2406
        e3 = args[2]->getPyValue();
2407
        v3 = pyToQuantity(e3,expr,"Invalid third argument.");
2408
    }
2409

2410
    double output;
2411
    Unit unit;
2412
    double scaler = 1;
2413

2414
    double value = v1.getValue();
2415

2416
    /* Check units and arguments */
2417
    switch (f) {
2418
    case COS:
2419
    case SIN:
2420
    case TAN:
2421
    case ROTATIONX:
2422
    case ROTATIONY:
2423
    case ROTATIONZ:
2424
        if (!(v1.isDimensionlessOrUnit(Unit::Angle)))
2425
            _EXPR_THROW("Unit must be either empty or an angle.", expr);
2426

2427
        // Convert value to radians
2428
        value *= M_PI / 180.0;
2429
        unit = Unit();
2430
        break;
2431
    case ACOS:
2432
    case ASIN:
2433
    case ATAN:
2434
        if (!v1.isDimensionless())
2435
            _EXPR_THROW("Unit must be empty.", expr);
2436
        unit = Unit::Angle;
2437
        scaler = 180.0 / M_PI;
2438
        break;
2439
    case EXP:
2440
    case LOG:
2441
    case LOG10:
2442
    case SINH:
2443
    case TANH:
2444
    case COSH:
2445
        if (!v1.isDimensionless())
2446
            _EXPR_THROW("Unit must be empty.",expr);
2447
        unit = Unit();
2448
        break;
2449
    case ROUND:
2450
    case TRUNC:
2451
    case CEIL:
2452
    case FLOOR:
2453
    case ABS:
2454
        unit = v1.getUnit();
2455
        break;
2456
    case SQRT: {
2457
        unit = v1.getUnit();
2458

2459
        // All components of unit must be either zero or dividable by 2
2460
        UnitSignature s = unit.getSignature();
2461
        if ( !((s.Length % 2) == 0) &&
2462
              ((s.Mass % 2) == 0) &&
2463
              ((s.Time % 2) == 0) &&
2464
              ((s.ElectricCurrent % 2) == 0) &&
2465
              ((s.ThermodynamicTemperature % 2) == 0) &&
2466
              ((s.AmountOfSubstance % 2) == 0) &&
2467
              ((s.LuminousIntensity % 2) == 0) &&
2468
              ((s.Angle % 2) == 0))
2469
            _EXPR_THROW("All dimensions must be even to compute the square root.",expr);
2470

2471
        unit = Unit(s.Length /2,
2472
                    s.Mass / 2,
2473
                    s.Time / 2,
2474
                    s.ElectricCurrent / 2,
2475
                    s.ThermodynamicTemperature / 2,
2476
                    s.AmountOfSubstance / 2,
2477
                    s.LuminousIntensity / 2,
2478
                    s.Angle);
2479
        break;
2480
    }
2481
    case CBRT: {
2482
        unit = v1.getUnit();
2483

2484
        // All components of unit must be either zero or dividable by 3
2485
        UnitSignature s = unit.getSignature();
2486
        if ( !((s.Length % 3) == 0) &&
2487
              ((s.Mass % 3) == 0) &&
2488
              ((s.Time % 3) == 0) &&
2489
              ((s.ElectricCurrent % 3) == 0) &&
2490
              ((s.ThermodynamicTemperature % 3) == 0) &&
2491
              ((s.AmountOfSubstance % 3) == 0) &&
2492
              ((s.LuminousIntensity % 3) == 0) &&
2493
              ((s.Angle % 3) == 0))
2494
            _EXPR_THROW("All dimensions must be multiples of 3 to compute the cube root.",expr);
2495

2496
        unit = Unit(s.Length /3,
2497
                    s.Mass / 3,
2498
                    s.Time / 3,
2499
                    s.ElectricCurrent / 3,
2500
                    s.ThermodynamicTemperature / 3,
2501
                    s.AmountOfSubstance / 3,
2502
                    s.LuminousIntensity / 3,
2503
                    s.Angle);
2504
        break;
2505
    }
2506
    case ATAN2:
2507
        if (e2.isNone())
2508
            _EXPR_THROW("Invalid second argument.",expr);
2509

2510
        if (v1.getUnit() != v2.getUnit())
2511
            _EXPR_THROW("Units must be equal.",expr);
2512
        unit = Unit::Angle;
2513
        scaler = 180.0 / M_PI;
2514
        break;
2515
    case MOD:
2516
        if (e2.isNone())
2517
            _EXPR_THROW("Invalid second argument.",expr);
2518
        unit = v1.getUnit() / v2.getUnit();
2519
        break;
2520
    case POW: {
2521
        if (e2.isNone())
2522
            _EXPR_THROW("Invalid second argument.",expr);
2523

2524
        if (!v2.isDimensionless())
2525
            _EXPR_THROW("Exponent is not allowed to have a unit.",expr);
2526

2527
        // Compute new unit for exponentiation
2528
        double exponent = v2.getValue();
2529
        if (!v1.isDimensionless()) {
2530
            if (exponent - boost::math::round(exponent) < 1e-9)
2531
                unit = v1.getUnit().pow(exponent);
2532
            else
2533
                _EXPR_THROW("Exponent must be an integer when used with a unit.",expr);
2534
        }
2535
        break;
2536
    }
2537
    case HYPOT:
2538
    case CATH:
2539
        if (e2.isNone())
2540
            _EXPR_THROW("Invalid second argument.",expr);
2541
        if (v1.getUnit() != v2.getUnit())
2542
            _EXPR_THROW("Units must be equal.",expr);
2543

2544
        if (args.size() > 2) {
2545
            if (e3.isNone())
2546
                _EXPR_THROW("Invalid second argument.",expr);
2547
            if (v2.getUnit() != v3.getUnit())
2548
                _EXPR_THROW("Units must be equal.",expr);
2549
        }
2550
        unit = v1.getUnit();
2551
        break;
2552
    case TRANSLATIONM:
2553
        if (v1.isDimensionlessOrUnit(Unit::Length) && v2.isDimensionlessOrUnit(Unit::Length) && v3.isDimensionlessOrUnit(Unit::Length))
2554
            break;
2555
        _EXPR_THROW("Translation units must be a length or dimensionless.", expr);
2556
    default:
2557
        _EXPR_THROW("Unknown function: " << f,0);
2558
    }
2559

2560
    /* Compute result */
2561
    switch (f) {
2562
    case ACOS:
2563
        output = acos(value);
2564
        break;
2565
    case ASIN:
2566
        output = asin(value);
2567
        break;
2568
    case ATAN:
2569
        output = atan(value);
2570
        break;
2571
    case ABS:
2572
        output = fabs(value);
2573
        break;
2574
    case EXP:
2575
        output = exp(value);
2576
        break;
2577
    case LOG:
2578
        output = log(value);
2579
        break;
2580
    case LOG10:
2581
        output = log(value) / log(10.0);
2582
        break;
2583
    case SIN:
2584
        output = sin(value);
2585
        break;
2586
    case SINH:
2587
        output = sinh(value);
2588
        break;
2589
    case TAN:
2590
        output = tan(value);
2591
        break;
2592
    case TANH:
2593
        output = tanh(value);
2594
        break;
2595
    case SQRT:
2596
        output = sqrt(value);
2597
        break;
2598
    case CBRT:
2599
        output = cbrt(value);
2600
        break;
2601
    case COS:
2602
        output = cos(value);
2603
        break;
2604
    case COSH:
2605
        output = cosh(value);
2606
        break;
2607
    case MOD: {
2608
        output = fmod(value, v2.getValue());
2609
        break;
2610
    }
2611
    case ATAN2: {
2612
        output = atan2(value, v2.getValue());
2613
        break;
2614
    }
2615
    case POW: {
2616
        output = pow(value, v2.getValue());
2617
        break;
2618
    }
2619
    case HYPOT: {
2620
        output = sqrt(pow(v1.getValue(), 2) + pow(v2.getValue(), 2) + (!e3.isNone() ? pow(v3.getValue(), 2) : 0));
2621
        break;
2622
    }
2623
    case CATH: {
2624
        output = sqrt(pow(v1.getValue(), 2) - pow(v2.getValue(), 2) - (!e3.isNone() ? pow(v3.getValue(), 2) : 0));
2625
        break;
2626
    }
2627
    case ROUND:
2628
        output = boost::math::round(value);
2629
        break;
2630
    case TRUNC:
2631
        output = boost::math::trunc(value);
2632
        break;
2633
    case CEIL:
2634
        output = ceil(value);
2635
        break;
2636
    case FLOOR:
2637
        output = floor(value);
2638
        break;
2639
    case ROTATIONX:
2640
    case ROTATIONY:
2641
    case ROTATIONZ:
2642
        return Py::asObject(new Base::RotationPy(Base::Rotation(
2643
            Vector3d(static_cast<double>(f == ROTATIONX), static_cast<double>(f == ROTATIONY), static_cast<double>(f == ROTATIONZ)),
2644
            value)));
2645
    case TRANSLATIONM:
2646
        return translationMatrix(v1.getValue(), v2.getValue(), v3.getValue());
2647
    default:
2648
        _EXPR_THROW("Unknown function: " << f,0);
2649
    }
2650

2651
    return Py::asObject(new QuantityPy(new Quantity(scaler * output, unit)));
2652
}
2653

2654
Py::Object FunctionExpression::_getPyValue() const {
2655
    return evaluate(this,f,args);
2656
}
2657

2658
/**
2659
  * Try to simplify the expression, i.e calculate all constant expressions.
2660
  *
2661
  * @returns A simplified expression.
2662
  */
2663

2664
Expression *FunctionExpression::simplify() const
2665
{
2666
    size_t numerics = 0;
2667
    std::vector<Expression*> a;
2668

2669
    // Try to simplify each argument to function
2670
    for (auto it : args) {
2671
        Expression * v = it->simplify();
2672

2673
        if (freecad_dynamic_cast<NumberExpression>(v))
2674
            ++numerics;
2675
        a.push_back(v);
2676
    }
2677

2678
    if (numerics == args.size()) {
2679
        // All constants, then evaluation must also be constant
2680

2681
        // Clean-up
2682
        for (auto it : args)
2683
            delete it;
2684

2685
        return eval();
2686
    }
2687
    else
2688
        return new FunctionExpression(owner, f, std::string(fname), a);
2689
}
2690

2691
/**
2692
  * Create a string representation of the expression.
2693
  *
2694
  * @returns A string representing the expression.
2695
  */
2696

2697
void FunctionExpression::_toString(std::ostream &ss, bool persistent,int) const
2698
{
2699
    switch (f) {
2700
    case ABS:
2701
        ss << "abs("; break;;
2702
    case ACOS:
2703
        ss << "acos("; break;;
2704
    case ASIN:
2705
        ss << "asin("; break;;
2706
    case ATAN:
2707
        ss << "atan("; break;;
2708
    case ATAN2:
2709
        ss << "atan2("; break;;
2710
    case CATH:
2711
        ss << "cath("; break;;
2712
    case CBRT:
2713
        ss << "cbrt("; break;;
2714
    case CEIL:
2715
        ss << "ceil("; break;;
2716
    case COS:
2717
        ss << "cos("; break;;
2718
    case COSH:
2719
        ss << "cosh("; break;;
2720
    case EXP:
2721
        ss << "exp("; break;;
2722
    case FLOOR:
2723
        ss << "floor("; break;;
2724
    case HYPOT:
2725
        ss << "hypot("; break;;
2726
    case LOG:
2727
        ss << "log("; break;;
2728
    case LOG10:
2729
        ss << "log10("; break;;
2730
    case MOD:
2731
        ss << "mod("; break;;
2732
    case POW:
2733
        ss << "pow("; break;;
2734
    case ROUND:
2735
        ss << "round("; break;;
2736
    case SIN:
2737
        ss << "sin("; break;;
2738
    case SINH:
2739
        ss << "sinh("; break;;
2740
    case SQRT:
2741
        ss << "sqrt("; break;;
2742
    case TAN:
2743
        ss << "tan("; break;;
2744
    case TANH:
2745
        ss << "tanh("; break;;
2746
    case TRUNC:
2747
        ss << "trunc("; break;;
2748
    case VANGLE:
2749
        ss << "vangle("; break;;
2750
    case VCROSS:
2751
        ss << "vcross("; break;;
2752
    case VDOT:
2753
        ss << "vdot("; break;;
2754
    case VLINEDIST:
2755
        ss << "vlinedist("; break;;
2756
    case VLINESEGDIST:
2757
        ss << "vlinesegdist("; break;;
2758
    case VLINEPROJ:
2759
        ss << "vlineproj("; break;;
2760
    case VNORMALIZE:
2761
        ss << "vnormalize("; break;;
2762
    case VPLANEDIST:
2763
        ss << "vplanedist("; break;;
2764
    case VPLANEPROJ:
2765
        ss << "vplaneproj("; break;;
2766
    case VSCALE:
2767
        ss << "vscale("; break;;
2768
    case VSCALEX:
2769
        ss << "vscalex("; break;;
2770
    case VSCALEY:
2771
        ss << "vscaley("; break;;
2772
    case VSCALEZ:
2773
        ss << "vscalez("; break;;
2774
    case MINVERT:
2775
        ss << "minvert("; break;;
2776
    case MROTATE:
2777
        ss << "mrotate("; break;;
2778
    case MROTATEX:
2779
        ss << "mrotatex("; break;;
2780
    case MROTATEY:
2781
        ss << "mrotatey("; break;;
2782
    case MROTATEZ:
2783
        ss << "mrotatez("; break;;
2784
    case MSCALE:
2785
        ss << "mscale("; break;;
2786
    case MTRANSLATE:
2787
        ss << "mtranslate("; break;;
2788
    case CREATE:
2789
        ss << "create("; break;;
2790
    case LIST:
2791
        ss << "list("; break;;
2792
    case MATRIX:
2793
        ss << "matrix("; break;;
2794
    case PLACEMENT:
2795
        ss << "placement("; break;;
2796
    case ROTATION:
2797
        ss << "rotation("; break;;
2798
    case ROTATIONX:
2799
        ss << "rotationx("; break;;
2800
    case ROTATIONY:
2801
        ss << "rotationy("; break;;
2802
    case ROTATIONZ:
2803
        ss << "rotationz("; break;;
2804
    case STR:
2805
        ss << "str("; break;;
2806
    case PARSEQUANT:
2807
        ss << "parsequant("; break;;
2808
    case TRANSLATIONM:
2809
        ss << "translationm("; break;;
2810
    case TUPLE:
2811
        ss << "tuple("; break;;
2812
    case VECTOR:
2813
        ss << "vector("; break;;
2814
    case HIDDENREF:
2815
        ss << "hiddenref("; break;;
2816
    case HREF:
2817
        ss << "href("; break;;
2818
    case AVERAGE:
2819
        ss << "average("; break;;
2820
    case COUNT:
2821
        ss << "count("; break;;
2822
    case MAX:
2823
        ss << "max("; break;;
2824
    case MIN:
2825
        ss << "min("; break;;
2826
    case STDDEV:
2827
        ss << "stddev("; break;;
2828
    case SUM:
2829
        ss << "sum("; break;;
2830
    default:
2831
        ss << fname << "("; break;;
2832
    }
2833
    for (size_t i = 0; i < args.size(); ++i) {
2834
        ss << args[i]->toString(persistent);
2835
        if (i != args.size() - 1)
2836
            ss << "; ";
2837
    }
2838
    ss << ')';
2839
}
2840

2841
/**
2842
  * Create a copy of the expression.
2843
  *
2844
  * @returns A deep copy of the expression.
2845
  */
2846

2847
Expression *FunctionExpression::_copy() const
2848
{
2849
    std::vector<Expression*>::const_iterator i = args.begin();
2850
    std::vector<Expression*> a;
2851

2852
    while (i != args.end()) {
2853
        a.push_back((*i)->copy());
2854
        ++i;
2855
    }
2856
    return new FunctionExpression(owner, f, std::string(fname), a);
2857
}
2858

2859
void FunctionExpression::_visit(ExpressionVisitor &v)
2860
{
2861
    std::vector<Expression*>::const_iterator i = args.begin();
2862

2863
    HiddenReference ref(f == HIDDENREF || f == HREF);
2864
    while (i != args.end()) {
2865
        (*i)->visit(v);
2866
        ++i;
2867
    }
2868
}
2869

2870
//
2871
// VariableExpression class
2872
//
2873

2874
TYPESYSTEM_SOURCE(App::VariableExpression, App::UnitExpression)
2875

2876
VariableExpression::VariableExpression(const DocumentObject *_owner, const ObjectIdentifier& _var)
2877
    : UnitExpression(_owner)
2878
    , var(_var)
2879
{
2880
}
2881

2882
VariableExpression::~VariableExpression() = default;
2883

2884
/**
2885
  * Determine if the expression is touched or not, i.e whether the Property object it
2886
  * refers to is touched().
2887
  *
2888
  * @returns True if the Property object is touched, false if not.
2889
  */
2890

2891
bool VariableExpression::isTouched() const
2892
{
2893
    return var.isTouched();
2894
}
2895

2896
/**
2897
  * Find the property this expression referse to.
2898
  *
2899
  * Unqualified names (i.e the name only without any dots) are resolved in the owning DocumentObjects.
2900
  * Qualified names are looked up in the owning Document. It is first looked up by its internal name.
2901
  * If not found, the DocumentObjects' labels searched.
2902
  *
2903
  * If something fails, an exception is thrown.
2904
  *
2905
  * @returns The Property object if it is derived from either PropertyInteger, PropertyFloat, or PropertyString.
2906
  */
2907

2908
const Property * VariableExpression::getProperty() const
2909
{
2910
    const Property * prop = var.getProperty();
2911

2912
    if (prop)
2913
        return prop;
2914
    else
2915
        throw Expression::Exception(var.resolveErrorString().c_str());
2916
}
2917

2918
void VariableExpression::addComponent(Component *c) {
2919
    do {
2920
        if(!components.empty())
2921
            break;
2922
        if(!c->e1 && !c->e2) {
2923
            var << c->comp;
2924
            return;
2925
        }
2926
        long l1=0,l2=0,l3=1;
2927
        if(c->e3) {
2928
            auto n3 = freecad_dynamic_cast<NumberExpression>(c->e3);
2929
            if(!n3 || !essentiallyEqual(n3->getValue(),(double)l3))
2930
                break;
2931
        }
2932
        if(c->e1) {
2933
            auto n1 = freecad_dynamic_cast<NumberExpression>(c->e1);
2934
            if(!n1) {
2935
                if(c->e2 || c->e3)
2936
                    break;
2937
                auto s = freecad_dynamic_cast<StringExpression>(c->e1);
2938
                if(!s)
2939
                    break;
2940
                var << ObjectIdentifier::MapComponent(
2941
                        ObjectIdentifier::String(s->getText(),true));
2942
                return;
2943
            }
2944
            if(!essentiallyInteger(n1->getValue(),l1))
2945
                break;
2946
            if(!c->comp.isRange()) {
2947
                var << ObjectIdentifier::ArrayComponent(l1);
2948
                return;
2949
            } else if(!c->e2) {
2950
                var << ObjectIdentifier::RangeComponent(l1,l2,l3);
2951
                return;
2952
            }
2953
        }
2954
        auto n2 = freecad_dynamic_cast<NumberExpression>(c->e2);
2955
        if(n2 && essentiallyInteger(n2->getValue(),l2)) {
2956
            var << ObjectIdentifier::RangeComponent(l1,l2,l3);
2957
            return;
2958
        }
2959
    }while(false);
2960

2961
    Expression::addComponent(c);
2962
}
2963

2964
bool VariableExpression::_isIndexable() const {
2965
    return true;
2966
}
2967

2968
Py::Object VariableExpression::_getPyValue() const {
2969
    return var.getPyValue(true);
2970
}
2971

2972
void VariableExpression::_toString(std::ostream &ss, bool persistent,int) const {
2973
    if(persistent)
2974
        ss << var.toPersistentString();
2975
    else
2976
        ss << var.toString();
2977
}
2978

2979
/**
2980
  * Simplify the expression. Simplification of VariableExpression objects is
2981
  * not possible (if it is instantiated it would be an evaluation instead).
2982
  *
2983
  * @returns A copy of the expression.
2984
  */
2985

2986
Expression *VariableExpression::simplify() const
2987
{
2988
    return copy();
2989
}
2990

2991
/**
2992
  * Return a copy of the expression.
2993
  */
2994

2995
Expression *VariableExpression::_copy() const
2996
{
2997
    return new VariableExpression(owner, var);
2998
}
2999

3000
void VariableExpression::_getIdentifiers(std::map<App::ObjectIdentifier,bool> &deps) const
3001
{
3002
    bool hidden = HiddenReference::isHidden();
3003
    auto res = deps.insert(std::make_pair(var,hidden));
3004
    if(!hidden || res.second)
3005
        res.first->second = hidden;
3006
}
3007

3008
bool VariableExpression::_relabeledDocument(const std::string &oldName,
3009
        const std::string &newName, ExpressionVisitor &v)
3010
{
3011
    return var.relabeledDocument(v, oldName, newName);
3012
}
3013

3014
bool VariableExpression::_adjustLinks(
3015
        const std::set<App::DocumentObject *> &inList, ExpressionVisitor &v)
3016
{
3017
    return var.adjustLinks(v,inList);
3018
}
3019

3020
void VariableExpression::_importSubNames(const ObjectIdentifier::SubNameMap &subNameMap)
3021
{
3022
    var.importSubNames(subNameMap);
3023
}
3024

3025
void VariableExpression::_updateLabelReference(
3026
        App::DocumentObject *obj, const std::string &ref, const char *newLabel)
3027
{
3028
    var.updateLabelReference(obj,ref,newLabel);
3029
}
3030

3031
bool VariableExpression::_updateElementReference(
3032
        App::DocumentObject *feature, bool reverse, ExpressionVisitor &v)
3033
{
3034
    return var.updateElementReference(v,feature,reverse);
3035
}
3036

3037
bool VariableExpression::_renameObjectIdentifier(
3038
    const std::map<ObjectIdentifier, ObjectIdentifier>& paths,
3039
    const ObjectIdentifier& path,
3040
    ExpressionVisitor& visitor)
3041
{
3042
    const auto& oldPath = var.canonicalPath();
3043
    auto it = paths.find(oldPath);
3044
    if (it != paths.end()) {
3045
        visitor.aboutToChange();
3046
        const bool originalHasDocumentObjectName = var.hasDocumentObjectName();
3047
        ObjectIdentifier::String originalDocumentObjectName = var.getDocumentObjectName();
3048
        std::string originalSubObjectName = var.getSubObjectName();
3049
        if (path.getOwner()) {
3050
            var = it->second.relativeTo(path);
3051
        }
3052
        else {
3053
            var = it->second;
3054
        }
3055
        if (originalHasDocumentObjectName) {
3056
            var.setDocumentObjectName(std::move(originalDocumentObjectName),
3057
                                      true,
3058
                                      originalSubObjectName);
3059
        }
3060
        return true;
3061
    }
3062
    return false;
3063
}
3064

3065
void VariableExpression::_collectReplacement(
3066
        std::map<ObjectIdentifier,ObjectIdentifier> &paths,
3067
        const App::DocumentObject *parent,
3068
        App::DocumentObject *oldObj,
3069
        App::DocumentObject *newObj) const
3070
{
3071
    ObjectIdentifier path;
3072
    if(var.replaceObject(path,parent,oldObj,newObj))
3073
        paths[var.canonicalPath()] = std::move(path);
3074
}
3075

3076
void VariableExpression::_moveCells(const CellAddress &address,
3077
        int rowCount, int colCount, ExpressionVisitor &v)
3078
{
3079
    if(var.hasDocumentObjectName(true))
3080
        return;
3081

3082
    int idx = 0;
3083
    const auto &comp = var.getPropertyComponent(0,&idx);
3084
    CellAddress addr = stringToAddress(comp.getName().c_str(),true);
3085
    if(!addr.isValid())
3086
        return;
3087

3088
    int thisRow = addr.row();
3089
    int thisCol = addr.col();
3090
    if (thisRow >= address.row() || thisCol >= address.col()) {
3091
        v.aboutToChange();
3092
        addr.setRow(thisRow + rowCount);
3093
        addr.setCol(thisCol + colCount);
3094
        var.setComponent(idx,ObjectIdentifier::SimpleComponent(addr.toString()));
3095
    }
3096
}
3097

3098
void VariableExpression::_offsetCells(int rowOffset, int colOffset, ExpressionVisitor &v) {
3099
    if(var.hasDocumentObjectName(true))
3100
        return;
3101

3102
    int idx = 0;
3103
    const auto &comp = var.getPropertyComponent(0,&idx);
3104
    CellAddress addr = stringToAddress(comp.getName().c_str(),true);
3105
    if(!addr.isValid() || (addr.isAbsoluteCol() && addr.isAbsoluteRow()))
3106
        return;
3107

3108
    if(!addr.isAbsoluteCol())
3109
        addr.setCol(addr.col()+colOffset);
3110
    if(!addr.isAbsoluteRow())
3111
        addr.setRow(addr.row()+rowOffset);
3112
    if(!addr.isValid()) {
3113
        FC_WARN("Not changing relative cell reference '"
3114
                << comp.getName() << "' due to invalid offset "
3115
                << '(' << colOffset << ", " << rowOffset << ')');
3116
    } else {
3117
        v.aboutToChange();
3118
        var.setComponent(idx,ObjectIdentifier::SimpleComponent(addr.toString()));
3119
    }
3120
}
3121

3122
void VariableExpression::setPath(const ObjectIdentifier &path)
3123
{
3124
     var = path;
3125
}
3126

3127
//
3128
// PyObjectExpression class
3129
//
3130

3131
TYPESYSTEM_SOURCE(App::PyObjectExpression, App::Expression)
3132

3133
PyObjectExpression::~PyObjectExpression() {
3134
    if(pyObj) {
3135
        Base::PyGILStateLocker lock;
3136
        Py::_XDECREF(pyObj);
3137
    }
3138
}
3139

3140
Py::Object PyObjectExpression::_getPyValue() const {
3141
    if(!pyObj)
3142
        return Py::Object();
3143
    return Py::Object(pyObj);
3144
}
3145

3146
void PyObjectExpression::setPyValue(Py::Object obj) {
3147
    Py::_XDECREF(pyObj);
3148
    pyObj = obj.ptr();
3149
    Py::_XINCREF(pyObj);
3150
}
3151

3152
void PyObjectExpression::setPyValue(PyObject *obj, bool owned) {
3153
    if(pyObj == obj)
3154
        return;
3155
    Py::_XDECREF(pyObj);
3156
    pyObj = obj;
3157
    if(!owned)
3158
        Py::_XINCREF(pyObj);
3159
}
3160

3161
void PyObjectExpression::_toString(std::ostream &ss, bool,int) const
3162
{
3163
    if(!pyObj)
3164
        ss << "None";
3165
    else {
3166
        Base::PyGILStateLocker lock;
3167
        ss << Py::Object(pyObj).as_string();
3168
    }
3169
}
3170

3171
Expression* PyObjectExpression::_copy() const
3172
{
3173
    return new PyObjectExpression(owner,pyObj,false);
3174
}
3175

3176
//
3177
// StringExpression class
3178
//
3179

3180
TYPESYSTEM_SOURCE(App::StringExpression, App::Expression)
3181

3182
StringExpression::StringExpression(const DocumentObject *_owner, const std::string &_text)
3183
    : Expression(_owner)
3184
    , text(_text)
3185
{
3186
}
3187

3188
StringExpression::~StringExpression() {
3189
    if(cache) {
3190
        Base::PyGILStateLocker lock;
3191
        Py::_XDECREF(cache);
3192
    }
3193
}
3194

3195
/**
3196
  * Simplify the expression. For strings, this is a simple copy of the object.
3197
  */
3198

3199
Expression *StringExpression::simplify() const
3200
{
3201
    return copy();
3202
}
3203

3204
void StringExpression::_toString(std::ostream &ss, bool,int) const
3205
{
3206
    ss << quote(text);
3207
}
3208

3209
/**
3210
  * Return a copy of the expression.
3211
  */
3212

3213
Expression *StringExpression::_copy() const
3214
{
3215
    return new StringExpression(owner, text);
3216
}
3217

3218
Py::Object StringExpression::_getPyValue() const {
3219
    return Py::String(text);
3220
}
3221

3222
TYPESYSTEM_SOURCE(App::ConditionalExpression, App::Expression)
3223

3224
ConditionalExpression::ConditionalExpression(const DocumentObject *_owner, Expression *_condition, Expression *_trueExpr, Expression *_falseExpr)
3225
    : Expression(_owner)
3226
    , condition(_condition)
3227
    , trueExpr(_trueExpr)
3228
    , falseExpr(_falseExpr)
3229
{
3230
}
3231

3232
ConditionalExpression::~ConditionalExpression()
3233
{
3234
    delete condition;
3235
    delete trueExpr;
3236
    delete falseExpr;
3237
}
3238

3239
bool ConditionalExpression::isTouched() const
3240
{
3241
    return condition->isTouched() || trueExpr->isTouched() || falseExpr->isTouched();
3242
}
3243

3244
Py::Object ConditionalExpression::_getPyValue() const {
3245
    if(condition->getPyValue().isTrue())
3246
        return trueExpr->getPyValue();
3247
    else
3248
        return falseExpr->getPyValue();
3249
}
3250

3251
Expression *ConditionalExpression::simplify() const
3252
{
3253
    std::unique_ptr<Expression> e(condition->simplify());
3254
    NumberExpression * v = freecad_dynamic_cast<NumberExpression>(e.get());
3255

3256
    if (!v)
3257
        return new ConditionalExpression(owner, condition->simplify(), trueExpr->simplify(), falseExpr->simplify());
3258
    else {
3259
        if (fabs(v->getValue()) > 0.5)
3260
            return trueExpr->simplify();
3261
        else
3262
            return falseExpr->simplify();
3263
    }
3264
}
3265

3266
void ConditionalExpression::_toString(std::ostream &ss, bool persistent,int) const
3267
{
3268
    condition->toString(ss,persistent);
3269
    ss << " ? ";
3270
    if (trueExpr->priority() <= priority()) {
3271
        ss << '(';
3272
        trueExpr->toString(ss,persistent);
3273
        ss << ')';
3274
    } else
3275
        trueExpr->toString(ss,persistent);
3276

3277
    ss << " : ";
3278

3279
    if (falseExpr->priority() <= priority()) {
3280
        ss << '(';
3281
        falseExpr->toString(ss,persistent);
3282
        ss << ')';
3283
    } else
3284
        falseExpr->toString(ss,persistent);
3285
}
3286

3287
Expression *ConditionalExpression::_copy() const
3288
{
3289
    return new ConditionalExpression(owner, condition->copy(), trueExpr->copy(), falseExpr->copy());
3290
}
3291

3292
int ConditionalExpression::priority() const
3293
{
3294
    return 2;
3295
}
3296

3297
void ConditionalExpression::_visit(ExpressionVisitor &v)
3298
{
3299
    condition->visit(v);
3300
    trueExpr->visit(v);
3301
    falseExpr->visit(v);
3302
}
3303

3304
TYPESYSTEM_SOURCE(App::ConstantExpression, App::NumberExpression)
3305

3306
ConstantExpression::ConstantExpression(const DocumentObject *_owner,
3307
        const char *_name, const Quantity & _quantity)
3308
    : NumberExpression(_owner, _quantity)
3309
    , name(_name)
3310
{
3311
}
3312

3313
Expression *ConstantExpression::_copy() const
3314
{
3315
    return new ConstantExpression(owner, name, getQuantity());
3316
}
3317

3318
void ConstantExpression::_toString(std::ostream &ss, bool,int) const
3319
{
3320
    ss << name;
3321
}
3322

3323
Py::Object ConstantExpression::_getPyValue() const {
3324
    if(!cache) {
3325
        if(strcmp(name,"None")==0)
3326
            cache = Py::new_reference_to(Py::None());
3327
        else if(strcmp(name,"True")==0)
3328
            cache = Py::new_reference_to(Py::True());
3329
        else if(strcmp(name, "False")==0)
3330
            cache = Py::new_reference_to(Py::False());
3331
        else
3332
            return NumberExpression::_getPyValue();
3333
    }
3334
    return Py::Object(cache);
3335
}
3336

3337
bool ConstantExpression::isNumber() const {
3338
    return strcmp(name,"None")
3339
        && strcmp(name,"True")
3340
        && strcmp(name, "False");
3341
}
3342

3343
TYPESYSTEM_SOURCE(App::RangeExpression, App::Expression)
3344

3345
RangeExpression::RangeExpression(const DocumentObject *_owner, const std::string &begin, const std::string &end)
3346
    : Expression(_owner), begin(begin), end(end)
3347
{
3348
}
3349

3350
bool RangeExpression::isTouched() const
3351
{
3352
    Range i(getRange());
3353

3354
    do {
3355
        Property * prop = owner->getPropertyByName(i.address().c_str());
3356

3357
        if (prop && prop->isTouched())
3358
            return true;
3359
    } while (i.next());
3360

3361
    return false;
3362
}
3363

3364
Py::Object RangeExpression::_getPyValue() const {
3365
    Py::List list;
3366
    Range range(getRange());
3367
    do {
3368
        Property * p = owner->getPropertyByName(range.address().c_str());
3369
        if(p)
3370
            list.append(Py::asObject(p->getPyObject()));
3371
    } while (range.next());
3372
    return list;
3373
}
3374

3375
void RangeExpression::_toString(std::ostream &ss, bool,int) const
3376
{
3377
    ss << begin << ":" << end;
3378
}
3379

3380
Expression *RangeExpression::_copy() const
3381
{
3382
    return new RangeExpression(owner, begin, end);
3383
}
3384

3385
Expression *RangeExpression::simplify() const
3386
{
3387
    return copy();
3388
}
3389

3390
void RangeExpression::_getIdentifiers(std::map<App::ObjectIdentifier,bool> &deps) const
3391
{
3392
    bool hidden = HiddenReference::isHidden();
3393

3394
    assert(owner);
3395

3396
    Range i(getRange());
3397

3398
    do {
3399
        ObjectIdentifier var(owner,i.address());
3400
        auto res = deps.insert(std::make_pair(var,hidden));
3401
        if(!hidden || res.second)
3402
            res.first->second = hidden;
3403
    } while (i.next());
3404
}
3405

3406
Range RangeExpression::getRange() const
3407
{
3408
    auto c1 = stringToAddress(begin.c_str(),true);
3409
    auto c2 = stringToAddress(end.c_str(),true);
3410
    if(c1.isValid() && c2.isValid())
3411
        return Range(c1,c2);
3412

3413
    Base::PyGILStateLocker lock;
3414
    static const std::string attr("getCellFromAlias");
3415
    Py::Object pyobj(owner->getPyObject(),true);
3416
    if(!pyobj.hasAttr(attr))
3417
        EXPR_THROW("Invalid cell range " << begin << ':' << end);
3418
    Py::Callable callable(pyobj.getAttr(attr));
3419
    if(!c1.isValid()) {
3420
        try {
3421
            Py::Tuple arg(1);
3422
            arg.setItem(0,Py::String(begin));
3423
            c1 = CellAddress(callable.apply(arg).as_string().c_str());
3424
        } catch(Py::Exception &) {
3425
            _EXPR_PY_THROW("Invalid cell address '" << begin << "': ",this);
3426
        } catch(Base::Exception &e) {
3427
            _EXPR_RETHROW(e,"Invalid cell address '" << begin << "': ",this);
3428
        }
3429
    }
3430
    if(!c2.isValid()) {
3431
        try {
3432
            Py::Tuple arg(1);
3433
            arg.setItem(0,Py::String(end));
3434
            c2 = CellAddress(callable.apply(arg).as_string().c_str());
3435
        } catch(Py::Exception &) {
3436
            _EXPR_PY_THROW("Invalid cell address '" << end << "': ", this);
3437
        } catch(Base::Exception &e) {
3438
            _EXPR_RETHROW(e,"Invalid cell address '" << end << "': ", this);
3439
        }
3440
    }
3441
    return Range(c1,c2);
3442
}
3443

3444
bool RangeExpression::_renameObjectIdentifier(
3445
        const std::map<ObjectIdentifier,ObjectIdentifier> &paths,
3446
        const ObjectIdentifier &path, ExpressionVisitor &v)
3447
{
3448
    (void)path;
3449
    bool touched =false;
3450
    auto it = paths.find(ObjectIdentifier(owner,begin));
3451
    if (it != paths.end()) {
3452
        v.aboutToChange();
3453
        begin = it->second.getPropertyName();
3454
        touched = true;
3455
    }
3456
    it = paths.find(ObjectIdentifier(owner,end));
3457
    if (it != paths.end()) {
3458
        v.aboutToChange();
3459
        end = it->second.getPropertyName();
3460
        touched = true;
3461
    }
3462
    return touched;
3463
}
3464

3465
void RangeExpression::_moveCells(const CellAddress &address,
3466
        int rowCount, int colCount, ExpressionVisitor &v)
3467
{
3468
    CellAddress addr = stringToAddress(begin.c_str(),true);
3469
    if(addr.isValid()) {
3470
        int thisRow = addr.row();
3471
        int thisCol = addr.col();
3472
        if (thisRow >= address.row() || thisCol >= address.col()) {
3473
            v.aboutToChange();
3474
            addr.setRow(thisRow+rowCount);
3475
            addr.setCol(thisCol+colCount);
3476
            begin = addr.toString();
3477
        }
3478
    }
3479
    addr = stringToAddress(end.c_str(),true);
3480
    if(addr.isValid()) {
3481
        int thisRow = addr.row();
3482
        int thisCol = addr.col();
3483
        if (thisRow >= address.row() || thisCol >= address.col()) {
3484
            v.aboutToChange();
3485
            addr.setRow(thisRow + rowCount);
3486
            addr.setCol(thisCol + colCount);
3487
            end = addr.toString();
3488
        }
3489
    }
3490
}
3491

3492
void RangeExpression::_offsetCells(int rowOffset, int colOffset, ExpressionVisitor &v)
3493
{
3494
    CellAddress addr = stringToAddress(begin.c_str(),true);
3495
    if(addr.isValid() && (!addr.isAbsoluteRow() || !addr.isAbsoluteCol())) {
3496
        v.aboutToChange();
3497
        if(!addr.isAbsoluteRow())
3498
            addr.setRow(addr.row()+rowOffset);
3499
        if(!addr.isAbsoluteCol())
3500
            addr.setCol(addr.col()+colOffset);
3501
        begin = addr.toString();
3502
    }
3503
    addr = stringToAddress(end.c_str(),true);
3504
    if(addr.isValid() && (!addr.isAbsoluteRow() || !addr.isAbsoluteCol())) {
3505
        v.aboutToChange();
3506
        if(!addr.isAbsoluteRow())
3507
            addr.setRow(addr.row()+rowOffset);
3508
        if(!addr.isAbsoluteCol())
3509
            addr.setCol(addr.col()+colOffset);
3510
        end = addr.toString();
3511
    }
3512
}
3513

3514

3515
////////////////////////////////////////////////////////////////////////////////////
3516

3517
static Base::XMLReader *_Reader = nullptr;
3518
ExpressionParser::ExpressionImporter::ExpressionImporter(Base::XMLReader &reader) {
3519
    assert(!_Reader);
3520
    _Reader = &reader;
3521
}
3522

3523
ExpressionParser::ExpressionImporter::~ExpressionImporter() {
3524
    assert(_Reader);
3525
    _Reader = nullptr;
3526
}
3527

3528
Base::XMLReader *ExpressionParser::ExpressionImporter::reader() {
3529
    return _Reader;
3530
}
3531

3532
namespace App {
3533

3534
namespace ExpressionParser {
3535

3536
bool isModuleImported(PyObject *module) {
3537
    (void)module;
3538
    return false;
3539
}
3540

3541
/**
3542
 * Error function for parser. Throws a generic Base::Exception with the parser error.
3543
 */
3544

3545
void ExpressionParser_yyerror(const char *errorinfo)
3546
{
3547
    (void)errorinfo;
3548
}
3549

3550
/* helper function for tuning number strings with groups in a locale agnostic way... */
3551
double num_change(char* yytext,char dez_delim,char grp_delim)
3552
{
3553
    double ret_val;
3554
    char temp[40];
3555
    int i = 0;
3556
    for(char* c=yytext;*c!='\0';c++){
3557
        // skip group delimiter
3558
        if(*c==grp_delim) continue;
3559
        // check for a dez delimiter other then dot
3560
        if(*c==dez_delim && dez_delim !='.')
3561
             temp[i++] = '.';
3562
        else
3563
            temp[i++] = *c;
3564
        // check buffer overflow
3565
        if (i>39)
3566
            return 0.0;
3567
    }
3568
    temp[i] = '\0';
3569

3570
    errno = 0;
3571
    ret_val = strtod( temp, nullptr );
3572
    if (ret_val == 0 && errno == ERANGE)
3573
        throw Base::UnderflowError("Number underflow.");
3574
    if (ret_val == HUGE_VAL || ret_val == -HUGE_VAL)
3575
        throw Base::OverflowError("Number overflow.");
3576

3577
    return ret_val;
3578
}
3579

3580
static Expression * ScanResult = nullptr;                    /**< The resulting expression after a successful parsing */
3581
static const App::DocumentObject * DocumentObject = nullptr; /**< The DocumentObject that will own the expression */
3582
static bool unitExpression = false;                    /**< True if the parsed string is a unit only */
3583
static bool valueExpression = false;                   /**< True if the parsed string is a full expression */
3584
static std::stack<std::string> labels;                /**< Label string primitive */
3585
static std::map<std::string, FunctionExpression::Function> registered_functions;                /**< Registered functions */
3586
static int last_column;
3587
static int column;
3588

3589
// show the parser the lexer method
3590
#define yylex ExpressionParserlex
3591
int ExpressionParserlex();
3592

3593
#if defined(__clang__)
3594
# pragma clang diagnostic push
3595
# pragma clang diagnostic ignored "-Wsign-compare"
3596
# pragma clang diagnostic ignored "-Wunneeded-internal-declaration"
3597
#elif defined (__GNUC__)
3598
# pragma GCC diagnostic push
3599
# pragma GCC diagnostic ignored "-Wsign-compare"
3600
# pragma GCC diagnostic ignored "-Wfree-nonheap-object"
3601
#endif
3602

3603
// Parser, defined in ExpressionParser.y
3604
# define YYTOKENTYPE
3605
#include "ExpressionParser.tab.c"
3606

3607
#ifndef DOXYGEN_SHOULD_SKIP_THIS
3608
// Scanner, defined in ExpressionParser.l
3609
#include "lex.ExpressionParser.c"
3610
#endif // DOXYGEN_SHOULD_SKIP_THIS
3611

3612
class StringBufferCleaner
3613
{
3614
public:
3615
    explicit StringBufferCleaner(YY_BUFFER_STATE buffer)
3616
        : my_string_buffer {buffer}
3617
    {}
3618
    ~StringBufferCleaner()
3619
    {
3620
        // free the scan buffer
3621
        yy_delete_buffer(my_string_buffer);
3622
    }
3623

3624
    StringBufferCleaner(const StringBufferCleaner&) = delete;
3625
    StringBufferCleaner(StringBufferCleaner&&) = delete;
3626
    StringBufferCleaner& operator=(const StringBufferCleaner&) = delete;
3627
    StringBufferCleaner& operator=(StringBufferCleaner&&) = delete;
3628

3629
private:
3630
    YY_BUFFER_STATE my_string_buffer;
3631
};
3632

3633
#if defined(__clang__)
3634
# pragma clang diagnostic pop
3635
#elif defined (__GNUC__)
3636
# pragma GCC diagnostic pop
3637
#endif
3638

3639
#ifdef _MSC_VER
3640
# define strdup _strdup
3641
#endif
3642

3643
static void initParser(const App::DocumentObject *owner)
3644
{
3645
    static bool has_registered_functions = false;
3646

3647
    using namespace App::ExpressionParser;
3648

3649
    ScanResult = nullptr;
3650
    App::ExpressionParser::DocumentObject = owner;
3651
    labels = std::stack<std::string>();
3652
    column = 0;
3653
    unitExpression = valueExpression = false;
3654

3655
    if (!has_registered_functions) {
3656
        registered_functions["abs"] = FunctionExpression::ABS;
3657
        registered_functions["acos"] = FunctionExpression::ACOS;
3658
        registered_functions["asin"] = FunctionExpression::ASIN;
3659
        registered_functions["atan"] = FunctionExpression::ATAN;
3660
        registered_functions["atan2"] = FunctionExpression::ATAN2;
3661
        registered_functions["cath"] = FunctionExpression::CATH;
3662
        registered_functions["cbrt"] = FunctionExpression::CBRT;
3663
        registered_functions["ceil"] = FunctionExpression::CEIL;
3664
        registered_functions["cos"] = FunctionExpression::COS;
3665
        registered_functions["cosh"] = FunctionExpression::COSH;
3666
        registered_functions["exp"] = FunctionExpression::EXP;
3667
        registered_functions["floor"] = FunctionExpression::FLOOR;
3668
        registered_functions["hypot"] = FunctionExpression::HYPOT;
3669
        registered_functions["log"] = FunctionExpression::LOG;
3670
        registered_functions["log10"] = FunctionExpression::LOG10;
3671
        registered_functions["mod"] = FunctionExpression::MOD;
3672
        registered_functions["pow"] = FunctionExpression::POW;
3673
        registered_functions["round"] = FunctionExpression::ROUND;
3674
        registered_functions["sin"] = FunctionExpression::SIN;
3675
        registered_functions["sinh"] = FunctionExpression::SINH;
3676
        registered_functions["sqrt"] = FunctionExpression::SQRT;
3677
        registered_functions["tan"] = FunctionExpression::TAN;
3678
        registered_functions["tanh"] = FunctionExpression::TANH;
3679
        registered_functions["trunc"] = FunctionExpression::TRUNC;
3680
        registered_functions["vangle"] = FunctionExpression::VANGLE;
3681
        registered_functions["vcross"] = FunctionExpression::VCROSS;
3682
        registered_functions["vdot"] = FunctionExpression::VDOT;
3683
        registered_functions["vlinedist"] = FunctionExpression::VLINEDIST;
3684
        registered_functions["vlinesegdist"] = FunctionExpression::VLINESEGDIST;
3685
        registered_functions["vlineproj"] = FunctionExpression::VLINEPROJ;
3686
        registered_functions["vnormalize"] = FunctionExpression::VNORMALIZE;
3687
        registered_functions["vplanedist"] = FunctionExpression::VPLANEDIST;
3688
        registered_functions["vplaneproj"] = FunctionExpression::VPLANEPROJ;
3689
        registered_functions["vscale"] = FunctionExpression::VSCALE;
3690
        registered_functions["vscalex"] = FunctionExpression::VSCALEX;
3691
        registered_functions["vscaley"] = FunctionExpression::VSCALEY;
3692
        registered_functions["vscalez"] = FunctionExpression::VSCALEZ;
3693

3694
        registered_functions["minvert"] = FunctionExpression::MINVERT;
3695
        registered_functions["mrotate"] = FunctionExpression::MROTATE;
3696
        registered_functions["mrotatex"] = FunctionExpression::MROTATEX;
3697
        registered_functions["mrotatey"] = FunctionExpression::MROTATEY;
3698
        registered_functions["mrotatez"] = FunctionExpression::MROTATEZ;
3699
        registered_functions["mscale"] = FunctionExpression::MSCALE;
3700
        registered_functions["mtranslate"] = FunctionExpression::MTRANSLATE;
3701

3702
        registered_functions["create"] = FunctionExpression::CREATE;
3703
        registered_functions["list"] = FunctionExpression::LIST;
3704
        registered_functions["matrix"] = FunctionExpression::MATRIX;
3705
        registered_functions["placement"] = FunctionExpression::PLACEMENT;
3706
        registered_functions["rotation"] = FunctionExpression::ROTATION;
3707
        registered_functions["rotationx"] = FunctionExpression::ROTATIONX;
3708
        registered_functions["rotationy"] = FunctionExpression::ROTATIONY;
3709
        registered_functions["rotationz"] = FunctionExpression::ROTATIONZ;
3710
        registered_functions["str"] = FunctionExpression::STR;
3711
        registered_functions["parsequant"] = FunctionExpression::PARSEQUANT;
3712
        registered_functions["translationm"] = FunctionExpression::TRANSLATIONM;
3713
        registered_functions["tuple"] = FunctionExpression::TUPLE;
3714
        registered_functions["vector"] = FunctionExpression::VECTOR;
3715

3716
        registered_functions["hiddenref"] = FunctionExpression::HIDDENREF;
3717
        registered_functions["href"] = FunctionExpression::HREF;
3718

3719
        // Aggregates
3720
        registered_functions["average"] = FunctionExpression::AVERAGE;
3721
        registered_functions["count"] = FunctionExpression::COUNT;
3722
        registered_functions["max"] = FunctionExpression::MAX;
3723
        registered_functions["min"] = FunctionExpression::MIN;
3724
        registered_functions["stddev"] = FunctionExpression::STDDEV;
3725
        registered_functions["sum"] = FunctionExpression::SUM;
3726

3727
        has_registered_functions = true;
3728
    }
3729
}
3730

3731
std::vector<std::tuple<int, int, std::string> > tokenize(const std::string &str)
3732
{
3733
    ExpressionParser::YY_BUFFER_STATE buf = ExpressionParser_scan_string(str.c_str());
3734
    ExpressionParser::StringBufferCleaner cleaner(buf);
3735
    std::vector<std::tuple<int, int, std::string> > result;
3736
    int token;
3737

3738
    column = 0;
3739
    try {
3740
        while ( (token  = ExpressionParserlex()) != 0)
3741
            result.emplace_back(token, ExpressionParser::last_column, yytext);
3742
    }
3743
    catch (...) {
3744
        // Ignore all exceptions
3745
    }
3746

3747
    return result;
3748
}
3749

3750
}
3751

3752
}
3753

3754
/**
3755
  * Parse the expression given by \a buffer, and use \a owner as the owner of the
3756
  * returned expression. If the parser fails for some reason, and exception is thrown.
3757
  *
3758
  * @param owner  The DocumentObject that will own the expression.
3759
  * @param buffer The string buffer to parse.
3760
  *
3761
  * @returns A pointer to an expression.
3762
  *
3763
  */
3764

3765
Expression * App::ExpressionParser::parse(const App::DocumentObject *owner, const char* buffer)
3766
{
3767
    // parse from buffer
3768
    ExpressionParser::YY_BUFFER_STATE my_string_buffer = ExpressionParser::ExpressionParser_scan_string (buffer);
3769
    ExpressionParser::StringBufferCleaner cleaner(my_string_buffer);
3770

3771
    initParser(owner);
3772

3773
    // run the parser
3774
    int result = ExpressionParser::ExpressionParser_yyparse ();
3775

3776
    if (result != 0)
3777
        throw ParserError("Failed to parse expression.");
3778

3779
    if (!ScanResult)
3780
        throw ParserError("Unknown error in expression");
3781

3782
    if (valueExpression)
3783
        return ScanResult;
3784
    else {
3785
        delete ScanResult;
3786
        throw Expression::Exception("Expression can not evaluate to a value.");
3787
    }
3788
}
3789

3790
UnitExpression * ExpressionParser::parseUnit(const App::DocumentObject *owner, const char* buffer)
3791
{
3792
    // parse from buffer
3793
    ExpressionParser::YY_BUFFER_STATE my_string_buffer = ExpressionParser::ExpressionParser_scan_string (buffer);
3794
    ExpressionParser::StringBufferCleaner cleaner(my_string_buffer);
3795

3796
    initParser(owner);
3797

3798
    // run the parser
3799
    int result = ExpressionParser::ExpressionParser_yyparse ();
3800

3801
    if (result != 0)
3802
        throw ParserError("Failed to parse expression.");
3803

3804
    if (!ScanResult)
3805
        throw ParserError("Unknown error in expression");
3806

3807
    // Simplify expression
3808
    Expression * simplified = ScanResult->simplify();
3809

3810
    if (!unitExpression) {
3811
        OperatorExpression * fraction = freecad_dynamic_cast<OperatorExpression>(ScanResult);
3812

3813
        if (fraction && fraction->getOperator() == OperatorExpression::DIV) {
3814
            NumberExpression * nom = freecad_dynamic_cast<NumberExpression>(fraction->getLeft());
3815
            UnitExpression * denom = freecad_dynamic_cast<UnitExpression>(fraction->getRight());
3816

3817
            // If not initially a unit expression, but value is equal to 1, it means the expression is something like 1/unit
3818
            if (denom && nom && essentiallyEqual(nom->getValue(), 1.0))
3819
                unitExpression = true;
3820
        }
3821
    }
3822
    delete ScanResult;
3823

3824
    if (unitExpression) {
3825
        NumberExpression * num = freecad_dynamic_cast<NumberExpression>(simplified);
3826

3827
        if (num) {
3828
           simplified = new UnitExpression(num->getOwner(), num->getQuantity());
3829
            delete num;
3830
        }
3831
        return freecad_dynamic_cast<UnitExpression>(simplified);
3832
    }
3833
    else {
3834
        delete simplified;
3835
        throw Expression::Exception("Expression is not a unit.");
3836
    }
3837
}
3838

3839
namespace {
3840
std::tuple<int, int> getTokenAndStatus(const std::string & str)
3841
{
3842
    ExpressionParser::YY_BUFFER_STATE buf = ExpressionParser::ExpressionParser_scan_string(str.c_str());
3843
    ExpressionParser::StringBufferCleaner cleaner(buf);
3844
    int token = ExpressionParser::ExpressionParserlex();
3845
    int status = ExpressionParser::ExpressionParserlex();
3846

3847
    return std::make_tuple(token, status);
3848
}
3849
}
3850

3851
bool ExpressionParser::isTokenAnIndentifier(const std::string & str)
3852
{
3853
    int token{}, status{};
3854
    std::tie(token, status) = getTokenAndStatus(str);
3855
    return (status == 0 && (token == IDENTIFIER || token == CELLADDRESS));
3856
}
3857

3858
bool ExpressionParser::isTokenAUnit(const std::string & str)
3859
{
3860
    int token{}, status{};
3861
    std::tie(token, status) = getTokenAndStatus(str);
3862
    return (status == 0 && token == UNIT);
3863
}
3864

3865
#if defined(__clang__)
3866
# pragma clang diagnostic pop
3867
#endif
3868

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.