Python ctypesでSpiderMonkeyを呼び出す

PythonでのFFI - ラシウラ の続きで、ctypesの練習にSpiderMonkeyのDLLを呼び出してみました。
べた書きで、後半の例題に必要最低限の情報を使うだけにとどめてます。

参考文献は

および、SpiderMonkeyのヘッダファイルです。

import ctypes

# ctypes: http://python.net/crew/theller/ctypes/tutorial.html
# spidermonkey: http://www.mozilla.org/js/spidermonkey/tutorial.html

# setup
libjs = ctypes.CDLL("libmozjs.so") # from ubuntu libmozjs package
class JSClass(ctypes.Structure):
    _fields_ = [
        ("name", ctypes.c_char_p),
        ("flags", ctypes.c_uint32),
        ("addProperty", libjs._FuncPtr),
        ("delProperty", libjs._FuncPtr),
        ("getProperty", libjs._FuncPtr),
        ("setProperty", libjs._FuncPtr),
        ("enumrate", libjs._FuncPtr),
        ("resolve", libjs._FuncPtr),
        ("convert", libjs._FuncPtr),
        ("finalize", libjs._FuncPtr),

        ("getObjectOps", libjs._FuncPtr),
        ("checkAccess", libjs._FuncPtr),
        ("call", libjs._FuncPtr),
        ("construct", libjs._FuncPtr),
        ("xdrObject", libjs._FuncPtr),
        ("hasInstance", libjs._FuncPtr),
        ("mark", libjs._FuncPtr),
        ("reserveSlots", libjs._FuncPtr),
        ]
    pass

global_class = JSClass()
global_class.name = "global"
global_class.flags = 0
global_class.addProperty = libjs.JS_PropertyStub
global_class.delProperty = libjs.JS_PropertyStub
global_class.getProperty = libjs.JS_PropertyStub
global_class.setProperty = libjs.JS_PropertyStub
global_class.enumerate = libjs.JS_EnumerateStub
global_class.resolve = libjs.JS_ResolveStub
global_class.convert = libjs.JS_ConvertStub
global_class.finalize = libjs.JS_FinalizeStub

rt = libjs.JS_Init(0x100000)
cx = libjs.JS_NewContext(rt, 0x1000)
globe = libjs.JS_NewObject(cx, ctypes.pointer(global_class), None, None)
libjs.JS_InitStandardClasses(cx, globe)


libjs.JS_GetStringBytes.restype = ctypes.c_char_p

# see macros in jsapi.h: STRING_TO_JSVAL
def String2jsval(jsstr):
    return jsstr | 0x4

# example: evaluate
script = """
var a = 100;
a + "abc";
"""
ret = ctypes.c_long(0)
filename = "snip"
lineno = 0
libjs.JS_EvaluateScript(cx, globe, script, len(script),
                        filename, lineno, ctypes.pointer(ret))
strp = libjs.JS_ValueToString(cx, ret)
print libjs.JS_GetStringBytes(strp)

# example: function and call it
script = """
function (name) {
  return "Hello " + name;
}
"""
ret = ctypes.c_long(0)
filename = "snip"
lineno = 0
libjs.JS_EvaluateScript(cx, globe, script, len(script),
                        filename, lineno, ctypes.pointer(ret))
funp = libjs.JS_ValueToFunction(cx, ret)

name = "Taro"
jsstr = libjs.JS_NewStringCopyN(cx, name, len(name))
argvt = ctypes.c_long * 1
argv = argvt(String2jsval(jsstr))

libjs.JS_CallFunction(cx, None, funp, len(argv), ctypes.pointer(argv), ctypes.pointer(ret))
strp = libjs.JS_ValueToString(cx, ret)
print libjs.JS_GetStringBytes(strp)

(注意点はContext cxはスレッドごとに作る必要があること。)

すでにPython SpiderMonkeyがあるんですけどね。