void ExpEvaluator::dump(const ExpOperation& oper, String& res) const { const char* name = getOperator(oper.opcode()); if (name) { res << name; return; } switch (oper.opcode()) { case OpcPush: case OpcCopy: if (oper.isInteger()) res << (int)oper.number(); else res << "'" << oper << "'"; break; case OpcField: res << oper.name(); break; case OpcFunc: res << oper.name() << "(" << (int)oper.number() << ")"; break; default: res << "[" << oper.opcode() << "]"; if (oper.number() && oper.isInteger()) res << "(" << (int)oper.number() << ")"; } }
bool ExpEvaluator::runFunction(ObjList& stack, const ExpOperation& oper) const { DDebug(DebugAll,"runFunction(%p,'%s' %ld) ext=%p", &stack,oper.name().c_str(),oper.number(),(void*)m_extender); if (oper.name() == YSTRING("chr")) { String res; for (long int i = oper.number(); i; i--) { ExpOperation* o = popOne(stack); if (!o) return gotError("ExpEvaluator stack underflow"); res = String((char)o->number()) + res; TelEngine::destruct(o); } stack.append(new ExpOperation(res)); return true; } if (oper.name() == YSTRING("now")) { if (oper.number()) return gotError("Function expects no arguments"); stack.append(new ExpOperation(Time::secNow())); return true; } return m_extender && m_extender->runFunction(this,stack,oper); }
bool ExpEvaluator::runFunction(ObjList& stack, const ExpOperation& oper, GenObject* context) const { DDebug(this,DebugAll,"runFunction(%p,'%s' %ld, %p) ext=%p", &stack,oper.name().c_str(),oper.number(),context,(void*)m_extender); if (oper.name() == YSTRING("chr")) { String res; for (long int i = oper.number(); i; i--) { ExpOperation* o = popValue(stack,context); if (!o) return gotError("ExpEvaluator stack underflow",oper.lineNumber()); res = String((char)o->number()) + res; TelEngine::destruct(o); } pushOne(stack,new ExpOperation(res)); return true; } if (oper.name() == YSTRING("now")) { if (oper.number()) return gotError("Function expects no arguments",oper.lineNumber()); pushOne(stack,new ExpOperation((long int)Time::secNow())); return true; } return m_extender && m_extender->runFunction(stack,oper,context); }
bool ExpEvaluator::runOperation(ObjList& stack, const ExpOperation& oper, GenObject* context) const { DDebug(this,DebugAll,"runOperation(%p,%u,%p) %s",&stack,oper.opcode(),context,getOperator(oper.opcode())); XDebug(this,DebugAll,"stack: %s",dump(stack).c_str()); bool boolRes = true; switch (oper.opcode()) { case OpcPush: case OpcField: pushOne(stack,oper.clone()); break; case OpcCopy: { Mutex* mtx = 0; ScriptRun* runner = YOBJECT(ScriptRun,&oper); if (runner) { if (runner->context()) mtx = runner->context()->mutex(); if (!mtx) mtx = runner; } pushOne(stack,oper.copy(mtx)); } break; case OpcNone: case OpcLabel: break; case OpcDrop: TelEngine::destruct(popOne(stack)); break; case OpcDup: { ExpOperation* op = popValue(stack,context); if (!op) return gotError("ExpEvaluator stack underflow",oper.lineNumber()); pushOne(stack,op->clone()); pushOne(stack,op); } break; case OpcAnd: case OpcOr: case OpcXor: case OpcShl: case OpcShr: case OpcAdd: case OpcSub: case OpcMul: case OpcDiv: case OpcMod: boolRes = false; // fall through case OpcEq: case OpcNe: case OpcLt: case OpcGt: case OpcLe: case OpcGe: { ExpOperation* op2 = popValue(stack,context); ExpOperation* op1 = popValue(stack,context); if (!op1 || !op2) { TelEngine::destruct(op1); TelEngine::destruct(op2); return gotError("ExpEvaluator stack underflow",oper.lineNumber()); } switch (oper.opcode()) { case OpcDiv: case OpcMod: if (!op2->valInteger()) return gotError("Division by zero",oper.lineNumber()); case OpcAdd: if (op1->isInteger() && op2->isInteger()) break; // turn addition into concatenation { String val = *op1 + *op2; TelEngine::destruct(op1); TelEngine::destruct(op2); DDebug(this,DebugAll,"String result: '%s'",val.c_str()); pushOne(stack,new ExpOperation(val)); return true; } default: break; } long int val = 0; switch (oper.opcode()) { case OpcAnd: val = op1->valInteger() & op2->valInteger(); break; case OpcOr: val = op1->valInteger() | op2->valInteger(); break; case OpcXor: val = op1->valInteger() ^ op2->valInteger(); break; case OpcShl: val = op1->valInteger() << op2->valInteger(); break; case OpcShr: val = op1->valInteger() >> op2->valInteger(); break; case OpcAdd: val = op1->valInteger() + op2->valInteger(); break; case OpcSub: val = op1->valInteger() - op2->valInteger(); break; case OpcMul: val = op1->valInteger() * op2->valInteger(); break; case OpcDiv: val = op1->valInteger() / op2->valInteger(); break; case OpcMod: val = op1->valInteger() % op2->valInteger(); break; case OpcLt: val = (op1->valInteger() < op2->valInteger()) ? 1 : 0; break; case OpcGt: val = (op1->valInteger() > op2->valInteger()) ? 1 : 0; break; case OpcLe: val = (op1->valInteger() <= op2->valInteger()) ? 1 : 0; break; case OpcGe: val = (op1->valInteger() >= op2->valInteger()) ? 1 : 0; break; case OpcEq: val = (*op1 == *op2) ? 1 : 0; break; case OpcNe: val = (*op1 != *op2) ? 1 : 0; break; default: break; } TelEngine::destruct(op1); TelEngine::destruct(op2); if (boolRes) { DDebug(this,DebugAll,"Bool result: '%s'",String::boolText(val != 0)); pushOne(stack,new ExpOperation(val != 0)); } else { DDebug(this,DebugAll,"Numeric result: %lu",val); pushOne(stack,new ExpOperation(val)); } } break; case OpcLAnd: case OpcLOr: { ExpOperation* op2 = popValue(stack,context); ExpOperation* op1 = popValue(stack,context); if (!op1 || !op2) { TelEngine::destruct(op1); TelEngine::destruct(op2); return gotError("ExpEvaluator stack underflow",oper.lineNumber()); } bool val = false; switch (oper.opcode()) { case OpcLAnd: val = op1->valBoolean() && op2->valBoolean(); break; case OpcLOr: val = op1->valBoolean() || op2->valBoolean(); break; default: break; } TelEngine::destruct(op1); TelEngine::destruct(op2); DDebug(this,DebugAll,"Bool result: '%s'",String::boolText(val)); pushOne(stack,new ExpOperation(val)); } break; case OpcCat: { ExpOperation* op2 = popValue(stack,context); ExpOperation* op1 = popValue(stack,context); if (!op1 || !op2) { TelEngine::destruct(op1); TelEngine::destruct(op2); return gotError("ExpEvaluator stack underflow",oper.lineNumber()); } String val = *op1 + *op2; TelEngine::destruct(op1); TelEngine::destruct(op2); DDebug(this,DebugAll,"String result: '%s'",val.c_str()); pushOne(stack,new ExpOperation(val)); } break; case OpcAs: { ExpOperation* op2 = popOne(stack); ExpOperation* op1 = popOne(stack); if (!op1 || !op2) { TelEngine::destruct(op1); TelEngine::destruct(op2); return gotError("ExpEvaluator stack underflow",oper.lineNumber()); } pushOne(stack,op1->clone(*op2)); TelEngine::destruct(op1); TelEngine::destruct(op2); } break; case OpcNeg: case OpcNot: case OpcLNot: { ExpOperation* op = popValue(stack,context); if (!op) return gotError("ExpEvaluator stack underflow",oper.lineNumber()); switch (oper.opcode()) { case OpcNeg: pushOne(stack,new ExpOperation(-op->valInteger())); break; case OpcNot: pushOne(stack,new ExpOperation(~op->valInteger())); break; case OpcLNot: pushOne(stack,new ExpOperation(!op->valBoolean())); break; default: pushOne(stack,new ExpOperation(op->valInteger())); break; } TelEngine::destruct(op); } break; case OpcFunc: return runFunction(stack,oper,context) || gotError("Function '" + oper.name() + "' call failed",oper.lineNumber()); case OpcIncPre: case OpcDecPre: case OpcIncPost: case OpcDecPost: { ExpOperation* fld = popOne(stack); if (!fld) return gotError("ExpEvaluator stack underflow",oper.lineNumber()); if (fld->opcode() != OpcField) { TelEngine::destruct(fld); return gotError("Expecting LValue in operator",oper.lineNumber()); } ExpOperation* val = 0; if (!(runField(stack,*fld,context) && (val = popOne(stack)))) { TelEngine::destruct(fld); return false; } long int num = val->valInteger(); switch (oper.opcode()) { case OpcIncPre: num++; (*val) = num; break; case OpcDecPre: num--; (*val) = num; break; case OpcIncPost: (*val) = num; num++; break; case OpcDecPost: (*val) = num; num--; break; default: break; } (*fld) = num; bool ok = runAssign(stack,*fld,context); TelEngine::destruct(fld); if (!ok) { TelEngine::destruct(val); return gotError("Assignment failed",oper.lineNumber()); } pushOne(stack,val); } break; case OpcAssign: { ExpOperation* val = popValue(stack,context); ExpOperation* fld = popOne(stack); if (!fld || !val) { TelEngine::destruct(fld); TelEngine::destruct(val); return gotError("ExpEvaluator stack underflow",oper.lineNumber()); } if (fld->opcode() != OpcField) { TelEngine::destruct(fld); TelEngine::destruct(val); return gotError("Expecting LValue in assignment",oper.lineNumber()); } ExpOperation* op = val->clone(fld->name()); TelEngine::destruct(fld); bool ok = runAssign(stack,*op,context); TelEngine::destruct(op); if (!ok) { TelEngine::destruct(val); return gotError("Assignment failed",oper.lineNumber()); } pushOne(stack,val); } break; default: if (oper.opcode() & OpcAssign) { // assignment by operation ExpOperation* val = popValue(stack,context); ExpOperation* fld = popOne(stack); if (!fld || !val) { TelEngine::destruct(fld); TelEngine::destruct(val); return gotError("ExpEvaluator stack underflow",oper.lineNumber()); } if (fld->opcode() != OpcField) { TelEngine::destruct(fld); TelEngine::destruct(val); return gotError("Expecting LValue in assignment",oper.lineNumber()); } pushOne(stack,fld->clone()); pushOne(stack,fld); pushOne(stack,val); ExpOperation op((Opcode)(oper.opcode() & ~OpcAssign), oper.name(),oper.number(),oper.barrier()); if (!runOperation(stack,op,context)) return false; static const ExpOperation assign(OpcAssign); return runOperation(stack,assign,context); } Debug(this,DebugStub,"Please implement operation %u '%s'", oper.opcode(),getOperator(oper.opcode())); return false; } return true; }