Pass objects for parsing nested instructions in expressions.
Added specific Javascript parsers for nested instructions. git-svn-id: http://voip.null.ro/svn/yate@5091 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
parent
8094964bc3
commit
7f5b22b1b6
|
@ -293,7 +293,7 @@ void ExpEvaluator::formatLineNo(String& buf, unsigned int line) const
|
|||
buf << "line " << line;
|
||||
}
|
||||
|
||||
bool ExpEvaluator::getInstruction(const char*& expr, Opcode nested)
|
||||
bool ExpEvaluator::getInstruction(const char*& expr, GenObject* nested)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -570,7 +570,7 @@ bool ExpEvaluator::getSeparator(const char*& expr, bool remove)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ExpEvaluator::runCompile(const char*& expr, char stop, Opcode nested)
|
||||
bool ExpEvaluator::runCompile(const char*& expr, char stop, GenObject* nested)
|
||||
{
|
||||
typedef struct {
|
||||
Opcode code;
|
||||
|
@ -579,7 +579,7 @@ bool ExpEvaluator::runCompile(const char*& expr, char stop, Opcode nested)
|
|||
StackedOpcode stack[10];
|
||||
unsigned int stackPos = 0;
|
||||
#ifdef DEBUG
|
||||
Debugger debug(DebugInfo,"runCompile()"," '%.1s' %u '%.30s'",&stop,nested,expr);
|
||||
Debugger debug(DebugInfo,"runCompile()"," '%.1s' %p '%.30s'",&stop,nested,expr);
|
||||
#endif
|
||||
if (skipComments(expr) == ')')
|
||||
return false;
|
||||
|
|
|
@ -28,6 +28,8 @@ using namespace TelEngine;
|
|||
|
||||
namespace { // anonymous
|
||||
|
||||
class ParseNested;
|
||||
|
||||
class JsContext : public JsObject, public Mutex
|
||||
{
|
||||
YCLASS(JsContext,JsObject)
|
||||
|
@ -75,6 +77,7 @@ protected:
|
|||
|
||||
class JsCode : public ScriptCode, public ExpEvaluator
|
||||
{
|
||||
friend class ParseNested;
|
||||
public:
|
||||
enum JsOpcode {
|
||||
OpcBegin = OpcPrivate + 1,
|
||||
|
@ -141,7 +144,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, Opcode nested);
|
||||
virtual bool getInstruction(const char*& expr, GenObject* nested);
|
||||
virtual bool getSimple(const char*& expr, bool constOnly = false);
|
||||
virtual Opcode getOperator(const char*& expr);
|
||||
virtual Opcode getUnaryOperator(const char*& expr);
|
||||
|
@ -157,12 +160,13 @@ private:
|
|||
ObjVector m_linked;
|
||||
ObjList m_included;
|
||||
bool preProcessInclude(const char*& expr, bool once, GenObject* context);
|
||||
bool parseIf(const char*& expr, Opcode nested);
|
||||
bool parseSwitch(const char*& expr, Opcode nested);
|
||||
bool parseFor(const char*& expr, Opcode nested);
|
||||
bool parseWhile(const char*& expr, Opcode nested);
|
||||
bool parseTry(const char*& expr, Opcode nested);
|
||||
bool parseFuncDef(const char*& expr, Opcode nested);
|
||||
bool parseInner(const char*& expr, JsOpcode opcode, ParseNested* nested);
|
||||
bool parseIf(const char*& expr, GenObject* nested);
|
||||
bool parseSwitch(const char*& expr, GenObject* nested);
|
||||
bool parseFor(const char*& expr, GenObject* nested);
|
||||
bool parseWhile(const char*& expr, GenObject* nested);
|
||||
bool parseTry(const char*& expr, GenObject* nested);
|
||||
bool parseFuncDef(const char*& expr, GenObject* nested);
|
||||
bool evalList(ObjList& stack, GenObject* context) const;
|
||||
bool evalVector(ObjList& stack, GenObject* context) const;
|
||||
bool jumpToLabel(long int label, GenObject* context) const;
|
||||
|
@ -187,6 +191,45 @@ private:
|
|||
unsigned int m_index;
|
||||
};
|
||||
|
||||
class ParseNested : public GenObject
|
||||
{
|
||||
YCLASS(ParseNested,GenObject)
|
||||
public:
|
||||
inline explicit ParseNested(JsCode* code, GenObject* nested,
|
||||
JsCode::JsOpcode oper = (JsCode::JsOpcode)ExpEvaluator::OpcNone)
|
||||
: m_code(code), m_nested(static_cast<ParseNested*>(nested)), m_opcode(oper)
|
||||
{ }
|
||||
inline operator GenObject*()
|
||||
{ return this; }
|
||||
inline operator JsCode::JsOpcode() const
|
||||
{ return m_opcode; }
|
||||
inline static JsCode::JsOpcode code(GenObject* nested)
|
||||
{ return nested ? *static_cast<ParseNested*>(nested) :
|
||||
(JsCode::JsOpcode)ExpEvaluator::OpcNone; }
|
||||
inline static ParseNested* find(GenObject* nested, JsCode::JsOpcode opcode)
|
||||
{ return nested ? static_cast<ParseNested*>(nested)->find(opcode) : 0; }
|
||||
inline static ParseNested* findMatch(GenObject* nested, JsCode::JsOpcode opcode)
|
||||
{ return nested ? static_cast<ParseNested*>(nested)->findMatch(opcode) : 0; }
|
||||
static bool parseInner(GenObject* nested, JsCode::JsOpcode opcode, const char*& expr)
|
||||
{ ParseNested* inner = findMatch(nested,opcode);
|
||||
return inner && inner->parseInner(expr,opcode); }
|
||||
protected:
|
||||
virtual bool isMatch(JsCode::JsOpcode opcode)
|
||||
{ return false; }
|
||||
inline bool parseInner(const char*& expr, JsCode::JsOpcode opcode)
|
||||
{ return m_code->parseInner(expr,opcode,this); }
|
||||
inline ParseNested* find(JsCode::JsOpcode opcode)
|
||||
{ return (opcode == m_opcode) ? this :
|
||||
(m_nested ? m_nested->find(opcode) : 0); }
|
||||
inline ParseNested* findMatch(JsCode::JsOpcode opcode)
|
||||
{ return isMatch(opcode) ? this :
|
||||
(m_nested ? m_nested->findMatch(opcode) : 0); }
|
||||
private:
|
||||
JsCode* m_code;
|
||||
ParseNested* m_nested;
|
||||
JsCode::JsOpcode m_opcode;
|
||||
};
|
||||
|
||||
#define MAKEOP(s,o) { s, JsCode::Opc ## o }
|
||||
static const TokenDict s_operators[] =
|
||||
{
|
||||
|
@ -775,11 +818,11 @@ int JsCode::preProcess(const char*& expr, GenObject* context)
|
|||
}
|
||||
}
|
||||
|
||||
bool JsCode::getInstruction(const char*& expr, Opcode nested)
|
||||
bool JsCode::getInstruction(const char*& expr, GenObject* nested)
|
||||
{
|
||||
if (inError())
|
||||
return false;
|
||||
XDebug(this,DebugAll,"JsCode::getInstruction '%.30s' %u",expr,nested);
|
||||
XDebug(this,DebugAll,"JsCode::getInstruction '%.30s' %p",expr,nested);
|
||||
if (skipComments(expr) == '{') {
|
||||
expr++;
|
||||
for (;;) {
|
||||
|
@ -825,42 +868,29 @@ bool JsCode::getInstruction(const char*& expr, Opcode nested)
|
|||
case OpcWhile:
|
||||
return parseWhile(expr,nested);
|
||||
case OpcCase:
|
||||
if (OpcSwitch != (JsOpcode)nested)
|
||||
return gotError("Case not in switch",saved);
|
||||
if (!ExpEvaluator::getSimple(expr,true))
|
||||
return gotError("Expecting case constant",expr);
|
||||
if (!ParseNested::parseInner(nested,OpcCase,expr))
|
||||
return gotError("case not inside switch",saved);
|
||||
if (skipComments(expr) != ':')
|
||||
return gotError("Expecting ':'",expr);
|
||||
expr++;
|
||||
break;
|
||||
case OpcDefault:
|
||||
if (OpcSwitch != (JsOpcode)nested)
|
||||
return gotError("Default not in switch",saved);
|
||||
if (!ParseNested::parseInner(nested,OpcDefault,expr))
|
||||
return gotError("Unexpected default instruction",saved);
|
||||
if (skipComments(expr) != ':')
|
||||
return gotError("Expecting ':'",expr);
|
||||
expr++;
|
||||
break;
|
||||
case OpcBreak:
|
||||
switch ((JsOpcode)nested) {
|
||||
case OpcSwitch:
|
||||
case OpcFor:
|
||||
case OpcWhile:
|
||||
break;
|
||||
default:
|
||||
return gotError("Unexpected break instruction",saved);
|
||||
}
|
||||
if (!ParseNested::parseInner(nested,OpcBreak,expr))
|
||||
return gotError("Unexpected break instruction",saved);
|
||||
if (skipComments(expr) != ';')
|
||||
return gotError("Expecting ';'",expr);
|
||||
expr++;
|
||||
break;
|
||||
case OpcCont:
|
||||
switch ((JsOpcode)nested) {
|
||||
case OpcFor:
|
||||
case OpcWhile:
|
||||
break;
|
||||
default:
|
||||
return gotError("Unexpected continue instruction",saved);
|
||||
}
|
||||
if (!ParseNested::parseInner(nested,OpcCont,expr))
|
||||
return gotError("Unexpected continue instruction",saved);
|
||||
if (skipComments(expr) != ';')
|
||||
return gotError("Expecting ';'",expr);
|
||||
expr++;
|
||||
|
@ -875,7 +905,72 @@ bool JsCode::getInstruction(const char*& expr, Opcode nested)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool JsCode::parseIf(const char*& expr, Opcode nested)
|
||||
class ParseWhile : public ParseNested
|
||||
{
|
||||
friend class JsCode;
|
||||
public:
|
||||
inline ParseWhile(JsCode* code, GenObject* nested, long int lblCont, long int lblBreak)
|
||||
: ParseNested(code,nested,JsCode::OpcWhile),
|
||||
m_lblCont(lblCont), m_lblBreak(lblBreak)
|
||||
{ }
|
||||
protected:
|
||||
virtual bool isMatch(JsCode::JsOpcode opcode)
|
||||
{ return JsCode::OpcBreak == opcode || JsCode::OpcCont == opcode; }
|
||||
private:
|
||||
long int m_lblCont;
|
||||
long int m_lblBreak;
|
||||
};
|
||||
|
||||
class ParseSwitch : public ParseNested
|
||||
{
|
||||
friend class JsCode;
|
||||
public:
|
||||
inline ParseSwitch(JsCode* code, GenObject* nested)
|
||||
: ParseNested(code,nested,JsCode::OpcSwitch)
|
||||
{ }
|
||||
protected:
|
||||
virtual bool isMatch(JsCode::JsOpcode opcode)
|
||||
{ return JsCode::OpcCase == opcode || JsCode::OpcDefault == opcode ||
|
||||
JsCode::OpcBreak == opcode; }
|
||||
};
|
||||
|
||||
// Parse keywords inner to specific instructions
|
||||
bool JsCode::parseInner(const char*& expr, JsOpcode opcode, ParseNested* nested)
|
||||
{
|
||||
switch (*nested) {
|
||||
case OpcWhile:
|
||||
switch (opcode) {
|
||||
case OpcBreak:
|
||||
addOpcode((Opcode)OpcJump,static_cast<ParseWhile*>(nested)->m_lblBreak);
|
||||
break;
|
||||
case OpcCont:
|
||||
addOpcode((Opcode)OpcJump,static_cast<ParseWhile*>(nested)->m_lblCont);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case OpcSwitch:
|
||||
switch (opcode) {
|
||||
case OpcCase:
|
||||
if (!ExpEvaluator::getSimple(expr,true))
|
||||
return gotError("Expecting case constant",expr);
|
||||
break;
|
||||
case OpcDefault:
|
||||
break;
|
||||
case OpcBreak:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsCode::parseIf(const char*& expr, GenObject* nested)
|
||||
{
|
||||
if (skipComments(expr) != '(')
|
||||
return gotError("Expecting '('",expr);
|
||||
|
@ -906,7 +1001,7 @@ bool JsCode::parseIf(const char*& expr, Opcode nested)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool JsCode::parseSwitch(const char*& expr, Opcode nested)
|
||||
bool JsCode::parseSwitch(const char*& expr, GenObject* nested)
|
||||
{
|
||||
if (skipComments(expr) != '(')
|
||||
return gotError("Expecting '('",expr);
|
||||
|
@ -917,8 +1012,9 @@ bool JsCode::parseSwitch(const char*& expr, Opcode nested)
|
|||
if (skipComments(++expr) != '{')
|
||||
return gotError("Expecting '{'",expr);
|
||||
expr++;
|
||||
ParseSwitch parseStack(this,nested);
|
||||
for (;;) {
|
||||
if (!runCompile(expr,'}',(Opcode)OpcSwitch))
|
||||
if (!runCompile(expr,'}',parseStack))
|
||||
return false;
|
||||
bool sep = false;
|
||||
while (skipComments(expr) && getSeparator(expr,true))
|
||||
|
@ -932,7 +1028,7 @@ bool JsCode::parseSwitch(const char*& expr, Opcode nested)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool JsCode::parseFor(const char*& expr, Opcode nested)
|
||||
bool JsCode::parseFor(const char*& expr, GenObject* nested)
|
||||
{
|
||||
if (skipComments(expr) != '(')
|
||||
return gotError("Expecting '('",expr);
|
||||
|
@ -940,14 +1036,15 @@ bool JsCode::parseFor(const char*& expr, Opcode nested)
|
|||
return false;
|
||||
if (skipComments(expr) != ')')
|
||||
return gotError("Expecting ')'",expr);
|
||||
if (!runCompile(++expr,';',(Opcode)OpcFor))
|
||||
ParseNested parseStack(this,nested,OpcFor);
|
||||
if (!runCompile(++expr,';',parseStack))
|
||||
return false;
|
||||
if (skipComments(expr) == ';')
|
||||
expr++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsCode::parseWhile(const char*& expr, Opcode nested)
|
||||
bool JsCode::parseWhile(const char*& expr, GenObject* nested)
|
||||
{
|
||||
ExpOperation* lbl = addOpcode(OpcLabel,++m_label);
|
||||
if (skipComments(expr) != '(')
|
||||
|
@ -957,17 +1054,19 @@ bool JsCode::parseWhile(const char*& expr, Opcode nested)
|
|||
if (skipComments(expr) != ')')
|
||||
return gotError("Expecting ')'",expr);
|
||||
ExpOperation* jump = addOpcode((Opcode)OpcJumpFalse,++m_label);
|
||||
if (!runCompile(++expr,0,(Opcode)OpcWhile))
|
||||
ParseWhile parseStack(this,nested,lbl->number(),jump->number());
|
||||
if (!runCompile(++expr,0,parseStack))
|
||||
return false;
|
||||
addOpcode((Opcode)OpcJump,lbl->number());
|
||||
addOpcode(OpcLabel,jump->number());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsCode::parseTry(const char*& expr, Opcode nested)
|
||||
bool JsCode::parseTry(const char*& expr, GenObject* nested)
|
||||
{
|
||||
addOpcode((Opcode)OpcTry);
|
||||
if (!runCompile(expr,0,(Opcode)OpcTry))
|
||||
ParseNested parseStack(this,nested,OpcTry);
|
||||
if (!runCompile(expr,0,parseStack))
|
||||
return false;
|
||||
skipComments(expr);
|
||||
if ((JsOpcode)ExpEvaluator::getOperator(expr,s_instr) == OpcCatch) {
|
||||
|
@ -988,7 +1087,7 @@ bool JsCode::parseTry(const char*& expr, Opcode nested)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool JsCode::parseFuncDef(const char*& expr, Opcode nested)
|
||||
bool JsCode::parseFuncDef(const char*& expr, GenObject* nested)
|
||||
{
|
||||
skipComments(expr);
|
||||
int len = getKeyword(expr);
|
||||
|
|
|
@ -496,10 +496,10 @@ protected:
|
|||
* Runs the parser and compiler for one (sub)expression
|
||||
* @param expr Pointer to text to parse, gets advanced
|
||||
* @param stop Optional character expected after the expression
|
||||
* @param nested The instruction within this expression is nested
|
||||
* @param nested User defined object to pass for nested parsing
|
||||
* @return True if one expression was compiled and a separator follows
|
||||
*/
|
||||
virtual bool runCompile(const char*& expr, char stop = 0, Opcode nested = OpcNone);
|
||||
virtual bool runCompile(const char*& expr, char stop = 0, GenObject* nested = 0);
|
||||
|
||||
/**
|
||||
* Skip over comments and whitespaces
|
||||
|
@ -570,10 +570,10 @@ protected:
|
|||
/**
|
||||
* Get an instruction or block, advance parsing pointer past it
|
||||
* @param expr Pointer to text to parse, gets advanced on success
|
||||
* @param nested The instruction within this one is nested
|
||||
* @param nested User defined object passed from nested parsing
|
||||
* @return True if succeeded, must add the operands internally
|
||||
*/
|
||||
virtual bool getInstruction(const char*& expr, Opcode nested = OpcNone);
|
||||
virtual bool getInstruction(const char*& expr, GenObject* nested = 0);
|
||||
|
||||
/**
|
||||
* Get an operand, advance parsing pointer past it
|
||||
|
|
Loading…
Reference in New Issue