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() << ")"; } }
ExpOperation* ExpEvaluator::popOne(ObjList& stack) { ExpOperation* o = 0; for (;;) { o = static_cast<ExpOperation*>(stack.get()); if (o || !stack.next()) break; // non-terminal NULL - remove the list entry stack.remove(); } if (o && o->barrier()) { XDebug(DebugInfo,"Not popping barrier %u: '%s'='%s'",o->opcode(),o->name().c_str(),o->c_str()); return 0; } stack.remove(o,false); #ifdef DEBUG #ifdef XDEBUG Debug(DebugAll,"popOne: %p%s%s",o, (YOBJECT(ExpFunction,o) ? " function" : ""), (YOBJECT(ExpWrapper,o) ? " wrapper" : "")); #else Debug(DebugAll,"popOne: %p",o); #endif #endif return o; }
ExpOperation* ExpEvaluator::popValue(ObjList& stack, GenObject* context) const { ExpOperation* oper = popOne(stack); if (!oper || (oper->opcode() != OpcField)) return oper; XDebug(DebugAll,"ExpEvaluator::popValue() field '%s' [%p]", oper->name().c_str(),this); bool ok = runField(stack,*oper,context); TelEngine::destruct(oper); return ok ? popOne(stack) : 0; }
ExpOperation* ExpEvaluator::popAny(ObjList& stack) { ExpOperation* o = 0; for (;;) { o = static_cast<ExpOperation*>(stack.get()); if (o || !stack.next()) break; // non-terminal NULL - remove the list entry stack.remove(); } stack.remove(o,false); #ifdef DEBUG #ifdef XDEBUG Debug(DebugAll,"popAny: %p%s%s '%s'",o, (YOBJECT(ExpFunction,o) ? " function" : ""), (YOBJECT(ExpWrapper,o) ? " wrapper" : ""), (o ? o->name().safe() : (const char*)0)); #else Debug(DebugAll,"popAny: %p '%s'",o,(o ? o->name().safe() : (const char*)0)); #endif #endif return o; }
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); }
void ExpEvaluator::addOpcode(ExpEvaluator::Opcode oper) { DDebug(DebugAll,"addOpcode %u",oper); if (oper == OpcAs) { // the second operand is used just for the field name ExpOperation* o = 0; for (ObjList* l = m_opcodes.skipNull(); l; l=l->skipNext()) o = static_cast<ExpOperation*>(l->get()); if (o && (o->opcode() == OpcField)) { o->m_opcode = OpcPush; o->String::operator=(o->name()); } } m_opcodes.append(new ExpOperation(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); }
ExpOperation* ExpEvaluator::addOpcode(ExpEvaluator::Opcode oper, bool barrier) { DDebug(this,DebugAll,"addOpcode %u (%s)",oper,getOperator(oper)); if (oper == OpcAs) { // the second operand is used just for the field name ExpOperation* o = 0; for (ObjList* l = m_opcodes.skipNull(); l; l=l->skipNext()) o = static_cast<ExpOperation*>(l->get()); if (o && (o->opcode() == OpcField)) { o->m_opcode = OpcPush; o->String::operator=(o->name()); } } ExpOperation* op = new ExpOperation(oper,0,ExpOperation::nonInteger(),barrier); op->lineNumber(lineNumber()); m_opcodes.append(op); return op; }
bool ExpEvaluator::runField(ObjList& stack, const ExpOperation& oper) const { DDebug(DebugAll,"runField(%p,'%s') ext=%p", &stack,oper.name().c_str(),(void*)m_extender); return m_extender && m_extender->runField(this,stack,oper); }
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; }
bool ExpEvaluator::runAssign(ObjList& stack, const ExpOperation& oper, GenObject* context) const { DDebug(this,DebugAll,"runAssign('%s'='%s',%p) ext=%p", oper.name().c_str(),oper.c_str(),context,(void*)m_extender); return m_extender && m_extender->runAssign(stack,oper,context); }