add autocasting
authorkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sun, 28 Nov 2010 22:36:29 +0000 (22:36 +0000)
committerkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sun, 28 Nov 2010 22:36:29 +0000 (22:36 +0000)
git-svn-id: https://silmor.de/svn/softmagic/elam/trunk@641 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33

src/elamboolengine.cpp
src/elamengine.cpp
src/elamengine.h
src/elamexpression.cpp
src/elamfloatengine.cpp
src/elamintengine.cpp
src/elamstringengine.cpp

index 98f9ba5..7813106 100644 (file)
@@ -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<int>()<<QVariant::Int<<QVariant::UInt <<QVariant::LongLong<<QVariant::ULongLong <<QVariant::Char<<QVariant::String, boolCast, 20);
        //constants
        eng.setConstant("null",QVariant());
        eng.setConstant("true",true);
index dabbd6b..d53a432 100644 (file)
@@ -36,12 +36,20 @@ class DPTR_CLASS_NAME(Engine):public DPtr
                        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)
@@ -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;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
index d186d70..14e595d 100644 (file)
@@ -43,6 +43,11 @@ If the parser does not find a valid literal according to its rules it must retur
 */
 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.
@@ -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,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
index d87a3f1..89d80f8 100644 (file)
@@ -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
        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);
 }
@@ -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
index 5d8a904..b0ffb66 100644 (file)
@@ -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<int>()<<QVariant::Int<<QVariant::LongLong<<QVariant::UInt<<QVariant::ULongLong, fltCast, 30);
        //unary
        eng.unaryOperator("-").setCallback(floatMinus,fid);
        eng.unaryOperator("+").setCallback(floatPlus,fid);
index 9ab9f3c..d75fd16 100644 (file)
@@ -108,11 +108,14 @@ int IntEngine::intParserPrio()
        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
index aee1e40..a847d19 100644 (file)
@@ -148,10 +148,13 @@ int StringEngine::stringParserPrio()
        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