return o1.toBool()^o2.toBool();
}
+QVariant boolCast(const QVariant&v){return v.toBool();}
void BoolEngine::configureBoolEngine(Engine&eng)
{
int bid=QVariant::Bool;
//cast
eng.setFunction("bool",boolFunc);
+ eng.setAutoCast(bid, QList<int>()<<QVariant::Int<<QVariant::UInt <<QVariant::LongLong<<QVariant::ULongLong <<QVariant::Char<<QVariant::String, boolCast, 20);
//constants
eng.setConstant("null",QVariant());
eng.setConstant("true",true);
int prio;
};
QMap<QString,BinaryOperator_s>binary;
+ struct CastFunc_s {
+ CastFunc_s(int p=50){prio=p;target=-1;cfunc=0;}
+ int target,prio;
+ QList<int>origin;
+ TypeCast cfunc;
+ };
+ QList<CastFunc_s>casts;
+ QList<int>primtypes;
};
DEFINE_DPTR(Engine);
Engine::Engine(QObject* parent): QObject(parent)
{
-
+ registerType(Exception::metaTypeId());
}
QVariant Engine::evaluate(QString ex)
if(!d->cclass.isName(n))return false;
if(d->funcs.contains(n))return false;
d->vars.remove(n);
- d->consts.insert(n,v);
+ d->consts.insert(n,autoCast(v));
return true;
}
if(!d->cclass.isName(n))return false;
if(d->consts.contains(n))return false;
if(d->funcs.contains(n))return false;
- d->vars.insert(n,v);
+ d->vars.insert(n,autoCast(v));
return true;
}
return ! d->unary[name].isNull();
}
+void Engine::registerType(int typeId)
+{
+ if(!d->primtypes.contains(typeId))
+ d->primtypes.append(typeId);
+}
+
+void Engine::setAutoCast(int target, QList< int > origin, TypeCast castfunc, int prio)
+{
+ if(castfunc==0)return;
+ if(prio<0)return;
+ registerType(target);
+ Private::CastFunc_s cf(prio);
+ cf.cfunc=castfunc;
+ cf.origin=origin;
+ cf.target=target;
+ d->casts.append(cf);
+}
+
+QVariant Engine::autoCast(const QVariant& v)const
+{
+ //check for primary
+ int vid=v.userType();
+ if(d->primtypes.contains(vid))
+ return v;
+ //find matching cast
+ int prio=-1;int pos=-1;
+ for(int i=0;i<d->casts.size();i++){
+ if(!d->casts[i].origin.contains(vid))continue;
+ if(prio<d->casts[i].prio){
+ pos=i;
+ prio=d->casts[i].prio;
+ }
+ }
+ //found it?
+ if(pos<0)return v;
+ else return d->casts[pos].cfunc(v);
+}
+
//end of namespace
};
\ No newline at end of file
*/
typedef QPair<QString,QVariant> (*LiteralParser)(const QString&expr,Engine&engine,int start);
+/**Wraps a cast function to convert various types into another type.
+\param orig the original value of any type
+\returns the converted value that must conform to the expected type*/
+typedef QVariant (*TypeCast)(const QVariant&orig);
+
/**The calculation engine of .
Instances of this class can be configured to represent a specific system of functions and operators.
///returns true if the name represents an assignment operator
Q_INVOKABLE bool isAssignment(QString name)const;
+
+ /**performs automatic casting
+ \returns the casted value or the original value if it is of a primary type or if there is no known cast for it*/
+ Q_INVOKABLE QVariant autoCast(const QVariant&)const;
+
public slots:
///returns the value of the named variable or constant
QVariant getValue(QString)const;
///sets/overrides the priority of an operator, creating the operator if it does not exist yet
void setBinaryOperatorPrio(QString name,int prio);
-
+
+ /**registers a type as primary, this means it is not cast into another type when encountered
+ \param typeId the QVariant ID of the type to register*/
+ void registerType(int typeId);
+ /**Registers an automatic cast function.
+
+ Automatic cast functions must succeed in converting, if the result is uncertain (e.g. as in converting a string to a number) use an explicit function.
+
+ \param target the target of the cast function, the target is automatically registered as primary type (see registerType)
+ \param origin type IDs that are automatically converted using this function, origins that are also primary types are ignored
+ \param castfunc the function that converts these types
+ \param prio the priority of the cast, if a cast function for the same origin, but a higher priority exists the one with the higher priority is used; the priority must be a positive value*/
+ void setAutoCast(int target,QList<int>origin,TypeCast castfunc,int prio=50);
+
///simply parses an expression string into an object
Expression expression(QString);
///simply parses an expression string into an object
QVariant sub2=d->subexpr[1].evaluate();
if(sub2.userType()==ELAM::Exception::metaTypeId())
return sub2;
+ sub1=d->parent->autoCast(sub1);
+ sub2=d->parent->autoCast(sub2);
//get operator
BinaryOperator binop=d->parent->binaryOperator(un);
//perform operation
//gather arguments
QList<QVariant>args;
for(int i=0;i<d->subexpr.size();i++)
- args<<d->subexpr[i].evaluate();
+ args<<d->parent->autoCast(d->subexpr[i].evaluate());
//execute
return func(args);
}
//check for exception
if(sub.userType()==ELAM::Exception::metaTypeId())
return sub;
+ sub=d->parent->autoCast(sub);
//get operator
UnaryOperator unop=d->parent->unaryOperator(un);
//perform operation
return 10;
}
+static QVariant fltCast(const QVariant&v){return v.toDouble();}
void FloatEngine::configureFloatEngine(ELAM::Engine& eng)
{
eng.setLiteralParser(floatLiteralParser2,"0123456789.",floatLowParserPrio());
int fid=QVariant::Double;
int iid=QVariant::LongLong;
+ eng.setAutoCast(fid, QList<int>()<<QVariant::Int<<QVariant::LongLong<<QVariant::UInt<<QVariant::ULongLong, fltCast, 30);
//unary
eng.unaryOperator("-").setCallback(floatMinus,fid);
eng.unaryOperator("+").setCallback(floatPlus,fid);
return 20;
}
+static QVariant intCast(const QVariant&v){return v.toLongLong();}
void IntEngine::configureIntEngine(ELAM::Engine& eng)
{
int iid=QVariant::LongLong;
eng.setLiteralParser(IntLiteralParser,"0123456789",intParserPrio());
+ eng.setAutoCast(iid, QList<int>()<<QVariant::Int<<QVariant::UInt<<QVariant::ULongLong, intCast, 40);
+ eng.setAutoCast(iid, QList<int>()<<QVariant::Double, intCast, 30);
//cast
eng.setFunction("int",intFunc);
//unaries
return 50;
}
+static QVariant strCast(const QVariant&v){return v.toString();}
+
void StringEngine::configureStringEngine(Engine& eng)
{
int sid=QVariant::String;
int aid=AnyType::metaTypeId();
+ eng.setAutoCast(sid, QList<int>()<<QVariant::Char, strCast, 40);
//parser
eng.setLiteralParser(strLiteralParser,"\'\"",stringParserPrio());
//cast