1
/***************************************************************************
2
* Copyright (c) 2015 Eivind Kvedalen <eivind@kvedalen.name> *
4
* This file is part of the FreeCAD CAx development system. *
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. *
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. *
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 *
21
***************************************************************************/
23
#include "PreCompiled.h"
29
# pragma clang diagnostic push
30
# pragma clang diagnostic ignored "-Wdelete-non-virtual-dtor"
33
#include <boost/algorithm/string/predicate.hpp>
34
#include <boost/math/special_functions/round.hpp>
35
#include <boost/math/special_functions/trunc.hpp>
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>
52
#include "ExpressionParser.h"
55
/** \defgroup Expression Expressions framework
57
\brief The expression system allows users to write expressions and formulas that produce values
63
FC_LOG_LEVEL_INIT("Expression", true, true)
66
#define M_PI 3.14159265358979323846
69
#define M_E 2.71828182845904523536
72
# define DOUBLE_MAX 1.7976931348623157E+308 /* max decimal value of a "double"*/
75
# define DOUBLE_MIN 2.2250738585072014E-308 /* min decimal value of a "double"*/
79
#define strtoll _strtoi64
80
#pragma warning(disable : 4003)
81
#pragma warning(disable : 4065)
84
#define __EXPR_THROW(_e,_msg,_expr) do {\
85
std::ostringstream ss;\
86
ss << _msg << (_expr);\
87
throw _e(ss.str().c_str());\
90
#define _EXPR_THROW(_msg,_expr) __EXPR_THROW(ExpressionError,_msg,_expr)
92
#define __EXPR_SET_MSG(_e,_msg,_expr) do {\
93
std::ostringstream ss;\
94
ss << _msg << _e.what() << (_expr);\
95
_e.setMessage(ss.str());\
98
#define _EXPR_RETHROW(_e,_msg,_expr) do {\
99
__EXPR_SET_MSG(_e,_msg,_expr);\
103
#define _EXPR_PY_THROW(_msg,_expr) do {\
104
Base::PyException _e;\
105
__EXPR_SET_MSG(_e,_msg,_expr);\
106
_e.raiseException();\
109
#define EXPR_PY_THROW(_expr) _EXPR_PY_THROW("", _expr)
111
#define EXPR_THROW(_msg) _EXPR_THROW(_msg, this)
113
#define ARGUMENT_THROW(_msg) EXPR_THROW("Invalid number of arguments: " _msg)
115
#define RUNTIME_THROW(_msg) __EXPR_THROW(Base::RuntimeError, _msg, static_cast<Expression*>(nullptr))
117
#define TYPE_THROW(_msg) __EXPR_THROW(Base::TypeError, _msg, static_cast<Expression*>(nullptr))
119
#define PARSER_THROW(_msg) __EXPR_THROW(Base::ParserError, _msg, static_cast<Expression*>(nullptr))
121
#define PY_THROW(_msg) __EXPR_THROW(Py::RuntimeError, _msg, static_cast<Expression*>(nullptr))
123
static inline std::ostream &operator<<(std::ostream &os, const App::Expression *expr) {
125
os << "\nin expression: ";
132
void copy_vector(T &dst, const T& src) {
134
dst.reserve(src.size());
137
dst.push_back(s->copy());
143
////////////////////////////////////////////////////////////////////////////////
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)
148
// #define USE_FAST_ANY
150
static inline bool is_type(const App::any &value, const std::type_info& t) {
152
return &value.type() == &t;
154
return value.type() == t;
159
static inline const T &cast(const App::any &value) {
161
return *value.cast<T>();
163
return App::any_cast<const T&>(value);
168
static inline T &cast(App::any &value) {
170
return *value.cast<T>();
172
return App::any_cast<T&>(value);
177
static inline T &&cast(App::any &&value) {
179
return std::move(*value.cast<T>());
181
return App::any_cast<T&&>(std::move(value));
185
std::string unquote(const std::string & input)
187
assert(input.size() >= 4);
190
std::string::const_iterator cur = input.begin() + 2;
191
std::string::const_iterator end = input.end() - 2;
193
output.reserve(input.size());
195
bool escaped = false;
232
////////////////////////////////////////////////////////////////////////////////////
236
void ExpressionVisitor::getIdentifiers(Expression &e, std::map<App::ObjectIdentifier,bool> &ids) {
237
e._getIdentifiers(ids);
240
bool ExpressionVisitor::adjustLinks(Expression &e, const std::set<App::DocumentObject*> &inList) {
241
return e._adjustLinks(inList,*this);
244
void ExpressionVisitor::importSubNames(Expression &e, const ObjectIdentifier::SubNameMap &subNameMap) {
245
e._importSubNames(subNameMap);
248
void ExpressionVisitor::updateLabelReference(Expression &e,
249
DocumentObject *obj, const std::string &ref, const char *newLabel)
251
e._updateLabelReference(obj,ref,newLabel);
254
bool ExpressionVisitor::updateElementReference(Expression &e, App::DocumentObject *feature, bool reverse) {
255
return e._updateElementReference(feature,reverse,*this);
258
bool ExpressionVisitor::relabeledDocument(
259
Expression &e, const std::string &oldName, const std::string &newName)
261
return e._relabeledDocument(oldName,newName,*this);
264
bool ExpressionVisitor::renameObjectIdentifier(Expression &e,
265
const std::map<ObjectIdentifier,ObjectIdentifier> &paths, const ObjectIdentifier &path)
267
return e._renameObjectIdentifier(paths,path,*this);
270
void ExpressionVisitor::collectReplacement(Expression &e,
271
std::map<ObjectIdentifier,ObjectIdentifier> &paths,
272
const App::DocumentObject *parent, App::DocumentObject *oldObj, App::DocumentObject *newObj) const
274
return e._collectReplacement(paths,parent,oldObj,newObj);
277
void ExpressionVisitor::moveCells(Expression &e, const CellAddress &address, int rowCount, int colCount) {
278
e._moveCells(address,rowCount,colCount,*this);
281
void ExpressionVisitor::offsetCells(Expression &e, int rowOffset, int colOffset) {
282
e._offsetCells(rowOffset,colOffset,*this);
285
/////////////////////////////////////////////////////////////////////////////////////
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)
293
static bool approximatelyEqual(double a, double b, double epsilon)
295
return fabs(a - b) <= ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon);
300
static inline bool essentiallyEqual(T a, T b)
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);
307
inline bool essentiallyZero(T a) {
312
inline bool essentiallyZero(double a) {
313
return essentiallyEqual(a, 0.0);
317
inline bool essentiallyZero(float a) {
318
return essentiallyEqual(a, 0.0f);
322
static inline bool definitelyGreaterThan(T a, T b)
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);
329
static inline bool definitelyLessThan(T a, T b)
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);
335
static inline int essentiallyInteger(double a, long &l, int &i) {
337
if (std::modf(a,&intpart) == 0.0) {
339
if (intpart >= INT_MIN) {
340
i = static_cast<int>(intpart);
344
if (intpart >= LONG_MIN) {
345
l = static_cast<long>(intpart);
349
else if (intpart <= INT_MAX) {
350
i = static_cast<int>(intpart);
354
else if (intpart <= static_cast<double>(LONG_MAX)) {
355
l = static_cast<int>(intpart);
362
static inline bool essentiallyInteger(double a, long &l) {
364
if (std::modf(a,&intpart) == 0.0) {
366
if (intpart >= LONG_MIN) {
367
l = static_cast<long>(intpart);
371
else if (intpart <= static_cast<double>(LONG_MAX)) {
372
l = static_cast<long>(intpart);
379
// This class is intended to be contained inside App::any (via a shared_ptr)
380
// without holding Python global lock
381
struct PyObjectWrapper {
383
using Pointer = std::shared_ptr<PyObjectWrapper>;
385
explicit PyObjectWrapper(PyObject *obj):pyobj(obj) {
390
Base::PyGILStateLocker lock;
394
PyObjectWrapper(const PyObjectWrapper &) = delete;
395
PyObjectWrapper &operator=(const PyObjectWrapper &) = delete;
397
Py::Object get() const {
400
return Py::Object(const_cast<PyObject*>(pyobj));
407
static inline PyObjectWrapper::Pointer pyObjectWrap(PyObject *obj) {
408
return std::make_shared<PyObjectWrapper>(obj);
411
static inline bool isAnyPyObject(const App::any &value) {
412
return is_type(value,typeid(PyObjectWrapper::Pointer));
415
static inline Py::Object __pyObjectFromAny(const App::any &value) {
416
return cast<PyObjectWrapper::Pointer>(value)->get();
419
static Py::Object _pyObjectFromAny(const App::any &value, const Expression *e) {
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));
441
_EXPR_THROW("Unknown type", e);
445
Py::Object pyObjectFromAny(const App::any &value) {
446
return _pyObjectFromAny(value,nullptr);
449
App::any pyObjectToAny(Py::Object value, bool check) {
454
PyObject *pyvalue = value.ptr();
457
return {pyObjectWrap(pyvalue)};
459
if (PyObject_TypeCheck(pyvalue, &Base::QuantityPy::Type)) {
460
Base::QuantityPy * qp = static_cast<Base::QuantityPy*>(pyvalue);
461
Base::Quantity * q = qp->getQuantityPtr();
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);
472
FC_THROWM(Base::ValueError, "Invalid unicode string");
474
return App::any(std::string(utf8value));
477
return App::any(pyObjectWrap(pyvalue));
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));
493
static inline Quantity pyToQuantity(const Py::Object &pyobj,
494
const Expression *e, const char *msg=nullptr)
497
if(!pyToQuantity(q,pyobj)) {
499
msg = "Failed to convert to Quantity.";
500
__EXPR_THROW(TypeError,msg,e);
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();
511
switch(essentiallyInteger(v,l,i)) {
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));
535
msg = "Failed to convert to Quantity";
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;
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;
567
bool isAnyEqual(const App::any &v1, const App::any &v2) {
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);
581
if(anyToLong(l1,v1)) {
584
else if(anyToDouble(d2,v2))
585
return essentiallyEqual((double)l1,d2);
588
}else if(anyToDouble(d1,v1))
589
return anyToDouble(d2,v2) && essentiallyEqual(d1,d2);
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;
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;
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);
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));
624
if (is_type(v1,typeid(Quantity)))
625
return cast<Quantity>(v1) == cast<Quantity>(v2);
627
if (!isAnyPyObject(v1))
628
throw Base::TypeError("Unknown type");
630
Base::PyGILStateLocker lock;
631
Py::Object o1 = __pyObjectFromAny(v1);
632
Py::Object o2 = __pyObjectFromAny(v2);
633
if(!o1.isType(o2.type()))
635
int res = PyObject_RichCompareBool(o1.ptr(),o2.ptr(),Py_EQ);
637
PyException::ThrowException();
641
Expression* expressionFromPy(const DocumentObject *owner, const Py::Object &value) {
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()) {
651
return new ConstantExpression(owner,"True",Quantity(1.0));
653
return new ConstantExpression(owner,"False",Quantity(0.0));
656
if(pyToQuantity(q,value))
657
return new NumberExpression(owner,q);
659
return new PyObjectExpression(owner,value.ptr());
665
// Expression component
667
Expression::Component::Component(const std::string &n)
668
:comp(ObjectIdentifier::SimpleComponent(n))
669
,e1(nullptr) ,e2(nullptr) ,e3(nullptr)
672
Expression::Component::Component(Expression *_e1, Expression *_e2, Expression *_e3, bool isRange)
673
:e1(_e1) ,e2(_e2) ,e3(_e3)
675
if(isRange || e2 || e3)
676
comp = ObjectIdentifier::RangeComponent(0);
679
Expression::Component::Component(const ObjectIdentifier::Component &comp)
681
,e1(nullptr) ,e2(nullptr) ,e3(nullptr)
684
Expression::Component::Component(const Component &other)
686
,e1(other.e1?other.e1->copy():nullptr)
687
,e2(other.e2?other.e2->copy():nullptr)
688
,e3(other.e3?other.e3->copy():nullptr)
691
Expression::Component::~Component()
698
Expression::Component* Expression::Component::copy() const {
699
return new Component(*this);
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();
710
Py::Object Expression::Component::get(const Expression *owner, const Py::Object &pyobj) const {
712
if(!e1 && !e2 && !e3)
713
return comp.get(pyobj);
714
if(!comp.isRange() && !e2 && !e3) {
715
auto index = e1->getPyValue();
717
if(pyobj.isMapping())
718
res = Py::Mapping(pyobj).getItem(index);
720
Py_ssize_t i = PyNumber_AsSsize_t(index.ptr(), PyExc_IndexError);
722
throw Py::Exception();
723
res = Py::Sequence(pyobj).getItem(i);
726
throw Py::Exception();
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,
735
e3?v3.ptr():nullptr);
737
throw Py::Exception();
738
Py::Object slice(s,true);
739
PyObject *res = PyObject_GetItem(pyobj.ptr(),slice.ptr());
741
throw Py::Exception();
742
return Py::asObject(res);
744
}catch(Py::Exception &) {
745
EXPR_PY_THROW(owner);
750
void Expression::Component::set(const Expression *owner, Py::Object &pyobj, const Py::Object &value) const
752
if(!e1 && !e2 && !e3)
753
return comp.set(pyobj,value);
755
if(!comp.isRange() && !e2 && !e3) {
756
auto index = e1->getPyValue();
757
if(pyobj.isMapping())
758
Py::Mapping(pyobj).setItem(index,value);
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();
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,
771
e3?v3.ptr():nullptr);
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();
778
}catch(Py::Exception &) {
779
EXPR_PY_THROW(owner);
783
void Expression::Component::del(const Expression *owner, Py::Object &pyobj) const {
785
if (!e1 && !e2 && !e3) {
788
else if (!comp.isRange() && !e2 && !e3) {
789
auto index = e1->getPyValue();
790
if (pyobj.isMapping()) {
791
Py::Mapping(pyobj).delItem(index);
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();
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,
806
e3?v3.ptr():nullptr);
808
throw Py::Exception();
809
Py::Object slice(s,true);
810
if (PyObject_DelItem(pyobj.ptr(),slice.ptr())<0)
811
throw Py::Exception();
814
catch(Py::Exception &) {
815
EXPR_PY_THROW(owner);
819
void Expression::Component::visit(ExpressionVisitor &v) {
825
bool Expression::Component::isTouched() const {
826
return (e1&&e1->isTouched()) ||
827
(e2&&e2->isTouched()) ||
828
(e3&&e3->isTouched());
831
void Expression::Component::toString(std::ostream &ss, bool persistent) const {
832
if(!e1 && !e2 && !e3) {
835
comp.toString(ss,!persistent);
840
e1->toString(ss,persistent);
841
if(e2 || comp.isRange())
844
e2->toString(ss,persistent);
847
e3->toString(ss,persistent);
854
// Expression base-class
857
TYPESYSTEM_SOURCE_ABSTRACT(App::Expression, Base::BaseClass)
859
Expression::Expression(const DocumentObject *_owner)
860
: owner(const_cast<App::DocumentObject*>(_owner))
865
Expression::~Expression()
867
for(auto c : components)
871
Expression::Component* Expression::createComponent(const std::string &n) {
872
return new Component(n);
875
Expression::Component* Expression::createComponent(
876
Expression* e1, Expression* e2, Expression* e3, bool isRange)
878
return new Component(e1,e2,e3,isRange);
882
int Expression::priority() const {
886
Expression * Expression::parse(const DocumentObject *owner, const std::string &buffer)
888
return ExpressionParser::parse(owner, buffer.c_str());
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))
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);
907
ExpressionDeps Expression::getDeps(int option) const {
909
getDeps(deps, option);
913
void Expression::getDepObjects(
914
std::map<App::DocumentObject*,bool> &deps, std::vector<std::string> *labels) const
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)) {
924
std::copy(strings.begin(), strings.end(), std::back_inserter(*labels));
927
auto res = deps.insert(std::make_pair(obj, hidden));
928
if (!hidden || res.second)
929
res.first->second = hidden;
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);
943
class GetIdentifiersExpressionVisitor : public ExpressionVisitor {
945
explicit GetIdentifiersExpressionVisitor(std::map<App::ObjectIdentifier,bool> &deps)
949
void visit(Expression &e) override {
950
this->getIdentifiers(e,deps);
953
std::map<App::ObjectIdentifier,bool> &deps;
956
void Expression::getIdentifiers(std::map<App::ObjectIdentifier,bool> &deps) const {
957
GetIdentifiersExpressionVisitor v(deps);
958
const_cast<Expression*>(this)->visit(v);
961
std::map<App::ObjectIdentifier,bool> Expression::getIdentifiers() const {
962
std::map<App::ObjectIdentifier,bool> deps;
963
getIdentifiers(deps);
967
class AdjustLinksExpressionVisitor : public ExpressionVisitor {
969
explicit AdjustLinksExpressionVisitor(const std::set<App::DocumentObject*> &inList)
973
void visit(Expression &e) override {
974
if(this->adjustLinks(e,inList))
978
const std::set<App::DocumentObject*> &inList;
982
bool Expression::adjustLinks(const std::set<App::DocumentObject*> &inList) {
983
AdjustLinksExpressionVisitor v(inList);
988
class ImportSubNamesExpressionVisitor : public ExpressionVisitor {
990
explicit ImportSubNamesExpressionVisitor(const ObjectIdentifier::SubNameMap &subNameMap)
991
:subNameMap(subNameMap)
994
void visit(Expression &e) override {
995
this->importSubNames(e,subNameMap);
998
const ObjectIdentifier::SubNameMap &subNameMap;
1001
ExpressionPtr Expression::importSubNames(const std::map<std::string,std::string> &nameMap) const {
1002
if(!owner || !owner->getDocument())
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();
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))
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));
1024
if(subNameMap.empty())
1026
ImportSubNamesExpressionVisitor v(subNameMap);
1029
return ExpressionPtr(res);
1032
class UpdateLabelExpressionVisitor : public ExpressionVisitor {
1034
UpdateLabelExpressionVisitor(App::DocumentObject *obj, const std::string &ref, const char *newLabel)
1035
:obj(obj),ref(ref),newLabel(newLabel)
1038
void visit(Expression &e) override {
1039
this->updateLabelReference(e,obj,ref,newLabel);
1042
App::DocumentObject *obj;
1043
const std::string &ref;
1044
const char *newLabel;
1047
ExpressionPtr Expression::updateLabelReference(
1048
App::DocumentObject *obj, const std::string &ref, const char *newLabel) const
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);
1061
return ExpressionPtr(expr);
1067
class ReplaceObjectExpressionVisitor : public ExpressionVisitor {
1069
ReplaceObjectExpressionVisitor(const DocumentObject *parent,
1070
DocumentObject *oldObj, DocumentObject *newObj)
1071
: parent(parent),oldObj(oldObj),newObj(newObj)
1075
void visit(Expression &e) override {
1077
this->collectReplacement(e,paths,parent,oldObj,newObj);
1079
this->renameObjectIdentifier(e,paths,dummy);
1082
const DocumentObject *parent;
1083
DocumentObject *oldObj;
1084
DocumentObject *newObj;
1085
ObjectIdentifier dummy;
1086
std::map<ObjectIdentifier, ObjectIdentifier> paths;
1087
bool collect = true;
1090
ExpressionPtr Expression::replaceObject(const DocumentObject *parent,
1091
DocumentObject *oldObj, DocumentObject *newObj) const
1093
ReplaceObjectExpressionVisitor v(parent,oldObj,newObj);
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);
1102
// Now make a copy and do the actual replacement
1106
return ExpressionPtr(expr);
1109
App::any Expression::getValueAsAny() const {
1110
Base::PyGILStateLocker lock;
1111
return pyObjectToAny(getPyValue());
1114
Py::Object Expression::getPyValue() const {
1116
Py::Object pyobj = _getPyValue();
1117
if(!components.empty()) {
1118
for(auto &c : components)
1119
pyobj = c->get(this,pyobj);
1122
}catch(Py::Exception &) {
1123
EXPR_PY_THROW(this);
1125
return Py::Object();
1128
void Expression::addComponent(Component *component) {
1130
components.push_back(component);
1133
void Expression::visit(ExpressionVisitor &v) {
1135
for(auto &c : components)
1140
Expression* Expression::eval() const {
1141
Base::PyGILStateLocker lock;
1142
return expressionFromPy(owner,getPyValue());
1145
bool Expression::isSame(const Expression &other, bool checkComment) const {
1148
if(getTypeId()!=other.getTypeId())
1150
return (!checkComment || comment==other.comment)
1151
&& toString(true,true) == other.toString(true,true);
1154
std::string Expression::toString(bool persistent, bool checkPriority, int indent) const {
1155
std::ostringstream ss;
1156
toString(ss,persistent,checkPriority,indent);
1160
void Expression::toString(std::ostream &ss, bool persistent, bool checkPriority, int indent) const {
1161
if(components.empty()) {
1162
bool needsParens = checkPriority && priority()<20;
1165
_toString(ss,persistent,indent);
1170
if(!_isIndexable()) {
1172
_toString(ss,persistent,indent);
1175
_toString(ss,persistent,indent);
1176
for(auto &c : components)
1177
c->toString(ss,persistent);
1180
Expression* Expression::copy() const {
1181
auto expr = _copy();
1182
copy_vector(expr->components,components);
1183
expr->comment = comment;
1189
// UnitExpression class
1192
TYPESYSTEM_SOURCE(App::UnitExpression, App::Expression)
1194
UnitExpression::UnitExpression(const DocumentObject *_owner, const Base::Quantity & _quantity, const std::string &_unitStr)
1195
: Expression(_owner)
1196
, quantity(_quantity)
1201
UnitExpression::~UnitExpression() {
1203
Base::PyGILStateLocker lock;
1204
Py::_XDECREF(cache);
1208
void UnitExpression::setQuantity(const Quantity &_quantity)
1210
quantity = _quantity;
1212
Base::PyGILStateLocker lock;
1213
Py::_XDECREF(cache);
1219
* Set unit information.
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.
1226
void UnitExpression::setUnit(const Quantity &_quantity)
1228
quantity = _quantity;
1230
Base::PyGILStateLocker lock;
1231
Py::_XDECREF(cache);
1237
* Simplify the expression. In this case, a NumberExpression is returned,
1238
* as it cannot be simplified any more.
1241
Expression *UnitExpression::simplify() const
1243
return new NumberExpression(owner, quantity);
1247
* Return a string representation, in this case the unit string.
1251
* Return a string representation of the expression.
1254
void UnitExpression::_toString(std::ostream &ss, bool,int) const
1260
* Return a copy of the expression.
1263
Expression *UnitExpression::_copy() const
1265
return new UnitExpression(owner, quantity, unitStr);
1268
Py::Object UnitExpression::_getPyValue() const {
1270
cache = Py::new_reference_to(pyFromQuantity(quantity));
1271
return Py::Object(cache);
1275
// NumberExpression class
1278
TYPESYSTEM_SOURCE(App::NumberExpression, App::Expression)
1280
NumberExpression::NumberExpression(const DocumentObject *_owner, const Quantity &_quantity)
1281
: UnitExpression(_owner, _quantity)
1286
* Simplify the expression. For NumberExpressions, we return a copy(), as it cannot
1287
* be simplified any more.
1290
Expression *NumberExpression::simplify() const
1296
* Create and return a copy of the expression.
1299
Expression *NumberExpression::_copy() const
1301
return new NumberExpression(owner, getQuantity());
1305
* Negate the stored value.
1308
void NumberExpression::negate()
1310
setQuantity(-getQuantity());
1313
void NumberExpression::_toString(std::ostream &ss, bool,int) const
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
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();
1325
/* Trim of any extra spaces */
1326
//while (s.size() > 0 && s[s.size() - 1] == ' ')
1327
// s.erase(s.size() - 1);
1330
bool NumberExpression::isInteger(long *l) const {
1334
return essentiallyInteger(getValue(),*l);
1338
// OperatorExpression class
1341
TYPESYSTEM_SOURCE(App::OperatorExpression, App::Expression)
1343
OperatorExpression::OperatorExpression(const App::DocumentObject *_owner, Expression * _left, Operator _op, Expression * _right)
1344
: UnitExpression(_owner)
1352
OperatorExpression::~OperatorExpression()
1359
* Determine whether the expression is touched or not, i.e relies on properties that are touched.
1362
bool OperatorExpression::isTouched() const
1364
return left->isTouched() || right->isTouched();
1367
static Py::Object calc(const Expression *expr, int op,
1368
const Expression *left, const Expression *right, bool inplace)
1370
Py::Object l = left->getPyValue();
1372
// For security reason, restrict supported types
1373
if(!PyObject_TypeCheck(l.ptr(),&PyObjectBase::Type)
1374
&& !l.isNumeric() && !l.isString() && !l.isList() && !l.isDict())
1376
__EXPR_THROW(Base::TypeError,"Unsupported operator", expr);
1379
// check possible unary operation first
1381
case OperatorExpression::POS:{
1382
PyObject *res = PyNumber_Positive(l.ptr());
1383
if(!res) EXPR_PY_THROW(expr);
1384
return Py::asObject(res);
1386
case OperatorExpression::NEG:{
1387
PyObject *res = PyNumber_Negative(l.ptr());
1388
if(!res) EXPR_PY_THROW(expr);
1389
return Py::asObject(res);
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)
1403
__EXPR_THROW(Base::TypeError,"Unsupported operator", expr);
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);\
1414
RICH_COMPARE(LTE,LE)
1416
RICH_COMPARE(GTE,GE)
1418
RICH_COMPARE(NEQ,NE)
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);
1426
#define BINARY_OP(_op,_pyop) \
1427
case OperatorExpression::_op: {\
1432
BINARY_OP(SUB,Subtract)
1433
BINARY_OP(MUL,Multiply)
1434
BINARY_OP(UNIT,Multiply)
1435
BINARY_OP(DIV,TrueDivide)
1436
case OperatorExpression::ADD: {
1438
if (PyUnicode_CheckExact(*l) && PyUnicode_CheckExact(*r)) {
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
1445
PyUnicode_Append(&res, r.ptr());
1447
res = PyUnicode_Concat(l.ptr(),r.ptr());
1448
if(!res) EXPR_PY_THROW(expr);
1449
return Py::asObject(res);
1453
case OperatorExpression::POW: {
1456
res = PyNumber_InPlacePower(l.ptr(),r.ptr(),Py::None().ptr());
1458
res = PyNumber_Power(l.ptr(),r.ptr(),Py::None().ptr());
1459
if(!res) EXPR_PY_THROW(expr);
1460
return Py::asObject(res);
1462
case OperatorExpression::MOD: {
1464
if (PyUnicode_CheckExact(l.ptr()) &&
1465
(!PyUnicode_Check(r.ptr()) || PyUnicode_CheckExact(r.ptr())))
1466
res = PyUnicode_Format(l.ptr(), r.ptr());
1468
res = PyNumber_InPlaceRemainder(l.ptr(),r.ptr());
1470
res = PyNumber_InPlaceRemainder(l.ptr(),r.ptr());
1471
if(!res) EXPR_PY_THROW(expr);
1472
return Py::asObject(res);
1475
__EXPR_THROW(RuntimeError,"Unsupported operator",expr);
1479
Py::Object OperatorExpression::_getPyValue() const {
1480
return calc(this,op,left,right,false);
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.
1488
* @returns Simplified expression.
1491
Expression *OperatorExpression::simplify() const
1493
Expression * v1 = left->simplify();
1494
Expression * v2 = right->simplify();
1496
// Both arguments reduced to numerics? Then evaluate and return answer
1497
if (freecad_dynamic_cast<NumberExpression>(v1) && freecad_dynamic_cast<NumberExpression>(v2)) {
1503
return new OperatorExpression(owner, v1, op, v2);
1507
* Create a string representation of the expression.
1509
* @returns A string representing the expression.
1512
void OperatorExpression::_toString(std::ostream &s, bool persistent,int) const
1515
Operator leftOperator(NONE), rightOperator(NONE);
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
1522
else if (leftOperator == op) { // Same operator ?
1523
if (!isLeftAssociative())
1525
//else if (!isCommutative())
1526
// needsParens = true;
1531
s << "-" << (needsParens ? "(" : "") << left->toString(persistent) << (needsParens ? ")" : "");
1534
s << "+" << (needsParens ? "(" : "") << left->toString(persistent) << (needsParens ? ")" : "");
1541
s << "(" << left->toString(persistent) << ")";
1543
s << left->toString(persistent);
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
1594
else if (rightOperator == op) { // Same operator ?
1595
if (!isRightAssociative())
1597
else if (!isCommutative())
1600
else if (right->priority() == priority()) { // Same priority ?
1601
if (!isRightAssociative() || rightOperator == MOD)
1607
right->toString(s,persistent);
1610
right->toString(s,persistent);
1614
* A deep copy of the expression.
1617
Expression *OperatorExpression::_copy() const
1619
return new OperatorExpression(owner, left->copy(), op, right->copy());
1623
* Return the operators priority. This is used to add parentheses where
1624
* needed when creating a string representation of the expression.
1626
* @returns The operator's priority.
1629
int OperatorExpression::priority() const
1658
void OperatorExpression::_visit(ExpressionVisitor &v)
1666
bool OperatorExpression::isCommutative() const
1679
bool OperatorExpression::isLeftAssociative() const
1684
bool OperatorExpression::isRightAssociative() const
1696
// FunctionExpression class. This class handles functions with one or two parameters.
1699
TYPESYSTEM_SOURCE(App::FunctionExpression, App::UnitExpression)
1701
static int _HiddenReference;
1703
struct HiddenReference {
1704
explicit HiddenReference(bool cond)
1710
~HiddenReference() {
1715
static bool check(int option) {
1716
return (option==Expression::DepNormal && _HiddenReference)
1717
|| (option==Expression::DepHidden && !_HiddenReference);
1720
static bool isHidden() {
1721
return _HiddenReference!=0;
1727
FunctionExpression::FunctionExpression(const DocumentObject *_owner, Function _f, std::string &&name, std::vector<Expression *> _args)
1728
: UnitExpression(_owner)
1730
, fname(std::move(name))
1762
if (args.size() != 1)
1763
ARGUMENT_THROW("exactly one required.");
1766
if (args.size() > 3)
1767
ARGUMENT_THROW("exactly one, two, or three required.");
1770
if (args.size() != 1 && args.size() != 3)
1771
ARGUMENT_THROW("exactly one or three required.");
1785
if (args.size() != 2)
1786
ARGUMENT_THROW("exactly two required.");
1791
if (args.size() < 2 || args.size() > 3)
1792
ARGUMENT_THROW("exactly two, or three required.");
1796
if (args.size() != 2 && args.size() != 4)
1797
ARGUMENT_THROW("exactly two or four required.");
1800
if (args.size() < 2 || args.size() > 4)
1801
ARGUMENT_THROW("exactly two, three, or four required.");
1809
if (args.size() != 3)
1810
ARGUMENT_THROW("exactly three required.");
1813
if (args.size() != 4)
1814
ARGUMENT_THROW("exactly four required.");
1817
if (args.size() > 16)
1818
ARGUMENT_THROW("exactly 16 or less required.");
1828
ARGUMENT_THROW("at least one required.");
1837
PARSER_THROW("Unknown function");
1842
FunctionExpression::~FunctionExpression()
1844
std::vector<Expression*>::iterator i = args.begin();
1846
while (i != args.end()) {
1853
* Determine whether the expressions is considered touched, i.e one or both of its arguments
1856
* @return True if touched, false if not.
1859
bool FunctionExpression::isTouched() const
1861
std::vector<Expression*>::const_iterator i = args.begin();
1863
while (i != args.end()) {
1864
if ((*i)->isTouched())
1871
/* Various collectors for aggregate functions */
1875
Collector() = default;
1876
virtual ~Collector() = default;
1877
virtual void collect(Quantity value) {
1879
q.setUnit(value.getUnit());
1881
virtual Quantity getQuantity() const {
1889
class SumCollector : public Collector {
1891
SumCollector() : Collector() { }
1893
void collect(Quantity value) override {
1894
Collector::collect(value);
1901
class AverageCollector : public Collector {
1903
AverageCollector() : Collector() { }
1905
void collect(Quantity value) override {
1906
Collector::collect(value);
1912
Quantity getQuantity() const override { return q/(double)n; }
1918
class StdDevCollector : public Collector {
1920
StdDevCollector() : Collector() { }
1922
void collect(Quantity value) override {
1923
Collector::collect(value);
1925
M2 = Quantity(0, value.getUnit() * value.getUnit());
1926
mean = Quantity(0, value.getUnit());
1930
const Quantity delta = value - mean;
1932
mean = mean + delta / n;
1933
M2 = M2 + delta * (value - mean);
1937
Quantity getQuantity() const override {
1939
throw ExpressionError("Invalid number of entries: at least two required.");
1941
return Quantity((M2 / (n - 1.0)).pow(Quantity(0.5)).getValue(), mean.getUnit());
1950
class CountCollector : public Collector {
1952
CountCollector() : Collector() { }
1954
void collect(Quantity value) override {
1955
Collector::collect(value);
1960
Quantity getQuantity() const override { return Quantity(n); }
1966
class MinCollector : public Collector {
1968
MinCollector() : Collector() { }
1970
void collect(Quantity value) override {
1971
Collector::collect(value);
1972
if (first || value < q)
1978
class MaxCollector : public Collector {
1980
MaxCollector() : Collector() { }
1982
void collect(Quantity value) override {
1983
Collector::collect(value);
1984
if (first || value > q)
1990
Py::Object FunctionExpression::evalAggregate(
1991
const Expression *owner, int f, const std::vector<Expression*> &args)
1993
std::unique_ptr<Collector> c;
1997
c = std::make_unique<SumCollector>();
2000
c = std::make_unique<AverageCollector>();
2003
c = std::make_unique<StdDevCollector>();
2006
c = std::make_unique<CountCollector>();
2009
c = std::make_unique<MinCollector>();
2012
c = std::make_unique<MaxCollector>();
2018
for (auto &arg : args) {
2019
if (arg->isDerivedFrom(RangeExpression::getClassTypeId())) {
2020
Range range(static_cast<const RangeExpression&>(*arg).getRange());
2023
Property * p = owner->getOwner()->getPropertyByName(range.address().c_str());
2024
PropertyQuantity * qp;
2026
PropertyInteger * ip;
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()));
2038
_EXPR_THROW("Invalid property type for aggregate.", owner);
2039
} while (range.next());
2043
if(pyToQuantity(q,arg->getPyValue()))
2048
return pyFromQuantity(c->getQuantity());
2051
Base::Vector3d FunctionExpression::evaluateSecondVectorArgument(const Expression *expression, const std::vector<Expression*> &arguments)
2053
Py::Tuple vectorValues;
2054
Py::Object secondParameter = arguments[1]->getPyValue();
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);
2062
vectorValues = Py::Tuple(Py::Sequence(secondParameter));
2064
vectorValues = Py::Tuple(3);
2065
vectorValues.setItem(0, secondParameter);
2066
vectorValues.setItem(1, arguments[2]->getPyValue());
2067
vectorValues.setItem(2, arguments[3]->getPyValue());
2071
if (!PyArg_ParseTuple(vectorValues.ptr(), "ddd", &vector.x, &vector.y, &vector.z)) {
2073
_EXPR_THROW("Error parsing scale values.", expression);
2079
void FunctionExpression::initialiseObject(const Py::Object *object, const std::vector<Expression*> &arguments, const unsigned long offset)
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());
2086
PyObjectBase::__PyInit(object->ptr(), constructorArguments.ptr(), kwd.ptr());
2090
Py::Object FunctionExpression::transformFirstArgument(
2091
const Expression* expression,
2092
const std::vector<Expression*> &arguments,
2093
const Base::Matrix4D* transformationMatrix
2096
Py::Object target = arguments[0]->getPyValue();
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)));
2111
_EXPR_THROW("Function requires the first argument to be either Matrix, Placement or Rotation.", expression);
2114
Py::Object FunctionExpression::translationMatrix(double x, double y, double z)
2116
Base::Matrix4D matrix;
2117
matrix.move(x, y, z);
2118
return Py::asObject(new Base::MatrixPy(matrix));
2121
double FunctionExpression::extractLengthValueArgument(
2122
const Expression *expression,
2123
const std::vector<Expression*> &arguments,
2127
Quantity argumentQuantity = pyToQuantity(arguments[argumentIndex]->getPyValue(), expression);
2129
if (!(argumentQuantity.isDimensionlessOrUnit(Unit::Length))) {
2130
_EXPR_THROW("Unit must be either empty or a length.", expression);
2133
return argumentQuantity.getValue();
2136
Base::Vector3d FunctionExpression::extractVectorArgument(
2137
const Expression *expression,
2138
const std::vector<Expression*> &arguments,
2142
Py::Object argument = arguments[argumentIndex]->getPyValue();
2144
if (!PyObject_TypeCheck(argument.ptr(), &Base::VectorPy::Type)) {
2145
_EXPR_THROW("Argument must be a vector.", expression);
2148
return static_cast<Base::VectorPy*>(argument.ptr())->value();
2151
Py::Object FunctionExpression::evaluate(const Expression *expr, int f, const std::vector<Expression*> &args)
2153
if(!expr || !expr->getOwner())
2154
_EXPR_THROW("Invalid owner.", expr);
2156
// Handle aggregate functions
2158
return evalAggregate(expr, f, args);
2162
if (args.size() == 1 && args[0]->isDerivedFrom(RangeExpression::getClassTypeId()))
2163
return args[0]->getPyValue();
2164
Py::List list(args.size());
2166
for (auto &arg : args)
2167
list.setItem(i++, arg->getPyValue());
2171
if (args.size() == 1 && args[0]->isDerivedFrom(RangeExpression::getClassTypeId()))
2172
return Py::Tuple(args[0]->getPyValue());
2173
Py::Tuple tuple(args.size());
2175
for (auto &arg : args)
2176
tuple.setItem(i++, arg->getPyValue());
2182
_EXPR_THROW("Function requires at least one argument.",expr);
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);
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()));
2201
"Function requires the first argument to be either Matrix, Placement or Rotation.",
2206
Py::Object rotationObject = args[1]->getPyValue();
2207
if (!PyObject_TypeCheck(rotationObject.ptr(), &Base::RotationPy::Type))
2209
rotationObject = Py::asObject(new Base::RotationPy(Base::Rotation()));
2210
initialiseObject(&rotationObject, args, 1);
2213
Base::Matrix4D rotationMatrix;
2214
static_cast<Base::RotationPy*>(rotationObject.ptr())->getRotationPtr()->getValue(rotationMatrix);
2216
return transformFirstArgument(expr, args, &rotationMatrix);
2222
Py::Object rotationAngleParameter = args[1]->getPyValue();
2223
Quantity rotationAngle = pyToQuantity(rotationAngleParameter, expr, "Invalid rotation angle.");
2225
if (!(rotationAngle.isDimensionlessOrUnit(Unit::Angle)))
2226
_EXPR_THROW("Unit must be either empty or an angle.", expr);
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);
2234
return transformFirstArgument(expr, args, &rotationMatrix);
2237
Vector3d scaleValues = evaluateSecondVectorArgument(expr, args);
2239
Base::Matrix4D scaleMatrix;
2240
scaleMatrix.scale(scaleValues);
2242
return transformFirstArgument(expr, args, &scaleMatrix);
2245
Vector3d translateValues = evaluateSecondVectorArgument(expr, args);
2247
Base::Matrix4D translateMatrix;
2248
translateMatrix.move(translateValues);
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)));
2257
return transformFirstArgument(expr, args, &translateMatrix);
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());
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()));
2274
_EXPR_THROW("Unknown type '" << type << "'.", expr);
2275
initialiseObject(&res, args, 1);
2279
Py::Object matrix = Py::asObject(new Base::MatrixPy(Base::Matrix4D()));
2280
initialiseObject(&matrix, args);
2284
Py::Object placement = Py::asObject(new Base::PlacementPy(Base::Placement()));
2285
initialiseObject(&placement, args);
2289
Py::Object rotation = Py::asObject(new Base::RotationPy(Base::Rotation()));
2290
initialiseObject(&rotation, args);
2294
return Py::String(args[0]->getPyValue().as_string());
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)));
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);
2309
if (!PyArg_ParseTuple(Py::Tuple(Py::Sequence(parameter)).ptr(), "ddd", &x, &y, &z)) {
2311
_EXPR_THROW("Error parsing sequence.", expr);
2313
return translationMatrix(x, y, z);
2316
Py::Object vector = Py::asObject(new Base::VectorPy(Base::Vector3d()));
2317
initialiseObject(&vector, args);
2322
return args[0]->getPyValue();
2336
Base::Vector3d vector1 = extractVectorArgument(expr, args, 0);
2340
return Py::asObject(new Base::VectorPy(vector1.Normalize()));
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));
2349
double scaleX = extractLengthValueArgument(expr, args, 1);
2350
vector1.ScaleX(scaleX);
2351
return Py::asObject(new Base::VectorPy(vector1));
2354
double scaleY = extractLengthValueArgument(expr, args, 1);
2355
vector1.ScaleY(scaleY);
2356
return Py::asObject(new Base::VectorPy(vector1));
2359
double scaleZ = extractLengthValueArgument(expr, args, 1);
2360
vector1.ScaleZ(scaleZ);
2361
return Py::asObject(new Base::VectorPy(vector1));
2365
Base::Vector3d vector2 = extractVectorArgument(expr, args, 1);
2369
return Py::asObject(new QuantityPy(new Quantity(vector1.GetAngle(vector2) * 180 / M_PI, Unit::Angle)));
2371
return Py::asObject(new Base::VectorPy(vector1.Cross(vector2)));
2373
return Py::Float(vector1.Dot(vector2));
2376
Base::Vector3d vector3 = extractVectorArgument(expr, args, 2);
2380
return Py::asObject(new QuantityPy(new Quantity(vector1.DistanceToLine(vector2, vector3), Unit::Length)));
2382
return Py::asObject(new Base::VectorPy(vector1.DistanceToLineSegment(vector2, vector3)));
2384
vector1.ProjectToLine(vector2, vector3);
2385
return Py::asObject(new Base::VectorPy(vector1));
2387
return Py::asObject(new QuantityPy(new Quantity(vector1.DistanceToPlane(vector2, vector3), Unit::Length)));
2389
vector1.ProjectToPlane(vector2, vector3);
2390
return Py::asObject(new Base::VectorPy(vector1));
2395
Py::Object e1 = args[0]->getPyValue();
2396
Quantity v1 = pyToQuantity(e1,expr,"Invalid first argument.");
2399
if (args.size() > 1) {
2400
e2 = args[1]->getPyValue();
2401
v2 = pyToQuantity(e2,expr,"Invalid second argument.");
2405
if (args.size() > 2) {
2406
e3 = args[2]->getPyValue();
2407
v3 = pyToQuantity(e3,expr,"Invalid third argument.");
2414
double value = v1.getValue();
2416
/* Check units and arguments */
2424
if (!(v1.isDimensionlessOrUnit(Unit::Angle)))
2425
_EXPR_THROW("Unit must be either empty or an angle.", expr);
2427
// Convert value to radians
2428
value *= M_PI / 180.0;
2434
if (!v1.isDimensionless())
2435
_EXPR_THROW("Unit must be empty.", expr);
2437
scaler = 180.0 / M_PI;
2445
if (!v1.isDimensionless())
2446
_EXPR_THROW("Unit must be empty.",expr);
2454
unit = v1.getUnit();
2457
unit = v1.getUnit();
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);
2471
unit = Unit(s.Length /2,
2474
s.ElectricCurrent / 2,
2475
s.ThermodynamicTemperature / 2,
2476
s.AmountOfSubstance / 2,
2477
s.LuminousIntensity / 2,
2482
unit = v1.getUnit();
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);
2496
unit = Unit(s.Length /3,
2499
s.ElectricCurrent / 3,
2500
s.ThermodynamicTemperature / 3,
2501
s.AmountOfSubstance / 3,
2502
s.LuminousIntensity / 3,
2508
_EXPR_THROW("Invalid second argument.",expr);
2510
if (v1.getUnit() != v2.getUnit())
2511
_EXPR_THROW("Units must be equal.",expr);
2513
scaler = 180.0 / M_PI;
2517
_EXPR_THROW("Invalid second argument.",expr);
2518
unit = v1.getUnit() / v2.getUnit();
2522
_EXPR_THROW("Invalid second argument.",expr);
2524
if (!v2.isDimensionless())
2525
_EXPR_THROW("Exponent is not allowed to have a unit.",expr);
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);
2533
_EXPR_THROW("Exponent must be an integer when used with a unit.",expr);
2540
_EXPR_THROW("Invalid second argument.",expr);
2541
if (v1.getUnit() != v2.getUnit())
2542
_EXPR_THROW("Units must be equal.",expr);
2544
if (args.size() > 2) {
2546
_EXPR_THROW("Invalid second argument.",expr);
2547
if (v2.getUnit() != v3.getUnit())
2548
_EXPR_THROW("Units must be equal.",expr);
2550
unit = v1.getUnit();
2553
if (v1.isDimensionlessOrUnit(Unit::Length) && v2.isDimensionlessOrUnit(Unit::Length) && v3.isDimensionlessOrUnit(Unit::Length))
2555
_EXPR_THROW("Translation units must be a length or dimensionless.", expr);
2557
_EXPR_THROW("Unknown function: " << f,0);
2560
/* Compute result */
2563
output = acos(value);
2566
output = asin(value);
2569
output = atan(value);
2572
output = fabs(value);
2575
output = exp(value);
2578
output = log(value);
2581
output = log(value) / log(10.0);
2584
output = sin(value);
2587
output = sinh(value);
2590
output = tan(value);
2593
output = tanh(value);
2596
output = sqrt(value);
2599
output = cbrt(value);
2602
output = cos(value);
2605
output = cosh(value);
2608
output = fmod(value, v2.getValue());
2612
output = atan2(value, v2.getValue());
2616
output = pow(value, v2.getValue());
2620
output = sqrt(pow(v1.getValue(), 2) + pow(v2.getValue(), 2) + (!e3.isNone() ? pow(v3.getValue(), 2) : 0));
2624
output = sqrt(pow(v1.getValue(), 2) - pow(v2.getValue(), 2) - (!e3.isNone() ? pow(v3.getValue(), 2) : 0));
2628
output = boost::math::round(value);
2631
output = boost::math::trunc(value);
2634
output = ceil(value);
2637
output = floor(value);
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)),
2646
return translationMatrix(v1.getValue(), v2.getValue(), v3.getValue());
2648
_EXPR_THROW("Unknown function: " << f,0);
2651
return Py::asObject(new QuantityPy(new Quantity(scaler * output, unit)));
2654
Py::Object FunctionExpression::_getPyValue() const {
2655
return evaluate(this,f,args);
2659
* Try to simplify the expression, i.e calculate all constant expressions.
2661
* @returns A simplified expression.
2664
Expression *FunctionExpression::simplify() const
2666
size_t numerics = 0;
2667
std::vector<Expression*> a;
2669
// Try to simplify each argument to function
2670
for (auto it : args) {
2671
Expression * v = it->simplify();
2673
if (freecad_dynamic_cast<NumberExpression>(v))
2678
if (numerics == args.size()) {
2679
// All constants, then evaluation must also be constant
2682
for (auto it : args)
2688
return new FunctionExpression(owner, f, std::string(fname), a);
2692
* Create a string representation of the expression.
2694
* @returns A string representing the expression.
2697
void FunctionExpression::_toString(std::ostream &ss, bool persistent,int) const
2701
ss << "abs("; break;;
2703
ss << "acos("; break;;
2705
ss << "asin("; break;;
2707
ss << "atan("; break;;
2709
ss << "atan2("; break;;
2711
ss << "cath("; break;;
2713
ss << "cbrt("; break;;
2715
ss << "ceil("; break;;
2717
ss << "cos("; break;;
2719
ss << "cosh("; break;;
2721
ss << "exp("; break;;
2723
ss << "floor("; break;;
2725
ss << "hypot("; break;;
2727
ss << "log("; break;;
2729
ss << "log10("; break;;
2731
ss << "mod("; break;;
2733
ss << "pow("; break;;
2735
ss << "round("; break;;
2737
ss << "sin("; break;;
2739
ss << "sinh("; break;;
2741
ss << "sqrt("; break;;
2743
ss << "tan("; break;;
2745
ss << "tanh("; break;;
2747
ss << "trunc("; break;;
2749
ss << "vangle("; break;;
2751
ss << "vcross("; break;;
2753
ss << "vdot("; break;;
2755
ss << "vlinedist("; break;;
2757
ss << "vlinesegdist("; break;;
2759
ss << "vlineproj("; break;;
2761
ss << "vnormalize("; break;;
2763
ss << "vplanedist("; break;;
2765
ss << "vplaneproj("; break;;
2767
ss << "vscale("; break;;
2769
ss << "vscalex("; break;;
2771
ss << "vscaley("; break;;
2773
ss << "vscalez("; break;;
2775
ss << "minvert("; break;;
2777
ss << "mrotate("; break;;
2779
ss << "mrotatex("; break;;
2781
ss << "mrotatey("; break;;
2783
ss << "mrotatez("; break;;
2785
ss << "mscale("; break;;
2787
ss << "mtranslate("; break;;
2789
ss << "create("; break;;
2791
ss << "list("; break;;
2793
ss << "matrix("; break;;
2795
ss << "placement("; break;;
2797
ss << "rotation("; break;;
2799
ss << "rotationx("; break;;
2801
ss << "rotationy("; break;;
2803
ss << "rotationz("; break;;
2805
ss << "str("; break;;
2807
ss << "parsequant("; break;;
2809
ss << "translationm("; break;;
2811
ss << "tuple("; break;;
2813
ss << "vector("; break;;
2815
ss << "hiddenref("; break;;
2817
ss << "href("; break;;
2819
ss << "average("; break;;
2821
ss << "count("; break;;
2823
ss << "max("; break;;
2825
ss << "min("; break;;
2827
ss << "stddev("; break;;
2829
ss << "sum("; break;;
2831
ss << fname << "("; break;;
2833
for (size_t i = 0; i < args.size(); ++i) {
2834
ss << args[i]->toString(persistent);
2835
if (i != args.size() - 1)
2842
* Create a copy of the expression.
2844
* @returns A deep copy of the expression.
2847
Expression *FunctionExpression::_copy() const
2849
std::vector<Expression*>::const_iterator i = args.begin();
2850
std::vector<Expression*> a;
2852
while (i != args.end()) {
2853
a.push_back((*i)->copy());
2856
return new FunctionExpression(owner, f, std::string(fname), a);
2859
void FunctionExpression::_visit(ExpressionVisitor &v)
2861
std::vector<Expression*>::const_iterator i = args.begin();
2863
HiddenReference ref(f == HIDDENREF || f == HREF);
2864
while (i != args.end()) {
2871
// VariableExpression class
2874
TYPESYSTEM_SOURCE(App::VariableExpression, App::UnitExpression)
2876
VariableExpression::VariableExpression(const DocumentObject *_owner, const ObjectIdentifier& _var)
2877
: UnitExpression(_owner)
2882
VariableExpression::~VariableExpression() = default;
2885
* Determine if the expression is touched or not, i.e whether the Property object it
2886
* refers to is touched().
2888
* @returns True if the Property object is touched, false if not.
2891
bool VariableExpression::isTouched() const
2893
return var.isTouched();
2897
* Find the property this expression referse to.
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.
2903
* If something fails, an exception is thrown.
2905
* @returns The Property object if it is derived from either PropertyInteger, PropertyFloat, or PropertyString.
2908
const Property * VariableExpression::getProperty() const
2910
const Property * prop = var.getProperty();
2915
throw Expression::Exception(var.resolveErrorString().c_str());
2918
void VariableExpression::addComponent(Component *c) {
2920
if(!components.empty())
2922
if(!c->e1 && !c->e2) {
2926
long l1=0,l2=0,l3=1;
2928
auto n3 = freecad_dynamic_cast<NumberExpression>(c->e3);
2929
if(!n3 || !essentiallyEqual(n3->getValue(),(double)l3))
2933
auto n1 = freecad_dynamic_cast<NumberExpression>(c->e1);
2937
auto s = freecad_dynamic_cast<StringExpression>(c->e1);
2940
var << ObjectIdentifier::MapComponent(
2941
ObjectIdentifier::String(s->getText(),true));
2944
if(!essentiallyInteger(n1->getValue(),l1))
2946
if(!c->comp.isRange()) {
2947
var << ObjectIdentifier::ArrayComponent(l1);
2950
var << ObjectIdentifier::RangeComponent(l1,l2,l3);
2954
auto n2 = freecad_dynamic_cast<NumberExpression>(c->e2);
2955
if(n2 && essentiallyInteger(n2->getValue(),l2)) {
2956
var << ObjectIdentifier::RangeComponent(l1,l2,l3);
2961
Expression::addComponent(c);
2964
bool VariableExpression::_isIndexable() const {
2968
Py::Object VariableExpression::_getPyValue() const {
2969
return var.getPyValue(true);
2972
void VariableExpression::_toString(std::ostream &ss, bool persistent,int) const {
2974
ss << var.toPersistentString();
2976
ss << var.toString();
2980
* Simplify the expression. Simplification of VariableExpression objects is
2981
* not possible (if it is instantiated it would be an evaluation instead).
2983
* @returns A copy of the expression.
2986
Expression *VariableExpression::simplify() const
2992
* Return a copy of the expression.
2995
Expression *VariableExpression::_copy() const
2997
return new VariableExpression(owner, var);
3000
void VariableExpression::_getIdentifiers(std::map<App::ObjectIdentifier,bool> &deps) const
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;
3008
bool VariableExpression::_relabeledDocument(const std::string &oldName,
3009
const std::string &newName, ExpressionVisitor &v)
3011
return var.relabeledDocument(v, oldName, newName);
3014
bool VariableExpression::_adjustLinks(
3015
const std::set<App::DocumentObject *> &inList, ExpressionVisitor &v)
3017
return var.adjustLinks(v,inList);
3020
void VariableExpression::_importSubNames(const ObjectIdentifier::SubNameMap &subNameMap)
3022
var.importSubNames(subNameMap);
3025
void VariableExpression::_updateLabelReference(
3026
App::DocumentObject *obj, const std::string &ref, const char *newLabel)
3028
var.updateLabelReference(obj,ref,newLabel);
3031
bool VariableExpression::_updateElementReference(
3032
App::DocumentObject *feature, bool reverse, ExpressionVisitor &v)
3034
return var.updateElementReference(v,feature,reverse);
3037
bool VariableExpression::_renameObjectIdentifier(
3038
const std::map<ObjectIdentifier, ObjectIdentifier>& paths,
3039
const ObjectIdentifier& path,
3040
ExpressionVisitor& visitor)
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);
3055
if (originalHasDocumentObjectName) {
3056
var.setDocumentObjectName(std::move(originalDocumentObjectName),
3058
originalSubObjectName);
3065
void VariableExpression::_collectReplacement(
3066
std::map<ObjectIdentifier,ObjectIdentifier> &paths,
3067
const App::DocumentObject *parent,
3068
App::DocumentObject *oldObj,
3069
App::DocumentObject *newObj) const
3071
ObjectIdentifier path;
3072
if(var.replaceObject(path,parent,oldObj,newObj))
3073
paths[var.canonicalPath()] = std::move(path);
3076
void VariableExpression::_moveCells(const CellAddress &address,
3077
int rowCount, int colCount, ExpressionVisitor &v)
3079
if(var.hasDocumentObjectName(true))
3083
const auto &comp = var.getPropertyComponent(0,&idx);
3084
CellAddress addr = stringToAddress(comp.getName().c_str(),true);
3088
int thisRow = addr.row();
3089
int thisCol = addr.col();
3090
if (thisRow >= address.row() || thisCol >= address.col()) {
3092
addr.setRow(thisRow + rowCount);
3093
addr.setCol(thisCol + colCount);
3094
var.setComponent(idx,ObjectIdentifier::SimpleComponent(addr.toString()));
3098
void VariableExpression::_offsetCells(int rowOffset, int colOffset, ExpressionVisitor &v) {
3099
if(var.hasDocumentObjectName(true))
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()))
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 << ')');
3118
var.setComponent(idx,ObjectIdentifier::SimpleComponent(addr.toString()));
3122
void VariableExpression::setPath(const ObjectIdentifier &path)
3128
// PyObjectExpression class
3131
TYPESYSTEM_SOURCE(App::PyObjectExpression, App::Expression)
3133
PyObjectExpression::~PyObjectExpression() {
3135
Base::PyGILStateLocker lock;
3136
Py::_XDECREF(pyObj);
3140
Py::Object PyObjectExpression::_getPyValue() const {
3142
return Py::Object();
3143
return Py::Object(pyObj);
3146
void PyObjectExpression::setPyValue(Py::Object obj) {
3147
Py::_XDECREF(pyObj);
3149
Py::_XINCREF(pyObj);
3152
void PyObjectExpression::setPyValue(PyObject *obj, bool owned) {
3155
Py::_XDECREF(pyObj);
3158
Py::_XINCREF(pyObj);
3161
void PyObjectExpression::_toString(std::ostream &ss, bool,int) const
3166
Base::PyGILStateLocker lock;
3167
ss << Py::Object(pyObj).as_string();
3171
Expression* PyObjectExpression::_copy() const
3173
return new PyObjectExpression(owner,pyObj,false);
3177
// StringExpression class
3180
TYPESYSTEM_SOURCE(App::StringExpression, App::Expression)
3182
StringExpression::StringExpression(const DocumentObject *_owner, const std::string &_text)
3183
: Expression(_owner)
3188
StringExpression::~StringExpression() {
3190
Base::PyGILStateLocker lock;
3191
Py::_XDECREF(cache);
3196
* Simplify the expression. For strings, this is a simple copy of the object.
3199
Expression *StringExpression::simplify() const
3204
void StringExpression::_toString(std::ostream &ss, bool,int) const
3210
* Return a copy of the expression.
3213
Expression *StringExpression::_copy() const
3215
return new StringExpression(owner, text);
3218
Py::Object StringExpression::_getPyValue() const {
3219
return Py::String(text);
3222
TYPESYSTEM_SOURCE(App::ConditionalExpression, App::Expression)
3224
ConditionalExpression::ConditionalExpression(const DocumentObject *_owner, Expression *_condition, Expression *_trueExpr, Expression *_falseExpr)
3225
: Expression(_owner)
3226
, condition(_condition)
3227
, trueExpr(_trueExpr)
3228
, falseExpr(_falseExpr)
3232
ConditionalExpression::~ConditionalExpression()
3239
bool ConditionalExpression::isTouched() const
3241
return condition->isTouched() || trueExpr->isTouched() || falseExpr->isTouched();
3244
Py::Object ConditionalExpression::_getPyValue() const {
3245
if(condition->getPyValue().isTrue())
3246
return trueExpr->getPyValue();
3248
return falseExpr->getPyValue();
3251
Expression *ConditionalExpression::simplify() const
3253
std::unique_ptr<Expression> e(condition->simplify());
3254
NumberExpression * v = freecad_dynamic_cast<NumberExpression>(e.get());
3257
return new ConditionalExpression(owner, condition->simplify(), trueExpr->simplify(), falseExpr->simplify());
3259
if (fabs(v->getValue()) > 0.5)
3260
return trueExpr->simplify();
3262
return falseExpr->simplify();
3266
void ConditionalExpression::_toString(std::ostream &ss, bool persistent,int) const
3268
condition->toString(ss,persistent);
3270
if (trueExpr->priority() <= priority()) {
3272
trueExpr->toString(ss,persistent);
3275
trueExpr->toString(ss,persistent);
3279
if (falseExpr->priority() <= priority()) {
3281
falseExpr->toString(ss,persistent);
3284
falseExpr->toString(ss,persistent);
3287
Expression *ConditionalExpression::_copy() const
3289
return new ConditionalExpression(owner, condition->copy(), trueExpr->copy(), falseExpr->copy());
3292
int ConditionalExpression::priority() const
3297
void ConditionalExpression::_visit(ExpressionVisitor &v)
3299
condition->visit(v);
3301
falseExpr->visit(v);
3304
TYPESYSTEM_SOURCE(App::ConstantExpression, App::NumberExpression)
3306
ConstantExpression::ConstantExpression(const DocumentObject *_owner,
3307
const char *_name, const Quantity & _quantity)
3308
: NumberExpression(_owner, _quantity)
3313
Expression *ConstantExpression::_copy() const
3315
return new ConstantExpression(owner, name, getQuantity());
3318
void ConstantExpression::_toString(std::ostream &ss, bool,int) const
3323
Py::Object ConstantExpression::_getPyValue() const {
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());
3332
return NumberExpression::_getPyValue();
3334
return Py::Object(cache);
3337
bool ConstantExpression::isNumber() const {
3338
return strcmp(name,"None")
3339
&& strcmp(name,"True")
3340
&& strcmp(name, "False");
3343
TYPESYSTEM_SOURCE(App::RangeExpression, App::Expression)
3345
RangeExpression::RangeExpression(const DocumentObject *_owner, const std::string &begin, const std::string &end)
3346
: Expression(_owner), begin(begin), end(end)
3350
bool RangeExpression::isTouched() const
3352
Range i(getRange());
3355
Property * prop = owner->getPropertyByName(i.address().c_str());
3357
if (prop && prop->isTouched())
3364
Py::Object RangeExpression::_getPyValue() const {
3366
Range range(getRange());
3368
Property * p = owner->getPropertyByName(range.address().c_str());
3370
list.append(Py::asObject(p->getPyObject()));
3371
} while (range.next());
3375
void RangeExpression::_toString(std::ostream &ss, bool,int) const
3377
ss << begin << ":" << end;
3380
Expression *RangeExpression::_copy() const
3382
return new RangeExpression(owner, begin, end);
3385
Expression *RangeExpression::simplify() const
3390
void RangeExpression::_getIdentifiers(std::map<App::ObjectIdentifier,bool> &deps) const
3392
bool hidden = HiddenReference::isHidden();
3396
Range i(getRange());
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;
3406
Range RangeExpression::getRange() const
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);
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));
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);
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);
3441
return Range(c1,c2);
3444
bool RangeExpression::_renameObjectIdentifier(
3445
const std::map<ObjectIdentifier,ObjectIdentifier> &paths,
3446
const ObjectIdentifier &path, ExpressionVisitor &v)
3449
bool touched =false;
3450
auto it = paths.find(ObjectIdentifier(owner,begin));
3451
if (it != paths.end()) {
3453
begin = it->second.getPropertyName();
3456
it = paths.find(ObjectIdentifier(owner,end));
3457
if (it != paths.end()) {
3459
end = it->second.getPropertyName();
3465
void RangeExpression::_moveCells(const CellAddress &address,
3466
int rowCount, int colCount, ExpressionVisitor &v)
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()) {
3474
addr.setRow(thisRow+rowCount);
3475
addr.setCol(thisCol+colCount);
3476
begin = addr.toString();
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()) {
3485
addr.setRow(thisRow + rowCount);
3486
addr.setCol(thisCol + colCount);
3487
end = addr.toString();
3492
void RangeExpression::_offsetCells(int rowOffset, int colOffset, ExpressionVisitor &v)
3494
CellAddress addr = stringToAddress(begin.c_str(),true);
3495
if(addr.isValid() && (!addr.isAbsoluteRow() || !addr.isAbsoluteCol())) {
3497
if(!addr.isAbsoluteRow())
3498
addr.setRow(addr.row()+rowOffset);
3499
if(!addr.isAbsoluteCol())
3500
addr.setCol(addr.col()+colOffset);
3501
begin = addr.toString();
3503
addr = stringToAddress(end.c_str(),true);
3504
if(addr.isValid() && (!addr.isAbsoluteRow() || !addr.isAbsoluteCol())) {
3506
if(!addr.isAbsoluteRow())
3507
addr.setRow(addr.row()+rowOffset);
3508
if(!addr.isAbsoluteCol())
3509
addr.setCol(addr.col()+colOffset);
3510
end = addr.toString();
3515
////////////////////////////////////////////////////////////////////////////////////
3517
static Base::XMLReader *_Reader = nullptr;
3518
ExpressionParser::ExpressionImporter::ExpressionImporter(Base::XMLReader &reader) {
3523
ExpressionParser::ExpressionImporter::~ExpressionImporter() {
3528
Base::XMLReader *ExpressionParser::ExpressionImporter::reader() {
3534
namespace ExpressionParser {
3536
bool isModuleImported(PyObject *module) {
3542
* Error function for parser. Throws a generic Base::Exception with the parser error.
3545
void ExpressionParser_yyerror(const char *errorinfo)
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)
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 !='.')
3564
// check buffer overflow
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.");
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;
3589
// show the parser the lexer method
3590
#define yylex ExpressionParserlex
3591
int ExpressionParserlex();
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"
3603
// Parser, defined in ExpressionParser.y
3605
#include "ExpressionParser.tab.c"
3607
#ifndef DOXYGEN_SHOULD_SKIP_THIS
3608
// Scanner, defined in ExpressionParser.l
3609
#include "lex.ExpressionParser.c"
3610
#endif // DOXYGEN_SHOULD_SKIP_THIS
3612
#if defined(__clang__)
3613
# pragma clang diagnostic pop
3614
#elif defined (__GNUC__)
3615
# pragma GCC diagnostic pop
3619
# define strdup _strdup
3622
static void initParser(const App::DocumentObject *owner)
3624
static bool has_registered_functions = false;
3626
using namespace App::ExpressionParser;
3628
ScanResult = nullptr;
3629
App::ExpressionParser::DocumentObject = owner;
3630
labels = std::stack<std::string>();
3632
unitExpression = valueExpression = false;
3634
if (!has_registered_functions) {
3635
registered_functions["abs"] = FunctionExpression::ABS;
3636
registered_functions["acos"] = FunctionExpression::ACOS;
3637
registered_functions["asin"] = FunctionExpression::ASIN;
3638
registered_functions["atan"] = FunctionExpression::ATAN;
3639
registered_functions["atan2"] = FunctionExpression::ATAN2;
3640
registered_functions["cath"] = FunctionExpression::CATH;
3641
registered_functions["cbrt"] = FunctionExpression::CBRT;
3642
registered_functions["ceil"] = FunctionExpression::CEIL;
3643
registered_functions["cos"] = FunctionExpression::COS;
3644
registered_functions["cosh"] = FunctionExpression::COSH;
3645
registered_functions["exp"] = FunctionExpression::EXP;
3646
registered_functions["floor"] = FunctionExpression::FLOOR;
3647
registered_functions["hypot"] = FunctionExpression::HYPOT;
3648
registered_functions["log"] = FunctionExpression::LOG;
3649
registered_functions["log10"] = FunctionExpression::LOG10;
3650
registered_functions["mod"] = FunctionExpression::MOD;
3651
registered_functions["pow"] = FunctionExpression::POW;
3652
registered_functions["round"] = FunctionExpression::ROUND;
3653
registered_functions["sin"] = FunctionExpression::SIN;
3654
registered_functions["sinh"] = FunctionExpression::SINH;
3655
registered_functions["sqrt"] = FunctionExpression::SQRT;
3656
registered_functions["tan"] = FunctionExpression::TAN;
3657
registered_functions["tanh"] = FunctionExpression::TANH;
3658
registered_functions["trunc"] = FunctionExpression::TRUNC;
3659
registered_functions["vangle"] = FunctionExpression::VANGLE;
3660
registered_functions["vcross"] = FunctionExpression::VCROSS;
3661
registered_functions["vdot"] = FunctionExpression::VDOT;
3662
registered_functions["vlinedist"] = FunctionExpression::VLINEDIST;
3663
registered_functions["vlinesegdist"] = FunctionExpression::VLINESEGDIST;
3664
registered_functions["vlineproj"] = FunctionExpression::VLINEPROJ;
3665
registered_functions["vnormalize"] = FunctionExpression::VNORMALIZE;
3666
registered_functions["vplanedist"] = FunctionExpression::VPLANEDIST;
3667
registered_functions["vplaneproj"] = FunctionExpression::VPLANEPROJ;
3668
registered_functions["vscale"] = FunctionExpression::VSCALE;
3669
registered_functions["vscalex"] = FunctionExpression::VSCALEX;
3670
registered_functions["vscaley"] = FunctionExpression::VSCALEY;
3671
registered_functions["vscalez"] = FunctionExpression::VSCALEZ;
3673
registered_functions["minvert"] = FunctionExpression::MINVERT;
3674
registered_functions["mrotate"] = FunctionExpression::MROTATE;
3675
registered_functions["mrotatex"] = FunctionExpression::MROTATEX;
3676
registered_functions["mrotatey"] = FunctionExpression::MROTATEY;
3677
registered_functions["mrotatez"] = FunctionExpression::MROTATEZ;
3678
registered_functions["mscale"] = FunctionExpression::MSCALE;
3679
registered_functions["mtranslate"] = FunctionExpression::MTRANSLATE;
3681
registered_functions["create"] = FunctionExpression::CREATE;
3682
registered_functions["list"] = FunctionExpression::LIST;
3683
registered_functions["matrix"] = FunctionExpression::MATRIX;
3684
registered_functions["placement"] = FunctionExpression::PLACEMENT;
3685
registered_functions["rotation"] = FunctionExpression::ROTATION;
3686
registered_functions["rotationx"] = FunctionExpression::ROTATIONX;
3687
registered_functions["rotationy"] = FunctionExpression::ROTATIONY;
3688
registered_functions["rotationz"] = FunctionExpression::ROTATIONZ;
3689
registered_functions["str"] = FunctionExpression::STR;
3690
registered_functions["parsequant"] = FunctionExpression::PARSEQUANT;
3691
registered_functions["translationm"] = FunctionExpression::TRANSLATIONM;
3692
registered_functions["tuple"] = FunctionExpression::TUPLE;
3693
registered_functions["vector"] = FunctionExpression::VECTOR;
3695
registered_functions["hiddenref"] = FunctionExpression::HIDDENREF;
3696
registered_functions["href"] = FunctionExpression::HREF;
3699
registered_functions["average"] = FunctionExpression::AVERAGE;
3700
registered_functions["count"] = FunctionExpression::COUNT;
3701
registered_functions["max"] = FunctionExpression::MAX;
3702
registered_functions["min"] = FunctionExpression::MIN;
3703
registered_functions["stddev"] = FunctionExpression::STDDEV;
3704
registered_functions["sum"] = FunctionExpression::SUM;
3706
has_registered_functions = true;
3710
std::vector<std::tuple<int, int, std::string> > tokenize(const std::string &str)
3712
ExpressionParser::YY_BUFFER_STATE buf = ExpressionParser_scan_string(str.c_str());
3713
std::vector<std::tuple<int, int, std::string> > result;
3718
while ( (token = ExpressionParserlex()) != 0)
3719
result.emplace_back(token, ExpressionParser::last_column, yytext);
3722
// Ignore all exceptions
3725
ExpressionParser_delete_buffer(buf);
3734
* Parse the expression given by \a buffer, and use \a owner as the owner of the
3735
* returned expression. If the parser fails for some reason, and exception is thrown.
3737
* @param owner The DocumentObject that will own the expression.
3738
* @param buffer The string buffer to parse.
3740
* @returns A pointer to an expression.
3744
Expression * App::ExpressionParser::parse(const App::DocumentObject *owner, const char* buffer)
3746
// parse from buffer
3747
ExpressionParser::YY_BUFFER_STATE my_string_buffer = ExpressionParser::ExpressionParser_scan_string (buffer);
3752
int result = ExpressionParser::ExpressionParser_yyparse ();
3754
// free the scan buffer
3755
ExpressionParser::ExpressionParser_delete_buffer (my_string_buffer);
3758
throw ParserError("Failed to parse expression.");
3761
throw ParserError("Unknown error in expression");
3763
if (valueExpression)
3767
throw Expression::Exception("Expression can not evaluate to a value.");
3771
UnitExpression * ExpressionParser::parseUnit(const App::DocumentObject *owner, const char* buffer)
3773
// parse from buffer
3774
ExpressionParser::YY_BUFFER_STATE my_string_buffer = ExpressionParser::ExpressionParser_scan_string (buffer);
3779
int result = ExpressionParser::ExpressionParser_yyparse ();
3781
// free the scan buffer
3782
ExpressionParser::ExpressionParser_delete_buffer (my_string_buffer);
3785
throw ParserError("Failed to parse expression.");
3788
throw ParserError("Unknown error in expression");
3790
// Simplify expression
3791
Expression * simplified = ScanResult->simplify();
3793
if (!unitExpression) {
3794
OperatorExpression * fraction = freecad_dynamic_cast<OperatorExpression>(ScanResult);
3796
if (fraction && fraction->getOperator() == OperatorExpression::DIV) {
3797
NumberExpression * nom = freecad_dynamic_cast<NumberExpression>(fraction->getLeft());
3798
UnitExpression * denom = freecad_dynamic_cast<UnitExpression>(fraction->getRight());
3800
// If not initially a unit expression, but value is equal to 1, it means the expression is something like 1/unit
3801
if (denom && nom && essentiallyEqual(nom->getValue(), 1.0))
3802
unitExpression = true;
3807
if (unitExpression) {
3808
NumberExpression * num = freecad_dynamic_cast<NumberExpression>(simplified);
3811
simplified = new UnitExpression(num->getOwner(), num->getQuantity());
3814
return freecad_dynamic_cast<UnitExpression>(simplified);
3818
throw Expression::Exception("Expression is not a unit.");
3823
std::tuple<int, int> getTokenAndStatus(const std::string & str)
3825
ExpressionParser::YY_BUFFER_STATE buf = ExpressionParser::ExpressionParser_scan_string(str.c_str());
3826
int token = ExpressionParser::ExpressionParserlex();
3827
int status = ExpressionParser::ExpressionParserlex();
3828
ExpressionParser::ExpressionParser_delete_buffer(buf);
3830
return std::make_tuple(token, status);
3834
bool ExpressionParser::isTokenAnIndentifier(const std::string & str)
3836
int token{}, status{};
3837
std::tie(token, status) = getTokenAndStatus(str);
3838
return (status == 0 && (token == IDENTIFIER || token == CELLADDRESS));
3841
bool ExpressionParser::isTokenAUnit(const std::string & str)
3843
int token{}, status{};
3844
std::tie(token, status) = getTokenAndStatus(str);
3845
return (status == 0 && token == UNIT);
3848
#if defined(__clang__)
3849
# pragma clang diagnostic pop