PropertyExpressionEngine: convert to link type property

PropertyExpressionEngine is changed to derived from a new class
PropertyExpressionContainer, which is in turn derives from
PropertyXLinkContainer. This makes PropertyExpressionEngine a link type
property that is capable of external linking. It now uses the unified
link property APIs for dependency management and tracking of object
life time, re-labeling, etc.

ObjectIdentifier is modified to support sub-object reference, but is
not exposed to end-user, because expression syntax is kept mostly
unchanged, which will be submitted in future PR. There is, however,
one small change in expression syntax (ExpressionParser.y) to introduce
local property reference to avoid ambiguity mentioned in
FreeCAD/FreeCAD#1619

Modified Expression/ExpressionModifier interface to support various link
property API for link modification.
This commit is contained in:
Zheng, Lei
2019-08-17 14:52:09 +02:00
committed by wmayer
parent e85bf9cd0e
commit 93e60caa35
25 changed files with 3895 additions and 1645 deletions
+1
View File
@@ -1671,6 +1671,7 @@ void Application::initTypes(void)
App ::FunctionExpression ::init();
App ::BooleanExpression ::init();
App ::RangeExpression ::init();
App ::PyObjectExpression ::init();
// register transaction type
new App::TransactionProducer<TransactionDocumentObject>
+9 -9
View File
@@ -372,7 +372,7 @@ void Document::exportGraphviz(std::ostream& out) const
void addExpressionSubgraphIfNeeded(DocumentObject * obj, bool CSsubgraphs) {
boost::unordered_map<const App::ObjectIdentifier, const PropertyExpressionEngine::ExpressionInfo> expressions = obj->ExpressionEngine.getExpressions();
auto expressions = obj->ExpressionEngine.getExpressions();
if (!expressions.empty()) {
@@ -394,11 +394,11 @@ void Document::exportGraphviz(std::ostream& out) const
}
// Create subgraphs for all documentobjects that it depends on; it will depend on some property there
boost::unordered_map<const App::ObjectIdentifier, const PropertyExpressionEngine::ExpressionInfo>::const_iterator i = expressions.begin();
auto i = expressions.begin();
while (i != expressions.end()) {
std::set<ObjectIdentifier> deps;
i->second.expression->getDeps(deps);
i->second->getIdentifiers(deps);
std::set<ObjectIdentifier>::const_iterator j = deps.begin();
while (j != deps.end()) {
@@ -486,8 +486,8 @@ void Document::exportGraphviz(std::ostream& out) const
}
// Add expressions and its dependencies
boost::unordered_map<const App::ObjectIdentifier, const PropertyExpressionEngine::ExpressionInfo> expressions = docObj->ExpressionEngine.getExpressions();
boost::unordered_map<const App::ObjectIdentifier, const PropertyExpressionEngine::ExpressionInfo>::const_iterator i = expressions.begin();
auto expressions = docObj->ExpressionEngine.getExpressions();
auto i = expressions.begin();
// Add nodes for each property that has an expression attached to it
while (i != expressions.end()) {
@@ -507,7 +507,7 @@ void Document::exportGraphviz(std::ostream& out) const
// Get dependencies
std::set<ObjectIdentifier> deps;
i->second.expression->getDeps(deps);
i->second->getIdentifiers(deps);
// Create subgraphs for all documentobjects that it depends on; it will depend on some property there
std::set<ObjectIdentifier>::const_iterator j = deps.begin();
@@ -648,12 +648,12 @@ void Document::exportGraphviz(std::ostream& out) const
const DocumentObject * docObj = *j;
// Add expressions and its dependencies
boost::unordered_map<const App::ObjectIdentifier, const PropertyExpressionEngine::ExpressionInfo> expressions = docObj->ExpressionEngine.getExpressions();
boost::unordered_map<const App::ObjectIdentifier, const PropertyExpressionEngine::ExpressionInfo>::const_iterator i = expressions.begin();
auto expressions = docObj->ExpressionEngine.getExpressions();
auto i = expressions.begin();
while (i != expressions.end()) {
std::set<ObjectIdentifier> deps;
i->second.expression->getDeps(deps);
i->second->getIdentifiers(deps);
// Create subgraphs for all documentobjects that it depends on; it will depend on some property there
std::set<ObjectIdentifier>::const_iterator k = deps.begin();
+2 -44
View File
@@ -762,13 +762,11 @@ void DocumentObject::Save (Base::Writer &writer) const
* @brief Associate the expression \expr with the object identifier \a path in this document object.
* @param path Target object identifier for the result of the expression
* @param expr Expression tree
* @param comment Optional comment describing the expression
*/
void DocumentObject::setExpression(const ObjectIdentifier &path, boost::shared_ptr<Expression> expr, const char * comment)
void DocumentObject::setExpression(const ObjectIdentifier &path, boost::shared_ptr<Expression> expr)
{
ExpressionEngine.setValue(path, expr, comment);
connectRelabelSignals();
ExpressionEngine.setValue(path, expr);
}
/**
@@ -799,46 +797,6 @@ void DocumentObject::renameObjectIdentifiers(const std::map<ObjectIdentifier, Ob
ExpressionEngine.renameObjectIdentifiers(paths);
}
/**
* @brief Helper function that sets up a signal to track document object renames.
*/
void DocumentObject::connectRelabelSignals()
{
// Only keep signal if the ExpressionEngine has at least one expression
if (ExpressionEngine.numExpressions() > 0) {
// Not already connected?
if (!onRelabledObjectConnection.connected()) {
onRelabledObjectConnection = getDocument()->signalRelabelObject
.connect(boost::bind(&PropertyExpressionEngine::slotObjectRenamed,
&ExpressionEngine, _1));
}
// Connect to signalDeletedObject, to properly track deletion of other objects
// that might be referenced in an expression
if (!onDeletedObjectConnection.connected()) {
onDeletedObjectConnection = getDocument()->signalDeletedObject
.connect(boost::bind(&PropertyExpressionEngine::slotObjectDeleted,
&ExpressionEngine, _1));
}
try {
// Crude method to resolve all expression dependencies
ExpressionEngine.execute();
}
catch (...) {
// Ignore any error
}
}
else {
// Disconnect signals; nothing to track now
onRelabledObjectConnection.disconnect();
onRelabledDocumentConnection.disconnect();
onDeletedObjectConnection.disconnect();
}
}
void DocumentObject::onDocumentRestored()
{
//call all extensions
+1 -8
View File
@@ -351,14 +351,12 @@ public:
/* Expression support */
virtual void setExpression(const ObjectIdentifier & path, boost::shared_ptr<App::Expression> expr, const char *comment = 0);
virtual void setExpression(const ObjectIdentifier & path, boost::shared_ptr<App::Expression> expr);
virtual const PropertyExpressionEngine::ExpressionInfo getExpression(const ObjectIdentifier &path) const;
virtual void renameObjectIdentifiers(const std::map<App::ObjectIdentifier, App::ObjectIdentifier> & paths);
virtual void connectRelabelSignals();
const std::string & getOldLabel() const { return oldLabel; }
const char *getViewProviderNameStored() const {
@@ -531,11 +529,6 @@ protected: // attributes
/// pointer to the document this object belongs to
App::Document* _pDoc;
// Connections to track relabeling of document and document objects
boost::signals2::scoped_connection onRelabledDocumentConnection;
boost::signals2::scoped_connection onRelabledObjectConnection;
boost::signals2::scoped_connection onDeletedObjectConnection;
/// Old label; used for renaming expressions
std::string oldLabel;
+13
View File
@@ -176,6 +176,19 @@ non-object sub-element name if any.
</UserDocu>
</Documentation>
</Methode>
<Methode Name="resolveSubElement" Const="true">
<Documentation>
<UserDocu>
resolveSubElement(subname,append,type) -- resolve both new and old style sub element
subname: subname reference contianing object hierarchy
append: Whether to append object hierarchy prefix inside subname to returned element name
type: 0: normal, 1: for import, 2: for export
Return tuple(obj,newElementName,oldElementName)
</UserDocu>
</Documentation>
</Methode>
<Methode Name="adjustRelativeLinks">
<Documentation>
<UserDocu>adjustRelativeLinks(parent,recursive=True) -- auto correct potential cyclic dependencies</UserDocu>
+30 -3
View File
@@ -27,6 +27,7 @@
#include "DocumentObject.h"
#include "Document.h"
#include "Expression.h"
#include "GeoFeature.h"
#include "GroupExtension.h"
#include "GeoFeatureGroupExtension.h"
@@ -327,9 +328,11 @@ PyObject* DocumentObjectPy::setExpression(PyObject * args)
else if (PyString_Check(expr)) {
const char * exprStr = PyString_AsString(expr);
#endif
boost::shared_ptr<Expression> shared_expr(ExpressionParser::parse(getDocumentObjectPtr(), exprStr));
boost::shared_ptr<Expression> shared_expr(Expression::parse(getDocumentObjectPtr(), exprStr));
if(shared_expr && comment)
shared_expr->comment = comment;
getDocumentObjectPtr()->setExpression(p, shared_expr, comment);
getDocumentObjectPtr()->setExpression(p, shared_expr);
}
else if (PyUnicode_Check(expr)) {
#if PY_MAJOR_VERSION >= 3
@@ -341,7 +344,9 @@ PyObject* DocumentObjectPy::setExpression(PyObject * args)
Py_DECREF(unicode);
boost::shared_ptr<Expression> shared_expr(ExpressionParser::parse(getDocumentObjectPtr(), exprStr.c_str()));
getDocumentObjectPtr()->setExpression(p, shared_expr, comment);
if(shared_expr && comment)
shared_expr->comment = comment;
getDocumentObjectPtr()->setExpression(p, shared_expr);
}
else {
// utf-8 encoding failed
@@ -785,6 +790,28 @@ PyObject *DocumentObjectPy::resolve(PyObject *args)
Py_Return;
}
PyObject *DocumentObjectPy::resolveSubElement(PyObject *args)
{
const char *subname;
PyObject *append = Py_False;
int type = 0;
if (!PyArg_ParseTuple(args, "s|Oi",&subname,&append,&type))
return NULL; // NULL triggers exception
PY_TRY {
std::pair<std::string,std::string> elementName;
auto obj = GeoFeature::resolveElement(getDocumentObjectPtr(), subname,elementName,
PyObject_IsTrue(append),(GeoFeature::ElementNameType)type);
Py::Tuple ret(3);
ret.setItem(0,obj?Py::Object(obj->getPyObject(),true):Py::None());
ret.setItem(1,Py::String(elementName.first));
ret.setItem(2,Py::String(elementName.second));
return Py::new_reference_to(ret);
} PY_CATCH;
Py_Return;
}
Py::List DocumentObjectPy::getParents() const {
Py::List ret;
for(auto &v : getDocumentObjectPtr()->getParents())
+1131 -154
View File
File diff suppressed because it is too large Load Diff
+190 -58
View File
@@ -27,7 +27,7 @@
#include <boost/tuple/tuple.hpp>
#include <Base/Exception.h>
#include <Base/Unit.h>
#include <App/Property.h>
#include <App/PropertyLinks.h>
#include <App/ObjectIdentifier.h>
#include <Base/BaseClass.h>
#include <Base/Quantity.h>
@@ -41,29 +41,66 @@ class DocumentObject;
class Expression;
class Document;
typedef std::unique_ptr<Expression> ExpressionPtr;
AppExport bool isAnyEqual(const App::any &v1, const App::any &v2);
AppExport Base::Quantity anyToQuantity(const App::any &value, const char *errmsg = 0);
typedef std::map<App::DocumentObject*, std::map<std::string, std::vector<ObjectIdentifier> > > ExpressionDeps;
class AppExport ExpressionVisitor {
public:
virtual ~ExpressionVisitor() {}
virtual void visit(Expression * e) = 0;
virtual void visit(Expression &e) = 0;
virtual void aboutToChange() {}
virtual int changed() const { return 0;}
virtual void reset() {}
virtual App::PropertyLinkBase* getPropertyLink() {return 0;}
protected:
void getIdentifiers(Expression &e, std::set<App::ObjectIdentifier> &);
void getDeps(Expression &e, ExpressionDeps &);
void getDepObjects(Expression &e, std::set<App::DocumentObject*> &, std::vector<std::string> *);
bool adjustLinks(Expression &e, const std::set<App::DocumentObject*> &inList);
bool relabeledDocument(Expression &e, const std::string &oldName, const std::string &newName);
bool renameObjectIdentifier(Expression &e,
const std::map<ObjectIdentifier,ObjectIdentifier> &, const ObjectIdentifier &);
void collectReplacement(Expression &e, std::map<ObjectIdentifier,ObjectIdentifier> &,
const App::DocumentObject *parent, App::DocumentObject *oldObj, App::DocumentObject *newObj) const;
bool updateElementReference(Expression &e, App::DocumentObject *feature,bool reverse);
void importSubNames(Expression &e, const ObjectIdentifier::SubNameMap &subNameMap);
void updateLabelReference(Expression &e, App::DocumentObject *obj,
const std::string &ref, const char *newLabel);
void moveCells(Expression &e, const CellAddress &address, int rowCount, int colCount);
void offsetCells(Expression &e, int rowOffset, int colOffset);
};
template<class P> class ExpressionModifier : public ExpressionVisitor {
public:
ExpressionModifier(P & _prop)
: prop(_prop) { }
: prop(_prop)
, propLink(Base::freecad_dynamic_cast<App::PropertyLinkBase>(&prop))
, signaller(_prop,false)
, _changed(0)
{}
virtual ~ExpressionModifier() { }
void setExpressionChanged() {
if (!signaller)
signaller = boost::shared_ptr<typename AtomicPropertyChangeInterface<P>::AtomicPropertyChange>(AtomicPropertyChangeInterface<P>::getAtomicPropertyChange(prop));
virtual void aboutToChange() override{
++_changed;
signaller.aboutToChange();
}
bool getChanged() const { return signaller != 0; }
virtual int changed() const override { return _changed; }
virtual void reset() override {_changed = 0;}
virtual App::PropertyLinkBase* getPropertyLink() override {return propLink;}
protected:
P & prop;
boost::shared_ptr<typename AtomicPropertyChangeInterface<P>::AtomicPropertyChange> signaller;
App::PropertyLinkBase *propLink;
typename AtomicPropertyChangeInterface<P>::AtomicPropertyChange signaller;
int _changed;
};
/**
@@ -84,31 +121,78 @@ public:
virtual Expression * eval() const = 0;
virtual std::string toString() const = 0;
virtual std::string toString(bool persistent=false) const = 0;
static Expression * parse(const App::DocumentObject * owner, const std::string& buffer);
virtual Expression * copy() const = 0;
Expression * copy() const;
virtual int priority() const { return 0; }
virtual void getDeps(std::set<ObjectIdentifier> &/*props*/) const { }
void getIdentifiers(std::set<App::ObjectIdentifier> &) const;
std::set<App::ObjectIdentifier> getIdentifiers() const;
void getDeps(ExpressionDeps &deps) const;
ExpressionDeps getDeps() const;
std::set<App::DocumentObject*> getDepObjects(std::vector<std::string> *labels=0) const;
void getDepObjects(std::set<App::DocumentObject*> &, std::vector<std::string> *labels=0) const;
ExpressionPtr importSubNames(const std::map<std::string,std::string> &nameMap) const;
ExpressionPtr updateLabelReference(App::DocumentObject *obj,
const std::string &ref, const char *newLabel) const;
ExpressionPtr replaceObject(const App::DocumentObject *parent,
App::DocumentObject *oldObj, App::DocumentObject *newObj) const;
bool adjustLinks(const std::set<App::DocumentObject*> &inList);
virtual Expression * simplify() const = 0;
virtual void visit(ExpressionVisitor & v) { v.visit(this); }
void visit(ExpressionVisitor & v);
class Exception : public Base::Exception {
public:
Exception(const char *sMessage) : Base::Exception(sMessage) { }
};
const App::DocumentObject * getOwner() const { return owner; }
App::DocumentObject * getOwner() const { return owner; }
virtual boost::any getValueAsAny() const { static boost::any empty; return empty; }
bool isSame(const Expression &other) const;
friend ExpressionVisitor;
protected:
const App::DocumentObject * owner; /**< The document object used to access unqualified variables (i.e local scope) */
virtual Expression *_copy() const = 0;
virtual void _getDeps(ExpressionDeps &) const {}
virtual void _getDepObjects(std::set<App::DocumentObject*> &, std::vector<std::string> *) const {}
virtual void _getIdentifiers(std::set<App::ObjectIdentifier> &) const {}
virtual bool _adjustLinks(const std::set<App::DocumentObject*> &, ExpressionVisitor &) {return false;}
virtual bool _updateElementReference(App::DocumentObject *,bool,ExpressionVisitor &) {return false;}
virtual bool _relabeledDocument(const std::string &, const std::string &, ExpressionVisitor &) {return false;}
virtual void _importSubNames(const ObjectIdentifier::SubNameMap &) {}
virtual void _updateLabelReference(App::DocumentObject *, const std::string &, const char *) {}
virtual bool _renameObjectIdentifier(const std::map<ObjectIdentifier,ObjectIdentifier> &,
const ObjectIdentifier &, ExpressionVisitor &) {return false;}
virtual void _collectReplacement(std::map<ObjectIdentifier,ObjectIdentifier> &,
const App::DocumentObject *parent, App::DocumentObject *oldObj, App::DocumentObject *newObj) const
{
(void)parent;
(void)oldObj;
(void)newObj;
}
virtual void _moveCells(const CellAddress &, int, int, ExpressionVisitor &) {}
virtual void _offsetCells(int, int, ExpressionVisitor &) {}
virtual void _visit(ExpressionVisitor &) {}
protected:
App::DocumentObject * owner; /**< The document object used to access unqualified variables (i.e local scope) */
public:
std::string comment;
};
/**
@@ -125,9 +209,9 @@ public:
virtual Expression * simplify() const;
virtual std::string toString() const;
virtual std::string toString(bool persistent=false) const;
virtual Expression * copy() const;
virtual Expression * _copy() const;
virtual int priority() const;
@@ -163,13 +247,15 @@ public:
virtual Expression * simplify() const;
virtual Expression * copy() const;
virtual Expression * _copy() const;
virtual int priority() const;
void negate();
virtual std::string toString() const;
virtual std::string toString(bool persistent=false) const;
bool isInteger(long *v=0) const;
protected:
};
@@ -179,9 +265,9 @@ class AppExport ConstantExpression : public NumberExpression {
public:
ConstantExpression(const App::DocumentObject *_owner = 0, std::string _name = "", const Base::Quantity &_quantity = Base::Quantity());
virtual std::string toString() const;
virtual std::string toString(bool persistent=false) const;
virtual Expression * copy() const;
virtual Expression * _copy() const;
virtual int priority() const;
@@ -196,7 +282,7 @@ class AppExport BooleanExpression : public NumberExpression {
public:
BooleanExpression(const App::DocumentObject *_owner = 0, bool _value = false);
virtual Expression * copy() const;
virtual Expression * _copy() const;
};
@@ -236,15 +322,13 @@ public:
virtual Expression * simplify() const;
virtual std::string toString() const;
virtual std::string toString(bool persistent=false) const;
virtual Expression * copy() const;
virtual Expression * _copy() const;
virtual int priority() const;
virtual void getDeps(std::set<ObjectIdentifier> &props) const;
virtual void visit(ExpressionVisitor & v);
virtual void _visit(ExpressionVisitor & v);
Operator getOperator() const { return op; }
@@ -278,15 +362,13 @@ public:
virtual Expression * simplify() const;
virtual std::string toString() const;
virtual std::string toString(bool persistent=false) const;
virtual Expression * copy() const;
virtual Expression * _copy() const;
virtual int priority() const;
virtual void getDeps(std::set<ObjectIdentifier> &props) const;
virtual void visit(ExpressionVisitor & v);
virtual void _visit(ExpressionVisitor & v);
protected:
@@ -355,15 +437,13 @@ public:
virtual Expression * simplify() const;
virtual std::string toString() const;
virtual std::string toString(bool persistent=false) const;
virtual Expression * copy() const;
virtual Expression * _copy() const;
virtual int priority() const;
virtual void getDeps(std::set<ObjectIdentifier> &props) const;
virtual void visit(ExpressionVisitor & v);
virtual void _visit(ExpressionVisitor & v);
protected:
Expression *evalAggregate() const;
@@ -393,35 +473,73 @@ public:
virtual Expression * simplify() const;
virtual std::string toString() const { return var.toString(); }
virtual std::string toString(bool persistent=false) const;
virtual Expression * copy() const;
virtual Expression * _copy() const;
virtual int priority() const;
virtual void getDeps(std::set<ObjectIdentifier> &props) const;
std::string name() const { return var.getPropertyName(); }
ObjectIdentifier getPath() const { return var; }
void setPath(const ObjectIdentifier & path);
bool validDocumentObjectRename(const std::string & oldName, const std::string & newName);
bool renameDocumentObject(const std::string & oldName, const std::string & newName);
bool validDocumentRename(const std::string &oldName, const std::string &newName);
bool renameDocument(const std::string &oldName, const std::string &newName);
const App::Property *getProperty() const;
protected:
virtual void _getDeps(ExpressionDeps &) const;
virtual void _getDepObjects(std::set<App::DocumentObject*> &, std::vector<std::string> *) const;
virtual void _getIdentifiers(std::set<App::ObjectIdentifier> &) const;
virtual bool _adjustLinks(const std::set<App::DocumentObject*> &, ExpressionVisitor &);
virtual void _importSubNames(const ObjectIdentifier::SubNameMap &);
virtual void _updateLabelReference(App::DocumentObject *, const std::string &, const char *);
virtual bool _updateElementReference(App::DocumentObject *,bool,ExpressionVisitor &);
virtual bool _relabeledDocument(const std::string &, const std::string &, ExpressionVisitor &);
virtual bool _renameObjectIdentifier(const std::map<ObjectIdentifier,ObjectIdentifier> &,
const ObjectIdentifier &, ExpressionVisitor &);
virtual void _collectReplacement(std::map<ObjectIdentifier,ObjectIdentifier> &,
const App::DocumentObject *parent, App::DocumentObject *oldObj,
App::DocumentObject *newObj) const;
virtual void _moveCells(const CellAddress &, int, int, ExpressionVisitor &);
virtual void _offsetCells(int, int, ExpressionVisitor &);
protected:
ObjectIdentifier var; /**< Variable name */
};
//////////////////////////////////////////////////////////////////////
class AppExport PyObjectExpression : public Expression {
TYPESYSTEM_HEADER();
public:
PyObjectExpression(const App::DocumentObject *_owner=0, PyObject *pyobj=0, bool owned=false)
:Expression(_owner)
{
setPyObject(pyobj,owned);
}
virtual ~PyObjectExpression();
Py::Object getPyObject() const;
void setPyObject(Py::Object pyobj);
void setPyObject(PyObject *pyobj, bool owned=false);
virtual std::string toString(bool) const;
virtual Expression * eval() const { return copy(); }
virtual Expression * simplify() const { return copy(); }
protected:
virtual Expression* _copy() const;
protected:
PyObject *pyObj = 0;
};
/**
* Class implementing a string. Used to signal either a genuine string or
* a failed evaluation of an expression.
@@ -436,13 +554,13 @@ public:
virtual Expression * simplify() const;
virtual std::string toString() const;
virtual std::string toString(bool persistent=false) const;
virtual std::string getText() const { return text; }
virtual int priority() const;
virtual Expression * copy() const;
virtual Expression * _copy() const;
protected:
@@ -460,22 +578,26 @@ public:
virtual Expression * eval() const;
virtual std::string toString() const;
virtual std::string toString(bool persistent=false) const;
virtual Expression * copy() const;
virtual Expression * _copy() const;
virtual int priority() const;
virtual void getDeps(std::set<App::ObjectIdentifier> &props) const;
virtual App::Expression * simplify() const;
Range getRange() const { return range; }
void setRange(const Range & r);
Range getRange() const;
protected:
Range range;
virtual void _getDeps(ExpressionDeps &) const;
virtual bool _renameObjectIdentifier(const std::map<ObjectIdentifier,ObjectIdentifier> &,
const ObjectIdentifier &, ExpressionVisitor &);
virtual void _moveCells(const CellAddress &, int, int, ExpressionVisitor &);
virtual void _offsetCells(int, int, ExpressionVisitor &);
protected:
std::string begin;
std::string end;
};
namespace ExpressionParser {
@@ -486,6 +608,16 @@ AppExport bool isTokenAnIndentifier(const std::string & str);
AppExport bool isTokenAUnit(const std::string & str);
AppExport std::vector<boost::tuple<int, int, std::string> > tokenize(const std::string & str);
/// Convenient class to mark begin of importing
class AppExport ExpressionImporter {
public:
ExpressionImporter(Base::XMLReader &reader);
~ExpressionImporter();
static Base::XMLReader *reader();
};
AppExport bool isModuleImported(PyObject *);
/**
* @brief The semantic_type class encapsulates the value in the parse tree during parsing.
*/
+258 -234
View File
@@ -382,18 +382,18 @@ union yyalloc
#endif /* !YYCOPY_NEEDED */
/* YYFINAL -- State number of the termination state. */
#define YYFINAL 34
#define YYFINAL 38
/* YYLAST -- Last index in YYTABLE. */
#define YYLAST 188
#define YYLAST 196
/* YYNTOKENS -- Number of terminals. */
#define YYNTOKENS 40
/* YYNNTS -- Number of nonterminals. */
#define YYNNTS 14
/* YYNRULES -- Number of rules. */
#define YYNRULES 73
#define YYNRULES 74
/* YYNSTATES -- Number of states. */
#define YYNSTATES 130
#define YYNSTATES 132
/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
by yylex, with out-of-bounds checking. */
@@ -446,10 +446,10 @@ static const yytype_uint8 yyrline[] =
76, 77, 78, 79, 80, 81, 82, 83, 84, 87,
88, 89, 90, 92, 93, 94, 95, 96, 97, 100,
101, 102, 103, 106, 107, 108, 109, 110, 111, 114,
115, 116, 117, 118, 119, 122, 126, 131, 136, 144,
145, 149, 150, 151, 152, 153, 154, 155, 156, 157,
160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
172, 173, 176, 177
115, 116, 117, 118, 119, 122, 126, 131, 136, 141,
149, 150, 154, 155, 156, 157, 158, 159, 160, 161,
162, 165, 166, 167, 168, 169, 170, 171, 172, 173,
174, 177, 178, 181, 182
};
#endif
@@ -481,12 +481,12 @@ static const yytype_uint16 yytoknum[] =
};
# endif
#define YYPACT_NINF -100
#define YYPACT_NINF -102
#define yypact_value_is_default(Yystate) \
(!!((Yystate) == (-100)))
(!!((Yystate) == (-102)))
#define YYTABLE_NINF -74
#define YYTABLE_NINF -75
#define yytable_value_is_error(Yytable_value) \
0
@@ -495,19 +495,20 @@ static const yytype_uint16 yytoknum[] =
STATE-NUM. */
static const yytype_int16 yypact[] =
{
61, 79, -100, -100, 137, -100, -100, -100, -28, 106,
104, 104, 61, 18, 154, -1, 27, 89, -100, -100,
16, 26, -15, -17, 104, 154, 143, -100, 7, 86,
-100, -100, 112, 47, -100, 104, 104, 104, 104, 104,
104, 104, 104, 104, 61, 104, -1, 31, 104, -1,
-1, 43, 146, 22, 23, 24, -100, 79, 79, 39,
-100, -100, -100, -100, 33, -100, 42, 56, -100, -100,
154, 154, 154, 154, 154, 154, 128, 128, 72, 72,
31, -100, 135, 31, 31, 48, -100, 81, -100, -100,
69, -100, -100, -100, -100, -100, -100, 154, -100, 154,
-100, 7, 127, 84, 96, 98, 104, -100, 22, -100,
101, 119, 132, 7, 7, 7, 73, -100, 148, 149,
152, -100, -100, -100, 7, 7, 7, -100, -100, -100
67, 92, -102, -102, 131, -102, -102, -102, -32, -2,
117, 117, 67, 3, 24, 167, -4, 15, 86, -102,
-102, 23, 45, -7, -18, 117, 167, 153, -102, 73,
74, -102, -102, 125, 60, 19, -102, -102, -102, 117,
117, 117, 117, 117, 117, 117, 117, 117, 67, 117,
-4, 59, 117, -4, -4, 4, 101, 3, 13, 26,
-102, 92, 92, 30, -102, -102, -102, -102, 55, -102,
75, 77, -102, -102, 167, 167, 167, 167, 167, 167,
103, 103, 90, 90, 59, -102, 148, 59, 59, 29,
-102, -102, -102, 95, -102, -102, -102, -102, -102, 167,
-102, 167, -102, 73, 140, 97, 109, 111, 117, -102,
3, -102, 116, 126, 132, 73, 73, 73, 38, -102,
120, 134, 154, -102, -102, -102, 73, 73, 73, -102,
-102, -102
};
/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
@@ -515,33 +516,34 @@ static const yytype_int16 yypact[] =
means the default is an error. */
static const yytype_uint8 yydefact[] =
{
0, 0, 19, 20, 51, 39, 21, 22, 52, 6,
0, 0, 0, 0, 2, 4, 0, 3, 7, 45,
0, 0, 51, 52, 0, 23, 0, 24, 0, 0,
8, 9, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 5, 0, 0,
0, 0, 0, 0, 0, 0, 17, 0, 0, 60,
62, 61, 59, 50, 0, 49, 0, 0, 16, 44,
33, 34, 35, 36, 37, 38, 11, 10, 12, 13,
14, 15, 0, 41, 40, 0, 42, 51, 72, 47,
0, 52, 46, 32, 31, 30, 29, 25, 27, 26,
28, 0, 0, 56, 55, 53, 0, 43, 0, 69,
0, 0, 0, 0, 0, 0, 18, 48, 66, 65,
63, 58, 57, 54, 0, 0, 0, 68, 67, 64
0, 0, 19, 20, 52, 39, 21, 22, 53, 6,
0, 0, 0, 0, 0, 2, 4, 0, 3, 7,
45, 0, 0, 52, 53, 0, 23, 0, 24, 0,
0, 8, 9, 0, 0, 52, 53, 46, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 5, 0, 0, 0, 0, 0, 0, 0, 0,
17, 0, 0, 61, 63, 62, 60, 51, 0, 50,
0, 0, 16, 44, 33, 34, 35, 36, 37, 38,
11, 10, 12, 13, 14, 15, 0, 41, 40, 0,
42, 73, 48, 0, 47, 32, 31, 30, 29, 25,
27, 26, 28, 0, 0, 57, 56, 54, 0, 43,
0, 70, 0, 0, 0, 0, 0, 0, 18, 49,
67, 66, 64, 59, 58, 55, 0, 0, 0, 69,
68, 65
};
/* YYPGOTO[NTERM-NUM]. */
static const yytype_int16 yypgoto[] =
{
-100, -100, 0, -100, -100, 129, -100, 5, -100, -39,
-49, -99, -100, 130
-102, -102, 0, -102, -102, 44, -102, 5, -102, -35,
-6, -101, -102, 128
};
/* YYDEFGOTO[NTERM-NUM]. */
static const yytype_int8 yydefgoto[] =
{
-1, 13, 32, 15, 26, 27, 16, 33, 18, 67,
19, 62, 20, 21
-1, 14, 33, 16, 27, 28, 17, 34, 19, 71,
20, 66, 21, 22
};
/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
@@ -549,48 +551,50 @@ static const yytype_int8 yydefgoto[] =
number is the opposite. If YYTABLE_NINF, syntax error. */
static const yytype_int16 yytable[] =
{
14, 25, 109, 89, 92, 17, 5, 55, -73, 54,
30, 31, 86, 59, 121, 122, 123, 60, 34, -73,
47, 28, -71, 29, 61, 127, 128, 129, 87, 93,
95, 46, 91, 94, 96, 70, 71, 72, 73, 74,
75, 76, 77, 78, 79, 81, 107, 63, 82, 80,
48, 65, 63, 52, 83, 84, 65, 97, 99, 117,
51, 85, 53, 112, 1, 2, 3, 4, 5, 6,
7, 8, 103, 49, 50, 101, 51, 102, 9, 10,
69, 104, 1, 2, 3, 22, 11, 6, 7, 23,
63, 41, 64, 12, 65, 105, 9, 10, 42, 43,
44, 45, 45, 66, 11, 108, 116, 1, 2, 3,
4, 24, 6, 7, 8, 49, 50, 28, 51, 29,
113, 9, 10, 35, 36, 37, 38, 39, 40, 11,
41, 63, 114, 110, 115, 65, 24, 42, 43, 44,
118, 45, -72, -70, 111, 68, 35, 36, 37, 38,
39, 40, 87, 41, 43, 44, 8, 45, 119, 106,
42, 43, 44, 88, 45, 35, 36, 37, 38, 39,
40, 120, 41, 28, -71, 29, 56, 57, 58, 42,
43, 44, 90, 45, 124, 125, 98, 100, 126
15, 26, 111, 5, -74, 18, 59, 37, 67, 35,
31, 32, 69, 36, 123, 124, 125, 58, -74, 95,
90, 51, 89, 96, 38, 129, 130, 131, 50, 29,
-72, 30, 97, 67, -73, -71, 98, 69, 52, 74,
75, 76, 77, 78, 79, 80, 81, 82, 83, 85,
92, 94, 86, 84, 109, 29, 45, 30, 87, 88,
56, 99, 101, 46, 47, 48, 103, 49, 104, 114,
1, 2, 3, 4, 5, 6, 7, 8, 67, 63,
68, 57, 69, 64, 9, 10, 53, 54, 55, 55,
65, 70, 11, 73, 105, 1, 2, 3, 23, 12,
6, 7, 24, 13, 119, 100, 102, 35, 118, 9,
10, 8, 53, 54, 106, 55, 107, 11, 91, 49,
1, 2, 3, 4, 25, 6, 7, 8, 13, 47,
48, 110, 49, 115, 9, 10, 39, 40, 41, 42,
43, 44, 11, 45, 67, 116, 112, 117, 69, 25,
46, 47, 48, 13, 49, 120, 126, 113, 72, 39,
40, 41, 42, 43, 44, 121, 45, 29, -72, 30,
127, 122, 108, 46, 47, 48, 0, 49, 39, 40,
41, 42, 43, 44, 93, 45, 60, 61, 62, 0,
128, 0, 46, 47, 48, 0, 49
};
static const yytype_uint8 yycheck[] =
static const yytype_int16 yycheck[] =
{
0, 1, 101, 52, 53, 0, 7, 24, 36, 24,
10, 11, 51, 6, 113, 114, 115, 10, 0, 36,
15, 36, 37, 38, 17, 124, 125, 126, 6, 6,
6, 32, 10, 10, 10, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 85, 4, 48, 44,
23, 8, 4, 37, 49, 50, 8, 57, 58, 108,
29, 18, 36, 102, 3, 4, 5, 6, 7, 8,
9, 10, 39, 26, 27, 36, 29, 38, 17, 18,
33, 39, 3, 4, 5, 6, 25, 8, 9, 10,
4, 18, 6, 32, 8, 39, 17, 18, 25, 26,
27, 29, 29, 17, 25, 36, 106, 3, 4, 5,
6, 32, 8, 9, 10, 26, 27, 36, 29, 38,
36, 17, 18, 11, 12, 13, 14, 15, 16, 25,
18, 4, 36, 6, 36, 8, 32, 25, 26, 27,
39, 29, 36, 37, 17, 33, 11, 12, 13, 14,
15, 16, 6, 18, 26, 27, 10, 29, 39, 24,
25, 26, 27, 17, 29, 11, 12, 13, 14, 15,
16, 39, 18, 36, 37, 38, 33, 34, 35, 25,
26, 27, 52, 29, 36, 36, 57, 58, 36
0, 1, 103, 7, 36, 0, 24, 13, 4, 6,
10, 11, 8, 10, 115, 116, 117, 24, 36, 6,
55, 16, 18, 10, 0, 126, 127, 128, 32, 36,
37, 38, 6, 4, 36, 37, 10, 8, 23, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
56, 57, 52, 48, 89, 36, 18, 38, 53, 54,
37, 61, 62, 25, 26, 27, 36, 29, 38, 104,
3, 4, 5, 6, 7, 8, 9, 10, 4, 6,
6, 36, 8, 10, 17, 18, 26, 27, 29, 29,
17, 17, 25, 33, 39, 3, 4, 5, 6, 32,
8, 9, 10, 36, 110, 61, 62, 6, 108, 17,
18, 10, 26, 27, 39, 29, 39, 25, 17, 29,
3, 4, 5, 6, 32, 8, 9, 10, 36, 26,
27, 36, 29, 36, 17, 18, 11, 12, 13, 14,
15, 16, 25, 18, 4, 36, 6, 36, 8, 32,
25, 26, 27, 36, 29, 39, 36, 17, 33, 11,
12, 13, 14, 15, 16, 39, 18, 36, 37, 38,
36, 39, 24, 25, 26, 27, -1, 29, 11, 12,
13, 14, 15, 16, 56, 18, 33, 34, 35, -1,
36, -1, 25, 26, 27, -1, 29
};
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
@@ -598,18 +602,19 @@ static const yytype_uint8 yycheck[] =
static const yytype_uint8 yystos[] =
{
0, 3, 4, 5, 6, 7, 8, 9, 10, 17,
18, 25, 32, 41, 42, 43, 46, 47, 48, 50,
52, 53, 6, 10, 32, 42, 44, 45, 36, 38,
42, 42, 42, 47, 0, 11, 12, 13, 14, 15,
16, 18, 25, 26, 27, 29, 32, 47, 23, 26,
27, 29, 37, 36, 24, 24, 33, 34, 35, 6,
10, 17, 51, 4, 6, 8, 17, 49, 33, 33,
42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
47, 42, 42, 47, 47, 18, 49, 6, 17, 50,
53, 10, 50, 6, 10, 6, 10, 42, 45, 42,
45, 36, 38, 39, 39, 39, 24, 49, 36, 51,
6, 17, 49, 36, 36, 36, 42, 50, 39, 39,
39, 51, 51, 51, 36, 36, 36, 51, 51, 51
18, 25, 32, 36, 41, 42, 43, 46, 47, 48,
50, 52, 53, 6, 10, 32, 42, 44, 45, 36,
38, 42, 42, 42, 47, 6, 10, 50, 0, 11,
12, 13, 14, 15, 16, 18, 25, 26, 27, 29,
32, 47, 23, 26, 27, 29, 37, 36, 24, 24,
33, 34, 35, 6, 10, 17, 51, 4, 6, 8,
17, 49, 33, 33, 42, 42, 42, 42, 42, 42,
42, 42, 42, 42, 47, 42, 42, 47, 47, 18,
49, 17, 50, 53, 50, 6, 10, 6, 10, 42,
45, 42, 45, 36, 38, 39, 39, 39, 24, 49,
36, 51, 6, 17, 49, 36, 36, 36, 42, 50,
39, 39, 39, 51, 51, 51, 36, 36, 36, 51,
51, 51
};
/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
@@ -619,10 +624,10 @@ static const yytype_uint8 yyr1[] =
42, 42, 42, 42, 42, 42, 42, 42, 42, 43,
43, 43, 43, 44, 44, 44, 44, 44, 44, 45,
45, 45, 45, 46, 46, 46, 46, 46, 46, 47,
47, 47, 47, 47, 47, 48, 48, 48, 48, 49,
49, 50, 50, 50, 50, 50, 50, 50, 50, 50,
51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
52, 52, 53, 53
47, 47, 47, 47, 47, 48, 48, 48, 48, 48,
49, 49, 50, 50, 50, 50, 50, 50, 50, 50,
50, 51, 51, 51, 51, 51, 51, 51, 51, 51,
51, 52, 52, 53, 53
};
/* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
@@ -632,10 +637,10 @@ static const yytype_uint8 yyr2[] =
3, 3, 3, 3, 3, 3, 3, 3, 5, 1,
1, 1, 1, 1, 1, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 1,
3, 3, 3, 4, 3, 1, 3, 3, 5, 1,
1, 1, 1, 4, 6, 4, 4, 6, 6, 3,
1, 1, 1, 4, 6, 4, 4, 6, 6, 3,
1, 1, 1, 1
3, 3, 3, 4, 3, 1, 2, 3, 3, 5,
1, 1, 1, 1, 4, 6, 4, 4, 6, 6,
3, 1, 1, 1, 4, 6, 4, 4, 6, 6,
3, 1, 1, 1, 1
};
@@ -1061,25 +1066,25 @@ yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
case 42: /* exp */
#line 59 "ExpressionParser.y" /* yacc.c:1257 */
{ delete ((*yyvaluep).expr); }
#line 1065 "ExpressionParser.tab.c" /* yacc.c:1257 */
#line 1070 "ExpressionParser.tab.c" /* yacc.c:1257 */
break;
case 44: /* args */
#line 60 "ExpressionParser.y" /* yacc.c:1257 */
{ std::vector<Expression*>::const_iterator i = ((*yyvaluep).arguments).begin(); while (i != ((*yyvaluep).arguments).end()) { delete *i; ++i; } }
#line 1071 "ExpressionParser.tab.c" /* yacc.c:1257 */
#line 1076 "ExpressionParser.tab.c" /* yacc.c:1257 */
break;
case 46: /* cond */
#line 59 "ExpressionParser.y" /* yacc.c:1257 */
{ delete ((*yyvaluep).expr); }
#line 1077 "ExpressionParser.tab.c" /* yacc.c:1257 */
#line 1082 "ExpressionParser.tab.c" /* yacc.c:1257 */
break;
case 47: /* unit_exp */
#line 59 "ExpressionParser.y" /* yacc.c:1257 */
{ delete ((*yyvaluep).expr); }
#line 1083 "ExpressionParser.tab.c" /* yacc.c:1257 */
#line 1088 "ExpressionParser.tab.c" /* yacc.c:1257 */
break;
@@ -1343,259 +1348,259 @@ yyreduce:
case 2:
#line 66 "ExpressionParser.y" /* yacc.c:1646 */
{ ScanResult = (yyvsp[0].expr); valueExpression = true; }
#line 1347 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1352 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 3:
#line 67 "ExpressionParser.y" /* yacc.c:1646 */
{ ScanResult = (yyvsp[0].expr); unitExpression = true; }
#line 1353 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1358 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 4:
#line 70 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = (yyvsp[0].expr); }
#line 1359 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1364 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 5:
#line 71 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-1].expr), OperatorExpression::UNIT, (yyvsp[0].expr)); }
#line 1365 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1370 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 6:
#line 72 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new StringExpression(DocumentObject, (yyvsp[0].string)); }
#line 1371 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1376 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 7:
#line 73 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new VariableExpression(DocumentObject, (yyvsp[0].path)); }
#line 1377 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1382 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 8:
#line 74 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[0].expr), OperatorExpression::NEG, new NumberExpression(DocumentObject, Quantity(-1))); }
#line 1383 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1388 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 9:
#line 75 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[0].expr), OperatorExpression::POS, new NumberExpression(DocumentObject, Quantity(1))); }
#line 1389 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1394 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 10:
#line 76 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::ADD, (yyvsp[0].expr)); }
#line 1395 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1400 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 11:
#line 77 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::SUB, (yyvsp[0].expr)); }
#line 1401 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1406 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 12:
#line 78 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::MUL, (yyvsp[0].expr)); }
#line 1407 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1412 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 13:
#line 79 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::DIV, (yyvsp[0].expr)); }
#line 1413 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1418 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 14:
#line 80 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::DIV, (yyvsp[0].expr)); }
#line 1419 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1424 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 15:
#line 81 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::POW, (yyvsp[0].expr)); }
#line 1425 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1430 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 16:
#line 82 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = (yyvsp[-1].expr); }
#line 1431 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1436 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 17:
#line 83 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new FunctionExpression(DocumentObject, (yyvsp[-2].func), (yyvsp[-1].arguments)); }
#line 1437 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1442 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 18:
#line 84 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new ConditionalExpression(DocumentObject, (yyvsp[-4].expr), (yyvsp[-2].expr), (yyvsp[0].expr)); }
#line 1443 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1448 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 19:
#line 87 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new NumberExpression(DocumentObject, Quantity((yyvsp[0].fvalue))); }
#line 1449 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1454 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 20:
#line 88 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new NumberExpression(DocumentObject, Quantity((yyvsp[0].fvalue))); }
#line 1455 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1460 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 21:
#line 89 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new NumberExpression(DocumentObject, Quantity((double)(yyvsp[0].ivalue))); }
#line 1461 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1466 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 22:
#line 90 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new ConstantExpression(DocumentObject, (yyvsp[0].constant).name, Quantity((yyvsp[0].constant).fvalue)); }
#line 1467 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1472 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 23:
#line 92 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.arguments).push_back((yyvsp[0].expr)); }
#line 1473 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1478 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 24:
#line 93 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.arguments).push_back((yyvsp[0].expr)); }
#line 1479 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1484 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 25:
#line 94 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyvsp[-2].arguments).push_back((yyvsp[0].expr)); (yyval.arguments) = (yyvsp[-2].arguments); }
#line 1485 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1490 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 26:
#line 95 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyvsp[-2].arguments).push_back((yyvsp[0].expr)); (yyval.arguments) = (yyvsp[-2].arguments); }
#line 1491 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1496 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 27:
#line 96 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyvsp[-2].arguments).push_back((yyvsp[0].expr)); (yyval.arguments) = (yyvsp[-2].arguments); }
#line 1497 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1502 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 28:
#line 97 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyvsp[-2].arguments).push_back((yyvsp[0].expr)); (yyval.arguments) = (yyvsp[-2].arguments); }
#line 1503 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1508 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 29:
#line 100 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new RangeExpression(DocumentObject, (yyvsp[-2].string), (yyvsp[0].string)); }
#line 1509 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1514 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 30:
#line 101 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new RangeExpression(DocumentObject, (yyvsp[-2].string), (yyvsp[0].string)); }
#line 1515 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1520 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 31:
#line 102 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new RangeExpression(DocumentObject, (yyvsp[-2].string), (yyvsp[0].string)); }
#line 1521 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1526 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 32:
#line 103 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new RangeExpression(DocumentObject, (yyvsp[-2].string), (yyvsp[0].string)); }
#line 1527 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1532 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 33:
#line 106 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::EQ, (yyvsp[0].expr)); }
#line 1533 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1538 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 34:
#line 107 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::NEQ, (yyvsp[0].expr)); }
#line 1539 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1544 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 35:
#line 108 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::LT, (yyvsp[0].expr)); }
#line 1545 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1550 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 36:
#line 109 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::GT, (yyvsp[0].expr)); }
#line 1551 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1556 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 37:
#line 110 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::GTE, (yyvsp[0].expr)); }
#line 1557 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1562 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 38:
#line 111 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::LTE, (yyvsp[0].expr)); }
#line 1563 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1568 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 39:
#line 114 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new UnitExpression(DocumentObject, (yyvsp[0].quantity).scaler, (yyvsp[0].quantity).unitStr ); }
#line 1569 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1574 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 40:
#line 115 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::DIV, (yyvsp[0].expr)); }
#line 1575 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1580 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 41:
#line 116 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::MUL, (yyvsp[0].expr)); }
#line 1581 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1586 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 42:
#line 117 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::POW, new NumberExpression(DocumentObject, Quantity((double)(yyvsp[0].ivalue)))); }
#line 1587 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1592 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 43:
#line 118 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-3].expr), OperatorExpression::POW, new OperatorExpression(DocumentObject, new NumberExpression(DocumentObject, Quantity((double)(yyvsp[0].ivalue))), OperatorExpression::NEG, new NumberExpression(DocumentObject, Quantity(-1)))); }
#line 1593 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1598 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 44:
#line 119 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.expr) = (yyvsp[-1].expr); }
#line 1599 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1604 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 45:
@@ -1603,193 +1608,212 @@ yyreduce:
{ /* Path to property within document object */
(yyval.path) = ObjectIdentifier(DocumentObject);
(yyval.path).addComponents((yyvsp[0].components));
(yyval.path).resolveAmbiguity();
}
#line 1608 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1613 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 46:
#line 126 "ExpressionParser.y" /* yacc.c:1646 */
{ /* Path to property within document object */
(yyval.path) = ObjectIdentifier(DocumentObject);
(yyval.path).setDocumentObjectName((yyvsp[-2].string_or_identifier), true);
{ /* Path to property of the current document object */
(yyval.path) = ObjectIdentifier(DocumentObject,true);
(yyval.path).setDocumentObjectName(DocumentObject);
(yyval.path).addComponents((yyvsp[0].components));
}
#line 1618 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1623 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 47:
#line 131 "ExpressionParser.y" /* yacc.c:1646 */
{ /* Path to property from an external document, within a named document object */
{ /* Path to property within document object */
(yyval.path) = ObjectIdentifier(DocumentObject);
(yyval.path).setDocumentName((yyvsp[-2].string_or_identifier), true);
(yyvsp[-2].string_or_identifier).checkImport(DocumentObject);
(yyval.path).addComponent(ObjectIdentifier::SimpleComponent((yyvsp[-2].string_or_identifier)));
(yyval.path).addComponents((yyvsp[0].components));
(yyval.path).resolveAmbiguity();
}
#line 1628 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1633 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 48:
#line 136 "ExpressionParser.y" /* yacc.c:1646 */
{ /* Path to property from an external document, within a named document object */
(yyval.path) = ObjectIdentifier(DocumentObject);
(yyval.path).setDocumentName((yyvsp[-4].string_or_identifier), true);
(yyval.path).setDocumentObjectName((yyvsp[-2].string_or_identifier), true);
(yyval.path).setDocumentName(std::move(yyvsp[-2].string_or_identifier), true);
if((yyvsp[0].components).size()) {
(yyval.path).setDocumentObjectName(ObjectIdentifier::String((yyvsp[0].components).front().getName(),false,true), true);
(yyvsp[0].components).pop_front();
}
(yyval.path).addComponents((yyvsp[0].components));
(yyval.path).resolveAmbiguity();
}
#line 1639 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1643 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 49:
#line 144 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.ivalue) = (yyvsp[0].ivalue); }
#line 1645 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 141 "ExpressionParser.y" /* yacc.c:1646 */
{ /* Path to property from an external document, within a named document object */
(yyval.path) = ObjectIdentifier(DocumentObject);
(yyval.path).setDocumentName(std::move(yyvsp[-4].string_or_identifier), true);
(yyval.path).setDocumentObjectName(std::move(yyvsp[-2].string_or_identifier), true);
(yyval.path).addComponents((yyvsp[0].components));
(yyval.path).resolveAmbiguity();
}
#line 1654 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 50:
#line 145 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.ivalue) = (yyvsp[0].fvalue); }
#line 1651 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 149 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.ivalue) = (yyvsp[0].ivalue); }
#line 1660 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 51:
#line 149 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.components).push_front(ObjectIdentifier::Component::SimpleComponent((yyvsp[0].string))); }
#line 1657 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 150 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.ivalue) = (yyvsp[0].fvalue); }
#line 1666 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 52:
#line 150 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.components).push_front(ObjectIdentifier::Component::SimpleComponent((yyvsp[0].string))); }
#line 1663 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 154 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[0].string))); }
#line 1672 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 53:
#line 151 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.components).push_front(ObjectIdentifier::Component::ArrayComponent((yyvsp[-3].string), (yyvsp[-1].ivalue))); }
#line 1669 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 155 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[0].string))); }
#line 1678 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 54:
#line 152 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyvsp[0].components).push_front(ObjectIdentifier::Component::ArrayComponent((yyvsp[-5].string), (yyvsp[-3].ivalue))); (yyval.components) = (yyvsp[0].components); }
#line 1675 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 156 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.components).push_front(ObjectIdentifier::ArrayComponent((yyvsp[-1].ivalue))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-3].string))); }
#line 1684 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 55:
#line 153 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.components).push_front(ObjectIdentifier::Component::MapComponent((yyvsp[-3].string), ObjectIdentifier::String((yyvsp[-1].string), true))); }
#line 1681 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 157 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyvsp[0].components).push_front(ObjectIdentifier::ArrayComponent((yyvsp[-3].ivalue))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-5].string))); (yyval.components) = (yyvsp[0].components); }
#line 1690 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 56:
#line 154 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.components).push_front(ObjectIdentifier::Component::MapComponent((yyvsp[-3].string), (yyvsp[-1].string))); }
#line 1687 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 158 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.components).push_front(ObjectIdentifier::MapComponent(ObjectIdentifier::String((yyvsp[-1].string), true))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-3].string))); }
#line 1696 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 57:
#line 155 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyvsp[0].components).push_front(ObjectIdentifier::Component::MapComponent((yyvsp[-5].string), ObjectIdentifier::String((yyvsp[-3].string), true))); (yyval.components) = (yyvsp[0].components); }
#line 1693 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 159 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.components).push_front(ObjectIdentifier::MapComponent((yyvsp[-1].string))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-3].string))); }
#line 1702 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 58:
#line 156 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyvsp[0].components).push_front(ObjectIdentifier::Component::MapComponent((yyvsp[-5].string), (yyvsp[-3].string))); (yyval.components) = (yyvsp[0].components); }
#line 1699 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 160 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyvsp[0].components).push_front(ObjectIdentifier::MapComponent(ObjectIdentifier::String((yyvsp[-3].string), true))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-5].string))); (yyval.components) = (yyvsp[0].components); }
#line 1708 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 59:
#line 157 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyvsp[0].components).push_front(ObjectIdentifier::Component::SimpleComponent((yyvsp[-2].string))); (yyval.components) = (yyvsp[0].components); }
#line 1705 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 161 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyvsp[0].components).push_front(ObjectIdentifier::MapComponent((yyvsp[-3].string))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-5].string))); (yyval.components) = (yyvsp[0].components); }
#line 1714 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 60:
#line 160 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.components).push_front(ObjectIdentifier::Component::SimpleComponent((yyvsp[0].string))); }
#line 1711 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 162 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyvsp[0].components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-2].string))); (yyval.components) = (yyvsp[0].components); }
#line 1720 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 61:
#line 161 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.components).push_front(ObjectIdentifier::Component::SimpleComponent((yyvsp[0].string))); }
#line 1717 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 165 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[0].string))); }
#line 1726 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 62:
#line 162 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.components).push_front(ObjectIdentifier::Component::SimpleComponent((yyvsp[0].string))); }
#line 1723 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 166 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[0].string))); }
#line 1732 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 63:
#line 163 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.components).push_front(ObjectIdentifier::Component::ArrayComponent((yyvsp[-3].string), (yyvsp[-1].ivalue))); }
#line 1729 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 167 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[0].string))); }
#line 1738 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 64:
#line 164 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyvsp[0].components).push_front(ObjectIdentifier::Component::ArrayComponent((yyvsp[-5].string), (yyvsp[-3].ivalue))); (yyval.components) = (yyvsp[0].components); }
#line 1735 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 168 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.components).push_front(ObjectIdentifier::ArrayComponent((yyvsp[-1].ivalue))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-3].string))); }
#line 1744 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 65:
#line 165 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.components).push_front(ObjectIdentifier::Component::MapComponent((yyvsp[-3].string), ObjectIdentifier::String((yyvsp[-1].string), true))); }
#line 1741 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 169 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyvsp[0].components).push_front(ObjectIdentifier::ArrayComponent((yyvsp[-3].ivalue))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-5].string))); (yyval.components) = (yyvsp[0].components); }
#line 1750 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 66:
#line 166 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.components).push_front(ObjectIdentifier::Component::MapComponent((yyvsp[-3].string), (yyvsp[-1].string))); }
#line 1747 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 170 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.components).push_front(ObjectIdentifier::MapComponent(ObjectIdentifier::String((yyvsp[-1].string), true))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-3].string))); }
#line 1756 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 67:
#line 167 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyvsp[0].components).push_front(ObjectIdentifier::Component::MapComponent((yyvsp[-5].string), ObjectIdentifier::String((yyvsp[-3].string), true))); (yyval.components) = (yyvsp[0].components); }
#line 1753 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 171 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.components).push_front(ObjectIdentifier::MapComponent((yyvsp[-1].string))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-3].string))); }
#line 1762 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 68:
#line 168 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyvsp[0].components).push_front(ObjectIdentifier::Component::MapComponent((yyvsp[-5].string), (yyvsp[-3].string))); (yyval.components) = (yyvsp[0].components); }
#line 1759 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 172 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyvsp[0].components).push_front(ObjectIdentifier::MapComponent(ObjectIdentifier::String((yyvsp[-3].string), true))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-5].string))); (yyval.components) = (yyvsp[0].components); }
#line 1768 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 69:
#line 169 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyvsp[0].components).push_front(ObjectIdentifier::Component::SimpleComponent((yyvsp[-2].string))); (yyval.components) = (yyvsp[0].components); }
#line 1765 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 173 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyvsp[0].components).push_front(ObjectIdentifier::MapComponent((yyvsp[-3].string))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-5].string))); (yyval.components) = (yyvsp[0].components); }
#line 1774 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 70:
#line 172 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.string_or_identifier) = ObjectIdentifier::String((yyvsp[0].string), true); }
#line 1771 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 174 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyvsp[0].components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-2].string))); (yyval.components) = (yyvsp[0].components); }
#line 1780 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 71:
#line 173 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.string_or_identifier) = ObjectIdentifier::String((yyvsp[0].string)); }
#line 1777 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 177 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.string_or_identifier) = ObjectIdentifier::String((yyvsp[0].string), true); }
#line 1786 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 72:
#line 176 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.string_or_identifier) = ObjectIdentifier::String((yyvsp[0].string), true); }
#line 1783 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 178 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.string_or_identifier) = ObjectIdentifier::String((yyvsp[0].string)); }
#line 1792 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 73:
#line 177 "ExpressionParser.y" /* yacc.c:1646 */
#line 181 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.string_or_identifier) = ObjectIdentifier::String((yyvsp[0].string), true); }
#line 1789 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1798 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
case 74:
#line 182 "ExpressionParser.y" /* yacc.c:1646 */
{ (yyval.string_or_identifier) = ObjectIdentifier::String((yyvsp[0].string), true); }
#line 1804 "ExpressionParser.tab.c" /* yacc.c:1646 */
break;
#line 1793 "ExpressionParser.tab.c" /* yacc.c:1646 */
#line 1808 "ExpressionParser.tab.c" /* yacc.c:1646 */
default: break;
}
/* User semantic actions sometimes alter yychar, and that requires
@@ -2017,5 +2041,5 @@ yyreturn:
#endif
return yyresult;
}
#line 180 "ExpressionParser.y" /* yacc.c:1906 */
#line 185 "ExpressionParser.y" /* yacc.c:1906 */
+33 -23
View File
@@ -122,22 +122,32 @@ unit_exp: UNIT { $$ = new UnitExpression(Docume
identifier: path { /* Path to property within document object */
$$ = ObjectIdentifier(DocumentObject);
$$.addComponents($1);
$$.resolveAmbiguity();
}
| '.' path { /* Path to property of the current document object */
$$ = ObjectIdentifier(DocumentObject,true);
$$.setDocumentObjectName(DocumentObject);
$$.addComponents($2);
}
| object '.' path { /* Path to property within document object */
$$ = ObjectIdentifier(DocumentObject);
$$.setDocumentObjectName($1, true);
$1.checkImport(DocumentObject);
$$.addComponent(ObjectIdentifier::SimpleComponent($1));
$$.addComponents($3);
$$.resolveAmbiguity();
}
| document '#' path { /* Path to property from an external document, within a named document object */
$$ = ObjectIdentifier(DocumentObject);
$$.setDocumentName($1, true);
$$.setDocumentName(std::move($1), true);
$$.addComponents($3);
$$.resolveAmbiguity();
}
| document '#' object '.' path { /* Path to property from an external document, within a named document object */
$$ = ObjectIdentifier(DocumentObject);
$$.setDocumentName($1, true);
$$.setDocumentObjectName($3, true);
$$.setDocumentName(std::move($1), true);
$$.setDocumentObjectName(std::move($3), true);
$$.addComponents($5);
$$.resolveAmbiguity();
}
;
@@ -146,27 +156,27 @@ integer: INTEGER { $$ = $1; }
;
path: IDENTIFIER { $$.push_front(ObjectIdentifier::Component::SimpleComponent($1)); }
| CELLADDRESS { $$.push_front(ObjectIdentifier::Component::SimpleComponent($1)); }
| IDENTIFIER '[' integer ']' { $$.push_front(ObjectIdentifier::Component::ArrayComponent($1, $3)); }
| IDENTIFIER '[' integer ']' '.' subpath { $6.push_front(ObjectIdentifier::Component::ArrayComponent($1, $3)); $$ = $6; }
| IDENTIFIER '[' STRING ']' { $$.push_front(ObjectIdentifier::Component::MapComponent($1, ObjectIdentifier::String($3, true))); }
| IDENTIFIER '[' IDENTIFIER ']' { $$.push_front(ObjectIdentifier::Component::MapComponent($1, $3)); }
| IDENTIFIER '[' STRING ']' '.' subpath { $6.push_front(ObjectIdentifier::Component::MapComponent($1, ObjectIdentifier::String($3, true))); $$ = $6; }
| IDENTIFIER '[' IDENTIFIER ']' '.' subpath { $6.push_front(ObjectIdentifier::Component::MapComponent($1, $3)); $$ = $6; }
| IDENTIFIER '.' subpath { $3.push_front(ObjectIdentifier::Component::SimpleComponent($1)); $$ = $3; }
path: IDENTIFIER { $$.push_front(ObjectIdentifier::SimpleComponent($1)); }
| CELLADDRESS { $$.push_front(ObjectIdentifier::SimpleComponent($1)); }
| IDENTIFIER '[' integer ']' { $$.push_front(ObjectIdentifier::ArrayComponent($3)); $$.push_front(ObjectIdentifier::SimpleComponent($1); }
| IDENTIFIER '[' integer ']' '.' subpath { $6.push_front(ObjectIdentifier::ArrayComponent($3)); $$.push_front(ObjectIdentifier::SimpleComponent($1); $$ = $6; }
| IDENTIFIER '[' STRING ']' { $$.push_front(ObjectIdentifier::MapComponent(ObjectIdentifier::String($3, true))); }
| IDENTIFIER '[' IDENTIFIER ']' { $$.push_front(ObjectIdentifier::MapComponent($3)); $$.push_front(ObjectIdentifier::SimpleComponent($1); }
| IDENTIFIER '[' STRING ']' '.' subpath { $6.push_front(ObjectIdentifier::MapComponent(ObjectIdentifier::String($3, true))); $$.push_front(ObjectIdentifier::SimpleComponent($1); $$ = $6; }
| IDENTIFIER '[' IDENTIFIER ']' '.' subpath { $6.push_front(ObjectIdentifier::MapComponent($3)); $$.push_front(ObjectIdentifier::SimpleComponent($1); $$ = $6; }
| IDENTIFIER '.' subpath { $3.push_front(ObjectIdentifier::SimpleComponent($1)); $$ = $3; }
;
subpath: IDENTIFIER { $$.push_front(ObjectIdentifier::Component::SimpleComponent($1)); }
| STRING { $$.push_front(ObjectIdentifier::Component::SimpleComponent($1)); }
| CELLADDRESS { $$.push_front(ObjectIdentifier::Component::SimpleComponent($1)); }
| IDENTIFIER '[' integer ']' { $$.push_front(ObjectIdentifier::Component::ArrayComponent($1, $3)); }
| IDENTIFIER '[' integer ']' '.' subpath { $6.push_front(ObjectIdentifier::Component::ArrayComponent($1, $3)); $$ = $6; }
| IDENTIFIER '[' STRING ']' { $$.push_front(ObjectIdentifier::Component::MapComponent($1, ObjectIdentifier::String($3, true))); }
| IDENTIFIER '[' IDENTIFIER ']' { $$.push_front(ObjectIdentifier::Component::MapComponent($1, $3)); }
| IDENTIFIER '[' STRING ']' '.' subpath { $6.push_front(ObjectIdentifier::Component::MapComponent($1, ObjectIdentifier::String($3, true))); $$ = $6; }
| IDENTIFIER '[' IDENTIFIER ']' '.' subpath { $6.push_front(ObjectIdentifier::Component::MapComponent($1, $3)); $$ = $6; }
| IDENTIFIER '.' subpath { $3.push_front(ObjectIdentifier::Component::SimpleComponent($1)); $$ = $3; }
subpath: IDENTIFIER { $$.push_front(ObjectIdentifier::SimpleComponent($1)); }
| STRING { $$.push_front(ObjectIdentifier::SimpleComponent($1)); }
| CELLADDRESS { $$.push_front(ObjectIdentifier::SimpleComponent($1)); }
| IDENTIFIER '[' integer ']' { $$.push_front(ObjectIdentifier::ArrayComponent($3)); $$.push_front(ObjectIdentifier::SimpleComponent($1)); }
| IDENTIFIER '[' integer ']' '.' subpath { $6.push_front(ObjectIdentifier::ArrayComponent($3)); $$.push_front(ObjectIdentifier::SimpleComponent($1));$$ = $6; }
| IDENTIFIER '[' STRING ']' { $$.push_front(ObjectIdentifier::MapComponent(ObjectIdentifier::String($3, true))); $$.push_front(ObjectIdentifier::SimpleComponent($1)); }
| IDENTIFIER '[' IDENTIFIER ']' { $$.push_front(ObjectIdentifier::MapComponent($3)); $$.push_front(ObjectIdentifier::SimpleComponent($1)); }
| IDENTIFIER '[' STRING ']' '.' subpath { $6.push_front(ObjectIdentifier::MapComponent(ObjectIdentifier::String($3, true))); $$.push_front(ObjectIdentifier::SimpleComponent($1));$$ = $6; }
| IDENTIFIER '[' IDENTIFIER ']' '.' subpath { $6.push_front(ObjectIdentifier::MapComponent($3)); $$.push_front(ObjectIdentifier::SimpleComponent($1));$$ = $6; }
| IDENTIFIER '.' subpath { $3.push_front(ObjectIdentifier::SimpleComponent($1)); $$ = $3; }
;
document: STRING { $$ = ObjectIdentifier::String($1, true); }
+50 -52
View File
@@ -43,18 +43,8 @@ public:
{
}
void visit(Expression *node) {
VariableExpression *expr = Base::freecad_dynamic_cast<VariableExpression>(node);
if (expr) {
const App::ObjectIdentifier & oldPath = expr->getPath().canonicalPath();
const std::map<ObjectIdentifier, ObjectIdentifier>::const_iterator it = paths.find(oldPath);
if (it != paths.end()) {
ExpressionModifier<P>::setExpressionChanged();
expr->setPath(it->second.relativeTo(owner));
}
}
void visit(Expression &node) {
this->renameObjectIdentifier(node,paths,owner);
}
@@ -63,64 +53,72 @@ private:
const ObjectIdentifier owner; /**< Owner of expression */
};
/**
* @brief The RelabelDocumentObjectExpressionVisitor class is a functor class used to rename variables in an expression.
*/
template<class P> class RelabelDocumentObjectExpressionVisitor : public ExpressionModifier<P> {
template<class P> class UpdateElementReferenceExpressionVisitor : public ExpressionModifier<P> {
public:
RelabelDocumentObjectExpressionVisitor(P & _prop, const std::string & _oldName, const std::string & _newName)
: ExpressionModifier<P>(_prop)
, oldName(_oldName)
, newName(_newName)
UpdateElementReferenceExpressionVisitor(P & _prop, App::DocumentObject *feature=0, bool reverse=false)
: ExpressionModifier<P>(_prop),feature(feature),reverse(reverse)
{
}
~RelabelDocumentObjectExpressionVisitor() {
}
/**
* @brief Visit each node in the expression, and if it is a VariableExpression object, incoke renameDocumentObject in it.
* @param node Node to visit
*/
void visit(Expression * node) {
VariableExpression *expr = Base::freecad_dynamic_cast<VariableExpression>(node);
if (expr && expr->validDocumentObjectRename(oldName, newName)) {
ExpressionModifier<P>::setExpressionChanged();
expr->renameDocumentObject(oldName, newName);
}
void visit(Expression &node) {
this->updateElementReference(node,feature,reverse);
}
private:
std::string oldName; /**< Document object name to replace */
std::string newName; /**< New document object name */
App::DocumentObject *feature;
bool reverse;
};
template<class P> class RelabelDocumentExpressionVisitor : public ExpressionModifier<P> {
// Document relabel is not undoable, so we don't derive from
// ExpressionModifier, hence not calling aboutToSetValue/hasSetValue().
// By right, modification of document label should not change evaluation result
// of any expression.
class RelabelDocumentExpressionVisitor : public ExpressionVisitor {
public:
RelabelDocumentExpressionVisitor(P & prop, const std::string & _oldName, const std::string & _newName)
: ExpressionModifier<P>(prop)
, oldName(_oldName)
, newName(_newName)
RelabelDocumentExpressionVisitor(const App::Document &doc)
: doc(doc)
{
}
void visit(Expression * node) {
VariableExpression *expr = Base::freecad_dynamic_cast<VariableExpression>(node);
if (expr && expr->validDocumentRename(oldName, newName)) {
ExpressionModifier<P>::setExpressionChanged();
expr->renameDocument(oldName, newName);
}
void visit(Expression &node) {
this->relabeledDocument(node,doc.getOldLabel(),doc.Label.getStrValue());
}
private:
std::string oldName;
std::string newName;
const App::Document &doc;
};
template<class P> class MoveCellsExpressionVisitor : public ExpressionModifier<P> {
public:
MoveCellsExpressionVisitor(P &prop, const CellAddress &address, int rowCount, int colCount)
: ExpressionModifier<P>(prop),address(address),rowCount(rowCount),colCount(colCount)
{}
void visit(Expression &node) {
this->moveCells(node,address,rowCount,colCount);
}
private:
CellAddress address;
int rowCount;
int colCount;
};
template<class P> class OffsetCellsExpressionVisitor : public ExpressionModifier<P> {
public:
OffsetCellsExpressionVisitor(P &prop, int rowOffset, int colOffset)
: ExpressionModifier<P>(prop),rowOffset(rowOffset),colOffset(colOffset)
{}
void visit(Expression &node) {
this->offsetCells(node,rowOffset,colOffset);
}
private:
int rowOffset;
int colOffset;
};
}
+1173 -428
View File
File diff suppressed because it is too large Load Diff
+246 -44
View File
@@ -24,39 +24,86 @@
#ifndef APP_PATH_H
#define APP_PATH_H
#include <climits>
#include <memory>
#include <vector>
#include <string>
#include <set>
#include <map>
#include <bitset>
#ifndef BOOST_105400
#include <boost/any.hpp>
#else
#include <boost_any_1_55.hpp>
#endif
#include <CXX/Objects.hxx>
namespace App
{
using any = boost::any;
template<class T>
inline const T &any_cast(const boost::any &value) {
return boost::any_cast<const T&>(value);
}
template<class T>
inline T &any_cast(boost::any &value) {
return boost::any_cast<T&>(value);
}
class Property;
class Document;
class PropertyContainer;
class DocumentObject;
class ExpressionVisitor;
AppExport std::string quote(const std::string &input);
AppExport std::string quote(const std::string &input, bool toPython=false);
// Unfortunately VS2013 does not support default move constructor, so we have
// to implement them manually
#define FC_DEFAULT_CTORS(_t) \
_t(const _t &) = default;\
_t &operator=(const _t &) = default;\
_t(_t &&other) { *this = std::move(other); }\
_t &operator=(_t &&other)
class AppExport ObjectIdentifier {
public:
class AppExport DocumentMapper {
public:
DocumentMapper(const std::map<std::string,std::string> &);
~DocumentMapper();
};
class String {
friend class ObjectIdentifier;
public:
// Constructor
String(const std::string & s = "", bool _isRealString = false, bool _forceIdentifier = false) : str(s), isString(_isRealString), forceIdentifier(_forceIdentifier) { }
String(const std::string & s = "", bool _isRealString = false, bool _forceIdentifier = false)
: str(s), isString(_isRealString), forceIdentifier(_forceIdentifier)
{ }
String(std::string &&s, bool _isRealString = false, bool _forceIdentifier = false)
: str(std::move(s)), isString(_isRealString), forceIdentifier(_forceIdentifier)
{ }
FC_DEFAULT_CTORS(String) {
str = std::move(other.str);
isString = other.isString;
forceIdentifier = other.forceIdentifier;
return *this;
}
// Accessors
/** Returns the string */
std::string getString() const { return str; }
const std::string &getString() const { return str; }
/** Return true is string need to be quoted */
bool isRealString() const { return isString; }
@@ -64,7 +111,7 @@ public:
bool isForceIdentifier() const { return forceIdentifier; }
/** Returns a possibly quoted string */
std::string toString() const;
std::string toString(bool toPython=false) const;
// Operators
@@ -82,6 +129,8 @@ public:
bool operator>(const String & other) const { return str > other.str; }
void checkImport(const App::DocumentObject *owner,
const App::DocumentObject *obj=0, String *objName=0);
private:
std::string str;
@@ -103,22 +152,38 @@ public:
enum typeEnum {
SIMPLE,
MAP,
ARRAY
ARRAY,
RANGE,
} ;
public:
// Constructors
FC_DEFAULT_CTORS(Component) {
name = std::move(other.name);
type = other.type;
begin = other.begin;
end = other.end;
step = other.step;
return *this;
}
Component(const String &_component, typeEnum _type = SIMPLE, int _index = -1, String _key = String());
Component(const String &_name = String(), typeEnum _type=SIMPLE,
int begin=INT_MAX, int end=INT_MAX, int step=1);
Component(String &&_name, typeEnum _type=SIMPLE,
int begin=INT_MAX, int end=INT_MAX, int step=1);
static Component SimpleComponent(const char * _component);
static Component SimpleComponent(const String & _component);
static Component SimpleComponent(String &&_component);
static Component ArrayComponent(const String &_component, int _index);
static Component ArrayComponent(int _index);
static Component MapComponent(const String &_component, const String &_key);
static Component RangeComponent(int _begin, int _end = INT_MAX, int _step=1);
static Component MapComponent(const String &_key);
static Component MapComponent(String &&_key);
// Type queries
@@ -128,93 +193,175 @@ public:
bool isArray() const { return type == ARRAY; }
bool isRange() const { return type == RANGE; }
// Accessors
std::string toString() const;
void toString(std::ostream &ss, bool toPython=false) const;
std::string getName() const { return name.getString(); }
const std::string &getName() const { return name.getString(); }
std::size_t getIndex() const { return static_cast<std::size_t>(index); }
int getIndex() const {return begin;}
size_t getIndex(size_t count) const;
String getKey() const { return key; }
bool getKeyIsString() const { return keyIsString; }
int getBegin() const { return begin; }
int getEnd() const { return end; }
int getStep() const { return step; }
// Operators
bool operator==(const Component & other) const;
bool operator<(const Component & other) const;
Py::Object get(const Py::Object &pyobj) const;
void set(Py::Object &pyobj, const Py::Object &value) const;
void del(Py::Object &pyobj) const;
private:
String name;
typeEnum type;
int index;
String key;
bool keyIsString;
int begin;
int end;
int step;
friend class ObjectIdentifier;
};
ObjectIdentifier(const App::PropertyContainer * _owner = 0, const std::string & property = std::string());
static Component SimpleComponent(const char * _component)
{return Component::SimpleComponent(_component);}
ObjectIdentifier(const App::Property & prop);
static Component SimpleComponent(const String & _component)
{return Component::SimpleComponent(_component);}
static Component SimpleComponent(String &&_component)
{return Component::SimpleComponent(std::move(_component));}
static Component ArrayComponent(int _index)
{return Component::ArrayComponent(_index); }
static Component RangeComponent(int _begin, int _end = INT_MAX, int _step=1)
{return Component::RangeComponent(_begin,_end,_step);}
static Component MapComponent(const String &_key)
{return Component::MapComponent(_key);}
static Component MapComponent(String &&_key)
{return Component::MapComponent(_key);}
ObjectIdentifier(const App::PropertyContainer * _owner = 0,
const std::string & property = std::string(), int index=INT_MAX);
ObjectIdentifier(const App::PropertyContainer * _owner, bool localProperty);
ObjectIdentifier(const App::Property & prop, int index=INT_MAX);
FC_DEFAULT_CTORS(ObjectIdentifier) {
owner = other.owner;
documentName = std::move(other.documentName);
documentObjectName = std::move(other.documentObjectName);
subObjectName = std::move(other.subObjectName);
shadowSub = std::move(other.shadowSub);
components = std::move(other.components);
documentNameSet = other.documentNameSet;
documentObjectNameSet = other.documentObjectNameSet;
localProperty = other.localProperty;
_cache = std::move(other._cache);
_hash = std::move(other._hash);
return *this;
}
virtual ~ObjectIdentifier() {}
App::DocumentObject *getOwner() const { return owner; }
// Components
void addComponent(const Component &c) { components.push_back(c); }
void addComponent(const Component &c) {
components.push_back(c);
_cache.clear();
}
// Components
void addComponent(Component &&c) {
components.push_back(std::move(c));
_cache.clear();
}
std::string getPropertyName() const;
template<typename C>
void addComponents(const C &cs) { components.insert(components.end(), cs.begin(), cs.end()); }
const std::string getPropertyName() const;
const Component & getPropertyComponent(int i) const;
std::string getSubPathStr() const;
Component & getPropertyComponent(int i);
std::vector<Component> getPropertyComponents() const;
const std::vector<Component> &getComponents() const { return components; }
std::string getSubPathStr(bool toPython=false) const;
int numComponents() const;
int numSubComponents() const;
virtual std::string toString() const;
const std::string &toString() const;
std::string toPersistentString() const;
std::string toEscapedString() const;
App::Property *getProperty() const;
bool isTouched() const;
App::Property *getProperty(int *ptype=0) const;
App::ObjectIdentifier canonicalPath() const;
// Document-centric functions
void setDocumentName(const String & name, bool force = false);
void setDocumentName(String &&name, bool force = false);
const String getDocumentName() const;
String getDocumentName() const;
void setDocumentObjectName(const String & name, bool force = false);
void setDocumentObjectName(String &&name, bool force = false,
String &&subname = String(), bool checkImport=false);
const String getDocumentObjectName() const;
void setDocumentObjectName(const App::DocumentObject *obj, bool force = false,
String &&subname = String(), bool checkImport=false);
bool validDocumentObjectRename(const std::string &oldName, const std::string &newName);
bool hasDocumentObjectName(bool forced=false) const;
bool renameDocumentObject(const std::string & oldName, const std::string & newName);
bool isLocalProperty() const { return localProperty; }
bool validDocumentRename(const std::string &oldName, const std::string &newName);
String getDocumentObjectName() const;
bool renameDocument(const std::string &oldName, const std::string &newName);
const std::string &getSubObjectName(bool newStyle) const;
const std::string &getSubObjectName() const;
App::Document *getDocument(String name = String()) const;
typedef std::map<std::pair<App::DocumentObject*,std::string>,std::string> SubNameMap;
void importSubNames(const SubNameMap &subNameMap);
bool updateLabelReference(App::DocumentObject *, const std::string &, const char *);
bool relabeledDocument(ExpressionVisitor &v, const std::string &oldLabel, const std::string &newLabel);
std::pair<App::DocumentObject*,std::string> getDep(std::vector<std::string> *labels=0) const;
App::Document *getDocument(String name = String(), bool *ambiguous=0) const;
App::DocumentObject *getDocumentObject() const;
std::vector<std::string> getStringList() const;
App::ObjectIdentifier relativeTo(const App::ObjectIdentifier & other) const;
bool replaceObject(ObjectIdentifier &res, const App::DocumentObject *parent,
App::DocumentObject *oldObj, App::DocumentObject *newObj) const;
// Operators
App::ObjectIdentifier & operator<<(const Component & value);
App::ObjectIdentifier & operator<<(Component &&value);
bool operator==(const ObjectIdentifier & other) const;
@@ -224,12 +371,14 @@ public:
// Getter
boost::any getValue() const;
App::any getValue(bool pathValue=false, bool *isPseudoProperty=0) const;
Py::Object getPyValue(bool pathValue=false, bool *isPseudoProperty=0) const;
// Setter; is const because it does not alter the object state,
// but does have a aide effect.
void setValue(const boost::any & value) const;
void setValue(const App::any & value) const;
// Static functions
@@ -237,6 +386,16 @@ public:
std::string resolveErrorString() const;
bool adjustLinks(ExpressionVisitor &v, const std::set<App::DocumentObject *> &inList);
bool updateElementReference(ExpressionVisitor &v, App::DocumentObject *feature=0, bool reverse=false);
void resolveAmbiguity();
bool verify(const App::Property &prop, bool silent=false) const;
std::size_t hash() const;
protected:
struct ResolveResults {
@@ -248,29 +407,72 @@ protected:
String resolvedDocumentName;
App::DocumentObject * resolvedDocumentObject;
String resolvedDocumentObjectName;
String subObjectName;
App::DocumentObject * resolvedSubObject;
App::Property * resolvedProperty;
std::string propertyName;
int propertyType;
std::bitset<32> flags;
std::string resolveErrorString() const;
void getProperty(const ObjectIdentifier &oi);
};
std::string getPythonAccessor() const;
friend struct ResolveResults;
App::Property *resolveProperty(const App::DocumentObject *obj,
const char *propertyName, App::DocumentObject *&sobj,int &ptype) const;
void getSubPathStr(std::ostream &ss, const ResolveResults &result, bool toPython=false) const;
Py::Object access(const ResolveResults &rs, Py::Object *value=0) const;
void resolve(ResolveResults & results) const;
void resolveAmbiguity(ResolveResults &results);
App::DocumentObject *getDocumentObject(const App::Document *doc, const String &name, bool &byIdentifier) const;
static App::DocumentObject *getDocumentObject(
const App::Document *doc, const String &name, std::bitset<32> &flags);
const App::PropertyContainer * owner;
App::DocumentObject * owner;
String documentName;
bool documentNameSet;
String documentObjectName;
bool documentObjectNameSet;
String subObjectName;
std::pair<std::string,std::string> shadowSub;
std::vector<Component> components;
bool documentNameSet;
bool documentObjectNameSet;
bool localProperty;
private:
std::string _cache; // Cached string represstation of this identifier
std::size_t _hash; // Cached hash of this string
};
std::size_t AppExport hash_value(const App::ObjectIdentifier & path);
inline std::size_t hash_value(const App::ObjectIdentifier & path) {
return path.hash();
}
/** Helper function to convert Python object to/from App::any
*
* WARNING! Must hold Python global interpreter lock before calling these
* functions
*/
//@{
App::any AppExport pyObjectToAny(Py::Object pyobj, bool check=true);
Py::Object AppExport pyObjectFromAny(const App::any &value);
//@}
}
namespace std {
template<>
struct hash<App::ObjectIdentifier> {
typedef App::ObjectIdentifier argument_type;
typedef std::size_t result_type;
inline result_type operator()(argument_type const& s) const {
return s.hash();
}
};
}
#endif
+9
View File
@@ -26,6 +26,7 @@
// Std. configurations
#include <Base/Exception.h>
#include <Base/Persistence.h>
#ifndef BOOST_105400
#include <boost/any.hpp>
@@ -35,6 +36,9 @@
#include <string>
#include <bitset>
namespace Py {
class Object;
}
namespace App
{
@@ -140,6 +144,11 @@ public:
/// Get value of property
virtual const boost::any getPathValue(const App::ObjectIdentifier & path) const;
/// Get Python value of property
virtual bool getPyPathValue(const App::ObjectIdentifier &, Py::Object &) const {
return false;
}
/// Convert p to a canonical representation of it
virtual App::ObjectIdentifier canonicalPath(const App::ObjectIdentifier & p) const;
+383 -381
View File
@@ -27,6 +27,7 @@
#include <Base/Interpreter.h>
#include <Base/Writer.h>
#include <Base/Reader.h>
#include <Base/Tools.h>
#include "Expression.h"
#include "ExpressionVisitors.h"
#include "PropertyExpressionEngine.h"
@@ -42,44 +43,44 @@ using namespace App;
using namespace Base;
using namespace boost;
class ObjectDeletedExpressionVisitor : public ExpressionVisitor {
public:
TYPESYSTEM_SOURCE_ABSTRACT(App::PropertyExpressionContainer , App::PropertyXLinkContainer);
ObjectDeletedExpressionVisitor(const App::DocumentObject * _obj)
: obj(_obj)
, found(false)
{
static std::set<PropertyExpressionContainer*> _ExprContainers;
PropertyExpressionContainer::PropertyExpressionContainer() {
static bool inited;
if(!inited) {
inited = true;
GetApplication().signalRelabelDocument.connect(PropertyExpressionContainer::slotRelabelDocument);
}
_ExprContainers.insert(this);
}
/**
* @brief Visit each node in the expression, and if it is a VariableExpression object check if it references obj
* @param node Node to visit
*/
PropertyExpressionContainer::~PropertyExpressionContainer() {
_ExprContainers.erase(this);
}
void visit(Expression * node) {
VariableExpression *expr = freecad_dynamic_cast<VariableExpression>(node);
if (expr && expr->getPath().getDocumentObject() == obj)
found = true;
void PropertyExpressionContainer::slotRelabelDocument(const App::Document &doc) {
// For use a private _ExprContainers to track all living
// PropertyExpressionContainer including those inside undo/redo stack,
// because document relabel is not undoable/redoable.
if(doc.getOldLabel() != doc.Label.getValue()) {
for(auto prop : _ExprContainers)
prop->onRelabeledDocument(doc);
}
}
bool isFound() const { return found; }
///////////////////////////////////////////////////////////////////////////////////////
private:
const App::DocumentObject * obj;
bool found;
};
TYPESYSTEM_SOURCE(App::PropertyExpressionEngine , App::Property);
TYPESYSTEM_SOURCE(App::PropertyExpressionEngine , App::PropertyExpressionContainer);
/**
* @brief Construct a new PropertyExpressionEngine object.
*/
PropertyExpressionEngine::PropertyExpressionEngine()
: Property()
, AtomicPropertyChangeInterface()
, running(false)
: running(false)
, validator(0)
{
}
@@ -110,81 +111,74 @@ Property *PropertyExpressionEngine::Copy() const
PropertyExpressionEngine * engine = new PropertyExpressionEngine();
for (ExpressionMap::const_iterator it = expressions.begin(); it != expressions.end(); ++it)
engine->expressions[it->first] = ExpressionInfo(boost::shared_ptr<Expression>(it->second.expression->copy()), it->second.comment.c_str());
engine->expressions[it->first] = ExpressionInfo(boost::shared_ptr<Expression>(it->second.expression->copy()));
engine->validator = validator;
return engine;
}
void PropertyExpressionEngine::hasSetValue()
{
App::DocumentObject *owner = dynamic_cast<App::DocumentObject*>(getContainer());
if(!owner || !owner->getNameInDocument() || owner->isRestoring() || testFlag(LinkDetached)) {
PropertyExpressionContainer::hasSetValue();
return;
}
std::set<App::DocumentObject*> deps;
std::vector<std::string> labels;
unregisterElementReference();
UpdateElementReferenceExpressionVisitor<PropertyExpressionEngine> v(*this);
for(auto &e : expressions) {
auto expr = e.second.expression;
if(expr) {
expr->getDepObjects(deps,&labels);
if(!restoring)
expr->visit(v);
}
}
registerLabelReferences(std::move(labels));
updateDeps(std::move(deps));
PropertyExpressionContainer::hasSetValue();
}
void PropertyExpressionEngine::Paste(const Property &from)
{
const PropertyExpressionEngine * fromee = static_cast<const PropertyExpressionEngine*>(&from);
AtomicPropertyChange signaller(*this);
#ifndef USE_OLD_DAG
//maintain backlinks, verify that this property is owned by a DocumentObject
App::DocumentObject* parent = dynamic_cast<App::DocumentObject*>(getContainer());
if (parent) {
ExpressionMap::const_iterator i = expressions.begin();
while (i != expressions.end()) {
std::set<ObjectIdentifier> deps;
i->second.expression->getDeps(deps);
std::set<ObjectIdentifier>::const_iterator j = deps.begin();
while (j != deps.end()) {
const ObjectIdentifier & p = *j;
DocumentObject* docObj = p.getDocumentObject();
if (docObj && (docObj != parent))
docObj->_removeBackLink(parent);
++j;
}
++i;
}
}
#endif
expressions.clear();
for (ExpressionMap::const_iterator it = fromee->expressions.begin(); it != fromee->expressions.end(); ++it) {
expressions[it->first] = ExpressionInfo(boost::shared_ptr<Expression>(it->second.expression->copy()), it->second.comment.c_str());
#ifndef USE_OLD_DAG
if (parent) {
//maintain backlinks
std::set<ObjectIdentifier> deps;
it->second.expression->getDeps(deps);
std::set<ObjectIdentifier>::const_iterator j = deps.begin();
while (j != deps.end()) {
const ObjectIdentifier & p = *j;
DocumentObject* docObj = p.getDocumentObject();
if (docObj && (docObj != parent))
docObj->_addBackLink(parent);
++j;
}
}
#endif
expressionChanged(it->first);
for(auto &e : fromee->expressions) {
expressions[e.first] = ExpressionInfo(
boost::shared_ptr<Expression>(e.second.expression->copy()));
expressionChanged(e.first);
}
validator = fromee->validator;
signaller.tryInvoke();
}
void PropertyExpressionEngine::Save(Base::Writer &writer) const
{
writer.Stream() << writer.ind() << "<ExpressionEngine count=\"" << expressions.size() <<"\">" << std::endl;
writer.incInd();
writer.Stream() << writer.ind() << "<ExpressionEngine count=\"" << expressions.size();
if(PropertyExpressionContainer::_XLinks.empty()) {
writer.Stream() << "\">" << std::endl;
writer.incInd();
} else {
writer.Stream() << "\" xlink=\"1\">" << std::endl;
writer.incInd();
PropertyExpressionContainer::Save(writer);
}
for (ExpressionMap::const_iterator it = expressions.begin(); it != expressions.end(); ++it) {
writer.Stream() << writer.ind() << "<Expression path=\"" << Property::encodeAttribute(it->first.toString()) <<"\"" <<
" expression=\"" << Property::encodeAttribute(it->second.expression->toString()) << "\"";
if (it->second.comment.size() > 0)
writer.Stream() << " comment=\"" << Property::encodeAttribute(it->second.comment) << "\"";
writer.Stream() << writer.ind() << "<Expression path=\""
<< Property::encodeAttribute(it->first.toString()) <<"\" expression=\""
<< Property::encodeAttribute(it->second.expression->toString(true)) << "\"";
if (it->second.expression->comment.size() > 0)
writer.Stream() << " comment=\""
<< Property::encodeAttribute(it->second.expression->comment) << "\"";
writer.Stream() << "/>" << std::endl;
}
writer.decInd();
@@ -194,19 +188,22 @@ void PropertyExpressionEngine::Save(Base::Writer &writer) const
void PropertyExpressionEngine::Restore(Base::XMLReader &reader)
{
reader.readElement("ExpressionEngine");
int count = reader.getAttributeAsFloat("count");
restoredExpressions.clear();
if(reader.hasAttribute("xlink") && reader.getAttributeAsInteger("xlink"))
PropertyExpressionContainer::Restore(reader);
restoredExpressions.reset(new std::vector<RestoredExpression>);
restoredExpressions->reserve(count);
for (int i = 0; i < count; ++i) {
DocumentObject * docObj = freecad_dynamic_cast<DocumentObject>(getContainer());
reader.readElement("Expression");
ObjectIdentifier path = ObjectIdentifier::parse(docObj, reader.getAttribute("path"));
boost::shared_ptr<Expression> expression(ExpressionParser::parse(docObj, reader.getAttribute("expression")));
const char * comment = reader.hasAttribute("comment") ? reader.getAttribute("comment") : 0;
restoredExpressions[path] = ExpressionInfo(expression, comment);
restoredExpressions->emplace_back();
auto &info = restoredExpressions->back();
info.path = reader.getAttribute("path");
info.expr = reader.getAttribute("expression");
if(reader.hasAttribute("comment"))
info.comment = reader.getAttribute("comment");
}
reader.readEndElement("ExpressionEngine");
@@ -227,8 +224,6 @@ void PropertyExpressionEngine::buildGraphStructures(const ObjectIdentifier & pat
boost::unordered_map<int, ObjectIdentifier> & revNodes,
std::vector<Edge> & edges) const
{
std::set<ObjectIdentifier> deps;
/* Insert target property into nodes structure */
if (nodes.find(path) == nodes.end()) {
int s = nodes.size();
@@ -239,26 +234,20 @@ void PropertyExpressionEngine::buildGraphStructures(const ObjectIdentifier & pat
else
revNodes[nodes[path]] = path;
/* Get the dependencies for this expression */
expression->getDeps(deps);
/* Insert dependencies into nodes structure */
std::set<ObjectIdentifier>::const_iterator di = deps.begin();
while (di != deps.end()) {
Property * prop = di->getProperty();
if (prop) {
ObjectIdentifier cPath(di->canonicalPath());
if (nodes.find(cPath) == nodes.end()) {
int s = nodes.size();
nodes[cPath] = s;
for(auto &dep : expression->getDeps()) {
for(auto &info : dep.second) {
if(info.first.empty())
continue;
for(auto &oid : info.second) {
ObjectIdentifier cPath(oid.canonicalPath());
if (nodes.find(cPath) == nodes.end()) {
int s = nodes.size();
nodes[cPath] = s;
}
edges.push_back(std::make_pair(nodes[path], nodes[cPath]));
}
edges.push_back(std::make_pair(nodes[path], nodes[cPath]));
}
++di;
}
}
@@ -268,7 +257,7 @@ void PropertyExpressionEngine::buildGraphStructures(const ObjectIdentifier & pat
* @return New ObjectIdentifier
*/
const ObjectIdentifier PropertyExpressionEngine::canonicalPath(const ObjectIdentifier &p) const
ObjectIdentifier PropertyExpressionEngine::canonicalPath(const ObjectIdentifier &p) const
{
DocumentObject * docObj = freecad_dynamic_cast<DocumentObject>(getContainer());
@@ -276,15 +265,15 @@ const ObjectIdentifier PropertyExpressionEngine::canonicalPath(const ObjectIdent
if (!docObj)
throw Base::RuntimeError("PropertyExpressionEngine must be owned by a DocumentObject.");
Property * prop = p.getProperty();
int ptype;
Property * prop = p.getProperty(&ptype);
// p pointing to a property...?
if (!prop)
throw Base::RuntimeError("Property not found");
throw Base::RuntimeError(p.resolveErrorString().c_str());
// ... in the same container as I?
if (prop->getContainer() != getContainer())
throw Base::RuntimeError("Property does not belong to same container as PropertyExpressionEngine");
if(ptype || prop->getContainer()!=getContainer())
return p;
// In case someone calls this with p pointing to a PropertyExpressionEngine for some reason
if (prop->isDerivedFrom(PropertyExpressionEngine::classTypeId))
@@ -304,61 +293,37 @@ size_t PropertyExpressionEngine::numExpressions() const
return expressions.size();
}
/**
* @brief Slot called when a document object is renamed.
* @param obj Renamed object
*/
void PropertyExpressionEngine::slotObjectRenamed(const DocumentObject &obj)
{
#ifdef FC_PROPERTYEXPRESSIONENGINE_LOG
std::clog << "Object " << obj.getOldLabel() << " renamed to " << obj.Label.getValue() << std::endl;
#endif
DocumentObject * docObj = freecad_dynamic_cast<DocumentObject>(getContainer());
/* In a document object, and on undo stack? */
if (!docObj || docObj->getNameInDocument() == 0)
return;
RelabelDocumentObjectExpressionVisitor<PropertyExpressionEngine> v(*this, obj.getOldLabel(), obj.Label.getStrValue());
for (ExpressionMap::iterator it = expressions.begin(); it != expressions.end(); ++it) {
bool changed = v.getChanged();
it->second.expression->visit(v);
if (changed != v.getChanged())
expressionChanged(it->first);
}
}
void PropertyExpressionEngine::slotObjectDeleted(const DocumentObject &obj)
void PropertyExpressionEngine::afterRestore()
{
DocumentObject * docObj = freecad_dynamic_cast<DocumentObject>(getContainer());
if(restoredExpressions && docObj) {
Base::FlagToggler<bool> flag(restoring);
AtomicPropertyChange signaller(*this);
/* In a document object, and on undo stack? */
if (!docObj || docObj->getNameInDocument() == 0)
return;
PropertyExpressionContainer::afterRestore();
ObjectIdentifier::DocumentMapper mapper(this->_DocMap);
ObjectDeletedExpressionVisitor v(&obj);
for (ExpressionMap::iterator it = expressions.begin(); it != expressions.end(); ++it) {
it->second.expression->visit(v);
if (v.isFound()) {
touch(); // Touch to force recompute; that will trigger a proper error
return;
for(auto &info : *restoredExpressions) {
ObjectIdentifier path = ObjectIdentifier::parse(docObj, info.path);
boost::shared_ptr<Expression> expression(Expression::parse(docObj, info.expr.c_str()));
if(expression)
expression->comment = std::move(info.comment);
setValue(path, expression);
}
signaller.tryInvoke();
}
restoredExpressions.reset();
}
void PropertyExpressionEngine::onDocumentRestored()
{
AtomicPropertyChange signaller(*this);
for (ExpressionMap::iterator it = restoredExpressions.begin(); it != restoredExpressions.end(); ++it)
setValue(it->first, it->second.expression, it->second.comment.size() > 0 ? it->second.comment.c_str() : 0);
void PropertyExpressionEngine::onContainerRestored() {
Base::FlagToggler<bool> flag(restoring);
unregisterElementReference();
UpdateElementReferenceExpressionVisitor<PropertyExpressionEngine> v(*this);
for(auto &e : expressions) {
auto expr = e.second.expression;
if(expr)
expr->visit(v);
}
}
/**
@@ -387,7 +352,7 @@ const boost::any PropertyExpressionEngine::getPathValue(const App::ObjectIdentif
* @param comment Optional comment.
*/
void PropertyExpressionEngine::setValue(const ObjectIdentifier & path, boost::shared_ptr<Expression> expr, const char *comment)
void PropertyExpressionEngine::setValue(const ObjectIdentifier & path, boost::shared_ptr<Expression> expr)
{
ObjectIdentifier usePath(canonicalPath(path));
const Property * prop = usePath.getProperty();
@@ -402,83 +367,17 @@ void PropertyExpressionEngine::setValue(const ObjectIdentifier & path, boost::sh
if (expr) {
std::string error = validateExpression(usePath, expr);
if (error.size() > 0)
throw Base::RuntimeError(error.c_str());
AtomicPropertyChange signaller(*this);
#ifndef USE_OLD_DAG
// When overriding an ObjectIdentifier key then first remove
// the dependency caused by the expression as otherwise it happens
// that the same object dependency is added twice for the same
// identifier. This makes it impossible to properly clear dependencies
// and thus leads to topological errors on recompute.
//
// Verify that this property is owned by a DocumentObject
App::DocumentObject* parent = dynamic_cast<App::DocumentObject*>(getContainer());
if (parent) {
if (it != expressions.end() && it->second.expression) {
std::set<ObjectIdentifier> deps;
it->second.expression->getDeps(deps);
std::set<ObjectIdentifier>::const_iterator j = deps.begin();
while (j != deps.end()) {
const ObjectIdentifier & p = *j;
DocumentObject* docObj = p.getDocumentObject();
if (docObj && (docObj != parent))
docObj->_removeBackLink(parent);
++j;
}
}
}
#endif
expressions[usePath] = ExpressionInfo(expr, comment);
#ifndef USE_OLD_DAG
//maintain the backlinks in the documentobject graph datastructure
if (parent) {
std::set<ObjectIdentifier> deps;
expr->getDeps(deps);
std::set<ObjectIdentifier>::const_iterator j = deps.begin();
while (j != deps.end()) {
const ObjectIdentifier & p = *j;
DocumentObject* docObj = p.getDocumentObject();
if (docObj && (docObj != parent))
docObj->_addBackLink(parent);
++j;
}
}
#endif
expressions[usePath] = ExpressionInfo(expr);
expressionChanged(usePath);
}
else {
signaller.tryInvoke();
} else {
AtomicPropertyChange signaller(*this);
#ifndef USE_OLD_DAG
//verify that this property is owned by a DocumentObject
//verify that the ObjectIdentifier usePath is part of the expression map and
//that the expression is not null
App::DocumentObject* parent = dynamic_cast<App::DocumentObject*>(getContainer());
if (parent && it != expressions.end() && it->second.expression) {
//maintain the backlinks in the documentobject graph datastructure
std::set<ObjectIdentifier> deps;
it->second.expression->getDeps(deps);
std::set<ObjectIdentifier>::const_iterator j = deps.begin();
while (j != deps.end()) {
const ObjectIdentifier & p = *j;
DocumentObject* docObj = p.getDocumentObject();
if (docObj && (docObj != parent))
docObj->_removeBackLink(parent);
++j;
}
}
#endif
expressions.erase(usePath);
expressionChanged(usePath);
signaller.tryInvoke();
}
}
@@ -509,14 +408,29 @@ struct cycle_detector : public boost::dfs_visitor<> {
*/
void PropertyExpressionEngine::buildGraph(const ExpressionMap & exprs,
boost::unordered_map<int, ObjectIdentifier> & revNodes, DiGraph & g) const
boost::unordered_map<int, ObjectIdentifier> & revNodes,
DiGraph & g, ExecuteOption option) const
{
boost::unordered_map<ObjectIdentifier, int> nodes;
std::vector<Edge> edges;
// Build data structure for graph
for (ExpressionMap::const_iterator it = exprs.begin(); it != exprs.end(); ++it)
for (ExpressionMap::const_iterator it = exprs.begin(); it != exprs.end(); ++it) {
if(option!=ExecuteAll) {
auto prop = it->first.getProperty();
if(!prop)
throw Base::RuntimeError("Path does not resolve to a property.");
bool is_output = prop->testStatus(App::Property::Output)||(prop->getType()&App::Prop_Output);
if((is_output && option==ExecuteNonOutput) || (!is_output && option==ExecuteOutput))
continue;
if(option == ExecuteOnRestore
&& !prop->testStatus(Property::Transient)
&& !(prop->getType() & Prop_Transient)
&& !prop->testStatus(Property::EvalOnRestore))
continue;
}
buildGraphStructures(it->first, it->second.expression, nodes, revNodes, edges);
}
// Create graph
g = DiGraph(revNodes.size());
@@ -544,13 +458,13 @@ void PropertyExpressionEngine::buildGraph(const ExpressionMap & exprs,
* order, in case properties depends on each other.
*/
std::vector<App::ObjectIdentifier> PropertyExpressionEngine::computeEvaluationOrder()
std::vector<App::ObjectIdentifier> PropertyExpressionEngine::computeEvaluationOrder(ExecuteOption option)
{
std::vector<App::ObjectIdentifier> evaluationOrder;
boost::unordered_map<int, ObjectIdentifier> revNodes;
DiGraph g;
buildGraph(expressions, revNodes, g);
buildGraph(expressions, revNodes, g, option);
/* Compute evaluation order for expressions */
std::vector<int> c;
@@ -569,7 +483,7 @@ std::vector<App::ObjectIdentifier> PropertyExpressionEngine::computeEvaluationOr
* @return StdReturn on success.
*/
DocumentObjectExecReturn *App::PropertyExpressionEngine::execute()
DocumentObjectExecReturn *App::PropertyExpressionEngine::execute(ExecuteOption option, bool *touched)
{
DocumentObject * docObj = freecad_dynamic_cast<DocumentObject>(getContainer());
@@ -579,6 +493,24 @@ DocumentObjectExecReturn *App::PropertyExpressionEngine::execute()
if (running)
return DocumentObject::StdReturn;
if(option == ExecuteOnRestore) {
bool found = false;
for(auto &e : expressions) {
auto prop = e.first.getProperty();
if(!prop)
continue;
if(prop->testStatus(App::Property::Transient)
|| (prop->getType()&App::Prop_Transient)
|| prop->testStatus(App::Property::EvalOnRestore))
{
found = true;
break;
}
}
if(!found)
return DocumentObject::StdReturn;
}
/* Resetter class, to ensure that the "running" variable gets set to false, even if
* an exception is thrown.
*/
@@ -595,7 +527,7 @@ DocumentObjectExecReturn *App::PropertyExpressionEngine::execute()
resetter r(running);
// Compute evaluation order
std::vector<App::ObjectIdentifier> evaluationOrder = computeEvaluationOrder();
std::vector<App::ObjectIdentifier> evaluationOrder = computeEvaluationOrder(option);
std::vector<ObjectIdentifier>::const_iterator it = evaluationOrder.begin();
#ifdef FC_PROPERTYEXPRESSIONENGINE_LOG
@@ -603,7 +535,7 @@ DocumentObjectExecReturn *App::PropertyExpressionEngine::execute()
#endif
/* Evaluate the expressions, and update properties */
while (it != evaluationOrder.end()) {
for (;it != evaluationOrder.end();++it) {
// Get property to update
Property * prop = it->getProperty();
@@ -617,69 +549,28 @@ DocumentObjectExecReturn *App::PropertyExpressionEngine::execute()
if (parent != docObj)
throw Base::RuntimeError("Invalid property owner.");
// Evaluate expression
std::unique_ptr<Expression> e(expressions[*it].expression->eval());
#ifdef FC_PROPERTYEXPRESSIONENGINE_LOG
{
Base::Quantity q;
boost::any value = e->getValueAsAny();
if (value.type() == typeid(Base::Quantity))
q = boost::any_cast<Base::Quantity>(value);
else if (value.type() == typeid(double))
q = boost::any_cast<double>(value);
else {
std::clog << "Unknown return value for expression.";
q = 0;
}
std::clog << "Assigning value " << q.getValue() << " to " << (*it).toString().c_str() << " (" << prop->getName() << ")" << std::endl;
}
#endif
/* Set value of property */
prop->setPathValue(*it, e->getValueAsAny());
++it;
try {
// Evaluate expression
std::unique_ptr<Expression> e(expressions[*it].expression->eval());
auto value = e->getValueAsAny();
if(option == ExecuteOnRestore && prop->testStatus(Property::EvalOnRestore)) {
if(isAnyEqual(value, prop->getPathValue(*it)))
continue;
if(touched)
*touched = true;
}
prop->setPathValue(*it, value);
}catch(Base::Exception &e) {
std::ostringstream ss;
ss << e.what() << std::endl << "in property binding '" << prop->getName() << "'";
e.setMessage(ss.str());
throw;
}
}
return DocumentObject::StdReturn;
}
/**
* @brief Find document objects that the expressions depend on.
* @param docObjs Dependencies
*/
void PropertyExpressionEngine::getDocumentObjectDeps(std::vector<DocumentObject *> &docObjs) const
{
DocumentObject * owner = freecad_dynamic_cast<DocumentObject>(getContainer());
if (owner == 0)
return;
ExpressionMap::const_iterator i = expressions.begin();
while (i != expressions.end()) {
std::set<ObjectIdentifier> deps;
i->second.expression->getDeps(deps);
std::set<ObjectIdentifier>::const_iterator j = deps.begin();
while (j != deps.end()) {
const ObjectIdentifier & p = *j;
DocumentObject* docObj = p.getDocumentObject();
if (docObj && docObj != owner)
docObjs.push_back(docObj);
++j;
}
++i;
}
}
/**
* @brief Find paths to document object.
* @param obj Document object
@@ -691,30 +582,16 @@ void PropertyExpressionEngine::getPathsToDocumentObject(DocumentObject* obj,
{
DocumentObject * owner = freecad_dynamic_cast<DocumentObject>(getContainer());
if (owner == 0)
if (owner == 0 || owner==obj)
return;
ExpressionMap::const_iterator i = expressions.begin();
while (i != expressions.end()) {
std::set<ObjectIdentifier> deps;
i->second.expression->getDeps(deps);
std::set<ObjectIdentifier>::const_iterator j = deps.begin();
while (j != deps.end()) {
const ObjectIdentifier & p = *j;
DocumentObject* docObj = p.getDocumentObject();
if (docObj == obj && docObj != owner) {
paths.push_back(i->first);
break;
}
++j;
}
++i;
for(auto &v : expressions) {
const auto &deps = v.second.expression->getDeps();
auto it = deps.find(obj);
if(it==deps.end())
continue;
for(auto &dep : it->second)
paths.insert(paths.end(),dep.second.begin(),dep.second.end());
}
}
@@ -725,48 +602,12 @@ void PropertyExpressionEngine::getPathsToDocumentObject(DocumentObject* obj,
bool PropertyExpressionEngine::depsAreTouched() const
{
ExpressionMap::const_iterator i = expressions.begin();
while (i != expressions.end()) {
std::set<ObjectIdentifier> deps;
i->second.expression->getDeps(deps);
std::set<ObjectIdentifier>::const_iterator j = deps.begin();
while (j != deps.end()) {
const ObjectIdentifier & p = *j;
Property* prop = p.getProperty();
if (prop && prop->isTouched())
return true;
++j;
}
++i;
}
for(auto obj : _Deps)
if(obj->isTouched())
return true;
return false;
}
/**
* @brief Get a map of all registered expressions.
* @return Map of expressions.
*/
boost::unordered_map<const ObjectIdentifier, const PropertyExpressionEngine::ExpressionInfo> PropertyExpressionEngine::getExpressions() const
{
boost::unordered_map<const ObjectIdentifier, const ExpressionInfo> result;
ExpressionMap::const_iterator i = expressions.begin();
while (i != expressions.end()) {
result.insert(std::make_pair(i->first, i->second));
++i;
}
return result;
}
/**
* @brief Validate the given path and expression.
* @param path Object Identifier for expression.
@@ -785,33 +626,16 @@ std::string PropertyExpressionEngine::validateExpression(const ObjectIdentifier
return error;
}
// Get dependencies from expression
std::set<App::ObjectIdentifier> exprDeps;
expr->getDeps(exprDeps);
// Get document object
DocumentObject * pathDocObj = usePath.getDocumentObject();
assert(pathDocObj);
// Check for document object dependencies
for (std::set<App::ObjectIdentifier>::const_iterator j = exprDeps.begin(); j != exprDeps.end(); ++j) {
DocumentObject * docObj = (*j).getDocumentObject();
// Skip internal dependencies;
if (docObj == pathDocObj)
continue;
// Get dependencies for the document object pointed to be *j
std::vector<DocumentObject*> targets;
targets.push_back(docObj);
// Does the dependency resolve to a document? If not, ignore it
if ((*j).getDocument()) {
std::vector<DocumentObject*> deps = (*j).getDocument()->getDependencyList(targets);
for (std::vector<DocumentObject*>::const_iterator i = deps.begin(); i != deps.end(); ++i) {
if (*i == pathDocObj)
return (*j).toString() + " reference creates a cyclic dependency.";
}
auto inList = pathDocObj->getInListEx(true);
for(auto docObj : expr->getDepObjects()) {
if(inList.count(docObj)) {
std::stringstream ss;
ss << "cyclic reference to " << docObj->getFullName();
return ss.str();
}
}
@@ -899,3 +723,181 @@ void PropertyExpressionEngine::setPyObject(PyObject *)
{
throw Base::RuntimeError("Property is read-only");
}
/* The policy implemented in the following function is to auto erase binding in
* case linked object is gone. I think it is better to cause error and get
* user's attension
*
void PropertyExpressionEngine::breakLink(App::DocumentObject *obj, bool clear) {
auto owner = dynamic_cast<App::DocumentObject*>(getContainer());
if(!owner)
return;
if(_Deps.count(obj)==0 && (!clear || obj!=owner || _Deps.empty()))
return;
AtomicPropertyChange signaler(*this);
for(auto it=expressions.begin(),itNext=it;it!=expressions.end();it=itNext) {
++itNext;
const auto &deps = it->second.expression->getDepObjects();
if(clear) {
// here means we are breaking all expression, except those that has
// no depdenecy or self dependency
if(deps.empty() || (deps.size()==1 && *deps.begin()==owner))
continue;
}else if(!deps.count(obj))
continue;
auto path = it->first;
expressions.erase(it);
expressionChanged(path);
}
}
*/
bool PropertyExpressionEngine::adjustLink(const std::set<DocumentObject*> &inList) {
auto owner = dynamic_cast<App::DocumentObject*>(getContainer());
if(!owner)
return false;
bool found = false;
for(auto obj : _Deps) {
if(inList.count(obj)) {
found = true;
break;
}
}
if(!found)
return false;
AtomicPropertyChange signaler(*this);
for(auto &v : expressions) {
try {
if(v.second.expression->adjustLinks(inList))
expressionChanged(v.first);
}catch(Base::Exception &e) {
std::ostringstream ss;
ss << "Failed to adjust link for " << owner->getFullName() << " in expression "
<< v.second.expression->toString() << ": " << e.what();
throw Base::RuntimeError(ss.str());
}
}
return true;
}
void PropertyExpressionEngine::updateElementReference(DocumentObject *feature, bool reverse, bool notify)
{
(void)notify;
if(!feature)
unregisterElementReference();
UpdateElementReferenceExpressionVisitor<PropertyExpressionEngine> v(*this,feature,reverse);
for(auto &e : expressions) {
e.second.expression->visit(v);
if(v.changed()) {
expressionChanged(e.first);
v.reset();
}
}
if(feature && v.changed()) {
auto owner = dynamic_cast<App::DocumentObject*>(getContainer());
if(owner)
owner->onUpdateElementReference(this);
}
}
bool PropertyExpressionEngine::referenceChanged() const {
return false;
}
Property *PropertyExpressionEngine::CopyOnImportExternal(
const std::map<std::string,std::string> &nameMap) const
{
std::unique_ptr<PropertyExpressionEngine> engine;
for(auto it=expressions.begin();it!=expressions.end();++it) {
boost::shared_ptr<Expression> expr(it->second.expression->importSubNames(nameMap));
if(!expr && !engine)
continue;
if(!engine) {
engine.reset(new PropertyExpressionEngine);
for(auto it2=expressions.begin();it2!=it;++it2) {
engine->expressions[it2->first] = ExpressionInfo(
boost::shared_ptr<Expression>(it2->second.expression->copy()));
}
}else if(!expr)
expr = it->second.expression;
engine->expressions[it->first] = ExpressionInfo(expr);
}
if(!engine)
return 0;
engine->validator = validator;
return engine.release();
}
Property *PropertyExpressionEngine::CopyOnLabelChange(App::DocumentObject *obj,
const std::string &ref, const char *newLabel) const
{
std::unique_ptr<PropertyExpressionEngine> engine;
for(auto it=expressions.begin();it!=expressions.end();++it) {
boost::shared_ptr<Expression> expr(it->second.expression->updateLabelReference(obj,ref,newLabel));
if(!expr && !engine)
continue;
if(!engine) {
engine.reset(new PropertyExpressionEngine);
for(auto it2=expressions.begin();it2!=it;++it2) {
engine->expressions[it2->first] = ExpressionInfo(
boost::shared_ptr<Expression>(it2->second.expression->copy()));
}
}else if(!expr)
expr = it->second.expression;
engine->expressions[it->first] = ExpressionInfo(expr);
}
if(!engine)
return 0;
engine->validator = validator;
return engine.release();
}
Property *PropertyExpressionEngine::CopyOnLinkReplace(const App::DocumentObject *parent,
App::DocumentObject *oldObj, App::DocumentObject *newObj) const
{
std::unique_ptr<PropertyExpressionEngine> engine;
for(auto it=expressions.begin();it!=expressions.end();++it) {
boost::shared_ptr<Expression> expr(
it->second.expression->replaceObject(parent,oldObj,newObj));
if(!expr && !engine)
continue;
if(!engine) {
engine.reset(new PropertyExpressionEngine);
for(auto it2=expressions.begin();it2!=it;++it2) {
engine->expressions[it2->first] = ExpressionInfo(
boost::shared_ptr<Expression>(it2->second.expression->copy()));
}
}else if(!expr)
expr = it->second.expression;
engine->expressions[it->first] = ExpressionInfo(expr);
}
if(!engine)
return 0;
engine->validator = validator;
return engine.release();
}
std::map<App::ObjectIdentifier, const App::Expression*>
PropertyExpressionEngine::getExpressions() const
{
std::map<App::ObjectIdentifier, const Expression*> res;
for(auto &v : expressions)
res[v.first] = v.second.expression.get();
return res;
}
void PropertyExpressionEngine::setExpressions(
std::map<App::ObjectIdentifier, App::ExpressionPtr> &&exprs)
{
AtomicPropertyChange signaller(*this);
for(auto &v : exprs)
setValue(v.first,std::move(v.second));
}
void PropertyExpressionEngine::onRelabeledDocument(const App::Document &doc)
{
RelabelDocumentExpressionVisitor v(doc);
for(auto &e : expressions)
e.second.expression->visit(v);
}
+69 -24
View File
@@ -28,7 +28,7 @@
#include <boost/signals2.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/topological_sort.hpp>
#include <App/Property.h>
#include <App/PropertyLinks.h>
#include <App/Expression.h>
#include <set>
@@ -44,11 +44,38 @@ class DocumentObjectExecReturn;
class ObjectIdentifier;
class Expression;
class AppExport PropertyExpressionEngine : public App::Property, private App::AtomicPropertyChangeInterface<PropertyExpressionEngine>
class AppExport PropertyExpressionContainer : public App::PropertyXLinkContainer
{
TYPESYSTEM_HEADER();
public:
PropertyExpressionContainer();
virtual ~PropertyExpressionContainer();
virtual std::map<App::ObjectIdentifier, const App::Expression*> getExpressions() const = 0;
virtual void setExpressions(std::map<App::ObjectIdentifier, App::ExpressionPtr> &&exprs) = 0;
protected:
virtual void onRelabeledDocument(const App::Document &doc) = 0;
private:
static void slotRelabelDocument(const App::Document &doc);
};
class AppExport PropertyExpressionEngine : public App::PropertyExpressionContainer,
private App::AtomicPropertyChangeInterface<PropertyExpressionEngine>
{
TYPESYSTEM_HEADER();
public:
virtual void updateElementReference(
App::DocumentObject *feature, bool reverse=false, bool notify=false) override;
virtual bool referenceChanged() const override;
virtual bool adjustLink(const std::set<App::DocumentObject *> &inList) override;
virtual Property *CopyOnImportExternal(const std::map<std::string,std::string> &nameMap) const override;
virtual Property *CopyOnLabelChange(App::DocumentObject *obj,
const std::string &ref, const char *newLabel) const override;
virtual Property *CopyOnLinkReplace(const App::DocumentObject *parent,
App::DocumentObject *oldObj, App::DocumentObject *newObj) const override;
typedef boost::function<std::string (const App::ObjectIdentifier & path, boost::shared_ptr<const App::Expression> expr)> ValidatorFunc;
@@ -58,22 +85,17 @@ public:
struct ExpressionInfo {
boost::shared_ptr<App::Expression> expression; /**< The actual expression tree */
std::string comment; /**< Optional comment for this expression */
ExpressionInfo(boost::shared_ptr<App::Expression> expression = boost::shared_ptr<App::Expression>(), const char * comment = 0) {
ExpressionInfo(boost::shared_ptr<App::Expression> expression = boost::shared_ptr<App::Expression>()) {
this->expression = expression;
if (comment)
this->comment = comment;
}
ExpressionInfo(const ExpressionInfo & other) {
expression = other.expression;
comment = other.comment;
}
ExpressionInfo & operator=(const ExpressionInfo & other) {
expression = other.expression;
comment = other.comment;
return *this;
}
};
@@ -83,6 +105,10 @@ public:
unsigned int getMemSize (void) const;
virtual std::map<App::ObjectIdentifier, const App::Expression*> getExpressions() const override;
virtual void setExpressions(std::map<App::ObjectIdentifier, App::ExpressionPtr> &&exprs) override;
virtual void onRelabeledDocument(const App::Document &doc) override;
void setValue() { } // Dummy
Property *Copy(void) const;
@@ -93,20 +119,31 @@ public:
void Restore(Base::XMLReader &reader);
void setValue(const App::ObjectIdentifier &path, boost::shared_ptr<App::Expression> expr, const char * comment = 0);
void setValue(const App::ObjectIdentifier &path, boost::shared_ptr<App::Expression> expr);
const boost::any getPathValue(const App::ObjectIdentifier & path) const;
DocumentObjectExecReturn * execute();
void getDocumentObjectDeps(std::vector<DocumentObject*> & docObjs) const;
/// Execute options
enum ExecuteOption {
/// Execute all expression
ExecuteAll,
/// Execute only output property bindings
ExecuteOutput,
/// Execute only non-output property bindings
ExecuteNonOutput,
/// Execute on document restore
ExecuteOnRestore,
};
/** Evaluate the expressions
*
* @param option: execution option, see ExecuteOption.
*/
DocumentObjectExecReturn * execute(ExecuteOption option=ExecuteAll, bool *touched=0);
void getPathsToDocumentObject(DocumentObject*, std::vector<App::ObjectIdentifier> & paths) const;
bool depsAreTouched() const;
boost::unordered_map<const App::ObjectIdentifier, const ExpressionInfo> getExpressions() const;
/* Expression validator */
void setValidator(ValidatorFunc f) { validator = f; }
@@ -116,45 +153,53 @@ public:
void renameObjectIdentifiers(const std::map<App::ObjectIdentifier, App::ObjectIdentifier> & paths);
const App::ObjectIdentifier canonicalPath(const App::ObjectIdentifier &p) const;
App::ObjectIdentifier canonicalPath(const App::ObjectIdentifier &p) const;
size_t numExpressions() const;
void slotObjectRenamed(const App::DocumentObject & obj);
void slotObjectDeleted(const DocumentObject &obj);
///signal called when an expression was changed
boost::signals2::signal<void (const App::ObjectIdentifier &)> expressionChanged;
void onDocumentRestored();
virtual void afterRestore() override;
virtual void onContainerRestored() override;
/* Python interface */
PyObject *getPyObject(void);
void setPyObject(PyObject *);
protected:
virtual void hasSetValue() override;
private:
typedef boost::adjacency_list< boost::listS, boost::vecS, boost::directedS > DiGraph;
typedef std::pair<int, int> Edge;
typedef boost::unordered_map<const App::ObjectIdentifier, ExpressionInfo> ExpressionMap;
std::vector<App::ObjectIdentifier> computeEvaluationOrder();
std::vector<App::ObjectIdentifier> computeEvaluationOrder(ExecuteOption option);
void buildGraphStructures(const App::ObjectIdentifier &path,
const boost::shared_ptr<Expression> expression, boost::unordered_map<App::ObjectIdentifier, int> &nodes,
boost::unordered_map<int, App::ObjectIdentifier> &revNodes, std::vector<Edge> &edges) const;
void buildGraph(const ExpressionMap &exprs,
boost::unordered_map<int, App::ObjectIdentifier> &revNodes, DiGraph &g) const;
boost::unordered_map<int, App::ObjectIdentifier> &revNodes,
DiGraph &g, ExecuteOption option=ExecuteAll) const;
bool running; /**< Boolean used to avoid loops */
bool restoring = false;
ExpressionMap expressions; /**< Stored expressions */
ValidatorFunc validator; /**< Valdiator functor */
ExpressionMap restoredExpressions; /**< Expressions are read from file to this map first before they are validated and inserted into the actual map */
struct RestoredExpression {
std::string path;
std::string expr;
std::string comment;
};
/**< Expressions are read from file to this map first before they are validated and inserted into the actual map */
std::unique_ptr<std::vector<RestoredExpression> > restoredExpressions;
friend class AtomicPropertyChange;
+83 -66
View File
@@ -39,7 +39,10 @@
#include <Base/VectorPy.h>
#include <Base/MatrixPy.h>
#include <Base/PlacementPy.h>
#include <Base/QuantityPy.h>
#include "Document.h"
#include "DocumentObject.h"
#include "Placement.h"
#include "PropertyGeo.h"
#include "ObjectIdentifier.h"
@@ -193,14 +196,46 @@ void PropertyVector::Paste(const Property &from)
void PropertyVector::getPaths(std::vector<ObjectIdentifier> &paths) const
{
paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("x")));
paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("y")));
paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("z")));
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("x")));
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("y")));
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("z")));
}
const boost::any PropertyVector::getPathValue(const ObjectIdentifier &path) const
{
Base::Unit unit = getUnit();
if(!unit.isEmpty()) {
std::string p = path.getSubPathStr();
if (p == ".x" || p == ".y" || p == ".z") {
// Convert double to quantity
return Base::Quantity(boost::any_cast<double>(Property::getPathValue(path)), unit);
}
}
return Property::getPathValue(path);
}
bool PropertyVector::getPyPathValue(const ObjectIdentifier &path, Py::Object &res) const
{
Base::Unit unit = getUnit();
if(unit.isEmpty())
return false;
std::string p = path.getSubPathStr();
if (p == ".x") {
res = new QuantityPy(new Quantity(getValue().x,unit));
} else if(p == ".y") {
res = new QuantityPy(new Quantity(getValue().y,unit));
} else if(p == ".z") {
res = new QuantityPy(new Quantity(getValue().z,unit));
} else
return false;
return true;
}
//**************************************************************************
// PropertyVectorDistance
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -216,18 +251,6 @@ PropertyVectorDistance::PropertyVectorDistance()
}
const boost::any PropertyVectorDistance::getPathValue(const ObjectIdentifier &path) const
{
std::string p = path.getSubPathStr();
if (p == ".x" || p == ".y" || p == ".z") {
// Convert double to quantity
return Base::Quantity(boost::any_cast<double>(Property::getPathValue(path)), Unit::Length);
}
else
return Property::getPathValue(path);
}
PropertyVectorDistance::~PropertyVectorDistance()
{
@@ -253,18 +276,6 @@ PropertyPosition::~PropertyPosition()
}
const boost::any PropertyPosition::getPathValue(const ObjectIdentifier &path) const
{
std::string p = path.getSubPathStr();
if (p == ".x" || p == ".y" || p == ".z") {
// Convert double to quantity
return Base::Quantity(boost::any_cast<double>(Property::getPathValue(path)), Unit::Length);
}
else
return Property::getPathValue(path);
}
//**************************************************************************
// PropertyPosition
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -285,18 +296,6 @@ PropertyDirection::~PropertyDirection()
}
const boost::any PropertyDirection::getPathValue(const ObjectIdentifier &path) const
{
std::string p = path.getSubPathStr();
if (p == ".x" || p == ".y" || p == ".z") {
// Convert double to quantity
return Base::Quantity(boost::any_cast<double>(Property::getPathValue(path)), Unit::Length);
}
else
return Property::getPathValue(path);
}
//**************************************************************************
// PropertyVectorList
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -601,30 +600,30 @@ const Base::Placement & PropertyPlacement::getValue(void)const
void PropertyPlacement::getPaths(std::vector<ObjectIdentifier> &paths) const
{
paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("Base"))
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("x")));
paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("Base"))
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("y")));
paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("Base"))
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("z")));
paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("Rotation"))
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("Angle")));
paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("Rotation"))
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("Axis"))
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("x")));
paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("Rotation"))
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("Axis"))
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("y")));
paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("Rotation"))
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("Axis"))
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("z")));
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Base"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("x")));
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Base"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("y")));
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Base"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("z")));
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Rotation"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Angle")));
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Rotation"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Axis"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("x")));
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Rotation"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Axis"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("y")));
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Rotation"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Axis"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("z")));
}
void PropertyPlacement::setPathValue(const ObjectIdentifier &path, const boost::any &value)
@@ -669,6 +668,24 @@ const boost::any PropertyPlacement::getPathValue(const ObjectIdentifier &path) c
return Property::getPathValue(path);
}
bool PropertyPlacement::getPyPathValue(const ObjectIdentifier &path, Py::Object &res) const
{
std::string p = path.getSubPathStr();
if (p == ".Rotation.Angle") {
Base::Vector3d axis; double angle;
_cPos.getRotation().getValue(axis,angle);
res = new QuantityPy(new Quantity(Base::toDegrees(angle),Unit::Angle));
} else if (p == ".Base.x") {
res = new QuantityPy(new Quantity(_cPos.getPosition().x,Unit::Length));
} else if (p == ".Base.y") {
res = new QuantityPy(new Quantity(_cPos.getPosition().y,Unit::Length));
} else if (p == ".Base.z") {
res = new QuantityPy(new Quantity(_cPos.getPosition().z,Unit::Length));
} else
return false;
return true;
}
PyObject *PropertyPlacement::getPyObject(void)
{
return new Base::PlacementPy(new Base::Placement(_cPos));
+21 -4
View File
@@ -30,6 +30,7 @@
#include <Base/Matrix.h>
#include <Base/BoundBox.h>
#include <Base/Placement.h>
#include <Base/Unit.h>
#include "Property.h"
#include "PropertyLinks.h"
@@ -98,6 +99,14 @@ public:
return sizeof(Base::Vector3d);
}
virtual const boost::any getPathValue(const ObjectIdentifier &path) const override;
virtual bool getPyPathValue(const ObjectIdentifier &path, Py::Object &res) const override;
virtual Base::Unit getUnit() const {
return Base::Unit();
}
private:
Base::Vector3d _cVec;
};
@@ -120,7 +129,9 @@ public:
*/
virtual ~PropertyVectorDistance();
const boost::any getPathValue(const ObjectIdentifier &path) const;
virtual Base::Unit getUnit() const {
return Base::Unit::Length;
}
const char* getEditorName(void) const {
return "Gui::PropertyEditor::PropertyVectorDistanceItem";
@@ -144,7 +155,9 @@ public:
*/
virtual ~PropertyPosition();
const boost::any getPathValue(const ObjectIdentifier &path) const;
virtual Base::Unit getUnit() const {
return Base::Unit::Length;
}
const char* getEditorName(void) const {
return "Gui::PropertyEditor::PropertyPositionItem";
@@ -168,7 +181,9 @@ public:
*/
virtual ~PropertyDirection();
const boost::any getPathValue(const ObjectIdentifier &path) const;
virtual Base::Unit getUnit() const {
return Base::Unit::Length;
}
const char* getEditorName(void) const {
return "Gui::PropertyEditor::PropertyDirectionItem";
@@ -304,7 +319,9 @@ public:
void setPathValue(const ObjectIdentifier &path, const boost::any &value);
const boost::any getPathValue(const ObjectIdentifier &path) const;
virtual const boost::any getPathValue(const ObjectIdentifier &path) const override;
virtual bool getPyPathValue(const ObjectIdentifier &path, Py::Object &res) const override;
const char* getEditorName(void) const {
return "Gui::PropertyEditor::PropertyPlacementItem";
+9 -6
View File
@@ -41,6 +41,7 @@
#include <Base/PyObjectBase.h>
#include <Base/QuantityPy.h>
#include <Base/UnitPy.h>
#include "Expression.h"
using namespace App;
using namespace Base;
@@ -120,7 +121,9 @@ void PropertyQuantity::setPyObject(PyObject *value)
if (PyObject_TypeCheck(value, &(UnitPy::Type))) {
Base::UnitPy *pcObject = static_cast<Base::UnitPy*>(value);
Base::Unit unit = *(pcObject->getUnitPtr());
aboutToSetValue();
_Unit = unit;
hasSetValue();
}
else {
Base::Quantity quant= createQuantityFromPy(value);
@@ -140,12 +143,12 @@ void PropertyQuantity::setPyObject(PyObject *value)
void PropertyQuantity::setPathValue(const ObjectIdentifier & /*path*/, const boost::any &value)
{
if (value.type() == typeid(double))
setValue(boost::any_cast<double>(value));
else if (value.type() == typeid(Base::Quantity))
setValue((boost::any_cast<Quantity>(value)).getValue());
else
throw bad_cast();
auto q = App::anyToQuantity(value);
aboutToSetValue();
if(!q.getUnit().isEmpty())
_Unit = q.getUnit();
_dValue=q.getValue();
setValue(q.getValue());
}
const boost::any PropertyQuantity::getPathValue(const ObjectIdentifier & /*path*/) const
+39 -13
View File
@@ -107,11 +107,11 @@ bool Range::next()
* @returns The row.
*/
int App::decodeRow(const std::string &rowstr)
int App::decodeRow(const std::string &rowstr, bool silent)
{
int row = validRow(rowstr);
if (row >= 0)
if (silent || row >= 0)
return row;
else
throw Base::IndexError("Invalid row specification.");
@@ -126,11 +126,11 @@ int App::decodeRow(const std::string &rowstr)
*
*/
int App::decodeColumn(const std::string &colstr)
int App::decodeColumn(const std::string &colstr, bool silent)
{
int col = validColumn(colstr);
if (col >= 0)
if (silent || col >= 0)
return col;
else
throw Base::IndexError("Invalid column specification");
@@ -201,19 +201,29 @@ int App::validColumn(const std::string &colstr)
*
*/
App::CellAddress App::stringToAddress(const char * strAddress)
App::CellAddress App::stringToAddress(const char * strAddress, bool silent)
{
static const boost::regex e("\\${0,1}([A-Z]{1,2})\\${0,1}([0-9]{1,5})");
boost::cmatch cm;
assert(strAddress != 0);
if (boost::regex_match(strAddress, cm, e)) {
const boost::sub_match<const char *> colstr = cm[1];
const boost::sub_match<const char *> rowstr = cm[2];
static boost::regex e("(\\$?[A-Z]{1,2})(\\$?[0-9]{1,5})");
boost::cmatch cm;
return CellAddress(decodeRow(rowstr.str()), decodeColumn(colstr.str()));
if (boost::regex_match(strAddress, cm, e)) {
bool absCol = (cm[1].first[0]=='$');
std::string r,c;
if(absCol)
c = std::string(cm[1].first+1,cm[1].second);
else
c = std::string(cm[1].first,cm[1].second);
bool absRow = (cm[2].first[0]=='$');
if(absRow)
r = std::string(cm[2].first+1,cm[2].second);
else
r = std::string(cm[2].first,cm[2].second);
return CellAddress(decodeRow(r,silent), decodeColumn(c,silent), absRow, absCol);
}
else if(silent)
return CellAddress();
else
throw Base::RuntimeError("Invalid cell specifier.");
}
@@ -224,10 +234,12 @@ App::CellAddress App::stringToAddress(const char * strAddress)
* @returns Address given as a string.
*/
std::string App::CellAddress::toString() const
std::string App::CellAddress::toString(bool noAbsolute) const
{
std::stringstream s;
if(_absCol && !noAbsolute)
s << '$';
if (col() < 26)
s << (char)('A' + col());
else {
@@ -237,7 +249,21 @@ std::string App::CellAddress::toString() const
s << (char)('A' + (colnum % 26));
}
if(_absRow && !noAbsolute)
s << '$';
s << (row() + 1);
return s.str();
}
bool App::CellAddress::parseAbsoluteAddress(const char *txt) {
if(txt[0]=='$' || (txt[0] && txt[1] && (txt[1]=='$' || txt[2]=='$'))) {
CellAddress addr = stringToAddress(txt,true);
if(addr.isValid()) {
*this = addr;
return true;
}
}
return false;
}
+19 -5
View File
@@ -29,15 +29,17 @@ namespace App {
struct CellAddress;
AppExport CellAddress stringToAddress(const char *strAddress);
AppExport int decodeColumn(const std::string &colstr);
AppExport int decodeRow(const std::string &rowstr);
AppExport CellAddress stringToAddress(const char *strAddress, bool silent=false);
AppExport int decodeColumn(const std::string &colstr, bool silent=false);
AppExport int decodeRow(const std::string &rowstr, bool silent=false);
AppExport int validColumn(const std::string &colstr);
AppExport int validRow(const std::string &rowstr);
struct AppExport CellAddress {
CellAddress(int row = -1, int col = -1) : _row(row), _col(col) { }
CellAddress(int row = -1, int col = -1, bool absRow=false, bool absCol=false)
: _row(row), _col(col), _absRow(absRow), _absCol(absCol)
{ }
CellAddress(const char * address) {
*this = stringToAddress(address);
@@ -47,10 +49,16 @@ struct AppExport CellAddress {
*this = stringToAddress(address.c_str());
}
bool parseAbsoluteAddress(const char *txt);
inline int row() const { return _row; }
inline int col() const { return _col; }
void setRow(int r) { _row = r; }
void setCol(int c) { _col = c; }
inline bool operator<(const CellAddress & other) const { return asInt() < other.asInt(); }
inline bool operator==(const CellAddress & other) const { return asInt() == other.asInt(); }
@@ -59,7 +67,11 @@ struct AppExport CellAddress {
inline bool isValid() { return (row() >=0 && row() < MAX_ROWS && col() >= 0 && col() < MAX_COLUMNS); }
std::string toString() const;
inline bool isAbsoluteRow() const { return _absRow; }
inline bool isAbsoluteCol() const { return _absCol; }
std::string toString(bool noAbsolute=false) const;
// Static members
@@ -73,6 +85,8 @@ protected:
short _row;
short _col;
bool _absRow;
bool _absCol;
};
/**
+101 -73
View File
@@ -33,6 +33,7 @@
#include <Base/Reader.h>
#include <Base/Writer.h>
#include <Base/Tools.h>
#include <Base/QuantityPy.h>
#include <App/ObjectIdentifier.h>
#include <App/DocumentObject.h>
@@ -68,13 +69,13 @@ PropertyConstraintList::~PropertyConstraintList()
App::ObjectIdentifier PropertyConstraintList::makeArrayPath(int idx)
{
return App::ObjectIdentifier(getContainer()) << App::ObjectIdentifier::Component::ArrayComponent(ObjectIdentifier::String(getName()), idx);
return App::ObjectIdentifier(*this,idx);
}
App::ObjectIdentifier PropertyConstraintList::makeSimplePath(const Constraint * c)
{
return App::ObjectIdentifier(getContainer()) << App::ObjectIdentifier::Component::SimpleComponent(getName())
<< App::ObjectIdentifier::Component::SimpleComponent(App::ObjectIdentifier::String(c->Name, !ExpressionParser::isTokenAnIndentifier(c->Name)));
return App::ObjectIdentifier(*this) << App::ObjectIdentifier::SimpleComponent(
App::ObjectIdentifier::String(c->Name, !ExpressionParser::isTokenAnIndentifier(c->Name)));
}
App::ObjectIdentifier PropertyConstraintList::makePath(int idx, const Constraint * c)
@@ -175,43 +176,52 @@ void PropertyConstraintList::setValue(const Constraint* lValue)
void PropertyConstraintList::setValues(const std::vector<Constraint*>& lValue)
{
auto copy = lValue;
for(auto &cstr : copy)
cstr = cstr->clone();
aboutToSetValue();
applyValues(lValue);
applyValues(std::move(copy));
hasSetValue();
}
void PropertyConstraintList::applyValues(const std::vector<Constraint*>& lValue)
void PropertyConstraintList::setValues(std::vector<Constraint*>&& lValue) {
aboutToSetValue();
applyValues(std::move(lValue));
hasSetValue();
}
void PropertyConstraintList::applyValues(std::vector<Constraint*>&& lValue)
{
std::vector<Constraint*> oldVals(_lValueList);
std::set<Constraint*> oldVals(_lValueList.begin(),_lValueList.end());
std::map<App::ObjectIdentifier, App::ObjectIdentifier> renamed;
std::set<App::ObjectIdentifier> removed;
boost::unordered_map<boost::uuids::uuid, std::size_t> newValueMap;
/* Check for renames */
for (unsigned int i = 0; i < lValue.size(); i++) {
boost::unordered_map<boost::uuids::uuid, std::size_t>::const_iterator j = valueMap.find(lValue[i]->tag);
if (j != valueMap.end() && (i != j->second || _lValueList[j->second]->Name != lValue[i]->Name) ) {
App::ObjectIdentifier old_oid(makePath(j->second, _lValueList[j->second] ));
App::ObjectIdentifier new_oid(makePath(i, lValue[i]));
renamed[old_oid] = new_oid;
if (j != valueMap.end()) {
if(i != j->second || _lValueList[j->second]->Name != lValue[i]->Name) {
App::ObjectIdentifier old_oid(makePath(j->second, _lValueList[j->second] ));
App::ObjectIdentifier new_oid(makePath(i, lValue[i]));
renamed[old_oid] = new_oid;
}
valueMap.erase(j);
}
}
/* Update value map with new tags from new array */
valueMap.clear();
for (std::size_t i = 0; i < lValue.size(); i++)
valueMap[lValue[i]->tag] = i;
newValueMap[lValue[i]->tag] = i;
// safety insurance in case new new values contain some pointers of the old values
oldVals.erase(lValue[i]);
}
/* Collect info about removed elements */
for (std::size_t i = 0; i < oldVals.size(); i++) {
boost::unordered_map<boost::uuids::uuid, std::size_t>::const_iterator j = valueMap.find(oldVals[i]->tag);
App::ObjectIdentifier oid(makePath(i, oldVals[i]));
for(auto &v : valueMap)
removed.insert(makePath(v.second,_lValueList[v.second]));
/* If not found in new values, place it in the set to be removed */
if (j == valueMap.end())
removed.insert(oid);
}
/* Update value map with new tags from new array */
valueMap = std::move(newValueMap);
/* Signal removes first, in case renamed values below have the same names as some of the removed ones. */
if (removed.size() > 0)
@@ -221,16 +231,11 @@ void PropertyConstraintList::applyValues(const std::vector<Constraint*>& lValue)
if (renamed.size() > 0)
signalConstraintsRenamed(renamed);
/* Resize array to new size */
_lValueList.resize(lValue.size());
/* copy all objects */
for (unsigned int i = 0; i < lValue.size(); i++)
_lValueList[i] = lValue[i]->clone();
_lValueList = std::move(lValue);
/* Clean-up; remove old values */
for (unsigned int i = 0; i < oldVals.size(); i++)
delete oldVals[i];
for(auto &v : oldVals)
delete v;
}
PyObject *PropertyConstraintList::getPyObject(void)
@@ -241,6 +246,32 @@ PyObject *PropertyConstraintList::getPyObject(void)
return list;
}
bool PropertyConstraintList::getPyPathValue(const App::ObjectIdentifier &path, Py::Object &res) const {
if(path.numSubComponents()!=2 || path.getPropertyComponent(0).getName()!=getName())
return false;
const ObjectIdentifier::Component & c1 = path.getPropertyComponent(1);
const Constraint *cstr = 0;
if (c1.isArray())
cstr = _lValueList[c1.getIndex(_lValueList.size())];
else if (c1.isSimple()) {
ObjectIdentifier::Component c1 = path.getPropertyComponent(1);
for(auto c : _lValueList) {
if(c->Name == c1.getName()) {
cstr = c;
break;
}
}
}
if(!cstr)
return false;
Quantity q = cstr->getPresentationValue();
res = new Base::QuantityPy(new Base::Quantity(q));
return true;
}
void PropertyConstraintList::setPyObject(PyObject *value)
{
if (PyList_Check(value)) {
@@ -307,26 +338,21 @@ void PropertyConstraintList::Restore(Base::XMLReader &reader)
reader.readEndElement("ConstraintList");
// assignment
setValues(values);
for (Constraint* it : values)
delete it;
setValues(std::move(values));
}
Property *PropertyConstraintList::Copy(void) const
{
PropertyConstraintList *p = new PropertyConstraintList();
p->applyValidGeometryKeys(validGeometryKeys);
p->applyValues(_lValueList);
p->setValues(_lValueList);
return p;
}
void PropertyConstraintList::Paste(const Property &from)
{
const PropertyConstraintList& FromList = dynamic_cast<const PropertyConstraintList&>(from);
aboutToSetValue();
applyValues(FromList._lValueList);
applyValidGeometryKeys(FromList.validGeometryKeys);
hasSetValue();
setValues(FromList._lValueList);
}
unsigned int PropertyConstraintList::getMemSize(void) const
@@ -414,8 +440,7 @@ bool PropertyConstraintList::validConstraintName(const std::string & name)
ObjectIdentifier PropertyConstraintList::createPath(int ConstrNbr) const
{
return App::ObjectIdentifier(getContainer())
<< App::ObjectIdentifier::Component::ArrayComponent(App::ObjectIdentifier::String(getName()), ConstrNbr);
return App::ObjectIdentifier(*this,ConstrNbr);
}
int PropertyConstraintList::getIndexFromConstraintName(const string &name)
@@ -425,21 +450,27 @@ int PropertyConstraintList::getIndexFromConstraintName(const string &name)
void PropertyConstraintList::setPathValue(const ObjectIdentifier &path, const boost::any &value)
{
const ObjectIdentifier::Component & c0 = path.getPropertyComponent(0);
if(path.numSubComponents()!=2 || path.getPropertyComponent(0).getName()!=getName())
FC_THROWM(Base::ValueError,"invalid constraint path " << path.toString());
const ObjectIdentifier::Component & c1 = path.getPropertyComponent(1);
double dvalue;
if (value.type() == typeid(double))
dvalue = boost::any_cast<double>(value);
else if (value.type() == typeid(float))
dvalue = App::any_cast<float>(value);
else if (value.type() == typeid(long))
dvalue = App::any_cast<long>(value);
else if (value.type() == typeid(int))
dvalue = App::any_cast<int>(value);
else if (value.type() == typeid(Quantity))
dvalue = (boost::any_cast<Quantity>(value)).getValue();
dvalue = (App::any_cast<const Quantity &>(value)).getValue();
else
throw std::bad_cast();
if (c0.isArray() && path.numSubComponents() == 1) {
int index = c0.getIndex();
if (c0.getIndex() >= _lValueList.size())
throw Base::IndexError("Array out of bounds");
if (c1.isArray()) {
size_t index = c1.getIndex(_lValueList.size());
switch (_lValueList[index]->Type) {
case Angle:
dvalue = Base::toRadians<double>(dvalue);
@@ -452,9 +483,7 @@ void PropertyConstraintList::setPathValue(const ObjectIdentifier &path, const bo
hasSetValue();
return;
}
else if (c0.isSimple() && path.numSubComponents() == 2) {
ObjectIdentifier::Component c1 = path.getPropertyComponent(1);
else if (c1.isSimple()) {
for (std::vector<Constraint *>::const_iterator it = _lValueList.begin(); it != _lValueList.end(); ++it) {
int index = it - _lValueList.begin();
@@ -473,20 +502,20 @@ void PropertyConstraintList::setPathValue(const ObjectIdentifier &path, const bo
}
}
}
throw Base::ValueError("Invalid constraint");
FC_THROWM(Base::ValueError,"invalid constraint path " << path.toString());
}
const Constraint * PropertyConstraintList::getConstraint(const ObjectIdentifier &path) const
{
const ObjectIdentifier::Component & c0 = path.getPropertyComponent(0);
if(path.numSubComponents()!=2 || path.getPropertyComponent(0).getName()!=getName())
FC_THROWM(Base::ValueError,"Invalid constraint path " << path.toString());
if (c0.isArray() && path.numSubComponents() == 1) {
if (c0.getIndex() >= _lValueList.size())
throw Base::IndexError("Array out of bounds");
const ObjectIdentifier::Component & c1 = path.getPropertyComponent(1);
return _lValueList[c0.getIndex()];
if (c1.isArray()) {
return _lValueList[c1.getIndex(_lValueList.size())];
}
else if (c0.isSimple() && path.numSubComponents() == 2) {
else if (c1.isSimple()) {
ObjectIdentifier::Component c1 = path.getPropertyComponent(1);
for (std::vector<Constraint *>::const_iterator it = _lValueList.begin(); it != _lValueList.end(); ++it) {
@@ -494,7 +523,7 @@ const Constraint * PropertyConstraintList::getConstraint(const ObjectIdentifier
return *it;
}
}
throw Base::ValueError("Invalid constraint");
FC_THROWM(Base::ValueError,"Invalid constraint path " << path.toString());
}
const boost::any PropertyConstraintList::getPathValue(const ObjectIdentifier &path) const
@@ -502,31 +531,30 @@ const boost::any PropertyConstraintList::getPathValue(const ObjectIdentifier &pa
return boost::any(getConstraint(path)->getPresentationValue());
}
const ObjectIdentifier PropertyConstraintList::canonicalPath(const ObjectIdentifier &p) const
ObjectIdentifier PropertyConstraintList::canonicalPath(const ObjectIdentifier &p) const
{
const ObjectIdentifier::Component & c0 = p.getPropertyComponent(0);
if(p.numSubComponents()!=2 || p.getPropertyComponent(0).getName()!=getName())
FC_THROWM(Base::ValueError,"Invalid constraint path " << p.toString());
if (c0.isArray() && p.numSubComponents() == 1) {
if (c0.getIndex() < _lValueList.size() && _lValueList[c0.getIndex()]->Name.size() > 0)
return ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
<< ObjectIdentifier::Component::SimpleComponent(_lValueList[c0.getIndex()]->Name);
const ObjectIdentifier::Component & c1 = p.getPropertyComponent(1);
if (c1.isArray()) {
size_t idx = c1.getIndex();
if (idx < _lValueList.size() && _lValueList[idx]->Name.size() > 0)
return ObjectIdentifier(*this) << ObjectIdentifier::SimpleComponent(_lValueList[idx]->Name);
return p;
}
else if (c0.isSimple() && p.numSubComponents() == 2) {
ObjectIdentifier::Component c1 = p.getPropertyComponent(1);
if (c1.isSimple())
return p;
else if (c1.isSimple()) {
return p;
}
throw Base::ValueError("Invalid constraint");
FC_THROWM(Base::ValueError,"Invalid constraint path " << p.toString());
}
void PropertyConstraintList::getPaths(std::vector<ObjectIdentifier> &paths) const
{
for (std::vector<Constraint *>::const_iterator it = _lValueList.begin(); it != _lValueList.end(); ++it) {
if ((*it)->Name.size() > 0)
paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
<< ObjectIdentifier::Component::SimpleComponent((*it)->Name));
paths.push_back(ObjectIdentifier(*this) << ObjectIdentifier::SimpleComponent((*it)->Name));
}
}
+11 -2
View File
@@ -86,6 +86,13 @@ public:
*/
void setValues(const std::vector<Constraint*>&);
/*!
Sets a vector of constraint to the property.
The values of the array are moved, and the ownership of constraints
inside are taken by this property
*/
void setValues(std::vector<Constraint*>&&);
/*!
Index operator
\note If the geometry is invalid then the index operator
@@ -124,9 +131,11 @@ public:
const Constraint *getConstraint(const App::ObjectIdentifier &path) const;
virtual void setPathValue(const App::ObjectIdentifier & path, const boost::any & value);
virtual const boost::any getPathValue(const App::ObjectIdentifier & path) const;
virtual const App::ObjectIdentifier canonicalPath(const App::ObjectIdentifier & p) const;
virtual App::ObjectIdentifier canonicalPath(const App::ObjectIdentifier & p) const;
virtual void getPaths(std::vector<App::ObjectIdentifier> & paths) const;
virtual bool getPyPathValue(const App::ObjectIdentifier &path, Py::Object &res) const override;
typedef std::pair<int, const Constraint*> ConstraintInfo ;
boost::signals2::signal<void (const std::map<App::ObjectIdentifier, App::ObjectIdentifier> &)> signalConstraintsRenamed;
@@ -153,7 +162,7 @@ private:
std::vector<unsigned int> validGeometryKeys;
bool invalidGeometry;
void applyValues(const std::vector<Constraint*>&);
void applyValues(std::vector<Constraint*>&&);
void applyValidGeometryKeys(const std::vector<unsigned int> &keys);
static std::vector<Constraint *> _emptyValueList;
+13 -13
View File
@@ -6393,17 +6393,17 @@ std::string SketchObject::validateExpression(const App::ObjectIdentifier &path,
return "Reference constraints cannot be set!";
}
std::set<App::ObjectIdentifier> deps;
expr->getDeps(deps);
auto deps = expr->getDeps();
auto it = deps.find(this);
if(it!=deps.end()) {
auto it2 = it->second.find("Constraints");
if(it2 != it->second.end()) {
for(auto &oid : it2->second) {
const Constraint * constraint = Constraints.getConstraint(oid);
for (std::set<App::ObjectIdentifier>::const_iterator i = deps.begin(); i != deps.end(); ++i) {
const App::Property * prop = (*i).getProperty();
if (prop == &Constraints) {
const Constraint * constraint = Constraints.getConstraint(*i);
if (!constraint->isDriving)
return "Reference constraint from this sketch cannot be used in this expression.";
if (!constraint->isDriving)
return "Reference constraint from this sketch cannot be used in this expression.";
}
}
}
return "";
@@ -6468,7 +6468,7 @@ void SketchObject::constraintsRemoved(const std::set<App::ObjectIdentifier> &rem
std::set<App::ObjectIdentifier>::const_iterator i = removed.begin();
while (i != removed.end()) {
ExpressionEngine.setValue(*i, boost::shared_ptr<App::Expression>(), 0);
ExpressionEngine.setValue(*i, boost::shared_ptr<App::Expression>());
++i;
}
}
@@ -6860,9 +6860,9 @@ bool SketchObject::AutoLockTangencyAndPerpty(Constraint *cstr, bool bForce, bool
return true;
}
void SketchObject::setExpression(const App::ObjectIdentifier &path, boost::shared_ptr<App::Expression> expr, const char * comment)
void SketchObject::setExpression(const App::ObjectIdentifier &path, boost::shared_ptr<App::Expression> expr)
{
DocumentObject::setExpression(path, expr, comment);
DocumentObject::setExpression(path, expr);
if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver, constraints and UI
solve();
+1 -1
View File
@@ -414,7 +414,7 @@ protected:
virtual void onDocumentRestored();
virtual void restoreFinished();
virtual void setExpression(const App::ObjectIdentifier &path, boost::shared_ptr<App::Expression> expr, const char * comment = 0);
virtual void setExpression(const App::ObjectIdentifier &path, boost::shared_ptr<App::Expression> expr);
std::string validateExpression(const App::ObjectIdentifier &path, boost::shared_ptr<const App::Expression> expr);