QVariant BinaryOperator::execute ( const QVariant&op1,const QVariant&op2 ) const
{
- //TODO: implement
- return QVariant();
+ //search for match
+ QPair<int,int>k(op1.userType(),op2.userType());
+ QPair<int,int>kl(k.first,AnyType::metaTypeId());
+ QPair<int,int>kr(AnyType::metaTypeId(),k.second);
+ QPair<int,int>ka(AnyType::metaTypeId(),AnyType::metaTypeId());
+ BinaryOperatorCall bc=0;
+ //search for perfect, then left, then right, then any match
+ if(d->callmap.contains(k))bc=d->callmap[k];else
+ if(d->callmap.contains(kl))bc=d->callmap[kl];else
+ if(d->callmap.contains(kr))bc=d->callmap[kr];else
+ if(d->callmap.contains(ka))bc=d->callmap[ka];
+ //bail out if none found
+ if(bc==0)
+ return Exception(Exception::TypeMismatchError, "operator cannot work on this type");
+ //execute
+ return bc(op1,op2);
}
BinaryOperatorCall BinaryOperator::getCallback ( QString type1, QString type2 ) const
{
- //TODO: implement
- return 0;
+ QPair<int,int>k( QVariant::nameToType(type1.toAscii().data()), QVariant::nameToType(type2.toAscii().data()));
+ if(d->callmap.contains(k))
+ return d->callmap[k];
+ else
+ return 0;
}
BinaryOperatorCall BinaryOperator::getCallback ( int type1, int type2 ) const
{
- //TODO: implement
- return 0;
+ QPair<int,int>k(type1,type2);
+ if(d->callmap.contains(k))
+ return d->callmap[k];
+ else
+ return 0;
}
QList< QPair< int, int > > BinaryOperator::getTypeIds() const
{
- //TODO: implement
- return QList< QPair< int, int > > ();
+ return d->callmap.keys();
}
QList< QPair< QString, QString > > BinaryOperator::getTypeNames() const
{
- //TODO: implement
- return QList< QPair< QString, QString > >();
+ QList<QPair<int,int> > k=d->callmap.keys();
+ QList<QPair<QString,QString> >ret;
+ for(int i=0;i<k.size();i++)
+ ret<<QPair<QString,QString>( QVariant::typeToName((QVariant::Type)k[i].first), QVariant::typeToName((QVariant::Type)k[i].second));
+ return ret;
}
-void BinaryOperator::removeCallback ( BinaryOperatorCall )
+void BinaryOperator::removeCallback ( BinaryOperatorCall c)
{
- //TODO: implement
-
+ QList<QPair<int,int> > k=d->callmap.keys();
+ for(int i=0;i<k.size();i++)
+ if(d->callmap[k[i]]==c)
+ d->callmap.remove(k[i]);
}
-void BinaryOperator::removeCallback ( QString , QString )
+void BinaryOperator::removeCallback ( QString t1, QString t2)
{
- //TODO: implement
-
+ removeCallback( QVariant::nameToType(t1.toAscii().data()), QVariant::nameToType(t2.toAscii().data()));
}
-void BinaryOperator::removeCallback ( int , int )
+void BinaryOperator::removeCallback ( int t1, int t2)
{
- //TODO: implement
-
+ d->callmap.remove(QPair<int,int>(t1,t2));
}
void BinaryOperator::setCallback ( BinaryOperatorCall callback, QString type1, QString type2 )
{
- //TODO: implement
-
+ setCallback(callback, QVariant::nameToType(type1.toAscii().data()), QVariant::nameToType(type2.toAscii().data()));
}
void BinaryOperator::setCallback ( BinaryOperatorCall callback, int type1, int type2 )
{
- //TODO: implement
+ if(callback==0)
+ d->callmap.remove(QPair<int,int>(type1,type2));
+ else
+ d->callmap.insert(QPair<int,int>(type1,type2),callback);
+}
+bool BinaryOperator::isNull() const
+{
+ return d->callmap.isEmpty();
}
+
//end of namespace
};
\ No newline at end of file
///calls the callback function associated with the type of the argument, throws an exception if there is no callback
QVariant execute(const QVariant&,const QVariant&)const;
+
+ ///true if this operator has no callbacks
+ bool isNull()const;
};
//end of namespace
{
if(lf.size()!=1)
return Exception(Exception::ArgumentListError, "expecting exactly one argument");
- return lf[0].type()==Exception::metaTypeId();
+ return lf[0].userType()==Exception::metaTypeId();
}
static QVariant isExceptionOrNullFunc(const QList<QVariant>&lf)
{
if(lf.size()!=1)
return Exception(Exception::ArgumentListError, "expecting exactly one argument");
- return lf[0].isNull() || lf[0].type()==Exception::metaTypeId();
+ return lf[0].isNull() || lf[0].userType()==Exception::metaTypeId();
}
static QVariant catchFunc(const QList<QVariant>&lf)
{
if(lf.size()<1||lf.size()>3)
return Exception(Exception::ArgumentListError, "expecting 1-3 arguments");
- if(lf[0].type()==Exception::metaTypeId()){
+ if(lf[0].userType()==Exception::metaTypeId()){
if(lf.size()>1)return lf[1];
else return true;
}else{
//check whether prio matches
if(d->binary[name].prio==prio)
return d->binary[name].op;
+ //override if the op is empty
+ if(d->binary[name].op.isNull())
+ match=OverridePrio;
//check matching mode
switch(match){
case OverridePrio:
return d->cclass.isAssignment(name);
}
+bool Engine::hasBinaryOperator(QString name) const
+{
+ if(!d->binary.contains(name))return false;
+ return ! d->binary[name].op.isNull();
+}
+
+bool Engine::hasUnaryOperator(QString name) const
+{
+ if(!d->unary.contains(name))return false;
+ return ! d->unary[name].isNull();
+}
+
//end of namespace
};
\ No newline at end of file
Q_INVOKABLE bool hasFunction(QString)const;
///returns the pointer to the function
Q_INVOKABLE Function getFunction(QString)const;
+
+ ///returns true if there is an unaryOperator with this name
+ Q_INVOKABLE bool hasUnaryOperator(QString name)const;
+ ///returns true if there is an binaryOperator with this name
+ Q_INVOKABLE bool hasBinaryOperator(QString name)const;
/** \brief returns an existing or new unary operator object
\param name the name token of the operator, if the name is not a valid operator it cannot be called from this engine until character classes change*/
for(int i=0;i<tok.size();i++){
dbg<<"\n";
printtoken(dbg,tok[i],tlevel+1);
+ dbg.nospace();
}
dbg<<")";
}
case Token::ParClose:dbg<<"ClosingParenthesis";break;
case Token::ParOpen:dbg<<"OpeningParenthesis";break;
case Token::Comma:dbg<<"Comma";break;
- case Token::Literal:dbg<<"LiteralValue,value="<<tok.literalValue();break;
+ case Token::Literal:
+ dbg<<"LiteralValue,value="<<tok.literalValue();
+ dbg.nospace();
+ break;
case Token::Whitespace:dbg<<"WhiteSpace";break;
case Token::Parentheses:dbg<<"Parentheses";break;
case Token::Function:dbg<<"Function";break;
case Token::AssignmentOp:dbg<<"Assignment";break;
default:dbg<<"Unknown:"<<(int)tok.type();break;
}
- dbg<<",pos="<<tok.position();
+ dbg<<",pos="<<tok.position();dbg.nospace();
QList<Token> sub=tok.subTokens();
if(sub.size()>0){
dbg<<",sub-tokens:";
}
dbg<<")";
}
-QDebug&operator<<(QDebug&dbg,const Token&tok)
+QDebug&operator<<(QDebug dbg,const Token&tok)
{
dbg.nospace();
printtoken(dbg,tok,0);
return dbg.space();
}
-QDebug&operator<<(QDebug&dbg,const QList<Token>&tok)
+QDebug&operator<<(QDebug dbg,const QList<Token>&tok)
{
dbg.nospace();
printtokenlist(dbg,tok,0,0);
Expression::Expression(Engine* parent, const QList< Token >& toks)
{
+ d->parent=parent;
//check for simple errors
ELAM::Exception ex=scanForError(toks);
if(ex.errorType()!=ELAM::Exception::NoError){
d->tokens=toks;
return;
}
- d->parent=parent;
d->tokens=reduceTokens(toks);
- qDebug()<<"tokens:"<<d->tokens;
+// qDebug()<<"tokens:"<<d->tokens;
//check for nothing and complain
if(d->tokens.size()==0){
d->type=Exception;
if(d->tokens.size()==1){
switch(d->tokens[0].type()){
case Token::Function:
+ d->type=Function;
functionInit();
- d->type=(Type)d->tokens[0].type();
break;
case Token::Parentheses:
d->subexpr<<Expression(parent,d->tokens[0].subTokens());
- d->type=(Type)d->tokens[0].type();
+ d->type=Parentheses;
break;
case Token::Constant:
case Token::Variable:
return;
}
//ok
+ d->type=AssignmentOp;
+ d->oppos=i;
+ d->subexpr<<Expression(parent,d->tokens.mid(0,1));
d->subexpr<<Expression(parent,d->tokens.mid(2));
return;
}
//split operation
d->oppos=cpos;
if(d->tokens[cpos].type()==Token::BinaryOp){
+ d->type=BinaryOp;
d->subexpr<<Expression(parent,d->tokens.mid(0,cpos));
d->subexpr<<Expression(parent,d->tokens.mid(cpos+1));
}else{
+ d->type=UnaryOp;
d->subexpr<<Expression(parent,d->tokens.mid(cpos+1));
}
}
void Expression::functionInit()
{
- QList<Token>sub=d->tokens[0].subTokens();
+ //create hierarchy
+ QList<Token>sub=reduceTokens(d->tokens[0].subTokens());
+ //scan for commas
QList<Token>par;
for(int i=0;i<sub.size();i++){
if(sub[i].type()==Token::Comma){
d->subexpr<<Expression(d->parent,par);
par.clear();
- }
+ }else par<<sub[i];
}
+ //last component
if(par.size()>0){
d->subexpr<<Expression(d->parent,par);
}
QVariant Expression::evaluate()
{
- if(d->type==Exception)return d->excep;
- if(d->parent.isNull())return ELAM::Exception(ELAM::Exception::OperationError,"Lost engine context, cannot evaluate.");
- return QVariant();
+ //basic checks
+ if(d->type==Exception)
+ return d->excep;
+ if(d->parent.isNull())
+ return ELAM::Exception(ELAM::Exception::OperationError,"Lost engine context, cannot evaluate.");
+ //check type
+ switch(d->type){
+ case Literal:return d->tokens[0].literalValue();
+ case Variable:
+ case Constant:{
+ QString n=d->tokens[0].content();
+ if(d->parent->hasValue(n))
+ return d->parent->getValue(n);
+ else
+ return ELAM::Exception(ELAM::Exception::UnknownValueError, "unknown variable or constant", d->tokens[0].position());
+ }
+ case Parentheses:return d->subexpr[0].evaluate();
+ case Function:return evalFunction();
+ case UnaryOp:return evalUnary();
+ case BinaryOp:
+ return evalBinary();
+ case AssignmentOp:
+ return evalAssign();
+ default:
+ return ELAM::Exception(ELAM::Exception::OperationError, "internal error: unknown expression type", position());
+ }
}
-void printExpression(QDebug&dbg,const Expression&ex,int level)
+QVariant Expression::evalBinary()
+{
+ QString un=d->tokens.value(d->oppos).content();
+ if(d->type==AssignmentOp)
+ un=d->parent->characterClasses().toOperator(un);
+ if(!d->parent->hasBinaryOperator(un))
+ return ELAM::Exception(ELAM::Exception::UnknownOperatorError,"unknown operator", position());
+ //get sub-expression and check for exception
+ QVariant sub1=d->subexpr[0].evaluate();
+ if(sub1.userType()==ELAM::Exception::metaTypeId())
+ return sub1;
+ QVariant sub2=d->subexpr[1].evaluate();
+ if(sub2.userType()==ELAM::Exception::metaTypeId())
+ return sub2;
+ //get operator
+ BinaryOperator binop=d->parent->binaryOperator(un);
+ //perform operation
+ QVariant r=binop.execute(sub1,sub2);
+ if(r.userType()==Exception::metaTypeId()){
+ ELAM::Exception ex=r;
+ if(!ex.position().isValid())
+ ex.setPosition(position());
+ }
+ return r;
+}
+
+QVariant Expression::evalAssign()
+{
+ QString un=d->tokens.value(d->oppos).content();
+ QVariant r;
+ //execute operations to gain result
+ if(d->parent->characterClasses().isSimpleAssignment(un))
+ r=d->subexpr[1].evaluate();
+ else
+ r=evalBinary();
+ //check for exception
+ if(r.userType()!=ELAM::Exception::metaTypeId())
+ d->parent->setVariable(d->tokens[0].content(),r);
+ //return result
+ return r;
+}
+
+
+QVariant Expression::evalFunction()
{
+ //basic checks
+ QString fn=d->tokens[0].content();
+ ELAM::Function func=d->parent->getFunction(fn);
+ if(func==0)
+ return ELAM::Exception(ELAM::Exception::UnknownFunctionError, "unknown function", position());
+ //gather arguments
+ QList<QVariant>args;
+ for(int i=0;i<d->subexpr.size();i++)
+ args<<d->subexpr[i].evaluate();
+ //execute
+ return func(args);
+}
+
+QVariant Expression::evalUnary()
+{
+ QString un=d->tokens.value(d->oppos).content();
+ if(!d->parent->hasUnaryOperator(un))
+ return ELAM::Exception(ELAM::Exception::UnknownOperatorError,"unknown operator", position());
+ //get sub-expression
+ QVariant sub=d->subexpr[0].evaluate();
+ //check for exception
+ if(sub.userType()==ELAM::Exception::metaTypeId())
+ return sub;
+ //get operator
+ UnaryOperator unop=d->parent->unaryOperator(un);
+ //perform operation
+ return unop.execute(sub);
+}
+
+
+Position Expression::position() const
+{
+ switch(d->type){
+ case Expression::Literal:
+ case Expression::Variable:
+ case Expression::Constant:
+ case Expression::Function:
+ case Expression::Parentheses:
+ return d->tokens.value(0).position();
+ case Expression::UnaryOp:
+ case Expression::BinaryOp:
+ case Expression::AssignmentOp:
+ return d->tokens.value(d->oppos).position();
+ case Expression::Exception:
+ return d->excep.errorPos();
+ default:
+ return Position();
+ }
+}
+
+
+void Expression::printExpression(QDebug&dbg,const Expression&ex,int level)
+{
+ dbg.nospace();
printspaces(dbg,level);
dbg<<"Expression(type=";
+ int ptok=-1;
switch(ex.d->type){
- case Expression::Literal:dbg<<"Literal";break;
- case Expression::Variable:dbg<<"Variable";break;
- case Expression::Constant:dbg<<"Constant";break;
- case Expression::Function:dbg<<"Function";break;
- case Expression::Parentheses:dbg<<"Parentheses";break;
- case Expression::UnaryOp:dbg<<"UnaryOperator";break;
- case Expression::BinaryOp:dbg<<"BinaryOperator";break;
- case Expression::AssignmentOp:dbg<<"Assignment";break;
- case Expression::Exception:dbg<<"Exception";break;
- default:dbg<<"Unknown:"<<(int)ex.d->type;break;
+ case Expression::Literal:
+ dbg<<"Literal";
+ ptok=0;
+ break;
+ case Expression::Variable:
+ dbg<<"Variable";
+ ptok=0;
+ break;
+ case Expression::Constant:
+ dbg<<"Constant";
+ ptok=0;
+ break;
+ case Expression::Function:
+ dbg<<"Function";
+ ptok=0;
+ break;
+ case Expression::Parentheses:
+ dbg<<"Parentheses";
+ break;
+ case Expression::UnaryOp:
+ dbg<<"UnaryOperator:" <<ex.d->tokens.value(ex.d->oppos).content() <<"sub1";
+ break;
+ case Expression::BinaryOp:
+ dbg<<"BinaryOperator:sub1" <<ex.d->tokens.value(ex.d->oppos).content() <<"sub2";
+ break;
+ case Expression::AssignmentOp:
+ dbg<<"Assignment:sub1" <<ex.d->tokens.value(ex.d->oppos).content() <<"sub2";
+ break;
+ case Expression::Exception:
+ dbg<<"Exception";
+ break;
+ default:
+ dbg<<"Unknown:id="<<(int)ex.d->type;
+ break;
}
+ dbg<<","<<ex.d->tokens.size()<<" tokens,pos="<<ex.position();dbg.nospace();
if(ex.d->excep.errorType()!=ELAM::Exception::NoError)
dbg<<",exception="<<ex.d->excep;
+ if(ptok>=0){
+ dbg<<",token "<<ptok<<":\n";
+ printtoken(dbg,ex.d->tokens.value(0),level+1);
+ dbg.nospace();
+ }
if(ex.d->subexpr.size()>0){
dbg<<",subexpressions:";
for(int i=0;i<ex.d->subexpr.size();i++){
dbg<<"\n";
printExpression(dbg,ex.d->subexpr[i],level+1);
+ dbg.nospace();
}
}
dbg<<")";
}
-QDebug& operator<<(QDebug&dbg,const Expression&ex)
+QDebug& operator<<(QDebug dbg,const Expression&ex)
{
dbg.nospace();
- printExpression(dbg,ex,0);
+ Expression::printExpression(dbg,ex,0);
return dbg.space();
}
inline bool isLiteral()const{return type()&LiteralMask;}
protected:
friend class Expression;
+ ///makes the tokens type more specialized
void setSubType(Type);
+ ///adds a token to the sub-token list
void addSubToken(const Token&);
+ ///overrides the list of sub-tokens
void setSubTokens(const QList<Token>&);
};
-QDebug& operator<<(QDebug&,const Token&);
+///makes tokens accessable to qDebug()
+QDebug& operator<<(QDebug,const Token&);
+///makes tokens accessable to qDebug()
+QDebug& operator<<(QDebug,const QList<Token>&);
class Engine;
/**Represents an expression in the context of its engine.
///evaluates the expression and returns the result of the evaluation
QVariant evaluate();
+
+ ///returns the position of the main element of this expression
+ Position position()const;
private:
- friend void printExpression(QDebug&,const Expression&,int);
+ friend QDebug& operator<<(QDebug,const Expression&);
+ ///helper for qDebug()
+ static void printExpression(QDebug&,const Expression&,int);
///scan tokens and decide what specific sub-type they are
QList<Token>classifyTokens(QList<Token> toks);
/**pushes parentheses and function arguments into the sub-tokens of their parents;
QList<Token>simplifyTokens(QList<Token> toks);
///parses tokens and splits them by comma
void functionInit();
+ ///helper for evaluate - evaluates a function
+ QVariant evalFunction();
+ ///helper for evaluate - evaluates an unary operator
+ QVariant evalUnary();
+ ///helper for evaluate - evaluates an binary operator
+ QVariant evalBinary();
+ ///helper for evaluate - evaluates an assignment and an optional binary operator
+ QVariant evalAssign();
};
-QDebug& operator<<(QDebug&,const Expression&);
+///makes expressions accessable to qDebug()
+QDebug& operator<<(QDebug,const Expression&);
//end of namespace
};
QVariant UnaryOperator::execute(const QVariant& op) const
{
if(d->callmap.size()==0)
- return qVariantFromValue<Exception>(Exception(Exception::UnknownOperatorError));
+ return Exception(Exception::UnknownOperatorError);
//search for direct match
- if(d->callmap.contains(op.type()))
- return d->callmap[op.type()](op);
+ if(d->callmap.contains(op.userType()))
+ return d->callmap[op.userType()](op);
//search for fallback
int any=AnyType::metaTypeId();
if(d->callmap.contains(any))
return d->callmap[any](op);
- return qVariantFromValue<Exception>(Exception(Exception::TypeMismatchError));
+ return Exception(Exception::TypeMismatchError);
}
QList< int > UnaryOperator::getTypeIds() const
d->callmap.remove(t);
}
+bool UnaryOperator::isNull() const
+{
+ return d->callmap.isEmpty();
+}
+
//end of namespace
};
\ No newline at end of file
///calls the callback function associated with the type of the argument, throws an exception if there is no callback
QVariant execute(const QVariant&)const;
+
+ ///true if this operator has no callbacks
+ bool isNull()const;
};
//end of namespace
{
operator=(e);
}
+
+Exception::Exception(const QVariant& v)
+{
+ operator=(v.value<Exception>());
+}
+Exception::Exception(Exception::ErrorType type, Position pos, QString errorText)
+{
+ mtype=type;
+ merr=errorText;
+ mpos=pos;
+}
+
+
Exception::Exception(ErrorType tp,QString errText, Position pos)
{
mtype=tp;
{
return Exception_metaid;
}
+
Exception& Exception::operator=(const Exception& e)
{
mtype=e.mtype;
return AnyType_metaid;
}
-QDebug& operator<< ( QDebug& dbg, const ELAM::Position& pos)
+QDebug& operator<< ( QDebug dbg, const ELAM::Position& pos)
{
if(!pos.isValid())dbg.nospace()<<"Position(invalid)";
else dbg.nospace()<<"Position(line="<<pos.line()<<",col="<<pos.column()<<")";
return dbg.space();
}
+QDebug&operator<<(QDebug dbg,const Exception&ex)
+{
+ dbg.nospace()<<"Exception(type=";
+ switch(ex.errorType()){
+ case Exception::NoError:dbg<<"NoError";break;
+ case Exception::ParserError:dbg<<"ParserError";break;
+ case Exception::UnknownOperatorError:dbg<<"UnknownOperation";break;
+ case Exception::UnknownFunctionError:dbg<<"UnknownFunction";break;
+ case Exception::UnknownValueError:dbg<<"UnknownValue";break;
+ case Exception::TypeMismatchError:dbg<<"TypeMismatch";break;
+ case Exception::ArgumentListError:dbg<<"ArgumentList";break;
+ case Exception::OperationError:dbg<<"Operation";break;
+ default:dbg<<"Unknown:"<<(int)ex.errorType();break;
+ }
+ if(ex.errorText()!="")
+ dbg<<",text="<<ex.errorText();
+ dbg<<",pos="<<ex.errorPos();
+ dbg.nospace()<<")";
+ return dbg.space();
+}
+QDebug&operator<<(QDebug dbg,const AnyType&){dbg.nospace()<<"AnyType";return dbg.space();}
+
//end of namespace
};
\ No newline at end of file
private:
int mline,mcol;
};
-QDebug&operator<<(QDebug&,const Position&);
+QDebug&operator<<(QDebug,const Position&);
/**Objects of this class represent an exception in the evaluation of an ELAM expression.*/
class Exception
UnknownOperatorError,
///the function is not known
UnknownFunctionError,
+ ///unknown variable or constant
+ UnknownValueError,
///the operator or function is known, but the type of one of the arguments is not supported
TypeMismatchError,
///the amount of arguments to a function is wrong or the syntax of arguments
///instantiates a copy of an exception
Exception(const Exception&);
+ ///instantiate a copy from a matching variant
+ Exception(const QVariant&);
/**instantiates an exception
\param type the type of exception
\param errorText some human readable text describing the problem
ErrorType errorType()const{return mtype;}
///the position in the original expression where the error originated
Position errorPos()const{return mpos;}
+ ///the position in the original expression where the error originated
+ Position position()const{return mpos;}
///the line in the original expression where the error originated
int errorLine()const{return mpos.line();}
///the column in the original expression where the error originated
int errorColumn()const{return mpos.column();}
+ ///overrides the exceptions position
+ void setPosition(Position p){mpos=p;}
+
///converts the exception to a variant
operator QVariant()const{return QVariant::fromValue<Exception>(*this);}
Position mpos;
};
+QDebug&operator<<(QDebug,const Exception&);
+
/**this type is not actually used, its ID is used as a fallback to tell operators, functions and engines that any supported type can be used*/
class AnyType
{
///returns the meta type ID of the ANY type
static int metaTypeId();
};
+QDebug&operator<<(QDebug,const AnyType&);
//end of namespace
};
+
Q_DECLARE_METATYPE(ELAM::Exception);
Q_DECLARE_METATYPE(ELAM::AnyType);
{
IntEngine ie;
FloatEngine::configureFloatEngine(ie);
- QString exs="a=b+=345*int(3.5)+ - -(+65/(5))";
+ ie.setVariable("b",(qlonglong)0);
+ QString exs="a=b+=345*int(3.15)+ - -(+65/(5))";
Expression ex=ie.expression(exs);
- qDebug()<<"expression:"<<ex;
+// qDebug()<<"expression:\n"<<ex;
QVariant v=ie.evaluate(ex);
+ QVariant xv=Exception();
+// if(v.userType()==Exception::metaTypeId())qDebug()<<"exception:"<<Exception(v);
+ QVariant cmp=(qlonglong)(345*3+65/5);
+ QCOMPARE(v,cmp);
+ QCOMPARE(ie.getVariable("b"),cmp);
+ QCOMPARE(ie.getVariable("a"),cmp);
+ QCOMPARE(ie.evaluate("-2"),QVariant((qlonglong)-2));
+ ie.setVariable("v",(qlonglong)2);
+ ie.setConstant("c",(qlonglong)-3);
+ QCOMPARE(ie.evaluate("-v"),QVariant((qlonglong)-2));
+ QCOMPARE(ie.evaluate("-c"),QVariant((qlonglong)3));
+
+}
+
+static QVariant mycount(const QList<QVariant>&args)
+{
+ return (qlonglong)args.size();
+}
+static QVariant mysum(const QList<QVariant>&args)
+{
+ qlonglong r=0;
+ for(int i=0;i<args.size();i++)
+ r+=args[i].toLongLong();
+ return r;
+}
+
+void ElamTest::excepttest()
+{
+ IntEngine ie;
+ QVariant v=ie.evaluate("-novar");
+ QCOMPARE(v.userType(),Exception::metaTypeId());
+ Exception ex=v;
+// qDebug()<<ex;
+ QCOMPARE(ex.errorType(),Exception::UnknownValueError);
+ ex=ie.evaluate("9/0");
+ QCOMPARE(ex.errorType(),Exception::OperationError);
+ ex=ie.evaluate("(novar)");
+ QCOMPARE(ex.errorType(),Exception::UnknownValueError);
+}
+
+void ElamTest::counttest()
+{
+ IntEngine ie;
+ ie.setFunction("count",mycount);
+ QCOMPARE(ie.evaluate("count(1,2,3,count(4,5,6))"),QVariant((qlonglong)4));
+}
+
+void ElamTest::functest()
+{
+ IntEngine ie;
+ ie.setFunction("count",mycount);
+ ie.setFunction("sum",mysum);
+ QCOMPARE(ie.evaluate("sum(1,2,3,count(1,x,n))"),QVariant((qlonglong)9));
}
Q_OBJECT
private slots:
void evaltest();
+ void excepttest();
+ void counttest();
+ void functest();
};
#include <QtCore>
#include <QtTest>
-#include <QDebug>
+// #include <QDebug>
using namespace ELAM;