Mercurial > scratch
comparison jseval.py @ 0:1102944b174d
Origination.
author | Atul Varma <varmaa@toolness.com> |
---|---|
date | Wed, 11 Jun 2008 08:30:05 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1102944b174d |
---|---|
1 # jseval.py | |
2 # By Atul Varma <varmaa@toolness.com> | |
3 # | |
4 # This is a simple example of embedding the SpiderMonkey engine into | |
5 # Python using ctypes. | |
6 | |
7 import sys | |
8 import ctypes | |
9 | |
10 # Sample Python function to inject into JavaScript space. | |
11 def displayMessage(msg): | |
12 print msg | |
13 | |
14 class JSEngine( object ): | |
15 def __init__( self, dllpath ): | |
16 self._dllpath = dllpath | |
17 | |
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) | |
39 ] | |
40 | |
41 JSNativeFunction = ctypes.CFUNCTYPE( | |
42 ctypes.c_int, # Return value | |
43 ctypes.c_void_p, # Context | |
44 ctypes.c_void_p, # Object | |
45 ctypes.c_int, # argc | |
46 ctypes.POINTER( ctypes.c_int ), # argv | |
47 ctypes.POINTER( ctypes.c_int ), # retval | |
48 ) | |
49 | |
50 def _initRuntime( self ): | |
51 self.jsdll = ctypes.cdll.LoadLibrary(self._dllpath) | |
52 self.runtime = self.jsdll.JS_Init( 32768 ) | |
53 | |
54 if self.runtime == 0: | |
55 raise JSError( "JS_Init() failed." ) | |
56 | |
57 def _shutdownRuntime( self ): | |
58 self.jsdll.JS_Finish( self.runtime ) | |
59 del self.runtime | |
60 del self.jsdll | |
61 | |
62 def _getNewContext( self ): | |
63 context = self.jsdll.JS_NewContext(self.runtime, 8192) | |
64 if context == 0: | |
65 raise JSError( "JS_NewContext() failed." ) | |
66 return context | |
67 | |
68 def _createGlobalClass( self, name ): | |
69 globalClass = self.JSClass( | |
70 name, 0, | |
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 | |
80 ) | |
81 return globalClass | |
82 | |
83 def _createGlobalObject( self, context, globalClass ): | |
84 globalObj = self.jsdll.JS_NewObject( | |
85 context, | |
86 ctypes.byref( globalClass ), | |
87 0, | |
88 0 | |
89 ) | |
90 | |
91 if not globalObj: | |
92 raise JSError( "JS_NewObject() failed." ) | |
93 | |
94 return globalObj | |
95 | |
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 ) | |
101 retval[0] = 0 | |
102 return 1 | |
103 | |
104 retval = self.jsdll.JS_DefineFunction( | |
105 context, | |
106 globalObj, | |
107 "displayMessage", | |
108 self.JSNativeFunction( jsDisplayMessage ), | |
109 1, | |
110 0 | |
111 ) | |
112 | |
113 if retval == 0: | |
114 raise JSError( "JS_DefineFunction() failed." ) | |
115 | |
116 def eval( self, scriptString ): | |
117 """ | |
118 Evaluates the given string of JavaScript code and returns the | |
119 result as a string. | |
120 | |
121 The string must be ascii-encodable, as this function does not | |
122 currently use JavaScript's unicode API. | |
123 """ | |
124 | |
125 # For more information on what's going on here, see: | |
126 # | |
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 | |
130 | |
131 script = scriptString.encode( "ascii" ) | |
132 | |
133 # We carefully set up and shutdown everything on each pass, to | |
134 # make the world a happier place. | |
135 self._initRuntime() | |
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 ) | |
142 | |
143 try: | |
144 rval = ctypes.c_int() | |
145 | |
146 ok = self.jsdll.JS_EvaluateScript( | |
147 context, | |
148 globalObj, | |
149 script, | |
150 len(script), | |
151 "<string>", | |
152 0, | |
153 ctypes.byref( rval ) | |
154 ) | |
155 | |
156 if not ok: | |
157 raise JSEvalError( "JS_EvaluateScript() failed." ) | |
158 | |
159 jsString = self.jsdll.JS_ValueToString( context, rval ) | |
160 cString = ctypes.c_char_p( | |
161 self.jsdll.JS_GetStringBytes( jsString ) | |
162 ) | |
163 retval = cString.value | |
164 finally: | |
165 self.jsdll.JS_DestroyContext( context ) | |
166 self._shutdownRuntime() | |
167 | |
168 return retval | |
169 | |
170 class JSError( Exception ): | |
171 pass | |
172 | |
173 class JSEvalError( JSError ): | |
174 pass | |
175 | |
176 if __name__ == "__main__": | |
177 args = sys.argv[1:] | |
178 if len(args) < 1: | |
179 print "usage: %s <path-to-spidermonkey-dll>" % sys.argv[0] | |
180 sys.exit(1) | |
181 | |
182 e = JSEngine(sys.argv[1]) | |
183 | |
184 e.eval("displayMessage('hi from spidermonkey! ' + Math.abs(-5));") |