@@ -42,9 +42,10 @@ typedef struct
4242static PyTypeObject ContextType ;
4343static PyObject * Context_new (PyTypeObject * type , PyObject * args , PyObject * kwds );
4444static void Context_dealloc (Context * self );
45- static PyObject * Context_Eval (Context * self , PyObject * args );
45+ static PyObject * Context_Eval (Context * self , PyObject * args , PyObject * kwargs );
46+ static PyObject * Context_EvalSync (Context * self , PyObject * args , PyObject * kwargs );
4647static PyObject * Context_Set (Context * self , PyObject * args );
47-
48+ static PyObject * Context_GetRuntime ( Context * self , PyObject * Py_UNUSED ( ignored ));
4849static JSValue py_to_js_value (JSContext * ctx , PyObject * obj );
4950static JSValue py_callable_handler (JSContext * ctx , JSValueConst this_val , int argc , JSValueConst * argv , int magic , JSValue * func_data );
5051
@@ -255,7 +256,12 @@ static PyObject *js_value_to_py(JSContext *ctx, JSValue val)
255256 case JS_TAG_EXCEPTION :
256257 {
257258 JSValue exc = JS_GetException (ctx );
258- const char * str = JS_ToCString (ctx , exc );
259+ JSValue val = JS_GetPropertyStr (ctx , exc , "stack" );
260+ if (JS_IsUndefined (val ))
261+ {
262+ val = JS_DupValue (ctx , exc );
263+ }
264+ const char * str = JS_ToCString (ctx , val );
259265 if (str )
260266 {
261267 PyErr_SetString (PyExc_RuntimeError , str );
@@ -265,6 +271,7 @@ static PyObject *js_value_to_py(JSContext *ctx, JSValue val)
265271 {
266272 PyErr_SetString (PyExc_RuntimeError , "Unknown QuickJS exception" );
267273 }
274+ JS_FreeValue (ctx , val );
268275 JS_FreeValue (ctx , exc );
269276 return NULL ;
270277 }
@@ -411,21 +418,59 @@ static PyObject *Context_Set(Context *self, PyObject *args)
411418 Py_RETURN_NONE ;
412419}
413420
414- static PyObject * Context_Eval (Context * self , PyObject * args )
421+ static PyObject * Context_Eval (Context * self , PyObject * args , PyObject * kwargs )
422+ {
423+ static char * kwlist [] = {"code" , "filename" , NULL };
424+ const char * code ;
425+ const char * filename = "input.js" ;
426+ if (!PyArg_ParseTupleAndKeywords (args , kwargs , "s|s" , kwlist , & code , & filename ))
427+ {
428+ return NULL ;
429+ }
430+
431+ JSValue val = JS_Eval (self -> ctx , code , strlen (code ), filename , JS_EVAL_TYPE_GLOBAL );
432+ PyObject * result = js_value_to_py (self -> ctx , val );
433+ JS_FreeValue (self -> ctx , val );
434+ return result ;
435+ }
436+
437+ static PyObject * Context_EvalSync (Context * self , PyObject * args , PyObject * kwargs )
415438{
439+ static char * kwlist [] = {"code" , "filename" , NULL };
416440 const char * code ;
417441 const char * filename = "input.js" ;
418- if (!PyArg_ParseTuple (args , "s|s" , & code , & filename ))
442+ if (!PyArg_ParseTupleAndKeywords (args , kwargs , "s|s" , kwlist , & code , & filename ))
419443 {
420444 return NULL ;
421445 }
422446
423447 JSValue val = JS_Eval (self -> ctx , code , strlen (code ), filename , JS_EVAL_TYPE_GLOBAL );
448+
449+ // Run the job queue until empty
450+ JSContext * ctx1 ;
451+ int err ;
452+ while (JS_IsJobPending (self -> runtime -> rt ))
453+ {
454+ err = JS_ExecutePendingJob (self -> runtime -> rt , & ctx1 );
455+ if (err < 0 )
456+ {
457+ JS_FreeValue (self -> ctx , val );
458+ // js_value_to_py with JS_EXCEPTION will set the Python error
459+ return js_value_to_py (self -> ctx , JS_EXCEPTION );
460+ }
461+ }
462+
424463 PyObject * result = js_value_to_py (self -> ctx , val );
425464 JS_FreeValue (self -> ctx , val );
426465 return result ;
427466}
428467
468+ static PyObject * Context_GetRuntime (Context * self , PyObject * Py_UNUSED (ignored ))
469+ {
470+ Py_INCREF (self -> runtime );
471+ return (PyObject * )self -> runtime ;
472+ }
473+
429474static PyObject * Context_new (PyTypeObject * type , PyObject * args , PyObject * kwds )
430475{
431476 PyErr_SetString (PyExc_RuntimeError , "Cannot create Context directly; use Runtime.new_context()" );
@@ -441,8 +486,10 @@ static void Context_dealloc(Context *self)
441486}
442487
443488static PyMethodDef Context_methods [] = {
444- {"eval" , (PyCFunction )Context_Eval , METH_VARARGS , "Evaluate JavaScript code" },
489+ {"eval" , (PyCFunction )Context_Eval , METH_VARARGS | METH_KEYWORDS , "Evaluate JavaScript code" },
490+ {"eval_sync" , (PyCFunction )Context_EvalSync , METH_VARARGS | METH_KEYWORDS , "Evaluate JavaScript code and run pending jobs" },
445491 {"set" , (PyCFunction )Context_Set , METH_VARARGS , "Set a global value" },
492+ {"get_runtime" , (PyCFunction )Context_GetRuntime , METH_NOARGS , "Get the Runtime associated with this Context" },
446493 {NULL } /* Sentinel */
447494};
448495
0 commit comments