Origination.
2 # By Atul Varma <varmaa@toolness.com>
4 # This is a simple example of embedding the SpiderMonkey engine into
10 # Sample Python function to inject into JavaScript space.
11 def displayMessage(msg):
14 class JSEngine( object ):
15 def __init__( self, dllpath ):
16 self._dllpath = dllpath
18 class JSClass( ctypes.Structure ):
19 _fields_ = [("name", ctypes.c_char_p),
20 ("flags", ctypes.c_uint32),
21 # Mandatory non-null members
22 ("addProperty", ctypes.c_void_p),
23 ("delProperty", ctypes.c_void_p),
24 ("getProperty", ctypes.c_void_p),
25 ("setProperty", ctypes.c_void_p),
26 ("enumerate", ctypes.c_void_p),
27 ("resolve", ctypes.c_void_p),
28 ("convert", ctypes.c_void_p),
29 ("finalize", ctypes.c_void_p),
30 # Optionally non-null members
31 ("getObjectOps", ctypes.c_void_p),
32 ("checkAccess", ctypes.c_void_p),
33 ("call", ctypes.c_void_p),
34 ("construct", ctypes.c_void_p),
35 ("xdrObject", ctypes.c_void_p),
36 ("hasInstance", ctypes.c_void_p),
37 ("mark", ctypes.c_void_p),
38 ("reserveSlots", ctypes.c_void_p)
41 JSNativeFunction = ctypes.CFUNCTYPE(
42 ctypes.c_int, # Return value
43 ctypes.c_void_p, # Context
44 ctypes.c_void_p, # Object
46 ctypes.POINTER( ctypes.c_int ), # argv
47 ctypes.POINTER( ctypes.c_int ), # retval
50 def _initRuntime( self ):
51 self.jsdll = ctypes.cdll.LoadLibrary(self._dllpath)
52 self.runtime = self.jsdll.JS_Init( 32768 )
55 raise JSError( "JS_Init() failed." )
57 def _shutdownRuntime( self ):
58 self.jsdll.JS_Finish( self.runtime )
62 def _getNewContext( self ):
63 context = self.jsdll.JS_NewContext(self.runtime, 8192)
65 raise JSError( "JS_NewContext() failed." )
68 def _createGlobalClass( self, name ):
69 globalClass = self.JSClass(
71 ctypes.cast( self.jsdll.JS_PropertyStub, ctypes.c_void_p ),
72 ctypes.cast( self.jsdll.JS_PropertyStub, ctypes.c_void_p ),
73 ctypes.cast( self.jsdll.JS_PropertyStub, ctypes.c_void_p ),
74 ctypes.cast( self.jsdll.JS_PropertyStub, ctypes.c_void_p ),
75 ctypes.cast( self.jsdll.JS_EnumerateStub, ctypes.c_void_p ),
76 ctypes.cast( self.jsdll.JS_ResolveStub, ctypes.c_void_p ),
77 ctypes.cast( self.jsdll.JS_ConvertStub, ctypes.c_void_p ),
78 ctypes.cast( self.jsdll.JS_FinalizeStub, ctypes.c_void_p ),
79 0, 0, 0, 0, 0, 0, 0, 0
83 def _createGlobalObject( self, context, globalClass ):
84 globalObj = self.jsdll.JS_NewObject(
86 ctypes.byref( globalClass ),
92 raise JSError( "JS_NewObject() failed." )
96 def _installDisplayMessageFunction( self, context, globalObj ):
97 def jsDisplayMessage( context, object, argc, argv, retval ):
98 jsString = self.jsdll.JS_ValueToString( context, argv[0] )
99 cString = ctypes.c_char_p( self.jsdll.JS_GetStringBytes( jsString ) )
100 displayMessage( cString.value )
104 retval = self.jsdll.JS_DefineFunction(
108 self.JSNativeFunction( jsDisplayMessage ),
114 raise JSError( "JS_DefineFunction() failed." )
116 def eval( self, scriptString ):
118 Evaluates the given string of JavaScript code and returns the
121 The string must be ascii-encodable, as this function does not
122 currently use JavaScript's unicode API.
125 # For more information on what's going on here, see:
127 # http://developer.mozilla.org [continued on next line]
128 # /en/docs/JavaScript_C_Engine_Embedder%27s_Guide
129 # http://www.mozilla.org/js/spidermonkey/tutorial.html
131 script = scriptString.encode( "ascii" )
133 # We carefully set up and shutdown everything on each pass, to
134 # make the world a happier place.
136 context = self._getNewContext()
137 name = ctypes.c_char_p( "enso" )
138 globalClass = self._createGlobalClass( name )
139 globalObj = self._createGlobalObject( context, globalClass )
140 self._installDisplayMessageFunction( context, globalObj )
141 builtins = self.jsdll.JS_InitStandardClasses( context, globalObj )
144 rval = ctypes.c_int()
146 ok = self.jsdll.JS_EvaluateScript(
157 raise JSEvalError( "JS_EvaluateScript() failed." )
159 jsString = self.jsdll.JS_ValueToString( context, rval )
160 cString = ctypes.c_char_p(
161 self.jsdll.JS_GetStringBytes( jsString )
163 retval = cString.value
165 self.jsdll.JS_DestroyContext( context )
166 self._shutdownRuntime()
170 class JSError( Exception ):
173 class JSEvalError( JSError ):
176 if __name__ == "__main__":
179 print "usage: %s <path-to-spidermonkey-dll>" % sys.argv[0]
182 e = JSEngine(sys.argv[1])
184 e.eval("displayMessage('hi from spidermonkey! ' + Math.abs(-5));")