├── .editorconfig ├── .gitattributes ├── .github └── workflows │ ├── ci.yml │ ├── fuzz.yml │ └── publish.yml ├── .gitignore ├── CMakeLists.txt ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── Makefile ├── Package.resolved ├── Package.swift ├── README.md ├── binding.gyp ├── bindings ├── c │ ├── tree-sitter-haskell.h │ └── tree-sitter-haskell.pc.in ├── go │ ├── binding.go │ └── binding_test.go ├── node │ ├── binding.cc │ ├── binding_test.js │ ├── index.d.ts │ └── index.js ├── python │ ├── tests │ │ └── test_binding.py │ └── tree_sitter_haskell │ │ ├── __init__.py │ │ ├── __init__.pyi │ │ ├── binding.c │ │ └── py.typed ├── rust │ ├── build.rs │ └── lib.rs └── swift │ ├── TreeSitterHaskell │ └── haskell.h │ └── TreeSitterHaskellTests │ └── TreeSitterHaskellTests.swift ├── examples └── Basic.hs ├── go.mod ├── go.sum ├── grammar.js ├── grammar ├── class.js ├── conflicts.js ├── context.js ├── data.js ├── decl.js ├── exp.js ├── externals.js ├── general.js ├── id.js ├── inline.js ├── lexeme.js ├── literal.js ├── module.js ├── operator.js ├── pat.js ├── patsyn.js ├── precedences.js ├── th.js ├── type.js └── util.js ├── package-lock.json ├── package.json ├── pyproject.toml ├── queries ├── highlights.scm ├── injections.scm └── locals.scm ├── setup.py ├── src ├── grammar.json ├── node-types.json ├── parser.c ├── scanner.c ├── tree_sitter │ ├── alloc.h │ ├── array.h │ └── parser.h └── unicode.h ├── test └── corpus │ ├── char.txt │ ├── class.txt │ ├── comment.txt │ ├── consym.txt │ ├── context.txt │ ├── cpp.txt │ ├── data.txt │ ├── decl.txt │ ├── default.txt │ ├── exp.txt │ ├── family.txt │ ├── foreign.txt │ ├── gadt.txt │ ├── id.txt │ ├── implicit.txt │ ├── import.txt │ ├── instance.txt │ ├── layout.txt │ ├── module.txt │ ├── newtype.txt │ ├── number.txt │ ├── pat.txt │ ├── patsyn.txt │ ├── pragma.txt │ ├── prec.txt │ ├── signature.txt │ ├── special.txt │ ├── string.txt │ ├── th.txt │ ├── type.txt │ └── varsym.txt └── tree-sitter.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | 6 | [*.{json,toml,yml,gyp}] 7 | indent_style = space 8 | indent_size = 2 9 | 10 | [*.js] 11 | indent_style = space 12 | indent_size = 2 13 | 14 | [*.scm] 15 | indent_style = space 16 | indent_size = 2 17 | 18 | [*.{c,cc,h}] 19 | indent_style = space 20 | indent_size = 4 21 | 22 | [*.rs] 23 | indent_style = space 24 | indent_size = 4 25 | 26 | [*.{py,pyi}] 27 | indent_style = space 28 | indent_size = 4 29 | 30 | [*.swift] 31 | indent_style = space 32 | indent_size = 4 33 | 34 | [*.go] 35 | indent_style = tab 36 | indent_size = 8 37 | 38 | [Makefile] 39 | indent_style = tab 40 | indent_size = 8 41 | 42 | [parser.c] 43 | indent_size = 2 44 | 45 | [{alloc,array,parser}.h] 46 | indent_size = 2 47 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | # Generated source files 4 | src/*.json linguist-generated 5 | src/parser.c linguist-generated 6 | src/tree_sitter/* linguist-generated 7 | 8 | # C bindings 9 | bindings/c/* linguist-generated 10 | CMakeLists.txt linguist-generated 11 | Makefile linguist-generated 12 | 13 | # Rust bindings 14 | bindings/rust/* linguist-generated 15 | Cargo.toml linguist-generated 16 | Cargo.lock linguist-generated 17 | 18 | # Node.js bindings 19 | bindings/node/* linguist-generated 20 | binding.gyp linguist-generated 21 | package.json linguist-generated 22 | package-lock.json linguist-generated 23 | 24 | # Python bindings 25 | bindings/python/** linguist-generated 26 | setup.py linguist-generated 27 | pyproject.toml linguist-generated 28 | 29 | # Go bindings 30 | bindings/go/* linguist-generated 31 | go.mod linguist-generated 32 | go.sum linguist-generated 33 | 34 | # Swift bindings 35 | bindings/swift/** linguist-generated 36 | Package.swift linguist-generated 37 | Package.resolved linguist-generated 38 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | paths: 7 | - grammar.js 8 | - src/** 9 | - test/** 10 | - bindings/** 11 | - binding.gyp 12 | pull_request: 13 | paths: 14 | - grammar.js 15 | - src/** 16 | - test/** 17 | - bindings/** 18 | - binding.gyp 19 | 20 | concurrency: 21 | group: ${{github.workflow}}-${{github.ref}} 22 | cancel-in-progress: true 23 | 24 | jobs: 25 | test: 26 | name: Test parser 27 | runs-on: ${{matrix.os}} 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | os: [ubuntu-latest, windows-latest, macos-14] 32 | steps: 33 | - name: Checkout repository 34 | uses: actions/checkout@v4 35 | - name: Set up tree-sitter 36 | uses: tree-sitter/setup-action/cli@v1 37 | - name: Set up examples 38 | run: |- 39 | git clone https://github.com/joshvera/effects examples/effects --single-branch --depth=1 --filter=blob:none 40 | git clone https://github.com/PostgRest/postgrest examples/postgrest --single-branch --depth=1 --filter=blob:none 41 | git clone https://github.com/GaloisInc/ivory examples/ivory --single-branch --depth=1 --filter=blob:none 42 | git clone https://github.com/polysemy-research/polysemy examples/polysemy --single-branch --depth=1 --filter=blob:none 43 | git clone https://github.com/github/semantic examples/semantic --single-branch --depth=1 --filter=blob:none 44 | git clone https://github.com/haskell/haskell-language-server examples/haskell-language-server --single-branch --depth=1 --filter=blob:none 45 | git clone https://github.com/AndrasKovacs/flatparse examples/flatparse --single-branch --depth=1 --filter=blob:none 46 | git clone https://github.com/ekmett/lens examples/lens --single-branch --depth=1 --filter=blob:none 47 | git clone https://github.com/tek/tsh-test-ghc examples/tsh-test-ghc --single-branch --depth=1 --filter=blob:none 48 | - name: Run tests 49 | uses: tree-sitter/parser-test-action@v2 50 | with: 51 | test-rust: ${{runner.os == 'Linux'}} 52 | - name: Parse examples 53 | id: examples 54 | uses: tree-sitter/parse-action@v4 55 | with: 56 | files: | 57 | examples/*.hs 58 | !exampels/haskell-language-server/test/functional/Symbol.hs 59 | !examples/lens/tests/properties.hs 60 | !examples/semantic/semantic/test/fixtures/haskell/corpus/function-declarations.A.hs 61 | !examples/semantic/semantic/test/fixtures/haskell/corpus/function-declarations.B.hs 62 | !examples/semantic/semantic/test/fixtures/haskell/corpus/tempate-haskell.A.hs 63 | !examples/semantic/semantic/test/fixtures/haskell/corpus/template-haskell.B.hs 64 | !examples/semantic/semantic/test/fixtures/haskell/corpus/algebraic-datatype-declarations.A.hs 65 | !examples/semantic/semantic/test/fixtures/haskell/corpus/algebraic-datatype-declarations.B.hs 66 | !examples/semantic/semantic/test/fixtures/haskell/corpus/newtype-declaration.A.hs 67 | !examples/semantic/semantic/test/fixtures/haskell/corpus/newtype-declaration.B.hs 68 | !examples/semantic/semantic/test/fixtures/haskell/corpus/type-synonyms.A.hs 69 | !examples/semantic/semantic/test/fixtures/haskell/corpus/type-synonyms.B.hs 70 | !examples/polysemy/src/Polysemy/Law.hs 71 | !examples/tsh-test-ghc/compiler/GHC/Builtin/PrimOps.hs 72 | invalid-files: | 73 | !examples/haskell-language-server/test/testdata/FuncTestFail.hs 74 | -------------------------------------------------------------------------------- /.github/workflows/fuzz.yml: -------------------------------------------------------------------------------- 1 | name: Fuzz Parser 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | paths: 7 | - src/scanner.c 8 | pull_request: 9 | paths: 10 | - src/scanner.c 11 | 12 | jobs: 13 | fuzz: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v4 18 | - name: Run fuzzer 19 | uses: tree-sitter/fuzz-action@v4 20 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish packages 2 | 3 | on: 4 | push: 5 | tags: ["*"] 6 | 7 | permissions: 8 | contents: write 9 | id-token: write 10 | attestations: write 11 | 12 | jobs: 13 | github: 14 | uses: tree-sitter/workflows/.github/workflows/release.yml@main 15 | with: 16 | generate: true 17 | attestations: true 18 | npm: 19 | uses: tree-sitter/workflows/.github/workflows/package-npm.yml@main 20 | secrets: 21 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} 22 | with: 23 | generate: true 24 | crates: 25 | uses: tree-sitter/workflows/.github/workflows/package-crates.yml@main 26 | secrets: 27 | CARGO_REGISTRY_TOKEN: ${{secrets.CARGO_REGISTRY_TOKEN}} 28 | with: 29 | generate: true 30 | pypi: 31 | uses: tree-sitter/workflows/.github/workflows/package-pypi.yml@main 32 | secrets: 33 | PYPI_API_TOKEN: ${{secrets.PYPI_API_TOKEN}} 34 | with: 35 | generate: true 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Rust artifacts 2 | target/ 3 | 4 | # Node artifacts 5 | build/ 6 | prebuilds/ 7 | node_modules/ 8 | 9 | # Swift artifacts 10 | .build/ 11 | 12 | # Go artifacts 13 | _obj/ 14 | 15 | # Python artifacts 16 | .venv/ 17 | dist/ 18 | *.egg-info 19 | *.whl 20 | 21 | # C artifacts 22 | *.a 23 | *.so 24 | *.so.* 25 | *.dylib 26 | *.dll 27 | *.pc 28 | 29 | # Example dirs 30 | /examples/*/ 31 | 32 | # Grammar volatiles 33 | *.wasm 34 | *.obj 35 | *.o 36 | 37 | # Archives 38 | *.tar.gz 39 | *.tgz 40 | *.zip 41 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | project(tree-sitter-haskell 4 | VERSION "0.23.1" 5 | DESCRIPTION "Haskell grammar for tree-sitter" 6 | HOMEPAGE_URL "https://github.com/tree-sitter/tree-sitter-haskell" 7 | LANGUAGES C) 8 | 9 | option(BUILD_SHARED_LIBS "Build using shared libraries" ON) 10 | option(TREE_SITTER_REUSE_ALLOCATOR "Reuse the library allocator" OFF) 11 | 12 | set(TREE_SITTER_ABI_VERSION 14 CACHE STRING "Tree-sitter ABI version") 13 | if(NOT ${TREE_SITTER_ABI_VERSION} MATCHES "^[0-9]+$") 14 | unset(TREE_SITTER_ABI_VERSION CACHE) 15 | message(FATAL_ERROR "TREE_SITTER_ABI_VERSION must be an integer") 16 | endif() 17 | 18 | find_program(TREE_SITTER_CLI tree-sitter DOC "Tree-sitter CLI") 19 | 20 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/parser.c" 21 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/grammar.json" 22 | COMMAND "${TREE_SITTER_CLI}" generate src/grammar.json 23 | --abi=${TREE_SITTER_ABI_VERSION} 24 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 25 | COMMENT "Generating parser.c") 26 | 27 | add_library(tree-sitter-haskell src/parser.c) 28 | if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/scanner.c) 29 | target_sources(tree-sitter-haskell PRIVATE src/scanner.c) 30 | endif() 31 | target_include_directories(tree-sitter-haskell PRIVATE src) 32 | 33 | target_compile_definitions(tree-sitter-haskell PRIVATE 34 | $<$:TREE_SITTER_REUSE_ALLOCATOR> 35 | $<$:TREE_SITTER_DEBUG>) 36 | 37 | set_target_properties(tree-sitter-haskell 38 | PROPERTIES 39 | C_STANDARD 11 40 | POSITION_INDEPENDENT_CODE ON 41 | SOVERSION "${TREE_SITTER_ABI_VERSION}.${PROJECT_VERSION_MAJOR}" 42 | DEFINE_SYMBOL "") 43 | 44 | configure_file(bindings/c/tree-sitter-haskell.pc.in 45 | "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-haskell.pc" @ONLY) 46 | 47 | include(GNUInstallDirs) 48 | 49 | install(FILES bindings/c/tree-sitter-haskell.h 50 | DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/tree_sitter") 51 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-haskell.pc" 52 | DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig") 53 | install(TARGETS tree-sitter-haskell 54 | LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}") 55 | 56 | add_custom_target(ts-test "${TREE_SITTER_CLI}" test 57 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 58 | COMMENT "tree-sitter test") 59 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "1.1.3" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "cc" 16 | version = "1.1.37" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "40545c26d092346d8a8dab71ee48e7685a7a9cba76e634790c215b41a4a7b4cf" 19 | dependencies = [ 20 | "shlex", 21 | ] 22 | 23 | [[package]] 24 | name = "memchr" 25 | version = "2.7.4" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 28 | 29 | [[package]] 30 | name = "regex" 31 | version = "1.11.1" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 34 | dependencies = [ 35 | "aho-corasick", 36 | "memchr", 37 | "regex-automata", 38 | "regex-syntax", 39 | ] 40 | 41 | [[package]] 42 | name = "regex-automata" 43 | version = "0.4.8" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" 46 | dependencies = [ 47 | "aho-corasick", 48 | "memchr", 49 | "regex-syntax", 50 | ] 51 | 52 | [[package]] 53 | name = "regex-syntax" 54 | version = "0.8.5" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 57 | 58 | [[package]] 59 | name = "shlex" 60 | version = "1.3.0" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 63 | 64 | [[package]] 65 | name = "tree-sitter" 66 | version = "0.23.2" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "0203df02a3b6dd63575cc1d6e609edc2181c9a11867a271b25cfd2abff3ec5ca" 69 | dependencies = [ 70 | "cc", 71 | "regex", 72 | "regex-syntax", 73 | "tree-sitter-language", 74 | ] 75 | 76 | [[package]] 77 | name = "tree-sitter-haskell" 78 | version = "0.23.1" 79 | dependencies = [ 80 | "cc", 81 | "tree-sitter", 82 | "tree-sitter-language", 83 | ] 84 | 85 | [[package]] 86 | name = "tree-sitter-language" 87 | version = "0.1.2" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | checksum = "e8ddffe35a0e5eeeadf13ff7350af564c6e73993a24db62caee1822b185c2600" 90 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tree-sitter-haskell" 3 | description = "Haskell grammar for tree-sitter" 4 | version = "0.23.1" 5 | authors = ["Max Brunsfeld "] 6 | license = "MIT" 7 | readme = "README.md" 8 | keywords = ["incremental", "parsing", "tree-sitter", "haskell"] 9 | categories = ["parsing", "text-editors"] 10 | repository = "https://github.com/tree-sitter/tree-sitter-haskell" 11 | edition = "2021" 12 | autoexamples = false 13 | 14 | build = "bindings/rust/build.rs" 15 | include = ["LICENSE", "bindings/rust/*", "grammar.js", "queries/*", "src/*", "tree-sitter.json"] 16 | 17 | [lib] 18 | path = "bindings/rust/lib.rs" 19 | 20 | [dependencies] 21 | tree-sitter-language = "0.1" 22 | 23 | [build-dependencies] 24 | cc = "1.1.15" 25 | 26 | [dev-dependencies] 27 | tree-sitter = "0.23" 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Max Brunsfeld 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(OS),Windows_NT) 2 | $(error Windows is not supported) 3 | endif 4 | 5 | LANGUAGE_NAME := tree-sitter-haskell 6 | HOMEPAGE_URL := https://github.com/tree-sitter/tree-sitter-haskell 7 | VERSION := 0.23.1 8 | 9 | # repository 10 | SRC_DIR := src 11 | 12 | TS ?= tree-sitter 13 | 14 | # install directory layout 15 | PREFIX ?= /usr/local 16 | INCLUDEDIR ?= $(PREFIX)/include 17 | LIBDIR ?= $(PREFIX)/lib 18 | PCLIBDIR ?= $(LIBDIR)/pkgconfig 19 | 20 | # source/object files 21 | PARSER := $(SRC_DIR)/parser.c 22 | EXTRAS := $(filter-out $(PARSER),$(wildcard $(SRC_DIR)/*.c)) 23 | OBJS := $(patsubst %.c,%.o,$(PARSER) $(EXTRAS)) 24 | 25 | # flags 26 | ARFLAGS ?= rcs 27 | override CFLAGS += -I$(SRC_DIR) -std=c11 -fPIC 28 | 29 | # ABI versioning 30 | SONAME_MAJOR = $(shell sed -n 's/\#define LANGUAGE_VERSION //p' $(PARSER)) 31 | SONAME_MINOR = $(word 1,$(subst ., ,$(VERSION))) 32 | 33 | # OS-specific bits 34 | ifeq ($(shell uname),Darwin) 35 | SOEXT = dylib 36 | SOEXTVER_MAJOR = $(SONAME_MAJOR).$(SOEXT) 37 | SOEXTVER = $(SONAME_MAJOR).$(SONAME_MINOR).$(SOEXT) 38 | LINKSHARED = -dynamiclib -Wl,-install_name,$(LIBDIR)/lib$(LANGUAGE_NAME).$(SOEXTVER),-rpath,@executable_path/../Frameworks 39 | else 40 | SOEXT = so 41 | SOEXTVER_MAJOR = $(SOEXT).$(SONAME_MAJOR) 42 | SOEXTVER = $(SOEXT).$(SONAME_MAJOR).$(SONAME_MINOR) 43 | LINKSHARED = -shared -Wl,-soname,lib$(LANGUAGE_NAME).$(SOEXTVER) 44 | endif 45 | ifneq ($(filter $(shell uname),FreeBSD NetBSD DragonFly),) 46 | PCLIBDIR := $(PREFIX)/libdata/pkgconfig 47 | endif 48 | 49 | all: lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT) $(LANGUAGE_NAME).pc 50 | 51 | lib$(LANGUAGE_NAME).a: $(OBJS) 52 | $(AR) $(ARFLAGS) $@ $^ 53 | 54 | lib$(LANGUAGE_NAME).$(SOEXT): $(OBJS) 55 | $(CC) $(LDFLAGS) $(LINKSHARED) $^ $(LDLIBS) -o $@ 56 | ifneq ($(STRIP),) 57 | $(STRIP) $@ 58 | endif 59 | 60 | $(LANGUAGE_NAME).pc: bindings/c/$(LANGUAGE_NAME).pc.in 61 | sed -e 's|@PROJECT_VERSION@|$(VERSION)|' \ 62 | -e 's|@CMAKE_INSTALL_LIBDIR@|$(LIBDIR:$(PREFIX)/%=%)|' \ 63 | -e 's|@CMAKE_INSTALL_INCLUDEDIR@|$(INCLUDEDIR:$(PREFIX)/%=%)|' \ 64 | -e 's|@PROJECT_DESCRIPTION@|$(DESCRIPTION)|' \ 65 | -e 's|@PROJECT_HOMEPAGE_URL@|$(HOMEPAGE_URL)|' \ 66 | -e 's|@CMAKE_INSTALL_PREFIX@|$(PREFIX)|' $< > $@ 67 | 68 | $(PARSER): $(SRC_DIR)/grammar.json 69 | $(TS) generate $^ 70 | 71 | install: all 72 | install -d '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter '$(DESTDIR)$(PCLIBDIR)' '$(DESTDIR)$(LIBDIR)' 73 | install -m644 bindings/c/$(LANGUAGE_NAME).h '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h 74 | install -m644 $(LANGUAGE_NAME).pc '$(DESTDIR)$(PCLIBDIR)'/$(LANGUAGE_NAME).pc 75 | install -m644 lib$(LANGUAGE_NAME).a '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).a 76 | install -m755 lib$(LANGUAGE_NAME).$(SOEXT) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER) 77 | ln -sf lib$(LANGUAGE_NAME).$(SOEXTVER) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) 78 | ln -sf lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXT) 79 | 80 | uninstall: 81 | $(RM) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).a \ 82 | '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER) \ 83 | '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) \ 84 | '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXT) \ 85 | '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h \ 86 | '$(DESTDIR)$(PCLIBDIR)'/$(LANGUAGE_NAME).pc 87 | 88 | clean: 89 | $(RM) $(OBJS) $(LANGUAGE_NAME).pc lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT) 90 | 91 | test: 92 | $(TS) test 93 | 94 | .PHONY: all install uninstall clean test 95 | -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "SwiftTreeSitter", 6 | "repositoryURL": "https://github.com/ChimeHQ/SwiftTreeSitter", 7 | "state": { 8 | "branch": null, 9 | "revision": "2599e95310b3159641469d8a21baf2d3d200e61f", 10 | "version": "0.8.0" 11 | } 12 | } 13 | ] 14 | }, 15 | "version": 1 16 | } 17 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "TreeSitterHaskell", 6 | products: [ 7 | .library(name: "TreeSitterHaskell", targets: ["TreeSitterHaskell"]), 8 | ], 9 | dependencies: [ 10 | .package(url: "https://github.com/ChimeHQ/SwiftTreeSitter", from: "0.8.0"), 11 | ], 12 | targets: [ 13 | .target( 14 | name: "TreeSitterHaskell", 15 | dependencies: [], 16 | path: ".", 17 | sources: [ 18 | "src/parser.c", 19 | "src/scanner.c", 20 | ], 21 | resources: [ 22 | .copy("queries") 23 | ], 24 | publicHeadersPath: "bindings/swift", 25 | cSettings: [.headerSearchPath("src")] 26 | ), 27 | .testTarget( 28 | name: "TreeSitterHaskellTests", 29 | dependencies: [ 30 | "SwiftTreeSitter", 31 | "TreeSitterHaskell", 32 | ], 33 | path: "bindings/swift/TreeSitterHaskellTests" 34 | ) 35 | ], 36 | cLanguageStandard: .c11 37 | ) 38 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "tree_sitter_haskell_binding", 5 | "dependencies": [ 6 | " 2 | 3 | typedef struct TSLanguage TSLanguage; 4 | 5 | extern "C" TSLanguage *tree_sitter_haskell(); 6 | 7 | // "tree-sitter", "language" hashed with BLAKE2 8 | const napi_type_tag LANGUAGE_TYPE_TAG = { 9 | 0x8AF2E5212AD58ABF, 0xD5006CAD83ABBA16 10 | }; 11 | 12 | Napi::Object Init(Napi::Env env, Napi::Object exports) { 13 | exports["name"] = Napi::String::New(env, "haskell"); 14 | auto language = Napi::External::New(env, tree_sitter_haskell()); 15 | language.TypeTag(&LANGUAGE_TYPE_TAG); 16 | exports["language"] = language; 17 | return exports; 18 | } 19 | 20 | NODE_API_MODULE(tree_sitter_haskell_binding, Init) 21 | -------------------------------------------------------------------------------- /bindings/node/binding_test.js: -------------------------------------------------------------------------------- 1 | const assert = require("node:assert"); 2 | const { test } = require("node:test"); 3 | 4 | const Parser = require("tree-sitter"); 5 | 6 | test("can load grammar", () => { 7 | const parser = new Parser(); 8 | assert.doesNotThrow(() => parser.setLanguage(require("."))); 9 | }); 10 | -------------------------------------------------------------------------------- /bindings/node/index.d.ts: -------------------------------------------------------------------------------- 1 | type BaseNode = { 2 | type: string; 3 | named: boolean; 4 | }; 5 | 6 | type ChildNode = { 7 | multiple: boolean; 8 | required: boolean; 9 | types: BaseNode[]; 10 | }; 11 | 12 | type NodeInfo = 13 | | (BaseNode & { 14 | subtypes: BaseNode[]; 15 | }) 16 | | (BaseNode & { 17 | fields: { [name: string]: ChildNode }; 18 | children: ChildNode[]; 19 | }); 20 | 21 | type Language = { 22 | name: string; 23 | language: unknown; 24 | nodeTypeInfo: NodeInfo[]; 25 | }; 26 | 27 | declare const language: Language; 28 | export = language; 29 | -------------------------------------------------------------------------------- /bindings/node/index.js: -------------------------------------------------------------------------------- 1 | const root = require("path").join(__dirname, "..", ".."); 2 | 3 | module.exports = 4 | typeof process.versions.bun === "string" 5 | // Support `bun build --compile` by being statically analyzable enough to find the .node file at build-time 6 | ? require(`../../prebuilds/${process.platform}-${process.arch}/tree-sitter-haskell.node`) 7 | : require("node-gyp-build")(root); 8 | 9 | try { 10 | module.exports.nodeTypeInfo = require("../../src/node-types.json"); 11 | } catch (_) {} 12 | -------------------------------------------------------------------------------- /bindings/python/tests/test_binding.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | import tree_sitter, tree_sitter_haskell 4 | 5 | 6 | class TestLanguage(TestCase): 7 | def test_can_load_grammar(self): 8 | try: 9 | tree_sitter.Language(tree_sitter_haskell.language()) 10 | except Exception: 11 | self.fail("Error loading Haskell grammar") 12 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_haskell/__init__.py: -------------------------------------------------------------------------------- 1 | """Haskell grammar for tree-sitter""" 2 | 3 | from importlib.resources import files as _files 4 | 5 | from ._binding import language 6 | 7 | 8 | def _get_query(name, file): 9 | query = _files(f"{__package__}.queries") / file 10 | globals()[name] = query.read_text() 11 | return globals()[name] 12 | 13 | 14 | def __getattr__(name): 15 | if name == "HIGHLIGHTS_QUERY": 16 | return _get_query("HIGHLIGHTS_QUERY", "highlights.scm") 17 | if name == "INJECTIONS_QUERY": 18 | return _get_query("INJECTIONS_QUERY", "injections.scm") 19 | if name == "LOCALS_QUERY": 20 | return _get_query("LOCALS_QUERY", "locals.scm") 21 | 22 | raise AttributeError(f"module {__name__!r} has no attribute {name!r}") 23 | 24 | 25 | __all__ = [ 26 | "language", 27 | "HIGHLIGHTS_QUERY", 28 | "INJECTIONS_QUERY", 29 | "LOCALS_QUERY", 30 | ] 31 | 32 | 33 | def __dir__(): 34 | return sorted(__all__ + [ 35 | "__all__", "__builtins__", "__cached__", "__doc__", "__file__", 36 | "__loader__", "__name__", "__package__", "__path__", "__spec__", 37 | ]) 38 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_haskell/__init__.pyi: -------------------------------------------------------------------------------- 1 | from typing import Final 2 | 3 | HIGHLIGHTS_QUERY: Final[str] 4 | INJECTIONS_QUERY: Final[str] 5 | LOCALS_QUERY: Final[str] 6 | 7 | def language() -> object: ... 8 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_haskell/binding.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef struct TSLanguage TSLanguage; 4 | 5 | TSLanguage *tree_sitter_haskell(void); 6 | 7 | static PyObject* _binding_language(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) { 8 | return PyCapsule_New(tree_sitter_haskell(), "tree_sitter.Language", NULL); 9 | } 10 | 11 | static PyMethodDef methods[] = { 12 | {"language", _binding_language, METH_NOARGS, 13 | "Get the tree-sitter language for this grammar."}, 14 | {NULL, NULL, 0, NULL} 15 | }; 16 | 17 | static struct PyModuleDef module = { 18 | .m_base = PyModuleDef_HEAD_INIT, 19 | .m_name = "_binding", 20 | .m_doc = NULL, 21 | .m_size = -1, 22 | .m_methods = methods 23 | }; 24 | 25 | PyMODINIT_FUNC PyInit__binding(void) { 26 | return PyModule_Create(&module); 27 | } 28 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_haskell/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tree-sitter/tree-sitter-haskell/0975ef72fc3c47b530309ca93937d7d143523628/bindings/python/tree_sitter_haskell/py.typed -------------------------------------------------------------------------------- /bindings/rust/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let src_dir = std::path::Path::new("src"); 3 | 4 | let mut c_config = cc::Build::new(); 5 | c_config 6 | .std("c11") 7 | .include(src_dir) 8 | .flag_if_supported("-Wno-unused-value"); 9 | 10 | #[cfg(target_env = "msvc")] 11 | c_config.flag("-utf-8"); 12 | 13 | let parser_path = src_dir.join("parser.c"); 14 | c_config.file(&parser_path); 15 | println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap()); 16 | 17 | let scanner_path = src_dir.join("scanner.c"); 18 | c_config.file(&scanner_path); 19 | println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); 20 | 21 | c_config.compile("tree-sitter-haskell"); 22 | } 23 | -------------------------------------------------------------------------------- /bindings/rust/lib.rs: -------------------------------------------------------------------------------- 1 | //! This crate provides Haskell language support for the [tree-sitter][] parsing library. 2 | //! 3 | //! Typically, you will use the [language][language func] function to add this language to a 4 | //! tree-sitter [Parser][], and then use the parser to parse some code: 5 | //! 6 | //! ``` 7 | //! use tree_sitter::Parser; 8 | //! 9 | //! let code = r#" 10 | //! main = putStrLn "Hello World!" 11 | //! "#; 12 | //! let mut parser = Parser::new(); 13 | //! let language = tree_sitter_haskell::LANGUAGE; 14 | //! parser 15 | //! .set_language(&language.into()) 16 | //! .expect("Error loading Haskell parser"); 17 | //! let tree = parser.parse(code, None).unwrap(); 18 | //! assert!(!tree.root_node().has_error()); 19 | //! ``` 20 | //! 21 | //! [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html 22 | //! [language func]: fn.language.html 23 | //! [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html 24 | //! [tree-sitter]: https://tree-sitter.github.io/ 25 | 26 | use tree_sitter_language::LanguageFn; 27 | 28 | extern "C" { 29 | fn tree_sitter_haskell() -> *const (); 30 | } 31 | 32 | /// The tree-sitter [`LanguageFn`] for this grammar. 33 | pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_haskell) }; 34 | 35 | /// The content of the [`node-types.json`][] file for this grammar. 36 | /// 37 | /// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types 38 | pub const NODE_TYPES: &str = include_str!("../../src/node-types.json"); 39 | 40 | /// The syntax highlighting query for this language. 41 | pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm"); 42 | 43 | /// The syntax highlighting query for languages injected into this one. 44 | pub const INJECTIONS_QUERY: &str = include_str!("../../queries/injections.scm"); 45 | 46 | /// The local-variable syntax highlighting query for this language. 47 | pub const LOCALS_QUERY: &str = include_str!("../../queries/locals.scm"); 48 | 49 | #[cfg(test)] 50 | mod tests { 51 | #[test] 52 | fn test_can_load_grammar() { 53 | let mut parser = tree_sitter::Parser::new(); 54 | parser 55 | .set_language(&super::LANGUAGE.into()) 56 | .expect("Error loading Haskell parser"); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /bindings/swift/TreeSitterHaskell/haskell.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_HASKELL_H_ 2 | #define TREE_SITTER_HASKELL_H_ 3 | 4 | typedef struct TSLanguage TSLanguage; 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | const TSLanguage *tree_sitter_haskell(void); 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif 15 | 16 | #endif // TREE_SITTER_HASKELL_H_ 17 | -------------------------------------------------------------------------------- /bindings/swift/TreeSitterHaskellTests/TreeSitterHaskellTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import SwiftTreeSitter 3 | import TreeSitterHaskell 4 | 5 | final class TreeSitterHaskellTests: XCTestCase { 6 | func testCanLoadGrammar() throws { 7 | let parser = Parser() 8 | let language = Language(language: tree_sitter_haskell()) 9 | XCTAssertNoThrow(try parser.setLanguage(language), 10 | "Error loading Haskell grammar") 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/Basic.hs: -------------------------------------------------------------------------------- 1 | a = 1 2 | b = 2 3 | c = 3 4 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/tree-sitter/tree-sitter-haskell 2 | 3 | go 1.22 4 | 5 | require github.com/tree-sitter/go-tree-sitter v0.24.0 6 | 7 | require github.com/mattn/go-pointer v0.0.1 // indirect 8 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0= 4 | github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= 5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 7 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= 8 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 9 | github.com/tree-sitter/go-tree-sitter v0.24.0 h1:kRZb6aBNfcI/u0Qh8XEt3zjNVnmxTisDBN+kXK0xRYQ= 10 | github.com/tree-sitter/go-tree-sitter v0.24.0/go.mod h1:x681iFVoLMEwOSIHA1chaLkXlroXEN7WY+VHGFaoDbk= 11 | github.com/tree-sitter/tree-sitter-c v0.21.5-0.20240818205408-927da1f210eb h1:A8425heRM8mylnv4H58FPUiH+aYivyitre0PzxrfmWs= 12 | github.com/tree-sitter/tree-sitter-c v0.21.5-0.20240818205408-927da1f210eb/go.mod h1:dOF6gtQiF9UwNh995T5OphYmtIypkjsp3ap7r9AN/iA= 13 | github.com/tree-sitter/tree-sitter-cpp v0.22.4-0.20240818224355-b1a4e2b25148 h1:AfFPZwtwGN01BW1jDdqBVqscTwetvMpydqYZz57RSlc= 14 | github.com/tree-sitter/tree-sitter-cpp v0.22.4-0.20240818224355-b1a4e2b25148/go.mod h1:Bh6U3viD57rFXRYIQ+kmiYtr+1Bx0AceypDLJJSyi9s= 15 | github.com/tree-sitter/tree-sitter-embedded-template v0.21.1-0.20240819044651-ffbf64942c33 h1:TwqSV3qLp3tKSqirGLRHnjFk9Tc2oy57LIl+FQ4GjI4= 16 | github.com/tree-sitter/tree-sitter-embedded-template v0.21.1-0.20240819044651-ffbf64942c33/go.mod h1:CvCKCt3v04Ufos1zZnNCelBDeCGRpPucaN8QczoUsN4= 17 | github.com/tree-sitter/tree-sitter-go v0.21.3-0.20240818010209-8c0f0e7a6012 h1:Xvxck3tE5FW7F7bTS97iNM2ADMyCMJztVqn5HYKdJGo= 18 | github.com/tree-sitter/tree-sitter-go v0.21.3-0.20240818010209-8c0f0e7a6012/go.mod h1:T40D0O1cPvUU/+AmiXVXy1cncYQT6wem4Z0g4SfAYvY= 19 | github.com/tree-sitter/tree-sitter-html v0.20.5-0.20240818004741-d11201a263d0 h1:c46K6uh5Dz00zJeU9BfjXdb8I+E4RkUdfnWJpQADXFo= 20 | github.com/tree-sitter/tree-sitter-html v0.20.5-0.20240818004741-d11201a263d0/go.mod h1:hcNt/kOJHcIcuMvouE7LJcYdeFUFbVpBJ6d4wmOA+tU= 21 | github.com/tree-sitter/tree-sitter-java v0.21.1-0.20240824015150-576d8097e495 h1:jrt4qbJVEFs4H93/ITxygHc6u0TGqAkkate7TQ4wFSA= 22 | github.com/tree-sitter/tree-sitter-java v0.21.1-0.20240824015150-576d8097e495/go.mod h1:oyaR7fLnRV0hT9z6qwE9GkaeTom/hTDwK3H2idcOJFc= 23 | github.com/tree-sitter/tree-sitter-javascript v0.21.5-0.20240818005344-15887341e5b5 h1:om4X9AVg3asL8gxNJDcz4e/Wp+VpQj1PY3uJXKr6EOg= 24 | github.com/tree-sitter/tree-sitter-javascript v0.21.5-0.20240818005344-15887341e5b5/go.mod h1:nNqgPoV/h9uYWk6kYEFdEAhNVOacpfpRW5SFmdaP4tU= 25 | github.com/tree-sitter/tree-sitter-json v0.21.1-0.20240818005659-bdd69eb8c8a5 h1:pfV3G3k7NCKqKk8THBmyuh2zA33lgYHS3GVrzRR8ry4= 26 | github.com/tree-sitter/tree-sitter-json v0.21.1-0.20240818005659-bdd69eb8c8a5/go.mod h1:GbMKRjLfk0H+PI7nLi1Sx5lHf5wCpLz9al8tQYSxpEk= 27 | github.com/tree-sitter/tree-sitter-php v0.22.9-0.20240819002312-a552625b56c1 h1:ZXZMDwE+IhUtGug4Brv6NjJWUU3rfkZBKpemf6RY8/g= 28 | github.com/tree-sitter/tree-sitter-php v0.22.9-0.20240819002312-a552625b56c1/go.mod h1:UKCLuYnJ312Mei+3cyTmGOHzn0YAnaPRECgJmHtzrqs= 29 | github.com/tree-sitter/tree-sitter-python v0.21.1-0.20240818005537-55a9b8a4fbfb h1:EXEM82lFM7JjJb6qiKZXkpIDaCcbV2obNn82ghwj9lw= 30 | github.com/tree-sitter/tree-sitter-python v0.21.1-0.20240818005537-55a9b8a4fbfb/go.mod h1:lXCF1nGG5Dr4J3BTS0ObN4xJCCICiSu/b+Xe/VqMV7g= 31 | github.com/tree-sitter/tree-sitter-ruby v0.21.1-0.20240818211811-7dbc1e2d0e2d h1:fcYCvoXdcP1uRQYXqJHRy6Hec+uKScQdKVtMwK9JeCI= 32 | github.com/tree-sitter/tree-sitter-ruby v0.21.1-0.20240818211811-7dbc1e2d0e2d/go.mod h1:T1nShQ4v5AJtozZ8YyAS4uzUtDAJj/iv4YfwXSbUHzg= 33 | github.com/tree-sitter/tree-sitter-rust v0.21.3-0.20240818005432-2b43eafe6447 h1:o9alBu1J/WjrcTKEthYtXmdkDc5OVXD+PqlvnEZ0Lzc= 34 | github.com/tree-sitter/tree-sitter-rust v0.21.3-0.20240818005432-2b43eafe6447/go.mod h1:1Oh95COkkTn6Ezp0vcMbvfhRP5gLeqqljR0BYnBzWvc= 35 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 36 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 37 | -------------------------------------------------------------------------------- /grammar.js: -------------------------------------------------------------------------------- 1 | const 2 | class_ = require('./grammar/class.js'), 3 | conflicts = require('./grammar/conflicts.js'), 4 | context = require('./grammar/context.js'), 5 | data = require('./grammar/data.js'), 6 | decl = require('./grammar/decl.js'), 7 | exp = require('./grammar/exp.js'), 8 | externals = require('./grammar/externals.js'), 9 | general = require('./grammar/general.js'), 10 | id = require('./grammar/id.js'), 11 | inline = require('./grammar/inline.js'), 12 | lexeme = require('./grammar/lexeme.js'), 13 | literal = require('./grammar/literal.js'), 14 | module_ = require('./grammar/module.js'), 15 | operator = require('./grammar/operator.js'), 16 | pat = require('./grammar/pat.js'), 17 | patsyn = require('./grammar/patsyn.js'), 18 | precedences = require('./grammar/precedences.js'), 19 | th = require('./grammar/th.js'), 20 | type = require('./grammar/type.js') 21 | 22 | module.exports = grammar({ 23 | name: 'haskell', 24 | 25 | rules: { 26 | haskell: $ => seq( 27 | optional($.header), 28 | optional($._body), 29 | ), 30 | 31 | ...general, 32 | ...type, 33 | ...context, 34 | ...exp, 35 | ...pat, 36 | ...module_, 37 | ...data, 38 | ...class_, 39 | ...decl, 40 | ...patsyn, 41 | ...th, 42 | ...literal, 43 | ...id, 44 | ...operator, 45 | ...lexeme, 46 | 47 | }, 48 | 49 | ...externals, 50 | ...precedences, 51 | ...inline, 52 | ...conflicts, 53 | 54 | /** 55 | * These rules may occur anywhere in the grammar and don't have to be specified in productions. 56 | */ 57 | extras: $ => [ 58 | /\p{Zs}/, 59 | /\n/, 60 | /\r/, 61 | $.cpp, 62 | $.comment, 63 | $.haddock, 64 | $.pragma, 65 | ], 66 | 67 | /** 68 | * Rules with leading underscore are generally omitted from the AST, and can therefore not be used in queries. 69 | * The rules listed in this attribute are omitted from the AST, but their names can be used in queries in place of 70 | * their children; as well as in combination with them, using the syntax `expression/variable`. 71 | * This is most useful for choice rules that represent syntactic categories, like expressions, patterns, and types in 72 | * Haskell. 73 | * 74 | * See the readme for a detailed explanation. 75 | */ 76 | supertypes: $ => [ 77 | $.expression, 78 | $.pattern, 79 | $.type, 80 | $.quantified_type, 81 | $.constraint, 82 | $.constraints, 83 | $.type_param, 84 | $.declaration, 85 | $.decl, 86 | $.class_decl, 87 | $.instance_decl, 88 | $.statement, 89 | $.qualifier, 90 | $.guard, 91 | ], 92 | 93 | /** 94 | * This rule is used to detect that a reserved keyword is a prefix of an identifier. 95 | * 96 | * For example, if the identifier `ifM` occurs in a position where the keyword `if` is valid (so most expressions), 97 | * the fact that `ifM` matches `variable` prevents tree-sitter from lexing `if` followed by `M` as a `name`. 98 | */ 99 | word: $ => $.variable, 100 | 101 | }) 102 | -------------------------------------------------------------------------------- /grammar/class.js: -------------------------------------------------------------------------------- 1 | const { 2 | sep1, 3 | layout, 4 | context, 5 | forall, 6 | } = require('./util.js') 7 | 8 | module.exports = { 9 | 10 | // ------------------------------------------------------------------------ 11 | // associated families 12 | // ------------------------------------------------------------------------ 13 | 14 | /** 15 | * In associated family declarations, result type aliasing without injectivity is invalid, since that syntax is taken 16 | * by type instance declarations. 17 | */ 18 | _assoc_tyfam: $ => seq( 19 | 'type', 20 | optional('family'), 21 | $._type_head, 22 | optional(choice( 23 | $._kind_annotation, 24 | seq( 25 | $.type_family_result, 26 | $.type_family_injectivity, 27 | ), 28 | )), 29 | ), 30 | 31 | _assoc_tyinst: $ => seq( 32 | 'type', 33 | optional('instance'), 34 | forall($), 35 | $._cond_assoc_tyinst, 36 | $._type_instance_common, 37 | ), 38 | 39 | _assoc_datafam: $ => seq( 40 | 'data', 41 | optional('family'), 42 | $._datafam, 43 | ), 44 | 45 | _assoc_datainst_adt: $ => seq( 46 | 'data', 47 | optional('instance'), 48 | $._inst_adt, 49 | ), 50 | 51 | _assoc_datainst_newtype: $ => seq( 52 | 'newtype', 53 | optional('instance'), 54 | $._inst_newtype, 55 | ), 56 | 57 | _assoc_datainst: $ => choice( 58 | alias($._assoc_datainst_adt, $.data_type), 59 | alias($._assoc_datainst_newtype, $.newtype), 60 | ), 61 | 62 | // ------------------------------------------------------------------------ 63 | // class 64 | // ------------------------------------------------------------------------ 65 | 66 | default_signature: $ => seq('default', field('signature', $.signature)), 67 | 68 | /** 69 | * Classes can have both type families and instances, but only data families. 70 | */ 71 | class_decl: $ => choice( 72 | $._local_decl, 73 | $.default_signature, 74 | alias($._assoc_tyfam, $.type_family), 75 | alias($._assoc_tyinst, $.type_instance), 76 | alias($._assoc_datafam, $.data_family), 77 | ), 78 | 79 | fundep: $ => seq( 80 | field('matched', repeat1($.variable)), 81 | $._arrow, 82 | field('determined', repeat1($.variable)), 83 | ), 84 | 85 | fundeps: $ => seq($._bar, sep1(',', field('fundep', $.fundep))), 86 | 87 | class_declarations: $ => layout($, field('declaration', $.class_decl)), 88 | 89 | class: $ => seq( 90 | 'class', 91 | context($), 92 | $._type_head, 93 | field('fundeps', optional($.fundeps)), 94 | optional(seq($._where, optional(field('declarations', $.class_declarations)))), 95 | ), 96 | 97 | // ------------------------------------------------------------------------ 98 | // instance 99 | // ------------------------------------------------------------------------ 100 | 101 | instance_decl: $ => choice( 102 | $.decl, 103 | alias($._assoc_datainst, $.data_instance), 104 | alias($._assoc_tyinst, $.type_instance), 105 | ), 106 | 107 | instance_declarations: $ => layout($, field('declaration', $.instance_decl)), 108 | 109 | /** 110 | * instances only allow single foralls and contexts 111 | */ 112 | _instance: $ => seq( 113 | 'instance', 114 | forall($), 115 | context($), 116 | $._type_instance_head, 117 | ), 118 | 119 | instance: $ => seq( 120 | $._instance, 121 | optional(seq($._where, optional(field('declarations', $.instance_declarations)))), 122 | ), 123 | 124 | deriving_instance: $ => seq( 125 | optional($._phantom_deriving), 126 | 'deriving', 127 | optional(choice(field('strategy', $.deriving_strategy), field('via', $.via))), 128 | $._instance, 129 | ), 130 | } 131 | -------------------------------------------------------------------------------- /grammar/conflicts.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | conflicts: $ => [ 4 | 5 | /** 6 | * For reference in GHC: 7 | * - Note [Ambiguous syntactic categories] 8 | * - Note [PatBuilder] 9 | * - Note [Declaration/signature overlap] 10 | * - These correspond to `DisambECP` 11 | * 12 | * (fun x) y = undefined 13 | * (fun x -> y) = undefined 14 | * (fun) <> x = undefined 15 | * 16 | * The first one is a regular function with some redundant parens, where `fun` is the declared name. 17 | * The second one is a pattern binder with a view pattern, where `fun` is a free variable. 18 | * The third one is an infix pattern binder, where `fun` is a simple varid pattern with redundant parens. 19 | * 20 | * These conflicts are also relevant for top-level expression splices, which fundamentally conflict with decls, and 21 | * since decls start with either `var` or `pat`, they cannot be disambiguated. 22 | * 23 | * GHC parses functions and binds as expressions and sorts them into the right LHS in a post-processing step. 24 | * Since this is not possible in tree-sitter, these conflicts are more function-centric than in GHC. 25 | * 26 | * function: 27 | * func (A a) = a 28 | * 29 | * bind variable: 30 | * a : as = [1, 2, 3] 31 | * 32 | * pattern bind infix: 33 | * a : as = [1, 2, 3] 34 | * 35 | * pattern bind prefix: 36 | * Just 1 = Just 1 37 | * 38 | * splice: 39 | * makeLenses ''A 40 | * 41 | * Signature and bind: 42 | * 43 | * fun :: Int 44 | * fun :: Int = 5 45 | */ 46 | 47 | // Function vs bind 48 | [$._function_name, $.pattern], 49 | 50 | // Function vs bind vs splice 51 | [$._function_name, $.pattern, $.expression], 52 | 53 | // Bind vs splice 54 | [$.pattern, $.expression], 55 | 56 | // Signature vs bind 57 | [$.signature, $.pattern], 58 | 59 | /** 60 | * Unboxed syntax 61 | * 62 | * The hash in the opening parenthesis of unboxed tuples can be an operator. 63 | */ 64 | [$._operator_hash_head, $._unboxed_open], 65 | 66 | /** 67 | * Types conflicting with structures that look like types 68 | * 69 | * Note: These conflicts have been circumvented by a lookahead mechanism in the scanner. 70 | * This comment is preserved for reference. 71 | * 72 | * `name` and `constructor` use the same terminal symbol, but we cannot reduce `constructor` in prefix data 73 | * constructor declarations. 74 | * 75 | * In GHC, this corresponds to `DisambTD`. 76 | * 77 | * > data A = Name Int 78 | * > data A = Maybe Int :+ Int 79 | * > data A = Monoid a => A a 80 | * 81 | * All of these start with a `name` node. 82 | * In the first example, the `name` is a data constructor, which will not be reduced to a `type`. 83 | * 84 | * In the second example, the `name` is a type constructor applied to another type in the left operand of an infix 85 | * data constructor, so it must be reduced to `type`, and then to `apply` with the `Int`. 86 | * 87 | * In the third example, the `name` is a type constructor applied to a variable resulting in a constraint. 88 | * It will be reduced the same way as the second example, but using the class tree, which is mostly identical to the 89 | * type tree, but conflicts since we want to distinguish classes from types granularly. 90 | * 91 | * In GHC, these correspond to `mkHsAppTyHeadPV` and `mkHsAppTyPV`. 92 | * 93 | * > data A a b = a `C` b => a `A` b 94 | * > data A a b = a `A` b 95 | * 96 | * > data a *** b 97 | * > data a +++ b => a *** b 98 | * 99 | * In GHC, this corresponds to `mkHsOpTyPV`. 100 | * 101 | * > class A where type a + b = r | r -> a b 102 | * > class A where type a + b = (a, b) 103 | * 104 | * The first one is a type family declaration, the second one an instance. 105 | * 106 | * These were the conflicts that have been turned into scanner lookahead: 107 | * 108 | * [$._type_con, $.data_constructor], 109 | * [$._type_con, $._type_head_name], 110 | * [$._type_variable, $._tyvar], 111 | * [$._constructor_ticked, $._tycon_ticked], 112 | */ 113 | 114 | ], 115 | 116 | } 117 | -------------------------------------------------------------------------------- /grammar/context.js: -------------------------------------------------------------------------------- 1 | const { 2 | parens, 3 | sep2, 4 | } = require('./util.js') 5 | 6 | module.exports = { 7 | 8 | // ------------------------------------------------------------------------ 9 | // context 10 | // ------------------------------------------------------------------------ 11 | 12 | _class_apply: $ => prec.left('apply', seq( 13 | field('constructor', $.constraint), 14 | field('argument', $._type_apply_arg), 15 | )), 16 | 17 | _class_infix: $ => prec.right('infix', seq( 18 | $._cond_infix, 19 | field('left_operand', $.type), 20 | field('operator', $._tyops), 21 | field('right_operand', $.type), 22 | )), 23 | 24 | _ctr_parens: $ => parens($, $.constraints), 25 | 26 | _ctr_tuple: $ => parens($, sep2(',', $.constraints)), 27 | 28 | /** 29 | * Implicit parameters have an annotation with `::` but bind tighter than `_type_signature`, with the same precedence 30 | * as foralls, contexts and arrows. 31 | * 32 | * > A => ?a :: A | associates as | A => (?a :: A) 33 | * > ?a :: A -> A | associates as | ?a :: (A -> A) 34 | */ 35 | implicit_parameter: $ => prec.left(seq(field('name', $.implicit_variable), $._type_annotation)), 36 | 37 | constraint: $ => choice( 38 | $._type_name, 39 | alias($._class_infix, $.infix), 40 | alias($._class_apply, $.apply), 41 | alias($._ctr_parens, $.parens), 42 | alias($._ctr_tuple, $.tuple), 43 | alias($._type_wildcard, $.wildcard), 44 | $._universal, 45 | ), 46 | 47 | _ctr_forall: $ => prec('fun', seq($._forall_body, '.', field('constraint', $.constraints))), 48 | 49 | _ctr_context: $ => prec('fun', seq($._context_inline, field('constraint', $.constraints))), 50 | 51 | _ctr_signature: $ => prec('annotated', seq(field('constraint', $.constraints), $._kind_annotation)), 52 | 53 | constraints: $ => choice( 54 | $.constraint, 55 | alias($._ctr_context, $.context), 56 | alias($._ctr_forall, $.forall), 57 | $.implicit_parameter, 58 | alias($._ctr_signature, $.signature), 59 | ), 60 | 61 | _context_inline: $ => seq( 62 | $._cond_context, 63 | field('context', $.constraint), 64 | field('arrow', $._carrow), 65 | ), 66 | 67 | context: $ => prec('qtype-single', $._context_inline), 68 | 69 | } 70 | -------------------------------------------------------------------------------- /grammar/data.js: -------------------------------------------------------------------------------- 1 | const { 2 | sep1, 3 | sep, 4 | braces, 5 | layout, 6 | unboxed_sum_single, 7 | qualified, 8 | context, 9 | forall, 10 | } = require('./util.js') 11 | 12 | module.exports = { 13 | 14 | // ------------------------------------------------------------------------ 15 | // fields 16 | // ------------------------------------------------------------------------ 17 | 18 | field_name: $ => $.variable, 19 | _qfield_name: $ => qualified($, $.field_name), 20 | _field_names: $ => choice($.field_name, alias($._qfield_name, $.qualified)), 21 | 22 | field_path: $ => seq( 23 | field('field', $._field_names), 24 | repeat1(seq($._tight_dot, field('subfield', $.field_name))), 25 | ), 26 | 27 | _field_spec: $ => choice( 28 | $._field_names, 29 | $.field_path, 30 | ), 31 | 32 | field: $ => prec('annotated', seq( 33 | sep1(',', field('name', $.field_name)), 34 | $._colon2, 35 | field('type', $._parameter_type), 36 | )), 37 | 38 | _record_fields: $ => braces($, sep(',', field('field', $.field)), optional(',')), 39 | 40 | // ------------------------------------------------------------------------ 41 | // deriving 42 | // ------------------------------------------------------------------------ 43 | 44 | via: $ => seq('via', field('type', $.quantified_type)), 45 | 46 | deriving_strategy: _ => choice('stock', 'newtype', 'anyclass'), 47 | 48 | deriving: $ => seq( 49 | optional($._phantom_deriving), 50 | 'deriving', 51 | optional(field('strategy', $.deriving_strategy)), 52 | field('classes', $.constraint), 53 | optional(field('via', $.via)), 54 | ), 55 | 56 | // ------------------------------------------------------------------------ 57 | // gadt 58 | // ------------------------------------------------------------------------ 59 | 60 | _gadt_con_prefix: $ => field('type', $.quantified_type), 61 | 62 | _gadt_con_record: $ => seq( 63 | field('fields', alias($._record_fields, $.fields)), 64 | field('arrow', $._fun_arrow), 65 | field('type', $.quantified_type), 66 | ), 67 | 68 | /** 69 | * GADT constructors only allow single foralls and contexts 70 | */ 71 | gadt_constructor: $ => seq( 72 | choice( 73 | field('name', $._con), 74 | field('names', alias($._con_binding_list, $.binding_list)), 75 | ), 76 | $._colon2, 77 | forall($), 78 | context($), 79 | field('type', choice( 80 | alias($._gadt_con_prefix, $.prefix), 81 | alias($._gadt_con_record, $.record), 82 | )), 83 | ), 84 | 85 | gadt_constructors: $ => layout($, field('constructor', $.gadt_constructor)), 86 | 87 | _gadt: $ => seq( 88 | optional($._kind_annotation), 89 | $._where, 90 | optional(field('constructors', $.gadt_constructors)), 91 | ), 92 | 93 | // ------------------------------------------------------------------------ 94 | // data type 95 | // ------------------------------------------------------------------------ 96 | 97 | _field_type: $ => choice($.strict_field, $.lazy_field, $.type), 98 | 99 | _datacon_prefix: $ => seq( 100 | field('name', $._con), 101 | repeat(prec('patterns', field('field', $._field_type))), 102 | ), 103 | 104 | _datacon_infix: $ => prec('infix', seq( 105 | $._cond_data_infix, 106 | field('left_operand', $._field_type), 107 | field('operator', $._conop), 108 | field('right_operand', $._field_type), 109 | )), 110 | 111 | _datacon_record: $ => seq( 112 | field('name', $._constructor), 113 | field('fields', alias($._record_fields, $.fields)), 114 | ), 115 | 116 | _datacon_unboxed_sum: $ => unboxed_sum_single($, $.quantified_type), 117 | 118 | /** 119 | * Special constructors occurring in GHC code 120 | */ 121 | _datacon_special: $ => choice( 122 | $.unit, 123 | $.unboxed_unit, 124 | alias($._plist, $.empty_list), 125 | alias($._type_tuple, $.tuple), 126 | alias($._type_unboxed_tuple, $.unboxed_tuple), 127 | alias($._datacon_unboxed_sum, $.unboxed_sum), 128 | ), 129 | 130 | /** 131 | * data constructors only allow single foralls and contexts 132 | */ 133 | data_constructor: $ => seq( 134 | forall($), 135 | context($), 136 | field('constructor', choice( 137 | alias($._datacon_prefix, $.prefix), 138 | alias($._datacon_infix, $.infix), 139 | alias($._datacon_record, $.record), 140 | alias($._datacon_special, $.special), 141 | )), 142 | ), 143 | 144 | data_constructors: $ => sep1($._bar, field('constructor', $.data_constructor)), 145 | 146 | _data_rhs: $ => choice( 147 | $._kind_annotation, 148 | seq('=', field('constructors', $.data_constructors)), 149 | $._gadt, 150 | ), 151 | 152 | _data: $ => seq( 153 | context($), 154 | $._type_head, 155 | optional($._data_rhs), 156 | repeat(field('deriving', $.deriving)), 157 | ), 158 | 159 | data_type: $ => seq( 160 | optional('type'), 161 | 'data', 162 | $._data, 163 | ), 164 | 165 | // ------------------------------------------------------------------------ 166 | // newtype 167 | // ------------------------------------------------------------------------ 168 | 169 | _newtype_con_field: $ => $.type, 170 | 171 | newtype_constructor: $ => seq( 172 | field('name', $._con), 173 | field('field', choice( 174 | alias($._newtype_con_field, $.field), 175 | alias($._record_fields, $.record), 176 | )), 177 | ), 178 | 179 | _newtype: $ => seq( 180 | choice( 181 | seq('=', field('constructor', $.newtype_constructor)), 182 | $._gadt, 183 | ), 184 | repeat(field('deriving', $.deriving)), 185 | ), 186 | 187 | newtype: $ => seq( 188 | 'newtype', 189 | context($), 190 | $._type_head, 191 | $._newtype, 192 | ), 193 | 194 | // ------------------------------------------------------------------------ 195 | // data family 196 | // ------------------------------------------------------------------------ 197 | 198 | _datafam: $ => seq( 199 | $._type_head, 200 | optional($._kind_annotation), 201 | ), 202 | 203 | data_family: $ => seq( 204 | 'data', 205 | 'family', 206 | $._datafam, 207 | ), 208 | 209 | _inst_adt: $ => seq( 210 | forall($), 211 | context($), 212 | $._type_instance_head, 213 | optional($._data_rhs), 214 | repeat(field('deriving', $.deriving)), 215 | ), 216 | 217 | decl_inst_adt: $ => seq( 218 | 'data', 219 | 'instance', 220 | $._inst_adt, 221 | ), 222 | 223 | _inst_newtype: $ => seq( 224 | forall($), 225 | context($), 226 | $._type_instance_head, 227 | $._newtype, 228 | ), 229 | 230 | decl_inst_newtype: $ => seq( 231 | 'newtype', 232 | 'instance', 233 | $._inst_newtype, 234 | ), 235 | 236 | data_instance: $ => choice( 237 | alias($.decl_inst_adt, $.data_type), 238 | alias($.decl_inst_newtype, $.newtype), 239 | ), 240 | 241 | } 242 | -------------------------------------------------------------------------------- /grammar/decl.js: -------------------------------------------------------------------------------- 1 | const { 2 | sep1, 3 | sep2, 4 | parens, 5 | layout, 6 | } = require('./util.js') 7 | 8 | module.exports = { 9 | 10 | // ------------------------------------------------------------------------ 11 | // fixity 12 | // ------------------------------------------------------------------------ 13 | 14 | _fun_arrow_prec: _ => seq('-', '1'), 15 | 16 | // GHC.Types special decl 17 | _fun_arrow_fixity: $ => seq( 18 | field('associativity', 'infixr'), 19 | field('precedence', alias($._fun_arrow_prec, $.integer)), 20 | field('operator', alias('->', $.operator)), 21 | ), 22 | 23 | fixity: $ => choice( 24 | $._fun_arrow_fixity, 25 | seq( 26 | field('associativity', choice('infixl', 'infixr', 'infix')), 27 | field('precedence', optional($.integer)), 28 | field('operator', sep1(',', choice($._operator_minus, $._varop, $._conop))), 29 | ), 30 | ), 31 | 32 | // ------------------------------------------------------------------------ 33 | // signature 34 | // ------------------------------------------------------------------------ 35 | 36 | _con_binding_list: $ => sep2(',', field('name', $._con)), 37 | 38 | _var_binding_list: $ => sep2(',', field('name', $._var)), 39 | 40 | signature: $ => seq( 41 | choice( 42 | field('name', $._var), 43 | field('names', alias($._var_binding_list, $.binding_list)), 44 | ), 45 | $._type_annotation, 46 | ), 47 | 48 | // ------------------------------------------------------------------------ 49 | // function and pattern bind 50 | // ------------------------------------------------------------------------ 51 | 52 | _simple_bind_match: $ => seq('=', field('expression', $._exp)), 53 | 54 | _bind_match: $ => seq( 55 | $._guards, 56 | '=', 57 | $._cmd_texp_end, 58 | field('expression', $._exp), 59 | ), 60 | 61 | _bind_matches: $ => seq( 62 | choice( 63 | field('match', alias($._simple_bind_match, $.match)), 64 | repeat1(field('match', alias($._bind_match, $.match))), 65 | ), 66 | optional($._where_binds), 67 | ), 68 | 69 | _function_name: $ => field('name', $._var), 70 | 71 | function_head_parens: $ => parens( 72 | $, 73 | choice( 74 | $._function_head, 75 | $._function_head_patterns, 76 | ), 77 | ), 78 | 79 | _function_head_patterns: $ => choice( 80 | $._function_name, 81 | field('parens', $.function_head_parens), 82 | ), 83 | 84 | /** 85 | * The difference between a `function` with an `infix` head and a `bind` with `pat_infix` is that the former is for 86 | * _declaring_ a `varop` and the latter uses a `conop` to pattern match on the rhs expression. 87 | * The former may not have a type annotation, while the latter may. 88 | * 89 | * > a <> b = undefined 90 | * > h : t :: [Int] = undefined 91 | */ 92 | _function_head_infix: $ => seq( 93 | field('left_operand', $.pattern), 94 | optional($._cond_no_section_op), 95 | field('operator', choice(seq($._cond_minus, $._operator_minus), $._varop)), 96 | field('right_operand', $.pattern), 97 | ), 98 | 99 | _function_head: $ => choice( 100 | seq($._function_head_patterns, field('patterns', $.patterns)), 101 | alias($._function_head_infix, $.infix), 102 | ), 103 | 104 | function: $ => seq( 105 | $._function_head, 106 | $._bind_matches, 107 | ), 108 | 109 | /** 110 | * The `implicit_variable` here is for: 111 | * g = let ?par = Impy 5 in f 112 | */ 113 | bind: $ => prec('bind', seq( 114 | choice( 115 | field('pattern', $._pat), 116 | field('name', $._var), 117 | field('implicit', $.implicit_variable), 118 | ), 119 | $._bind_matches, 120 | )), 121 | 122 | /** 123 | * This is a supertype. 124 | */ 125 | decl: $ => choice( 126 | $.signature, 127 | $.function, 128 | $.bind, 129 | ), 130 | 131 | _local_decl: $ => choice( 132 | $.fixity, 133 | $.decl, 134 | ), 135 | 136 | local_binds: $ => layout($, field('decl', $._local_decl)), 137 | 138 | _where_binds: $ => seq($._where, optional(field('binds', $.local_binds))), 139 | 140 | // ------------------------------------------------------------------------ 141 | // foreign 142 | // ------------------------------------------------------------------------ 143 | 144 | calling_convention: _ => token(choice( 145 | 'ccall', 146 | 'stdcall', 147 | 'capi', 148 | 'prim', 149 | 'javascript', 150 | /[A-Z_]+/, // It's common in GHC to use a cpp #define for this 151 | )), 152 | 153 | safety: _ => token(choice( 154 | 'unsafe', 155 | 'safe', 156 | 'interruptible', 157 | )), 158 | 159 | entity: $ => $.string, 160 | 161 | foreign_import: $ => seq( 162 | 'foreign', 163 | 'import', 164 | field('calling_convention', $.calling_convention), 165 | optional(field('safety', $.safety)), 166 | optional(field('entity', $.entity)), 167 | field('signature', $.signature), 168 | ), 169 | 170 | foreign_export: $ => seq( 171 | 'foreign', 172 | 'export', 173 | field('calling_convention', $.calling_convention), 174 | optional(field('entity', $.entity)), 175 | field('signature', $.signature), 176 | ), 177 | 178 | // ------------------------------------------------------------------------ 179 | // default 180 | // ------------------------------------------------------------------------ 181 | 182 | default_types: $ => seq('default', parens($, optional(sep1(',', field('type', $._ktype))))), 183 | 184 | } 185 | -------------------------------------------------------------------------------- /grammar/externals.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | /** 4 | * These rules are handled manually by the custom lexer in `src/scanner.c`. 5 | * Whenever the symbols are used in the rule tree, the parser executes the scanner. 6 | * Since several symbols are present both here and in `extras`, the scanner will be invoked before every single 7 | * natively lexed symbol, repeatedly, until it fails. 8 | * This makes indentation/layout tracking simpler. 9 | * 10 | * There are three special behavioral classes of symbols in this grammar, indicated by their name prefix: 11 | * 12 | * `cmd`: Commands are sequenced after key tokens like opening braces that unconditionally trigger a state change in 13 | * the scanner. 14 | * They don't require the scanner to _decide_ that a symbol is valid – the native parser has already committed 15 | * to a symbol, and the command relays that information to the scanner so it can update its state and return. 16 | * For example, after having parsed an opening brace, the scanner adds a brace context to the stack in reaction 17 | * to `_cond_brace_open`, which will influence its future behavior. 18 | * These symbols do not produce nodes in the parse tree. 19 | * 20 | * `cond`: Conditions are hard requirements in the grammar that are decided by the scanner based on its state and the 21 | * lookahead. 22 | * For example, whitespace-sensitive operators (tight infix /prefix ops) like the `@` in a type application or 23 | * the `.` in a record projection are lexed when the following characters have certain properties. 24 | * When the scanner decides that such a symbol is valid, the parser cannot attempt to use an alternative 25 | * interpretation like it can with conflicts. 26 | * This is often difficult, but also especially useful to force declarations and other layout items to be 27 | * terminated when a new line has smaller or equal indent, preventing incorrect interpretations as top level 28 | * expression splices spanning multiple lines. 29 | * 30 | * `phantom`: Phantom symbols are used to signal to the scanner that certain constructs are valid without requiring 31 | * the scanner to actually parse them and produce text nodes for them. 32 | * In the grammar, they are always optional, and the scanner never emits the phantom symbol itself, but 33 | * decides whether to emit _other_ symbols when the phantom symbol is _not_ valid. 34 | * This is used to implement GHC's tactic of allowing layouts to end _whenever a parse error occurs_, but 35 | * using specialized heuristics. 36 | * 37 | * Most other symbols produce nodes, except for newline and the error sentinel. 38 | */ 39 | externals: $ => [ 40 | 41 | // This is an unused symbol that indicates to the scanner that a parse error has occurred. 42 | // Tree-sitter marks _all_ symbols as valid when calling the scanner after an error, so a symbol that's not used in 43 | // the grammar is only valid if that is the case. 44 | $.error_sentinel, 45 | 46 | // Emitted after every newline with equal or less indent to terminate layout-based rules, with a few exceptions. 47 | $._cond_layout_semicolon, 48 | 49 | // Instruct the scanner to push a layout context. 50 | // The first one is for declarations and miscellaneous other layouts. 51 | // The others are for the specific syntax construct. 52 | // The quote layout is for declaration quotes (`[d|data A ...|]`). 53 | $._cmd_layout_start, 54 | $._cmd_layout_start_do, 55 | $._cmd_layout_start_case, 56 | $._cmd_layout_start_if, 57 | $._cmd_layout_start_let, 58 | $._cmd_layout_start_quote, 59 | // This variant is used in a `choice` with the others, and serves only to create a terminal node for explicit 60 | // braces. 61 | // If the scanner emitted the same symbol for virtual and explicit braces, we would either get an anonymous node 62 | // ranging over the brace, or a terminal brace node even for virtual starts if we were to alias the symbol to '{' 63 | // unconditionally. 64 | // So we use separate symbols and alias only this one. 65 | // The same reasoning applies to `_cond_layout_end_explicit`. 66 | // The terminal could be ensured in different ways – adding an `optional('{')` after the start symbol, using 67 | // `seq($._cmd_layout_start_explicit, '{')` instead of including the brace in the scanner range, or branching the 68 | // entire layout on the start token to unconditionally use `_cmd_brace_close` instead of 69 | // `_cond_layout_end_explicit`. 70 | // However, these solutions are all very expensive, adding between 500 and 1000kB to the shared object size, and up 71 | // to a second in generation time. 72 | $._cmd_layout_start_explicit, 73 | 74 | // Emitted when a new line's indent mandates ending the current layout (depending on the layout sort), or when a 75 | // special inline layout-ending token is encountered, like an `in`. 76 | $._cond_layout_end, 77 | $._cond_layout_end_explicit, 78 | 79 | // Instruct the scanner to push or pop a brace context. 80 | $._cmd_brace_open, 81 | $._cmd_brace_close, 82 | 83 | // Instruct the scanner to push or pop a tuple expression context. 84 | // In parenthesized or bracketed expressions, certain tokens (like commas, bars, and closing brackets), can end 85 | // layouts, so the scanner must be aware of them. 86 | $._cmd_texp_start, 87 | $._cmd_texp_end, 88 | 89 | // Signal to the scanner that these symbols are valid. 90 | // See the explanation of phantom symbols above. 91 | $._phantom_where, 92 | $._phantom_in, 93 | $._phantom_arrow, 94 | $._phantom_bar, 95 | $._phantom_deriving, 96 | 97 | // Detect and emit text nodes for comments and CPP. 98 | // In particular, #else branches of CPP conditionals a fully contained in the resulting node, since their nonlinear 99 | // nature means they cannot be parsed. 100 | $.comment, 101 | $.haddock, 102 | $.cpp, 103 | $.pragma, 104 | 105 | // Starting quote brackets are a bit messy, so it's easier to let the scanner signal that it encountered one. 106 | // The body produces a text node until the ending bracket. 107 | $._cond_quote_start, 108 | $.quasiquote_body, 109 | 110 | // Whitespace-sensitive operators for splices (`$`, `$$`), projection and module dots (`a.b`, `A.b`), arithmetic 111 | // sequence dots `[1..10]`, as-pattern (`a@(Just b)`), type application (`@Int`), strictness and laziness 112 | // annotations (`!pat`, `~Int`), and modifiers (`Int %1 -> Int`). 113 | $._cond_splice, 114 | $._cond_qual_dot, 115 | $._cond_tight_dot, 116 | $._cond_prefix_dot, 117 | $._cond_dotdot, 118 | $._cond_tight_at, 119 | $._cond_prefix_at, 120 | $._cond_tight_bang, 121 | $._cond_prefix_bang, 122 | $._cond_tight_tilde, 123 | $._cond_prefix_tilde, 124 | $._cond_prefix_percent, 125 | 126 | // GHC lexes all qualified names as atomic tokens, but we can't do that because we need nodes for their 127 | // substructures. 128 | // However, infix expressions need single-token lookahead for the operator to resolve conflicts, which is 129 | // impossible without an external. 130 | // This symbol detects a qualified symbolic operator. 131 | $._cond_qualified_op, 132 | // This one performs an additional lookahead check for a following closing parenthesis, to disambiguate left 133 | // sections from infix ops in `(a - b +)`. 134 | $._cond_left_section_op, 135 | // This is an auxiliary for `_cond_left_section_op` that allows restarting the scanner without that symbol being 136 | // valid again when whitespace was skipped after a symop to discover that there's no parenthesis. 137 | // Without this, we would get wrong token ranges for the operator. 138 | $._cond_no_section_op, 139 | 140 | // This symbol always succeeds when a minus is ahead. 141 | // Infix expressions with minus as the operator conflict with function application. 142 | // `a - b` can be parsed as `a (- b)`, which would normally be solved by a simple precedence entry, but is 143 | // impossible to express because it contradicts another conflict: Negation in the left operand, `- a + b`, which 144 | // must be parsed as `(- a) + b`. 145 | // Simply sequencing this external before the operator solves this conflict, because a minus following an expression 146 | // can never be negation; it can only occur at the beginning of an expression. 147 | $._cond_minus, 148 | 149 | /** 150 | * The following symbols perform lookahead for various type constructs to resolve conflicts between infix types, 151 | * contexts, and type/datacon heads, because using GLR conflicts for these is very brittle and frequently leads to 152 | * misparsed trees. 153 | * 154 | * See the documentation under 'Constraints' in `src/scanner.c` for more. 155 | */ 156 | $._cond_context, 157 | $._cond_infix, 158 | $._cond_data_infix, 159 | $._cond_assoc_tyinst, 160 | 161 | // Symbolic operators, producing text nodes. 162 | // These are very difficult to parse in the grammar, because unlike most languages, Haskell's operators are not a 163 | // finite set, and therefore cannot be lexically disambiguated from special operators like `->`. 164 | // In the presence of runtime conflicts, this can easily lead to the invalid interpretation of reserved operators as 165 | // identifiers. 166 | // Furthermore, the regexes for all the unicode categories produce very large ternary operator trees if specified 167 | // in the grammar. 168 | $._varsym, 169 | $._consym, 170 | 171 | // The newline is used as a dummy symbol that is emitted whenever the scanner has to update its state even though 172 | // the current position must be parsed by the grammar. 173 | /\n/, 174 | 175 | ], 176 | 177 | } 178 | -------------------------------------------------------------------------------- /grammar/general.js: -------------------------------------------------------------------------------- 1 | const { 2 | sep1, 3 | layout_sort, 4 | } = require('./util.js') 5 | 6 | module.exports = { 7 | 8 | // ------------------------------------------------------------------------ 9 | // guard 10 | // ------------------------------------------------------------------------ 11 | 12 | generator: $ => seq( 13 | field('pattern', $._pat), 14 | field('arrow', $._larrow), 15 | field('expression', $._exp), 16 | ), 17 | 18 | _let_binds: $ => layout_sort($, $._cmd_layout_start_let, field('decl', $.decl)), 19 | 20 | _let: $ => seq('let', optional(field('binds', alias($._let_binds, $.local_binds)))), 21 | 22 | let: $ => $._let, 23 | 24 | /** 25 | * This is a supertype. 26 | */ 27 | guard: $ => choice( 28 | // Cannot be named `pattern` because name clash. 29 | alias($.generator, $.pattern_guard), 30 | $.let, 31 | alias($._exp, $.boolean), 32 | ), 33 | 34 | guards: $ => sep1(',', field('guard', $.guard)), 35 | 36 | _guards: $ => seq( 37 | $._bar, 38 | $._cmd_texp_start, 39 | field('guards', $.guards), 40 | ), 41 | 42 | // ------------------------------------------------------------------------ 43 | // rules shared by expression, pattern, type 44 | // ------------------------------------------------------------------------ 45 | 46 | _universal: $ => choice( 47 | $.splice, 48 | $.quasiquote, 49 | $.literal, 50 | $._unit_cons, 51 | $._tuple_cons, 52 | ), 53 | 54 | } 55 | -------------------------------------------------------------------------------- /grammar/id.js: -------------------------------------------------------------------------------- 1 | const { 2 | parens, 3 | ticked, 4 | promoted, 5 | qualified, 6 | } = require('./util.js') 7 | 8 | module.exports = { 9 | // ------------------------------------------------------------------------ 10 | // var 11 | // ------------------------------------------------------------------------ 12 | 13 | _qualified_variable: $ => qualified($, $.variable), 14 | _qvarid: $ => alias($._qualified_variable, $.qualified), 15 | _varids: $ => choice($._qvarid, $.variable), 16 | 17 | _var: $ => choice($.variable, $._pvarsym), 18 | _qvar: $ => choice($._qvarid, $._pqvarsym), 19 | _vars: $ => choice($._var, $._qvar), 20 | 21 | _variable_ticked: $ => ticked($.variable), 22 | 23 | _varop: $ => choice($.operator, alias($._variable_ticked, $.infix_id)), 24 | 25 | _qvariable_ticked: $ => ticked($._qvarid), 26 | 27 | _varids_ticked: $ => alias( 28 | choice( 29 | $._variable_ticked, 30 | $._qvariable_ticked, 31 | ), 32 | $.infix_id, 33 | ), 34 | 35 | // ------------------------------------------------------------------------ 36 | // con 37 | // ------------------------------------------------------------------------ 38 | 39 | _constructor: $ => alias($.name, $.constructor), 40 | _qualified_constructor: $ => qualified($, $._constructor), 41 | _qconid: $ => alias($._qualified_constructor, $.qualified), 42 | _conids: $ => choice($._qconid, $._constructor), 43 | 44 | _con: $ => choice($._constructor, $._pconsym), 45 | _qcon: $ => choice($._qconid, $._pqconsym), 46 | _cons: $ => choice(prec('con', $._con), $._qcon), 47 | 48 | _constructor_ticked: $ => ticked($._constructor), 49 | _conop: $ => choice($._constructor_operator_alias, alias($._constructor_ticked, $.infix_id)), 50 | 51 | _qconstructor_ticked: $ => ticked($._qconid), 52 | 53 | _conids_ticked: $ => alias( 54 | choice( 55 | $._constructor_ticked, 56 | $._qconstructor_ticked, 57 | ), 58 | $.infix_id, 59 | ), 60 | 61 | // ------------------------------------------------------------------------ 62 | // tycon 63 | // ------------------------------------------------------------------------ 64 | 65 | _tyconid: $ => $.name, 66 | _qualified_type: $ => qualified($, $._tyconid), 67 | _qtyconid: $ => alias($._qualified_type, $.qualified), 68 | _tyconids: $ => choice($._qtyconid, $._tyconid), 69 | 70 | _tycon_arrow: $ => parens($, alias($._arrow, $.operator)), 71 | _qualified_arrow: $ => qualified($, alias($._arrow, $.operator)), 72 | _qtycon_arrow: $ => parens($, alias($._qualified_arrow, $.qualified)), 73 | 74 | _tycon: $ => choice($._tyconid, $._pvarsym, alias($._tycon_arrow, $.prefix_id), $._pconsym), 75 | _qtycon: $ => choice($._qtyconid, alias($._qtycon_arrow, $.prefix_id), $._pqsym), 76 | _tycons: $ => choice($._tycon, $._qtycon), 77 | 78 | _promoted_tycons_alias: $ => seq('\'', $._cons), 79 | 80 | _promoted_tycons: $ => alias($._promoted_tycons_alias, $.promoted), 81 | 82 | _tycon_ticked: $ => ticked($._tyconid), 83 | _qtycon_ticked: $ => ticked($._qtyconid), 84 | 85 | _tyconids_ticked: $ => alias( 86 | choice( 87 | $._tycon_ticked, 88 | $._qtycon_ticked, 89 | ), 90 | $.infix_id, 91 | ), 92 | 93 | _tyconops: $ => choice( 94 | $._sym, 95 | $._qsym, 96 | $._operator_minus, 97 | $._tyconids_ticked, 98 | ), 99 | 100 | /** 101 | * Lenient parsing: `varsym` is not legal (like `'++`). 102 | */ 103 | _promoted_tyconops_alias: $ => promoted($._tyconops), 104 | 105 | _promoted_tyconops: $ => alias($._promoted_tyconops_alias, $.promoted), 106 | 107 | _tyops: $ => choice( 108 | $._tyconops, 109 | $._promoted_tyconops, 110 | ), 111 | 112 | // ------------------------------------------------------------------------ 113 | // op 114 | // ------------------------------------------------------------------------ 115 | 116 | _op_ticked: $ => choice( 117 | $._varids_ticked, 118 | $._conids_ticked, 119 | ), 120 | 121 | _ops: $ => choice( 122 | $.operator, 123 | $._qvarsym, 124 | $.constructor_operator, 125 | $._qconsym, 126 | $._op_ticked, 127 | ), 128 | 129 | _name: $ => choice($._var, $._con), 130 | _qname: $ => choice($._vars, $._cons), 131 | 132 | } 133 | -------------------------------------------------------------------------------- /grammar/inline.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | inline: $ => [ 4 | 5 | // ------------------------------------------------ 6 | // variable 7 | // ------------------------------------------------ 8 | 9 | $._var, 10 | $._vars, 11 | $._varids, 12 | $._varids_ticked, 13 | $._varop, 14 | 15 | // ------------------------------------------------ 16 | // constructor 17 | // ------------------------------------------------ 18 | 19 | $._constructor, 20 | $._con, 21 | $._qcon, 22 | $._cons, 23 | $._conids, 24 | $._conids_ticked, 25 | $._conop, 26 | $._op_ticked, 27 | $._modid, 28 | 29 | // ------------------------------------------------ 30 | // operator 31 | // ------------------------------------------------ 32 | 33 | $._qvarsym, 34 | $._qconsym, 35 | $._sym, 36 | $._qsym, 37 | $._pqsym, 38 | $._any_prefix_dot, 39 | $._any_tight_dot, 40 | $._unboxed_bar, 41 | 42 | // ------------------------------------------------ 43 | // expression 44 | // ------------------------------------------------ 45 | 46 | $._exp_name, 47 | $._exp_greedy, 48 | $._let, 49 | 50 | // ------------------------------------------------ 51 | // pattern 52 | // ------------------------------------------------ 53 | 54 | $._pat_apply_arg, 55 | $._pat_name, 56 | $._pat_texp, 57 | 58 | // ------------------------------------------------ 59 | // type 60 | // ------------------------------------------------ 61 | 62 | $._tyconid, 63 | $._tyconids, 64 | $._tycon, 65 | $._qtycon, 66 | $._tycons, 67 | $._tyconops, 68 | $._tyops, 69 | 70 | $._type_name, 71 | $._forall, 72 | $._type_apply_arg, 73 | $._parameter_type, 74 | $._field_type, 75 | $._type_head, 76 | $._type_instance_head, 77 | $._type_annotation, 78 | $._kind_annotation, 79 | 80 | // ------------------------------------------------ 81 | // literal 82 | // ------------------------------------------------ 83 | 84 | $._number, 85 | $._stringly, 86 | $._unit_cons, 87 | $._tuple_cons, 88 | $._universal, 89 | 90 | // ------------------------------------------------ 91 | // decl 92 | // ------------------------------------------------ 93 | 94 | $._function_head_patterns, 95 | $._function_head, 96 | 97 | ], 98 | 99 | } 100 | -------------------------------------------------------------------------------- /grammar/lexeme.js: -------------------------------------------------------------------------------- 1 | const id_char = /[\pL\p{Mn}\pN_']*/ 2 | 3 | const varid_start_char = /[_\p{Ll}\p{Lo}]/ 4 | 5 | const conid_start_char = /[\p{Lu}\p{Lt}]/ 6 | 7 | module.exports = { 8 | 9 | variable: _ => token(seq(varid_start_char, id_char, /#*/)), 10 | 11 | implicit_variable: _ => token(seq('?', varid_start_char, id_char)), 12 | 13 | name: _ => token(seq(conid_start_char, id_char, /#*/)), 14 | 15 | label: _ => token(seq('#', varid_start_char, id_char)), 16 | 17 | _carrow: _ => choice('=>', '⇒'), 18 | _arrow: _ => choice('->', '→'), 19 | _linear_arrow: _ => choice('->.', '⊸'), 20 | _larrow: _ => choice('<-', '←'), 21 | _colon2: _ => choice('::', '∷'), 22 | _promote: _ => '\'', 23 | 24 | _qual_dot: $ => seq($._cond_qual_dot, '.'), 25 | _tight_dot: $ => seq($._cond_tight_dot, '.'), 26 | _any_tight_dot: $ => choice($._qual_dot, $._tight_dot), 27 | _prefix_dot: $ => seq($._cond_prefix_dot, '.'), 28 | _any_prefix_dot: $ => choice($._qual_dot, $._prefix_dot), 29 | 30 | _tight_at: $ => seq($._cond_tight_at, '@'), 31 | _prefix_at: $ => seq($._cond_prefix_at, '@'), 32 | 33 | _prefix_bang: $ => seq($._cond_prefix_bang, '!'), 34 | _tight_bang: $ => seq($._cond_tight_bang, '!'), 35 | _any_prefix_bang: $ => choice($._prefix_bang, $._tight_bang), 36 | 37 | _prefix_tilde: $ => seq($._cond_prefix_tilde, '~'), 38 | _tight_tilde: $ => seq($._cond_tight_tilde, '~'), 39 | _any_prefix_tilde: $ => choice($._prefix_tilde, $._tight_tilde), 40 | 41 | _prefix_percent: $ => seq($._cond_prefix_percent, '%'), 42 | 43 | _dotdot: $ => seq($._cond_dotdot, '..'), 44 | 45 | _paren_open: $ => seq(alias(/\(/, '('), $._cmd_texp_start), 46 | _paren_close: $ => seq(alias(/\)/, ')'), $._cmd_texp_end), 47 | _bracket_open: $ => seq('[', $._cmd_texp_start), 48 | _bracket_close: $ => seq(']', $._cmd_texp_end), 49 | 50 | // Sadly, this does not have the effect of creating a single terminal for the bracket :'( 51 | _unboxed_open: $ => alias(seq($._paren_open, token.immediate('#')), '(#'), 52 | _unboxed_close: $ => seq('#)', $._cmd_texp_end), 53 | _unboxed_bar: _ => choice('|', token.immediate('|')), 54 | 55 | _where: $ => seq(optional($._phantom_where), 'where'), 56 | 57 | _bar: $ => seq(optional($._phantom_bar), '|'), 58 | 59 | } 60 | -------------------------------------------------------------------------------- /grammar/literal.js: -------------------------------------------------------------------------------- 1 | const { 2 | parens, 3 | brackets, 4 | unboxed, 5 | } = require('./util.js') 6 | 7 | const decimal = /[0-9][0-9_]*/ 8 | const exponent = /[eE][+-]?[0-9_]+/ 9 | const hex_exponent = /[pP][+-]?[0-9a-fA-F_]+/ 10 | const magic_hash = rule => token(seq(rule, optional(token.immediate(/##?/)))) 11 | 12 | module.exports = { 13 | 14 | // ------------------------------------------------------------------------ 15 | // literals 16 | // ------------------------------------------------------------------------ 17 | 18 | // the `choice` here is necessary to avoid integers being parsed as floats 19 | float: _ => magic_hash( 20 | seq( 21 | decimal, 22 | choice( 23 | seq(/\.[0-9_]+/, optional(exponent)), 24 | exponent, 25 | ), 26 | ), 27 | ), 28 | 29 | char: _ => magic_hash( 30 | choice( 31 | /'[^']'/, 32 | /'\\[^ ]*'/, 33 | ), 34 | ), 35 | 36 | string: _ => magic_hash( 37 | seq( 38 | '"', 39 | repeat(choice( 40 | /[^\\"\n]/, 41 | /\\(\^)?./, 42 | /\\\n\s*\\/, 43 | )), 44 | '"', 45 | ), 46 | ), 47 | 48 | _integer_literal: _ => magic_hash(decimal), 49 | _binary_literal: _ => magic_hash(/0[bB][01_]+/), 50 | _octal_literal: _ => magic_hash(/0[oO][0-7]+/), 51 | 52 | _hex_literal: _ => magic_hash( 53 | seq( 54 | /0[xX][0-9a-fA-F_]+/, 55 | optional(/\.[0-9a-fA-F_]+/), 56 | optional(hex_exponent), 57 | ) 58 | ), 59 | 60 | integer: $ => choice( 61 | $._binary_literal, 62 | $._integer_literal, 63 | $._octal_literal, 64 | $._hex_literal, 65 | ), 66 | 67 | _stringly: $ => choice( 68 | $.string, 69 | $.char, 70 | ), 71 | 72 | _number: $ => choice( 73 | $.integer, 74 | $.float, 75 | ), 76 | 77 | _plist: $ => brackets($), 78 | 79 | unit: $ => parens($), 80 | unboxed_unit: $ => unboxed($), 81 | 82 | prefix_tuple: $ => parens($, repeat1(',')), 83 | prefix_unboxed_tuple: $ => unboxed($, repeat1(',')), 84 | prefix_unboxed_sum: $ => unboxed($, repeat1($._unboxed_bar)), 85 | 86 | literal: $ => choice( 87 | $._stringly, 88 | $._number, 89 | ), 90 | 91 | _unit_cons: $ => choice( 92 | $.unit, 93 | $.unboxed_unit, 94 | ), 95 | 96 | _tuple_cons: $ => choice( 97 | $.prefix_tuple, 98 | $.prefix_unboxed_tuple, 99 | $.prefix_unboxed_sum, 100 | ), 101 | 102 | } 103 | -------------------------------------------------------------------------------- /grammar/module.js: -------------------------------------------------------------------------------- 1 | const { 2 | sep1, 3 | sep, 4 | parens, 5 | semi, 6 | semi_opt, 7 | semis, 8 | } = require('./util.js') 9 | 10 | module.exports = { 11 | 12 | // ------------------------------------------------------------------------ 13 | // module names 14 | // ------------------------------------------------------------------------ 15 | 16 | _modid: $ => alias($.name, $.module_id), 17 | 18 | _modid_prefix: $ => prec('qualifying-module', seq($._modid, $._any_tight_dot)), 19 | 20 | _qualifying_module: $ => repeat1($._modid_prefix), 21 | 22 | module: $ => seq(repeat($._modid_prefix), $._modid), 23 | 24 | // ------------------------------------------------------------------------ 25 | // import/export 26 | // ------------------------------------------------------------------------ 27 | 28 | namespace: _ => choice('pattern', 'type'), 29 | 30 | _child_type: $ => seq(field('namespace', 'type'), field('type', $._tyconids)), 31 | 32 | _child: $ => choice( 33 | alias($._child_type, $.associated_type), 34 | $._qname, 35 | ), 36 | 37 | children: $ => parens($, sep(',', field('element', choice(alias('..', $.all_names), $._child)))), 38 | 39 | _ie_entity: $ => seq( 40 | optional(field('namespace', $.namespace)), 41 | choice( 42 | field('variable', $._varids), 43 | field('type', $._tyconids), 44 | field('operator', choice($._sym_prefix, $._pqsym)), 45 | ), 46 | optional(field('children', $.children)), 47 | ), 48 | 49 | // ------------------------------------------------------------------------ 50 | // import 51 | // ------------------------------------------------------------------------ 52 | 53 | import_list: $ => parens( 54 | $, 55 | sep(',', field('name', alias($._ie_entity, $.import_name))), 56 | optional(','), 57 | ), 58 | 59 | import: $ => seq( 60 | 'import', 61 | optional('qualified'), 62 | optional(field('package', alias($.string, $.import_package))), 63 | field('module', $.module), 64 | optional('qualified'), 65 | optional(seq('as', field('alias', $.module))), 66 | optional(seq( 67 | optional('hiding'), 68 | field('names', $.import_list), 69 | )), 70 | ), 71 | 72 | // ------------------------------------------------------------------------ 73 | // export 74 | // ------------------------------------------------------------------------ 75 | 76 | module_export: $ => seq('module', field('module', $.module)), 77 | 78 | exports: $ => parens( 79 | $, 80 | optional(sep1(',', choice(field('export', alias($._ie_entity, $.export)), $.module_export))), 81 | optional(','), 82 | ), 83 | 84 | // ------------------------------------------------------------------------ 85 | // module body / sections 86 | // ------------------------------------------------------------------------ 87 | 88 | header: $ => seq( 89 | 'module', 90 | field('module', $.module), 91 | field('exports', optional($.exports)), 92 | $._where, 93 | ), 94 | 95 | imports: $ => seq(semis($, field('import', $.import)), semi($)), 96 | 97 | /** 98 | * Using `semi` at the end instead of `semi_opt` increases parser size by a full megabyte!! 99 | * 100 | * This allows imports after the first declaration to prevent the tree from jittering while typing an import: 101 | * 102 | * > import A 103 | * > imp 104 | * > import B 105 | * 106 | * The partially typed `imp` will be parsed as a `top_splice`, which forces `imports` to reduce after `import A`. 107 | * The rest of the file will then be part of `declarations` and all following imports will be broken until the keyword 108 | * has been completed. 109 | */ 110 | declarations: $ => seq($.declaration, repeat(seq(semi($), choice($.declaration, $.import))), semi_opt($)), 111 | 112 | _body: $ => seq( 113 | choice($._cmd_layout_start, alias($._cmd_layout_start_explicit, '{')), 114 | semi_opt($), 115 | field('imports', optional($.imports)), 116 | field('declarations', optional($.declarations)), 117 | $._layout_end, 118 | ), 119 | 120 | _layout_end: $ => choice( 121 | $._cond_layout_end, 122 | alias($._cond_layout_end_explicit, '}'), 123 | ), 124 | 125 | /** 126 | * This is a supertype. 127 | */ 128 | declaration: $ => choice( 129 | $.decl, 130 | $.type_synomym, 131 | $.kind_signature, 132 | $.type_family, 133 | $.type_instance, 134 | $.role_annotation, 135 | $.data_type, 136 | $.newtype, 137 | $.data_family, 138 | $.data_instance, 139 | $.class, 140 | $.instance, 141 | $.default_types, 142 | $.deriving_instance, 143 | $.pattern_synonym, 144 | $.foreign_import, 145 | $.foreign_export, 146 | $.fixity, 147 | $.top_splice, 148 | ), 149 | 150 | } 151 | -------------------------------------------------------------------------------- /grammar/operator.js: -------------------------------------------------------------------------------- 1 | const { 2 | parens, 3 | qualified, 4 | } = require('./util.js') 5 | 6 | module.exports = { 7 | 8 | // ------------------------------------------------------------------------ 9 | // var 10 | // ------------------------------------------------------------------------ 11 | 12 | _operator_qual_dot_head: $ => seq($._cond_qual_dot, $._varsym), 13 | 14 | _operator_hash_head: _ => seq( 15 | choice('#', token.immediate('#')), 16 | optional(choice(token.immediate('#'), token.immediate('|'))), 17 | ), 18 | 19 | operator: $ => choice( 20 | seq(optional($._cond_prefix_dot), $._varsym), 21 | $._operator_hash_head, 22 | '*', 23 | ), 24 | 25 | _operator_alias: $ => $.operator, 26 | 27 | _operator_minus: $ => alias('-', $.operator), 28 | 29 | _varsym_prefix: $ => parens( 30 | $, 31 | choice( 32 | $.operator, 33 | $._operator_minus, 34 | alias($._operator_qual_dot_head, $.operator), 35 | ), 36 | ), 37 | 38 | _pvarsym: $ => alias($._varsym_prefix, $.prefix_id), 39 | 40 | _qualified_varsym: $ => qualified($, choice($.operator, $._operator_minus)), 41 | _qvarsym: $ => alias($._qualified_varsym, $.qualified), 42 | 43 | _qvarsym_prefix: $ => parens($, $._qvarsym), 44 | _pqvarsym: $ => alias($._qvarsym_prefix, $.prefix_id), 45 | 46 | // ------------------------------------------------------------------------ 47 | // con 48 | // ------------------------------------------------------------------------ 49 | 50 | constructor_operator: $ => $._consym, 51 | 52 | _constructor_operator_alias: $ => $.constructor_operator, 53 | 54 | _consym_prefix: $ => parens($, $.constructor_operator), 55 | _pconsym: $ => alias($._consym_prefix, $.prefix_id), 56 | 57 | _qualified_consym: $ => qualified($, $.constructor_operator), 58 | _qconsym: $ => alias($._qualified_consym, $.qualified), 59 | 60 | _qconsym_prefix: $ => parens($, $._qconsym), 61 | _pqconsym: $ => alias($._qconsym_prefix, $.prefix_id), 62 | 63 | // ------------------------------------------------------------------------ 64 | // op 65 | // ------------------------------------------------------------------------ 66 | 67 | _sym: $ => choice($._operator_alias, $._constructor_operator_alias), 68 | 69 | _sym_prefix: $ => choice($._pvarsym, $._pconsym), 70 | 71 | _qsym: $ => choice($._qvarsym, $._qconsym), 72 | 73 | _pqsym: $ => choice($._pqvarsym, $._pqconsym), 74 | 75 | } 76 | -------------------------------------------------------------------------------- /grammar/pat.js: -------------------------------------------------------------------------------- 1 | const { 2 | sep1, 3 | sep2, 4 | sep, 5 | parens, 6 | braces, 7 | brackets, 8 | unboxed_tuple_full, 9 | unboxed_sum_single, 10 | } = require('./util.js') 11 | 12 | module.exports = { 13 | 14 | // ------------------------------------------------------------------------ 15 | // tuples and parens 16 | // ------------------------------------------------------------------------ 17 | 18 | _pat_parens: $ => parens($, field('pattern', $._pat_texp)), 19 | 20 | _pat_tuple_elems: $ => sep2(',', field('element', $._pat_texp)), 21 | 22 | _pat_tuple: $ => parens($, $._pat_tuple_elems), 23 | 24 | _pat_unboxed_tuple: $ => unboxed_tuple_full($, $._pat_texp), 25 | 26 | _pat_unboxed_sum: $ => unboxed_sum_single($, $._pat_texp), 27 | 28 | _pat_list: $ => brackets($, sep1(',', field('element', $._pat_texp)), optional(',')), 29 | 30 | // ------------------------------------------------------------------------ 31 | // record 32 | // ------------------------------------------------------------------------ 33 | 34 | field_pattern: $ => choice( 35 | alias('..', $.wildcard), 36 | seq(field('field', $._field_names), optional(seq('=', field('pattern', $._pat_texp)))), 37 | ), 38 | 39 | _pat_record: $ => prec('record', seq( 40 | field('constructor', $.pattern), 41 | braces($, sep(',', field('field', $.field_pattern))), 42 | )), 43 | 44 | // ------------------------------------------------------------------------ 45 | // misc 46 | // ------------------------------------------------------------------------ 47 | 48 | /** 49 | * This dynamic precedence penalty is relevant for the conflict between `function` and `bind`. 50 | * Consider: 51 | * 52 | * > f (A a) = exp 53 | * 54 | * Because of the "single choice disambiguated with named precedences" approach used for `pattern`, the left node in 55 | * `pat_apply` can be a variable, even though it's not valid Haskell. 56 | * While the static prec 'pat-name' covers this at generation time, Haskell's ambiguity requires us to use a runtime 57 | * conflict for `function`/`bind`, where static prec is ineffective. 58 | * Giving the reduction of `_var` to `pattern` a strong negative dynamic prec ensures that the runtime branch for 59 | * `bind` has lower precedence because of `f`, so `function` always wins. 60 | * 61 | * While `bind` usually has a lower score than `function` anyway in this situation because it is slightly more 62 | * complex, there are never any guarantees for runtime conflicts. 63 | * In particular, the presence of minor parse errors later in the declaration can tip the scales randomly. 64 | */ 65 | _pat_name: $ => choice( 66 | prec('pat-name', prec.dynamic(-1000, $._var)), 67 | $._cons, 68 | ), 69 | 70 | _pat_as: $ => prec('prefix', seq(field('bind', $.variable), $._tight_at, field('pattern', $.pattern))), 71 | 72 | _pat_wildcard: _ => '_', 73 | 74 | _pat_strict: $ => prec('prefix', seq($._any_prefix_bang, field('pattern', $.pattern))), 75 | 76 | _pat_irrefutable: $ => prec('prefix', seq($._any_prefix_tilde, field('pattern', $.pattern))), 77 | 78 | // ------------------------------------------------------------------------ 79 | // application 80 | // ------------------------------------------------------------------------ 81 | 82 | _pat_apply_arg: $ => choice( 83 | $.pattern, 84 | alias($._at_type, $.type_binder), 85 | $.explicit_type, 86 | ), 87 | 88 | _pat_apply: $ => prec.left('apply', seq( 89 | field('function', $.pattern), 90 | field('argument', $._pat_apply_arg), 91 | )), 92 | 93 | // ------------------------------------------------------------------------ 94 | // operators 95 | // ------------------------------------------------------------------------ 96 | 97 | _pat_negation: $ => seq('-', field('number', $._number)), 98 | 99 | _pat_infix: $ => prec.right('infix', seq( 100 | field('left_operand', $.pattern), 101 | optional($._cond_no_section_op), 102 | field('operator', choice( 103 | $.constructor_operator, 104 | $._conids_ticked, 105 | seq($._cond_qualified_op, $._qconsym), 106 | )), 107 | field('right_operand', $.pattern), 108 | )), 109 | 110 | // ------------------------------------------------------------------------ 111 | // top level 112 | // ------------------------------------------------------------------------ 113 | 114 | pattern: $ => choice( 115 | alias($._pat_infix, $.infix), 116 | alias($._pat_negation, $.negation), 117 | alias($._pat_apply, $.apply), 118 | $._pat_name, 119 | alias($._pat_as, $.as), 120 | alias($._pat_record, $.record), 121 | alias($._pat_wildcard, $.wildcard), 122 | alias($._pat_parens, $.parens), 123 | alias($._pat_tuple, $.tuple), 124 | alias($._pat_unboxed_tuple, $.unboxed_tuple), 125 | alias($._pat_unboxed_sum, $.unboxed_sum), 126 | alias($._pat_list, $.list), 127 | alias($._plist, $.list), 128 | alias($._pat_strict, $.strict), 129 | alias($._pat_irrefutable, $.irrefutable), 130 | $._universal, 131 | ), 132 | 133 | patterns: $ => repeat1(prec('patterns', $._pat_apply_arg)), 134 | 135 | _pat_signature: $ => prec.right('annotated', seq( 136 | field('pattern', $.pattern), 137 | $._type_annotation, 138 | )), 139 | 140 | _pat: $ => choice( 141 | alias($._pat_signature, $.signature), 142 | prec.right($.pattern), 143 | ), 144 | 145 | view_pattern: $ => seq(field('expression', $._exp), $._arrow, field('pattern', $._pat_texp)), 146 | 147 | _pat_texp: $ => choice($.view_pattern, $._pat), 148 | 149 | } 150 | -------------------------------------------------------------------------------- /grammar/patsyn.js: -------------------------------------------------------------------------------- 1 | const { 2 | layout, 3 | optional_where, 4 | } = require('./util.js') 5 | 6 | module.exports = { 7 | // ------------------------------------------------------------------------ 8 | // pattern synonym 9 | // ------------------------------------------------------------------------ 10 | 11 | _patsyn_signature: $ => seq( 12 | field('synonym', choice($._con, alias($._con_binding_list, $.binding_list))), 13 | $._colon2, 14 | field('type', $.quantified_type), 15 | ), 16 | 17 | _patsyn_cons: $ => layout($, alias($.bind, $.constructor_synonym)), 18 | 19 | /** 20 | * This allows a `where` after any equation for parsing resilience, even though it's only valid for the arrow variant 21 | * (explicitly bidirectional patterns). 22 | * The `where` may also be empty. 23 | */ 24 | _patsyn_equation: $ => seq( 25 | field('synonym', $.pattern), 26 | choice( 27 | '=', 28 | $._larrow, 29 | ), 30 | field('pattern', $._pat), 31 | optional_where($, field('constructors', alias($._patsyn_cons, $.constructor_synonyms))), 32 | ), 33 | 34 | pattern_synonym: $ => seq( 35 | 'pattern', 36 | choice( 37 | alias($._patsyn_signature, $.signature), 38 | alias($._patsyn_equation, $.equation), 39 | ), 40 | ), 41 | 42 | } 43 | -------------------------------------------------------------------------------- /grammar/precedences.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | precedences: $ => [ 4 | 5 | // ------------------------------------------------ 6 | // associativity of expressions, patterns and types 7 | // ------------------------------------------------ 8 | 9 | [ 10 | 'projection', 11 | 'record', 12 | 'prefix', 13 | 'apply', 14 | 'negation', 15 | 'infix', 16 | 'implicit', 17 | 'fun', 18 | 'annotated', 19 | $.quantified_type, 20 | ], 21 | 22 | // ------------------------------------------------ 23 | // negation 24 | // ------------------------------------------------ 25 | 26 | [ 27 | $._pat_negation, 28 | $.literal, 29 | ], 30 | 31 | // ------------------------------------------------ 32 | // function vs bind 33 | // ------------------------------------------------ 34 | 35 | [ 36 | 'bind', 37 | 'pat-name', 38 | ], 39 | 40 | // ------------------------------------------------ 41 | // qualified names 42 | // ------------------------------------------------ 43 | 44 | /** 45 | * Prioritize shifting over a tight infix dot over reducing to a qualified constructor or module. 46 | */ 47 | [ 48 | 'qualifying-module', 49 | 'qualified-id', 50 | ], 51 | 52 | /** 53 | * Prioritize qualified variables over record field projection on constructors. 54 | */ 55 | [ 56 | 'qualifying-module', 57 | 'con', 58 | ], 59 | 60 | /** 61 | * Prioritize qualified names over the infix operator dot in types. 62 | */ 63 | [ 64 | 'qualifying-module', 65 | 'type-name', 66 | ], 67 | 68 | // ------------------------------------------------ 69 | // types and constraints 70 | // ------------------------------------------------ 71 | 72 | [ 73 | $.operator, 74 | $._type_star, 75 | ], 76 | 77 | [ 78 | $._type_wildcard, 79 | $._type_param_wildcard, 80 | ], 81 | 82 | [ 83 | $._constructor_ticked, 84 | $._tycon_ticked, 85 | ], 86 | 87 | [ 88 | 'qtype-single', 89 | 'qtype-curried', 90 | ], 91 | 92 | // ------------------------------------------------ 93 | // misc 94 | // ------------------------------------------------ 95 | 96 | /** 97 | * > f A a a = a 98 | * > data A = A Int Int 99 | * 100 | * This should not be parsed as constructor application, but separate patterns. 101 | */ 102 | [ 103 | 'patterns', 104 | 'apply', 105 | ], 106 | 107 | ], 108 | 109 | } 110 | -------------------------------------------------------------------------------- /grammar/th.js: -------------------------------------------------------------------------------- 1 | const { 2 | layout_sort, 3 | } = require('./util.js') 4 | 5 | const quote_bracket = ($, quoter) => seq( 6 | $._cond_quote_start, 7 | '[', 8 | field('quoter', quoter), 9 | '|', 10 | ) 11 | 12 | module.exports = { 13 | 14 | // ------------------------------------------------------------------------ 15 | // splice 16 | // ------------------------------------------------------------------------ 17 | 18 | /** 19 | * Even though the doc states "arbitrary expression", it's very rare for any others than names and parenthesized 20 | * expressions to occur, and it's very expensive to allow them. 21 | * Even only allowing list and quotes adds a full megabyte to the parser size. 22 | */ 23 | _splice_exp: $ => choice( 24 | $._exp_name, 25 | alias($._exp_parens, $.parens), 26 | $.literal, 27 | ), 28 | 29 | _splice_dollars: $ => seq( 30 | $._cond_splice, 31 | choice('$', '$$'), 32 | ), 33 | 34 | splice: $ => seq($._splice_dollars, field('expression', $._splice_exp)), 35 | 36 | /** 37 | * Since `expression` includes `splice`, this allows for a top level dollar splice as well. 38 | */ 39 | top_splice: $ => $.expression, 40 | 41 | quoter: $ => $._varids, 42 | 43 | /** 44 | * `_cond_quote_start` (in `quote_bracket`) is a zero-width token emitted by the scanner. 45 | * While the quoter and the bar may not be preceded by whitespace, this is not necessary to ensure here with 46 | * `token.immediate` since the scanner already verifies it. 47 | */ 48 | quasiquote: $ => seq( 49 | quote_bracket($, $.quoter), 50 | optional(field('body', $.quasiquote_body)), 51 | choice(token('|]'), '⟧'), 52 | ), 53 | 54 | quoted_decls: $ => layout_sort($, $._cmd_layout_start_quote, field('declaration', $.declaration)), 55 | 56 | /** 57 | * An "expression quotation" is valid in an expression, and its body may contain an expression, type, pattern or 58 | * declaration layout. 59 | * 60 | * Which of these are valid is decided by the quoter: `e`, `t`, `p` or `d`. 61 | * If the quoter is empty, or the special oxford bracket character is used, the body is parsed as an expression. 62 | */ 63 | _exp_quote: $ => seq( 64 | choice( 65 | seq(choice('⟦', quote_bracket($, optional('e'))), optional(alias($._exp, $.quoted_expression))), 66 | seq(quote_bracket($, 't'), optional(alias($._ktype, $.quoted_type))), 67 | seq(quote_bracket($, 'p'), optional(alias($._pat, $.quoted_pattern))), 68 | seq(quote_bracket($, 'd'), optional($.quoted_decls)), 69 | ), 70 | choice(token('|]'), '⟧'), 71 | ), 72 | 73 | _exp_typed_quote: $ => seq( 74 | $._cond_quote_start, 75 | '[', 76 | optional('e'), 77 | '||', 78 | optional(alias($._exp, $.quoted_expression)), 79 | token('||]'), 80 | ), 81 | 82 | } 83 | -------------------------------------------------------------------------------- /grammar/util.js: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // structure 3 | // ------------------------------------------------------------------------ 4 | 5 | const sep1 = (s, rule) => seq(rule, repeat(seq(s, rule))) 6 | 7 | const sep2 = (s, rule) => seq(rule, repeat1(seq(s, rule))) 8 | 9 | const sep = (s, rule) => optional(sep1(s, rule)) 10 | 11 | // ------------------------------------------------------------------------ 12 | // syntax 13 | // ------------------------------------------------------------------------ 14 | 15 | const parens = ($, ...rule) => seq($._paren_open, ...rule, $._paren_close) 16 | 17 | const braces = ($, ...rule) => seq('{', $._cmd_brace_open, ...rule, '}', $._cmd_brace_close) 18 | 19 | const brackets = ($, ...rule) => seq($._bracket_open, ...rule, $._bracket_close) 20 | 21 | const ticked = (...rule) => seq('`', ...rule, '`') 22 | 23 | const promoted = (...rule) => seq('\'', ...rule) 24 | 25 | const prefix_at = ($, ...rule) => prec('prefix', seq($._prefix_at, ...rule)) 26 | 27 | const semi = $ => choice(repeat1(';'), $._cond_layout_semicolon) 28 | 29 | const semi_opt = $ => optional(semi($)) 30 | 31 | const semis = ($, rule) => sep1(semi($), rule) 32 | 33 | // ------------------------------------------------------------------------ 34 | // layout 35 | // ------------------------------------------------------------------------ 36 | 37 | /** 38 | * More general variant of `layout_sort`. 39 | */ 40 | const layout_sort_single = ($, start, rule) => seq( 41 | choice(start, alias($._cmd_layout_start_explicit, '{')), 42 | rule, 43 | $._layout_end, 44 | ) 45 | 46 | /** 47 | * Wrap a repeated rule in a layout. 48 | * This is used for `where`, `let`, `of`, `if` and `do`, and the toplevel module. 49 | * The `start` rule must be one of the externals starting with `_cmd_layout_`, which instruct the scanner to push 50 | * a layout context with the current column as its indentation. 51 | * When a `_cond_layout_end` or `_cond_layout_semicolon` is encountered by the scanner, the recorded indent is compared 52 | * to the current one to make a decision. 53 | */ 54 | const layout_sort = ($, start, rule) => seq( 55 | choice(start, alias($._cmd_layout_start_explicit, '{')), 56 | optional(seq( 57 | semi_opt($), 58 | semis($, rule), 59 | semi_opt($), 60 | )), 61 | $._layout_end, 62 | ) 63 | 64 | /** 65 | * Same as `layout`, but using `layout_sort_single`. 66 | * This is necessary for braces without repeating layout elements. 67 | * Usually it is enough to just use `braces` for this (e.g. records), but if the rule is in a choice with a full 68 | * layout, we need to allow the layout start token since the scanner emits that unconditionally based on preceding 69 | * tokens. 70 | */ 71 | const layout_single = ($, rule) => layout_sort_single($, $._cmd_layout_start, rule) 72 | 73 | /** 74 | * Alias for `layout_sort` using the common layout type for the start token, which corresponds to declarations and GADT 75 | * constructors. 76 | */ 77 | const layout = ($, rule) => layout_sort($, $._cmd_layout_start, rule) 78 | 79 | // ------------------------------------------------------------------------ 80 | // unboxed 81 | // ------------------------------------------------------------------------ 82 | 83 | const unboxed = ($, ...rules) => seq($._unboxed_open, ...rules, $._unboxed_close) 84 | 85 | /** 86 | * At least one element is filled, for expressions. 87 | */ 88 | const unboxed_tuple_nonempty = ($, rule) => unboxed( 89 | $, 90 | repeat(','), 91 | field('element', rule), 92 | repeat(seq(',', optional(field('element', rule)))) 93 | ) 94 | 95 | /** 96 | * All elements are filled in, for types and patterns. 97 | */ 98 | const unboxed_tuple_full = ($, rule) => unboxed($, sep1(',', field('element', rule))) 99 | 100 | /** 101 | * Exactly one element is filled in, used by expressions, patterns and the special data constructors. 102 | */ 103 | const unboxed_sum_single = ($, rule) => unboxed( 104 | $, 105 | choice( 106 | seq(repeat1($._unboxed_bar), field('element', rule)), 107 | seq(field('element', rule), $._unboxed_bar) 108 | ), 109 | repeat($._unboxed_bar), 110 | ) 111 | 112 | /** 113 | * All elements are filled in, for types. 114 | */ 115 | const unboxed_sum_full = ($, rule) => unboxed($, sep2($._unboxed_bar, field('element', rule))) 116 | 117 | // ------------------------------------------------------------------------ 118 | // where 119 | // ------------------------------------------------------------------------ 120 | 121 | const optional_where = ($, rule) => optional(seq($._where, optional(rule))) 122 | 123 | // ------------------------------------------------------------------------ 124 | // misc 125 | // ------------------------------------------------------------------------ 126 | 127 | const qualified = ($, id) => prec('qualified-id', seq( 128 | field('module', alias($._qualifying_module, $.module)), 129 | field('id', id), 130 | )) 131 | 132 | const context = $ => optional(field('context', $.context)) 133 | 134 | const forall = $ => optional(field('forall', $._forall)) 135 | 136 | module.exports = { 137 | sep1, 138 | sep2, 139 | sep, 140 | parens, 141 | braces, 142 | brackets, 143 | ticked, 144 | promoted, 145 | prefix_at, 146 | semi, 147 | semi_opt, 148 | semis, 149 | layout_sort_single, 150 | layout_sort, 151 | layout_single, 152 | layout, 153 | unboxed, 154 | unboxed_tuple_nonempty, 155 | unboxed_tuple_full, 156 | unboxed_sum_single, 157 | unboxed_sum_full, 158 | optional_where, 159 | qualified, 160 | context, 161 | forall, 162 | } 163 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tree-sitter-haskell", 3 | "version": "0.23.1", 4 | "description": "Haskell grammar for tree-sitter", 5 | "repository": "https://github.com/tree-sitter/tree-sitter-haskell", 6 | "license": "MIT", 7 | "author": { 8 | "name": "Rick Winfrey" 9 | }, 10 | "contributors": [ 11 | { 12 | "name": "Max Brunsfeld", 13 | "email": "maxbrunsfeld@gmail.com" 14 | }, 15 | { 16 | "name": "Owen Shepherd" 17 | }, 18 | { 19 | "name": "Torsten Schmits" 20 | } 21 | ], 22 | "main": "bindings/node", 23 | "types": "bindings/node", 24 | "keywords": [ 25 | "incremental", 26 | "parsing", 27 | "tree-sitter", 28 | "haskell" 29 | ], 30 | "files": [ 31 | "grammar.js", 32 | "grammar/*.js", 33 | "tree-sitter.json", 34 | "binding.gyp", 35 | "prebuilds/**", 36 | "bindings/node/*", 37 | "queries/*", 38 | "src/**", 39 | "*.wasm" 40 | ], 41 | "dependencies": { 42 | "node-addon-api": "^8.2.2", 43 | "node-gyp-build": "^4.8.2" 44 | }, 45 | "devDependencies": { 46 | "prebuildify": "^6.0.1", 47 | "tree-sitter-cli": "^0.24.4" 48 | }, 49 | "peerDependencies": { 50 | "tree-sitter": "^0.21.1" 51 | }, 52 | "peerDependenciesMeta": { 53 | "tree-sitter": { 54 | "optional": true 55 | } 56 | }, 57 | "scripts": { 58 | "install": "node-gyp-build", 59 | "prestart": "tree-sitter build --wasm", 60 | "start": "tree-sitter playground", 61 | "test": "node --test bindings/node/*_test.js" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=42", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "tree-sitter-haskell" 7 | description = "Haskell grammar for tree-sitter" 8 | version = "0.23.1" 9 | keywords = ["incremental", "parsing", "tree-sitter", "haskell"] 10 | classifiers = [ 11 | "Intended Audience :: Developers", 12 | "License :: OSI Approved :: MIT License", 13 | "Topic :: Software Development :: Compilers", 14 | "Topic :: Text Processing :: Linguistic", 15 | "Typing :: Typed", 16 | ] 17 | requires-python = ">=3.9" 18 | license.text = "MIT" 19 | readme = "README.md" 20 | 21 | [[project.authors]] 22 | name = "Rick Winfrey" 23 | 24 | [[project.maintainers]] 25 | name = "Torsten Schmits" 26 | 27 | [project.urls] 28 | Homepage = "https://github.com/tree-sitter/tree-sitter-haskell" 29 | 30 | [project.optional-dependencies] 31 | core = ["tree-sitter~=0.22"] 32 | 33 | [tool.cibuildwheel] 34 | build = "cp39-*" 35 | build-frontend = "build" 36 | -------------------------------------------------------------------------------- /queries/highlights.scm: -------------------------------------------------------------------------------- 1 | ; ---------------------------------------------------------------------------- 2 | ; Parameters and variables 3 | ; NOTE: These are at the top, so that they have low priority, 4 | ; and don't override destructured parameters 5 | (variable) @variable 6 | 7 | (pattern/wildcard) @variable 8 | 9 | (decl/function 10 | patterns: (patterns 11 | (_) @variable.parameter)) 12 | 13 | (expression/lambda 14 | (_)+ @variable.parameter 15 | "->") 16 | 17 | (decl/function 18 | (infix 19 | (pattern) @variable.parameter)) 20 | 21 | ; ---------------------------------------------------------------------------- 22 | ; Literals and comments 23 | (integer) @number 24 | 25 | (negation) @number 26 | 27 | (expression/literal 28 | (float)) @number.float 29 | 30 | (char) @character 31 | 32 | (string) @string 33 | 34 | (unit) @string.special.symbol ; unit, as in () 35 | 36 | (comment) @comment 37 | 38 | ((haddock) @comment.documentation) 39 | 40 | ; ---------------------------------------------------------------------------- 41 | ; Punctuation 42 | [ 43 | "(" 44 | ")" 45 | "{" 46 | "}" 47 | "[" 48 | "]" 49 | ] @punctuation.bracket 50 | 51 | [ 52 | "," 53 | ";" 54 | ] @punctuation.delimiter 55 | 56 | ; ---------------------------------------------------------------------------- 57 | ; Keywords, operators, includes 58 | [ 59 | "forall" 60 | ; "∀" ; utf-8 is not cross-platform safe 61 | ] @keyword.repeat 62 | 63 | (pragma) @keyword.directive 64 | 65 | [ 66 | "if" 67 | "then" 68 | "else" 69 | "case" 70 | "of" 71 | ] @keyword.conditional 72 | 73 | [ 74 | "import" 75 | "qualified" 76 | "module" 77 | ] @keyword.import 78 | 79 | [ 80 | (operator) 81 | (constructor_operator) 82 | (all_names) 83 | (wildcard) 84 | "." 85 | ".." 86 | "=" 87 | "|" 88 | "::" 89 | "=>" 90 | "->" 91 | "<-" 92 | "\\" 93 | "`" 94 | "@" 95 | ] @operator 96 | 97 | ; TODO broken, also huh? 98 | ; ((qualified_module 99 | ; (module) @constructor) 100 | ; . 101 | ; (module)) 102 | 103 | (module 104 | (module_id) @module) 105 | 106 | [ 107 | "where" 108 | "let" 109 | "in" 110 | "class" 111 | "instance" 112 | "pattern" 113 | "data" 114 | "newtype" 115 | "family" 116 | "type" 117 | "as" 118 | "hiding" 119 | "deriving" 120 | "via" 121 | "stock" 122 | "anyclass" 123 | "do" 124 | "mdo" 125 | "rec" 126 | "infix" 127 | "infixl" 128 | "infixr" 129 | ] @keyword 130 | 131 | ; ---------------------------------------------------------------------------- 132 | ; Functions and variables 133 | (decl 134 | [ 135 | name: (variable) @function 136 | names: (binding_list (variable) @function) 137 | ]) 138 | 139 | (decl/bind 140 | name: (variable) @variable) 141 | 142 | ; Consider signatures (and accompanying functions) 143 | ; with only one value on the rhs as variables 144 | (decl/signature 145 | name: (variable) @variable 146 | type: (type)) 147 | 148 | ((decl/signature 149 | name: (variable) @_name 150 | type: (type)) 151 | . 152 | (decl 153 | name: (variable) @variable) 154 | match: (_) 155 | (#eq? @_name @variable)) 156 | 157 | ; but consider a type that involves 'IO' a decl/function 158 | (decl/signature 159 | name: (variable) @function 160 | type: (type/apply 161 | constructor: (name) @_type) 162 | (#eq? @_type "IO")) 163 | 164 | ((decl/signature 165 | name: (variable) @_name 166 | type: (type/apply 167 | constructor: (name) @_type) 168 | (#eq? @_type "IO")) 169 | . 170 | (decl 171 | name: (variable) @function) 172 | match: (_) 173 | (#eq? @_name @function)) 174 | 175 | ((decl/signature) @function 176 | . 177 | (decl/function 178 | name: (variable) @function)) 179 | 180 | (decl/bind 181 | name: (variable) @function 182 | (match 183 | expression: (expression/lambda))) 184 | 185 | ; view patterns 186 | (view_pattern 187 | [ 188 | (expression/variable) @function.call 189 | (expression/qualified 190 | (variable) @function.call) 191 | ]) 192 | 193 | ; consider infix functions as operators 194 | (infix_id 195 | [ 196 | (variable) @operator 197 | (qualified 198 | (variable) @operator) 199 | ]) 200 | 201 | ; decl/function calls with an infix operator 202 | ; e.g. func <$> a <*> b 203 | (infix 204 | [ 205 | (variable) @function.call 206 | (qualified 207 | ((module) @module 208 | (variable) @function.call)) 209 | ] 210 | . 211 | (operator)) 212 | 213 | ; infix operators applied to variables 214 | ((expression/variable) @variable 215 | . 216 | (operator)) 217 | 218 | ((operator) 219 | . 220 | [ 221 | (expression/variable) @variable 222 | (expression/qualified 223 | (variable) @variable) 224 | ]) 225 | 226 | ; decl/function calls with infix operators 227 | ([ 228 | (expression/variable) @function.call 229 | (expression/qualified 230 | (variable) @function.call) 231 | ] 232 | . 233 | (operator) @_op 234 | (#any-of? @_op "$" "<$>" ">>=" "=<<")) 235 | 236 | ; right hand side of infix operator 237 | ((infix 238 | [ 239 | (operator) 240 | (infix_id (variable)) 241 | ] ; infix or `func` 242 | . 243 | [ 244 | (variable) @function.call 245 | (qualified 246 | (variable) @function.call) 247 | ]) 248 | . 249 | (operator) @_op 250 | (#any-of? @_op "$" "<$>" "=<<")) 251 | 252 | ; decl/function composition, arrows, monadic composition (lhs) 253 | ( 254 | [ 255 | (expression/variable) @function 256 | (expression/qualified 257 | (variable) @function) 258 | ] 259 | . 260 | (operator) @_op 261 | (#any-of? @_op "." ">>>" "***" ">=>" "<=<")) 262 | 263 | ; right hand side of infix operator 264 | ((infix 265 | [ 266 | (operator) 267 | (infix_id (variable)) 268 | ] ; infix or `func` 269 | . 270 | [ 271 | (variable) @function 272 | (qualified 273 | (variable) @function) 274 | ]) 275 | . 276 | (operator) @_op 277 | (#any-of? @_op "." ">>>" "***" ">=>" "<=<")) 278 | 279 | ; function composition, arrows, monadic composition (rhs) 280 | ((operator) @_op 281 | . 282 | [ 283 | (expression/variable) @function 284 | (expression/qualified 285 | (variable) @function) 286 | ] 287 | (#any-of? @_op "." ">>>" "***" ">=>" "<=<")) 288 | 289 | ; function defined in terms of a function composition 290 | (decl/function 291 | name: (variable) @function 292 | (match 293 | expression: (infix 294 | operator: (operator) @_op 295 | (#any-of? @_op "." ">>>" "***" ">=>" "<=<")))) 296 | 297 | (apply 298 | [ 299 | (expression/variable) @function.call 300 | (expression/qualified 301 | (variable) @function.call) 302 | ]) 303 | 304 | ; function compositions, in parentheses, applied 305 | ; lhs 306 | (apply 307 | . 308 | (expression/parens 309 | (infix 310 | [ 311 | (variable) @function.call 312 | (qualified 313 | (variable) @function.call) 314 | ] 315 | . 316 | (operator)))) 317 | 318 | ; rhs 319 | (apply 320 | . 321 | (expression/parens 322 | (infix 323 | (operator) 324 | . 325 | [ 326 | (variable) @function.call 327 | (qualified 328 | (variable) @function.call) 329 | ]))) 330 | 331 | ; variables being passed to a function call 332 | (apply 333 | (_) 334 | . 335 | [ 336 | (expression/variable) @variable 337 | (expression/qualified 338 | (variable) @variable) 339 | ]) 340 | 341 | ; main is always a function 342 | ; (this prevents `main = undefined` from being highlighted as a variable) 343 | (decl/bind 344 | name: (variable) @function 345 | (#eq? @function "main")) 346 | 347 | ; scoped function types (func :: a -> b) 348 | (signature 349 | pattern: (pattern/variable) @function 350 | type: (quantified_type)) 351 | 352 | ; signatures that have a function type 353 | ; + binds that follow them 354 | (decl/signature 355 | name: (variable) @function 356 | type: (quantified_type)) 357 | 358 | ((decl/signature 359 | name: (variable) @_name 360 | type: (quantified_type)) 361 | . 362 | (decl/bind 363 | (variable) @function) 364 | (#eq? @function @_name)) 365 | 366 | ; ---------------------------------------------------------------------------- 367 | ; Types 368 | (name) @type 369 | 370 | (type/star) @type 371 | 372 | (variable) @type 373 | 374 | (constructor) @constructor 375 | 376 | ; True or False 377 | ((constructor) @boolean 378 | (#any-of? @boolean "True" "False")) 379 | 380 | ; otherwise (= True) 381 | ((variable) @boolean 382 | (#eq? @boolean "otherwise")) 383 | 384 | ; ---------------------------------------------------------------------------- 385 | ; Quasi-quotes 386 | (quoter) @function.call 387 | 388 | (quasiquote 389 | [ 390 | (quoter) @_name 391 | (_ 392 | (variable) @_name) 393 | ] 394 | (#eq? @_name "qq") 395 | (quasiquote_body) @string) 396 | 397 | (quasiquote 398 | (_ 399 | (variable) @_name) 400 | (#eq? @_name "qq") 401 | (quasiquote_body) @string) 402 | 403 | ; namespaced quasi-quoter 404 | (quasiquote 405 | (_ 406 | (module) @module 407 | . 408 | (variable) @function.call)) 409 | 410 | ; Highlighting of quasiquote_body for other languages is handled by injections.scm 411 | ; ---------------------------------------------------------------------------- 412 | ; Exceptions/error handling 413 | ((variable) @keyword.exception 414 | (#any-of? @keyword.exception 415 | "error" "undefined" "try" "tryJust" "tryAny" "catch" "catches" "catchJust" "handle" "handleJust" 416 | "throw" "throwIO" "throwTo" "throwError" "ioError" "mask" "mask_" "uninterruptibleMask" 417 | "uninterruptibleMask_" "bracket" "bracket_" "bracketOnErrorSource" "finally" "fail" 418 | "onException" "expectationFailure")) 419 | 420 | ; ---------------------------------------------------------------------------- 421 | ; Debugging 422 | ((variable) @keyword.debug 423 | (#any-of? @keyword.debug 424 | "trace" "traceId" "traceShow" "traceShowId" "traceWith" "traceShowWith" "traceStack" "traceIO" 425 | "traceM" "traceShowM" "traceEvent" "traceEventWith" "traceEventIO" "flushEventLog" "traceMarker" 426 | "traceMarkerIO")) 427 | 428 | ; ---------------------------------------------------------------------------- 429 | ; Fields 430 | 431 | (field_name 432 | (variable) @variable.member) 433 | 434 | (import_name 435 | (name) 436 | . 437 | (children 438 | (variable) @variable.member)) 439 | 440 | 441 | ; ---------------------------------------------------------------------------- 442 | ; Spell checking 443 | (comment) @spell 444 | -------------------------------------------------------------------------------- /queries/injections.scm: -------------------------------------------------------------------------------- 1 | ; ----------------------------------------------------------------------------- 2 | ; General language injection 3 | (quasiquote 4 | (quoter) @injection.language 5 | (quasiquote_body) @injection.content) 6 | 7 | ((comment) @injection.content 8 | (#set! injection.language "comment")) 9 | 10 | ; ----------------------------------------------------------------------------- 11 | ; shakespeare library 12 | ; NOTE: doesn't support templating 13 | ; TODO: add once CoffeeScript parser is added 14 | ; ; CoffeeScript: Text.Coffee 15 | ; (quasiquote 16 | ; (quoter) @_name 17 | ; (#eq? @_name "coffee") 18 | ; ((quasiquote_body) @injection.content 19 | ; (#set! injection.language "coffeescript"))) 20 | ; CSS: Text.Cassius, Text.Lucius 21 | (quasiquote 22 | (quoter) @_name 23 | (#any-of? @_name "cassius" "lucius") 24 | (quasiquote_body) @injection.content 25 | (#set! injection.language "css")) 26 | 27 | ; HTML: Text.Hamlet 28 | (quasiquote 29 | (quoter) @_name 30 | (#any-of? @_name "shamlet" "xshamlet" "hamlet" "xhamlet" "ihamlet") 31 | (quasiquote_body) @injection.content 32 | (#set! injection.language "html")) 33 | 34 | ; JS: Text.Julius 35 | (quasiquote 36 | (quoter) @_name 37 | (#any-of? @_name "js" "julius") 38 | (quasiquote_body) @injection.content 39 | (#set! injection.language "javascript")) 40 | 41 | ; TS: Text.TypeScript 42 | (quasiquote 43 | (quoter) @_name 44 | (#any-of? @_name "tsc" "tscJSX") 45 | (quasiquote_body) @injection.content 46 | (#set! injection.language "typescript")) 47 | 48 | ; ----------------------------------------------------------------------------- 49 | ; HSX 50 | (quasiquote 51 | (quoter) @_name 52 | (#eq? @_name "hsx") 53 | (quasiquote_body) @injection.content 54 | (#set! injection.language "html")) 55 | 56 | ; ----------------------------------------------------------------------------- 57 | ; Inline JSON from aeson 58 | (quasiquote 59 | (quoter) @_name 60 | (#eq? @_name "aesonQQ") 61 | (quasiquote_body) @injection.content 62 | (#set! injection.language "json")) 63 | 64 | ; ----------------------------------------------------------------------------- 65 | ; SQL 66 | ; postgresql-simple 67 | (quasiquote 68 | (quoter) @injection.language 69 | (#eq? @injection.language "sql") 70 | (quasiquote_body) @injection.content) 71 | 72 | (quasiquote 73 | (quoter) @_name 74 | (#any-of? @_name "persistUpperCase" "persistLowerCase" "persistWith") 75 | (quasiquote_body) @injection.content 76 | (#set! injection.language "haskell_persistent")) 77 | -------------------------------------------------------------------------------- /queries/locals.scm: -------------------------------------------------------------------------------- 1 | (signature name: (variable)) @local.definition 2 | (function name: (variable)) @local.definition 3 | (pattern/variable) @local.definition 4 | (expression/variable) @local.reference 5 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from os.path import isdir, join 2 | from platform import system 3 | 4 | from setuptools import Extension, find_packages, setup 5 | from setuptools.command.build import build 6 | from wheel.bdist_wheel import bdist_wheel 7 | 8 | 9 | class Build(build): 10 | def run(self): 11 | if isdir("queries"): 12 | dest = join(self.build_lib, "tree_sitter_haskell", "queries") 13 | self.copy_tree("queries", dest) 14 | super().run() 15 | 16 | 17 | class BdistWheel(bdist_wheel): 18 | def get_tag(self): 19 | python, abi, platform = super().get_tag() 20 | if python.startswith("cp"): 21 | python, abi = "cp39", "abi3" 22 | return python, abi, platform 23 | 24 | 25 | setup( 26 | packages=find_packages("bindings/python"), 27 | package_dir={"": "bindings/python"}, 28 | package_data={ 29 | "tree_sitter_haskell": ["*.pyi", "py.typed"], 30 | "tree_sitter_haskell.queries": ["*.scm"], 31 | }, 32 | ext_package="tree_sitter_haskell", 33 | ext_modules=[ 34 | Extension( 35 | name="_binding", 36 | sources=[ 37 | "bindings/python/tree_sitter_haskell/binding.c", 38 | "src/parser.c", 39 | "src/scanner.c", 40 | ], 41 | extra_compile_args=[ 42 | "-std=c11", 43 | "-fvisibility=hidden", 44 | ] if system() != "Windows" else [ 45 | "/std:c11", 46 | "/utf-8", 47 | ], 48 | define_macros=[ 49 | ("Py_LIMITED_API", "0x03090000"), 50 | ("PY_SSIZE_T_CLEAN", None), 51 | ("TREE_SITTER_HIDE_SYMBOLS", None), 52 | ], 53 | include_dirs=["src"], 54 | py_limited_api=True, 55 | ) 56 | ], 57 | cmdclass={ 58 | "build": Build, 59 | "bdist_wheel": BdistWheel 60 | }, 61 | zip_safe=False 62 | ) 63 | -------------------------------------------------------------------------------- /src/tree_sitter/alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_ALLOC_H_ 2 | #define TREE_SITTER_ALLOC_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | // Allow clients to override allocation functions 13 | #ifdef TREE_SITTER_REUSE_ALLOCATOR 14 | 15 | extern void *(*ts_current_malloc)(size_t size); 16 | extern void *(*ts_current_calloc)(size_t count, size_t size); 17 | extern void *(*ts_current_realloc)(void *ptr, size_t size); 18 | extern void (*ts_current_free)(void *ptr); 19 | 20 | #ifndef ts_malloc 21 | #define ts_malloc ts_current_malloc 22 | #endif 23 | #ifndef ts_calloc 24 | #define ts_calloc ts_current_calloc 25 | #endif 26 | #ifndef ts_realloc 27 | #define ts_realloc ts_current_realloc 28 | #endif 29 | #ifndef ts_free 30 | #define ts_free ts_current_free 31 | #endif 32 | 33 | #else 34 | 35 | #ifndef ts_malloc 36 | #define ts_malloc malloc 37 | #endif 38 | #ifndef ts_calloc 39 | #define ts_calloc calloc 40 | #endif 41 | #ifndef ts_realloc 42 | #define ts_realloc realloc 43 | #endif 44 | #ifndef ts_free 45 | #define ts_free free 46 | #endif 47 | 48 | #endif 49 | 50 | #ifdef __cplusplus 51 | } 52 | #endif 53 | 54 | #endif // TREE_SITTER_ALLOC_H_ 55 | -------------------------------------------------------------------------------- /src/tree_sitter/array.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_ARRAY_H_ 2 | #define TREE_SITTER_ARRAY_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include "./alloc.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #ifdef _MSC_VER 17 | #pragma warning(disable : 4101) 18 | #elif defined(__GNUC__) || defined(__clang__) 19 | #pragma GCC diagnostic push 20 | #pragma GCC diagnostic ignored "-Wunused-variable" 21 | #endif 22 | 23 | #define Array(T) \ 24 | struct { \ 25 | T *contents; \ 26 | uint32_t size; \ 27 | uint32_t capacity; \ 28 | } 29 | 30 | /// Initialize an array. 31 | #define array_init(self) \ 32 | ((self)->size = 0, (self)->capacity = 0, (self)->contents = NULL) 33 | 34 | /// Create an empty array. 35 | #define array_new() \ 36 | { NULL, 0, 0 } 37 | 38 | /// Get a pointer to the element at a given `index` in the array. 39 | #define array_get(self, _index) \ 40 | (assert((uint32_t)(_index) < (self)->size), &(self)->contents[_index]) 41 | 42 | /// Get a pointer to the first element in the array. 43 | #define array_front(self) array_get(self, 0) 44 | 45 | /// Get a pointer to the last element in the array. 46 | #define array_back(self) array_get(self, (self)->size - 1) 47 | 48 | /// Clear the array, setting its size to zero. Note that this does not free any 49 | /// memory allocated for the array's contents. 50 | #define array_clear(self) ((self)->size = 0) 51 | 52 | /// Reserve `new_capacity` elements of space in the array. If `new_capacity` is 53 | /// less than the array's current capacity, this function has no effect. 54 | #define array_reserve(self, new_capacity) \ 55 | _array__reserve((Array *)(self), array_elem_size(self), new_capacity) 56 | 57 | /// Free any memory allocated for this array. Note that this does not free any 58 | /// memory allocated for the array's contents. 59 | #define array_delete(self) _array__delete((Array *)(self)) 60 | 61 | /// Push a new `element` onto the end of the array. 62 | #define array_push(self, element) \ 63 | (_array__grow((Array *)(self), 1, array_elem_size(self)), \ 64 | (self)->contents[(self)->size++] = (element)) 65 | 66 | /// Increase the array's size by `count` elements. 67 | /// New elements are zero-initialized. 68 | #define array_grow_by(self, count) \ 69 | do { \ 70 | if ((count) == 0) break; \ 71 | _array__grow((Array *)(self), count, array_elem_size(self)); \ 72 | memset((self)->contents + (self)->size, 0, (count) * array_elem_size(self)); \ 73 | (self)->size += (count); \ 74 | } while (0) 75 | 76 | /// Append all elements from one array to the end of another. 77 | #define array_push_all(self, other) \ 78 | array_extend((self), (other)->size, (other)->contents) 79 | 80 | /// Append `count` elements to the end of the array, reading their values from the 81 | /// `contents` pointer. 82 | #define array_extend(self, count, contents) \ 83 | _array__splice( \ 84 | (Array *)(self), array_elem_size(self), (self)->size, \ 85 | 0, count, contents \ 86 | ) 87 | 88 | /// Remove `old_count` elements from the array starting at the given `index`. At 89 | /// the same index, insert `new_count` new elements, reading their values from the 90 | /// `new_contents` pointer. 91 | #define array_splice(self, _index, old_count, new_count, new_contents) \ 92 | _array__splice( \ 93 | (Array *)(self), array_elem_size(self), _index, \ 94 | old_count, new_count, new_contents \ 95 | ) 96 | 97 | /// Insert one `element` into the array at the given `index`. 98 | #define array_insert(self, _index, element) \ 99 | _array__splice((Array *)(self), array_elem_size(self), _index, 0, 1, &(element)) 100 | 101 | /// Remove one element from the array at the given `index`. 102 | #define array_erase(self, _index) \ 103 | _array__erase((Array *)(self), array_elem_size(self), _index) 104 | 105 | /// Pop the last element off the array, returning the element by value. 106 | #define array_pop(self) ((self)->contents[--(self)->size]) 107 | 108 | /// Assign the contents of one array to another, reallocating if necessary. 109 | #define array_assign(self, other) \ 110 | _array__assign((Array *)(self), (const Array *)(other), array_elem_size(self)) 111 | 112 | /// Swap one array with another 113 | #define array_swap(self, other) \ 114 | _array__swap((Array *)(self), (Array *)(other)) 115 | 116 | /// Get the size of the array contents 117 | #define array_elem_size(self) (sizeof *(self)->contents) 118 | 119 | /// Search a sorted array for a given `needle` value, using the given `compare` 120 | /// callback to determine the order. 121 | /// 122 | /// If an existing element is found to be equal to `needle`, then the `index` 123 | /// out-parameter is set to the existing value's index, and the `exists` 124 | /// out-parameter is set to true. Otherwise, `index` is set to an index where 125 | /// `needle` should be inserted in order to preserve the sorting, and `exists` 126 | /// is set to false. 127 | #define array_search_sorted_with(self, compare, needle, _index, _exists) \ 128 | _array__search_sorted(self, 0, compare, , needle, _index, _exists) 129 | 130 | /// Search a sorted array for a given `needle` value, using integer comparisons 131 | /// of a given struct field (specified with a leading dot) to determine the order. 132 | /// 133 | /// See also `array_search_sorted_with`. 134 | #define array_search_sorted_by(self, field, needle, _index, _exists) \ 135 | _array__search_sorted(self, 0, _compare_int, field, needle, _index, _exists) 136 | 137 | /// Insert a given `value` into a sorted array, using the given `compare` 138 | /// callback to determine the order. 139 | #define array_insert_sorted_with(self, compare, value) \ 140 | do { \ 141 | unsigned _index, _exists; \ 142 | array_search_sorted_with(self, compare, &(value), &_index, &_exists); \ 143 | if (!_exists) array_insert(self, _index, value); \ 144 | } while (0) 145 | 146 | /// Insert a given `value` into a sorted array, using integer comparisons of 147 | /// a given struct field (specified with a leading dot) to determine the order. 148 | /// 149 | /// See also `array_search_sorted_by`. 150 | #define array_insert_sorted_by(self, field, value) \ 151 | do { \ 152 | unsigned _index, _exists; \ 153 | array_search_sorted_by(self, field, (value) field, &_index, &_exists); \ 154 | if (!_exists) array_insert(self, _index, value); \ 155 | } while (0) 156 | 157 | // Private 158 | 159 | typedef Array(void) Array; 160 | 161 | /// This is not what you're looking for, see `array_delete`. 162 | static inline void _array__delete(Array *self) { 163 | if (self->contents) { 164 | ts_free(self->contents); 165 | self->contents = NULL; 166 | self->size = 0; 167 | self->capacity = 0; 168 | } 169 | } 170 | 171 | /// This is not what you're looking for, see `array_erase`. 172 | static inline void _array__erase(Array *self, size_t element_size, 173 | uint32_t index) { 174 | assert(index < self->size); 175 | char *contents = (char *)self->contents; 176 | memmove(contents + index * element_size, contents + (index + 1) * element_size, 177 | (self->size - index - 1) * element_size); 178 | self->size--; 179 | } 180 | 181 | /// This is not what you're looking for, see `array_reserve`. 182 | static inline void _array__reserve(Array *self, size_t element_size, uint32_t new_capacity) { 183 | if (new_capacity > self->capacity) { 184 | if (self->contents) { 185 | self->contents = ts_realloc(self->contents, new_capacity * element_size); 186 | } else { 187 | self->contents = ts_malloc(new_capacity * element_size); 188 | } 189 | self->capacity = new_capacity; 190 | } 191 | } 192 | 193 | /// This is not what you're looking for, see `array_assign`. 194 | static inline void _array__assign(Array *self, const Array *other, size_t element_size) { 195 | _array__reserve(self, element_size, other->size); 196 | self->size = other->size; 197 | memcpy(self->contents, other->contents, self->size * element_size); 198 | } 199 | 200 | /// This is not what you're looking for, see `array_swap`. 201 | static inline void _array__swap(Array *self, Array *other) { 202 | Array swap = *other; 203 | *other = *self; 204 | *self = swap; 205 | } 206 | 207 | /// This is not what you're looking for, see `array_push` or `array_grow_by`. 208 | static inline void _array__grow(Array *self, uint32_t count, size_t element_size) { 209 | uint32_t new_size = self->size + count; 210 | if (new_size > self->capacity) { 211 | uint32_t new_capacity = self->capacity * 2; 212 | if (new_capacity < 8) new_capacity = 8; 213 | if (new_capacity < new_size) new_capacity = new_size; 214 | _array__reserve(self, element_size, new_capacity); 215 | } 216 | } 217 | 218 | /// This is not what you're looking for, see `array_splice`. 219 | static inline void _array__splice(Array *self, size_t element_size, 220 | uint32_t index, uint32_t old_count, 221 | uint32_t new_count, const void *elements) { 222 | uint32_t new_size = self->size + new_count - old_count; 223 | uint32_t old_end = index + old_count; 224 | uint32_t new_end = index + new_count; 225 | assert(old_end <= self->size); 226 | 227 | _array__reserve(self, element_size, new_size); 228 | 229 | char *contents = (char *)self->contents; 230 | if (self->size > old_end) { 231 | memmove( 232 | contents + new_end * element_size, 233 | contents + old_end * element_size, 234 | (self->size - old_end) * element_size 235 | ); 236 | } 237 | if (new_count > 0) { 238 | if (elements) { 239 | memcpy( 240 | (contents + index * element_size), 241 | elements, 242 | new_count * element_size 243 | ); 244 | } else { 245 | memset( 246 | (contents + index * element_size), 247 | 0, 248 | new_count * element_size 249 | ); 250 | } 251 | } 252 | self->size += new_count - old_count; 253 | } 254 | 255 | /// A binary search routine, based on Rust's `std::slice::binary_search_by`. 256 | /// This is not what you're looking for, see `array_search_sorted_with` or `array_search_sorted_by`. 257 | #define _array__search_sorted(self, start, compare, suffix, needle, _index, _exists) \ 258 | do { \ 259 | *(_index) = start; \ 260 | *(_exists) = false; \ 261 | uint32_t size = (self)->size - *(_index); \ 262 | if (size == 0) break; \ 263 | int comparison; \ 264 | while (size > 1) { \ 265 | uint32_t half_size = size / 2; \ 266 | uint32_t mid_index = *(_index) + half_size; \ 267 | comparison = compare(&((self)->contents[mid_index] suffix), (needle)); \ 268 | if (comparison <= 0) *(_index) = mid_index; \ 269 | size -= half_size; \ 270 | } \ 271 | comparison = compare(&((self)->contents[*(_index)] suffix), (needle)); \ 272 | if (comparison == 0) *(_exists) = true; \ 273 | else if (comparison < 0) *(_index) += 1; \ 274 | } while (0) 275 | 276 | /// Helper macro for the `_sorted_by` routines below. This takes the left (existing) 277 | /// parameter by reference in order to work with the generic sorting function above. 278 | #define _compare_int(a, b) ((int)*(a) - (int)(b)) 279 | 280 | #ifdef _MSC_VER 281 | #pragma warning(default : 4101) 282 | #elif defined(__GNUC__) || defined(__clang__) 283 | #pragma GCC diagnostic pop 284 | #endif 285 | 286 | #ifdef __cplusplus 287 | } 288 | #endif 289 | 290 | #endif // TREE_SITTER_ARRAY_H_ 291 | -------------------------------------------------------------------------------- /src/tree_sitter/parser.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_PARSER_H_ 2 | #define TREE_SITTER_PARSER_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #define ts_builtin_sym_error ((TSSymbol)-1) 13 | #define ts_builtin_sym_end 0 14 | #define TREE_SITTER_SERIALIZATION_BUFFER_SIZE 1024 15 | 16 | #ifndef TREE_SITTER_API_H_ 17 | typedef uint16_t TSStateId; 18 | typedef uint16_t TSSymbol; 19 | typedef uint16_t TSFieldId; 20 | typedef struct TSLanguage TSLanguage; 21 | #endif 22 | 23 | typedef struct { 24 | TSFieldId field_id; 25 | uint8_t child_index; 26 | bool inherited; 27 | } TSFieldMapEntry; 28 | 29 | typedef struct { 30 | uint16_t index; 31 | uint16_t length; 32 | } TSFieldMapSlice; 33 | 34 | typedef struct { 35 | bool visible; 36 | bool named; 37 | bool supertype; 38 | } TSSymbolMetadata; 39 | 40 | typedef struct TSLexer TSLexer; 41 | 42 | struct TSLexer { 43 | int32_t lookahead; 44 | TSSymbol result_symbol; 45 | void (*advance)(TSLexer *, bool); 46 | void (*mark_end)(TSLexer *); 47 | uint32_t (*get_column)(TSLexer *); 48 | bool (*is_at_included_range_start)(const TSLexer *); 49 | bool (*eof)(const TSLexer *); 50 | void (*log)(const TSLexer *, const char *, ...); 51 | }; 52 | 53 | typedef enum { 54 | TSParseActionTypeShift, 55 | TSParseActionTypeReduce, 56 | TSParseActionTypeAccept, 57 | TSParseActionTypeRecover, 58 | } TSParseActionType; 59 | 60 | typedef union { 61 | struct { 62 | uint8_t type; 63 | TSStateId state; 64 | bool extra; 65 | bool repetition; 66 | } shift; 67 | struct { 68 | uint8_t type; 69 | uint8_t child_count; 70 | TSSymbol symbol; 71 | int16_t dynamic_precedence; 72 | uint16_t production_id; 73 | } reduce; 74 | uint8_t type; 75 | } TSParseAction; 76 | 77 | typedef struct { 78 | uint16_t lex_state; 79 | uint16_t external_lex_state; 80 | } TSLexMode; 81 | 82 | typedef union { 83 | TSParseAction action; 84 | struct { 85 | uint8_t count; 86 | bool reusable; 87 | } entry; 88 | } TSParseActionEntry; 89 | 90 | typedef struct { 91 | int32_t start; 92 | int32_t end; 93 | } TSCharacterRange; 94 | 95 | struct TSLanguage { 96 | uint32_t version; 97 | uint32_t symbol_count; 98 | uint32_t alias_count; 99 | uint32_t token_count; 100 | uint32_t external_token_count; 101 | uint32_t state_count; 102 | uint32_t large_state_count; 103 | uint32_t production_id_count; 104 | uint32_t field_count; 105 | uint16_t max_alias_sequence_length; 106 | const uint16_t *parse_table; 107 | const uint16_t *small_parse_table; 108 | const uint32_t *small_parse_table_map; 109 | const TSParseActionEntry *parse_actions; 110 | const char * const *symbol_names; 111 | const char * const *field_names; 112 | const TSFieldMapSlice *field_map_slices; 113 | const TSFieldMapEntry *field_map_entries; 114 | const TSSymbolMetadata *symbol_metadata; 115 | const TSSymbol *public_symbol_map; 116 | const uint16_t *alias_map; 117 | const TSSymbol *alias_sequences; 118 | const TSLexMode *lex_modes; 119 | bool (*lex_fn)(TSLexer *, TSStateId); 120 | bool (*keyword_lex_fn)(TSLexer *, TSStateId); 121 | TSSymbol keyword_capture_token; 122 | struct { 123 | const bool *states; 124 | const TSSymbol *symbol_map; 125 | void *(*create)(void); 126 | void (*destroy)(void *); 127 | bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist); 128 | unsigned (*serialize)(void *, char *); 129 | void (*deserialize)(void *, const char *, unsigned); 130 | } external_scanner; 131 | const TSStateId *primary_state_ids; 132 | }; 133 | 134 | static inline bool set_contains(TSCharacterRange *ranges, uint32_t len, int32_t lookahead) { 135 | uint32_t index = 0; 136 | uint32_t size = len - index; 137 | while (size > 1) { 138 | uint32_t half_size = size / 2; 139 | uint32_t mid_index = index + half_size; 140 | TSCharacterRange *range = &ranges[mid_index]; 141 | if (lookahead >= range->start && lookahead <= range->end) { 142 | return true; 143 | } else if (lookahead > range->end) { 144 | index = mid_index; 145 | } 146 | size -= half_size; 147 | } 148 | TSCharacterRange *range = &ranges[index]; 149 | return (lookahead >= range->start && lookahead <= range->end); 150 | } 151 | 152 | /* 153 | * Lexer Macros 154 | */ 155 | 156 | #ifdef _MSC_VER 157 | #define UNUSED __pragma(warning(suppress : 4101)) 158 | #else 159 | #define UNUSED __attribute__((unused)) 160 | #endif 161 | 162 | #define START_LEXER() \ 163 | bool result = false; \ 164 | bool skip = false; \ 165 | UNUSED \ 166 | bool eof = false; \ 167 | int32_t lookahead; \ 168 | goto start; \ 169 | next_state: \ 170 | lexer->advance(lexer, skip); \ 171 | start: \ 172 | skip = false; \ 173 | lookahead = lexer->lookahead; 174 | 175 | #define ADVANCE(state_value) \ 176 | { \ 177 | state = state_value; \ 178 | goto next_state; \ 179 | } 180 | 181 | #define ADVANCE_MAP(...) \ 182 | { \ 183 | static const uint16_t map[] = { __VA_ARGS__ }; \ 184 | for (uint32_t i = 0; i < sizeof(map) / sizeof(map[0]); i += 2) { \ 185 | if (map[i] == lookahead) { \ 186 | state = map[i + 1]; \ 187 | goto next_state; \ 188 | } \ 189 | } \ 190 | } 191 | 192 | #define SKIP(state_value) \ 193 | { \ 194 | skip = true; \ 195 | state = state_value; \ 196 | goto next_state; \ 197 | } 198 | 199 | #define ACCEPT_TOKEN(symbol_value) \ 200 | result = true; \ 201 | lexer->result_symbol = symbol_value; \ 202 | lexer->mark_end(lexer); 203 | 204 | #define END_STATE() return result; 205 | 206 | /* 207 | * Parse Table Macros 208 | */ 209 | 210 | #define SMALL_STATE(id) ((id) - LARGE_STATE_COUNT) 211 | 212 | #define STATE(id) id 213 | 214 | #define ACTIONS(id) id 215 | 216 | #define SHIFT(state_value) \ 217 | {{ \ 218 | .shift = { \ 219 | .type = TSParseActionTypeShift, \ 220 | .state = (state_value) \ 221 | } \ 222 | }} 223 | 224 | #define SHIFT_REPEAT(state_value) \ 225 | {{ \ 226 | .shift = { \ 227 | .type = TSParseActionTypeShift, \ 228 | .state = (state_value), \ 229 | .repetition = true \ 230 | } \ 231 | }} 232 | 233 | #define SHIFT_EXTRA() \ 234 | {{ \ 235 | .shift = { \ 236 | .type = TSParseActionTypeShift, \ 237 | .extra = true \ 238 | } \ 239 | }} 240 | 241 | #define REDUCE(symbol_name, children, precedence, prod_id) \ 242 | {{ \ 243 | .reduce = { \ 244 | .type = TSParseActionTypeReduce, \ 245 | .symbol = symbol_name, \ 246 | .child_count = children, \ 247 | .dynamic_precedence = precedence, \ 248 | .production_id = prod_id \ 249 | }, \ 250 | }} 251 | 252 | #define RECOVER() \ 253 | {{ \ 254 | .type = TSParseActionTypeRecover \ 255 | }} 256 | 257 | #define ACCEPT_INPUT() \ 258 | {{ \ 259 | .type = TSParseActionTypeAccept \ 260 | }} 261 | 262 | #ifdef __cplusplus 263 | } 264 | #endif 265 | 266 | #endif // TREE_SITTER_PARSER_H_ 267 | -------------------------------------------------------------------------------- /test/corpus/comment.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | comment: line 3 | ================================================================================ 4 | 5 | -- 6 | -- a 7 | -- 8 | -- a 9 | 10 | -------------------------------------------------------------------------------- 11 | 12 | (haskell 13 | (comment)) 14 | 15 | ================================================================================ 16 | comment: multi 17 | ================================================================================ 18 | 19 | {- a 20 | a 21 | - a 22 | -} 23 | f = a 24 | {-a-} 25 | 26 | -------------------------------------------------------------------------------- 27 | 28 | (haskell 29 | (comment) 30 | (declarations 31 | (bind 32 | (variable) 33 | (match 34 | (variable))) 35 | (comment))) 36 | 37 | ================================================================================ 38 | comment: hash inside 39 | ================================================================================ 40 | 41 | {- #comment -} 42 | 43 | -------------------------------------------------------------------------------- 44 | 45 | (haskell 46 | (comment)) 47 | 48 | ================================================================================ 49 | comment: newline termination 50 | ================================================================================ 51 | 52 | -- 53 | 54 | -------------------------------------------------------------------------------- 55 | 56 | (haskell 57 | (comment)) 58 | 59 | ================================================================================ 60 | comment: nested 61 | ================================================================================ 62 | 63 | {- comment 64 | {- nested 65 | -} 66 | } 67 | a = 68 | 69 | -} 70 | 71 | a = a 72 | 73 | -------------------------------------------------------------------------------- 74 | 75 | (haskell 76 | (comment) 77 | (declarations 78 | (bind 79 | (variable) 80 | (match 81 | (variable))))) 82 | 83 | ================================================================================ 84 | comment: unicode symbol 85 | ================================================================================ 86 | 87 | -- ∀ 88 | 89 | {- ∀ -} 90 | 91 | -------------------------------------------------------------------------------- 92 | 93 | (haskell 94 | (comment) 95 | (comment)) 96 | 97 | ================================================================================ 98 | comment: repeated minus before multiline end 99 | ================================================================================ 100 | 101 | module A where 102 | 103 | {- --} 104 | 105 | {- 106 | a 107 | -----} 108 | 109 | -------------------------------------------------------------------------------- 110 | 111 | (haskell 112 | (header 113 | (module 114 | (module_id))) 115 | (comment) 116 | (comment)) 117 | 118 | ================================================================================ 119 | comment: double brace before nested begin 120 | ================================================================================ 121 | 122 | module A where 123 | 124 | {- {{- -} -} 125 | 126 | -------------------------------------------------------------------------------- 127 | 128 | (haskell 129 | (header 130 | (module 131 | (module_id))) 132 | (comment)) 133 | 134 | ================================================================================ 135 | comment: terminated by eof 136 | ================================================================================ 137 | 138 | a = a 139 | 140 | {- 141 | 142 | a 143 | 144 | aaa 145 | 146 | -------------------------------------------------------------------------------- 147 | 148 | (haskell 149 | (declarations 150 | (bind 151 | (variable) 152 | (match 153 | (variable))) 154 | (comment))) 155 | 156 | ================================================================================ 157 | comment: end of line 158 | ================================================================================ 159 | 160 | a = a -- a 161 | 162 | -------------------------------------------------------------------------------- 163 | 164 | (haskell 165 | (declarations 166 | (bind 167 | (variable) 168 | (match 169 | (variable))) 170 | (comment))) 171 | 172 | ================================================================================ 173 | comment: escaped heralds 174 | ================================================================================ 175 | 176 | {- 177 | {\- 178 | -\} 179 | -} 180 | 181 | -------------------------------------------------------------------------------- 182 | 183 | (haskell 184 | (comment)) 185 | 186 | ================================================================================ 187 | comment: multiple braces 188 | ================================================================================ 189 | 190 | {- 191 | {{{{{ 192 | }}}}} 193 | -} 194 | 195 | -------------------------------------------------------------------------------- 196 | 197 | (haskell 198 | (comment)) 199 | 200 | ================================================================================ 201 | comment: symop char after first space 202 | ================================================================================ 203 | 204 | a = a -- > a 205 | 206 | a = a 207 | -- > a 208 | 209 | -------------------------------------------------------------------------------- 210 | 211 | (haskell 212 | (declarations 213 | (bind 214 | (variable) 215 | (match 216 | (variable))) 217 | (comment) 218 | (bind 219 | (variable) 220 | (match 221 | (variable))) 222 | (comment))) 223 | 224 | ================================================================================ 225 | comment: haddock 226 | ================================================================================ 227 | 228 | data A = 229 | A 230 | A -- ^ a 231 | A {- ^ a -} 232 | 233 | -- | a 234 | -- a 235 | a = a 236 | 237 | {- | a 238 | -} 239 | data A 240 | 241 | -------------------------------------------------------------------------------- 242 | 243 | (haskell 244 | (declarations 245 | (data_type 246 | (name) 247 | (data_constructors 248 | (data_constructor 249 | (prefix 250 | (constructor) 251 | (name) 252 | (haddock) 253 | (name))))) 254 | (haddock) 255 | (haddock) 256 | (bind 257 | (variable) 258 | (match 259 | (variable))) 260 | (haddock) 261 | (data_type 262 | (name)))) 263 | -------------------------------------------------------------------------------- /test/corpus/consym.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | consym: valid 3 | ================================================================================ 4 | 5 | data A = Int :+ Int 6 | 7 | -------------------------------------------------------------------------------- 8 | 9 | (haskell 10 | (declarations 11 | (data_type 12 | (name) 13 | (data_constructors 14 | (data_constructor 15 | (infix 16 | (name) 17 | (constructor_operator) 18 | (name))))))) 19 | 20 | ================================================================================ 21 | consym: error: :: 22 | ================================================================================ 23 | 24 | data A = Int :: Int 25 | 26 | -------------------------------------------------------------------------------- 27 | 28 | (haskell 29 | (declarations 30 | (data_type 31 | (name) 32 | (data_constructors 33 | (data_constructor 34 | (prefix 35 | (constructor) 36 | (ERROR) 37 | (name))))))) 38 | -------------------------------------------------------------------------------- /test/corpus/default.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | default: default decl 3 | ================================================================================ 4 | 5 | default () 6 | default (A, A :: A) 7 | 8 | -------------------------------------------------------------------------------- 9 | 10 | (haskell 11 | (declarations 12 | (default_types) 13 | (default_types 14 | (name) 15 | (signature 16 | (name) 17 | (name))))) 18 | -------------------------------------------------------------------------------- /test/corpus/foreign.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | foreign: decl 3 | ================================================================================ 4 | 5 | foreign import prim safe "fun" a :: (# A#, A# #) 6 | foreign import capi unsafe "fun" a :: A 7 | foreign import ccall interruptible "fun" a :: A 8 | foreign import ccall "fun" a :: A 9 | foreign export stdcall "fun" a :: A 10 | foreign export javascript "fun" a :: A 11 | 12 | -------------------------------------------------------------------------------- 13 | 14 | (haskell 15 | (declarations 16 | (foreign_import 17 | (calling_convention) 18 | (safety) 19 | (entity 20 | (string)) 21 | (signature 22 | (variable) 23 | (unboxed_tuple 24 | (name) 25 | (name)))) 26 | (foreign_import 27 | (calling_convention) 28 | (safety) 29 | (entity 30 | (string)) 31 | (signature 32 | (variable) 33 | (name))) 34 | (foreign_import 35 | (calling_convention) 36 | (safety) 37 | (entity 38 | (string)) 39 | (signature 40 | (variable) 41 | (name))) 42 | (foreign_import 43 | (calling_convention) 44 | (entity 45 | (string)) 46 | (signature 47 | (variable) 48 | (name))) 49 | (foreign_export 50 | (calling_convention) 51 | (entity 52 | (string)) 53 | (signature 54 | (variable) 55 | (name))) 56 | (foreign_export 57 | (calling_convention) 58 | (entity 59 | (string)) 60 | (signature 61 | (variable) 62 | (name))))) 63 | -------------------------------------------------------------------------------- /test/corpus/id.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | id: variable 3 | ================================================================================ 4 | 5 | a = a 6 | _a0 = a 7 | _A0 = a 8 | a0 = a 9 | a9 = a 10 | aA = a 11 | aZ' = a 12 | 13 | -------------------------------------------------------------------------------- 14 | 15 | (haskell 16 | (declarations 17 | (bind 18 | (variable) 19 | (match 20 | (variable))) 21 | (bind 22 | (variable) 23 | (match 24 | (variable))) 25 | (bind 26 | (variable) 27 | (match 28 | (variable))) 29 | (bind 30 | (variable) 31 | (match 32 | (variable))) 33 | (bind 34 | (variable) 35 | (match 36 | (variable))) 37 | (bind 38 | (variable) 39 | (match 40 | (variable))) 41 | (bind 42 | (variable) 43 | (match 44 | (variable))))) 45 | 46 | ================================================================================ 47 | id: constructor 48 | ================================================================================ 49 | 50 | data B = A 51 | | A0 52 | | A9 53 | | Aa 54 | | A_ 55 | | Az' 56 | 57 | -------------------------------------------------------------------------------- 58 | 59 | (haskell 60 | (declarations 61 | (data_type 62 | (name) 63 | (data_constructors 64 | (data_constructor 65 | (prefix 66 | (constructor))) 67 | (data_constructor 68 | (prefix 69 | (constructor))) 70 | (data_constructor 71 | (prefix 72 | (constructor))) 73 | (data_constructor 74 | (prefix 75 | (constructor))) 76 | (data_constructor 77 | (prefix 78 | (constructor))) 79 | (data_constructor 80 | (prefix 81 | (constructor))))))) 82 | 83 | ================================================================================ 84 | id: unicode 85 | ================================================================================ 86 | 87 | accenté = () 88 | data T = 89 | Œufs 90 | | Étonnement 91 | | Njtitlecasetest 92 | 93 | -------------------------------------------------------------------------------- 94 | 95 | (haskell 96 | (declarations 97 | (bind 98 | (variable) 99 | (match 100 | (unit))) 101 | (data_type 102 | (name) 103 | (data_constructors 104 | (data_constructor 105 | (prefix 106 | (constructor))) 107 | (data_constructor 108 | (prefix 109 | (constructor))) 110 | (data_constructor 111 | (prefix 112 | (constructor))))))) 113 | 114 | ================================================================================ 115 | id: hashes 116 | ================================================================================ 117 | 118 | a#### = a## 119 | 120 | data A## = A### 121 | 122 | -------------------------------------------------------------------------------- 123 | 124 | (haskell 125 | (declarations 126 | (bind 127 | (variable) 128 | (match 129 | (variable))) 130 | (data_type 131 | (name) 132 | (data_constructors 133 | (data_constructor 134 | (prefix 135 | (constructor))))))) 136 | -------------------------------------------------------------------------------- /test/corpus/implicit.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | implicit: synonym plain 3 | ================================================================================ 4 | 5 | type A = ?a :: A 6 | 7 | -------------------------------------------------------------------------------- 8 | 9 | (haskell 10 | (declarations 11 | (type_synomym 12 | (name) 13 | (implicit_parameter 14 | (implicit_variable) 15 | (name))))) 16 | 17 | ================================================================================ 18 | implicit: synonym parens 19 | ================================================================================ 20 | 21 | type A = (?a :: A) 22 | 23 | -------------------------------------------------------------------------------- 24 | 25 | (haskell 26 | (declarations 27 | (type_synomym 28 | (name) 29 | (parens 30 | (implicit_parameter 31 | (implicit_variable) 32 | (name)))))) 33 | 34 | ================================================================================ 35 | implicit: synonym parens kind annotation 36 | ================================================================================ 37 | 38 | type A = (?a :: Int :: Constraint) 39 | 40 | -------------------------------------------------------------------------------- 41 | 42 | (haskell 43 | (declarations 44 | (type_synomym 45 | (name) 46 | (parens 47 | (signature 48 | (implicit_parameter 49 | (implicit_variable) 50 | (name)) 51 | (name)))))) 52 | 53 | ================================================================================ 54 | implicit: synonym parens constrained 55 | ================================================================================ 56 | 57 | type A = (A => ?a :: A) 58 | 59 | -------------------------------------------------------------------------------- 60 | 61 | (haskell 62 | (declarations 63 | (type_synomym 64 | (name) 65 | (parens 66 | (context 67 | (name) 68 | (implicit_parameter 69 | (implicit_variable) 70 | (name))))))) 71 | 72 | ================================================================================ 73 | implicit: synonym parens constrained 74 | ================================================================================ 75 | 76 | type A = (?a :: A.A, A) 77 | 78 | -------------------------------------------------------------------------------- 79 | 80 | (haskell 81 | (declarations 82 | (type_synomym 83 | (name) 84 | (tuple 85 | (implicit_parameter 86 | (implicit_variable) 87 | (qualified 88 | (module 89 | (module_id)) 90 | (name))) 91 | (name))))) 92 | 93 | ================================================================================ 94 | implicit: synonym tuple 95 | ================================================================================ 96 | 97 | type A = (?a :: A.A, A) 98 | 99 | -------------------------------------------------------------------------------- 100 | 101 | (haskell 102 | (declarations 103 | (type_synomym 104 | (name) 105 | (tuple 106 | (implicit_parameter 107 | (implicit_variable) 108 | (qualified 109 | (module 110 | (module_id)) 111 | (name))) 112 | (name))))) 113 | 114 | ================================================================================ 115 | implicit: synonym context 116 | ================================================================================ 117 | 118 | type A = (?a :: A) => A 119 | 120 | -------------------------------------------------------------------------------- 121 | 122 | (haskell 123 | (declarations 124 | (type_synomym 125 | (name) 126 | (context 127 | (parens 128 | (implicit_parameter 129 | (implicit_variable) 130 | (name))) 131 | (name))))) 132 | 133 | ================================================================================ 134 | implicit: synonym forall/context in annotation 135 | ================================================================================ 136 | 137 | type A = ?a :: ∀ a . A a => A 138 | 139 | -------------------------------------------------------------------------------- 140 | 141 | (haskell 142 | (declarations 143 | (type_synomym 144 | (name) 145 | (implicit_parameter 146 | (implicit_variable) 147 | (forall 148 | (quantified_variables 149 | (variable)) 150 | (context 151 | (apply 152 | (name) 153 | (variable)) 154 | (name))))))) 155 | 156 | ================================================================================ 157 | implicit: signature with function in annotation 158 | ================================================================================ 159 | 160 | a :: (?aaa :: a -> a -> a) => a -> a 161 | 162 | -------------------------------------------------------------------------------- 163 | 164 | (haskell 165 | (declarations 166 | (signature 167 | (variable) 168 | (context 169 | (parens 170 | (implicit_parameter 171 | (implicit_variable) 172 | (function 173 | (variable) 174 | (function 175 | (variable) 176 | (variable))))) 177 | (function 178 | (variable) 179 | (variable)))))) 180 | -------------------------------------------------------------------------------- /test/corpus/module.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | module: exports empty 3 | ================================================================================ 4 | 5 | module A () where 6 | 7 | -------------------------------------------------------------------------------- 8 | 9 | (haskell 10 | (header 11 | (module 12 | (module_id)) 13 | (exports))) 14 | 15 | ================================================================================ 16 | module: exports regular 17 | ================================================================================ 18 | 19 | module A ( 20 | a', 21 | A, 22 | A(), 23 | A(..), 24 | A(a, a), 25 | ) where 26 | 27 | -------------------------------------------------------------------------------- 28 | 29 | (haskell 30 | (header 31 | (module 32 | (module_id)) 33 | (exports 34 | (export 35 | (variable)) 36 | (export 37 | (name)) 38 | (export 39 | (name) 40 | (children)) 41 | (export 42 | (name) 43 | (children 44 | (all_names))) 45 | (export 46 | (name) 47 | (children 48 | (variable) 49 | (variable)))))) 50 | 51 | ================================================================================ 52 | module: exports symbolic 53 | ================================================================================ 54 | 55 | module A ( 56 | (<>)((:<>), A), 57 | (:++), 58 | ) where 59 | 60 | -------------------------------------------------------------------------------- 61 | 62 | (haskell 63 | (header 64 | (module 65 | (module_id)) 66 | (exports 67 | (export 68 | (prefix_id 69 | (operator)) 70 | (children 71 | (prefix_id 72 | (constructor_operator)) 73 | (constructor))) 74 | (export 75 | (prefix_id 76 | (constructor_operator)))))) 77 | 78 | ================================================================================ 79 | module: exports type 80 | ================================================================================ 81 | 82 | module A ( 83 | type A, 84 | type (<>), 85 | type (:++), 86 | ) where 87 | 88 | -------------------------------------------------------------------------------- 89 | 90 | (haskell 91 | (header 92 | (module 93 | (module_id)) 94 | (exports 95 | (export 96 | (namespace) 97 | (name)) 98 | (export 99 | (namespace) 100 | (prefix_id 101 | (operator))) 102 | (export 103 | (namespace) 104 | (prefix_id 105 | (constructor_operator)))))) 106 | 107 | ================================================================================ 108 | module: exports pattern 109 | ================================================================================ 110 | 111 | module A ( 112 | pattern A, 113 | pattern (<>), 114 | A (.., a, ..), 115 | ) where 116 | 117 | -------------------------------------------------------------------------------- 118 | 119 | (haskell 120 | (header 121 | (module 122 | (module_id)) 123 | (exports 124 | (export 125 | (namespace) 126 | (name)) 127 | (export 128 | (namespace) 129 | (prefix_id 130 | (operator))) 131 | (export 132 | (name) 133 | (children 134 | (all_names) 135 | (variable) 136 | (all_names)))))) 137 | 138 | ================================================================================ 139 | module: exports module 140 | ================================================================================ 141 | 142 | module A ( 143 | a, 144 | module A, 145 | module A.A.A, 146 | ) where 147 | 148 | -------------------------------------------------------------------------------- 149 | 150 | (haskell 151 | (header 152 | (module 153 | (module_id)) 154 | (exports 155 | (export 156 | (variable)) 157 | (module_export 158 | (module 159 | (module_id))) 160 | (module_export 161 | (module 162 | (module_id) 163 | (module_id) 164 | (module_id)))))) 165 | 166 | ================================================================================ 167 | module: exports qualified 168 | ================================================================================ 169 | 170 | module A ( 171 | A.A.a, 172 | type (A.A.++), 173 | type (A.A.:++), 174 | A.A.A, 175 | A.A.A((<=<), (:++), A, a), 176 | type A.A((>>), A), 177 | pattern A.A((>>), A), 178 | ) where 179 | 180 | -------------------------------------------------------------------------------- 181 | 182 | (haskell 183 | (header 184 | (module 185 | (module_id)) 186 | (exports 187 | (export 188 | (qualified 189 | (module 190 | (module_id) 191 | (module_id)) 192 | (variable))) 193 | (export 194 | (namespace) 195 | (prefix_id 196 | (qualified 197 | (module 198 | (module_id) 199 | (module_id)) 200 | (operator)))) 201 | (export 202 | (namespace) 203 | (prefix_id 204 | (qualified 205 | (module 206 | (module_id) 207 | (module_id)) 208 | (constructor_operator)))) 209 | (export 210 | (qualified 211 | (module 212 | (module_id) 213 | (module_id)) 214 | (name))) 215 | (export 216 | (qualified 217 | (module 218 | (module_id) 219 | (module_id)) 220 | (name)) 221 | (children 222 | (prefix_id 223 | (operator)) 224 | (prefix_id 225 | (constructor_operator)) 226 | (constructor) 227 | (variable))) 228 | (export 229 | (namespace) 230 | (qualified 231 | (module 232 | (module_id)) 233 | (name)) 234 | (children 235 | (prefix_id 236 | (operator)) 237 | (constructor))) 238 | (export 239 | (namespace) 240 | (qualified 241 | (module 242 | (module_id)) 243 | (name)) 244 | (children 245 | (prefix_id 246 | (operator)) 247 | (constructor)))))) 248 | 249 | ================================================================================ 250 | module: exports zero indent 251 | ================================================================================ 252 | module A ( 253 | A 254 | , a, 255 | A 256 | ) where 257 | 258 | -------------------------------------------------------------------------------- 259 | 260 | (haskell 261 | (header 262 | (module 263 | (module_id)) 264 | (exports 265 | (export 266 | (name)) 267 | (export 268 | (variable)) 269 | (export 270 | (name))))) 271 | 272 | ================================================================================ 273 | module: qualified 274 | ================================================================================ 275 | 276 | module A.A'.A where 277 | 278 | -------------------------------------------------------------------------------- 279 | 280 | (haskell 281 | (header 282 | (module 283 | (module_id) 284 | (module_id) 285 | (module_id)))) 286 | 287 | ================================================================================ 288 | module: export minus 289 | ================================================================================ 290 | 291 | module A (type (-), (-)) where 292 | 293 | -------------------------------------------------------------------------------- 294 | 295 | (haskell 296 | (header 297 | (module 298 | (module_id)) 299 | (exports 300 | (export 301 | (namespace) 302 | (prefix_id 303 | (operator))) 304 | (export 305 | (prefix_id 306 | (operator)))))) 307 | 308 | ================================================================================ 309 | module: export dot 310 | ================================================================================ 311 | 312 | module A (type (.), (.)) where 313 | 314 | -------------------------------------------------------------------------------- 315 | 316 | (haskell 317 | (header 318 | (module 319 | (module_id)) 320 | (exports 321 | (export 322 | (namespace) 323 | (prefix_id 324 | (operator))) 325 | (export 326 | (prefix_id 327 | (operator)))))) 328 | 329 | ================================================================================ 330 | module: no trailing comma 331 | ================================================================================ 332 | 333 | module A ( 334 | A, 335 | A 336 | ) where 337 | 338 | -------------------------------------------------------------------------------- 339 | 340 | (haskell 341 | (header 342 | (module 343 | (module_id)) 344 | (exports 345 | (export 346 | (name)) 347 | (export 348 | (name))))) 349 | 350 | ================================================================================ 351 | module: namespace for type child 352 | ================================================================================ 353 | 354 | module A ( 355 | A (type A, A, ..) 356 | ) where 357 | 358 | -------------------------------------------------------------------------------- 359 | 360 | (haskell 361 | (header 362 | (module 363 | (module_id)) 364 | (exports 365 | (export 366 | (name) 367 | (children 368 | (associated_type 369 | (name)) 370 | (constructor) 371 | (all_names)))))) 372 | -------------------------------------------------------------------------------- /test/corpus/newtype.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | newtype: basic 3 | ================================================================================ 4 | 5 | newtype A = A A 6 | 7 | -------------------------------------------------------------------------------- 8 | 9 | (haskell 10 | (declarations 11 | (newtype 12 | (name) 13 | (newtype_constructor 14 | (constructor) 15 | (field 16 | (name)))))) 17 | 18 | ================================================================================ 19 | newtype: context 20 | ================================================================================ 21 | 22 | newtype A a => A a = A a 23 | 24 | -------------------------------------------------------------------------------- 25 | 26 | (haskell 27 | (declarations 28 | (newtype 29 | (context 30 | (apply 31 | (name) 32 | (variable))) 33 | (name) 34 | (type_params 35 | (variable)) 36 | (newtype_constructor 37 | (constructor) 38 | (field 39 | (variable)))))) 40 | 41 | ================================================================================ 42 | newtype: record 43 | ================================================================================ 44 | 45 | newtype A = A { a :: A a } 46 | 47 | -------------------------------------------------------------------------------- 48 | 49 | (haskell 50 | (declarations 51 | (newtype 52 | (name) 53 | (newtype_constructor 54 | (constructor) 55 | (record 56 | (field 57 | (field_name 58 | (variable)) 59 | (apply 60 | (name) 61 | (variable)))))))) 62 | 63 | ================================================================================ 64 | newtype: tyvar kind 65 | ================================================================================ 66 | 67 | newtype A a (a :: [* -> *]) a = 68 | A a 69 | 70 | -------------------------------------------------------------------------------- 71 | 72 | (haskell 73 | (declarations 74 | (newtype 75 | (name) 76 | (type_params 77 | (variable) 78 | (parens 79 | (annotated 80 | (variable) 81 | (list 82 | (function 83 | (star) 84 | (star))))) 85 | (variable)) 86 | (newtype_constructor 87 | (constructor) 88 | (field 89 | (variable)))))) 90 | 91 | ================================================================================ 92 | newtype: deriving 93 | ================================================================================ 94 | 95 | newtype A = A a deriving A 96 | newtype A a = 97 | A { a :: A } 98 | deriving (A, A) 99 | deriving newtype A 100 | deriving A via (A a) 101 | 102 | -------------------------------------------------------------------------------- 103 | 104 | (haskell 105 | (declarations 106 | (newtype 107 | (name) 108 | (newtype_constructor 109 | (constructor) 110 | (field 111 | (variable))) 112 | (deriving 113 | (name))) 114 | (newtype 115 | (name) 116 | (type_params 117 | (variable)) 118 | (newtype_constructor 119 | (constructor) 120 | (record 121 | (field 122 | (field_name 123 | (variable)) 124 | (name)))) 125 | (deriving 126 | (tuple 127 | (name) 128 | (name))) 129 | (deriving 130 | (deriving_strategy) 131 | (name)) 132 | (deriving 133 | (name) 134 | (via 135 | (parens 136 | (apply 137 | (name) 138 | (variable)))))))) 139 | 140 | ================================================================================ 141 | newtype: unlifted 142 | ================================================================================ 143 | 144 | newtype A :: TYPE 'A where 145 | A :: A# -> A 146 | 147 | -------------------------------------------------------------------------------- 148 | 149 | (haskell 150 | (declarations 151 | (newtype 152 | (name) 153 | (apply 154 | (name) 155 | (promoted 156 | (constructor))) 157 | (gadt_constructors 158 | (gadt_constructor 159 | (constructor) 160 | (prefix 161 | (function 162 | (name) 163 | (name)))))))) 164 | 165 | ================================================================================ 166 | newtype: prefix operator 167 | ================================================================================ 168 | 169 | newtype (++) a = (:++) a 170 | 171 | -------------------------------------------------------------------------------- 172 | 173 | (haskell 174 | (declarations 175 | (newtype 176 | (prefix_id 177 | (operator)) 178 | (type_params 179 | (variable)) 180 | (newtype_constructor 181 | (prefix_id 182 | (constructor_operator)) 183 | (field 184 | (variable)))))) 185 | -------------------------------------------------------------------------------- /test/corpus/number.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | number: decimal 3 | ================================================================================ 4 | 5 | a = 0 6 | a = 100_00_532 7 | a = 55# 8 | a = 55## 9 | 10 | -------------------------------------------------------------------------------- 11 | 12 | (haskell 13 | (declarations 14 | (bind 15 | (variable) 16 | (match 17 | (literal 18 | (integer)))) 19 | (bind 20 | (variable) 21 | (match 22 | (literal 23 | (integer)))) 24 | (bind 25 | (variable) 26 | (match 27 | (literal 28 | (integer)))) 29 | (bind 30 | (variable) 31 | (match 32 | (literal 33 | (integer)))))) 34 | 35 | ================================================================================ 36 | number: octal 37 | ================================================================================ 38 | 39 | a = 0o00 40 | a = 0O77 41 | a = 0O77## 42 | 43 | -------------------------------------------------------------------------------- 44 | 45 | (haskell 46 | (declarations 47 | (bind 48 | (variable) 49 | (match 50 | (literal 51 | (integer)))) 52 | (bind 53 | (variable) 54 | (match 55 | (literal 56 | (integer)))) 57 | (bind 58 | (variable) 59 | (match 60 | (literal 61 | (integer)))))) 62 | 63 | ================================================================================ 64 | number: hex 65 | ================================================================================ 66 | 67 | a = 0xA8 68 | a = 0XEF84Fe23 69 | a = 0xa_e_123_4 70 | a = 0xa_e_123_4## 71 | a = 0x0.1p-4 72 | a = 0xFp3 73 | 74 | -------------------------------------------------------------------------------- 75 | 76 | (haskell 77 | (declarations 78 | (bind 79 | (variable) 80 | (match 81 | (literal 82 | (integer)))) 83 | (bind 84 | (variable) 85 | (match 86 | (literal 87 | (integer)))) 88 | (bind 89 | (variable) 90 | (match 91 | (literal 92 | (integer)))) 93 | (bind 94 | (variable) 95 | (match 96 | (literal 97 | (integer)))) 98 | (bind 99 | (variable) 100 | (match 101 | (literal 102 | (integer)))) 103 | (bind 104 | (variable) 105 | (match 106 | (literal 107 | (integer)))))) 108 | 109 | ================================================================================ 110 | number: float 111 | ================================================================================ 112 | 113 | a = 0.32847283472 114 | a = 0.00e01 115 | a = 0.00e01# 116 | a = 0.00e+01 117 | a = 0.99E-01 118 | a = 00e01 119 | a = 00e+01 120 | a = 99E-01 121 | 122 | -------------------------------------------------------------------------------- 123 | 124 | (haskell 125 | (declarations 126 | (bind 127 | (variable) 128 | (match 129 | (literal 130 | (float)))) 131 | (bind 132 | (variable) 133 | (match 134 | (literal 135 | (float)))) 136 | (bind 137 | (variable) 138 | (match 139 | (literal 140 | (float)))) 141 | (bind 142 | (variable) 143 | (match 144 | (literal 145 | (float)))) 146 | (bind 147 | (variable) 148 | (match 149 | (literal 150 | (float)))) 151 | (bind 152 | (variable) 153 | (match 154 | (literal 155 | (float)))) 156 | (bind 157 | (variable) 158 | (match 159 | (literal 160 | (float)))) 161 | (bind 162 | (variable) 163 | (match 164 | (literal 165 | (float)))))) 166 | 167 | ================================================================================ 168 | number: binary 169 | ================================================================================ 170 | 171 | a = 0b01110 172 | a = 0B10010 173 | a = 0B10010## 174 | 175 | -------------------------------------------------------------------------------- 176 | 177 | (haskell 178 | (declarations 179 | (bind 180 | (variable) 181 | (match 182 | (literal 183 | (integer)))) 184 | (bind 185 | (variable) 186 | (match 187 | (literal 188 | (integer)))) 189 | (bind 190 | (variable) 191 | (match 192 | (literal 193 | (integer)))))) 194 | -------------------------------------------------------------------------------- /test/corpus/patsyn.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | patsyn: unidirectional simple 3 | ================================================================================ 4 | 5 | pattern A a <- a : a 6 | 7 | -------------------------------------------------------------------------------- 8 | 9 | (haskell 10 | (declarations 11 | (pattern_synonym 12 | (equation 13 | (apply 14 | (constructor) 15 | (variable)) 16 | (infix 17 | (variable) 18 | (constructor_operator) 19 | (variable)))))) 20 | 21 | ================================================================================ 22 | patsyn: unidirectional strict 23 | ================================================================================ 24 | 25 | pattern A a = A !a 26 | 27 | -------------------------------------------------------------------------------- 28 | 29 | (haskell 30 | (declarations 31 | (pattern_synonym 32 | (equation 33 | (apply 34 | (constructor) 35 | (variable)) 36 | (apply 37 | (constructor) 38 | (strict 39 | (variable))))))) 40 | 41 | ================================================================================ 42 | patsyn: explicit bidirectional list 43 | ================================================================================ 44 | 45 | pattern A a <- a : a where 46 | A a = [a] 47 | 48 | -------------------------------------------------------------------------------- 49 | 50 | (haskell 51 | (declarations 52 | (pattern_synonym 53 | (equation 54 | (apply 55 | (constructor) 56 | (variable)) 57 | (infix 58 | (variable) 59 | (constructor_operator) 60 | (variable)) 61 | (constructor_synonyms 62 | (constructor_synonym 63 | (apply 64 | (constructor) 65 | (variable)) 66 | (match 67 | (list 68 | (variable))))))))) 69 | 70 | ================================================================================ 71 | patsyn: explicit bidirectional strict 72 | ================================================================================ 73 | 74 | pattern A a <- A !a where 75 | A !a = A a 76 | 77 | -------------------------------------------------------------------------------- 78 | 79 | (haskell 80 | (declarations 81 | (pattern_synonym 82 | (equation 83 | (apply 84 | (constructor) 85 | (variable)) 86 | (apply 87 | (constructor) 88 | (strict 89 | (variable))) 90 | (constructor_synonyms 91 | (constructor_synonym 92 | (apply 93 | (constructor) 94 | (strict 95 | (variable))) 96 | (match 97 | (apply 98 | (constructor) 99 | (variable))))))))) 100 | 101 | ================================================================================ 102 | patsyn: explicit bidirectional record 103 | ================================================================================ 104 | 105 | pattern A { a } <- A a where 106 | A a = if a >= 0 then a else a 107 | 108 | -------------------------------------------------------------------------------- 109 | 110 | (haskell 111 | declarations: (declarations 112 | (pattern_synonym 113 | (equation 114 | synonym: (record 115 | constructor: (constructor) 116 | field: (field_pattern 117 | field: (field_name 118 | (variable)))) 119 | pattern: (apply 120 | function: (constructor) 121 | argument: (variable)) 122 | constructors: (constructor_synonyms 123 | (constructor_synonym 124 | pattern: (apply 125 | function: (constructor) 126 | argument: (variable)) 127 | match: (match 128 | expression: (conditional 129 | if: (infix 130 | left_operand: (variable) 131 | operator: (operator) 132 | right_operand: (literal 133 | (integer))) 134 | then: (variable) 135 | else: (variable))))))))) 136 | 137 | ================================================================================ 138 | patsyn: explicit bidirectional guards 139 | ================================================================================ 140 | 141 | pattern A a <- A a where 142 | A a 143 | | a >= 0 = (A a) 144 | | otherwise = A a 145 | 146 | -------------------------------------------------------------------------------- 147 | 148 | (haskell 149 | declarations: (declarations 150 | (pattern_synonym 151 | (equation 152 | synonym: (apply 153 | function: (constructor) 154 | argument: (variable)) 155 | pattern: (apply 156 | function: (constructor) 157 | argument: (variable)) 158 | constructors: (constructor_synonyms 159 | (constructor_synonym 160 | pattern: (apply 161 | function: (constructor) 162 | argument: (variable)) 163 | match: (match 164 | guards: (guards 165 | guard: (boolean 166 | (infix 167 | left_operand: (variable) 168 | operator: (operator) 169 | right_operand: (literal 170 | (integer))))) 171 | expression: (parens 172 | expression: (apply 173 | function: (constructor) 174 | argument: (variable)))) 175 | match: (match 176 | guards: (guards 177 | guard: (boolean 178 | (variable))) 179 | expression: (apply 180 | function: (constructor) 181 | argument: (variable))))))))) 182 | 183 | ================================================================================ 184 | patsyn: signature 185 | ================================================================================ 186 | 187 | pattern A :: A -> A -> (A, A) 188 | pattern A, A :: A 189 | 190 | -------------------------------------------------------------------------------- 191 | 192 | (haskell 193 | declarations: (declarations 194 | (pattern_synonym 195 | (signature 196 | synonym: (constructor) 197 | type: (function 198 | parameter: (name) 199 | result: (function 200 | parameter: (name) 201 | result: (tuple 202 | element: (name) 203 | element: (name)))))) 204 | (pattern_synonym 205 | (signature 206 | synonym: (binding_list 207 | name: (constructor) 208 | name: (constructor)) 209 | type: (name))))) 210 | 211 | ================================================================================ 212 | patsyn: unidirectional record 213 | ================================================================================ 214 | 215 | pattern A {a, a} = (a, a) 216 | 217 | -------------------------------------------------------------------------------- 218 | 219 | (haskell 220 | (declarations 221 | (pattern_synonym 222 | (equation 223 | (record 224 | (constructor) 225 | (field_pattern 226 | (field_name 227 | (variable))) 228 | (field_pattern 229 | (field_name 230 | (variable)))) 231 | (tuple 232 | (variable) 233 | (variable)))))) 234 | 235 | ================================================================================ 236 | patsyn: operator 237 | ================================================================================ 238 | 239 | pattern (:->) :: A 240 | pattern a :-> b <- a 241 | 242 | -------------------------------------------------------------------------------- 243 | 244 | (haskell 245 | declarations: (declarations 246 | (pattern_synonym 247 | (signature 248 | synonym: (prefix_id 249 | (constructor_operator)) 250 | type: (name))) 251 | (pattern_synonym 252 | (equation 253 | synonym: (infix 254 | left_operand: (variable) 255 | operator: (constructor_operator) 256 | right_operand: (variable)) 257 | pattern: (variable))))) 258 | 259 | ================================================================================ 260 | patsyn: ticked infix 261 | ================================================================================ 262 | 263 | pattern A <- a `A` a 264 | pattern A <- a `A.A` a 265 | 266 | -------------------------------------------------------------------------------- 267 | 268 | (haskell 269 | (declarations 270 | (pattern_synonym 271 | (equation 272 | (constructor) 273 | (infix 274 | (variable) 275 | (infix_id 276 | (constructor)) 277 | (variable)))) 278 | (pattern_synonym 279 | (equation 280 | (constructor) 281 | (infix 282 | (variable) 283 | (infix_id 284 | (qualified 285 | (module 286 | (module_id)) 287 | (constructor))) 288 | (variable)))))) 289 | -------------------------------------------------------------------------------- /test/corpus/pragma.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | pragma: inline 3 | ================================================================================ 4 | 5 | a = a 6 | {-# inline a #-} 7 | 8 | a = a 9 | {-# inline conlike [1] a #-} 10 | 11 | a = a 12 | {-#INLINE [~2] a#-} 13 | 14 | -------------------------------------------------------------------------------- 15 | 16 | (haskell 17 | (declarations 18 | (bind 19 | (variable) 20 | (match 21 | (variable))) 22 | (pragma) 23 | (bind 24 | (variable) 25 | (match 26 | (variable))) 27 | (pragma) 28 | (bind 29 | (variable) 30 | (match 31 | (variable))) 32 | (pragma))) 33 | 34 | ================================================================================ 35 | pragma: without module 36 | ================================================================================ 37 | 38 | {-# LANGUAGE LambdaCase #-} 39 | {-# language ScopedTypeVariables, DataKinds #-} 40 | 41 | -------------------------------------------------------------------------------- 42 | 43 | (haskell 44 | (pragma) 45 | (pragma)) 46 | 47 | ================================================================================ 48 | pragma: before module 49 | ================================================================================ 50 | 51 | {-# language LambdaCase #-} 52 | {-# language ScopedTypeVariables, DataKinds #-} 53 | module A where 54 | 55 | -------------------------------------------------------------------------------- 56 | 57 | (haskell 58 | (pragma) 59 | (pragma) 60 | (header 61 | (module 62 | (module_id)))) 63 | 64 | ================================================================================ 65 | pragma: after module 66 | ================================================================================ 67 | 68 | module A where 69 | {-# language X #-} 70 | a = a 71 | 72 | -------------------------------------------------------------------------------- 73 | 74 | (haskell 75 | (header 76 | (module 77 | (module_id))) 78 | (pragma) 79 | (declarations 80 | (bind 81 | (variable) 82 | (match 83 | (variable))))) 84 | 85 | ================================================================================ 86 | pragma: between imports 87 | ================================================================================ 88 | 89 | module A where 90 | {-# language X #-} 91 | import A 92 | {-# language X #-} 93 | import A 94 | {-# language X #-} 95 | a = a 96 | 97 | -------------------------------------------------------------------------------- 98 | 99 | (haskell 100 | (header 101 | (module 102 | (module_id))) 103 | (pragma) 104 | (imports 105 | (import 106 | (module 107 | (module_id))) 108 | (pragma) 109 | (import 110 | (module 111 | (module_id))) 112 | (pragma)) 113 | (declarations 114 | (bind 115 | (variable) 116 | (match 117 | (variable))))) 118 | 119 | ================================================================================ 120 | pragma: before import inline 121 | ================================================================================ 122 | 123 | module A where 124 | 125 | import A 126 | {-# language X #-} import A 127 | import A 128 | 129 | -------------------------------------------------------------------------------- 130 | 131 | (haskell 132 | (header 133 | (module 134 | (module_id))) 135 | (imports 136 | (import 137 | (module 138 | (module_id))) 139 | (pragma) 140 | (import 141 | (module 142 | (module_id))) 143 | (import 144 | (module 145 | (module_id))))) 146 | 147 | ================================================================================ 148 | pragma: instance overlap 149 | ================================================================================ 150 | 151 | instance {-# overlappable #-} A where 152 | 153 | -------------------------------------------------------------------------------- 154 | 155 | (haskell 156 | (declarations 157 | (instance 158 | (pragma) 159 | (name)))) 160 | 161 | ================================================================================ 162 | pragma: multiline 163 | ================================================================================ 164 | 165 | module A where 166 | {-# rules 167 | "a/a" [2] forall a . a a = a 168 | #-} 169 | 170 | a = a 171 | 172 | -------------------------------------------------------------------------------- 173 | 174 | (haskell 175 | (header 176 | (module 177 | (module_id))) 178 | (pragma) 179 | (declarations 180 | (bind 181 | (variable) 182 | (match 183 | (variable))))) 184 | 185 | ================================================================================ 186 | pragma: no whitespace before strictness annotation 187 | ================================================================================ 188 | 189 | data A = A {-# a #-}!A 190 | data A = A {- a -}~A 191 | 192 | -------------------------------------------------------------------------------- 193 | 194 | (haskell 195 | (declarations 196 | (data_type 197 | (name) 198 | (data_constructors 199 | (data_constructor 200 | (prefix 201 | (constructor) 202 | (pragma) 203 | (strict_field 204 | (name)))))) 205 | (data_type 206 | (name) 207 | (data_constructors 208 | (data_constructor 209 | (prefix 210 | (constructor) 211 | (comment) 212 | (lazy_field 213 | (name)))))))) 214 | 215 | ================================================================================ 216 | pragma: before do statement 217 | ================================================================================ 218 | 219 | a = do 220 | a <- a 221 | {-# SCC "a" #-} a 222 | 223 | -------------------------------------------------------------------------------- 224 | 225 | (haskell 226 | (declarations 227 | (bind 228 | (variable) 229 | (match 230 | (do 231 | (bind 232 | (variable) 233 | (variable)) 234 | (pragma) 235 | (exp 236 | (variable))))))) 237 | 238 | ================================================================================ 239 | pragma: instance method with cpp 240 | ================================================================================ 241 | 242 | instance A where 243 | #if 244 | a = a 245 | #endif 246 | {-# inline a #-} 247 | 248 | a = a 249 | 250 | -------------------------------------------------------------------------------- 251 | 252 | (haskell 253 | (declarations 254 | (instance 255 | (name) 256 | (cpp) 257 | (instance_declarations 258 | (bind 259 | (variable) 260 | (match 261 | (variable))) 262 | (cpp) 263 | (pragma))) 264 | (bind 265 | (variable) 266 | (match 267 | (variable))))) 268 | 269 | ================================================================================ 270 | pragma: indented before decl without module 271 | ================================================================================ 272 | {-# language A #-} 273 | 274 | a = a 275 | 276 | -------------------------------------------------------------------------------- 277 | 278 | (haskell 279 | (pragma) 280 | (declarations 281 | (bind 282 | (variable) 283 | (match 284 | (variable))))) 285 | 286 | ================================================================================ 287 | pragma: indented after decl 288 | ================================================================================ 289 | a = a 290 | 291 | {-# prag #-} 292 | 293 | a = a 294 | -------------------------------------------------------------------------------- 295 | 296 | (haskell 297 | (declarations 298 | (bind 299 | (variable) 300 | (match 301 | (variable))) 302 | (pragma) 303 | (bind 304 | (variable) 305 | (match 306 | (variable))))) 307 | 308 | ================================================================================ 309 | pragma: indented after module 310 | ================================================================================ 311 | module A where 312 | {-# prag #-} 313 | a = a 314 | -- This is a parse error in GHC, but since we leniently readjust top level indent 315 | -- when it decreases, it doesn't happen here. 316 | 317 | -------------------------------------------------------------------------------- 318 | 319 | (haskell 320 | (header 321 | (module 322 | (module_id))) 323 | (pragma) 324 | (declarations 325 | (bind 326 | (variable) 327 | (match 328 | (variable))) 329 | (comment))) 330 | 331 | ================================================================================ 332 | pragma: between decls 333 | ================================================================================ 334 | 335 | a = a 336 | {-# prag #-} 337 | a = a 338 | 339 | -------------------------------------------------------------------------------- 340 | 341 | (haskell 342 | (declarations 343 | (bind 344 | (variable) 345 | (match 346 | (variable))) 347 | (pragma) 348 | (bind 349 | (variable) 350 | (match 351 | (variable))))) 352 | 353 | ================================================================================ 354 | pragma: followed by inline comment 355 | ================================================================================ 356 | a = a 357 | {-# prag #-} -- a 358 | a = a 359 | 360 | -------------------------------------------------------------------------------- 361 | 362 | (haskell 363 | (declarations 364 | (bind 365 | (variable) 366 | (match 367 | (variable))) 368 | (pragma) 369 | (comment) 370 | (bind 371 | (variable) 372 | (match 373 | (variable))))) 374 | 375 | ================================================================================ 376 | pragma: followed by block comment 377 | ================================================================================ 378 | a = a 379 | {-# prag #-} {- a 380 | -} 381 | a = a 382 | 383 | -------------------------------------------------------------------------------- 384 | 385 | (haskell 386 | (declarations 387 | (bind 388 | (variable) 389 | (match 390 | (variable))) 391 | (pragma) 392 | (comment) 393 | (bind 394 | (variable) 395 | (match 396 | (variable))))) 397 | 398 | ================================================================================ 399 | pragma: after block comment 400 | ================================================================================ 401 | a = do 402 | a 403 | {- a -} 404 | {-# prag #-} 405 | a = a 406 | 407 | -------------------------------------------------------------------------------- 408 | 409 | (haskell 410 | (declarations 411 | (bind 412 | (variable) 413 | (match 414 | (do 415 | (exp 416 | (variable))))) 417 | (comment) 418 | (pragma) 419 | (bind 420 | (variable) 421 | (match 422 | (variable))))) 423 | -------------------------------------------------------------------------------- /test/corpus/signature.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | signature: forall 3 | ================================================================================ 4 | 5 | a :: forall a (a :: * -> Type) . (∀ a . a -> a) -> A a 6 | 7 | -------------------------------------------------------------------------------- 8 | 9 | (haskell 10 | (declarations 11 | (signature 12 | (variable) 13 | (forall 14 | (quantified_variables 15 | (variable) 16 | (parens 17 | (annotated 18 | (variable) 19 | (function 20 | (star) 21 | (name))))) 22 | (function 23 | (parens 24 | (forall 25 | (quantified_variables 26 | (variable)) 27 | (function 28 | (variable) 29 | (variable)))) 30 | (apply 31 | (name) 32 | (variable))))))) 33 | 34 | ================================================================================ 35 | signature: alternating forall/context/arrow/infix 36 | ================================================================================ 37 | 38 | a :: A a => ∀ a. a ++ a => a -> ∀ a. a -> A => A => A a 39 | 40 | -------------------------------------------------------------------------------- 41 | 42 | (haskell 43 | (declarations 44 | (signature 45 | (variable) 46 | (context 47 | (apply 48 | (name) 49 | (variable)) 50 | (forall 51 | (quantified_variables 52 | (variable)) 53 | (context 54 | (infix 55 | (variable) 56 | (operator) 57 | (variable)) 58 | (function 59 | (variable) 60 | (forall 61 | (quantified_variables 62 | (variable)) 63 | (function 64 | (variable) 65 | (context 66 | (name) 67 | (context 68 | (name) 69 | (apply 70 | (name) 71 | (variable))))))))))))) 72 | 73 | ================================================================================ 74 | signature: partial 75 | ================================================================================ 76 | 77 | a :: A -> _ -> (_, a) -> _a 78 | 79 | -------------------------------------------------------------------------------- 80 | 81 | (haskell 82 | (declarations 83 | (signature 84 | (variable) 85 | (function 86 | (name) 87 | (function 88 | (wildcard) 89 | (function 90 | (tuple 91 | (wildcard) 92 | (variable)) 93 | (variable))))))) 94 | 95 | ================================================================================ 96 | signature: unicode herald 97 | ================================================================================ 98 | 99 | a ∷ a 100 | 101 | -------------------------------------------------------------------------------- 102 | 103 | (haskell 104 | (declarations 105 | (signature 106 | (variable) 107 | (variable)))) 108 | -------------------------------------------------------------------------------- /test/corpus/special.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | special: GHC fixity decl for -> in GHC.Types 3 | ================================================================================ 4 | 5 | infixr -1 -> 6 | 7 | -------------------------------------------------------------------------------- 8 | 9 | (haskell 10 | declarations: (declarations 11 | (fixity 12 | precedence: (integer) 13 | operator: (operator)))) 14 | -------------------------------------------------------------------------------- /test/corpus/string.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | string: special chars 3 | ================================================================================ 4 | 5 | a = "\\\"\a\b\f\n\r\t\v\&\NUL\SOH\STX\ETX\EOT\ENQ\ACK\BEL\BS\HT\LF\VT\FF\CR\SO\SI\DLE\DC1\DC2\DC3\DC4\NAK\SYN\ETB\CAN\EM\SUB\ESC\FS\GS\RS\US\SP\DEL\^A\^Z\^@\^[\^]\^\\^^\^_" 6 | 7 | -------------------------------------------------------------------------------- 8 | 9 | (haskell 10 | (declarations 11 | (bind 12 | (variable) 13 | (match 14 | (literal 15 | (string)))))) 16 | 17 | ================================================================================ 18 | string: gap 19 | ================================================================================ 20 | 21 | a = "start\ 22 | \" 23 | 24 | a = "start\ 25 | \end" 26 | 27 | -------------------------------------------------------------------------------- 28 | 29 | (haskell 30 | (declarations 31 | (bind 32 | (variable) 33 | (match 34 | (literal 35 | (string)))) 36 | (bind 37 | (variable) 38 | (match 39 | (literal 40 | (string)))))) 41 | 42 | ================================================================================ 43 | string: magic hash 44 | ================================================================================ 45 | 46 | a = "a"# 47 | a = "a"## 48 | 49 | -------------------------------------------------------------------------------- 50 | 51 | (haskell 52 | (declarations 53 | (bind 54 | (variable) 55 | (match 56 | (literal 57 | (string)))) 58 | (bind 59 | (variable) 60 | (match 61 | (literal 62 | (string)))))) 63 | -------------------------------------------------------------------------------- /tree-sitter.json: -------------------------------------------------------------------------------- 1 | { 2 | "grammars": [ 3 | { 4 | "name": "haskell", 5 | "camelcase": "Haskell", 6 | "scope": "source.haskell", 7 | "path": ".", 8 | "file-types": [ 9 | "hs", 10 | "hs-boot" 11 | ], 12 | "highlights": "queries/highlights.scm", 13 | "injection-regex": "^(hs|haskell)$" 14 | } 15 | ], 16 | "metadata": { 17 | "version": "0.23.1", 18 | "license": "MIT", 19 | "description": "Haskell grammar for tree-sitter", 20 | "authors": [ 21 | { 22 | "name": "Rick Winfrey" 23 | }, 24 | { 25 | "name": "Max Brunsfeld", 26 | "email": "maxbrunsfeld@gmail.com" 27 | }, 28 | { 29 | "name": "Owen Shepherd" 30 | }, 31 | { 32 | "name": "Torsten Schmits" 33 | } 34 | ], 35 | "links": { 36 | "repository": "https://github.com/tree-sitter/tree-sitter-haskell" 37 | } 38 | }, 39 | "bindings": { 40 | "c": true, 41 | "go": true, 42 | "node": true, 43 | "python": true, 44 | "rust": true, 45 | "swift": true 46 | } 47 | } 48 | --------------------------------------------------------------------------------