Unify fail macros (#1062)

This commit is contained in:
Hood Chatham 2021-01-07 22:33:27 -08:00 committed by GitHub
parent 1baffc14f8
commit e11d40ef04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 156 additions and 108 deletions

View File

@ -4,6 +4,11 @@
#include "jsproxy.h"
#include <emscripten.h>
EM_JS_NUM(errcode, log_error, (char* msg), {
let jsmsg = UTF8ToString(msg);
console.error(jsmsg);
});
void
PyodideErr_SetJsError(JsRef err)
{

View File

@ -17,6 +17,9 @@ typedef int errcode;
int
error_handling_init();
errcode
log_error(char* msg);
// WARNING: These wrappers around EM_JS cause macros in body to be expanded.
// This causes trouble with true and false.
// In types.h we provide nonstandard definitions:
@ -36,6 +39,7 @@ error_handling_init();
Module.handle_js_error(e); \
return 0; \
} \
throw new Error("Assertion error: control reached end of function without return");\
})
#define EM_JS_NUM(ret, func_name, args, body...) \
@ -49,7 +53,47 @@ error_handling_init();
Module.handle_js_error(e); \
return -1; \
} \
return 0; /* some of these were void */ \
})
// clang-format on
#ifdef DEBUG_F
#define FAIL() \
do { \
char* msg; \
asprintf(&msg, \
"Raised exception on line %d in func %s, file %s\n", \
__LINE__, \
__func__, \
__FILE__); \
log_error(msg); \
free(msg); \
goto finally \
} while (0)
#else
#define FAIL() goto finally
#endif
#define FAIL_IF_NULL(x) \
do { \
if (x == NULL) { \
FAIL(); \
} \
} while (0)
#define FAIL_IF_MINUS_ONE(x) \
do { \
if (x != 0) { \
FAIL(); \
} \
} while (0)
#define FAIL_IF_ERR_OCCURRED(x) \
do { \
if (PyErr_Occurred()) { \
FAIL(); \
} \
} while (0)
#endif // ERROR_HANDLING_H

View File

@ -43,6 +43,12 @@ typedef struct _JsRefStruct* JsRef;
#define Js_FALSE ((JsRef)(6))
#define Js_NULL ((JsRef)(8))
#define hiwire_CLEAR(x) \
do { \
hiwire_decref(x); \
x = NULL; \
} while (0)
/**
* Initialize the variables and functions required for hiwire.
*/

View File

