Duktape是款比较小巧的JavaScript引擎,适用于嵌入式系统,不过API使用不太方便,研究了两天决定放弃。下面把测试代码上来,做个备忘吧。
duktape_helper.hpp文件
#ifndef DUKTAPE_HELPER_HPP
#define DUKTAPE_HELPER_HPP
#include <memory>
#include <string>
#include <type_traits>
#include "duktape.h"
namespace duktape {
class StackAssert {
private:
duk_context *m_context;
unsigned m_expected;
unsigned m_begin;
public:
/**
* Create the stack checker.
*
* No-op if NDEBUG is set.
*
* \param ctx the context
* \param expected the size expected relative to the already existing values
*/
inline StackAssert(duk_context *ctx, unsigned expected = 0) noexcept
: m_context(ctx)
, m_expected(expected)
, m_begin(static_cast<unsigned>(duk_get_top(ctx)))
{
}
/**
* Verify the expected size.
*
* No-op if NDEBUG is set.
*/
inline ~StackAssert() noexcept
{
if (static_cast<unsigned>(duk_get_top(m_context)) - m_begin != m_expected) {
std::fprintf(stderr, "Corrupt stack detection in StackAssert:\n");
std::fprintf(stderr, " Size at start: %u\n", m_begin);
std::fprintf(stderr, " Size at end: %d\n", duk_get_top(m_context));
std::fprintf(stderr, " Expected (user): %u\n", m_expected);
std::fprintf(stderr, " Expected (adjusted): %u\n", m_expected + m_begin);
std::fprintf(stderr, " Number of stale values: %u\n", duk_get_top(m_context) - m_begin - m_expected);
std::abort();
}
}
};
template< typename T >
struct duk_result
{
static T get(duk_context *ctx, duk_idx_t idx)
{
return duk_to_null(ctx,idx);
}
};
template<>
struct duk_result<int>
{
static int get(duk_context *ctx, duk_idx_t idx)
{
return duk_to_int(ctx,idx);
}
};
template<>
struct duk_result<double>
{
static double get(duk_context *ctx, duk_idx_t idx)
{
return duk_to_number(ctx,idx);
}
};
template<>
struct duk_result<const char*>
{
static const char* get(duk_context *ctx, duk_idx_t idx)
{
return duk_to_string(ctx,idx);
}
};
class SharedPtr
{
using Deleter = void (*)(duk_context *);
std::unique_ptr<duk_context,Deleter> ptr_;
SharedPtr( const SharedPtr &) = delete;
SharedPtr& operator = ( const SharedPtr&) = delete;
public:
SharedPtr(duk_context *p ):ptr_(p,duk_destroy_heap)
{}
inline operator duk_context *() noexcept
{
return ptr_.get();
}
inline operator duk_context *() const noexcept
{
return ptr_.get();
}
};
using deleter = void(*)(duk_context*);
typedef std::unique_ptr<duk_context,deleter> stack_pop;
class script
{
public:
script():m_ctx(duk_create_heap_default())
{
}
duk_context * context() const
{
return m_ctx;
}
inline operator duk_context *() noexcept
{
return m_ctx;
}
inline operator duk_context *() const noexcept
{
return m_ctx;
}
void evaluate( const std::string & script )
{
StackAssert sa(m_ctx);
stack_pop pop(m_ctx,duk_pop);
duk_eval_string(m_ctx,script.c_str());
}
template<typename R , typename ...Args>
R evaluate(const char* functionName ,Args ...args )
{
StackAssert sa(m_ctx);
stack_pop pop(m_ctx,duk_pop);
duk_get_global_string(m_ctx,functionName);
duk_push_args(m_ctx,args...);
duk_call(m_ctx,sizeof...(args));
return duk_result<R>::get(m_ctx,-1);
}
void defineFunctions(duk_function_list_entry * fs )
{
for( ; fs->key ; fs++ ){
duk_push_c_function(m_ctx, fs->value, fs->nargs);
duk_put_global_string(m_ctx, fs->key);
}
}
void defineFunction(const char* key , duk_c_function func, duk_idx_t nargs)
{
duk_push_c_function(m_ctx, func, nargs);
duk_put_global_string(m_ctx, key);
}
private:
SharedPtr m_ctx;
script( const script &) = delete;
script& operator = ( const script&) = delete;
};
//help template function for duk_push_
template<typename T> void duk_push_arg(duk_context *ctx,T t) {}
template<> void duk_push_arg(duk_context *ctx,int t)
{
duk_push_int(ctx,t);
}
template<> void duk_push_arg(duk_context *ctx,double t)
{
duk_push_number(ctx,t);
}
template<> void duk_push_arg(duk_context *ctx,const char* t)
{
duk_push_string(ctx,t);
}
template<> void duk_push_arg(duk_context *ctx,bool t)
{
duk_push_boolean(ctx,t);
}
template<> void duk_push_arg(duk_context *ctx,void* t)
{
duk_push_pointer(ctx,t);
}
template <typename ...Args>
void duk_push_args(duk_context *ctx,Args... args)
{
std::initializer_list<int> lst{(duk_push_arg(ctx,std::forward< Args>(args)),0)...};
}
}//namespace Duktape
#endif // DUKTAPE_HELPER_HPP
main.cpp文件
#include <iostream>
#include <memory>
#include "duktape_helper.hpp"
static duk_ret_t native_print(duk_context *ctx) {
duk_push_string(ctx, " ");
duk_insert(ctx, 0);
duk_join(ctx, duk_get_top(ctx) - 1);
std::cout<<duk_safe_to_string(ctx, -1)<<std::endl;
return 0;
}
static duk_ret_t native_adder(duk_context *ctx) {
int i;
int n = duk_get_top(ctx); /* #args */
double res = 0.0;
for (i = 0; i < n; i++) {
res += duk_to_number(ctx, i);
}
duk_push_number(ctx, res);
return 1; /* one return value */
}
int main()
{
std::cout << "Run duktape JavaScript !" << std::endl;
std::shared_ptr<duktape::script> duk = std::make_shared<duktape::script>();
duk_function_list_entry functions[] = {
{"print",native_print,DUK_VARARGS},
{"adder",native_adder,DUK_VARARGS},
{0}
};
duk->defineFunctions(functions);
duk->evaluate("var a = 'Hello world'; print(a + ' ' + Duktape.version);");
duk->evaluate("print('2.2+3.3=' + adder(2.2, 3.3));");
duk->evaluate("function sum(a,b){ return a+b; }");
duk->evaluate("var printVersion = function (msg,a,b){"
"var disp = msg+(a+b) ; "
"print ('Duktape Version: '+ Duktape.version); "
"return disp;}");
const char* result;
result = duk->evaluate<const char*>("printVersion","call javascript function ",56,44);
std::cout<<result<<std::endl;
double ret;
ret = duk->evaluate<double>("sum",56,44);
std::cout<<ret<<std::endl;
return 0;
}
CMakeLists.txt文件
cmake_minimum_required(VERSION 2.8)
set(CMAKE_VERBOSE_MAKEFILE ON)
project(duk_jse)
set(CMAKE_C_COMPILER clang)
set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_C_FLAGS -std=c99)
set(CMAKE_CXX_FLAGS "-std=c++11")
set(LIST_SRC main.cpp
duktape.c)
add_executable(${PROJECT_NAME} ${LIST_SRC})
代码挺简单,就不注释了。还测试过v7,sipdermonkey1.8,如果是做嵌入式系统v7就够用了,sipdermonkey的api和文档都很好,就是大了些,不过1.8版本编译后也可以。