1{
2 lib,
3 stdenv,
4 buildPythonPackage,
5 pytestCheckHook,
6 tree-sitter,
7 symlinkJoin,
8 writeTextDir,
9 pythonOlder,
10 # `name`: grammar derivation pname in the format of `tree-sitter-<lang>`
11 name,
12 grammarDrv,
13}:
14let
15 inherit (grammarDrv) version;
16
17 snakeCaseName = lib.replaceStrings [ "-" ] [ "_" ] name;
18 drvPrefix = "python-${name}";
19 # If the name of the grammar attribute differs from the grammar's symbol name,
20 # it could cause a symbol mismatch at load time. This manually curated collection
21 # of overrides ensures the binding can find the correct symbol
22 langIdentOverrides = {
23 tree_sitter_org_nvim = "tree_sitter_org";
24 };
25 langIdent = langIdentOverrides.${snakeCaseName} or snakeCaseName;
26in
27buildPythonPackage {
28 inherit version;
29 pname = drvPrefix;
30
31 src = symlinkJoin {
32 name = "${drvPrefix}-source";
33 paths = [
34 (writeTextDir "${snakeCaseName}/__init__.py" ''
35 from ._binding import language
36
37 __all__ = ["language"]
38 '')
39 (writeTextDir "${snakeCaseName}/binding.c" ''
40 #include <Python.h>
41
42 typedef struct TSLanguage TSLanguage;
43
44 TSLanguage *${langIdent}(void);
45
46 static PyObject* _binding_language(PyObject *self, PyObject *args) {
47 return PyLong_FromVoidPtr(${langIdent}());
48 }
49
50 static PyMethodDef methods[] = {
51 {"language", _binding_language, METH_NOARGS,
52 "Get the tree-sitter language for this grammar."},
53 {NULL, NULL, 0, NULL}
54 };
55
56 static struct PyModuleDef module = {
57 .m_base = PyModuleDef_HEAD_INIT,
58 .m_name = "_binding",
59 .m_doc = NULL,
60 .m_size = -1,
61 .m_methods = methods
62 };
63
64 PyMODINIT_FUNC PyInit__binding(void) {
65 return PyModule_Create(&module);
66 }
67 '')
68 (writeTextDir "setup.py" ''
69 from platform import system
70 from setuptools import Extension, setup
71
72
73 setup(
74 packages=["${snakeCaseName}"],
75 ext_package="${snakeCaseName}",
76 ext_modules=[
77 Extension(
78 name="_binding",
79 sources=["${snakeCaseName}/binding.c"],
80 extra_objects = ["${grammarDrv}/parser"],
81 extra_compile_args=(
82 ["-std=c11"] if system() != 'Windows' else []
83 ),
84 )
85 ],
86 )
87 '')
88 (writeTextDir "pyproject.toml" ''
89 [build-system]
90 requires = ["setuptools", "wheel"]
91 build-backend = "setuptools.build_meta"
92
93 [project]
94 name="${snakeCaseName}"
95 description = "${langIdent} grammar for tree-sitter"
96 version = "${version}"
97 keywords = ["parsing", "incremental", "python"]
98 classifiers = [
99 "Development Status :: 4 - Beta",
100 "Intended Audience :: Developers",
101 "License :: OSI Approved :: MIT License",
102 "Topic :: Software Development :: Compilers",
103 "Topic :: Text Processing :: Linguistic",
104 ]
105
106 requires-python = ">=3.8"
107 license.text = "MIT"
108 readme = "README.md"
109
110 [project.optional-dependencies]
111 core = ["tree-sitter~=0.21"]
112
113 [tool.cibuildwheel]
114 build = "cp38-*"
115 build-frontend = "build"
116 '')
117 (writeTextDir "tests/test_language.py" ''
118 from ${snakeCaseName} import language
119 from tree_sitter import Language, Parser
120
121 # This test only checks that the binding can load the grammar from the compiled shared object.
122 # It does not verify the grammar itself; that is tested in
123 # `pkgs/development/tools/parsing/tree-sitter/grammar.nix`.
124
125 def test_language():
126 lang = Language(language())
127 assert lang is not None
128 parser = Parser()
129 parser.language = lang
130 tree = parser.parse(bytes("", "utf-8"))
131 assert tree is not None
132 '')
133 ];
134 };
135
136 preConfigure = lib.optionalString stdenv.hostPlatform.isDarwin ''
137 export DYLD_LIBRARY_PATH="${grammarDrv}"
138 '';
139
140 preCheck = ''
141 # https://github.com/NixOS/nixpkgs/issues/255262
142 rm -r ${snakeCaseName}
143 '';
144
145 disabled = pythonOlder "3.8";
146
147 nativeCheckInputs = [
148 tree-sitter
149 pytestCheckHook
150 ];
151 pythonImportsCheck = [ snakeCaseName ];
152
153 meta = {
154 description = "Python bindings for ${name}";
155 license = lib.licenses.mit;
156 maintainers = with lib.maintainers; [
157 a-jay98
158 adfaure
159 mightyiam
160 stepbrobd
161 ];
162 };
163}