Added source file name and line number to compiled bytecode and operands.

Report the location in compile and runtime errors.


git-svn-id: http://voip.null.ro/svn/yate@5074 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2012-05-28 13:48:25 +00:00
parent d32634e03f
commit cb19a8c2d3
3 changed files with 281 additions and 82 deletions

View File

@ -61,7 +61,6 @@ static const TokenDict s_operators_c[] =
MAKEOP("&", And),
MAKEOP("|", Or),
MAKEOP("^", Xor),
MAKEOP(".", Cat),
MAKEOP("@", As),
MAKEOP("=", Assign),
{ 0, 0 }
@ -146,12 +145,14 @@ bool ExpExtender::runAssign(ObjList& stack, const ExpOperation& oper, GenObject*
ExpEvaluator::ExpEvaluator(const TokenDict* operators, const TokenDict* unaryOps)
: m_operators(operators), m_unaryOps(unaryOps), m_inError(false), m_extender(0)
: m_operators(operators), m_unaryOps(unaryOps),
m_inError(false), m_lineNo(1), m_extender(0)
{
}
ExpEvaluator::ExpEvaluator(ExpEvaluator::Parser style)
: m_operators(0), m_unaryOps(0), m_inError(false), m_extender(0)
: m_operators(0), m_unaryOps(0),
m_inError(false), m_lineNo(1), m_extender(0)
{
switch (style) {
case C:
@ -167,7 +168,7 @@ ExpEvaluator::ExpEvaluator(ExpEvaluator::Parser style)
ExpEvaluator::ExpEvaluator(const ExpEvaluator& original)
: m_operators(original.m_operators), m_unaryOps(original.unaryOps()),
m_inError(false), m_extender(0)
m_inError(false), m_lineNo(original.lineNumber()), m_extender(0)
{
extender(original.extender());
for (ObjList* l = original.m_opcodes.skipNull(); l; l = l->skipNext()) {
@ -197,9 +198,34 @@ char ExpEvaluator::skipWhites(const char*& expr)
{
if (!expr)
return 0;
while (*expr==' ' || *expr=='\t' || *expr=='\r' || *expr=='\n')
expr++;
return *expr;
char skip = '\0';
for (;; *expr++) {
char c = *expr;
switch (*expr) {
case ' ':
case '\t':
skip = '\0';
continue;
case '\r':
if (skip != c) {
m_lineNo++;
skip = '\n';
}
else
skip = '\0';
continue;
case '\n':
if (skip != c) {
m_lineNo++;
skip = '\r';
}
else
skip = '\0';
continue;
default:
return c;
}
}
}
bool ExpEvaluator::keywordChar(char c) const
@ -208,7 +234,7 @@ bool ExpEvaluator::keywordChar(char c) const
('0' <= c && c <= '9') || (c == '_');
}
char ExpEvaluator::skipComments(const char*& expr, GenObject* context) const
char ExpEvaluator::skipComments(const char*& expr, GenObject* context)
{
return skipWhites(expr);
}
@ -221,7 +247,6 @@ int ExpEvaluator::preProcess(const char*& expr, GenObject* context)
ExpEvaluator::Opcode ExpEvaluator::getOperator(const char*& expr, const TokenDict* operators, bool caseInsensitive) const
{
XDebug(this,DebugAll,"getOperator('%.30s',%p,%s)",expr,operators,String::boolText(caseInsensitive));
skipComments(expr);
if (operators) {
bool kw = keywordChar(*expr);
for (const TokenDict* o = operators; o->token; o++) {
@ -240,25 +265,34 @@ ExpEvaluator::Opcode ExpEvaluator::getOperator(const char*& expr, const TokenDic
return OpcNone;
}
bool ExpEvaluator::gotError(const char* error, const char* text) const
bool ExpEvaluator::gotError(const char* error, const char* text, unsigned int line) const
{
if (!error) {
if (!text)
return false;
error = "unknown error";
}
Debug(this,DebugWarn,"Evaluator error: %s%s%.50s",error,
(text ? " at: " : ""),
c_safe(text));
if (!line)
line = lineNumber();
String lineNo;
formatLineNo(lineNo,line);
Debug(this,DebugWarn,"Evaluator error: %s in %s%s%.50s",error,
lineNo.c_str(),(text ? " at: " : ""),c_safe(text));
return false;
}
bool ExpEvaluator::gotError(const char* error, const char* text)
bool ExpEvaluator::gotError(const char* error, const char* text, unsigned int line)
{
m_inError = true;
return const_cast<const ExpEvaluator*>(this)->gotError(error,text);
}
void ExpEvaluator::formatLineNo(String& buf, unsigned int line) const
{
buf.clear();
buf << "line " << line;
}
bool ExpEvaluator::getInstruction(const char*& expr, Opcode nested)
{
return false;
@ -444,11 +478,13 @@ bool ExpEvaluator::getField(const char*& expr)
ExpEvaluator::Opcode ExpEvaluator::getOperator(const char*& expr)
{
skipComments(expr);
return getOperator(expr,m_operators);
}
ExpEvaluator::Opcode ExpEvaluator::getUnaryOperator(const char*& expr)
{
skipComments(expr);
return getOperator(expr,m_unaryOps);
}
@ -575,6 +611,7 @@ bool ExpEvaluator::runCompile(const char*& expr, char stop, Opcode nested)
}
if (inError())
return false;
skipComments(expr);
oper = getOperator(expr);
if (oper == OpcNone)
return gotError("Operator or separator expected",expr);
@ -630,10 +667,9 @@ bool ExpEvaluator::trySimplify()
if (o->opcode() == OpcLAnd || o->opcode() == OpcAnd || o->opcode() == OpcMul) {
if ((op1->opcode() == OpcPush && !op1->number() && op2->opcode() == OpcField) ||
(op2->opcode() == OpcPush && !op2->number() && op1->opcode() == OpcField)) {
if (o->opcode() == OpcLAnd)
(m_opcodes+i)->set(new ExpOperation(false));
else
(m_opcodes+i)->set(new ExpOperation((long int)0));
ExpOperation* newOp = (o->opcode() == OpcLAnd) ? new ExpOperation(false) : new ExpOperation((long int)0);
newOp->lineNumber(o->lineNumber());
(m_opcodes+i)->set(newOp);
m_opcodes.remove(op1);
m_opcodes.remove(op2);
i -= 2;
@ -644,7 +680,9 @@ bool ExpEvaluator::trySimplify()
if (o->opcode() == OpcLOr) {
if ((op1->opcode() == OpcPush && op1->number() && op2->opcode() == OpcField) ||
(op2->opcode() == OpcPush && op2->number() && op1->opcode() == OpcField)) {
(m_opcodes+i)->set(new ExpOperation(true));
ExpOperation* newOp = new ExpOperation(true);
newOp->lineNumber(o->lineNumber());
(m_opcodes+i)->set(newOp);
m_opcodes.remove(op1);
m_opcodes.remove(op2);
i -= 2;
@ -658,7 +696,9 @@ bool ExpEvaluator::trySimplify()
pushOne(stack,op2->clone());
if (runOperation(stack,*o)) {
// replace operators and operation with computed constant
(m_opcodes+i)->set(popOne(stack));
ExpOperation* newOp = popOne(stack);
newOp->lineNumber(o->lineNumber());
(m_opcodes+i)->set(newOp);
m_opcodes.remove(op1);
m_opcodes.remove(op2);
i -= 2;
@ -679,7 +719,9 @@ bool ExpEvaluator::trySimplify()
pushOne(stack,op->clone());
if (runOperation(stack,*o)) {
// replace unary operator and operation with computed constant
(m_opcodes+i)->set(popOne(stack));
ExpOperation* newOp = popOne(stack);
newOp->lineNumber(o->lineNumber());
(m_opcodes+i)->set(newOp);
m_opcodes.remove(op);
i--;
done = true;
@ -701,6 +743,17 @@ bool ExpEvaluator::trySimplify()
return done;
}
void ExpEvaluator::addOpcode(ExpOperation* oper, unsigned int line)
{
if (!oper)
return;
DDebug(this,DebugAll,"addOpcode %u, %u",oper->opcode(),line);
if (!line)
line = lineNumber();
oper->lineNumber(line);
m_opcodes.append(oper);
}
ExpOperation* ExpEvaluator::addOpcode(ExpEvaluator::Opcode oper, bool barrier)
{
DDebug(this,DebugAll,"addOpcode %u",oper);
@ -715,6 +768,7 @@ ExpOperation* ExpEvaluator::addOpcode(ExpEvaluator::Opcode oper, bool barrier)
}
}
ExpOperation* op = new ExpOperation(oper,0,ExpOperation::nonInteger(),barrier);
op->lineNumber(lineNumber());
m_opcodes.append(op);
return op;
}
@ -723,6 +777,7 @@ ExpOperation* ExpEvaluator::addOpcode(ExpEvaluator::Opcode oper, long int value,
{
DDebug(this,DebugAll,"addOpcode %u %lu",oper,value);
ExpOperation* op = new ExpOperation(oper,0,value,barrier);
op->lineNumber(lineNumber());
m_opcodes.append(op);
return op;
}
@ -731,6 +786,7 @@ ExpOperation* ExpEvaluator::addOpcode(ExpEvaluator::Opcode oper, const String& n
{
DDebug(this,DebugAll,"addOpcode %u '%s' %ld",oper,name.c_str(),value);
ExpOperation* op = new ExpOperation(oper,name,value,barrier);
op->lineNumber(lineNumber());
m_opcodes.append(op);
return op;
}
@ -739,6 +795,7 @@ ExpOperation* ExpEvaluator::addOpcode(const String& value)
{
DDebug(this,DebugAll,"addOpcode ='%s'",value.c_str());
ExpOperation* op = new ExpOperation(value);
op->lineNumber(lineNumber());
m_opcodes.append(op);
return op;
}
@ -747,6 +804,7 @@ ExpOperation* ExpEvaluator::addOpcode(long int value)
{
DDebug(this,DebugAll,"addOpcode =%ld",value);
ExpOperation* op = new ExpOperation(value);
op->lineNumber(lineNumber());
m_opcodes.append(op);
return op;
}
@ -755,6 +813,7 @@ ExpOperation* ExpEvaluator::addOpcode(bool value)
{
DDebug(this,DebugAll,"addOpcode =%s",String::boolText(value));
ExpOperation* op = new ExpOperation(value);
op->lineNumber(lineNumber());
m_opcodes.append(op);
return op;
}
@ -769,6 +828,17 @@ ExpOperation* ExpEvaluator::popOpcode()
return static_cast<ExpOperation*>(l->remove(false));
}
unsigned int ExpEvaluator::getLineOf(ExpOperation* op1, ExpOperation* op2, ExpOperation* op3)
{
if (op1 && op1->lineNumber())
return op1->lineNumber();
if (op2 && op2->lineNumber())
return op2->lineNumber();
if (op3 && op3->lineNumber())
return op3->lineNumber();
return 0;
}
void ExpEvaluator::pushOne(ObjList& stack, ExpOperation* oper)
{
if (oper)
@ -858,13 +928,13 @@ bool ExpEvaluator::runOperation(ObjList& stack, const ExpOperation& oper, GenObj
if (!op1 || !op2) {
TelEngine::destruct(op1);
TelEngine::destruct(op2);
return gotError("ExpEvaluator stack underflow");
return gotError("ExpEvaluator stack underflow",oper.lineNumber());
}
switch (oper.opcode()) {
case OpcDiv:
case OpcMod:
if (!op2->number())
return gotError("Division by zero");
return gotError("Division by zero",oper.lineNumber());
case OpcAdd:
if (op1->isInteger() && op2->isInteger())
break;
@ -953,7 +1023,7 @@ bool ExpEvaluator::runOperation(ObjList& stack, const ExpOperation& oper, GenObj
if (!op1 || !op2) {
TelEngine::destruct(op1);
TelEngine::destruct(op2);
return gotError("ExpEvaluator stack underflow");
return gotError("ExpEvaluator stack underflow",oper.lineNumber());
}
bool val = false;
switch (oper.opcode()) {
@ -979,7 +1049,7 @@ bool ExpEvaluator::runOperation(ObjList& stack, const ExpOperation& oper, GenObj
if (!op1 || !op2) {
TelEngine::destruct(op1);
TelEngine::destruct(op2);
return gotError("ExpEvaluator stack underflow");
return gotError("ExpEvaluator stack underflow",oper.lineNumber());
}
String val = *op1 + *op2;
TelEngine::destruct(op1);
@ -995,7 +1065,7 @@ bool ExpEvaluator::runOperation(ObjList& stack, const ExpOperation& oper, GenObj
if (!op1 || !op2) {
TelEngine::destruct(op1);
TelEngine::destruct(op2);
return gotError("ExpEvaluator stack underflow");
return gotError("ExpEvaluator stack underflow",oper.lineNumber());
}
pushOne(stack,op1->clone(*op2));
TelEngine::destruct(op1);
@ -1008,7 +1078,7 @@ bool ExpEvaluator::runOperation(ObjList& stack, const ExpOperation& oper, GenObj
{
ExpOperation* op = popValue(stack,context);
if (!op)
return gotError("ExpEvaluator stack underflow");
return gotError("ExpEvaluator stack underflow",oper.lineNumber());
long int val = op->number();
TelEngine::destruct(op);
switch (oper.opcode()) {
@ -1028,7 +1098,8 @@ bool ExpEvaluator::runOperation(ObjList& stack, const ExpOperation& oper, GenObj
}
break;
case OpcFunc:
return runFunction(stack,oper,context) || gotError("Function call failed");
return runFunction(stack,oper,context) ||
gotError("Function '" + oper.name() + "' call failed",oper.lineNumber());
case OpcIncPre:
case OpcDecPre:
case OpcIncPost:
@ -1036,10 +1107,10 @@ bool ExpEvaluator::runOperation(ObjList& stack, const ExpOperation& oper, GenObj
{
ExpOperation* fld = popOne(stack);
if (!fld)
return gotError("ExpEvaluator stack underflow");
return gotError("ExpEvaluator stack underflow",oper.lineNumber());
if (fld->opcode() != OpcField) {
TelEngine::destruct(fld);
return gotError("Expecting LValue in operator");
return gotError("Expecting LValue in operator",oper.lineNumber());
}
ExpOperation* val = 0;
if (!(runField(stack,*fld,context) && (val = popOne(stack)))) {
@ -1072,7 +1143,7 @@ bool ExpEvaluator::runOperation(ObjList& stack, const ExpOperation& oper, GenObj
TelEngine::destruct(fld);
if (!ok) {
TelEngine::destruct(val);
return gotError("Assignment failed");
return gotError("Assignment failed",oper.lineNumber());
}
pushOne(stack,val);
}
@ -1084,12 +1155,12 @@ bool ExpEvaluator::runOperation(ObjList& stack, const ExpOperation& oper, GenObj
if (!fld || !val) {
TelEngine::destruct(fld);
TelEngine::destruct(val);
return gotError("ExpEvaluator stack underflow");
return gotError("ExpEvaluator stack underflow",oper.lineNumber());
}
if (fld->opcode() != OpcField) {
TelEngine::destruct(fld);
TelEngine::destruct(val);
return gotError("Expecting LValue in assignment");
return gotError("Expecting LValue in assignment",oper.lineNumber());
}
ExpOperation* op = val->clone(fld->name());
TelEngine::destruct(fld);
@ -1097,7 +1168,7 @@ bool ExpEvaluator::runOperation(ObjList& stack, const ExpOperation& oper, GenObj
TelEngine::destruct(op);
if (!ok) {
TelEngine::destruct(val);
return gotError("Assignment failed");
return gotError("Assignment failed",oper.lineNumber());
}
pushOne(stack,val);
}
@ -1110,12 +1181,12 @@ bool ExpEvaluator::runOperation(ObjList& stack, const ExpOperation& oper, GenObj
if (!fld || !val) {
TelEngine::destruct(fld);
TelEngine::destruct(val);
return gotError("ExpEvaluator stack underflow");
return gotError("ExpEvaluator stack underflow",oper.lineNumber());
}
if (fld->opcode() != OpcField) {
TelEngine::destruct(fld);
TelEngine::destruct(val);
return gotError("Expecting LValue in assignment");
return gotError("Expecting LValue in assignment",oper.lineNumber());
}
pushOne(stack,fld->clone());
pushOne(stack,fld);
@ -1143,7 +1214,7 @@ bool ExpEvaluator::runFunction(ObjList& stack, const ExpOperation& oper, GenObje
for (long int i = oper.number(); i; i--) {
ExpOperation* o = popValue(stack,context);
if (!o)
return gotError("ExpEvaluator stack underflow");
return gotError("ExpEvaluator stack underflow",oper.lineNumber());
res = String((char)o->number()) + res;
TelEngine::destruct(o);
}
@ -1152,7 +1223,7 @@ bool ExpEvaluator::runFunction(ObjList& stack, const ExpOperation& oper, GenObje
}
if (oper.name() == YSTRING("now")) {
if (oper.number())
return gotError("Function expects no arguments");
return gotError("Function expects no arguments",oper.lineNumber());
pushOne(stack,new ExpOperation((long int)Time::secNow()));
return true;
}
@ -1316,10 +1387,20 @@ void ExpEvaluator::dump(const ObjList& codes, String& res) const
}
ExpOperation* ExpOperation::clone(const char* name) const
{
ExpOperation* op = new ExpOperation(*this,name);
op->lineNumber(lineNumber());
return op;
}
ExpOperation* ExpFunction::clone(const char* name) const
{
XDebug(DebugInfo,"ExpFunction::clone('%s') [%p]",name,this);
return new ExpFunction(name,number());
ExpFunction* op = new ExpFunction(name,number());
op->lineNumber(lineNumber());
return op;
}
@ -1329,7 +1410,9 @@ ExpOperation* ExpWrapper::clone(const char* name) const
RefObject* r = YOBJECT(RefObject,object());
if (r)
r->ref();
return new ExpWrapper(object(),name);
ExpWrapper* op = new ExpWrapper(object(),name);
op->lineNumber(lineNumber());
return op;
}
void* ExpWrapper::getObject(const String& name) const

View File

@ -54,6 +54,7 @@ public:
OpcBegin = OpcPrivate + 1,
OpcEnd,
OpcIndex,
OpcFieldOf,
OpcTypeof,
OpcNew,
OpcFor,
@ -103,11 +104,12 @@ public:
JsObject* parseArray(const char*& expr, bool constOnly);
JsObject* parseObject(const char*& expr, bool constOnly);
protected:
virtual void formatLineNo(String& buf, unsigned int line) const;
virtual bool getString(const char*& expr);
virtual bool getEscape(const char*& expr, String& str, char sep);
virtual bool keywordChar(char c) const;
virtual int getKeyword(const char* str) const;
virtual char skipComments(const char*& expr, GenObject* context = 0) 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, Opcode nested);
virtual bool getSimple(const char*& expr, bool constOnly = false);
@ -153,6 +155,7 @@ private:
#define MAKEOP(s,o) { s, JsCode::Opc ## o }
static const TokenDict s_operators[] =
{
MAKEOP(".",FieldOf),
{ 0, 0 }
};
@ -384,6 +387,16 @@ bool JsCode::link()
return true;
}
void JsCode::formatLineNo(String& buf, unsigned int line) const
{
unsigned int fnum = (line >> 24) & 0xff;
if (!fnum)
return ExpEvaluator::formatLineNo(buf,line);
buf.clear();
const GenObject* file = m_included[fnum - 1];
buf << (file ? file->toString().c_str() : "???") << ":" << (line & 0xffffff);
}
bool JsCode::getString(const char*& expr)
{
if (inError())
@ -519,7 +532,7 @@ int JsCode::getKeyword(const char* str) const
return len;
}
char JsCode::skipComments(const char*& expr, GenObject* context) const
char JsCode::skipComments(const char*& expr, GenObject* context)
{
char c = skipWhites(expr);
while (c == '/') {
@ -555,30 +568,32 @@ bool JsCode::preProcessInclude(const char*& expr, bool once, GenObject* context)
return false;
char c = skipComments(expr);
if (c == '"' || c == '\'') {
char sep = c;
const char* start = ++expr;
while ((c = *expr++)) {
if (c != sep)
continue;
String str(start,expr-start-1);
String str;
if (ExpEvaluator::getString(expr,str)) {
DDebug(this,DebugAll,"Found include '%s'",str.safe());
parser->adjustPath(str);
str.trimSpaces();
bool ok = !str.null();
if (ok) {
bool already = m_included.find(str);
if (!(once && already)) {
int idx = m_included.index(str);
if (!(once && (idx >= 0))) {
if (idx < 0) {
String* s = new String(str);
m_included.append(s);
idx = m_included.index(s);
}
// use the upper bits of line # for file index
unsigned int savedLine = m_lineNo;
m_lineNo = ((idx + 1) << 24) | 1;
m_depth++;
ok = parser->parseFile(str,true);
m_depth--;
if (ok && !already)
m_included.append(new String(str));
m_lineNo = savedLine;
}
}
return ok || gotError("Failed to include " + str);
}
expr--;
return gotError("Expecting string end");
return false;
}
return gotError("Expecting include file",expr);
}
@ -587,6 +602,7 @@ int JsCode::preProcess(const char*& expr, GenObject* context)
{
int rval = -1;
for (;;) {
skipComments(expr);
JsOpcode opc = (JsOpcode)ExpEvaluator::getOperator(expr,s_preProc);
switch (opc) {
case OpcInclude:
@ -628,6 +644,7 @@ bool JsCode::getInstruction(const char*& expr, Opcode nested)
return true;
}
const char* saved = expr;
skipComments(expr);
Opcode op = ExpEvaluator::getOperator(expr,s_instr);
switch ((JsOpcode)op) {
case (JsOpcode)OpcNone:
@ -655,6 +672,7 @@ bool JsCode::getInstruction(const char*& expr, Opcode nested)
if (skipComments(expr) == ';')
expr++;
const char* save = expr;
skipComments(expr);
if ((JsOpcode)ExpEvaluator::getOperator(expr,s_instr) == OpcElse) {
ExpOperation* jump = addOpcode((Opcode)OpcJump,++m_label);
addOpcode(OpcLabel,cond->number());
@ -702,6 +720,7 @@ bool JsCode::getInstruction(const char*& expr, Opcode nested)
if (!runCompile(expr,0,op))
return false;
{
skipComments(expr);
if ((JsOpcode)ExpEvaluator::getOperator(expr,s_instr) == OpcCatch) {
if (skipComments(expr) != '(')
return gotError("Expecting '('",expr);
@ -712,6 +731,7 @@ bool JsCode::getInstruction(const char*& expr, Opcode nested)
if (!runCompile(++expr))
return false;
}
skipComments(expr);
if ((JsOpcode)ExpEvaluator::getOperator(expr,s_instr) == OpcFinally) {
if (!runCompile(expr))
return false;
@ -766,6 +786,7 @@ bool JsCode::getNumber(const char*& expr)
{
if (inError())
return false;
skipComments(expr);
switch ((JsOpcode)ExpEvaluator::getOperator(expr,s_bools)) {
case OpcFalse:
addOpcode(false);
@ -784,6 +805,7 @@ ExpEvaluator::Opcode JsCode::getOperator(const char*& expr)
if (inError())
return OpcNone;
XDebug(this,DebugAll,"JsCode::getOperator '%.30s'",expr);
skipComments(expr);
Opcode op = ExpEvaluator::getOperator(expr,s_operators);
if (OpcNone != op)
return op;
@ -795,6 +817,7 @@ ExpEvaluator::Opcode JsCode::getUnaryOperator(const char*& expr)
if (inError())
return OpcNone;
XDebug(this,DebugAll,"JsCode::getUnaryOperator '%.30s'",expr);
skipComments(expr);
Opcode op = ExpEvaluator::getOperator(expr,s_unaryOps);
if (OpcNone != op)
return op;
@ -816,6 +839,7 @@ ExpEvaluator::Opcode JsCode::getPostfixOperator(const char*& expr)
expr++;
return (Opcode)OpcIndex;
}
skipComments(expr);
Opcode op = ExpEvaluator::getOperator(expr,s_postfixOps);
if (OpcNone != op)
return op;
@ -846,6 +870,8 @@ int JsCode::getPrecedence(ExpEvaluator::Opcode oper) const
case OpcNew:
case OpcIndex:
return 12;
case OpcFieldOf:
return 13;
default:
return ExpEvaluator::getPrecedence(oper);
}
@ -874,7 +900,7 @@ bool JsCode::getSimple(const char*& expr, bool constOnly)
jso = parseObject(expr,constOnly);
if (!jso)
return false;
m_opcodes.append(new ExpWrapper(jso));
addOpcode(new ExpWrapper(jso));
return true;
}
@ -976,7 +1002,7 @@ bool JsCode::runOperation(ObjList& stack, const ExpOperation& oper, GenObject* c
}
if (!b) {
TelEngine::destruct(op);
return gotError("ExpEvaluator stack underflow");
return gotError("ExpEvaluator stack underflow",oper.lineNumber());
}
b->clear();
pushOne(stack,op);
@ -989,23 +1015,42 @@ bool JsCode::runOperation(ObjList& stack, const ExpOperation& oper, GenObject* c
if (!op1 || !op2) {
TelEngine::destruct(op1);
TelEngine::destruct(op2);
return gotError("Stack underflow");
return gotError("Stack underflow",oper.lineNumber());
}
if (op1->opcode() != OpcField) {
TelEngine::destruct(op1);
TelEngine::destruct(op2);
return gotError("Expecting field name");
return gotError("Expecting field name",oper.lineNumber());
}
pushOne(stack,new ExpOperation(OpcField,op1->name() + "." + *op2));
TelEngine::destruct(op1);
TelEngine::destruct(op2);
}
break;
case OpcFieldOf:
{
ExpOperation* op2 = popOne(stack);
ExpOperation* op1 = popOne(stack);
if (!op1 || !op2) {
TelEngine::destruct(op1);
TelEngine::destruct(op2);
return gotError("Stack underflow",oper.lineNumber());
}
if (op1->opcode() != OpcField || op2->opcode() != OpcField) {
TelEngine::destruct(op1);
TelEngine::destruct(op2);
return gotError("Expecting field names",oper.lineNumber());
}
pushOne(stack,new ExpOperation(OpcField,op1->name() + "." + op2->name()));
TelEngine::destruct(op1);
TelEngine::destruct(op2);
}
break;
case OpcTypeof:
{
ExpOperation* op = popValue(stack,context);
if (!op)
return gotError("Stack underflow");
return gotError("Stack underflow",oper.lineNumber());
switch (op->opcode()) {
case OpcPush:
{
@ -1031,7 +1076,7 @@ bool JsCode::runOperation(ObjList& stack, const ExpOperation& oper, GenObject* c
{
ExpOperation* op = popOne(stack);
if (!op)
return gotError("Stack underflow");
return gotError("Stack underflow",oper.lineNumber());
switch (op->opcode()) {
case OpcField:
break;
@ -1046,7 +1091,7 @@ bool JsCode::runOperation(ObjList& stack, const ExpOperation& oper, GenObject* c
// fall through
default:
TelEngine::destruct(op);
return gotError("Expecting class name");
return gotError("Expecting class name",oper.lineNumber());
}
ExpFunction ctr(op->name(),op->number());
TelEngine::destruct(op);
@ -1057,7 +1102,7 @@ bool JsCode::runOperation(ObjList& stack, const ExpOperation& oper, GenObject* c
{
ExpOperation* op = popOne(stack);
if (!op)
return gotError("Stack underflow");
return gotError("Stack underflow",oper.lineNumber());
bool ok = false;
while (ExpOperation* drop = popAny(stack)) {
JsOpcode c = (JsOpcode)drop->opcode();
@ -1068,7 +1113,7 @@ bool JsCode::runOperation(ObjList& stack, const ExpOperation& oper, GenObject* c
}
}
if (!ok)
return gotError("Uncaught exception: " + *op);
return gotError("Uncaught exception: " + *op,oper.lineNumber());
pushOne(stack,op);
}
break;
@ -1089,7 +1134,7 @@ bool JsCode::runOperation(ObjList& stack, const ExpOperation& oper, GenObject* c
}
if (!ok) {
TelEngine::destruct(op);
return gotError("Return outside function call");
return gotError("Return outside function call",oper.lineNumber());
}
pushOne(stack,op);
}
@ -1101,7 +1146,7 @@ bool JsCode::runOperation(ObjList& stack, const ExpOperation& oper, GenObject* c
{
ExpOperation* op = popValue(stack,context);
if (!op)
return gotError("Stack underflow");
return gotError("Stack underflow",oper.lineNumber());
bool val = op->number() != 0;
TelEngine::destruct(op);
switch ((JsOpcode)oper.opcode()) {
@ -1126,11 +1171,11 @@ bool JsCode::runOperation(ObjList& stack, const ExpOperation& oper, GenObject* c
case OpcJump:
case OpcJumpTrue:
case OpcJumpFalse:
return jumpToLabel(oper.number(),context) || gotError("Label not found");
return jumpToLabel(oper.number(),context) || gotError("Label not found",oper.lineNumber());
case OpcJRel:
case OpcJRelTrue:
case OpcJRelFalse:
return jumpRelative(oper.number(),context) || gotError("Relative jump failed");
return jumpRelative(oper.number(),context) || gotError("Relative jump failed",oper.lineNumber());
default:
return false;
}

View File

@ -283,6 +283,13 @@ public:
inline bool inError() const
{ return m_inError; }
/**
* Retrieve the number of line currently being parsed
* @return Number of current parsed line, 1 is the first line
*/
inline unsigned int lineNumber() const
{ return m_lineNo; }
/**
* Check if the expression is empty (no operands or operators)
* @return True if the expression is completely empty
@ -346,6 +353,15 @@ public:
*/
void extender(ExpExtender* ext);
/**
* Retrieve the line number from one to three operands
* @param op1 First operand
* @param op2 Optional second operand
* @param op3 Optional third operand
* @return Line number at compile time, zero if not found
*/
static unsigned int getLineOf(ExpOperation* op1, ExpOperation* op2 = 0, ExpOperation* op3 = 0);
/**
* Push an operand on an evaluation stack
* @param stack Evaluation stack to remove the operand from
@ -395,11 +411,11 @@ public:
protected:
/**
* Helper method to skip over whitespaces
* Method to skip over whitespaces, count parsed lines too
* @param expr Pointer to expression cursor, gets advanced
* @return First character after whitespaces where expr points
*/
static char skipWhites(const char*& expr);
virtual char skipWhites(const char*& expr);
/**
* Helper method to conditionally convert to lower case
@ -437,17 +453,44 @@ protected:
* Helper method to display debugging errors internally
* @param error Text of the error
* @param text Optional text that caused the error
* @param line Number of line generating the error, zero for parsing errors
* @return Always returns false
*/
bool gotError(const char* error = 0, const char* text = 0) const;
bool gotError(const char* error = 0, const char* text = 0, unsigned int line = 0) const;
/**
* Helper method to set error flag and display debugging errors internally
* @param error Text of the error
* @param text Optional text that caused the error
* @param line Number of line generating the error, zero for parsing errors
* @return Always returns false
*/
bool gotError(const char* error = 0, const char* text = 0);
bool gotError(const char* error = 0, const char* text = 0, unsigned int line = 0);
/**
* Helper method to display debugging errors internally
* @param error Text of the error
* @param line Number of line generating the error, zero for parsing errors
* @return Always returns false
*/
inline bool gotError(const char* error, unsigned int line) const
{ return gotError(error, 0, line); }
/**
* Helper method to set error flag and display debugging errors internally
* @param error Text of the error
* @param line Number of line generating the error, zero for parsing errors
* @return Always returns false
*/
inline bool gotError(const char* error, unsigned int line)
{ return gotError(error, 0, line); }
/**
* Formats a line number to display in error messages
* @param buf String buffer used to return the value
* @param line Line number to format
*/
virtual void formatLineNo(String& buf, unsigned int line) const;
/**
* Runs the parser and compiler for one (sub)expression
@ -464,7 +507,7 @@ protected:
* @param context Pointer to arbitrary object to be passed to called methods
* @return First character after comments or whitespaces where expr points
*/
virtual char skipComments(const char*& expr, GenObject* context = 0) const;
virtual char skipComments(const char*& expr, GenObject* context = 0);
/**
* Process top-level preprocessor directives
@ -593,6 +636,13 @@ protected:
*/
virtual bool getField(const char*& expr);
/**
* Add an aready built operation to the expression and set its line number
* @param oper Operation to add
* @param line Line number where operation was compiled, zero to used parsing point
*/
void addOpcode(ExpOperation* oper, unsigned int line = 0);
/**
* Add a simple operator to the expression
* @param oper Operator code to add
@ -728,6 +778,11 @@ protected:
*/
bool m_inError;
/**
* Current line index
*/
unsigned int m_lineNo;
private:
ExpExtender* m_extender;
};
@ -755,7 +810,7 @@ public:
inline ExpOperation(const ExpOperation& original)
: NamedString(original.name(),original),
m_opcode(original.opcode()), m_number(original.number()),
m_barrier(original.barrier())
m_lineNo(0), m_barrier(original.barrier())
{ }
/**
@ -766,7 +821,7 @@ public:
inline ExpOperation(const ExpOperation& original, const char* name)
: NamedString(name,original),
m_opcode(original.opcode()), m_number(original.number()),
m_barrier(original.barrier())
m_lineNo(0), m_barrier(original.barrier())
{ }
/**
@ -779,7 +834,7 @@ public:
: NamedString(name,value),
m_opcode(ExpEvaluator::OpcPush),
m_number(autoNum ? value.toLong(nonInteger()) : nonInteger()),
m_barrier(false)
m_lineNo(0), m_barrier(false)
{ if (autoNum && value.isBoolean()) m_number = value.toBoolean() ? 1 : 0; }
/**
@ -789,7 +844,7 @@ public:
*/
inline explicit ExpOperation(const char* value, const char* name = 0)
: NamedString(name,value),
m_opcode(ExpEvaluator::OpcPush), m_number(nonInteger()), m_barrier(false)
m_opcode(ExpEvaluator::OpcPush), m_number(nonInteger()), m_lineNo(0), m_barrier(false)
{ }
/**
@ -799,7 +854,8 @@ public:
*/
inline explicit ExpOperation(long int value, const char* name = 0)
: NamedString(name,"NaN"),
m_opcode(ExpEvaluator::OpcPush), m_number(value), m_barrier(false)
m_opcode(ExpEvaluator::OpcPush),
m_number(value), m_lineNo(0), m_barrier(false)
{ if (value != nonInteger()) String::operator=((int)value); }
/**
@ -809,7 +865,8 @@ public:
*/
inline explicit ExpOperation(bool value, const char* name = 0)
: NamedString(name,String::boolText(value)),
m_opcode(ExpEvaluator::OpcPush), m_number(value ? 1 : 0), m_barrier(false)
m_opcode(ExpEvaluator::OpcPush),
m_number(value ? 1 : 0), m_lineNo(0), m_barrier(false)
{ }
/**
@ -821,7 +878,7 @@ public:
*/
inline ExpOperation(ExpEvaluator::Opcode oper, const char* name = 0, long int value = nonInteger(), bool barrier = false)
: NamedString(name,""),
m_opcode(oper), m_number(value), m_barrier(barrier)
m_opcode(oper), m_number(value), m_lineNo(0), m_barrier(barrier)
{ }
/**
@ -833,7 +890,7 @@ public:
*/
inline ExpOperation(ExpEvaluator::Opcode oper, const char* name, const char* value, bool barrier = false)
: NamedString(name,value),
m_opcode(oper), m_number(nonInteger()), m_barrier(barrier)
m_opcode(oper), m_number(nonInteger()), m_lineNo(0), m_barrier(barrier)
{ }
/**
@ -864,6 +921,20 @@ public:
inline bool barrier() const
{ return m_barrier; }
/**
* Retrieve the line number where the operation was compiled from
* @return Line number, zero if unknown
*/
inline unsigned int lineNumber() const
{ return m_lineNo; }
/**
* Set the line number where the operation was compiled from
* @param line Number of the compiled line
*/
inline void lineNumber(unsigned int line)
{ m_lineNo = line; }
/**
* Number assignment operator
* @param num Numeric value to assign to the operation
@ -877,8 +948,7 @@ public:
* @param name Name of the cloned operation
* @return New operation instance
*/
virtual ExpOperation* clone(const char* name) const
{ return new ExpOperation(*this,name); }
virtual ExpOperation* clone(const char* name) const;
/**
* Clone method
@ -890,6 +960,7 @@ public:
private:
ExpEvaluator::Opcode m_opcode;
long int m_number;
unsigned int m_lineNo;
bool m_barrier;
};