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));")
