From: konrad Date: Sun, 28 Nov 2010 22:36:29 +0000 (+0000) Subject: add autocasting X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=287a251d0317350cf225a47a47a88284df950439;p=web%2Fkonrad%2Felam.git add autocasting git-svn-id: https://silmor.de/svn/softmagic/elam/trunk@641 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33 --- diff --git a/src/elamboolengine.cpp b/src/elamboolengine.cpp index 98f9ba5..7813106 100644 --- a/src/elamboolengine.cpp +++ b/src/elamboolengine.cpp @@ -45,6 +45,7 @@ static QVariant boolXor(const QVariant&o1,const QVariant&o2) return o1.toBool()^o2.toBool(); } +QVariant boolCast(const QVariant&v){return v.toBool();} void BoolEngine::configureBoolEngine(Engine&eng) { @@ -52,6 +53,7 @@ void BoolEngine::configureBoolEngine(Engine&eng) int bid=QVariant::Bool; //cast eng.setFunction("bool",boolFunc); + eng.setAutoCast(bid, QList()<binary; + struct CastFunc_s { + CastFunc_s(int p=50){prio=p;target=-1;cfunc=0;} + int target,prio; + QListorigin; + TypeCast cfunc; + }; + QListcasts; + QListprimtypes; }; DEFINE_DPTR(Engine); Engine::Engine(QObject* parent): QObject(parent) { - + registerType(Exception::metaTypeId()); } QVariant Engine::evaluate(QString ex) @@ -196,7 +204,7 @@ bool Engine::setConstant(QString n, QVariant v) 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; } @@ -205,7 +213,7 @@ bool Engine::setVariable(QString n, QVariant v) 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; } @@ -363,6 +371,44 @@ bool Engine::hasUnaryOperator(QString name) const 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;icasts.size();i++){ + if(!d->casts[i].origin.contains(vid))continue; + if(priocasts[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 diff --git a/src/elamengine.h b/src/elamengine.h index d186d70..14e595d 100644 --- a/src/elamengine.h +++ b/src/elamengine.h @@ -43,6 +43,11 @@ If the parser does not find a valid literal according to its rules it must retur */ typedef QPair (*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. @@ -106,6 +111,11 @@ class Engine:public QObject ///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; @@ -163,7 +173,20 @@ class Engine:public QObject ///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,QListorigin,TypeCast castfunc,int prio=50); + ///simply parses an expression string into an object Expression expression(QString); ///simply parses an expression string into an object diff --git a/src/elamexpression.cpp b/src/elamexpression.cpp index d87a3f1..89d80f8 100644 --- a/src/elamexpression.cpp +++ b/src/elamexpression.cpp @@ -438,6 +438,8 @@ QVariant Expression::evalBinary() 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 @@ -477,7 +479,7 @@ QVariant Expression::evalFunction() //gather arguments QListargs; for(int i=0;isubexpr.size();i++) - args<subexpr[i].evaluate(); + args<parent->autoCast(d->subexpr[i].evaluate()); //execute return func(args); } @@ -492,6 +494,7 @@ QVariant Expression::evalUnary() //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 diff --git a/src/elamfloatengine.cpp b/src/elamfloatengine.cpp index 5d8a904..b0ffb66 100644 --- a/src/elamfloatengine.cpp +++ b/src/elamfloatengine.cpp @@ -112,6 +112,7 @@ int FloatEngine::floatLowParserPrio() return 10; } +static QVariant fltCast(const QVariant&v){return v.toDouble();} void FloatEngine::configureFloatEngine(ELAM::Engine& eng) { @@ -119,6 +120,7 @@ void FloatEngine::configureFloatEngine(ELAM::Engine& eng) eng.setLiteralParser(floatLiteralParser2,"0123456789.",floatLowParserPrio()); int fid=QVariant::Double; int iid=QVariant::LongLong; + eng.setAutoCast(fid, QList()<()<()<()<