| 
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