|
1 | 1 | #include "types.h" |
2 | 2 |
|
| 3 | +extern void wasm_engine_delete(TSWasmEngine *engine); |
| 4 | +extern TSWasmEngine *wasmtime_engine_clone(TSWasmEngine *engine); |
| 5 | + |
3 | 6 | int language_init(Language *self, PyObject *args, PyObject *Py_UNUSED(kwargs)) { |
4 | 7 | PyObject *language; |
5 | 8 | if (!PyArg_ParseTuple(args, "O:__init__", &language)) { |
@@ -30,10 +33,119 @@ int language_init(Language *self, PyObject *args, PyObject *Py_UNUSED(kwargs)) { |
30 | 33 | } |
31 | 34 |
|
32 | 35 | void language_dealloc(Language *self) { |
| 36 | + if (self->wasm_engine != NULL) { |
| 37 | + wasm_engine_delete(self->wasm_engine); |
| 38 | + } |
33 | 39 | ts_language_delete(self->language); |
34 | 40 | Py_TYPE(self)->tp_free(self); |
35 | 41 | } |
36 | 42 |
|
| 43 | +// ctypes.cast(managed_pointer.ptr(), ctypes.c_void_p).value |
| 44 | +static void *get_managed_pointer(PyObject *cast, PyObject *c_void_p, PyObject *managed_pointer) { |
| 45 | + void *ptr = NULL; |
| 46 | + PyObject *ptr_method = NULL; |
| 47 | + PyObject *ptr_result = NULL; |
| 48 | + PyObject *cast_result = NULL; |
| 49 | + PyObject *value_attr = NULL; |
| 50 | + |
| 51 | + // Call .ptr() method on the managed pointer |
| 52 | + ptr_method = PyObject_GetAttrString(managed_pointer, "ptr"); |
| 53 | + if (ptr_method == NULL) { |
| 54 | + goto cleanup; |
| 55 | + } |
| 56 | + ptr_result = PyObject_CallObject(ptr_method, NULL); |
| 57 | + if (ptr_result == NULL) { |
| 58 | + goto cleanup; |
| 59 | + } |
| 60 | + |
| 61 | + // Call cast function |
| 62 | + cast_result = PyObject_CallFunctionObjArgs(cast, ptr_result, c_void_p, NULL); |
| 63 | + if (cast_result == NULL) { |
| 64 | + goto cleanup; |
| 65 | + } |
| 66 | + |
| 67 | + // Get the 'value' attribute from the cast result |
| 68 | + value_attr = PyObject_GetAttrString(cast_result, "value"); |
| 69 | + if (value_attr == NULL) { |
| 70 | + goto cleanup; |
| 71 | + } |
| 72 | + |
| 73 | + // Convert the value attribute to a C void pointer |
| 74 | + ptr = PyLong_AsVoidPtr(value_attr); |
| 75 | + |
| 76 | +cleanup: |
| 77 | + Py_XDECREF(value_attr); |
| 78 | + Py_XDECREF(cast_result); |
| 79 | + Py_XDECREF(ptr_result); |
| 80 | + Py_XDECREF(ptr_method); |
| 81 | + |
| 82 | + if (PyErr_Occurred()) { |
| 83 | + return NULL; |
| 84 | + } |
| 85 | + |
| 86 | + return ptr; |
| 87 | +} |
| 88 | + |
| 89 | +PyObject *language_from_wasm(PyTypeObject *cls, PyObject *args) { |
| 90 | + ModuleState *state = (ModuleState *)PyType_GetModuleState(cls); |
| 91 | + TSWasmError error; |
| 92 | + TSWasmStore *wasm_store = NULL; |
| 93 | + TSLanguage *language = NULL; |
| 94 | + Language *self = NULL; |
| 95 | + char *name; |
| 96 | + PyObject *py_engine = NULL; |
| 97 | + char *wasm; |
| 98 | + Py_ssize_t wasm_length; |
| 99 | + if (state->wasmtime_engine_type == NULL) { |
| 100 | + PyErr_SetString(PyExc_RuntimeError, "wasmtime module is not loaded"); |
| 101 | + return NULL; |
| 102 | + } |
| 103 | + if (!PyArg_ParseTuple(args, "sO!y#:from_wasm", &name, state->wasmtime_engine_type, &py_engine, &wasm, &wasm_length)) { |
| 104 | + return NULL; |
| 105 | + } |
| 106 | + |
| 107 | + TSWasmEngine *engine = (TSWasmEngine *)get_managed_pointer(state->ctypes_cast, state->c_void_p, py_engine); |
| 108 | + if (engine == NULL) { |
| 109 | + goto fail; |
| 110 | + } |
| 111 | + engine = wasmtime_engine_clone(engine); |
| 112 | + if (engine == NULL) { |
| 113 | + goto fail; |
| 114 | + } |
| 115 | + |
| 116 | + wasm_store = ts_wasm_store_new(engine, &error); |
| 117 | + if (wasm_store == NULL) { |
| 118 | + PyErr_Format(PyExc_RuntimeError, "Failed to create TSWasmStore: %s", error.message); |
| 119 | + goto fail; |
| 120 | + } |
| 121 | + |
| 122 | + language = (TSLanguage *)ts_wasm_store_load_language(wasm_store, name, wasm, wasm_length, &error); |
| 123 | + if (language == NULL) { |
| 124 | + PyErr_Format(PyExc_RuntimeError, "Failed to load language: %s", error.message); |
| 125 | + goto fail; |
| 126 | + } |
| 127 | + |
| 128 | + self = (Language *)cls->tp_alloc(cls, 0); |
| 129 | + if (self == NULL) { |
| 130 | + goto fail; |
| 131 | + } |
| 132 | + |
| 133 | + self->language = language; |
| 134 | + self->wasm_engine = engine; |
| 135 | + self->version = ts_language_version(self->language); |
| 136 | +#if HAS_LANGUAGE_NAMES |
| 137 | + self->name = ts_language_name(self->language); |
| 138 | +#endif |
| 139 | + return (PyObject *)self; |
| 140 | + |
| 141 | +fail: |
| 142 | + if (engine != NULL) { |
| 143 | + wasm_engine_delete(engine); |
| 144 | + } |
| 145 | + ts_language_delete(language); |
| 146 | + return NULL; |
| 147 | +} |
| 148 | + |
37 | 149 | PyObject *language_repr(Language *self) { |
38 | 150 | #if HAS_LANGUAGE_NAMES |
39 | 151 | if (self->name == NULL) { |
@@ -82,6 +194,10 @@ PyObject *language_get_field_count(Language *self, void *Py_UNUSED(payload)) { |
82 | 194 | return PyLong_FromUnsignedLong(ts_language_field_count(self->language)); |
83 | 195 | } |
84 | 196 |
|
| 197 | +PyObject *language_is_wasm(Language *self, void *Py_UNUSED(payload)) { |
| 198 | + return PyBool_FromLong(ts_language_is_wasm(self->language)); |
| 199 | +} |
| 200 | + |
85 | 201 | PyObject *language_node_kind_for_id(Language *self, PyObject *args) { |
86 | 202 | TSSymbol symbol; |
87 | 203 | if (!PyArg_ParseTuple(args, "H:node_kind_for_id", &symbol)) { |
@@ -190,6 +306,9 @@ PyObject *language_query(Language *self, PyObject *args) { |
190 | 306 | return PyObject_CallFunction((PyObject *)state->query_type, "Os#", self, source, length); |
191 | 307 | } |
192 | 308 |
|
| 309 | +PyDoc_STRVAR(language_from_wasm_doc, |
| 310 | + "from_wasm(self, name, engine, wasm, /)\n--\n\n" |
| 311 | + "Load a language compiled as wasm."); |
193 | 312 | PyDoc_STRVAR(language_node_kind_for_id_doc, |
194 | 313 | "node_kind_for_id(self, id, /)\n--\n\n" |
195 | 314 | "Get the name of the node kind for the given numerical id."); |
@@ -220,6 +339,12 @@ PyDoc_STRVAR( |
220 | 339 | "Create a new :class:`Query` from a string containing one or more S-expression patterns."); |
221 | 340 |
|
222 | 341 | static PyMethodDef language_methods[] = { |
| 342 | + { |
| 343 | + .ml_name = "from_wasm", |
| 344 | + .ml_meth = (PyCFunction)language_from_wasm, |
| 345 | + .ml_flags = METH_CLASS | METH_VARARGS, |
| 346 | + .ml_doc = language_from_wasm_doc, |
| 347 | + }, |
223 | 348 | { |
224 | 349 | .ml_name = "node_kind_for_id", |
225 | 350 | .ml_meth = (PyCFunction)language_node_kind_for_id, |
@@ -291,6 +416,8 @@ static PyGetSetDef language_accessors[] = { |
291 | 416 | PyDoc_STR("The number of valid states in this language."), NULL}, |
292 | 417 | {"field_count", (getter)language_get_field_count, NULL, |
293 | 418 | PyDoc_STR("The number of distinct field names in this language."), NULL}, |
| 419 | + {"is_wasm", (getter)language_is_wasm, NULL, |
| 420 | + PyDoc_STR("Check if the language came from a wasm module."), NULL}, |
294 | 421 | {NULL}, |
295 | 422 | }; |
296 | 423 |
|
|
0 commit comments