Added partial universal scripting implementation with Javascript support.
git-svn-id: http://voip.null.ro/svn/yate@4892 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
parent
7165d33d25
commit
b15e963c58
|
@ -0,0 +1 @@
|
|||
[general]
|
|
@ -1417,6 +1417,7 @@ AC_CONFIG_FILES([packing/rpm/yate.spec
|
|||
libs/yiax/Makefile
|
||||
libs/yxml/Makefile
|
||||
libs/yjabber/Makefile
|
||||
libs/yscript/Makefile
|
||||
libs/ymgcp/Makefile
|
||||
libs/ysig/Makefile
|
||||
libs/ypbx/Makefile
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
# Makefile
|
||||
# This file holds the make rules for the libyatescript
|
||||
|
||||
DEBUG :=
|
||||
|
||||
CXX := @CXX@ -Wall
|
||||
AR := ar
|
||||
DEFS :=
|
||||
INCLUDES := -I@top_srcdir@ -I../.. -I@srcdir@
|
||||
CFLAGS := @CFLAGS@ @MODULE_CPPFLAGS@ @INLINE_FLAGS@
|
||||
LDFLAGS:= @LDFLAGS@
|
||||
SONAME_OPT := @SONAME_OPT@
|
||||
YATELIBS := -L../.. -lyate @LIBS@
|
||||
INCFILES := @top_srcdir@/yateclass.h @srcdir@/yatescript.h
|
||||
|
||||
PROGS=
|
||||
LIBS = libyatescript.a
|
||||
OBJS = evaluator.o script.o javascript.o jsobjects.o
|
||||
LIBD_DEV:= libyatescript.so
|
||||
LIBD_VER:= $(LIBD_DEV).@PACKAGE_VERSION@
|
||||
LIBD:= ../../$(LIBD_VER) ../../$(LIBD_DEV)
|
||||
|
||||
LOCALFLAGS =
|
||||
LOCALLIBS =
|
||||
COMPILE = $(CXX) $(DEFS) $(DEBUG) $(INCLUDES) $(CFLAGS)
|
||||
LINK = $(CXX) $(LDFLAGS)
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
|
||||
# include optional local make rules
|
||||
-include YateLocal.mak
|
||||
|
||||
.PHONY: all debug ddebug xdebug
|
||||
all: $(LIBS) $(LIBD) $(PROGS)
|
||||
|
||||
debug:
|
||||
$(MAKE) all DEBUG=-g3 MODSTRIP=
|
||||
|
||||
ddebug:
|
||||
$(MAKE) all DEBUG='-g3 -DDEBUG' MODSTRIP=
|
||||
|
||||
xdebug:
|
||||
$(MAKE) all DEBUG='-g3 -DXDEBUG' MODSTRIP=
|
||||
|
||||
.PHONY: strip
|
||||
strip: all
|
||||
strip --strip-debug --discard-locals $(PROGS)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@-$(RM) $(PROGS) $(LIBS) $(LIBD) $(OBJS) core 2>/dev/null
|
||||
|
||||
%.o: @srcdir@/%.cpp $(INCFILES)
|
||||
$(COMPILE) -c $<
|
||||
|
||||
Makefile: @srcdir@/Makefile.in ../../config.status
|
||||
cd ../.. && ./config.status
|
||||
|
||||
../../$(LIBD_VER): $(OBJS)
|
||||
$(LINK) -o $@ $(SONAME_OPT)$(LIBD_VER) $^ $(YATELIBS)
|
||||
|
||||
../../$(LIBD_DEV): ../../$(LIBD_VER)
|
||||
cd ../.. && ln -sf $(LIBD_VER) $(LIBD_DEV)
|
||||
|
||||
$(LIBS): $(OBJS)
|
||||
$(AR) rcs $@ $^
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,434 @@
|
|||
/**
|
||||
* javascript.cpp
|
||||
* Yet Another (Java)script library
|
||||
* This file is part of the YATE Project http://YATE.null.ro
|
||||
*
|
||||
* Yet Another Telephony Engine - a fully featured software PBX and IVR
|
||||
* Copyright (C) 2011 Null Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "yatescript.h"
|
||||
|
||||
using namespace TelEngine;
|
||||
|
||||
namespace { // anonymous
|
||||
|
||||
class JsContext : public ScriptContext
|
||||
{
|
||||
YCLASS(JsContext,ScriptContext)
|
||||
public:
|
||||
virtual bool runFunction(const ExpEvaluator* eval, ObjList& stack, const ExpOperation& oper, void* context);
|
||||
virtual bool runField(const ExpEvaluator* eval, ObjList& stack, const ExpOperation& oper, void* context);
|
||||
virtual bool runAssign(const ExpEvaluator* eval, const ExpOperation& oper, void* context);
|
||||
};
|
||||
|
||||
class JsCode : public ScriptCode, public ExpEvaluator
|
||||
{
|
||||
YCLASS(JsCode,ScriptCode)
|
||||
public:
|
||||
enum JsOpcode {
|
||||
OpcBegin = OpcPrivate + 1,
|
||||
OpcEnd,
|
||||
OpcIndex,
|
||||
OpcNew,
|
||||
OpcFor,
|
||||
OpcWhile,
|
||||
OpcIf,
|
||||
OpcElse,
|
||||
OpcSwitch,
|
||||
OpcCase,
|
||||
OpcBreak,
|
||||
OpcCont,
|
||||
OpcIn,
|
||||
OpcVar,
|
||||
OpcWith,
|
||||
OpcTry,
|
||||
OpcCatch,
|
||||
OpcFinally,
|
||||
OpcThrow,
|
||||
OpcReturn,
|
||||
};
|
||||
inline JsCode()
|
||||
: ExpEvaluator(C), m_label(0)
|
||||
{ debugName("JsCode"); }
|
||||
virtual bool initialize(ScriptContext* context) const;
|
||||
virtual bool evaluate(ScriptContext& context, ObjList& results) const;
|
||||
protected:
|
||||
virtual bool keywordChar(char c) const;
|
||||
virtual int getKeyword(const char* str) const;
|
||||
virtual bool getInstruction(const char*& expr);
|
||||
virtual Opcode getOperator(const char*& expr);
|
||||
virtual Opcode getUnaryOperator(const char*& expr);
|
||||
virtual Opcode getPostfixOperator(const char*& expr);
|
||||
virtual const char* getOperator(Opcode oper) const;
|
||||
virtual int getPrecedence(ExpEvaluator::Opcode oper) const;
|
||||
virtual bool getSeparator(const char*& expr, bool remove);
|
||||
virtual bool runOperation(ObjList& stack, const ExpOperation& oper, void* context) const;
|
||||
private:
|
||||
int m_label;
|
||||
};
|
||||
|
||||
#define MAKEOP(s,o) { s, JsCode::Opc ## o }
|
||||
static const TokenDict s_operators[] =
|
||||
{
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static const TokenDict s_unaryOps[] =
|
||||
{
|
||||
MAKEOP("new", New),
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static const TokenDict s_postfixOps[] =
|
||||
{
|
||||
MAKEOP("++", IncPost),
|
||||
MAKEOP("--", DecPost),
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static const TokenDict s_instr[] =
|
||||
{
|
||||
MAKEOP("function", Func),
|
||||
MAKEOP("for", For),
|
||||
MAKEOP("while", While),
|
||||
MAKEOP("if", If),
|
||||
MAKEOP("else", Else),
|
||||
MAKEOP("switch", Switch),
|
||||
MAKEOP("case", Case),
|
||||
MAKEOP("break", Break),
|
||||
MAKEOP("continue", Cont),
|
||||
MAKEOP("in", In),
|
||||
MAKEOP("var", Var),
|
||||
MAKEOP("with", With),
|
||||
MAKEOP("try", Try),
|
||||
MAKEOP("catch", Catch),
|
||||
MAKEOP("finally", Finally),
|
||||
MAKEOP("throw", Throw),
|
||||
MAKEOP("return", Return),
|
||||
{ 0, 0 }
|
||||
};
|
||||
#undef MAKEOP
|
||||
|
||||
|
||||
bool JsContext::runFunction(const ExpEvaluator* eval, ObjList& stack, const ExpOperation& oper, void* context)
|
||||
{
|
||||
return ScriptContext::runFunction(eval,stack,oper,context);
|
||||
}
|
||||
|
||||
bool JsContext::runField(const ExpEvaluator* eval, ObjList& stack, const ExpOperation& oper, void* context)
|
||||
{
|
||||
if (!eval)
|
||||
return false;
|
||||
XDebug(DebugAll,"JsContext::runField '%s'",oper.name().c_str());
|
||||
return ScriptContext::runField(eval,stack,oper,context);
|
||||
}
|
||||
|
||||
bool JsContext::runAssign(const ExpEvaluator* eval, const ExpOperation& oper, void* context)
|
||||
{
|
||||
if (!eval)
|
||||
return false;
|
||||
XDebug(DebugAll,"JsContext::runAssign '%s'='%s'",oper.name().c_str(),oper.c_str());
|
||||
return ScriptContext::runAssign(eval,oper,context);
|
||||
}
|
||||
|
||||
|
||||
// Initialize standard globals in the execution context
|
||||
bool JsCode::initialize(ScriptContext* context) const
|
||||
{
|
||||
if (!context)
|
||||
return false;
|
||||
JsObject::initialize(*context);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsCode::evaluate(ScriptContext& context, ObjList& results) const
|
||||
{
|
||||
if (null())
|
||||
return false;
|
||||
return ExpEvaluator::evaluate(results,&context);
|
||||
}
|
||||
|
||||
bool JsCode::keywordChar(char c) const
|
||||
{
|
||||
return ExpEvaluator::keywordChar(c) || (c == '$');
|
||||
}
|
||||
|
||||
int JsCode::getKeyword(const char* str) const
|
||||
{
|
||||
int len = 0;
|
||||
for (;; len++) {
|
||||
char c = *str++;
|
||||
if (c <= ' ')
|
||||
break;
|
||||
if (keywordChar(c) || (len && (c == '.')))
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if (len > 1 && (str[-2] == '.'))
|
||||
len--;
|
||||
return len;
|
||||
}
|
||||
|
||||
bool JsCode::getInstruction(const char*& expr)
|
||||
{
|
||||
XDebug(this,DebugAll,"JsCode::getInstruction '%s'",expr);
|
||||
if (skipWhites(expr) == '{') {
|
||||
if (!runCompile(++expr,'}'))
|
||||
return false;
|
||||
if (skipWhites(expr) != '}')
|
||||
return gotError("Expecting '}'",expr);
|
||||
expr++;
|
||||
return true;
|
||||
}
|
||||
Opcode op = ExpEvaluator::getOperator(expr,s_instr);
|
||||
switch ((JsOpcode)op) {
|
||||
case (JsOpcode)OpcNone:
|
||||
return false;
|
||||
case OpcThrow:
|
||||
if (!runCompile(expr))
|
||||
return false;
|
||||
addOpcode(op);
|
||||
break;
|
||||
case OpcReturn:
|
||||
runCompile(expr);
|
||||
addOpcode(op);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ExpEvaluator::Opcode JsCode::getOperator(const char*& expr)
|
||||
{
|
||||
XDebug(this,DebugAll,"JsCode::getOperator '%s'",expr);
|
||||
Opcode op = ExpEvaluator::getOperator(expr,s_operators);
|
||||
if (OpcNone != op)
|
||||
return op;
|
||||
return ExpEvaluator::getOperator(expr);
|
||||
}
|
||||
|
||||
ExpEvaluator::Opcode JsCode::getUnaryOperator(const char*& expr)
|
||||
{
|
||||
XDebug(this,DebugAll,"JsCode::getUnaryOperator '%s'",expr);
|
||||
Opcode op = ExpEvaluator::getOperator(expr,s_unaryOps);
|
||||
if (OpcNone != op)
|
||||
return op;
|
||||
return ExpEvaluator::getUnaryOperator(expr);
|
||||
}
|
||||
|
||||
ExpEvaluator::Opcode JsCode::getPostfixOperator(const char*& expr)
|
||||
{
|
||||
XDebug(this,DebugAll,"JsCode::getPostfixOperator '%s'",expr);
|
||||
if (skipWhites(expr) == '[') {
|
||||
if (!runCompile(++expr,']'))
|
||||
return OpcNone;
|
||||
if (skipWhites(expr) != ']') {
|
||||
gotError("Expecting ']'",expr);
|
||||
return OpcNone;
|
||||
}
|
||||
expr++;
|
||||
return (Opcode)OpcIndex;
|
||||
}
|
||||
Opcode op = ExpEvaluator::getOperator(expr,s_postfixOps);
|
||||
if (OpcNone != op)
|
||||
return op;
|
||||
return ExpEvaluator::getPostfixOperator(expr);
|
||||
}
|
||||
|
||||
const char* JsCode::getOperator(Opcode oper) const
|
||||
{
|
||||
if (oper < OpcPrivate)
|
||||
return ExpEvaluator::getOperator(oper);
|
||||
if ((int)oper == (int)OpcIndex)
|
||||
return "[]";
|
||||
const char* tmp = lookup(oper,s_operators);
|
||||
if (!tmp) {
|
||||
tmp = lookup(oper,s_unaryOps);
|
||||
if (!tmp) {
|
||||
tmp = lookup(oper,s_postfixOps);
|
||||
if (!tmp)
|
||||
tmp = lookup(oper,s_instr);
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
int JsCode::getPrecedence(ExpEvaluator::Opcode oper) const
|
||||
{
|
||||
switch (oper) {
|
||||
case OpcNew:
|
||||
case OpcIndex:
|
||||
return 12;
|
||||
default:
|
||||
return ExpEvaluator::getPrecedence(oper);
|
||||
}
|
||||
}
|
||||
|
||||
bool JsCode::getSeparator(const char*& expr, bool remove)
|
||||
{
|
||||
switch (skipWhites(expr)) {
|
||||
case ']':
|
||||
case ';':
|
||||
if (remove)
|
||||
expr++;
|
||||
return true;
|
||||
}
|
||||
return ExpEvaluator::getSeparator(expr,remove);
|
||||
}
|
||||
|
||||
bool JsCode::runOperation(ObjList& stack, const ExpOperation& oper, void* context) const
|
||||
{
|
||||
switch ((JsOpcode)oper.opcode()) {
|
||||
case OpcBegin:
|
||||
pushOne(stack,new ExpOperation(OpcBegin));
|
||||
break;
|
||||
case OpcEnd:
|
||||
{
|
||||
ExpOperation* op = popOne(stack);
|
||||
ObjList* b = 0;
|
||||
for (ObjList* l = stack.skipNull(); l; l=l->skipNext()) {
|
||||
ExpOperation* o = static_cast<ExpOperation*>(l->get());
|
||||
if (o && (o->opcode() == (Opcode)OpcBegin))
|
||||
b = l;
|
||||
}
|
||||
if (!b) {
|
||||
TelEngine::destruct(op);
|
||||
return gotError("ExpEvaluator stack underflow");
|
||||
}
|
||||
b->clear();
|
||||
pushOne(stack,op);
|
||||
}
|
||||
break;
|
||||
case OpcIndex:
|
||||
{
|
||||
ExpOperation* op2 = popValue(stack,context);
|
||||
ExpOperation* op1 = popOne(stack);
|
||||
if (!op1 || !op2) {
|
||||
TelEngine::destruct(op1);
|
||||
TelEngine::destruct(op2);
|
||||
return gotError("Stack underflow");
|
||||
}
|
||||
if (op1->opcode() != OpcField) {
|
||||
TelEngine::destruct(op1);
|
||||
TelEngine::destruct(op2);
|
||||
return gotError("Expecting field name");
|
||||
}
|
||||
pushOne(stack,new ExpOperation(OpcField,op1->name() + "." + *op2));
|
||||
TelEngine::destruct(op1);
|
||||
TelEngine::destruct(op2);
|
||||
}
|
||||
break;
|
||||
case OpcNew:
|
||||
{
|
||||
ExpOperation* op = popOne(stack);
|
||||
if (!op)
|
||||
return gotError("Stack underflow");
|
||||
if (op->opcode() != OpcField) {
|
||||
TelEngine::destruct(op);
|
||||
return gotError("Expecting class name");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OpcThrow:
|
||||
{
|
||||
ExpOperation* op = popOne(stack);
|
||||
if (!op)
|
||||
return gotError("Stack underflow");
|
||||
bool ok = false;
|
||||
while (ExpOperation* drop = popAny(stack)) {
|
||||
JsOpcode c = (JsOpcode)drop->opcode();
|
||||
TelEngine::destruct(drop);
|
||||
if (c == OpcTry) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok)
|
||||
return gotError("'try' not found");
|
||||
pushOne(stack,op);
|
||||
}
|
||||
break;
|
||||
case OpcReturn:
|
||||
{
|
||||
ExpOperation* op = popOne(stack);
|
||||
bool ok = false;
|
||||
while (ExpOperation* drop = popAny(stack)) {
|
||||
ok = drop->opcode() == OpcFunc;
|
||||
int n = drop->number();
|
||||
TelEngine::destruct(drop);
|
||||
if (ok) {
|
||||
DDebug(this,DebugAll,"return popping %d off stack",n);
|
||||
while (n-- > 0)
|
||||
TelEngine::destruct(popAny(stack));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
TelEngine::destruct(op);
|
||||
return gotError("Function not found on stack");
|
||||
}
|
||||
pushOne(stack,op);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return ExpEvaluator::runOperation(stack,oper);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}; // anonymous namespace
|
||||
|
||||
|
||||
// Parse a piece of Javascript text
|
||||
bool JsParser::parse(const char* text)
|
||||
{
|
||||
if (TelEngine::null(text))
|
||||
return false;
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
// Evaluate a string as expression or statement
|
||||
ScriptRun::Status JsParser::eval(const String& text, ExpOperation** result, ScriptContext* context)
|
||||
{
|
||||
if (TelEngine::null(text))
|
||||
return ScriptRun::Invalid;
|
||||
JsCode* code = new JsCode;
|
||||
if (!code->compile(text)) {
|
||||
TelEngine::destruct(code);
|
||||
return ScriptRun::Invalid;
|
||||
}
|
||||
DDebug(DebugAll,"Compiled: %s",code->dump().c_str());
|
||||
code->simplify();
|
||||
DDebug(DebugAll,"Simplified: %s",code->dump().c_str());
|
||||
ScriptContext* ctxt = 0;
|
||||
if (!context)
|
||||
context = ctxt = new JsContext();
|
||||
ScriptRun* runner = new ScriptRun(code,context);
|
||||
TelEngine::destruct(ctxt);
|
||||
code->extender(runner->context());
|
||||
TelEngine::destruct(code);
|
||||
ScriptRun::Status rval = runner->run();
|
||||
if (result && (ScriptRun::Succeeded == rval))
|
||||
*result = ExpEvaluator::popOne(runner->stack());
|
||||
TelEngine::destruct(runner);
|
||||
return rval;
|
||||
}
|
||||
|
||||
/* vi: set ts=8 sw=4 sts=4 noet: */
|
|
@ -0,0 +1,125 @@
|
|||
/**
|
||||
* jsobject.cpp
|
||||
* Yet Another (Java)script library
|
||||
* This file is part of the YATE Project http://YATE.null.ro
|
||||
*
|
||||
* Yet Another Telephony Engine - a fully featured software PBX and IVR
|
||||
* Copyright (C) 2011 Null Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "yatescript.h"
|
||||
|
||||
using namespace TelEngine;
|
||||
|
||||
namespace { // anonymous
|
||||
|
||||
// Base class for all native objects that hold a NamedList
|
||||
class JsNative : public JsObject
|
||||
{
|
||||
YCLASS(JsNative,JsObject)
|
||||
public:
|
||||
inline JsNative(const char* name, NamedList* list)
|
||||
: JsObject(name),
|
||||
m_list(list)
|
||||
{ }
|
||||
virtual NamedList& list()
|
||||
{ return *m_list; }
|
||||
virtual const NamedList& list() const
|
||||
{ return *m_list; }
|
||||
private:
|
||||
NamedList* m_list;
|
||||
};
|
||||
|
||||
// Array object
|
||||
class JsArray : public JsObject
|
||||
{
|
||||
YCLASS(JsArray,JsObject)
|
||||
public:
|
||||
inline JsArray()
|
||||
: JsObject("Array")
|
||||
{ }
|
||||
};
|
||||
|
||||
// Function object
|
||||
class JsFunction : public JsObject
|
||||
{
|
||||
YCLASS(JsFunction,JsObject)
|
||||
public:
|
||||
inline JsFunction()
|
||||
: JsObject("Function")
|
||||
{ }
|
||||
};
|
||||
|
||||
// Object constructor
|
||||
class JsConstructor : public JsFunction
|
||||
{
|
||||
YCLASS(JsConstructor,JsFunction)
|
||||
public:
|
||||
inline JsConstructor()
|
||||
{ }
|
||||
};
|
||||
|
||||
// Date object
|
||||
class JsDate : public JsObject
|
||||
{
|
||||
YCLASS(JsDate,JsObject)
|
||||
public:
|
||||
inline JsDate()
|
||||
: JsObject("Date")
|
||||
{
|
||||
addParam(new ExpOperation(ExpEvaluator::OpcFunc,"now"));
|
||||
}
|
||||
};
|
||||
|
||||
// Math class - not really an object, all methods are static
|
||||
class JsMath : public JsObject
|
||||
{
|
||||
YCLASS(JsMath,JsObject)
|
||||
public:
|
||||
inline JsMath()
|
||||
: JsObject("Math")
|
||||
{
|
||||
addParam(new ExpOperation(ExpEvaluator::OpcFunc,"abs"));
|
||||
}
|
||||
};
|
||||
|
||||
}; // anonymous namespace
|
||||
|
||||
|
||||
// Helper function that adds an object to a parent
|
||||
static inline void addObject(NamedList& params, const char* name, NamedList* obj)
|
||||
{
|
||||
params.addParam(new NamedPointer(name,obj,obj->toString()));
|
||||
}
|
||||
|
||||
|
||||
// Initialize standard globals in the execution context
|
||||
void JsObject::initialize(ScriptContext& context)
|
||||
{
|
||||
NamedList& params = context.params();
|
||||
static_cast<String&>(params) = "[Object Global]";
|
||||
if (!params.getParam(YSTRING("Object")))
|
||||
addObject(params,"Object",new JsObject);
|
||||
if (!params.getParam(YSTRING("Function")))
|
||||
addObject(params,"Function",new JsFunction);
|
||||
if (!params.getParam(YSTRING("Date")))
|
||||
addObject(params,"Date",new JsDate);
|
||||
if (!params.getParam(YSTRING("Math")))
|
||||
addObject(params,"Math",new JsMath);
|
||||
}
|
||||
|
||||
/* vi: set ts=8 sw=4 sts=4 noet: */
|
|
@ -0,0 +1,159 @@
|
|||
/**
|
||||
* script.cpp
|
||||
* Yet Another (Java)script library
|
||||
* This file is part of the YATE Project http://YATE.null.ro
|
||||
*
|
||||
* Yet Another Telephony Engine - a fully featured software PBX and IVR
|
||||
* Copyright (C) 2011 Null Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "yatescript.h"
|
||||
|
||||
using namespace TelEngine;
|
||||
|
||||
ScriptParser::~ScriptParser()
|
||||
{
|
||||
TelEngine::destruct(m_code);
|
||||
}
|
||||
|
||||
void ScriptParser::setCode(ScriptCode* code)
|
||||
{
|
||||
ScriptCode* tmp = m_code;
|
||||
if (tmp == code)
|
||||
return;
|
||||
if (code)
|
||||
code->ref();
|
||||
m_code = code;
|
||||
TelEngine::destruct(tmp);
|
||||
}
|
||||
|
||||
|
||||
bool ScriptContext::runFunction(const ExpEvaluator* eval, ObjList& stack, const ExpOperation& oper, void* context)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ScriptContext::runField(const ExpEvaluator* eval, ObjList& stack, const ExpOperation& oper, void* context)
|
||||
{
|
||||
if (!eval)
|
||||
return false;
|
||||
XDebug(DebugAll,"ScriptContext::runField '%s'",oper.name().c_str());
|
||||
ExpEvaluator::pushOne(stack,new ExpOperation(m_params[oper.name()],oper.name()));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScriptContext::runAssign(const ExpEvaluator* eval, const ExpOperation& oper, void* context)
|
||||
{
|
||||
if (!eval)
|
||||
return false;
|
||||
XDebug(DebugAll,"ScriptContext::runAssign '%s'='%s'",oper.name().c_str(),oper.c_str());
|
||||
m_params.setParam(oper.name(),oper);
|
||||
return true;
|
||||
}
|
||||
|
||||
#define MAKE_NAME(x) { #x, ScriptRun::x }
|
||||
static const TokenDict s_states[] = {
|
||||
MAKE_NAME(Invalid),
|
||||
MAKE_NAME(Running),
|
||||
MAKE_NAME(Incomplete),
|
||||
MAKE_NAME(Succeeded),
|
||||
MAKE_NAME(Failed),
|
||||
{ 0, 0 }
|
||||
};
|
||||
#undef MAKE_NAME
|
||||
|
||||
ScriptRun::ScriptRun(ScriptCode* code, ScriptContext* context)
|
||||
: Mutex(true,"ScriptRun"),
|
||||
m_state(Invalid)
|
||||
{
|
||||
if (code)
|
||||
code->ref();
|
||||
m_code = code;
|
||||
if (context)
|
||||
context->ref();
|
||||
else
|
||||
context = new ScriptContext;
|
||||
m_context = context;
|
||||
reset();
|
||||
}
|
||||
|
||||
ScriptRun::~ScriptRun()
|
||||
{
|
||||
lock();
|
||||
m_state = Invalid;
|
||||
TelEngine::destruct(m_code);
|
||||
TelEngine::destruct(m_context);
|
||||
unlock();
|
||||
}
|
||||
|
||||
const char* ScriptRun::textState(Status state)
|
||||
{
|
||||
return lookup(state,s_states,"Unknown");
|
||||
}
|
||||
|
||||
// Reset script (but not the context) to initial state
|
||||
ScriptRun::Status ScriptRun::reset()
|
||||
{
|
||||
Lock mylock(this);
|
||||
// TODO
|
||||
m_stack.clear();
|
||||
return (m_state = (m_code && m_code->initialize(m_context)) ? Incomplete : Invalid);
|
||||
}
|
||||
|
||||
// Resume execution, run one or more instructions of code
|
||||
ScriptRun::Status ScriptRun::resume()
|
||||
{
|
||||
Lock mylock(this);
|
||||
if (Running != m_state)
|
||||
return m_state;
|
||||
RefPointer<ScriptCode> code = m_code;
|
||||
RefPointer<ScriptContext> ctxt = m_context;
|
||||
if (!(code && ctxt))
|
||||
return Invalid;
|
||||
mylock.drop();
|
||||
return code->evaluate(*ctxt,stack()) ? Succeeded : Failed;
|
||||
}
|
||||
|
||||
// Execute one or more instructions of code from where it was left
|
||||
ScriptRun::Status ScriptRun::execute()
|
||||
{
|
||||
Lock mylock(this);
|
||||
if (Incomplete != m_state)
|
||||
return m_state;
|
||||
m_state = Running;
|
||||
mylock.drop();
|
||||
Status st = resume();
|
||||
if (Running == st)
|
||||
st = Incomplete;
|
||||
lock();
|
||||
if (Running == m_state)
|
||||
m_state = st;
|
||||
unlock();
|
||||
return st;
|
||||
}
|
||||
|
||||
// Execute instructions until succeeds or fails
|
||||
ScriptRun::Status ScriptRun::run()
|
||||
{
|
||||
reset();
|
||||
ScriptRun::Status s = state();
|
||||
while (Incomplete == s)
|
||||
s = execute();
|
||||
return s;
|
||||
}
|
||||
|
||||
/* vi: set ts=8 sw=4 sts=4 noet: */
|
File diff suppressed because it is too large
Load Diff
|
@ -1196,13 +1196,14 @@ void SS7MTP3::notify(SS7Layer2* link)
|
|||
}
|
||||
}
|
||||
countLinks();
|
||||
String text;
|
||||
text << "Linkset has " << m_active << " active, ";
|
||||
text << m_checked << " checked of " << m_total << " links";
|
||||
#ifdef DEBUG
|
||||
String tmp;
|
||||
if (link)
|
||||
tmp << "Link '" << link->toString() << "' is " << (link->operational()?"":"not ") << "operational. ";
|
||||
Debug(this,DebugInfo,"%sLinkset has %u/%u/%u active/checked links [%p]",
|
||||
tmp.null()?"":tmp.c_str(),
|
||||
m_active,m_checked,m_total,this);
|
||||
Debug(this,DebugInfo,"%s%s [%p]",tmp.safe(),text.c_str(),this);
|
||||
#endif
|
||||
// if operational status of a link changed notify upper layer
|
||||
if (act != m_active || chk != m_checked) {
|
||||
|
@ -1252,7 +1253,7 @@ void SS7MTP3::notify(SS7Layer2* link)
|
|||
notif.addParam("total",String(m_total));
|
||||
notif.addParam("link", link ? link->toString() : "");
|
||||
notif.addParam("linkup", link ? String::boolText(link->operational()) : "");
|
||||
|
||||
notif.addParam("text", text);
|
||||
mylock.drop();
|
||||
SS7Layer3::notify(sls);
|
||||
engine()->notify(this,notif);
|
||||
|
|
|
@ -368,6 +368,10 @@ server/sipfeatures.yate: ../libs/yxml/libyatexml.a
|
|||
server/sipfeatures.yate: LOCALFLAGS = -I@top_srcdir@/libs/yxml
|
||||
server/sipfeatures.yate: LOCALLIBS = -L../libs/yxml -lyatexml
|
||||
|
||||
javascript.yate: ../libyatescript.so
|
||||
javascript.yate: LOCALFLAGS = -I@top_srcdir@/libs/yscript
|
||||
javascript.yate: LOCALLIBS = -lyatescript
|
||||
|
||||
zlibcompress.yate: LOCALFLAGS = $(ZLIB_INC)
|
||||
zlibcompress.yate: LOCALLIBS = $(ZLIB_LIB)
|
||||
|
||||
|
@ -405,6 +409,9 @@ server/ysnmpagent.yate: LOCALLIBS = -L../libs/yasn -lyasn -L../libs/ysnmp -lysnm
|
|||
../libyatejabber.so ../libs/yjabber/libyatejabber.a: @top_srcdir@/libs/yjabber/xmpputils.h @top_srcdir@/libs/yjabber/yatejabber.h @top_srcdir@/libs/yjabber/yatejingle.h
|
||||
$(MAKE) -C ../libs/yjabber
|
||||
|
||||
../libyatescript.so ../libs/yjabber/libyatescript.a: @top_srcdir@/libs/yscript/yatescript.h
|
||||
$(MAKE) -C ../libs/yscript
|
||||
|
||||
../libs/ypbx/libyatepbx.a: @top_srcdir@/libs/ypbx/yatepbx.h
|
||||
$(MAKE) -C ../libs/ypbx
|
||||
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
/**
|
||||
* javascript.cpp
|
||||
* This file is part of the YATE Project http://YATE.null.ro
|
||||
*
|
||||
* Javascript support based on libyscript
|
||||
*
|
||||
* Yet Another Telephony Engine - a fully featured software PBX and IVR
|
||||
* Copyright (C) 2011 Null Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <yatephone.h>
|
||||
#include <yatescript.h>
|
||||
|
||||
using namespace TelEngine;
|
||||
namespace { // anonymous
|
||||
|
||||
class JavascriptModule : public Module
|
||||
{
|
||||
public:
|
||||
JavascriptModule();
|
||||
~JavascriptModule();
|
||||
virtual void initialize();
|
||||
bool unload();
|
||||
protected:
|
||||
virtual bool commandExecute(String& retVal, const String& line);
|
||||
virtual bool commandComplete(Message& msg, const String& partLine, const String& partWord);
|
||||
};
|
||||
|
||||
|
||||
INIT_PLUGIN(JavascriptModule);
|
||||
|
||||
UNLOAD_PLUGIN(unloadNow)
|
||||
{
|
||||
if (unloadNow)
|
||||
return __plugin.unload();
|
||||
return true;
|
||||
}
|
||||
|
||||
JavascriptModule::JavascriptModule()
|
||||
: Module("javascript","misc",true)
|
||||
{
|
||||
Output("Loaded module Javascript");
|
||||
}
|
||||
|
||||
JavascriptModule::~JavascriptModule()
|
||||
{
|
||||
Output("Unloading module Javascript");
|
||||
}
|
||||
|
||||
bool JavascriptModule::commandExecute(String& retVal, const String& line)
|
||||
{
|
||||
if (!line.startsWith("js "))
|
||||
return false;
|
||||
String cmd = line.substr(3).trimSpaces();
|
||||
if (cmd.null())
|
||||
return false;
|
||||
ExpOperation* rval = 0;
|
||||
ScriptRun::Status st = JsParser::eval(cmd,&rval);
|
||||
if (rval)
|
||||
retVal << "'" << rval->name() << "'='" << *rval << "'\r\n";
|
||||
else
|
||||
retVal << ScriptRun::textState(st) << "\r\n";
|
||||
TelEngine::destruct(rval);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JavascriptModule::commandComplete(Message& msg, const String& partLine, const String& partWord)
|
||||
{
|
||||
if (partLine.null() && partWord.null())
|
||||
return false;
|
||||
if (partLine.null() || (partLine == "help"))
|
||||
itemComplete(msg.retValue(),"js",partWord);
|
||||
return Module::commandComplete(msg,partLine,partWord);
|
||||
}
|
||||
|
||||
bool JavascriptModule::unload()
|
||||
{
|
||||
uninstallRelays();
|
||||
return true;
|
||||
}
|
||||
|
||||
void JavascriptModule::initialize()
|
||||
{
|
||||
Output("Initializing module Javascript");
|
||||
setup();
|
||||
}
|
||||
|
||||
}; // anonymous namespace
|
||||
|
||||
/* vi: set ts=8 sw=4 sts=4 noet: */
|
Loading…
Reference in New Issue