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.
This commit is contained in:
Zheng, Lei
2019-08-26 15:55:39 +08:00
committed by wmayer
parent 38c47d6e95
commit c3db1e02ec
2 changed files with 63 additions and 12 deletions

View File

@@ -85,8 +85,7 @@ FC_LOG_LEVEL_INIT("Expression",true,true)
#define __EXPR_THROW(_e,_msg,_expr) do {\ #define __EXPR_THROW(_e,_msg,_expr) do {\
std::ostringstream ss;\ std::ostringstream ss;\
ss << _msg;\ ss << _msg << (_expr);\
if(_expr) ss << std::endl << (_expr)->toString();\
throw _e(ss.str().c_str());\ throw _e(ss.str().c_str());\
}while(0) }while(0)
@@ -94,8 +93,7 @@ FC_LOG_LEVEL_INIT("Expression",true,true)
#define __EXPR_SET_MSG(_e,_msg,_expr) do {\ #define __EXPR_SET_MSG(_e,_msg,_expr) do {\
std::ostringstream ss;\ std::ostringstream ss;\
ss << _msg << _e.what();\ ss << _msg << _e.what() << (_expr);\
if(_expr) ss << std::endl << (_expr)->toString();\
_e.setMessage(ss.str());\ _e.setMessage(ss.str());\
}while(0) }while(0)
@@ -122,6 +120,12 @@ FC_LOG_LEVEL_INIT("Expression",true,true)
#define PY_THROW(_msg) __EXPR_THROW(Py::RuntimeError,_msg, (Expression*)0) #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 // 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 CEIL:
case FLOOR: case FLOOR:
if (args.size() != 1) if (args.size() != 1)
throw ExpressionError("Invalid number of arguments: exactly one required."); EXPR_THROW("Invalid number of arguments: exactly one required.");
break; break;
case MOD: case MOD:
case ATAN2: case ATAN2:
case POW: case POW:
if (args.size() != 2) if (args.size() != 2)
throw ExpressionError("Invalid number of arguments: exactly two required."); EXPR_THROW("Invalid number of arguments: exactly two required.");
break; break;
case HYPOT: case HYPOT:
case CATH: case CATH:
if (args.size() < 2 || args.size() > 3) 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; break;
case STDDEV: case STDDEV:
case SUM: case SUM:
@@ -1538,13 +1542,17 @@ FunctionExpression::FunctionExpression(const DocumentObject *_owner, Function _f
case MIN: case MIN:
case MAX: case MAX:
if (args.size() == 0) 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; break;
case NONE: case NONE:
case AGGREGATES: case AGGREGATES:
case LAST: case LAST:
default: default:
throw ExpressionError("Unknown function"); EXPR_THROW("Unknown function");
break;
} }
} }
@@ -1771,6 +1779,11 @@ Expression * FunctionExpression::eval() const
if (f > AGGREGATES) if (f > AGGREGATES)
return evalAggregate(); return evalAggregate();
if(f == LIST || f == TUPLE) {
Base::PyGILStateLocker lock;
return new PyObjectExpression(owner,getPyValue().ptr());
}
std::unique_ptr<Expression> e1(args[0]->eval()); std::unique_ptr<Expression> e1(args[0]->eval());
std::unique_ptr<Expression> e2(args.size() > 1 ? args[1]->eval() : 0); std::unique_ptr<Expression> e2(args.size() > 1 ? args[1]->eval() : 0);
std::unique_ptr<Expression> e3(args.size() > 2 ? args[2]->eval() : 0); std::unique_ptr<Expression> e3(args.size() > 2 ? args[2]->eval() : 0);
@@ -1988,6 +2001,23 @@ boost::any FunctionExpression::getValueAsAny() const {
} }
Py::Object FunctionExpression::getPyValue() 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()); ExpressionPtr e(eval());
return e->getPyValue(); return e->getPyValue();
} }
@@ -2100,6 +2130,10 @@ std::string FunctionExpression::toString(bool persistent) const
return "min(" + ss.str() + ")"; return "min(" + ss.str() + ")";
case MAX: case MAX:
return "max(" + ss.str() + ")"; return "max(" + ss.str() + ")";
case LIST:
return "list(" + ss.str() + ")";
case TUPLE:
return "tuple(" + ss.str() + ")";
default: default:
assert(0); assert(0);
return std::string(); return std::string();
@@ -2637,11 +2671,24 @@ bool RangeExpression::isTouched() const
Expression *RangeExpression::eval() 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 { 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 std::string RangeExpression::toString(bool) const
@@ -2924,6 +2971,8 @@ static void initParser(const App::DocumentObject *owner)
registered_functions["floor"] = FunctionExpression::FLOOR; registered_functions["floor"] = FunctionExpression::FLOOR;
registered_functions["hypot"] = FunctionExpression::HYPOT; registered_functions["hypot"] = FunctionExpression::HYPOT;
registered_functions["cath"] = FunctionExpression::CATH; registered_functions["cath"] = FunctionExpression::CATH;
registered_functions["list"] = FunctionExpression::LIST;
registered_functions["tuple"] = FunctionExpression::TUPLE;
// Aggregates // Aggregates
registered_functions["sum"] = FunctionExpression::SUM; registered_functions["sum"] = FunctionExpression::SUM;

View File

@@ -267,6 +267,8 @@ public:
FLOOR, FLOOR,
HYPOT, HYPOT,
CATH, CATH,
LIST,
TUPLE,
// Aggregates // Aggregates
AGGREGATES, AGGREGATES,
@@ -453,7 +455,7 @@ public:
Range getRange() const; Range getRange() const;
virtual boost::any getValueAsAny() const override { return boost::any(); } virtual boost::any getValueAsAny() const override;
virtual Py::Object getPyValue() const override; virtual Py::Object getPyValue() const override;