Mercurial > scratch
view jseval.py @ 8:05f467a83cb9 ink_blog_post
Added open web magic ink page.
author | Atul Varma <varmaa@toolness.com> |
---|---|
date | Thu, 03 Sep 2009 19:34:28 -0700 |
parents | 1102944b174d |
children |
line wrap: on
line source
# jseval.py # By Atul Varma <varmaa@toolness.com> # # This is a simple example of embedding the SpiderMonkey engine into # Python using ctypes. import sys import ctypes # Sample Python function to inject into JavaScript space. def displayMessage(msg): print msg class JSEngine( object ): def __init__( self, dllpath ): self._dllpath = dllpath class JSClass( ctypes.Structure ): _fields_ = [("name", ctypes.c_char_p), ("flags", ctypes.c_uint32), # Mandatory non-null members ("addProperty", ctypes.c_void_p), ("delProperty", ctypes.c_void_p), ("getProperty", ctypes.c_void_p), ("setProperty", ctypes.c_void_p), ("enumerate", ctypes.c_void_p), ("resolve", ctypes.c_void_p), ("convert", ctypes.c_void_p), ("finalize", ctypes.c_void_p), # Optionally non-null members ("getObjectOps", ctypes.c_void_p), ("checkAccess", ctypes.c_void_p), ("call", ctypes.c_void_p), ("construct", ctypes.c_void_p), ("xdrObject", ctypes.c_void_p), ("hasInstance", ctypes.c_void_p), ("mark", ctypes.c_void_p), ("reserveSlots", ctypes.c_void_p) ] JSNativeFunction = ctypes.CFUNCTYPE( ctypes.c_int, # Return value ctypes.c_void_p, # Context ctypes.c_void_p, # Object ctypes.c_int, # argc ctypes.POINTER( ctypes.c_int ), # argv ctypes.POINTER( ctypes.c_int ), # retval ) def _initRuntime( self ): self.jsdll = ctypes.cdll.LoadLibrary(self._dllpath) self.runtime = self.jsdll.JS_Init( 32768 ) if self.runtime == 0: raise JSError( "JS_Init() failed." ) def _shutdownRuntime( self ): self.jsdll.JS_Finish( self.runtime ) del self.runtime del self.jsdll def _getNewContext( self ): context = self.jsdll.JS_NewContext(self.runtime, 8192) if context == 0: raise JSError( "JS_NewContext() failed." ) return context def _createGlobalClass( self, name ): globalClass = self.JSClass( name, 0, ctypes.cast( self.jsdll.JS_PropertyStub, ctypes.c_void_p ), ctypes.cast( self.jsdll.JS_PropertyStub, ctypes.c_void_p ), ctypes.cast( self.jsdll.JS_PropertyStub, ctypes.c_void_p ), ctypes.cast( self.jsdll.JS_PropertyStub, ctypes.c_void_p ), ctypes.cast( self.jsdll.JS_EnumerateStub, ctypes.c_void_p ), ctypes.cast( self.jsdll.JS_ResolveStub, ctypes.c_void_p ), ctypes.cast( self.jsdll.JS_ConvertStub, ctypes.c_void_p ), ctypes.cast( self.jsdll.JS_FinalizeStub, ctypes.c_void_p ), 0, 0, 0, 0, 0, 0, 0, 0 ) return globalClass def _createGlobalObject( self, context, globalClass ): globalObj = self.jsdll.JS_NewObject( context, ctypes.byref( globalClass ), 0, 0 ) if not globalObj: raise JSError( "JS_NewObject() failed." ) return globalObj def _installDisplayMessageFunction( self, context, globalObj ): def jsDisplayMessage( context, object, argc, argv, retval ): jsString = self.jsdll.JS_ValueToString( context, argv[0] ) cString = ctypes.c_char_p( self.jsdll.JS_GetStringBytes( jsString ) ) displayMessage( cString.value ) retval[0] = 0 return 1 retval = self.jsdll.JS_DefineFunction( context, globalObj, "displayMessage", self.JSNativeFunction( jsDisplayMessage ), 1, 0 ) if retval == 0: raise JSError( "JS_DefineFunction() failed." ) def eval( self, scriptString ): """ Evaluates the given string of JavaScript code and returns the result as a string. The string must be ascii-encodable, as this function does not currently use JavaScript's unicode API. """ # For more information on what's going on here, see: # # http://developer.mozilla.org [continued on next line] # /en/docs/JavaScript_C_Engine_Embedder%27s_Guide # http://www.mozilla.org/js/spidermonkey/tutorial.html script = scriptString.encode( "ascii" ) # We carefully set up and shutdown everything on each pass, to # make the world a happier place. self._initRuntime() context = self._getNewContext() name = ctypes.c_char_p( "enso" ) globalClass = self._createGlobalClass( name ) globalObj = self._createGlobalObject( context, globalClass ) self._installDisplayMessageFunction( context, globalObj ) builtins = self.jsdll.JS_InitStandardClasses( context, globalObj ) try: rval = ctypes.c_int() ok = self.jsdll.JS_EvaluateScript( context, globalObj, script, len(script), "<string>", 0, ctypes.byref( rval ) ) if not ok: raise JSEvalError( "JS_EvaluateScript() failed." ) jsString = self.jsdll.JS_ValueToString( context, rval ) cString = ctypes.c_char_p( self.jsdll.JS_GetStringBytes( jsString ) ) retval = cString.value finally: self.jsdll.JS_DestroyContext( context ) self._shutdownRuntime() return retval class JSError( Exception ): pass class JSEvalError( JSError ): pass if __name__ == "__main__": args = sys.argv[1:] if len(args) < 1: print "usage: %s <path-to-spidermonkey-dll>" % sys.argv[0] sys.exit(1) e = JSEngine(sys.argv[1]) e.eval("displayMessage('hi from spidermonkey! ' + Math.abs(-5));")