@ -29,6 +29,8 @@ typedef struct
} JsProxy;
// clang-format on
#define JsProxy_REF(x) (((JsProxy*)x)->js)
static void
JsProxy_dealloc(JsProxy* self)
{
@ -38,101 +40,123 @@ JsProxy_dealloc(JsProxy* self)
}
static PyObject*
JsProxy_Repr(PyObject* o)
JsProxy_Repr(PyObject* self)
{
JsProxy* self = (JsProxy*)o;
JsRef idrepr = hiwire_to_string(self->js);
JsRef idrepr = hiwire_to_string(JsProxy_REF(self));
PyObject* pyrepr = js2python(idrepr);
return pyrepr;
}
PyObject*
JsProxy_typeof(PyObject* obj, void* _unused)
JsProxy_typeof(PyObject* self, void* _unused)
{
JsProxy* self = (JsProxy*)obj;
JsRef idval = hiwire_typeof(self->js);
JsRef idval = hiwire_typeof(JsProxy_REF(self));
PyObject* result = js2python(idval);
hiwire_decref(idval);
return result;
}
static PyObject*
JsProxy_GetAttr(PyObject* o, PyObject* attr)
JsProxy_GetAttr(PyObject* self, PyObject* attr)
{
PyObject* result = PyObject_GenericGetAttr(o, attr);
PyObject* result = PyObject_GenericGetAttr(self, attr);
if (result != NULL) {
return result;
}
PyErr_Clear();
JsProxy* self = (JsProxy*)o;
bool success = false;
JsRef idresult;
// result:
PyObject* pyresult;
const char* key = PyUnicode_AsUTF8(attr);
if (key == NULL) {
return NULL;
}
JsRef idresult = hiwire_get_member_string(self->js, key);
FAIL_IF_NULL(key);
idresult = hiwire_get_member_string(JsProxy_REF(self), key);
if (idresult == NULL) {
PyErr_SetString(PyExc_AttributeError, key);
return NULL;
FAIL();
}
if (hiwire_is_function(idresult)) {
hiwire_decref(idresult);
return JsBoundMethod_cnew(self->js, key);
pyresult = JsBoundMethod_cnew(JsProxy_REF(self), key);
} else {
pyresult = js2python(idresult);
}
FAIL_IF_NULL(pyresult);
PyObject* pyresult = js2python(idresult);
success = true;
finally:
hiwire_decref(idresult);
if (!success) {
Py_CLEAR(pyresult);
}
return pyresult;
}
static int
JsProxy_SetAttr(PyObject* o, PyObject* attr, PyObject* pyvalue)
JsProxy_SetAttr(PyObject* self, PyObject* attr, PyObject* pyvalue)
{
JsProxy* self = (JsProxy*)o;
bool success = false;
JsRef idvalue = NULL;
const char* key = PyUnicode_AsUTF8(attr);
if (key == NULL) {
return -1;
}
FAIL_IF_NULL(key);
if (pyvalue == NULL) {
hiwire_delete_member_string(self->js, key);
FAIL_IF_MINUS_ONE(hiwire_delete_member_string(JsProxy_REF(self), key));
} else {
JsRef idvalue = python2js(pyvalue);
hiwire_set_member_string(self->js, key, idvalue);
hiwire_decref(idvalue);
idvalue = python2js(pyvalue);
FAIL_IF_MINUS_ONE(
hiwire_set_member_string(JsProxy_REF(self), key, idvalue));
}
return 0;
success = true;
finally:
hiwire_CLEAR(idvalue);
return success ? 0 : -1;
}
static PyObject*
JsProxy_Call(PyObject* o, PyObject* args, PyObject* kwargs)
JsProxy_Call(PyObject* self, PyObject* args, PyObject* kwargs)
{
JsProxy* self = (JsProxy*)o;
bool success = false;
JsRef idargs = NULL;
JsRef idarg = NULL;
JsRef idkwargs = NULL;
JsRef idresult = NULL;
// result:
PyObject* pyresult;
Py_ssize_t nargs = PyTuple_Size(args);
JsRef idargs = hiwire_array();
idargs = hiwire_array();
for (Py_ssize_t i = 0; i < nargs; ++i) {
JsRef idarg = python2js(PyTuple_GET_ITEM(args, i));
hiwire_push_array(idargs, idarg);
hiwire_decref(idarg);
idarg = python2js(PyTuple_GET_ITEM(args, i));
FAIL_IF_NULL(idarg);
FAIL_IF_MINUS_ONE(hiwire_push_array(idargs, idarg));
hiwire_CLEAR(idarg);
}
if (PyDict_Size(kwargs)) {
JsRef idkwargs = python2js(kwargs);
hiwire_push_array(idargs, idkwargs);
hiwire_decref(idkwargs);
idkwargs = python2js(kwargs);
FAIL_IF_MINUS_ONE(hiwire_push_array(idargs, idkwargs));
}
JsRef idresult = hiwire_call(self->js, idargs);
hiwire_decref(idargs);
PyObject* pyresult = js2python(idresult);
hiwire_decref(idresult);
idresult = hiwire_call(JsProxy_REF(self), idargs);
FAIL_IF_NULL(idresult);
pyresult = js2python(idresult);
FAIL_IF_NULL(pyresult);
success = true;
finally:
hiwire_CLEAR(idargs);
hiwire_CLEAR(idarg);
hiwire_CLEAR(idkwargs);
hiwire_CLEAR(idresult);
if (!success) {
Py_CLEAR(pyresult);
}
return pyresult;
}
@ -363,20 +387,6 @@ JsProxy_HasBytes(PyObject* o)
}
}
#define QUIT_IF_NULL(x) \
do { \
if (x == NULL) { \
goto finally; \
} \
} while (0)
#define QUIT_IF_NZ(x) \
do { \
if (x != 0) { \
goto finally; \
} \
} while (0)
#define GET_JSREF(x) (((JsProxy*)x)->js)
static PyObject*
@ -396,23 +406,23 @@ JsProxy_Dir(PyObject* self)
// Would have been nice if they'd supplied PyObject_GenericDir...
object__dir__ =
_PyObject_GetAttrId((PyObject*)&PyBaseObject_Type, &PyId___dir__);
QUIT_IF_NULL(object__dir__);
FAIL_IF_NULL(object__dir__);
keys = PyObject_CallFunctionObjArgs(object__dir__, self, NULL);
QUIT_IF_NULL(keys);
FAIL_IF_NULL(keys);
result_set = PySet_New(keys);
QUIT_IF_NULL(result_set);
FAIL_IF_NULL(result_set);
// Now get attributes of js object
iddir = hiwire_dir(GET_JSREF(self));
pydir = js2python(iddir);
QUIT_IF_NULL(pydir);
FAIL_IF_NULL(pydir);
// Merge and sort
QUIT_IF_NZ(_PySet_Update(result_set, pydir));
FAIL_IF_MINUS_ONE(_PySet_Update(result_set, pydir));
result = PyList_New(0);
QUIT_IF_NULL(result);
FAIL_IF_NULL(result);
null_or_pynone = _PyList_Extend((PyListObject*)result, result_set);
QUIT_IF_NULL(null_or_pynone);
QUIT_IF_NZ(PyList_Sort(result));
FAIL_IF_NULL(null_or_pynone);
FAIL_IF_MINUS_ONE(PyList_Sort(result));
success = true;
finally:
@ -689,6 +699,7 @@ JsException_AsJs(PyObject* err)
int
JsProxy_init()
{
bool success = false;
PyExc_BaseException_Type = (PyTypeObject*)PyExc_BaseException;
_Exc_JsException.tp_base = (PyTypeObject*)PyExc_Exception;
@ -697,18 +708,15 @@ JsProxy_init()
// Add JsException to the pyodide module so people can catch it if they want.
module = PyImport_ImportModule("pyodide");
if (module == NULL) {
goto fail;
}
if (PyObject_SetAttrString(module, "JsException", Exc_JsException)) {
goto fail;
}
FAIL_IF_NULL(module);
FAIL_IF_MINUS_ONE(
PyObject_SetAttrString(module, "JsException", Exc_JsException));
FAIL_IF_MINUS_ONE(PyType_Ready(&JsProxyType));
FAIL_IF_MINUS_ONE(PyType_Ready(&JsBoundMethodType));
FAIL_IF_MINUS_ONE(PyType_Ready(&_Exc_JsException));
success = true;
finally:
Py_CLEAR(module);
return (PyType_Ready(&JsProxyType) || PyType_Ready(&JsBoundMethodType) ||
PyType_Ready(&_Exc_JsException));
fail:
Py_CLEAR(module);
return -1;
return success ? 0 : -1;
}

