scratch

diff jseval.py @ 0:1102944b174d

Origination.
author Atul Varma <varmaa@toolness.com>
date Wed Jun 11 08:30:05 2008 -0700 (3 years ago)
parents
children
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/jseval.py Wed Jun 11 08:30:05 2008 -0700 1.3 @@ -0,0 +1,184 @@ 1.4 +# jseval.py 1.5 +# By Atul Varma <varmaa@toolness.com> 1.6 +# 1.7 +# This is a simple example of embedding the SpiderMonkey engine into 1.8 +# Python using ctypes. 1.9 + 1.10 +import sys 1.11 +import ctypes 1.12 + 1.13 +# Sample Python function to inject into JavaScript space. 1.14 +def displayMessage(msg): 1.15 + print msg 1.16 + 1.17 +class JSEngine( object ): 1.18 + def __init__( self, dllpath ): 1.19 + self._dllpath = dllpath 1.20 + 1.21 + class JSClass( ctypes.Structure ): 1.22 + _fields_ = [("name", ctypes.c_char_p), 1.23 + ("flags", ctypes.c_uint32), 1.24 + # Mandatory non-null members 1.25 + ("addProperty", ctypes.c_void_p), 1.26 + ("delProperty", ctypes.c_void_p), 1.27 + ("getProperty", ctypes.c_void_p), 1.28 + ("setProperty", ctypes.c_void_p), 1.29 + ("enumerate", ctypes.c_void_p), 1.30 + ("resolve", ctypes.c_void_p), 1.31 + ("convert", ctypes.c_void_p), 1.32 + ("finalize", ctypes.c_void_p), 1.33 + # Optionally non-null members 1.34 + ("getObjectOps", ctypes.c_void_p), 1.35 + ("checkAccess", ctypes.c_void_p), 1.36 + ("call", ctypes.c_void_p), 1.37 + ("construct", ctypes.c_void_p), 1.38 + ("xdrObject", ctypes.c_void_p), 1.39 + ("hasInstance", ctypes.c_void_p), 1.40 + ("mark", ctypes.c_void_p), 1.41 + ("reserveSlots", ctypes.c_void_p) 1.42 + ] 1.43 + 1.44 + JSNativeFunction = ctypes.CFUNCTYPE( 1.45 + ctypes.c_int, # Return value 1.46 + ctypes.c_void_p, # Context 1.47 + ctypes.c_void_p, # Object 1.48 + ctypes.c_int, # argc 1.49 + ctypes.POINTER( ctypes.c_int ), # argv 1.50 + ctypes.POINTER( ctypes.c_int ), # retval 1.51 + ) 1.52 + 1.53 + def _initRuntime( self ): 1.54 + self.jsdll = ctypes.cdll.LoadLibrary(self._dllpath) 1.55 + self.runtime = self.jsdll.JS_Init( 32768 ) 1.56 + 1.57 + if self.runtime == 0: 1.58 + raise JSError( "JS_Init() failed." ) 1.59 + 1.60 + def _shutdownRuntime( self ): 1.61 + self.jsdll.JS_Finish( self.runtime ) 1.62 + del self.runtime 1.63 + del self.jsdll 1.64 + 1.65 + def _getNewContext( self ): 1.66 + context = self.jsdll.JS_NewContext(self.runtime, 8192) 1.67 + if context == 0: 1.68 + raise JSError( "JS_NewContext() failed." ) 1.69 + return context 1.70 + 1.71 + def _createGlobalClass( self, name ): 1.72 + globalClass = self.JSClass( 1.73 + name, 0, 1.74 + ctypes.cast( self.jsdll.JS_PropertyStub, ctypes.c_void_p ), 1.75 + ctypes.cast( self.jsdll.JS_PropertyStub, ctypes.c_void_p ), 1.76 + ctypes.cast( self.jsdll.JS_PropertyStub, ctypes.c_void_p ), 1.77 + ctypes.cast( self.jsdll.JS_PropertyStub, ctypes.c_void_p ), 1.78 + ctypes.cast( self.jsdll.JS_EnumerateStub, ctypes.c_void_p ), 1.79 + ctypes.cast( self.jsdll.JS_ResolveStub, ctypes.c_void_p ), 1.80 + ctypes.cast( self.jsdll.JS_ConvertStub, ctypes.c_void_p ), 1.81 + ctypes.cast( self.jsdll.JS_FinalizeStub, ctypes.c_void_p ), 1.82 + 0, 0, 0, 0, 0, 0, 0, 0 1.83 + ) 1.84 + return globalClass 1.85 + 1.86 + def _createGlobalObject( self, context, globalClass ): 1.87 + globalObj = self.jsdll.JS_NewObject( 1.88 + context, 1.89 + ctypes.byref( globalClass ), 1.90 + 0, 1.91 + 0 1.92 + ) 1.93 + 1.94 + if not globalObj: 1.95 + raise JSError( "JS_NewObject() failed." ) 1.96 + 1.97 + return globalObj 1.98 + 1.99 + def _installDisplayMessageFunction( self, context, globalObj ): 1.100 + def jsDisplayMessage( context, object, argc, argv, retval ): 1.101 + jsString = self.jsdll.JS_ValueToString( context, argv[0] ) 1.102 + cString = ctypes.c_char_p( self.jsdll.JS_GetStringBytes( jsString ) ) 1.103 + displayMessage( cString.value ) 1.104 + retval[0] = 0 1.105 + return 1 1.106 + 1.107 + retval = self.jsdll.JS_DefineFunction( 1.108 + context, 1.109 + globalObj, 1.110 + "displayMessage", 1.111 + self.JSNativeFunction( jsDisplayMessage ), 1.112 + 1, 1.113 + 0 1.114 + ) 1.115 + 1.116 + if retval == 0: 1.117 + raise JSError( "JS_DefineFunction() failed." ) 1.118 + 1.119 + def eval( self, scriptString ): 1.120 + """ 1.121 + Evaluates the given string of JavaScript code and returns the 1.122 + result as a string. 1.123 + 1.124 + The string must be ascii-encodable, as this function does not 1.125 + currently use JavaScript's unicode API. 1.126 + """ 1.127 + 1.128 + # For more information on what's going on here, see: 1.129 + # 1.130 + # http://developer.mozilla.org [continued on next line] 1.131 + # /en/docs/JavaScript_C_Engine_Embedder%27s_Guide 1.132 + # http://www.mozilla.org/js/spidermonkey/tutorial.html 1.133 + 1.134 + script = scriptString.encode( "ascii" ) 1.135 + 1.136 + # We carefully set up and shutdown everything on each pass, to 1.137 + # make the world a happier place. 1.138 + self._initRuntime() 1.139 + context = self._getNewContext() 1.140 + name = ctypes.c_char_p( "enso" ) 1.141 + globalClass = self._createGlobalClass( name ) 1.142 + globalObj = self._createGlobalObject( context, globalClass ) 1.143 + self._installDisplayMessageFunction( context, globalObj ) 1.144 + builtins = self.jsdll.JS_InitStandardClasses( context, globalObj ) 1.145 + 1.146 + try: 1.147 + rval = ctypes.c_int() 1.148 + 1.149 + ok = self.jsdll.JS_EvaluateScript( 1.150 + context, 1.151 + globalObj, 1.152 + script, 1.153 + len(script), 1.154 + "<string>", 1.155 + 0, 1.156 + ctypes.byref( rval ) 1.157 + ) 1.158 + 1.159 + if not ok: 1.160 + raise JSEvalError( "JS_EvaluateScript() failed." ) 1.161 + 1.162 + jsString = self.jsdll.JS_ValueToString( context, rval ) 1.163 + cString = ctypes.c_char_p( 1.164 + self.jsdll.JS_GetStringBytes( jsString ) 1.165 + ) 1.166 + retval = cString.value 1.167 + finally: 1.168 + self.jsdll.JS_DestroyContext( context ) 1.169 + self._shutdownRuntime() 1.170 + 1.171 + return retval 1.172 + 1.173 +class JSError( Exception ): 1.174 + pass 1.175 + 1.176 +class JSEvalError( JSError ): 1.177 + pass 1.178 + 1.179 +if __name__ == "__main__": 1.180 + args = sys.argv[1:] 1.181 + if len(args) < 1: 1.182 + print "usage: %s <path-to-spidermonkey-dll>" % sys.argv[0] 1.183 + sys.exit(1) 1.184 + 1.185 + e = JSEngine(sys.argv[1]) 1.186 + 1.187 + e.eval("displayMessage('hi from spidermonkey! ' + Math.abs(-5));")