Fixed parsing of { objects } as expressions.

Fixed parsing of "var" declarations.
Fixed indexing and fields of expressions.
Small improvement to speed up the simplification of large code.


git-svn-id: http://voip.null.ro/svn/yate@5146 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2012-06-22 14:06:16 +00:00
parent 306a64c041
commit 3dcef54cd1
5 changed files with 105 additions and 30 deletions

View File

@ -293,7 +293,7 @@ void ExpEvaluator::formatLineNo(String& buf, unsigned int line) const
buf << "line " << line;
}
bool ExpEvaluator::getInstruction(const char*& expr, GenObject* nested)
bool ExpEvaluator::getInstruction(const char*& expr, char stop, GenObject* nested)
{
return false;
}
@ -590,7 +590,7 @@ bool ExpEvaluator::runCompile(const char*& expr, char stop, GenObject* nested)
return true;
}
for (;;) {
while (!stackPos && skipComments(expr) && getInstruction(expr,nested))
while (!stackPos && skipComments(expr) && (*expr != stop) && getInstruction(expr,stop,nested))
;
if (inError())
return false;
@ -634,9 +634,15 @@ bool ExpEvaluator::trySimplify()
{
DDebug(this,DebugInfo,"trySimplify");
bool done = false;
for (unsigned int i = 0; i < m_opcodes.length(); i++) {
for (unsigned int i = 0; ; i++) {
ExpOperation* o = static_cast<ExpOperation*>(m_opcodes[i]);
if (!o || o->barrier())
if (!o) {
if (i >= m_opcodes.length())
break;
else
continue;
}
if (o->barrier())
continue;
switch (o->opcode()) {
case OpcLAnd:

View File

@ -152,7 +152,7 @@ protected:
virtual int getKeyword(const char* str) const;
virtual char skipComments(const char*& expr, GenObject* context = 0);
virtual int preProcess(const char*& expr, GenObject* context = 0);
virtual bool getInstruction(const char*& expr, GenObject* nested);
virtual bool getInstruction(const char*& expr, char stop, GenObject* nested);
virtual bool getSimple(const char*& expr, bool constOnly = false);
virtual Opcode getOperator(const char*& expr);
virtual Opcode getUnaryOperator(const char*& expr);
@ -175,6 +175,7 @@ private:
bool parseSwitch(const char*& expr, GenObject* nested);
bool parseFor(const char*& expr, GenObject* nested);
bool parseWhile(const char*& expr, GenObject* nested);
bool parseVar(const char*& expr);
bool parseTry(const char*& expr, GenObject* nested);
bool parseFuncDef(const char*& expr, bool publish);
bool evalList(ObjList& stack, GenObject* context) const;
@ -882,7 +883,7 @@ bool JsCode::getOneInstruction(const char*& expr, GenObject* nested)
return false;
XDebug(this,DebugAll,"JsCode::getOneInstruction %p '%.30s'",nested,expr);
if (skipComments(expr) == '{') {
if (!getInstruction(expr,nested))
if (!getInstruction(expr,0,nested))
return false;
}
else {
@ -894,12 +895,14 @@ bool JsCode::getOneInstruction(const char*& expr, GenObject* nested)
return true;
}
bool JsCode::getInstruction(const char*& expr, GenObject* nested)
bool JsCode::getInstruction(const char*& expr, char stop, GenObject* nested)
{
if (inError())
return false;
XDebug(this,DebugAll,"JsCode::getInstruction %p '%.30s'",nested,expr);
XDebug(this,DebugAll,"JsCode::getInstruction %p '%.1s' '%.30s'",nested,&stop,expr);
if (skipComments(expr) == '{') {
if (stop == ')')
return false;
expr++;
for (;;) {
if (!runCompile(expr,'}',nested))
@ -930,13 +933,15 @@ bool JsCode::getInstruction(const char*& expr, GenObject* nested)
addOpcode(op);
break;
case OpcReturn:
if (skipComments(expr) == ';')
expr++;
else {
if (!runCompile(expr,';'))
return false;
if (skipComments(expr) == ';')
expr++;
switch (skipComments(expr)) {
case ';':
case '}':
break;
default:
if (!runCompile(expr,';'))
return false;
if ((skipComments(expr) != ';') && (*expr != '}'))
return gotError("Expecting ';' or '}'",expr);
}
addOpcode(op);
break;
@ -979,6 +984,8 @@ bool JsCode::getInstruction(const char*& expr, GenObject* nested)
return gotError("Expecting ';'",expr);
expr++;
break;
case OpcVar:
return parseVar(expr);
case OpcTry:
return parseTry(expr,nested);
case OpcFuncDef:
@ -1100,6 +1107,7 @@ bool JsCode::parseIf(const char*& expr, GenObject* nested)
if (skipComments(expr) != ')')
return gotError("Expecting ')'",expr);
ExpOperation* cond = addOpcode((Opcode)OpcJumpFalse,++m_label);
expr++;
if (!getOneInstruction(++expr,nested))
return false;
const char* save = expr;
@ -1243,6 +1251,23 @@ bool JsCode::parseWhile(const char*& expr, GenObject* nested)
return true;
}
bool JsCode::parseVar(const char*& expr)
{
if (inError())
return false;
XDebug(this,DebugAll,"parseVar '%.30s'",expr);
skipComments(expr);
int len = ExpEvaluator::getKeyword(expr);
if (len <= 0 || expr[len] == '(')
return gotError("Expecting variable name",expr);
String str(expr,len);
if (str.toInteger(s_instr,-1) >= 0 || str.toInteger(s_constants,-1) >= 0)
return gotError("Not a valid variable name",expr);
DDebug(this,DebugAll,"Found variable '%s'",str.safe());
addOpcode((Opcode)OpcVar,str);
return true;
}
bool JsCode::parseTry(const char*& expr, GenObject* nested)
{
addOpcode((Opcode)OpcTry);
@ -1599,6 +1624,15 @@ bool JsCode::runOperation(ObjList& stack, const ExpOperation& oper, GenObject* c
return gotError("Stack underflow",oper.lineNumber());
}
if (op1->opcode() != OpcField) {
ScriptContext* ctx = YOBJECT(ScriptContext,op1);
if (ctx) {
ExpOperation fld(OpcField,*op2);
if (ctx->runField(stack,fld,context)) {
TelEngine::destruct(op1);
TelEngine::destruct(op2);
break;
}
}
TelEngine::destruct(op1);
TelEngine::destruct(op2);
return gotError("Expecting field name",oper.lineNumber());
@ -1617,7 +1651,18 @@ bool JsCode::runOperation(ObjList& stack, const ExpOperation& oper, GenObject* c
TelEngine::destruct(op2);
return gotError("Stack underflow",oper.lineNumber());
}
if (op1->opcode() != OpcField || op2->opcode() != OpcField) {
if (op2->opcode() != OpcField) {
TelEngine::destruct(op1);
TelEngine::destruct(op2);
return gotError("Expecting field names",oper.lineNumber());
}
if (op1->opcode() != OpcField) {
ScriptContext* ctx = YOBJECT(ScriptContext,op1);
if (ctx && ctx->runField(stack,*op2,context)) {
TelEngine::destruct(op1);
TelEngine::destruct(op2);
break;
}
TelEngine::destruct(op1);
TelEngine::destruct(op2);
return gotError("Expecting field names",oper.lineNumber());
@ -1653,6 +1698,21 @@ bool JsCode::runOperation(ObjList& stack, const ExpOperation& oper, GenObject* c
TelEngine::destruct(op);
}
break;
case OpcVar:
{
for (ObjList* l = stack.skipNull(); l; l = l->skipNext()) {
JsObject* jso = YOBJECT(JsObject,l->get());
if (jso && jso->toString() == YSTRING("()")) {
if (!jso->hasField(stack,oper.name(),context)) {
XDebug(this,DebugInfo,"Creating variable '%s' in scope",
oper.name().c_str());
jso->params().setParam(new ExpWrapper(0,oper.name()));
}
break;
}
}
}
break;
case OpcNew:
{
ExpOperation* op = popOne(stack);
@ -1700,7 +1760,7 @@ bool JsCode::runOperation(ObjList& stack, const ExpOperation& oper, GenObject* c
break;
case OpcReturn:
{
ExpOperation* op = popOne(stack);
ExpOperation* op = popValue(stack,context);
bool ok = false;
while (ExpOperation* drop = popAny(stack)) {
ok = drop->opcode() == OpcFunc;

View File

@ -310,7 +310,7 @@ bool JsObject::runAssign(ObjList& stack, const ExpOperation& oper, GenObject* co
XDebug(DebugAll,"JsObject::runAssign() '%s'='%s' in '%s' [%p]",
oper.name().c_str(),oper.c_str(),toString().c_str(),this);
if (frozen()) {
Debug(DebugNote,"Object '%s' is frozen",toString().c_str());
Debug(DebugWarn,"Object '%s' is frozen",toString().c_str());
return false;
}
ExpFunction* ef = YOBJECT(ExpFunction,&oper);

View File

@ -570,10 +570,11 @@ protected:
/**
* Get an instruction or block, advance parsing pointer past it
* @param expr Pointer to text to parse, gets advanced on success
* @param stop Optional character expected after the instruction
* @param nested User defined object passed from nested parsing
* @return True if succeeded, must add the operands internally
*/
virtual bool getInstruction(const char*& expr, GenObject* nested = 0);
virtual bool getInstruction(const char*& expr, char stop = 0, GenObject* nested = 0);
/**
* Get an operand, advance parsing pointer past it

View File

@ -992,13 +992,25 @@ bool JsAssist::init()
{
if (!m_runner)
return false;
JsObject::initialize(m_runner->context());
JsEngine::initialize(m_runner->context());
JsChannel::initialize(m_runner->context(),this);
JsMessage::initialize(m_runner->context());
JsFile::initialize(m_runner->context());
ScriptContext* ctx = m_runner->context();
JsObject::initialize(ctx);
JsEngine::initialize(ctx);
JsChannel::initialize(ctx,this);
JsMessage::initialize(ctx);
JsFile::initialize(ctx);
if (ScriptRun::Invalid == m_runner->reset())
return false;
ScriptContext* chan = YOBJECT(ScriptContext,ctx->getField(m_runner->stack(),YSTRING("Channel"),m_runner));
if (chan) {
JsMessage* jsm = YOBJECT(JsMessage,chan->getField(m_runner->stack(),YSTRING("message"),m_runner));
if (!jsm) {
jsm = new JsMessage(0,ctx->mutex(),false);
ExpWrapper wrap(jsm,"message");
chan->runAssign(m_runner->stack(),wrap,m_runner);
}
if (jsm && jsm->ref())
ExpEvaluator::pushOne(m_runner->stack(),new ExpWrapper(jsm,"(message)"));
}
if (!m_runner->callable("onLoad"))
return true;
ScriptRun* runner = m_runner->code()->createRunner(m_runner->context());
@ -1049,12 +1061,8 @@ bool JsAssist::setMsg(Message* msg)
JsMessage* jsm = YOBJECT(JsMessage,chan->getField(stack,YSTRING("message"),m_runner));
if (jsm)
jsm->setMsg(msg,false);
else {
jsm = new JsMessage(msg,ctx->mutex(),false);
ExpWrapper wrap(jsm,"message");
if (!chan->runAssign(stack,wrap,m_runner))
return false;
}
else
return false;
m_message = jsm;
m_handled = false;
return true;