View File

@ -60,20 +60,6 @@ EM_JS_NUM(int,
return 0;
});
#define QUIT_IF_NULL(x) \
do { \
if (x == NULL) { \
goto fail; \
} \
} while (0)
#define QUIT_IF_NZ(x) \
do { \
if (x) { \
goto fail; \
} \
} while (0)
int
runpython_init()
{
@ -83,31 +69,29 @@ runpython_init()
// borrowed
PyObject* builtins = PyImport_AddModule("builtins");
QUIT_IF_NULL(builtins);
FAIL_IF_NULL(builtins);
// borrowed
PyObject* builtins_dict = PyModule_GetDict(builtins);
QUIT_IF_NULL(builtins_dict);
FAIL_IF_NULL(builtins_dict);
// borrowed
PyObject* __main__ = PyImport_AddModule("__main__");
QUIT_IF_NULL(__main__);
FAIL_IF_NULL(__main__);
// globals is static variable, borrowed
globals = PyModule_GetDict(__main__);
QUIT_IF_NULL(globals);
FAIL_IF_NULL(globals);
Py_INCREF(globals); // to owned
QUIT_IF_NZ(PyDict_Update(globals, builtins_dict));
FAIL_IF_MINUS_ONE(PyDict_Update(globals, builtins_dict));
// pyodide_py is static variable, new
pyodide_py = PyImport_ImportModule("pyodide");
QUIT_IF_NULL(pyodide_py);
FAIL_IF_NULL(pyodide_py);
pyodide_py_proxy = python2js(pyodide_py);
if (pyodide_py_proxy == NULL) {
goto fail;
}
FAIL_IF_NULL(pyodide_py_proxy);
// Currently by default, python2js copies dicts into objects.
// We want to feed Module.globals back to `eval_code` in `pyodide.runPython`
// (see definition in pyodide.js) but because the round trip conversion
@ -118,19 +102,20 @@ runpython_init()
// modifications.
Py_INCREF(globals); // pyproxy_new steals argument
globals_proxy = pyproxy_new(globals);
if (globals_proxy == NULL) {
goto fail;
}
QUIT_IF_NZ(runpython_init_js(pyodide_py_proxy, globals_proxy));
FAIL_IF_NULL(globals_proxy);
FAIL_IF_MINUS_ONE(runpython_init_js(pyodide_py_proxy, globals_proxy));
return 0;
fail:
success = true;
finally:
hiwire_decref(pyodide_py_proxy);
hiwire_decref(globals_proxy);
if (success) {
return 0;
}
if (PyErr_Occurred()) {
PyErr_Print();
}
Py_CLEAR(pyodide_py);
Py_CLEAR(globals);
hiwire_decref(pyodide_py_proxy);
hiwire_decref(globals_proxy);
return -1;
}