diff --git a/.gitignore b/.gitignore index 81578b9..bf924c1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,13 @@ node_modules build *.log package-lock.json + +# Rust bindings Cargo.lock /target/ + +# Python Bindings +.eggs/ +*.egg-info/ +*.so +__pycache__/ diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..902ebfc --- /dev/null +++ b/Pipfile @@ -0,0 +1,13 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +pygments = "*" +tree-sitter = "*" + +[dev-packages] + +[requires] +python_version = "3.9" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..3aa0466 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,37 @@ +{ + "_meta": { + "hash": { + "sha256": "5dcb098f3196a2355e6c76e6e66b1c85aafd1c47a5ca4143a961865561a040e6" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.9" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "pygments": { + "hashes": [ + "sha256:37a13ba168a02ac54cc5891a42b1caec333e59b66addb7fa633ea8a6d73445c0", + "sha256:b21b072d0ccdf29297a82a2363359d99623597b8a265b8081760e4d0f7153c88" + ], + "index": "pypi", + "version": "==2.8.0" + }, + "tree-sitter": { + "hashes": [ + "sha256:15e7616f0e41127ca70880a40301a6ebfe58ce92db4f142eac775a38e9c38cec", + "sha256:2618b781b065d419237dcd234f7a7cd68920c4f15c6809a99ed2c2dfd6d15d01" + ], + "index": "pypi", + "version": "==0.2.2" + } + }, + "develop": {} +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/bindings/python/tree_sitter_minizinc/__init__.py b/bindings/python/tree_sitter_minizinc/__init__.py new file mode 100644 index 0000000..5fb3bf7 --- /dev/null +++ b/bindings/python/tree_sitter_minizinc/__init__.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 + +from tree_sitter import Language, Parser +from pathlib import Path + +import pkg_resources + +LANGUAGE = Language(next(Path(__file__).parent.glob("binding.*.so")), "minizinc") +HIGHLIGHT_QUERY = LANGUAGE.query( + pkg_resources.resource_string(__name__, "queries/highlights.scm") +) + + +try: + from pygments.lexer import Lexer + from pygments import token + + class TreeSitterLexer(Lexer): + ts_alias = { + "comment": token.Comment, + "type.builtin": token.Name.Builtin, + "punctuation.delimiter": token.Punctuation, + "function": token.Name.Function, + "keyword": token.Keyword, + "operator": token.Operator, + "punctuation.bracket": token.Punctuation, + "number": token.Number, + "string": token.String, + "escape": token.String.Escape, + "constant.builtin": token.Generic, + "variable": token.Name.Variable, + } + + def __init__(self, **options): + self.parser = Parser() + self.parser.set_language(self.language) + super().__init__(**options) + + def get_tokens_unprocessed(self, text): + to_bytes = bytes(text, "utf8") + tree = self.parser.parse(to_bytes) + captures = self.highlight_query.captures(tree.root_node) + + last_pos = 0 + for node, annotation in captures: + if last_pos > node.start_byte: + # Double match - only use the first capture + continue + if last_pos != node.start_byte: + yield last_pos, token.Generic, to_bytes[ + last_pos : node.start_byte + ].decode() + yield node.start_byte, self.ts_alias[annotation], to_bytes[ + node.start_byte : node.end_byte + ].decode() + last_pos = node.end_byte + + if last_pos != tree.root_node.end_byte: + yield last_pos, token.Generic, to_bytes[ + last_pos : tree.root_node.end_byte + ].decode() + + class MiniZincLexer(TreeSitterLexer): + name = "MiniZinc" + aliases = ["fzn", "dzn", "mzn", "minizinc"] + filenames = ["*.mzn", "*.fzn", "*.dzn"] + + language = LANGUAGE + highlight_query = HIGHLIGHT_QUERY + + +except ImportError: + pass diff --git a/bindings/python/tree_sitter_minizinc/queries b/bindings/python/tree_sitter_minizinc/queries new file mode 120000 index 0000000..4578310 --- /dev/null +++ b/bindings/python/tree_sitter_minizinc/queries @@ -0,0 +1 @@ +../../../queries \ No newline at end of file diff --git a/queries/highlights.scm b/queries/highlights.scm index d615e5b..46621e0 100644 --- a/queries/highlights.scm +++ b/queries/highlights.scm @@ -27,7 +27,6 @@ "enum" "function" "if" - "in" "include" "let" "maximize" diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..b939009 --- /dev/null +++ b/setup.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +from pathlib import Path +from platform import system +from setuptools import Extension, find_packages, setup + +setup( + name="tree-sitter-minizinc", + use_scm_version=True, + setup_requires=["setuptools_scm"], + python_requires=">=3.6", + author="Jip J. Dekker", + author_email="jip.dekker@monash.edu", + description="", + long_description=Path("README.md").read_text(encoding="UTF-8"), + long_description_content_type="text/markdown", + url="https://www.minizinc.org/", + project_urls={ + "Bug Tracker": "https://github.com/Dekker1/tree-sitter-minizinc/issues", + "Source": "https://github.com/Dekker1/tree-sitter-minizinc", + }, + packages=find_packages(where="bindings/python"), + package_dir={"": "bindings/python"}, + ext_modules=[ + Extension( + "tree_sitter_minizinc.binding", + ["src/parser.c"], + include_dirs=["src"], + extra_compile_args=( + ["-std=c99", "-Wno-unused-variable"] if system() != "Windows" else None + ), + ) + ], + classifiers=[ + "Development Status :: 4 - Beta", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)", + "Operating System :: OS Independent", + "Topic :: Scientific/Engineering :: Artificial Intelligence", + "Topic :: Scientific/Engineering :: Mathematics", + ], + install_requires=["tree-sitter"], + entry_points=""" + [pygments.lexers] + minizinclexer = tree_sitter_minizinc:MiniZincLexer + """, + package_data={"": ["queries/*.scm"]}, +)