From c3db1e02ec5453e6c19a8a26c19fd780b381a585 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Mon, 26 Aug 2019 15:55:39 +0800 Subject: [PATCH] App: add list/tuple() function to Expression For easy creation of Python list/tuple using expression. Range expression can now be expanded into list or tuple. --- src/App/Expression.cpp | 71 ++++++++++++++++++++++++++++++++------ src/App/ExpressionParser.h | 4 ++- 2 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/App/Expression.cpp b/src/App/Expression.cpp index 0c041cbf66..8f03dd9a3d 100644 --- a/src/App/Expression.cpp +++ b/src/App/Expression.cpp @@ -85,8 +85,7 @@ FC_LOG_LEVEL_INIT("Expression",true,true) #define __EXPR_THROW(_e,_msg,_expr) do {\ std::ostringstream ss;\ - ss << _msg;\ - if(_expr) ss << std::endl << (_expr)->toString();\ + ss << _msg << (_expr);\ throw _e(ss.str().c_str());\ }while(0) @@ -94,8 +93,7 @@ FC_LOG_LEVEL_INIT("Expression",true,true) #define __EXPR_SET_MSG(_e,_msg,_expr) do {\ std::ostringstream ss;\ - ss << _msg << _e.what();\ - if(_expr) ss << std::endl << (_expr)->toString();\ + ss << _msg << _e.what() << (_expr);\ _e.setMessage(ss.str());\ }while(0) @@ -122,6 +120,12 @@ FC_LOG_LEVEL_INIT("Expression",true,true) #define PY_THROW(_msg) __EXPR_THROW(Py::RuntimeError,_msg, (Expression*)0) +static inline std::ostream &operator<<(std::ostream &os, const App::Expression *expr) { + if(expr) + os << std::endl << expr->toString(); + return os; +} + //////////////////////////////////////////////////////////////////////////////// // WARNING! The following define enables slightly faster any type comparison which @@ -1518,18 +1522,18 @@ FunctionExpression::FunctionExpression(const DocumentObject *_owner, Function _f case CEIL: case FLOOR: if (args.size() != 1) - throw ExpressionError("Invalid number of arguments: exactly one required."); + EXPR_THROW("Invalid number of arguments: exactly one required."); break; case MOD: case ATAN2: case POW: if (args.size() != 2) - throw ExpressionError("Invalid number of arguments: exactly two required."); + EXPR_THROW("Invalid number of arguments: exactly two required."); break; case HYPOT: case CATH: if (args.size() < 2 || args.size() > 3) - throw ExpressionError("Invalid number of arguments: exactly two, or three required."); + EXPR_THROW("Invalid number of arguments: exactly two, or three required."); break; case STDDEV: case SUM: @@ -1538,13 +1542,17 @@ FunctionExpression::FunctionExpression(const DocumentObject *_owner, Function _f case MIN: case MAX: if (args.size() == 0) - throw ExpressionError("Invalid number of arguments: at least one required."); + EXPR_THROW("Invalid number of arguments: at least one required."); + break; + case LIST: + case TUPLE: break; case NONE: case AGGREGATES: case LAST: default: - throw ExpressionError("Unknown function"); + EXPR_THROW("Unknown function"); + break; } } @@ -1771,6 +1779,11 @@ Expression * FunctionExpression::eval() const if (f > AGGREGATES) return evalAggregate(); + if(f == LIST || f == TUPLE) { + Base::PyGILStateLocker lock; + return new PyObjectExpression(owner,getPyValue().ptr()); + } + std::unique_ptr e1(args[0]->eval()); std::unique_ptr e2(args.size() > 1 ? args[1]->eval() : 0); std::unique_ptr e3(args.size() > 2 ? args[2]->eval() : 0); @@ -1988,6 +2001,23 @@ boost::any FunctionExpression::getValueAsAny() const { } Py::Object FunctionExpression::getPyValue() const { + if(f == LIST) { + if(args.size() == 1 && args[0]->isDerivedFrom(RangeExpression::getClassTypeId())) + return args[0]->getPyValue(); + Py::List list(args.size()); + int i=0; + for(auto &arg : args) + list.setItem(i++,arg->getPyValue()); + return list; + } else if (f == TUPLE) { + if(args.size() == 1 && args[0]->isDerivedFrom(RangeExpression::getClassTypeId())) + return Py::Tuple(args[0]->getPyValue()); + Py::Tuple tuple(args.size()); + int i=0; + for(auto &arg : args) + tuple.setItem(i++,arg->getPyValue()); + return tuple; + } ExpressionPtr e(eval()); return e->getPyValue(); } @@ -2100,6 +2130,10 @@ std::string FunctionExpression::toString(bool persistent) const return "min(" + ss.str() + ")"; case MAX: return "max(" + ss.str() + ")"; + case LIST: + return "list(" + ss.str() + ")"; + case TUPLE: + return "tuple(" + ss.str() + ")"; default: assert(0); return std::string(); @@ -2637,11 +2671,24 @@ bool RangeExpression::isTouched() const Expression *RangeExpression::eval() const { - throw Exception("Range expression cannot be evaluated"); + Base::PyGILStateLocker lock; + return expressionFromPy(owner,getPyValue()); +} + +boost::any RangeExpression::getValueAsAny() const { + Base::PyGILStateLocker lock; + return __pyObjectFromAny(getPyValue()); } Py::Object RangeExpression::getPyValue() const { - return Py::Object(); + Py::List list; + Range range(getRange()); + do { + Property * p = owner->getPropertyByName(range.address().c_str()); + if(p) + list.append(Py::asObject(p->getPyObject())); + } while (range.next()); + return list; } std::string RangeExpression::toString(bool) const @@ -2924,6 +2971,8 @@ static void initParser(const App::DocumentObject *owner) registered_functions["floor"] = FunctionExpression::FLOOR; registered_functions["hypot"] = FunctionExpression::HYPOT; registered_functions["cath"] = FunctionExpression::CATH; + registered_functions["list"] = FunctionExpression::LIST; + registered_functions["tuple"] = FunctionExpression::TUPLE; // Aggregates registered_functions["sum"] = FunctionExpression::SUM; diff --git a/src/App/ExpressionParser.h b/src/App/ExpressionParser.h index 2862fbebf9..5f47eae5cc 100644 --- a/src/App/ExpressionParser.h +++ b/src/App/ExpressionParser.h @@ -267,6 +267,8 @@ public: FLOOR, HYPOT, CATH, + LIST, + TUPLE, // Aggregates AGGREGATES, @@ -453,7 +455,7 @@ public: Range getRange() const; - virtual boost::any getValueAsAny() const override { return boost::any(); } + virtual boost::any getValueAsAny() const override; virtual Py::Object getPyValue() const override;