scratch

annotate 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

rev   line source
varmaa@0 1 # jseval.py
varmaa@0 2 # By Atul Varma <varmaa@toolness.com>
varmaa@0 3 #
varmaa@0 4 # This is a simple example of embedding the SpiderMonkey engine into
varmaa@0 5 # Python using ctypes.
varmaa@0 6
varmaa@0 7 import sys
varmaa@0 8 import ctypes
varmaa@0 9
varmaa@0 10 # Sample Python function to inject into JavaScript space.
varmaa@0 11 def displayMessage(msg):
varmaa@0 12 print msg
varmaa@0 13
varmaa@0 14 class JSEngine( object ):
varmaa@0 15 def __init__( self, dllpath ):
varmaa@0 16 self._dllpath = dllpath
varmaa@0 17
varmaa@0 18 class JSClass( ctypes.Structure ):
varmaa@0 19 _fields_ = [("name", ctypes.c_char_p),
varmaa@0 20 ("flags", ctypes.c_uint32),
varmaa@0 21 # Mandatory non-null members
varmaa@0 22 ("addProperty", ctypes.c_void_p),
varmaa@0 23 ("delProperty", ctypes.c_void_p),
varmaa@0 24 ("getProperty", ctypes.c_void_p),
varmaa@0 25 ("setProperty", ctypes.c_void_p),
varmaa@0 26 ("enumerate", ctypes.c_void_p),
varmaa@0 27 ("resolve", ctypes.c_void_p),
varmaa@0 28 ("convert", ctypes.c_void_p),
varmaa@0 29 ("finalize", ctypes.c_void_p),
varmaa@0 30 # Optionally non-null members
varmaa@0 31 ("getObjectOps", ctypes.c_void_p),
varmaa@0 32 ("checkAccess", ctypes.c_void_p),
varmaa@0 33 ("call", ctypes.c_void_p),
varmaa@0 34 ("construct", ctypes.c_void_p),
varmaa@0 35 ("xdrObject", ctypes.c_void_p),
varmaa@0 36 ("hasInstance", ctypes.c_void_p),
varmaa@0 37 ("mark", ctypes.c_void_p),
varmaa@0 38 ("reserveSlots", ctypes.c_void_p)
varmaa@0 39 ]
varmaa@0 40
varmaa@0 41 JSNativeFunction = ctypes.CFUNCTYPE(
varmaa@0 42 ctypes.c_int, # Return value
varmaa@0 43 ctypes.c_void_p, # Context
varmaa@0 44 ctypes.c_void_p, # Object
varmaa@0 45 ctypes.c_int, # argc
varmaa@0 46 ctypes.POINTER( ctypes.c_int ), # argv
varmaa@0 47 ctypes.POINTER( ctypes.c_int ), # retval
varmaa@0 48 )
varmaa@0 49
varmaa@0 50 def _initRuntime( self ):
varmaa@0 51 self.jsdll = ctypes.cdll.LoadLibrary(self._dllpath)
varmaa@0 52 self.runtime = self.jsdll.JS_Init( 32768 )
varmaa@0 53
varmaa@0 54 if self.runtime == 0:
varmaa@0 55 raise JSError( "JS_Init() failed." )
varmaa@0 56
varmaa@0 57 def _shutdownRuntime( self ):
varmaa@0 58 self.jsdll.JS_Finish( self.runtime )
varmaa@0 59 del self.runtime
varmaa@0 60 del self.jsdll
varmaa@0 61
varmaa@0 62 def _getNewContext( self ):
varmaa@0 63 context = self.jsdll.JS_NewContext(self.runtime, 8192)
varmaa@0 64 if context == 0:
varmaa@0 65 raise JSError( "JS_NewContext() failed." )
varmaa@0 66 return context
varmaa@0 67
varmaa@0 68 def _createGlobalClass( self, name ):
varmaa@0 69 globalClass = self.JSClass(
varmaa@0 70 name, 0,
varmaa@0 71 ctypes.cast( self.jsdll.JS_PropertyStub, ctypes.c_void_p ),
varmaa@0 72 ctypes.cast( self.jsdll.JS_PropertyStub, ctypes.c_void_p ),
varmaa@0 73 ctypes.cast( self.jsdll.JS_PropertyStub, ctypes.c_void_p ),
varmaa@0 74 ctypes.cast( self.jsdll.JS_PropertyStub, ctypes.c_void_p ),
varmaa@0 75 ctypes.cast( self.jsdll.JS_EnumerateStub, ctypes.c_void_p ),
varmaa@0 76 ctypes.cast( self.jsdll.JS_ResolveStub, ctypes.c_void_p ),
varmaa@0 77 ctypes.cast( self.jsdll.JS_ConvertStub, ctypes.c_void_p ),
varmaa@0 78 ctypes.cast( self.jsdll.JS_FinalizeStub, ctypes.c_void_p ),
varmaa@0 79 0, 0, 0, 0, 0, 0, 0, 0
varmaa@0 80 )
varmaa@0 81 return globalClass
varmaa@0 82
varmaa@0 83 def _createGlobalObject( self, context, globalClass ):
varmaa@0 84 globalObj = self.jsdll.JS_NewObject(
varmaa@0 85 context,
varmaa@0 86 ctypes.byref( globalClass ),
varmaa@0 87 0,
varmaa@0 88 0
varmaa@0 89 )
varmaa@0 90
varmaa@0 91 if not globalObj:
varmaa@0 92 raise JSError( "JS_NewObject() failed." )
varmaa@0 93
varmaa@0 94 return globalObj
varmaa@0 95
varmaa@0 96 def _installDisplayMessageFunction( self, context, globalObj ):
varmaa@0 97 def jsDisplayMessage( context, object, argc, argv, retval ):
varmaa@0 98 jsString = self.jsdll.JS_ValueToString( context, argv[0] )
varmaa@0 99 cString = ctypes.c_char_p( self.jsdll.JS_GetStringBytes( jsString ) )
varmaa@0 100 displayMessage( cString.value )
varmaa@0 101 retval[0] = 0
varmaa@0 102 return 1
varmaa@0 103
varmaa@0 104 retval = self.jsdll.JS_DefineFunction(
varmaa@0 105 context,
varmaa@0 106 globalObj,
varmaa@0 107 "displayMessage",
varmaa@0 108 self.JSNativeFunction( jsDisplayMessage ),
varmaa@0 109 1,
varmaa@0 110 0
varmaa@0 111 )
varmaa@0 112
varmaa@0 113 if retval == 0:
varmaa@0 114 raise JSError( "JS_DefineFunction() failed." )
varmaa@0 115
varmaa@0 116 def eval( self, scriptString ):
varmaa@0 117 """
varmaa@0 118 Evaluates the given string of JavaScript code and returns the
varmaa@0 119 result as a string.
varmaa@0 120
varmaa@0 121 The string must be ascii-encodable, as this function does not
varmaa@0 122 currently use JavaScript's unicode API.
varmaa@0 123 """
varmaa@0 124
varmaa@0 125 # For more information on what's going on here, see:
varmaa@0 126 #
varmaa@0 127 # http://developer.mozilla.org [continued on next line]
varmaa@0 128 # /en/docs/JavaScript_C_Engine_Embedder%27s_Guide
varmaa@0 129 # http://www.mozilla.org/js/spidermonkey/tutorial.html
varmaa@0 130
varmaa@0 131 script = scriptString.encode( "ascii" )
varmaa@0 132
varmaa@0 133 # We carefully set up and shutdown everything on each pass, to
varmaa@0 134 # make the world a happier place.
varmaa@0 135 self._initRuntime()
varmaa@0 136 context = self._getNewContext()
varmaa@0 137 name = ctypes.c_char_p( "enso" )
varmaa@0 138 globalClass = self._createGlobalClass( name )
varmaa@0 139 globalObj = self._createGlobalObject( context, globalClass )
varmaa@0 140 self._installDisplayMessageFunction( context, globalObj )
varmaa@0 141 builtins = self.jsdll.JS_InitStandardClasses( context, globalObj )
varmaa@0 142
varmaa@0 143 try:
varmaa@0 144 rval = ctypes.c_int()
varmaa@0 145
varmaa@0 146 ok = self.jsdll.JS_EvaluateScript(
varmaa@0 147 context,
varmaa@0 148 globalObj,
varmaa@0 149 script,
varmaa@0 150 len(script),
varmaa@0 151 "<string>",
varmaa@0 152 0,
varmaa@0 153 ctypes.byref( rval )
varmaa@0 154 )
varmaa@0 155
varmaa@0 156 if not ok:
varmaa@0 157 raise JSEvalError( "JS_EvaluateScript() failed." )
varmaa@0 158
varmaa@0 159 jsString = self.jsdll.JS_ValueToString( context, rval )
varmaa@0 160 cString = ctypes.c_char_p(
varmaa@0 161 self.jsdll.JS_GetStringBytes( jsString )
varmaa@0 162 )
varmaa@0 163 retval = cString.value
varmaa@0 164 finally:
varmaa@0 165 self.jsdll.JS_DestroyContext( context )
varmaa@0 166 self._shutdownRuntime()
varmaa@0 167
varmaa@0 168 return retval
varmaa@0 169
varmaa@0 170 class JSError( Exception ):
varmaa@0 171 pass
varmaa@0 172
varmaa@0 173 class JSEvalError( JSError ):
varmaa@0 174 pass
varmaa@0 175
varmaa@0 176 if __name__ == "__main__":
varmaa@0 177 args = sys.argv[1:]
varmaa@0 178 if len(args) < 1:
varmaa@0 179 print "usage: %s <path-to-spidermonkey-dll>" % sys.argv[0]
varmaa@0 180 sys.exit(1)
varmaa@0 181
varmaa@0 182 e = JSEngine(sys.argv[1])
varmaa@0 183
varmaa@0 184 e.eval("displayMessage('hi from spidermonkey! ' + Math.abs(-5));")