Showing preview only (1,335K chars total). Download the full file or copy to clipboard to get everything.
Repository: tree-sitter/tree-sitter-haskell
Branch: master
Commit: 0975ef72fc3c
Files: 101
Total size: 20.2 MB
Directory structure:
gitextract_gnpzepxr/
├── .editorconfig
├── .gitattributes
├── .github/
│ └── workflows/
│ ├── ci.yml
│ ├── fuzz.yml
│ └── publish.yml
├── .gitignore
├── CMakeLists.txt
├── 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/
│ ├── 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
├── grammar.js
├── 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
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
root = true
[*]
charset = utf-8
[*.{json,toml,yml,gyp}]
indent_style = space
indent_size = 2
[*.js]
indent_style = space
indent_size = 2
[*.scm]
indent_style = space
indent_size = 2
[*.{c,cc,h}]
indent_style = space
indent_size = 4
[*.rs]
indent_style = space
indent_size = 4
[*.{py,pyi}]
indent_style = space
indent_size = 4
[*.swift]
indent_style = space
indent_size = 4
[*.go]
indent_style = tab
indent_size = 8
[Makefile]
indent_style = tab
indent_size = 8
[parser.c]
indent_size = 2
[{alloc,array,parser}.h]
indent_size = 2
================================================
FILE: .gitattributes
================================================
* text=auto eol=lf
# Generated source files
src/*.json linguist-generated
src/parser.c linguist-generated
src/tree_sitter/* linguist-generated
# C bindings
bindings/c/* linguist-generated
CMakeLists.txt linguist-generated
Makefile linguist-generated
# Rust bindings
bindings/rust/* linguist-generated
Cargo.toml linguist-generated
Cargo.lock linguist-generated
# Node.js bindings
bindings/node/* linguist-generated
binding.gyp linguist-generated
package.json linguist-generated
package-lock.json linguist-generated
# Python bindings
bindings/python/** linguist-generated
setup.py linguist-generated
pyproject.toml linguist-generated
# Go bindings
bindings/go/* linguist-generated
go.mod linguist-generated
go.sum linguist-generated
# Swift bindings
bindings/swift/** linguist-generated
Package.swift linguist-generated
Package.resolved linguist-generated
================================================
FILE: .github/workflows/ci.yml
================================================
name: CI
on:
push:
branches: [master]
paths:
- grammar.js
- src/**
- test/**
- bindings/**
- binding.gyp
pull_request:
paths:
- grammar.js
- src/**
- test/**
- bindings/**
- binding.gyp
concurrency:
group: ${{github.workflow}}-${{github.ref}}
cancel-in-progress: true
jobs:
test:
name: Test parser
runs-on: ${{matrix.os}}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-14]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up tree-sitter
uses: tree-sitter/setup-action/cli@v1
- name: Set up examples
run: |-
git clone https://github.com/joshvera/effects examples/effects --single-branch --depth=1 --filter=blob:none
git clone https://github.com/PostgRest/postgrest examples/postgrest --single-branch --depth=1 --filter=blob:none
git clone https://github.com/GaloisInc/ivory examples/ivory --single-branch --depth=1 --filter=blob:none
git clone https://github.com/polysemy-research/polysemy examples/polysemy --single-branch --depth=1 --filter=blob:none
git clone https://github.com/github/semantic examples/semantic --single-branch --depth=1 --filter=blob:none
git clone https://github.com/haskell/haskell-language-server examples/haskell-language-server --single-branch --depth=1 --filter=blob:none
git clone https://github.com/AndrasKovacs/flatparse examples/flatparse --single-branch --depth=1 --filter=blob:none
git clone https://github.com/ekmett/lens examples/lens --single-branch --depth=1 --filter=blob:none
git clone https://github.com/tek/tsh-test-ghc examples/tsh-test-ghc --single-branch --depth=1 --filter=blob:none
- name: Run tests
uses: tree-sitter/parser-test-action@v2
with:
test-rust: ${{runner.os == 'Linux'}}
- name: Parse examples
id: examples
uses: tree-sitter/parse-action@v4
with:
files: |
examples/*.hs
!exampels/haskell-language-server/test/functional/Symbol.hs
!examples/lens/tests/properties.hs
!examples/semantic/semantic/test/fixtures/haskell/corpus/function-declarations.A.hs
!examples/semantic/semantic/test/fixtures/haskell/corpus/function-declarations.B.hs
!examples/semantic/semantic/test/fixtures/haskell/corpus/tempate-haskell.A.hs
!examples/semantic/semantic/test/fixtures/haskell/corpus/template-haskell.B.hs
!examples/semantic/semantic/test/fixtures/haskell/corpus/algebraic-datatype-declarations.A.hs
!examples/semantic/semantic/test/fixtures/haskell/corpus/algebraic-datatype-declarations.B.hs
!examples/semantic/semantic/test/fixtures/haskell/corpus/newtype-declaration.A.hs
!examples/semantic/semantic/test/fixtures/haskell/corpus/newtype-declaration.B.hs
!examples/semantic/semantic/test/fixtures/haskell/corpus/type-synonyms.A.hs
!examples/semantic/semantic/test/fixtures/haskell/corpus/type-synonyms.B.hs
!examples/polysemy/src/Polysemy/Law.hs
!examples/tsh-test-ghc/compiler/GHC/Builtin/PrimOps.hs
invalid-files: |
!examples/haskell-language-server/test/testdata/FuncTestFail.hs
================================================
FILE: .github/workflows/fuzz.yml
================================================
name: Fuzz Parser
on:
push:
branches: [master]
paths:
- src/scanner.c
pull_request:
paths:
- src/scanner.c
jobs:
fuzz:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Run fuzzer
uses: tree-sitter/fuzz-action@v4
================================================
FILE: .github/workflows/publish.yml
================================================
name: Publish packages
on:
push:
tags: ["*"]
permissions:
contents: write
id-token: write
attestations: write
jobs:
github:
uses: tree-sitter/workflows/.github/workflows/release.yml@main
with:
generate: true
attestations: true
npm:
uses: tree-sitter/workflows/.github/workflows/package-npm.yml@main
secrets:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
with:
generate: true
crates:
uses: tree-sitter/workflows/.github/workflows/package-crates.yml@main
secrets:
CARGO_REGISTRY_TOKEN: ${{secrets.CARGO_REGISTRY_TOKEN}}
with:
generate: true
pypi:
uses: tree-sitter/workflows/.github/workflows/package-pypi.yml@main
secrets:
PYPI_API_TOKEN: ${{secrets.PYPI_API_TOKEN}}
with:
generate: true
================================================
FILE: .gitignore
================================================
# Rust artifacts
target/
# Node artifacts
build/
prebuilds/
node_modules/
# Swift artifacts
.build/
# Go artifacts
_obj/
# Python artifacts
.venv/
dist/
*.egg-info
*.whl
# C artifacts
*.a
*.so
*.so.*
*.dylib
*.dll
*.pc
# Example dirs
/examples/*/
# Grammar volatiles
*.wasm
*.obj
*.o
# Archives
*.tar.gz
*.tgz
*.zip
================================================
FILE: CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.13)
project(tree-sitter-haskell
VERSION "0.23.1"
DESCRIPTION "Haskell grammar for tree-sitter"
HOMEPAGE_URL "https://github.com/tree-sitter/tree-sitter-haskell"
LANGUAGES C)
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
option(TREE_SITTER_REUSE_ALLOCATOR "Reuse the library allocator" OFF)
set(TREE_SITTER_ABI_VERSION 14 CACHE STRING "Tree-sitter ABI version")
if(NOT ${TREE_SITTER_ABI_VERSION} MATCHES "^[0-9]+$")
unset(TREE_SITTER_ABI_VERSION CACHE)
message(FATAL_ERROR "TREE_SITTER_ABI_VERSION must be an integer")
endif()
find_program(TREE_SITTER_CLI tree-sitter DOC "Tree-sitter CLI")
add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/parser.c"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/grammar.json"
COMMAND "${TREE_SITTER_CLI}" generate src/grammar.json
--abi=${TREE_SITTER_ABI_VERSION}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
COMMENT "Generating parser.c")
add_library(tree-sitter-haskell src/parser.c)
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/scanner.c)
target_sources(tree-sitter-haskell PRIVATE src/scanner.c)
endif()
target_include_directories(tree-sitter-haskell PRIVATE src)
target_compile_definitions(tree-sitter-haskell PRIVATE
$<$<BOOL:${TREE_SITTER_REUSE_ALLOCATOR}>:TREE_SITTER_REUSE_ALLOCATOR>
$<$<CONFIG:Debug>:TREE_SITTER_DEBUG>)
set_target_properties(tree-sitter-haskell
PROPERTIES
C_STANDARD 11
POSITION_INDEPENDENT_CODE ON
SOVERSION "${TREE_SITTER_ABI_VERSION}.${PROJECT_VERSION_MAJOR}"
DEFINE_SYMBOL "")
configure_file(bindings/c/tree-sitter-haskell.pc.in
"${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-haskell.pc" @ONLY)
include(GNUInstallDirs)
install(FILES bindings/c/tree-sitter-haskell.h
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/tree_sitter")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-haskell.pc"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig")
install(TARGETS tree-sitter-haskell
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}")
add_custom_target(ts-test "${TREE_SITTER_CLI}" test
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
COMMENT "tree-sitter test")
================================================
FILE: Cargo.toml
================================================
[package]
name = "tree-sitter-haskell"
description = "Haskell grammar for tree-sitter"
version = "0.23.1"
authors = ["Max Brunsfeld <maxbrunsfeld@gmail.com>"]
license = "MIT"
readme = "README.md"
keywords = ["incremental", "parsing", "tree-sitter", "haskell"]
categories = ["parsing", "text-editors"]
repository = "https://github.com/tree-sitter/tree-sitter-haskell"
edition = "2021"
autoexamples = false
build = "bindings/rust/build.rs"
include = ["LICENSE", "bindings/rust/*", "grammar.js", "queries/*", "src/*", "tree-sitter.json"]
[lib]
path = "bindings/rust/lib.rs"
[dependencies]
tree-sitter-language = "0.1"
[build-dependencies]
cc = "1.1.15"
[dev-dependencies]
tree-sitter = "0.23"
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2014 Max Brunsfeld
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: Makefile
================================================
ifeq ($(OS),Windows_NT)
$(error Windows is not supported)
endif
LANGUAGE_NAME := tree-sitter-haskell
HOMEPAGE_URL := https://github.com/tree-sitter/tree-sitter-haskell
VERSION := 0.23.1
# repository
SRC_DIR := src
TS ?= tree-sitter
# install directory layout
PREFIX ?= /usr/local
INCLUDEDIR ?= $(PREFIX)/include
LIBDIR ?= $(PREFIX)/lib
PCLIBDIR ?= $(LIBDIR)/pkgconfig
# source/object files
PARSER := $(SRC_DIR)/parser.c
EXTRAS := $(filter-out $(PARSER),$(wildcard $(SRC_DIR)/*.c))
OBJS := $(patsubst %.c,%.o,$(PARSER) $(EXTRAS))
# flags
ARFLAGS ?= rcs
override CFLAGS += -I$(SRC_DIR) -std=c11 -fPIC
# ABI versioning
SONAME_MAJOR = $(shell sed -n 's/\#define LANGUAGE_VERSION //p' $(PARSER))
SONAME_MINOR = $(word 1,$(subst ., ,$(VERSION)))
# OS-specific bits
ifeq ($(shell uname),Darwin)
SOEXT = dylib
SOEXTVER_MAJOR = $(SONAME_MAJOR).$(SOEXT)
SOEXTVER = $(SONAME_MAJOR).$(SONAME_MINOR).$(SOEXT)
LINKSHARED = -dynamiclib -Wl,-install_name,$(LIBDIR)/lib$(LANGUAGE_NAME).$(SOEXTVER),-rpath,@executable_path/../Frameworks
else
SOEXT = so
SOEXTVER_MAJOR = $(SOEXT).$(SONAME_MAJOR)
SOEXTVER = $(SOEXT).$(SONAME_MAJOR).$(SONAME_MINOR)
LINKSHARED = -shared -Wl,-soname,lib$(LANGUAGE_NAME).$(SOEXTVER)
endif
ifneq ($(filter $(shell uname),FreeBSD NetBSD DragonFly),)
PCLIBDIR := $(PREFIX)/libdata/pkgconfig
endif
all: lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT) $(LANGUAGE_NAME).pc
lib$(LANGUAGE_NAME).a: $(OBJS)
$(AR) $(ARFLAGS) $@ $^
lib$(LANGUAGE_NAME).$(SOEXT): $(OBJS)
$(CC) $(LDFLAGS) $(LINKSHARED) $^ $(LDLIBS) -o $@
ifneq ($(STRIP),)
$(STRIP) $@
endif
$(LANGUAGE_NAME).pc: bindings/c/$(LANGUAGE_NAME).pc.in
sed -e 's|@PROJECT_VERSION@|$(VERSION)|' \
-e 's|@CMAKE_INSTALL_LIBDIR@|$(LIBDIR:$(PREFIX)/%=%)|' \
-e 's|@CMAKE_INSTALL_INCLUDEDIR@|$(INCLUDEDIR:$(PREFIX)/%=%)|' \
-e 's|@PROJECT_DESCRIPTION@|$(DESCRIPTION)|' \
-e 's|@PROJECT_HOMEPAGE_URL@|$(HOMEPAGE_URL)|' \
-e 's|@CMAKE_INSTALL_PREFIX@|$(PREFIX)|' $< > $@
$(PARSER): $(SRC_DIR)/grammar.json
$(TS) generate $^
install: all
install -d '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter '$(DESTDIR)$(PCLIBDIR)' '$(DESTDIR)$(LIBDIR)'
install -m644 bindings/c/$(LANGUAGE_NAME).h '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h
install -m644 $(LANGUAGE_NAME).pc '$(DESTDIR)$(PCLIBDIR)'/$(LANGUAGE_NAME).pc
install -m644 lib$(LANGUAGE_NAME).a '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).a
install -m755 lib$(LANGUAGE_NAME).$(SOEXT) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER)
ln -sf lib$(LANGUAGE_NAME).$(SOEXTVER) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR)
ln -sf lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXT)
uninstall:
$(RM) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).a \
'$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER) \
'$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) \
'$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXT) \
'$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h \
'$(DESTDIR)$(PCLIBDIR)'/$(LANGUAGE_NAME).pc
clean:
$(RM) $(OBJS) $(LANGUAGE_NAME).pc lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT)
test:
$(TS) test
.PHONY: all install uninstall clean test
================================================
FILE: Package.resolved
================================================
{
"object": {
"pins": [
{
"package": "SwiftTreeSitter",
"repositoryURL": "https://github.com/ChimeHQ/SwiftTreeSitter",
"state": {
"branch": null,
"revision": "2599e95310b3159641469d8a21baf2d3d200e61f",
"version": "0.8.0"
}
}
]
},
"version": 1
}
================================================
FILE: Package.swift
================================================
// swift-tools-version:5.3
import PackageDescription
let package = Package(
name: "TreeSitterHaskell",
products: [
.library(name: "TreeSitterHaskell", targets: ["TreeSitterHaskell"]),
],
dependencies: [
.package(url: "https://github.com/ChimeHQ/SwiftTreeSitter", from: "0.8.0"),
],
targets: [
.target(
name: "TreeSitterHaskell",
dependencies: [],
path: ".",
sources: [
"src/parser.c",
"src/scanner.c",
],
resources: [
.copy("queries")
],
publicHeadersPath: "bindings/swift",
cSettings: [.headerSearchPath("src")]
),
.testTarget(
name: "TreeSitterHaskellTests",
dependencies: [
"SwiftTreeSitter",
"TreeSitterHaskell",
],
path: "bindings/swift/TreeSitterHaskellTests"
)
],
cLanguageStandard: .c11
)
================================================
FILE: README.md
================================================
# tree-sitter-haskell
[![CI][ci]](https://github.com/tree-sitter/tree-sitter-haskell/actions/workflows/ci.yml)
[![discord][discord]](https://discord.gg/w7nTvsVJhm)
[![matrix][matrix]](https://matrix.to/#/#tree-sitter-chat:matrix.org)
[![crates][crates]](https://crates.io/crates/tree-sitter-haskell)
[![npm][npm]](https://www.npmjs.com/package/tree-sitter-haskell)
[![pypi][pypi]](https://pypi.org/project/tree-sitter-haskell)
Haskell grammar for [tree-sitter].
# References
- [Haskell 2010 Language Report – Syntax References][ref]
- [GHC Language Extensions][ext]
# Supported Language Extensions
These extensions are supported ✅, unsupported ❌ or not applicable because they don't involve parsing ➖️:
- AllowAmbiguousTypes ➖️
- ApplicativeDo ➖️
- Arrows ❌
- BangPatterns ✅
- BinaryLiterals ✅
- BlockArguments ✅
- CApiFFI ✅
- ConstrainedClassMethods ✅
- ConstraintKinds ✅
- CPP ✅
- CUSKs ✅
- DataKinds ✅
- DatatypeContexts ✅
- DefaultSignatures ✅
- DeriveAnyClass ➖️
- DeriveDataTypeable ➖️
- DeriveFoldable ➖️
- DeriveFunctor ➖️
- DeriveGeneric ➖️
- DeriveLift ➖️
- DeriveTraversable ➖️
- DerivingStrategies ✅
- DerivingVia ✅
- DisambiguateRecordFields ➖️
- DuplicateRecordFields ➖️
- EmptyCase ✅
- EmptyDataDecls ✅
- EmptyDataDeriving ✅
- ExistentialQuantification ✅
- ExplicitForAll ✅
- ExplicitNamespaces ✅
- ExtendedDefaultRules ➖️
- FlexibleContexts ✅
- FlexibleInstances ✅
- ForeignFunctionInterface ✅
- FunctionalDependencies ✅
- GADTs ✅
- GADTSyntax ✅
- GeneralisedNewtypeDeriving ➖️
- GHCForeignImportPrim ✅
- Haskell2010 ➖️
- Haskell98 ➖️
- HexFloatLiterals ✅
- ImplicitParams ✅
- ImplicitPrelude ➖️
- ImportQualifiedPost ✅
- ImpredicativeTypes ➖️
- IncoherentInstances ➖️
- InstanceSigs ✅
- InterruptibleFFI ✅
- KindSignatures ✅
- LambdaCase ✅
- LexicalNegation ❌
- LiberalTypeSynonyms ✅
- LinearTypes ✅
- ListTuplePuns ✅
- MagicHash ✅
- Modifiers ❌
- MonadComprehensions ➖️
- MonadFailDesugaring ➖️
- MonoLocalBinds ➖️
- MonomorphismRestriction ➖️
- MultiParamTypeClasses ✅
- MultiWayIf ✅
- NamedFieldPuns ✅
- NamedWildCards ✅
- NegativeLiterals ➖️
- NondecreasingIndentation ✅
- NPlusKPatterns ➖️
- NullaryTypeClasses ✅
- NumDecimals ➖️
- NumericUnderscores ✅
- OverlappingInstances ➖️
- OverloadedLabels ✅
- OverloadedLists ➖️
- OverloadedRecordDot ✅
- OverloadedRecordUpdate ✅
- OverloadedStrings ➖️
- PackageImports ✅
- ParallelListComp ✅
- PartialTypeSignatures ✅
- PatternGuards ✅
- PatternSynonyms ✅
- PolyKinds ➖️
- PostfixOperators ➖️
- QualifiedDo ✅
- QuantifiedConstraints ✅
- QuasiQuotes ✅
- Rank2Types ✅
- RankNTypes ✅
- RebindableSyntax ➖️
- RecordWildCards ➖️
- RecursiveDo ✅
- RequiredTypeArguments ✅
- RoleAnnotations ✅
- Safe ➖️
- ScopedTypeVariables ✅
- StandaloneDeriving ✅
- StandaloneKindSignatures ✅
- StarIsType ✅
- StaticPointers ❌
- Strict ➖️
- StrictData ✅
- TemplateHaskell ✅
- TemplateHaskellQuotes ✅
- TraditionalRecordSyntax ➖️
- TransformListComp ✅
- Trustworthy ➖️
- TupleSections ✅
- TypeAbstractions ✅
- TypeApplications ✅
- TypeData ✅
- TypeFamilies ✅
- TypeFamilyDependencies ✅
- TypeInType ✅
- TypeOperators ✅
- TypeSynonymInstances ➖️
- UnboxedSums ✅
- UnboxedTuples ✅
- UndecidableInstances ➖️
- UndecidableSuperClasses ➖️
- UnicodeSyntax ✅
- UnliftedFFITypes ➖️
- UnliftedNewtypes ✅
- Unsafe ➖️
- ViewPatterns ✅
# Bugs
## CPP
Preprocessor `#elif` and `#else` directives cannot be handled correctly, since the parser state would have to be
manually reset to what it was at the `#if`.
As a workaround, the code blocks in the alternative branches are parsed as part of the directives.
# Querying
The grammar contains several [supertypes](https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types),
which group multiple other node types under a single name.
Supertype names do not occur as extra nodes in parse trees, but they can be used in queries in special ways:
- As an alias, matching any of their subtypes
- As prefix for one of their subtypes, matching its symbol only when it occurs as a production of the supertype
For example, the query `(expression)` matches the nodes `infix`, `record`, `projection`, `constructor`, and the second
and third `variable` in this tree for `cats <> Cat {mood = moods.sleepy}`:
```
(infix
(variable)
(operator)
(record
(constructor)
(field_update
(field_name (variable))
(projection (variable) (field_name (variable)))))))))
```
The two occurrences of `variable` in `field_name` (`mood` and `sleepy`) are not expressions, but record field names part
of a composite `record` expression.
Matching `variable` nodes specifically that are expressions is possible with the second special form.
A query for `(expression/variable)` will match only the other two, `cats` and `moods`.
The grammar's supertypes consist of the following sets:
- [`expression`](./grammar/exp.js)
Rules that are valid in any expression position, excluding type applications, explicit types and expression
signatures.
- [`pattern`](./grammar/pat.js)
Rules that are valid in any pattern position, excluding type binders, explicit types and pattern signatures.
- [`type`](./grammar/type.js)
Types that are either atomic (have no ambiguous associativity, like bracketed constructs, variables and type
constructors), applied types or infix types.
- [`quantified_type`](./grammar/type.js)
Types prefixed with a `forall`, context or function parameter.
- [`constraint`](./grammar/constraint.js)
Almost the same rules as `type`, but mirrored for use in contexts.
- [`constraints`](./grammar/constraints.js)
Analog of `quantified_type`, for constraints with `forall` or context.
- [`type_param`](./grammar/type.js)
Atomic nodes in type and class heads, like the three nodes following `A` in `data A @k a (b :: k)`.
- [`declaration`](./grammar/module.js)
All top-level declarations, like functions and data types.
- [`decl`](./grammar/decl.js)
Shorthand for declarations that are also valid in local bindings (`let` and `where`) and in class and instance bodies,
except for fixity declarations.
Consists of `signature`, `function` and `bind`.
- [`class_decl` and `instance_decl`](./grammar/class.js)
All declarations that are valid in classes and instances, which includes associated type and data families.
- [`statement`](./grammar/exp.js)
Different forms of `do`-notation statements.
- [`qualifier`](./grammar/exp.js)
Different forms of list comprehension qualifiers.
- [`guard`](./grammar/exp.js)
Different forms of guards in function equations and case alternatives.
# Development
The main driver for generating and testing the parser for this grammar is the [tree-sitter CLI][cli].
Other components of the project require additional tools, described below.
Some are made available through `npm` – for example, `npx tree-sitter` runs the CLI.
If you don't have `tree-sitter` available otherwise, prefix all the commands in the following sections with `npx`.
## Output path
The CLI writes the shared library containing the parser to the directory denoted by `$TREE_SITTER_LIBDIR`.
If that variable is unset, it defaults to `$HOME/.cache/tree-sitter/lib`.
In order to avoid clobbering this global directory with development versions, you can set the env var to a local path:
```
export TREE_SITTER_LIBDIR=$PWD/.lib
```
## The grammar
The javascript file `grammar.js` contains the entry point into the grammar's production rules.
Please consult the [tree-sitter documentation][grammar-docs] for a comprehensive introduction to the syntax and
semantics.
Parsing starts with the first item in the `rules` field:
```javascript
{
rules: {
haskell: $ => seq(
optional($.header),
optional($._body),
),
}
}
```
## Generating the parser
The first step in the development workflow converts the javascript rule definitions to C code in `src/parser.c`:
```
$ tree-sitter generate
```
Two byproducts of this process are written to `src/grammar.json` and `src/node-types.json`.
## Compiling the parser
The C code is automatically compiled by most of the test tools mentioned below, but you can instruct tree-sitter to do
it in one go:
```
$ tree-sitter generate --build
```
If you've set `$TREE_SITTER_LIBDIR` as mentioned above, the shared object will be written to `$PWD/.lib/haskell.so`.
Aside from the generated `src/parser.c`, tree-sitter will also compile and link `src/scanner.c` into this object.
This file contains the _external scanner_, which is a custom extension of the built-in lexer whose purpose is to handle
language constructs that cannot be expressed (efficiently) in the javascript grammar, like Haskell layouts.
### WebAssembly
The parser can be compiled to WebAssembly as well, which requires `emscripten`:
```
$ tree-sitter build --wasm
```
The resulting binary is written to `$PWD/tree-sitter-haskell.wasm`.
## Testing the parser
The most fundamental test infrastructure for tree-sitter grammars consists of a set of code snippets with associated
reference ASTs stored in `./test/corpus/*.txt`.
```
$ tree-sitter test
```
Individual tests can be run by specifying (a substring of) their description with `-f`:
```
$ tree-sitter test -f 'module: exports empty'
```
The project contains several other types of tests:
- `test/parse/run.bash [update] [test names ...]` parses the files in `test/parse/*.hs` and compares the output with
`test/parse/*.target`.
If `update` is specified as the first argument, it will update the `.target` file for the first failing test.
- `test/query/run.bash [update] [test names ...]` parses the files in `test/query/*.hs`, applies the queries in
`test/query/*.query` and compares the output with `test/query/*.target`, similar to `test/parse`.
- `test/rust/parse-test.rs` contains a few tests that use tree-sitter's Rust API to extract the test ranges for
terminals in a slightly more convenient way.
This requires `cargo` to be installed, and can be executed with `cargo test` (which also runs the tests in
`bindings/rust`).
- `test/parse-libs [wasm]` clones a set of Haskell libraries to `test/libs` and parses the entire codebase.
When invoked as `test/parse-libs wasm`, it will use the WebAssembly parser.
This requires `bc` to be installed.
- `test/parse-lib name [wasm]` parses only the library `name` in that directory (without cloning the repository).
### Debugging
The shared library built by `tree-sitter test` includes debug symbols, so if the scanner segfaults you can just run
`coredumpctl debug` to inspect the backtrace and memory:
```
newline_lookahead () at src/scanner.c:2583
2583 ((Newline *) 0)->indent = 5;
(gdb) bt
#0 newline_lookahead () at src/scanner.c:2583
#1 0x00007ffff7a0740e in newline_start () at src/scanner.c:2604
#2 scan () at src/scanner.c:2646
#3 eval () at src/scanner.c:2684
#4 tree_sitter_haskell_external_scanner_scan (payload=<optimized out>, lexer=<optimized out>,
valid_symbols=<optimized out>) at src/scanner.c:2724
#5 0x0000555555772488 in ts_parser.lex ()
```
For more control, launch `gdb tree-sitter` and start the process with `run test -f 'some test'`, and set a breakpoint
with `break tree_sitter_haskell_external_scanner_scan`.
To disable optimizations, run `tree-sitter test --debug-build`.
#### Tracing
The `test` and `parse` commands offer two modes for obtaining detailed information about the parsing process.
With `tree-sitter test --debug`, every lexer step and shift/reduce action is printed to stderr.
With `tree-sitter test --debug-graph`, the CLI will generate an HTML file showing a graph representation of every step.
This requires `graphviz` to be installed.
[tree-sitter]: https://github.com/tree-sitter/tree-sitter
[ref]: https://www.haskell.org/onlinereport/haskell2010/haskellch10.html
[ext]: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/exts/table.html
[cli]: https://github.com/tree-sitter/tree-sitter/tree/master/cli
[grammar-docs]: https://tree-sitter.github.io/tree-sitter/creating-parsers#writing-the-grammar
[ci]: https://img.shields.io/github/actions/workflow/status/tree-sitter/tree-sitter-haskell/ci.yml?logo=github&label=CI
[discord]: https://img.shields.io/discord/1063097320771698699?logo=discord&label=discord
[matrix]: https://img.shields.io/matrix/tree-sitter-chat%3Amatrix.org?logo=matrix&label=matrix
[npm]: https://img.shields.io/npm/v/tree-sitter-haskell?logo=npm
[crates]: https://img.shields.io/crates/v/tree-sitter-haskell?logo=rust
[pypi]: https://img.shields.io/pypi/v/tree-sitter-haskell?logo=pypi&logoColor=ffd242
================================================
FILE: binding.gyp
================================================
{
"targets": [
{
"target_name": "tree_sitter_haskell_binding",
"dependencies": [
"<!(node -p \"require('node-addon-api').targets\"):node_addon_api_except",
],
"include_dirs": [
"src",
],
"sources": [
"bindings/node/binding.cc",
"src/parser.c",
"src/scanner.c",
],
"conditions": [
["OS!='win'", {
"cflags_c": [
"-std=c11",
],
}, { # OS == "win"
"cflags_c": [
"/std:c11",
"/utf-8",
],
}],
],
}
]
}
================================================
FILE: bindings/c/tree-sitter-haskell.h
================================================
#ifndef TREE_SITTER_HASKELL_H_
#define TREE_SITTER_HASKELL_H_
typedef struct TSLanguage TSLanguage;
#ifdef __cplusplus
extern "C" {
#endif
const TSLanguage *tree_sitter_haskell(void);
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_HASKELL_H_
================================================
FILE: bindings/c/tree-sitter-haskell.pc.in
================================================
prefix=@CMAKE_INSTALL_PREFIX@
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
Name: tree-sitter-haskell
Description: @PROJECT_DESCRIPTION@
URL: @PROJECT_HOMEPAGE_URL@
Version: @PROJECT_VERSION@
Libs: -L${libdir} -ltree-sitter-haskell
Cflags: -I${includedir}
================================================
FILE: bindings/go/binding.go
================================================
package tree_sitter_haskell
// #cgo CFLAGS: -std=c11 -fPIC
// #include "../../src/parser.c"
// #include "../../src/scanner.c"
import "C"
import "unsafe"
// Get the tree-sitter Language for this grammar.
func Language() unsafe.Pointer {
return unsafe.Pointer(C.tree_sitter_haskell())
}
================================================
FILE: bindings/go/binding_test.go
================================================
package tree_sitter_haskell_test
import (
"testing"
tree_sitter "github.com/tree-sitter/go-tree-sitter"
tree_sitter_haskell "github.com/tree-sitter/tree-sitter-haskell/bindings/go"
)
func TestCanLoadGrammar(t *testing.T) {
language := tree_sitter.NewLanguage(tree_sitter_haskell.Language())
if language == nil {
t.Errorf("Error loading Haskell grammar")
}
}
================================================
FILE: bindings/node/binding.cc
================================================
#include <napi.h>
typedef struct TSLanguage TSLanguage;
extern "C" TSLanguage *tree_sitter_haskell();
// "tree-sitter", "language" hashed with BLAKE2
const napi_type_tag LANGUAGE_TYPE_TAG = {
0x8AF2E5212AD58ABF, 0xD5006CAD83ABBA16
};
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports["name"] = Napi::String::New(env, "haskell");
auto language = Napi::External<TSLanguage>::New(env, tree_sitter_haskell());
language.TypeTag(&LANGUAGE_TYPE_TAG);
exports["language"] = language;
return exports;
}
NODE_API_MODULE(tree_sitter_haskell_binding, Init)
================================================
FILE: bindings/node/binding_test.js
================================================
const assert = require("node:assert");
const { test } = require("node:test");
const Parser = require("tree-sitter");
test("can load grammar", () => {
const parser = new Parser();
assert.doesNotThrow(() => parser.setLanguage(require(".")));
});
================================================
FILE: bindings/node/index.d.ts
================================================
type BaseNode = {
type: string;
named: boolean;
};
type ChildNode = {
multiple: boolean;
required: boolean;
types: BaseNode[];
};
type NodeInfo =
| (BaseNode & {
subtypes: BaseNode[];
})
| (BaseNode & {
fields: { [name: string]: ChildNode };
children: ChildNode[];
});
type Language = {
name: string;
language: unknown;
nodeTypeInfo: NodeInfo[];
};
declare const language: Language;
export = language;
================================================
FILE: bindings/node/index.js
================================================
const root = require("path").join(__dirname, "..", "..");
module.exports =
typeof process.versions.bun === "string"
// Support `bun build --compile` by being statically analyzable enough to find the .node file at build-time
? require(`../../prebuilds/${process.platform}-${process.arch}/tree-sitter-haskell.node`)
: require("node-gyp-build")(root);
try {
module.exports.nodeTypeInfo = require("../../src/node-types.json");
} catch (_) {}
================================================
FILE: bindings/python/tests/test_binding.py
================================================
from unittest import TestCase
import tree_sitter, tree_sitter_haskell
class TestLanguage(TestCase):
def test_can_load_grammar(self):
try:
tree_sitter.Language(tree_sitter_haskell.language())
except Exception:
self.fail("Error loading Haskell grammar")
================================================
FILE: bindings/python/tree_sitter_haskell/__init__.py
================================================
"""Haskell grammar for tree-sitter"""
from importlib.resources import files as _files
from ._binding import language
def _get_query(name, file):
query = _files(f"{__package__}.queries") / file
globals()[name] = query.read_text()
return globals()[name]
def __getattr__(name):
if name == "HIGHLIGHTS_QUERY":
return _get_query("HIGHLIGHTS_QUERY", "highlights.scm")
if name == "INJECTIONS_QUERY":
return _get_query("INJECTIONS_QUERY", "injections.scm")
if name == "LOCALS_QUERY":
return _get_query("LOCALS_QUERY", "locals.scm")
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
__all__ = [
"language",
"HIGHLIGHTS_QUERY",
"INJECTIONS_QUERY",
"LOCALS_QUERY",
]
def __dir__():
return sorted(__all__ + [
"__all__", "__builtins__", "__cached__", "__doc__", "__file__",
"__loader__", "__name__", "__package__", "__path__", "__spec__",
])
================================================
FILE: bindings/python/tree_sitter_haskell/__init__.pyi
================================================
from typing import Final
HIGHLIGHTS_QUERY: Final[str]
INJECTIONS_QUERY: Final[str]
LOCALS_QUERY: Final[str]
def language() -> object: ...
================================================
FILE: bindings/python/tree_sitter_haskell/binding.c
================================================
#include <Python.h>
typedef struct TSLanguage TSLanguage;
TSLanguage *tree_sitter_haskell(void);
static PyObject* _binding_language(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) {
return PyCapsule_New(tree_sitter_haskell(), "tree_sitter.Language", NULL);
}
static PyMethodDef methods[] = {
{"language", _binding_language, METH_NOARGS,
"Get the tree-sitter language for this grammar."},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "_binding",
.m_doc = NULL,
.m_size = -1,
.m_methods = methods
};
PyMODINIT_FUNC PyInit__binding(void) {
return PyModule_Create(&module);
}
================================================
FILE: bindings/python/tree_sitter_haskell/py.typed
================================================
================================================
FILE: bindings/rust/build.rs
================================================
fn main() {
let src_dir = std::path::Path::new("src");
let mut c_config = cc::Build::new();
c_config
.std("c11")
.include(src_dir)
.flag_if_supported("-Wno-unused-value");
#[cfg(target_env = "msvc")]
c_config.flag("-utf-8");
let parser_path = src_dir.join("parser.c");
c_config.file(&parser_path);
println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap());
let scanner_path = src_dir.join("scanner.c");
c_config.file(&scanner_path);
println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap());
c_config.compile("tree-sitter-haskell");
}
================================================
FILE: bindings/rust/lib.rs
================================================
//! This crate provides Haskell language support for the [tree-sitter][] parsing library.
//!
//! Typically, you will use the [language][language func] function to add this language to a
//! tree-sitter [Parser][], and then use the parser to parse some code:
//!
//! ```
//! use tree_sitter::Parser;
//!
//! let code = r#"
//! main = putStrLn "Hello World!"
//! "#;
//! let mut parser = Parser::new();
//! let language = tree_sitter_haskell::LANGUAGE;
//! parser
//! .set_language(&language.into())
//! .expect("Error loading Haskell parser");
//! let tree = parser.parse(code, None).unwrap();
//! assert!(!tree.root_node().has_error());
//! ```
//!
//! [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html
//! [language func]: fn.language.html
//! [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html
//! [tree-sitter]: https://tree-sitter.github.io/
use tree_sitter_language::LanguageFn;
extern "C" {
fn tree_sitter_haskell() -> *const ();
}
/// The tree-sitter [`LanguageFn`] for this grammar.
pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_haskell) };
/// The content of the [`node-types.json`][] file for this grammar.
///
/// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types
pub const NODE_TYPES: &str = include_str!("../../src/node-types.json");
/// The syntax highlighting query for this language.
pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm");
/// The syntax highlighting query for languages injected into this one.
pub const INJECTIONS_QUERY: &str = include_str!("../../queries/injections.scm");
/// The local-variable syntax highlighting query for this language.
pub const LOCALS_QUERY: &str = include_str!("../../queries/locals.scm");
#[cfg(test)]
mod tests {
#[test]
fn test_can_load_grammar() {
let mut parser = tree_sitter::Parser::new();
parser
.set_language(&super::LANGUAGE.into())
.expect("Error loading Haskell parser");
}
}
================================================
FILE: bindings/swift/TreeSitterHaskell/haskell.h
================================================
#ifndef TREE_SITTER_HASKELL_H_
#define TREE_SITTER_HASKELL_H_
typedef struct TSLanguage TSLanguage;
#ifdef __cplusplus
extern "C" {
#endif
const TSLanguage *tree_sitter_haskell(void);
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_HASKELL_H_
================================================
FILE: bindings/swift/TreeSitterHaskellTests/TreeSitterHaskellTests.swift
================================================
import XCTest
import SwiftTreeSitter
import TreeSitterHaskell
final class TreeSitterHaskellTests: XCTestCase {
func testCanLoadGrammar() throws {
let parser = Parser()
let language = Language(language: tree_sitter_haskell())
XCTAssertNoThrow(try parser.setLanguage(language),
"Error loading Haskell grammar")
}
}
================================================
FILE: examples/Basic.hs
================================================
a = 1
b = 2
c = 3
================================================
FILE: go.mod
================================================
module github.com/tree-sitter/tree-sitter-haskell
go 1.22
require github.com/tree-sitter/go-tree-sitter v0.24.0
require github.com/mattn/go-pointer v0.0.1 // indirect
================================================
FILE: go.sum
================================================
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0=
github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tree-sitter/go-tree-sitter v0.24.0 h1:kRZb6aBNfcI/u0Qh8XEt3zjNVnmxTisDBN+kXK0xRYQ=
github.com/tree-sitter/go-tree-sitter v0.24.0/go.mod h1:x681iFVoLMEwOSIHA1chaLkXlroXEN7WY+VHGFaoDbk=
github.com/tree-sitter/tree-sitter-c v0.21.5-0.20240818205408-927da1f210eb h1:A8425heRM8mylnv4H58FPUiH+aYivyitre0PzxrfmWs=
github.com/tree-sitter/tree-sitter-c v0.21.5-0.20240818205408-927da1f210eb/go.mod h1:dOF6gtQiF9UwNh995T5OphYmtIypkjsp3ap7r9AN/iA=
github.com/tree-sitter/tree-sitter-cpp v0.22.4-0.20240818224355-b1a4e2b25148 h1:AfFPZwtwGN01BW1jDdqBVqscTwetvMpydqYZz57RSlc=
github.com/tree-sitter/tree-sitter-cpp v0.22.4-0.20240818224355-b1a4e2b25148/go.mod h1:Bh6U3viD57rFXRYIQ+kmiYtr+1Bx0AceypDLJJSyi9s=
github.com/tree-sitter/tree-sitter-embedded-template v0.21.1-0.20240819044651-ffbf64942c33 h1:TwqSV3qLp3tKSqirGLRHnjFk9Tc2oy57LIl+FQ4GjI4=
github.com/tree-sitter/tree-sitter-embedded-template v0.21.1-0.20240819044651-ffbf64942c33/go.mod h1:CvCKCt3v04Ufos1zZnNCelBDeCGRpPucaN8QczoUsN4=
github.com/tree-sitter/tree-sitter-go v0.21.3-0.20240818010209-8c0f0e7a6012 h1:Xvxck3tE5FW7F7bTS97iNM2ADMyCMJztVqn5HYKdJGo=
github.com/tree-sitter/tree-sitter-go v0.21.3-0.20240818010209-8c0f0e7a6012/go.mod h1:T40D0O1cPvUU/+AmiXVXy1cncYQT6wem4Z0g4SfAYvY=
github.com/tree-sitter/tree-sitter-html v0.20.5-0.20240818004741-d11201a263d0 h1:c46K6uh5Dz00zJeU9BfjXdb8I+E4RkUdfnWJpQADXFo=
github.com/tree-sitter/tree-sitter-html v0.20.5-0.20240818004741-d11201a263d0/go.mod h1:hcNt/kOJHcIcuMvouE7LJcYdeFUFbVpBJ6d4wmOA+tU=
github.com/tree-sitter/tree-sitter-java v0.21.1-0.20240824015150-576d8097e495 h1:jrt4qbJVEFs4H93/ITxygHc6u0TGqAkkate7TQ4wFSA=
github.com/tree-sitter/tree-sitter-java v0.21.1-0.20240824015150-576d8097e495/go.mod h1:oyaR7fLnRV0hT9z6qwE9GkaeTom/hTDwK3H2idcOJFc=
github.com/tree-sitter/tree-sitter-javascript v0.21.5-0.20240818005344-15887341e5b5 h1:om4X9AVg3asL8gxNJDcz4e/Wp+VpQj1PY3uJXKr6EOg=
github.com/tree-sitter/tree-sitter-javascript v0.21.5-0.20240818005344-15887341e5b5/go.mod h1:nNqgPoV/h9uYWk6kYEFdEAhNVOacpfpRW5SFmdaP4tU=
github.com/tree-sitter/tree-sitter-json v0.21.1-0.20240818005659-bdd69eb8c8a5 h1:pfV3G3k7NCKqKk8THBmyuh2zA33lgYHS3GVrzRR8ry4=
github.com/tree-sitter/tree-sitter-json v0.21.1-0.20240818005659-bdd69eb8c8a5/go.mod h1:GbMKRjLfk0H+PI7nLi1Sx5lHf5wCpLz9al8tQYSxpEk=
github.com/tree-sitter/tree-sitter-php v0.22.9-0.20240819002312-a552625b56c1 h1:ZXZMDwE+IhUtGug4Brv6NjJWUU3rfkZBKpemf6RY8/g=
github.com/tree-sitter/tree-sitter-php v0.22.9-0.20240819002312-a552625b56c1/go.mod h1:UKCLuYnJ312Mei+3cyTmGOHzn0YAnaPRECgJmHtzrqs=
github.com/tree-sitter/tree-sitter-python v0.21.1-0.20240818005537-55a9b8a4fbfb h1:EXEM82lFM7JjJb6qiKZXkpIDaCcbV2obNn82ghwj9lw=
github.com/tree-sitter/tree-sitter-python v0.21.1-0.20240818005537-55a9b8a4fbfb/go.mod h1:lXCF1nGG5Dr4J3BTS0ObN4xJCCICiSu/b+Xe/VqMV7g=
github.com/tree-sitter/tree-sitter-ruby v0.21.1-0.20240818211811-7dbc1e2d0e2d h1:fcYCvoXdcP1uRQYXqJHRy6Hec+uKScQdKVtMwK9JeCI=
github.com/tree-sitter/tree-sitter-ruby v0.21.1-0.20240818211811-7dbc1e2d0e2d/go.mod h1:T1nShQ4v5AJtozZ8YyAS4uzUtDAJj/iv4YfwXSbUHzg=
github.com/tree-sitter/tree-sitter-rust v0.21.3-0.20240818005432-2b43eafe6447 h1:o9alBu1J/WjrcTKEthYtXmdkDc5OVXD+PqlvnEZ0Lzc=
github.com/tree-sitter/tree-sitter-rust v0.21.3-0.20240818005432-2b43eafe6447/go.mod h1:1Oh95COkkTn6Ezp0vcMbvfhRP5gLeqqljR0BYnBzWvc=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
================================================
FILE: grammar/class.js
================================================
const {
sep1,
layout,
context,
forall,
} = require('./util.js')
module.exports = {
// ------------------------------------------------------------------------
// associated families
// ------------------------------------------------------------------------
/**
* In associated family declarations, result type aliasing without injectivity is invalid, since that syntax is taken
* by type instance declarations.
*/
_assoc_tyfam: $ => seq(
'type',
optional('family'),
$._type_head,
optional(choice(
$._kind_annotation,
seq(
$.type_family_result,
$.type_family_injectivity,
),
)),
),
_assoc_tyinst: $ => seq(
'type',
optional('instance'),
forall($),
$._cond_assoc_tyinst,
$._type_instance_common,
),
_assoc_datafam: $ => seq(
'data',
optional('family'),
$._datafam,
),
_assoc_datainst_adt: $ => seq(
'data',
optional('instance'),
$._inst_adt,
),
_assoc_datainst_newtype: $ => seq(
'newtype',
optional('instance'),
$._inst_newtype,
),
_assoc_datainst: $ => choice(
alias($._assoc_datainst_adt, $.data_type),
alias($._assoc_datainst_newtype, $.newtype),
),
// ------------------------------------------------------------------------
// class
// ------------------------------------------------------------------------
default_signature: $ => seq('default', field('signature', $.signature)),
/**
* Classes can have both type families and instances, but only data families.
*/
class_decl: $ => choice(
$._local_decl,
$.default_signature,
alias($._assoc_tyfam, $.type_family),
alias($._assoc_tyinst, $.type_instance),
alias($._assoc_datafam, $.data_family),
),
fundep: $ => seq(
field('matched', repeat1($.variable)),
$._arrow,
field('determined', repeat1($.variable)),
),
fundeps: $ => seq($._bar, sep1(',', field('fundep', $.fundep))),
class_declarations: $ => layout($, field('declaration', $.class_decl)),
class: $ => seq(
'class',
context($),
$._type_head,
field('fundeps', optional($.fundeps)),
optional(seq($._where, optional(field('declarations', $.class_declarations)))),
),
// ------------------------------------------------------------------------
// instance
// ------------------------------------------------------------------------
instance_decl: $ => choice(
$.decl,
alias($._assoc_datainst, $.data_instance),
alias($._assoc_tyinst, $.type_instance),
),
instance_declarations: $ => layout($, field('declaration', $.instance_decl)),
/**
* instances only allow single foralls and contexts
*/
_instance: $ => seq(
'instance',
forall($),
context($),
$._type_instance_head,
),
instance: $ => seq(
$._instance,
optional(seq($._where, optional(field('declarations', $.instance_declarations)))),
),
deriving_instance: $ => seq(
optional($._phantom_deriving),
'deriving',
optional(choice(field('strategy', $.deriving_strategy), field('via', $.via))),
$._instance,
),
}
================================================
FILE: grammar/conflicts.js
================================================
module.exports = {
conflicts: $ => [
/**
* For reference in GHC:
* - Note [Ambiguous syntactic categories]
* - Note [PatBuilder]
* - Note [Declaration/signature overlap]
* - These correspond to `DisambECP`
*
* (fun x) y = undefined
* (fun x -> y) = undefined
* (fun) <> x = undefined
*
* The first one is a regular function with some redundant parens, where `fun` is the declared name.
* The second one is a pattern binder with a view pattern, where `fun` is a free variable.
* The third one is an infix pattern binder, where `fun` is a simple varid pattern with redundant parens.
*
* These conflicts are also relevant for top-level expression splices, which fundamentally conflict with decls, and
* since decls start with either `var` or `pat`, they cannot be disambiguated.
*
* GHC parses functions and binds as expressions and sorts them into the right LHS in a post-processing step.
* Since this is not possible in tree-sitter, these conflicts are more function-centric than in GHC.
*
* function:
* func (A a) = a
*
* bind variable:
* a : as = [1, 2, 3]
*
* pattern bind infix:
* a : as = [1, 2, 3]
*
* pattern bind prefix:
* Just 1 = Just 1
*
* splice:
* makeLenses ''A
*
* Signature and bind:
*
* fun :: Int
* fun :: Int = 5
*/
// Function vs bind
[$._function_name, $.pattern],
// Function vs bind vs splice
[$._function_name, $.pattern, $.expression],
// Bind vs splice
[$.pattern, $.expression],
// Signature vs bind
[$.signature, $.pattern],
/**
* Unboxed syntax
*
* The hash in the opening parenthesis of unboxed tuples can be an operator.
*/
[$._operator_hash_head, $._unboxed_open],
/**
* Types conflicting with structures that look like types
*
* Note: These conflicts have been circumvented by a lookahead mechanism in the scanner.
* This comment is preserved for reference.
*
* `name` and `constructor` use the same terminal symbol, but we cannot reduce `constructor` in prefix data
* constructor declarations.
*
* In GHC, this corresponds to `DisambTD`.
*
* > data A = Name Int
* > data A = Maybe Int :+ Int
* > data A = Monoid a => A a
*
* All of these start with a `name` node.
* In the first example, the `name` is a data constructor, which will not be reduced to a `type`.
*
* In the second example, the `name` is a type constructor applied to another type in the left operand of an infix
* data constructor, so it must be reduced to `type`, and then to `apply` with the `Int`.
*
* In the third example, the `name` is a type constructor applied to a variable resulting in a constraint.
* It will be reduced the same way as the second example, but using the class tree, which is mostly identical to the
* type tree, but conflicts since we want to distinguish classes from types granularly.
*
* In GHC, these correspond to `mkHsAppTyHeadPV` and `mkHsAppTyPV`.
*
* > data A a b = a `C` b => a `A` b
* > data A a b = a `A` b
*
* > data a *** b
* > data a +++ b => a *** b
*
* In GHC, this corresponds to `mkHsOpTyPV`.
*
* > class A where type a + b = r | r -> a b
* > class A where type a + b = (a, b)
*
* The first one is a type family declaration, the second one an instance.
*
* These were the conflicts that have been turned into scanner lookahead:
*
* [$._type_con, $.data_constructor],
* [$._type_con, $._type_head_name],
* [$._type_variable, $._tyvar],
* [$._constructor_ticked, $._tycon_ticked],
*/
],
}
================================================
FILE: grammar/context.js
================================================
const {
parens,
sep2,
} = require('./util.js')
module.exports = {
// ------------------------------------------------------------------------
// context
// ------------------------------------------------------------------------
_class_apply: $ => prec.left('apply', seq(
field('constructor', $.constraint),
field('argument', $._type_apply_arg),
)),
_class_infix: $ => prec.right('infix', seq(
$._cond_infix,
field('left_operand', $.type),
field('operator', $._tyops),
field('right_operand', $.type),
)),
_ctr_parens: $ => parens($, $.constraints),
_ctr_tuple: $ => parens($, sep2(',', $.constraints)),
/**
* Implicit parameters have an annotation with `::` but bind tighter than `_type_signature`, with the same precedence
* as foralls, contexts and arrows.
*
* > A => ?a :: A | associates as | A => (?a :: A)
* > ?a :: A -> A | associates as | ?a :: (A -> A)
*/
implicit_parameter: $ => prec.left(seq(field('name', $.implicit_variable), $._type_annotation)),
constraint: $ => choice(
$._type_name,
alias($._class_infix, $.infix),
alias($._class_apply, $.apply),
alias($._ctr_parens, $.parens),
alias($._ctr_tuple, $.tuple),
alias($._type_wildcard, $.wildcard),
$._universal,
),
_ctr_forall: $ => prec('fun', seq($._forall_body, '.', field('constraint', $.constraints))),
_ctr_context: $ => prec('fun', seq($._context_inline, field('constraint', $.constraints))),
_ctr_signature: $ => prec('annotated', seq(field('constraint', $.constraints), $._kind_annotation)),
constraints: $ => choice(
$.constraint,
alias($._ctr_context, $.context),
alias($._ctr_forall, $.forall),
$.implicit_parameter,
alias($._ctr_signature, $.signature),
),
_context_inline: $ => seq(
$._cond_context,
field('context', $.constraint),
field('arrow', $._carrow),
),
context: $ => prec('qtype-single', $._context_inline),
}
================================================
FILE: grammar/data.js
================================================
const {
sep1,
sep,
braces,
layout,
unboxed_sum_single,
qualified,
context,
forall,
} = require('./util.js')
module.exports = {
// ------------------------------------------------------------------------
// fields
// ------------------------------------------------------------------------
field_name: $ => $.variable,
_qfield_name: $ => qualified($, $.field_name),
_field_names: $ => choice($.field_name, alias($._qfield_name, $.qualified)),
field_path: $ => seq(
field('field', $._field_names),
repeat1(seq($._tight_dot, field('subfield', $.field_name))),
),
_field_spec: $ => choice(
$._field_names,
$.field_path,
),
field: $ => prec('annotated', seq(
sep1(',', field('name', $.field_name)),
$._colon2,
field('type', $._parameter_type),
)),
_record_fields: $ => braces($, sep(',', field('field', $.field)), optional(',')),
// ------------------------------------------------------------------------
// deriving
// ------------------------------------------------------------------------
via: $ => seq('via', field('type', $.quantified_type)),
deriving_strategy: _ => choice('stock', 'newtype', 'anyclass'),
deriving: $ => seq(
optional($._phantom_deriving),
'deriving',
optional(field('strategy', $.deriving_strategy)),
field('classes', $.constraint),
optional(field('via', $.via)),
),
// ------------------------------------------------------------------------
// gadt
// ------------------------------------------------------------------------
_gadt_con_prefix: $ => field('type', $.quantified_type),
_gadt_con_record: $ => seq(
field('fields', alias($._record_fields, $.fields)),
field('arrow', $._fun_arrow),
field('type', $.quantified_type),
),
/**
* GADT constructors only allow single foralls and contexts
*/
gadt_constructor: $ => seq(
choice(
field('name', $._con),
field('names', alias($._con_binding_list, $.binding_list)),
),
$._colon2,
forall($),
context($),
field('type', choice(
alias($._gadt_con_prefix, $.prefix),
alias($._gadt_con_record, $.record),
)),
),
gadt_constructors: $ => layout($, field('constructor', $.gadt_constructor)),
_gadt: $ => seq(
optional($._kind_annotation),
$._where,
optional(field('constructors', $.gadt_constructors)),
),
// ------------------------------------------------------------------------
// data type
// ------------------------------------------------------------------------
_field_type: $ => choice($.strict_field, $.lazy_field, $.type),
_datacon_prefix: $ => seq(
field('name', $._con),
repeat(prec('patterns', field('field', $._field_type))),
),
_datacon_infix: $ => prec('infix', seq(
$._cond_data_infix,
field('left_operand', $._field_type),
field('operator', $._conop),
field('right_operand', $._field_type),
)),
_datacon_record: $ => seq(
field('name', $._constructor),
field('fields', alias($._record_fields, $.fields)),
),
_datacon_unboxed_sum: $ => unboxed_sum_single($, $.quantified_type),
/**
* Special constructors occurring in GHC code
*/
_datacon_special: $ => choice(
$.unit,
$.unboxed_unit,
alias($._plist, $.empty_list),
alias($._type_tuple, $.tuple),
alias($._type_unboxed_tuple, $.unboxed_tuple),
alias($._datacon_unboxed_sum, $.unboxed_sum),
),
/**
* data constructors only allow single foralls and contexts
*/
data_constructor: $ => seq(
forall($),
context($),
field('constructor', choice(
alias($._datacon_prefix, $.prefix),
alias($._datacon_infix, $.infix),
alias($._datacon_record, $.record),
alias($._datacon_special, $.special),
)),
),
data_constructors: $ => sep1($._bar, field('constructor', $.data_constructor)),
_data_rhs: $ => choice(
$._kind_annotation,
seq('=', field('constructors', $.data_constructors)),
$._gadt,
),
_data: $ => seq(
context($),
$._type_head,
optional($._data_rhs),
repeat(field('deriving', $.deriving)),
),
data_type: $ => seq(
optional('type'),
'data',
$._data,
),
// ------------------------------------------------------------------------
// newtype
// ------------------------------------------------------------------------
_newtype_con_field: $ => $.type,
newtype_constructor: $ => seq(
field('name', $._con),
field('field', choice(
alias($._newtype_con_field, $.field),
alias($._record_fields, $.record),
)),
),
_newtype: $ => seq(
choice(
seq('=', field('constructor', $.newtype_constructor)),
$._gadt,
),
repeat(field('deriving', $.deriving)),
),
newtype: $ => seq(
'newtype',
context($),
$._type_head,
$._newtype,
),
// ------------------------------------------------------------------------
// data family
// ------------------------------------------------------------------------
_datafam: $ => seq(
$._type_head,
optional($._kind_annotation),
),
data_family: $ => seq(
'data',
'family',
$._datafam,
),
_inst_adt: $ => seq(
forall($),
context($),
$._type_instance_head,
optional($._data_rhs),
repeat(field('deriving', $.deriving)),
),
decl_inst_adt: $ => seq(
'data',
'instance',
$._inst_adt,
),
_inst_newtype: $ => seq(
forall($),
context($),
$._type_instance_head,
$._newtype,
),
decl_inst_newtype: $ => seq(
'newtype',
'instance',
$._inst_newtype,
),
data_instance: $ => choice(
alias($.decl_inst_adt, $.data_type),
alias($.decl_inst_newtype, $.newtype),
),
}
================================================
FILE: grammar/decl.js
================================================
const {
sep1,
sep2,
parens,
layout,
} = require('./util.js')
module.exports = {
// ------------------------------------------------------------------------
// fixity
// ------------------------------------------------------------------------
_fun_arrow_prec: _ => seq('-', '1'),
// GHC.Types special decl
_fun_arrow_fixity: $ => seq(
field('associativity', 'infixr'),
field('precedence', alias($._fun_arrow_prec, $.integer)),
field('operator', alias('->', $.operator)),
),
fixity: $ => choice(
$._fun_arrow_fixity,
seq(
field('associativity', choice('infixl', 'infixr', 'infix')),
field('precedence', optional($.integer)),
field('operator', sep1(',', choice($._operator_minus, $._varop, $._conop))),
),
),
// ------------------------------------------------------------------------
// signature
// ------------------------------------------------------------------------
_con_binding_list: $ => sep2(',', field('name', $._con)),
_var_binding_list: $ => sep2(',', field('name', $._var)),
signature: $ => seq(
choice(
field('name', $._var),
field('names', alias($._var_binding_list, $.binding_list)),
),
$._type_annotation,
),
// ------------------------------------------------------------------------
// function and pattern bind
// ------------------------------------------------------------------------
_simple_bind_match: $ => seq('=', field('expression', $._exp)),
_bind_match: $ => seq(
$._guards,
'=',
$._cmd_texp_end,
field('expression', $._exp),
),
_bind_matches: $ => seq(
choice(
field('match', alias($._simple_bind_match, $.match)),
repeat1(field('match', alias($._bind_match, $.match))),
),
optional($._where_binds),
),
_function_name: $ => field('name', $._var),
function_head_parens: $ => parens(
$,
choice(
$._function_head,
$._function_head_patterns,
),
),
_function_head_patterns: $ => choice(
$._function_name,
field('parens', $.function_head_parens),
),
/**
* The difference between a `function` with an `infix` head and a `bind` with `pat_infix` is that the former is for
* _declaring_ a `varop` and the latter uses a `conop` to pattern match on the rhs expression.
* The former may not have a type annotation, while the latter may.
*
* > a <> b = undefined
* > h : t :: [Int] = undefined
*/
_function_head_infix: $ => seq(
field('left_operand', $.pattern),
optional($._cond_no_section_op),
field('operator', choice(seq($._cond_minus, $._operator_minus), $._varop)),
field('right_operand', $.pattern),
),
_function_head: $ => choice(
seq($._function_head_patterns, field('patterns', $.patterns)),
alias($._function_head_infix, $.infix),
),
function: $ => seq(
$._function_head,
$._bind_matches,
),
/**
* The `implicit_variable` here is for:
* g = let ?par = Impy 5 in f
*/
bind: $ => prec('bind', seq(
choice(
field('pattern', $._pat),
field('name', $._var),
field('implicit', $.implicit_variable),
),
$._bind_matches,
)),
/**
* This is a supertype.
*/
decl: $ => choice(
$.signature,
$.function,
$.bind,
),
_local_decl: $ => choice(
$.fixity,
$.decl,
),
local_binds: $ => layout($, field('decl', $._local_decl)),
_where_binds: $ => seq($._where, optional(field('binds', $.local_binds))),
// ------------------------------------------------------------------------
// foreign
// ------------------------------------------------------------------------
calling_convention: _ => token(choice(
'ccall',
'stdcall',
'capi',
'prim',
'javascript',
/[A-Z_]+/, // It's common in GHC to use a cpp #define for this
)),
safety: _ => token(choice(
'unsafe',
'safe',
'interruptible',
)),
entity: $ => $.string,
foreign_import: $ => seq(
'foreign',
'import',
field('calling_convention', $.calling_convention),
optional(field('safety', $.safety)),
optional(field('entity', $.entity)),
field('signature', $.signature),
),
foreign_export: $ => seq(
'foreign',
'export',
field('calling_convention', $.calling_convention),
optional(field('entity', $.entity)),
field('signature', $.signature),
),
// ------------------------------------------------------------------------
// default
// ------------------------------------------------------------------------
default_types: $ => seq('default', parens($, optional(sep1(',', field('type', $._ktype))))),
}
================================================
FILE: grammar/exp.js
================================================
const {
sep1,
sep,
parens,
braces,
brackets,
layout_sort,
layout,
unboxed_tuple_nonempty,
unboxed_sum_single,
qualified,
} = require('./util.js')
module.exports = {
// ------------------------------------------------------------------------
// names
// ------------------------------------------------------------------------
_exp_name: $ => choice(
$._cons,
$._vars,
$.variable,
$.implicit_variable,
$.label,
),
_exp_th_quoted_name: $ => choice(
seq('\'', field('name', choice($._vars, $._cons))),
prec('prefix', seq('\'\'', field('type', $.type))),
),
// ------------------------------------------------------------------------
// tuples and parens
// ------------------------------------------------------------------------
_exp_parens: $ => parens($, field('expression', $._exp)),
// Having this separate reduces size by ~15kB
_exp_tuple_elems: $ => seq(
choice(
seq(repeat1(','), field('element', $._exp)),
seq(field('element', $._exp), ',', optional(field('element', $._exp))),
),
repeat(seq(',', optional(field('element', $._exp))))
),
/**
* This needs to be disambiguated from `prefix_tuple`, which is a constructor with _only_ commas.
* Tuple sections aren't allowed in patterns.
*
* Since tuple expressions can contain singular expressions in sections like `(a,)` and `(,a)`, it has to be ensured
* that there is _at least_ each one comma and one expression in there, but the comma may be on either side and be
* preceded by any number of further commas, like `(,,,a)`.
*
* The final `repeat` is simpler, it just has to ensure that no two `_exp`s can be successive, but this encoding
* means that the optional `_exp` after `(5,)` needs to be included in the `choice`, otherwise a simple pair
* would be impossible.
*/
_exp_tuple: $ => parens($, $._exp_tuple_elems),
/**
* Unlike their boxed variants, unboxed tuples may be nullary and unary, making it simpler to parse them.
*/
_exp_unboxed_tuple: $ => unboxed_tuple_nonempty($, $._exp),
/**
* Unboxed sums must have at least one separating `|`, otherwise the expression would be a unary or nullary tuple.
* This is a lenient parser that allows multiple variants to be filled in, for simplicity.
*/
_exp_unboxed_sum: $ => unboxed_sum_single($, $._exp),
// ------------------------------------------------------------------------
// lists
// ------------------------------------------------------------------------
_exp_list: $ => brackets($, sep1(',', field('element', $._exp)), optional(',')),
/**
* An expression like `[1,2..20]`.
*/
_exp_arithmetic_sequence: $ => brackets(
$,
field('from', $._exp),
optional(seq(',', field('step', $._exp))),
$._dotdot,
optional(field('to', $._exp)),
),
/**
* `TransformListComp`, group style.
*
* Inlining `_exp` here is necessary to avoid a conflict.
*/
group: $ => seq(
'then',
'group',
optional(seq('by', field('key', choice(alias($._exp_signature, $.signature), $.expression)))),
'using',
field('classifier', $._exp),
),
/**
* `TransformListComp`, simple transformation style.
*/
transform: $ => seq(
'then',
field('transformation', $._exp),
optional(seq('by', field('key', $._exp))),
),
qualifier: $ => choice(
$.generator,
$.let,
$.transform,
$.group,
alias($._exp, $.boolean),
),
/**
* This is a supertype.
*/
qualifiers: $ => seq(sep1(',', field('qualifier', $.qualifier))),
_exp_list_comprehension: $ => brackets(
$,
field('expression', $._exp),
repeat1(seq('|', field('qualifiers', $.qualifiers))),
),
// ------------------------------------------------------------------------
// greedy block args
// ------------------------------------------------------------------------
_exp_lambda: $ => seq(
'\\',
field('patterns', $.patterns),
$._arrow,
field('expression', $._exp),
),
_exp_let_in: $ => seq($._let, optional($._phantom_in), 'in', field('expression', $._exp)),
_exp_conditional: $ => seq(
'if',
field('if', $._exp),
repeat(';'),
'then',
field('then', $._exp),
repeat(';'),
'else',
field('else', $._exp),
),
/**
* These block arguments don't end in a layout, so they all range over all following block arguments and will
* therefore always be the last argument in an application or infix chain.
* They also pull a trailing type annotation into their body.
*/
_exp_greedy: $ => choice(
alias($._exp_lambda, $.lambda),
alias($._exp_let_in, $.let_in),
alias($._exp_conditional, $.conditional),
),
// ------------------------------------------------------------------------
// do
// ------------------------------------------------------------------------
_exp_statement: $ => $._exp,
/**
* This is a supertype.
*/
statement: $ => choice(
alias($._exp_statement, $.exp),
alias($.generator, $.bind),
$.let,
$.rec,
),
_statements: $ => layout_sort($, $._cmd_layout_start_do, field('statement', $.statement)),
rec: $ => seq('rec', $._statements),
_do_keyword: _ => choice('mdo', 'do'),
do_module: $ => field('qualified_do', qualified($, $._do_keyword)),
_do: $ => choice(
$.do_module,
$._do_keyword
),
_exp_do: $ => seq($._do, $._statements),
// ------------------------------------------------------------------------
// case
// ------------------------------------------------------------------------
match: $ => seq(
$._guards,
optional($._phantom_arrow),
$._arrow,
$._cmd_texp_end,
field('expression', $._exp),
),
_simple_match: $ => seq($._arrow, field('expression', $._exp)),
_matches: $ => field('match', choice(
alias($._simple_match, $.match),
repeat1($.match),
)),
alternative: $ => seq(
field('pattern', $._pat),
$._matches,
optional($._where_binds),
),
_nalt: $ => seq(
field('patterns', $.patterns),
$._matches,
optional($._where_binds),
),
alternatives: $ => layout_sort($, $._cmd_layout_start_case, field('alternative', $.alternative)),
_nalts: $ => layout_sort($, $._cmd_layout_start_case, field('alternative', alias($._nalt, $.alternative))),
_exp_case: $ => seq('case', $._exp, 'of', optional(field('alternatives', $.alternatives))),
_exp_lambda_case: $ => seq(
'\\',
'case',
optional(field('alternatives', $.alternatives)),
),
/**
* alternatives are not optional in a `\cases` expression, but we're lenient.
*/
_exp_lambda_cases: $ => seq(
'\\',
'cases',
optional(field('alternatives', alias($._nalts, $.alternatives))),
),
_exp_multi_way_if: $ => seq(
'if',
$._cmd_layout_start_if,
repeat(field('match', $.match)),
$._cond_layout_end,
),
// ------------------------------------------------------------------------
// record
// ------------------------------------------------------------------------
field_update: $ => choice(
alias('..', $.wildcard),
seq(
field('field', $._field_spec),
optional(seq('=', field('expression', $._exp)))
),
),
_exp_record: $ => prec('record', seq(
field('expression', $.expression),
braces($, sep(',', field('field', $.field_update)))),
),
_exp_projection_selector: $ => parens(
$,
$._any_prefix_dot,
field('field', $.variable),
repeat(seq($._tight_dot, field('field', $.variable))),
),
/**
* A dot-syntax field projection like `var.name.othername`.
*/
_exp_projection: $ => seq(
prec('projection', seq(
field('expression', $.expression),
$._tight_dot,
)),
field('field', $.field_name),
),
// ------------------------------------------------------------------------
// application
// ------------------------------------------------------------------------
explicit_type: $ => parens($, 'type', field('type', $.type)),
_exp_apply: $ => prec.left('apply', seq(
field('function', $.expression),
field('argument', choice(
$.expression,
alias($._at_type, $.type_application),
$.explicit_type,
)),
)),
// ------------------------------------------------------------------------
// operators
// ------------------------------------------------------------------------
_exp_op: $ => choice(
$._sym,
$._op_ticked,
alias($._prefix_dot, $.operator),
),
_exp_section_left: $ => parens(
$,
field('left_operand', $.expression),
$._cond_left_section_op,
field('operator', choice(
$._exp_op,
$._operator_minus,
$._qsym,
)),
),
_exp_section_right: $ => parens(
$,
choice(
alias($._operator_qual_dot_head, $.operator),
$._ops,
),
field('right_operand', $.expression),
),
_exp_negation: $ => seq(
field('minus', '-'),
prec('negation', field('expression', $.expression)),
),
/**
* Infix expressions have severe conflicts with several structures:
*
* - Negation is supposed to bind less tight than application and tighter than infix, which requires an unsolvable
* precedence configuration
* - Qualified operators cannot be identified with single-token lookahead, which causes ambiguity with function
* application
* - Left operator sections require infix expressions in their operand to reduce before the section operator, but
* single-token lookahead also makes this decision impossible
*
* All of these are solved with external symbols.
* Consult `grammar/externals.js` for more information.
*/
_exp_infix: $ => prec.right('infix', seq(
field('left_operand', $.expression),
optional($._cond_no_section_op),
field('operator', choice(
seq($._cond_minus, $._operator_minus),
$._exp_op,
seq($._cond_qualified_op, $._qsym),
)),
field('right_operand', $.expression),
)),
// ------------------------------------------------------------------------
// top level
// ------------------------------------------------------------------------
/**
* This is a supertype.
*/
expression: $ => choice(
alias($._exp_infix, $.infix),
alias($._exp_negation, $.negation),
alias($._exp_apply, $.apply),
alias($._exp_record, $.record),
alias($._exp_projection, $.projection),
alias($._exp_arithmetic_sequence, $.arithmetic_sequence),
alias($._exp_list_comprehension, $.list_comprehension),
alias($._exp_unboxed_tuple, $.unboxed_tuple),
alias($._exp_unboxed_sum, $.unboxed_sum),
alias($._exp_projection_selector, $.projection_selector),
alias($._exp_quote, $.quote),
alias($._exp_typed_quote, $.typed_quote),
alias($._exp_th_quoted_name, $.th_quoted_name),
alias($._exp_lambda_case, $.lambda_case),
alias($._exp_lambda_cases, $.lambda_cases),
alias($._exp_do, $.do),
alias($._exp_parens, $.parens),
alias($._exp_tuple, $.tuple),
alias($._exp_list, $.list),
// Not using a name like "empty list" here because it's only really special in types.
alias($._plist, $.list),
alias($._exp_section_left, $.left_section),
alias($._exp_section_right, $.right_section),
$._exp_greedy,
alias($._exp_case, $.case),
alias($._exp_multi_way_if, $.multi_way_if),
$._exp_name,
$._universal,
),
_exp_signature: $ => prec.right('annotated', seq(
field('expression', $.expression),
$._type_annotation,
)),
_exp: $ => choice(
alias($._exp_signature, $.signature),
// Right-associative means that the reduction of `expression` to `_exp` loses against any shift.
prec.right($.expression),
),
}
================================================
FILE: grammar/externals.js
================================================
module.exports = {
/**
* These rules are handled manually by the custom lexer in `src/scanner.c`.
* Whenever the symbols are used in the rule tree, the parser executes the scanner.
* Since several symbols are present both here and in `extras`, the scanner will be invoked before every single
* natively lexed symbol, repeatedly, until it fails.
* This makes indentation/layout tracking simpler.
*
* There are three special behavioral classes of symbols in this grammar, indicated by their name prefix:
*
* `cmd`: Commands are sequenced after key tokens like opening braces that unconditionally trigger a state change in
* the scanner.
* They don't require the scanner to _decide_ that a symbol is valid – the native parser has already committed
* to a symbol, and the command relays that information to the scanner so it can update its state and return.
* For example, after having parsed an opening brace, the scanner adds a brace context to the stack in reaction
* to `_cond_brace_open`, which will influence its future behavior.
* These symbols do not produce nodes in the parse tree.
*
* `cond`: Conditions are hard requirements in the grammar that are decided by the scanner based on its state and the
* lookahead.
* For example, whitespace-sensitive operators (tight infix /prefix ops) like the `@` in a type application or
* the `.` in a record projection are lexed when the following characters have certain properties.
* When the scanner decides that such a symbol is valid, the parser cannot attempt to use an alternative
* interpretation like it can with conflicts.
* This is often difficult, but also especially useful to force declarations and other layout items to be
* terminated when a new line has smaller or equal indent, preventing incorrect interpretations as top level
* expression splices spanning multiple lines.
*
* `phantom`: Phantom symbols are used to signal to the scanner that certain constructs are valid without requiring
* the scanner to actually parse them and produce text nodes for them.
* In the grammar, they are always optional, and the scanner never emits the phantom symbol itself, but
* decides whether to emit _other_ symbols when the phantom symbol is _not_ valid.
* This is used to implement GHC's tactic of allowing layouts to end _whenever a parse error occurs_, but
* using specialized heuristics.
*
* Most other symbols produce nodes, except for newline and the error sentinel.
*/
externals: $ => [
// This is an unused symbol that indicates to the scanner that a parse error has occurred.
// Tree-sitter marks _all_ symbols as valid when calling the scanner after an error, so a symbol that's not used in
// the grammar is only valid if that is the case.
$.error_sentinel,
// Emitted after every newline with equal or less indent to terminate layout-based rules, with a few exceptions.
$._cond_layout_semicolon,
// Instruct the scanner to push a layout context.
// The first one is for declarations and miscellaneous other layouts.
// The others are for the specific syntax construct.
// The quote layout is for declaration quotes (`[d|data A ...|]`).
$._cmd_layout_start,
$._cmd_layout_start_do,
$._cmd_layout_start_case,
$._cmd_layout_start_if,
$._cmd_layout_start_let,
$._cmd_layout_start_quote,
// This variant is used in a `choice` with the others, and serves only to create a terminal node for explicit
// braces.
// If the scanner emitted the same symbol for virtual and explicit braces, we would either get an anonymous node
// ranging over the brace, or a terminal brace node even for virtual starts if we were to alias the symbol to '{'
// unconditionally.
// So we use separate symbols and alias only this one.
// The same reasoning applies to `_cond_layout_end_explicit`.
// The terminal could be ensured in different ways – adding an `optional('{')` after the start symbol, using
// `seq($._cmd_layout_start_explicit, '{')` instead of including the brace in the scanner range, or branching the
// entire layout on the start token to unconditionally use `_cmd_brace_close` instead of
// `_cond_layout_end_explicit`.
// However, these solutions are all very expensive, adding between 500 and 1000kB to the shared object size, and up
// to a second in generation time.
$._cmd_layout_start_explicit,
// Emitted when a new line's indent mandates ending the current layout (depending on the layout sort), or when a
// special inline layout-ending token is encountered, like an `in`.
$._cond_layout_end,
$._cond_layout_end_explicit,
// Instruct the scanner to push or pop a brace context.
$._cmd_brace_open,
$._cmd_brace_close,
// Instruct the scanner to push or pop a tuple expression context.
// In parenthesized or bracketed expressions, certain tokens (like commas, bars, and closing brackets), can end
// layouts, so the scanner must be aware of them.
$._cmd_texp_start,
$._cmd_texp_end,
// Signal to the scanner that these symbols are valid.
// See the explanation of phantom symbols above.
$._phantom_where,
$._phantom_in,
$._phantom_arrow,
$._phantom_bar,
$._phantom_deriving,
// Detect and emit text nodes for comments and CPP.
// In particular, #else branches of CPP conditionals a fully contained in the resulting node, since their nonlinear
// nature means they cannot be parsed.
$.comment,
$.haddock,
$.cpp,
$.pragma,
// Starting quote brackets are a bit messy, so it's easier to let the scanner signal that it encountered one.
// The body produces a text node until the ending bracket.
$._cond_quote_start,
$.quasiquote_body,
// Whitespace-sensitive operators for splices (`$`, `$$`), projection and module dots (`a.b`, `A.b`), arithmetic
// sequence dots `[1..10]`, as-pattern (`a@(Just b)`), type application (`@Int`), strictness and laziness
// annotations (`!pat`, `~Int`), and modifiers (`Int %1 -> Int`).
$._cond_splice,
$._cond_qual_dot,
$._cond_tight_dot,
$._cond_prefix_dot,
$._cond_dotdot,
$._cond_tight_at,
$._cond_prefix_at,
$._cond_tight_bang,
$._cond_prefix_bang,
$._cond_tight_tilde,
$._cond_prefix_tilde,
$._cond_prefix_percent,
// GHC lexes all qualified names as atomic tokens, but we can't do that because we need nodes for their
// substructures.
// However, infix expressions need single-token lookahead for the operator to resolve conflicts, which is
// impossible without an external.
// This symbol detects a qualified symbolic operator.
$._cond_qualified_op,
// This one performs an additional lookahead check for a following closing parenthesis, to disambiguate left
// sections from infix ops in `(a - b +)`.
$._cond_left_section_op,
// This is an auxiliary for `_cond_left_section_op` that allows restarting the scanner without that symbol being
// valid again when whitespace was skipped after a symop to discover that there's no parenthesis.
// Without this, we would get wrong token ranges for the operator.
$._cond_no_section_op,
// This symbol always succeeds when a minus is ahead.
// Infix expressions with minus as the operator conflict with function application.
// `a - b` can be parsed as `a (- b)`, which would normally be solved by a simple precedence entry, but is
// impossible to express because it contradicts another conflict: Negation in the left operand, `- a + b`, which
// must be parsed as `(- a) + b`.
// Simply sequencing this external before the operator solves this conflict, because a minus following an expression
// can never be negation; it can only occur at the beginning of an expression.
$._cond_minus,
/**
* The following symbols perform lookahead for various type constructs to resolve conflicts between infix types,
* contexts, and type/datacon heads, because using GLR conflicts for these is very brittle and frequently leads to
* misparsed trees.
*
* See the documentation under 'Constraints' in `src/scanner.c` for more.
*/
$._cond_context,
$._cond_infix,
$._cond_data_infix,
$._cond_assoc_tyinst,
// Symbolic operators, producing text nodes.
// These are very difficult to parse in the grammar, because unlike most languages, Haskell's operators are not a
// finite set, and therefore cannot be lexically disambiguated from special operators like `->`.
// In the presence of runtime conflicts, this can easily lead to the invalid interpretation of reserved operators as
// identifiers.
// Furthermore, the regexes for all the unicode categories produce very large ternary operator trees if specified
// in the grammar.
$._varsym,
$._consym,
// The newline is used as a dummy symbol that is emitted whenever the scanner has to update its state even though
// the current position must be parsed by the grammar.
/\n/,
],
}
================================================
FILE: grammar/general.js
================================================
const {
sep1,
layout_sort,
} = require('./util.js')
module.exports = {
// ------------------------------------------------------------------------
// guard
// ------------------------------------------------------------------------
generator: $ => seq(
field('pattern', $._pat),
field('arrow', $._larrow),
field('expression', $._exp),
),
_let_binds: $ => layout_sort($, $._cmd_layout_start_let, field('decl', $.decl)),
_let: $ => seq('let', optional(field('binds', alias($._let_binds, $.local_binds)))),
let: $ => $._let,
/**
* This is a supertype.
*/
guard: $ => choice(
// Cannot be named `pattern` because name clash.
alias($.generator, $.pattern_guard),
$.let,
alias($._exp, $.boolean),
),
guards: $ => sep1(',', field('guard', $.guard)),
_guards: $ => seq(
$._bar,
$._cmd_texp_start,
field('guards', $.guards),
),
// ------------------------------------------------------------------------
// rules shared by expression, pattern, type
// ------------------------------------------------------------------------
_universal: $ => choice(
$.splice,
$.quasiquote,
$.literal,
$._unit_cons,
$._tuple_cons,
),
}
================================================
FILE: grammar/id.js
================================================
const {
parens,
ticked,
promoted,
qualified,
} = require('./util.js')
module.exports = {
// ------------------------------------------------------------------------
// var
// ------------------------------------------------------------------------
_qualified_variable: $ => qualified($, $.variable),
_qvarid: $ => alias($._qualified_variable, $.qualified),
_varids: $ => choice($._qvarid, $.variable),
_var: $ => choice($.variable, $._pvarsym),
_qvar: $ => choice($._qvarid, $._pqvarsym),
_vars: $ => choice($._var, $._qvar),
_variable_ticked: $ => ticked($.variable),
_varop: $ => choice($.operator, alias($._variable_ticked, $.infix_id)),
_qvariable_ticked: $ => ticked($._qvarid),
_varids_ticked: $ => alias(
choice(
$._variable_ticked,
$._qvariable_ticked,
),
$.infix_id,
),
// ------------------------------------------------------------------------
// con
// ------------------------------------------------------------------------
_constructor: $ => alias($.name, $.constructor),
_qualified_constructor: $ => qualified($, $._constructor),
_qconid: $ => alias($._qualified_constructor, $.qualified),
_conids: $ => choice($._qconid, $._constructor),
_con: $ => choice($._constructor, $._pconsym),
_qcon: $ => choice($._qconid, $._pqconsym),
_cons: $ => choice(prec('con', $._con), $._qcon),
_constructor_ticked: $ => ticked($._constructor),
_conop: $ => choice($._constructor_operator_alias, alias($._constructor_ticked, $.infix_id)),
_qconstructor_ticked: $ => ticked($._qconid),
_conids_ticked: $ => alias(
choice(
$._constructor_ticked,
$._qconstructor_ticked,
),
$.infix_id,
),
// ------------------------------------------------------------------------
// tycon
// ------------------------------------------------------------------------
_tyconid: $ => $.name,
_qualified_type: $ => qualified($, $._tyconid),
_qtyconid: $ => alias($._qualified_type, $.qualified),
_tyconids: $ => choice($._qtyconid, $._tyconid),
_tycon_arrow: $ => parens($, alias($._arrow, $.operator)),
_qualified_arrow: $ => qualified($, alias($._arrow, $.operator)),
_qtycon_arrow: $ => parens($, alias($._qualified_arrow, $.qualified)),
_tycon: $ => choice($._tyconid, $._pvarsym, alias($._tycon_arrow, $.prefix_id), $._pconsym),
_qtycon: $ => choice($._qtyconid, alias($._qtycon_arrow, $.prefix_id), $._pqsym),
_tycons: $ => choice($._tycon, $._qtycon),
_promoted_tycons_alias: $ => seq('\'', $._cons),
_promoted_tycons: $ => alias($._promoted_tycons_alias, $.promoted),
_tycon_ticked: $ => ticked($._tyconid),
_qtycon_ticked: $ => ticked($._qtyconid),
_tyconids_ticked: $ => alias(
choice(
$._tycon_ticked,
$._qtycon_ticked,
),
$.infix_id,
),
_tyconops: $ => choice(
$._sym,
$._qsym,
$._operator_minus,
$._tyconids_ticked,
),
/**
* Lenient parsing: `varsym` is not legal (like `'++`).
*/
_promoted_tyconops_alias: $ => promoted($._tyconops),
_promoted_tyconops: $ => alias($._promoted_tyconops_alias, $.promoted),
_tyops: $ => choice(
$._tyconops,
$._promoted_tyconops,
),
// ------------------------------------------------------------------------
// op
// ------------------------------------------------------------------------
_op_ticked: $ => choice(
$._varids_ticked,
$._conids_ticked,
),
_ops: $ => choice(
$.operator,
$._qvarsym,
$.constructor_operator,
$._qconsym,
$._op_ticked,
),
_name: $ => choice($._var, $._con),
_qname: $ => choice($._vars, $._cons),
}
================================================
FILE: grammar/inline.js
================================================
module.exports = {
inline: $ => [
// ------------------------------------------------
// variable
// ------------------------------------------------
$._var,
$._vars,
$._varids,
$._varids_ticked,
$._varop,
// ------------------------------------------------
// constructor
// ------------------------------------------------
$._constructor,
$._con,
$._qcon,
$._cons,
$._conids,
$._conids_ticked,
$._conop,
$._op_ticked,
$._modid,
// ------------------------------------------------
// operator
// ------------------------------------------------
$._qvarsym,
$._qconsym,
$._sym,
$._qsym,
$._pqsym,
$._any_prefix_dot,
$._any_tight_dot,
$._unboxed_bar,
// ------------------------------------------------
// expression
// ------------------------------------------------
$._exp_name,
$._exp_greedy,
$._let,
// ------------------------------------------------
// pattern
// ------------------------------------------------
$._pat_apply_arg,
$._pat_name,
$._pat_texp,
// ------------------------------------------------
// type
// ------------------------------------------------
$._tyconid,
$._tyconids,
$._tycon,
$._qtycon,
$._tycons,
$._tyconops,
$._tyops,
$._type_name,
$._forall,
$._type_apply_arg,
$._parameter_type,
$._field_type,
$._type_head,
$._type_instance_head,
$._type_annotation,
$._kind_annotation,
// ------------------------------------------------
// literal
// ------------------------------------------------
$._number,
$._stringly,
$._unit_cons,
$._tuple_cons,
$._universal,
// ------------------------------------------------
// decl
// ------------------------------------------------
$._function_head_patterns,
$._function_head,
],
}
================================================
FILE: grammar/lexeme.js
================================================
const id_char = /[\pL\p{Mn}\pN_']*/
const varid_start_char = /[_\p{Ll}\p{Lo}]/
const conid_start_char = /[\p{Lu}\p{Lt}]/
module.exports = {
variable: _ => token(seq(varid_start_char, id_char, /#*/)),
implicit_variable: _ => token(seq('?', varid_start_char, id_char)),
name: _ => token(seq(conid_start_char, id_char, /#*/)),
label: _ => token(seq('#', varid_start_char, id_char)),
_carrow: _ => choice('=>', '⇒'),
_arrow: _ => choice('->', '→'),
_linear_arrow: _ => choice('->.', '⊸'),
_larrow: _ => choice('<-', '←'),
_colon2: _ => choice('::', '∷'),
_promote: _ => '\'',
_qual_dot: $ => seq($._cond_qual_dot, '.'),
_tight_dot: $ => seq($._cond_tight_dot, '.'),
_any_tight_dot: $ => choice($._qual_dot, $._tight_dot),
_prefix_dot: $ => seq($._cond_prefix_dot, '.'),
_any_prefix_dot: $ => choice($._qual_dot, $._prefix_dot),
_tight_at: $ => seq($._cond_tight_at, '@'),
_prefix_at: $ => seq($._cond_prefix_at, '@'),
_prefix_bang: $ => seq($._cond_prefix_bang, '!'),
_tight_bang: $ => seq($._cond_tight_bang, '!'),
_any_prefix_bang: $ => choice($._prefix_bang, $._tight_bang),
_prefix_tilde: $ => seq($._cond_prefix_tilde, '~'),
_tight_tilde: $ => seq($._cond_tight_tilde, '~'),
_any_prefix_tilde: $ => choice($._prefix_tilde, $._tight_tilde),
_prefix_percent: $ => seq($._cond_prefix_percent, '%'),
_dotdot: $ => seq($._cond_dotdot, '..'),
_paren_open: $ => seq(alias(/\(/, '('), $._cmd_texp_start),
_paren_close: $ => seq(alias(/\)/, ')'), $._cmd_texp_end),
_bracket_open: $ => seq('[', $._cmd_texp_start),
_bracket_close: $ => seq(']', $._cmd_texp_end),
// Sadly, this does not have the effect of creating a single terminal for the bracket :'(
_unboxed_open: $ => alias(seq($._paren_open, token.immediate('#')), '(#'),
_unboxed_close: $ => seq('#)', $._cmd_texp_end),
_unboxed_bar: _ => choice('|', token.immediate('|')),
_where: $ => seq(optional($._phantom_where), 'where'),
_bar: $ => seq(optional($._phantom_bar), '|'),
}
================================================
FILE: grammar/literal.js
================================================
const {
parens,
brackets,
unboxed,
} = require('./util.js')
const decimal = /[0-9][0-9_]*/
const exponent = /[eE][+-]?[0-9_]+/
const hex_exponent = /[pP][+-]?[0-9a-fA-F_]+/
const magic_hash = rule => token(seq(rule, optional(token.immediate(/##?/))))
module.exports = {
// ------------------------------------------------------------------------
// literals
// ------------------------------------------------------------------------
// the `choice` here is necessary to avoid integers being parsed as floats
float: _ => magic_hash(
seq(
decimal,
choice(
seq(/\.[0-9_]+/, optional(exponent)),
exponent,
),
),
),
char: _ => magic_hash(
choice(
/'[^']'/,
/'\\[^ ]*'/,
),
),
string: _ => magic_hash(
seq(
'"',
repeat(choice(
/[^\\"\n]/,
/\\(\^)?./,
/\\\n\s*\\/,
)),
'"',
),
),
_integer_literal: _ => magic_hash(decimal),
_binary_literal: _ => magic_hash(/0[bB][01_]+/),
_octal_literal: _ => magic_hash(/0[oO][0-7]+/),
_hex_literal: _ => magic_hash(
seq(
/0[xX][0-9a-fA-F_]+/,
optional(/\.[0-9a-fA-F_]+/),
optional(hex_exponent),
)
),
integer: $ => choice(
$._binary_literal,
$._integer_literal,
$._octal_literal,
$._hex_literal,
),
_stringly: $ => choice(
$.string,
$.char,
),
_number: $ => choice(
$.integer,
$.float,
),
_plist: $ => brackets($),
unit: $ => parens($),
unboxed_unit: $ => unboxed($),
prefix_tuple: $ => parens($, repeat1(',')),
prefix_unboxed_tuple: $ => unboxed($, repeat1(',')),
prefix_unboxed_sum: $ => unboxed($, repeat1($._unboxed_bar)),
literal: $ => choice(
$._stringly,
$._number,
),
_unit_cons: $ => choice(
$.unit,
$.unboxed_unit,
),
_tuple_cons: $ => choice(
$.prefix_tuple,
$.prefix_unboxed_tuple,
$.prefix_unboxed_sum,
),
}
================================================
FILE: grammar/module.js
================================================
const {
sep1,
sep,
parens,
semi,
semi_opt,
semis,
} = require('./util.js')
module.exports = {
// ------------------------------------------------------------------------
// module names
// ------------------------------------------------------------------------
_modid: $ => alias($.name, $.module_id),
_modid_prefix: $ => prec('qualifying-module', seq($._modid, $._any_tight_dot)),
_qualifying_module: $ => repeat1($._modid_prefix),
module: $ => seq(repeat($._modid_prefix), $._modid),
// ------------------------------------------------------------------------
// import/export
// ------------------------------------------------------------------------
namespace: _ => choice('pattern', 'type'),
_child_type: $ => seq(field('namespace', 'type'), field('type', $._tyconids)),
_child: $ => choice(
alias($._child_type, $.associated_type),
$._qname,
),
children: $ => parens($, sep(',', field('element', choice(alias('..', $.all_names), $._child)))),
_ie_entity: $ => seq(
optional(field('namespace', $.namespace)),
choice(
field('variable', $._varids),
field('type', $._tyconids),
field('operator', choice($._sym_prefix, $._pqsym)),
),
optional(field('children', $.children)),
),
// ------------------------------------------------------------------------
// import
// ------------------------------------------------------------------------
import_list: $ => parens(
$,
sep(',', field('name', alias($._ie_entity, $.import_name))),
optional(','),
),
import: $ => seq(
'import',
optional('qualified'),
optional(field('package', alias($.string, $.import_package))),
field('module', $.module),
optional('qualified'),
optional(seq('as', field('alias', $.module))),
optional(seq(
optional('hiding'),
field('names', $.import_list),
)),
),
// ------------------------------------------------------------------------
// export
// ------------------------------------------------------------------------
module_export: $ => seq('module', field('module', $.module)),
exports: $ => parens(
$,
optional(sep1(',', choice(field('export', alias($._ie_entity, $.export)), $.module_export))),
optional(','),
),
// ------------------------------------------------------------------------
// module body / sections
// ------------------------------------------------------------------------
header: $ => seq(
'module',
field('module', $.module),
field('exports', optional($.exports)),
$._where,
),
imports: $ => seq(semis($, field('import', $.import)), semi($)),
/**
* Using `semi` at the end instead of `semi_opt` increases parser size by a full megabyte!!
*
* This allows imports after the first declaration to prevent the tree from jittering while typing an import:
*
* > import A
* > imp
* > import B
*
* The partially typed `imp` will be parsed as a `top_splice`, which forces `imports` to reduce after `import A`.
* The rest of the file will then be part of `declarations` and all following imports will be broken until the keyword
* has been completed.
*/
declarations: $ => seq($.declaration, repeat(seq(semi($), choice($.declaration, $.import))), semi_opt($)),
_body: $ => seq(
choice($._cmd_layout_start, alias($._cmd_layout_start_explicit, '{')),
semi_opt($),
field('imports', optional($.imports)),
field('declarations', optional($.declarations)),
$._layout_end,
),
_layout_end: $ => choice(
$._cond_layout_end,
alias($._cond_layout_end_explicit, '}'),
),
/**
* This is a supertype.
*/
declaration: $ => choice(
$.decl,
$.type_synomym,
$.kind_signature,
$.type_family,
$.type_instance,
$.role_annotation,
$.data_type,
$.newtype,
$.data_family,
$.data_instance,
$.class,
$.instance,
$.default_types,
$.deriving_instance,
$.pattern_synonym,
$.foreign_import,
$.foreign_export,
$.fixity,
$.top_splice,
),
}
================================================
FILE: grammar/operator.js
================================================
const {
parens,
qualified,
} = require('./util.js')
module.exports = {
// ------------------------------------------------------------------------
// var
// ------------------------------------------------------------------------
_operator_qual_dot_head: $ => seq($._cond_qual_dot, $._varsym),
_operator_hash_head: _ => seq(
choice('#', token.immediate('#')),
optional(choice(token.immediate('#'), token.immediate('|'))),
),
operator: $ => choice(
seq(optional($._cond_prefix_dot), $._varsym),
$._operator_hash_head,
'*',
),
_operator_alias: $ => $.operator,
_operator_minus: $ => alias('-', $.operator),
_varsym_prefix: $ => parens(
$,
choice(
$.operator,
$._operator_minus,
alias($._operator_qual_dot_head, $.operator),
),
),
_pvarsym: $ => alias($._varsym_prefix, $.prefix_id),
_qualified_varsym: $ => qualified($, choice($.operator, $._operator_minus)),
_qvarsym: $ => alias($._qualified_varsym, $.qualified),
_qvarsym_prefix: $ => parens($, $._qvarsym),
_pqvarsym: $ => alias($._qvarsym_prefix, $.prefix_id),
// ------------------------------------------------------------------------
// con
// ------------------------------------------------------------------------
constructor_operator: $ => $._consym,
_constructor_operator_alias: $ => $.constructor_operator,
_consym_prefix: $ => parens($, $.constructor_operator),
_pconsym: $ => alias($._consym_prefix, $.prefix_id),
_qualified_consym: $ => qualified($, $.constructor_operator),
_qconsym: $ => alias($._qualified_consym, $.qualified),
_qconsym_prefix: $ => parens($, $._qconsym),
_pqconsym: $ => alias($._qconsym_prefix, $.prefix_id),
// ------------------------------------------------------------------------
// op
// ------------------------------------------------------------------------
_sym: $ => choice($._operator_alias, $._constructor_operator_alias),
_sym_prefix: $ => choice($._pvarsym, $._pconsym),
_qsym: $ => choice($._qvarsym, $._qconsym),
_pqsym: $ => choice($._pqvarsym, $._pqconsym),
}
================================================
FILE: grammar/pat.js
================================================
const {
sep1,
sep2,
sep,
parens,
braces,
brackets,
unboxed_tuple_full,
unboxed_sum_single,
} = require('./util.js')
module.exports = {
// ------------------------------------------------------------------------
// tuples and parens
// ------------------------------------------------------------------------
_pat_parens: $ => parens($, field('pattern', $._pat_texp)),
_pat_tuple_elems: $ => sep2(',', field('element', $._pat_texp)),
_pat_tuple: $ => parens($, $._pat_tuple_elems),
_pat_unboxed_tuple: $ => unboxed_tuple_full($, $._pat_texp),
_pat_unboxed_sum: $ => unboxed_sum_single($, $._pat_texp),
_pat_list: $ => brackets($, sep1(',', field('element', $._pat_texp)), optional(',')),
// ------------------------------------------------------------------------
// record
// ------------------------------------------------------------------------
field_pattern: $ => choice(
alias('..', $.wildcard),
seq(field('field', $._field_names), optional(seq('=', field('pattern', $._pat_texp)))),
),
_pat_record: $ => prec('record', seq(
field('constructor', $.pattern),
braces($, sep(',', field('field', $.field_pattern))),
)),
// ------------------------------------------------------------------------
// misc
// ------------------------------------------------------------------------
/**
* This dynamic precedence penalty is relevant for the conflict between `function` and `bind`.
* Consider:
*
* > f (A a) = exp
*
* Because of the "single choice disambiguated with named precedences" approach used for `pattern`, the left node in
* `pat_apply` can be a variable, even though it's not valid Haskell.
* While the static prec 'pat-name' covers this at generation time, Haskell's ambiguity requires us to use a runtime
* conflict for `function`/`bind`, where static prec is ineffective.
* Giving the reduction of `_var` to `pattern` a strong negative dynamic prec ensures that the runtime branch for
* `bind` has lower precedence because of `f`, so `function` always wins.
*
* While `bind` usually has a lower score than `function` anyway in this situation because it is slightly more
* complex, there are never any guarantees for runtime conflicts.
* In particular, the presence of minor parse errors later in the declaration can tip the scales randomly.
*/
_pat_name: $ => choice(
prec('pat-name', prec.dynamic(-1000, $._var)),
$._cons,
),
_pat_as: $ => prec('prefix', seq(field('bind', $.variable), $._tight_at, field('pattern', $.pattern))),
_pat_wildcard: _ => '_',
_pat_strict: $ => prec('prefix', seq($._any_prefix_bang, field('pattern', $.pattern))),
_pat_irrefutable: $ => prec('prefix', seq($._any_prefix_tilde, field('pattern', $.pattern))),
// ------------------------------------------------------------------------
// application
// ------------------------------------------------------------------------
_pat_apply_arg: $ => choice(
$.pattern,
alias($._at_type, $.type_binder),
$.explicit_type,
),
_pat_apply: $ => prec.left('apply', seq(
field('function', $.pattern),
field('argument', $._pat_apply_arg),
)),
// ------------------------------------------------------------------------
// operators
// ------------------------------------------------------------------------
_pat_negation: $ => seq('-', field('number', $._number)),
_pat_infix: $ => prec.right('infix', seq(
field('left_operand', $.pattern),
optional($._cond_no_section_op),
field('operator', choice(
$.constructor_operator,
$._conids_ticked,
seq($._cond_qualified_op, $._qconsym),
)),
field('right_operand', $.pattern),
)),
// ------------------------------------------------------------------------
// top level
// ------------------------------------------------------------------------
pattern: $ => choice(
alias($._pat_infix, $.infix),
alias($._pat_negation, $.negation),
alias($._pat_apply, $.apply),
$._pat_name,
alias($._pat_as, $.as),
alias($._pat_record, $.record),
alias($._pat_wildcard, $.wildcard),
alias($._pat_parens, $.parens),
alias($._pat_tuple, $.tuple),
alias($._pat_unboxed_tuple, $.unboxed_tuple),
alias($._pat_unboxed_sum, $.unboxed_sum),
alias($._pat_list, $.list),
alias($._plist, $.list),
alias($._pat_strict, $.strict),
alias($._pat_irrefutable, $.irrefutable),
$._universal,
),
patterns: $ => repeat1(prec('patterns', $._pat_apply_arg)),
_pat_signature: $ => prec.right('annotated', seq(
field('pattern', $.pattern),
$._type_annotation,
)),
_pat: $ => choice(
alias($._pat_signature, $.signature),
prec.right($.pattern),
),
view_pattern: $ => seq(field('expression', $._exp), $._arrow, field('pattern', $._pat_texp)),
_pat_texp: $ => choice($.view_pattern, $._pat),
}
================================================
FILE: grammar/patsyn.js
================================================
const {
layout,
optional_where,
} = require('./util.js')
module.exports = {
// ------------------------------------------------------------------------
// pattern synonym
// ------------------------------------------------------------------------
_patsyn_signature: $ => seq(
field('synonym', choice($._con, alias($._con_binding_list, $.binding_list))),
$._colon2,
field('type', $.quantified_type),
),
_patsyn_cons: $ => layout($, alias($.bind, $.constructor_synonym)),
/**
* This allows a `where` after any equation for parsing resilience, even though it's only valid for the arrow variant
* (explicitly bidirectional patterns).
* The `where` may also be empty.
*/
_patsyn_equation: $ => seq(
field('synonym', $.pattern),
choice(
'=',
$._larrow,
),
field('pattern', $._pat),
optional_where($, field('constructors', alias($._patsyn_cons, $.constructor_synonyms))),
),
pattern_synonym: $ => seq(
'pattern',
choice(
alias($._patsyn_signature, $.signature),
alias($._patsyn_equation, $.equation),
),
),
}
================================================
FILE: grammar/precedences.js
================================================
module.exports = {
precedences: $ => [
// ------------------------------------------------
// associativity of expressions, patterns and types
// ------------------------------------------------
[
'projection',
'record',
'prefix',
'apply',
'negation',
'infix',
'implicit',
'fun',
'annotated',
$.quantified_type,
],
// ------------------------------------------------
// negation
// ------------------------------------------------
[
$._pat_negation,
$.literal,
],
// ------------------------------------------------
// function vs bind
// ------------------------------------------------
[
'bind',
'pat-name',
],
// ------------------------------------------------
// qualified names
// ------------------------------------------------
/**
* Prioritize shifting over a tight infix dot over reducing to a qualified constructor or module.
*/
[
'qualifying-module',
'qualified-id',
],
/**
* Prioritize qualified variables over record field projection on constructors.
*/
[
'qualifying-module',
'con',
],
/**
* Prioritize qualified names over the infix operator dot in types.
*/
[
'qualifying-module',
'type-name',
],
// ------------------------------------------------
// types and constraints
// ------------------------------------------------
[
$.operator,
$._type_star,
],
[
$._type_wildcard,
$._type_param_wildcard,
],
[
$._constructor_ticked,
$._tycon_ticked,
],
[
'qtype-single',
'qtype-curried',
],
// ------------------------------------------------
// misc
// ------------------------------------------------
/**
* > f A a a = a
* > data A = A Int Int
*
* This should not be parsed as constructor application, but separate patterns.
*/
[
'patterns',
'apply',
],
],
}
================================================
FILE: grammar/th.js
================================================
const {
layout_sort,
} = require('./util.js')
const quote_bracket = ($, quoter) => seq(
$._cond_quote_start,
'[',
field('quoter', quoter),
'|',
)
module.exports = {
// ------------------------------------------------------------------------
// splice
// ------------------------------------------------------------------------
/**
* Even though the doc states "arbitrary expression", it's very rare for any others than names and parenthesized
* expressions to occur, and it's very expensive to allow them.
* Even only allowing list and quotes adds a full megabyte to the parser size.
*/
_splice_exp: $ => choice(
$._exp_name,
alias($._exp_parens, $.parens),
$.literal,
),
_splice_dollars: $ => seq(
$._cond_splice,
choice('$', '$$'),
),
splice: $ => seq($._splice_dollars, field('expression', $._splice_exp)),
/**
* Since `expression` includes `splice`, this allows for a top level dollar splice as well.
*/
top_splice: $ => $.expression,
quoter: $ => $._varids,
/**
* `_cond_quote_start` (in `quote_bracket`) is a zero-width token emitted by the scanner.
* While the quoter and the bar may not be preceded by whitespace, this is not necessary to ensure here with
* `token.immediate` since the scanner already verifies it.
*/
quasiquote: $ => seq(
quote_bracket($, $.quoter),
optional(field('body', $.quasiquote_body)),
choice(token('|]'), '⟧'),
),
quoted_decls: $ => layout_sort($, $._cmd_layout_start_quote, field('declaration', $.declaration)),
/**
* An "expression quotation" is valid in an expression, and its body may contain an expression, type, pattern or
* declaration layout.
*
* Which of these are valid is decided by the quoter: `e`, `t`, `p` or `d`.
* If the quoter is empty, or the special oxford bracket character is used, the body is parsed as an expression.
*/
_exp_quote: $ => seq(
choice(
seq(choice('⟦', quote_bracket($, optional('e'))), optional(alias($._exp, $.quoted_expression))),
seq(quote_bracket($, 't'), optional(alias($._ktype, $.quoted_type))),
seq(quote_bracket($, 'p'), optional(alias($._pat, $.quoted_pattern))),
seq(quote_bracket($, 'd'), optional($.quoted_decls)),
),
choice(token('|]'), '⟧'),
),
_exp_typed_quote: $ => seq(
$._cond_quote_start,
'[',
optional('e'),
'||',
optional(alias($._exp, $.quoted_expression)),
token('||]'),
),
}
================================================
FILE: grammar/type.js
================================================
const {
parens,
braces,
brackets,
prefix_at,
sep1,
sep2,
unboxed_tuple_full,
unboxed_sum_full,
forall,
layout,
layout_single,
optional_where,
} = require('./util.js')
module.exports = {
// ------------------------------------------------------------------------
// type parameters
// ------------------------------------------------------------------------
_inferred_tyvar: $ => braces($, $._ktype_param),
_type_param_parens: $ => parens($, $._ktype_param),
_type_param_wildcard: _ => '_',
_type_param_annotated: $ => prec('annotated', seq($.type_param, $._kind_annotation)),
_type_param_invisible: $ => prefix_at($, field('bind', $.type_param)),
/**
* This is a supertype.
*/
type_param: $ => choice(
alias($._type_param_wildcard, $.wildcard),
alias($._type_param_invisible, $.invisible),
alias($._type_param_parens, $.parens),
field('bind', $.variable),
),
_ktype_param: $ => choice(
$.type_param,
alias($._type_param_annotated, $.annotated),
),
type_params: $ => repeat1(prec('patterns', $.type_param)),
quantified_variables: $ => repeat1(choice($.type_param, alias($._inferred_tyvar, $.inferred))),
// ------------------------------------------------------------------------
// tuples and parens
// ------------------------------------------------------------------------
_type_parens: $ => parens($, field('type', $._ktype)),
_type_tuple_elems: $ => sep2(',', field('element', $._ktype)),
/**
* Tuple types must either be saturated or empty, sections aren't legal.
* We could be lenient here, but it seems useful to have a different node name for the prefix variant.
*/
_type_tuple: $ => parens($, $._type_tuple_elems),
_type_unboxed_tuple: $ => unboxed_tuple_full($, $._ktype),
_type_unboxed_sum: $ => unboxed_sum_full($, $._ktype),
_type_list: $ => brackets($, sep1(',', field('element', $._ktype))),
// ------------------------------------------------------------------------
// names etc
// ------------------------------------------------------------------------
_type_promoted: $ => seq(
'\'',
choice(
alias($._plist, $.empty_list),
alias($._type_tuple, $.tuple),
alias($._type_list, $.list),
$.prefix_tuple,
$.unit,
),
),
_type_name: $ => choice(
$.variable,
$._promoted_tycons,
prec('type-name', $._tycons),
),
_type_star: _ => choice('*', '★'),
_type_wildcard: _ => '_',
// ------------------------------------------------------------------------
// application
// ------------------------------------------------------------------------
_at_type: $ => prefix_at($, field('type', $.type)),
_type_apply_arg: $ => choice($.type, alias($._at_type, $.kind_application)),
/**
* Type application, as in `Either e (Int, Text)` or `TypeRep @Int`.
*/
_type_apply: $ => prec.left('apply', seq(
field('constructor', $.type),
field('argument', $._type_apply_arg),
)),
// ------------------------------------------------------------------------
// infix
// ------------------------------------------------------------------------
_type_infix: $ => prec.right('infix', seq(
field('left_operand', $.type),
field('operator', $._tyops),
field('right_operand', $.type),
)),
// ------------------------------------------------------------------------
// unquantified type
// ------------------------------------------------------------------------
/**
* This is a supertype.
*/
type: $ => choice(
$._type_name,
alias($._type_star, $.star),
alias($._type_wildcard, $.wildcard),
alias($._type_parens, $.parens),
alias($._type_promoted, $.promoted),
alias($._type_list, $.list),
alias($._plist, $.prefix_list),
alias($._type_unboxed_tuple, $.unboxed_tuple),
alias($._type_unboxed_sum, $.unboxed_sum),
alias($._type_tuple, $.tuple),
alias($._type_infix, $.infix),
alias($._type_apply, $.apply),
$._universal,
),
// ------------------------------------------------------------------------
// forall
// ------------------------------------------------------------------------
_forall_keyword: _ => choice('forall', '∀'),
_forall_body: $ => seq(
field('quantifier', $._forall_keyword),
optional(field('variables', $.quantified_variables)),
),
forall: $ => prec('qtype-single', seq(
$._forall_body,
'.',
)),
forall_required: $ => prec('qtype-single', seq(
$._forall_body,
$._arrow,
)),
_forall: $ => choice(
$.forall,
$.forall_required,
),
_qtype_forall: $ => prec.right('qtype-curried', seq(
$._forall_body,
'.',
field('type', $.quantified_type),
)),
_qtype_forall_required: $ => prec.right('qtype-curried', seq(
$._forall_body,
$._arrow,
field('type', $.quantified_type),
)),
// ------------------------------------------------------------------------
// function
// ------------------------------------------------------------------------
_fun_arrow: $ => seq(
optional($._phantom_arrow),
field('arrow', $._arrow),
),
modifier: $ => prec('prefix', seq($._prefix_percent, $.type)),
_linear_fun_arrow: $ => choice(
seq(
field('multiplicity', $.modifier),
$._fun_arrow,
),
seq(
optional($._phantom_arrow),
field('arrow', $._linear_arrow),
),
),
/**
* These also allow tight infix because unpack pragmas can precede them without space.
* Technically pragmas aren't considered for tight infix, but it's simpler to do it this way than to track that in the
* scanner.
*/
strict_field: $ => prec('prefix', seq($._any_prefix_bang, field('type', $.type))),
lazy_field: $ => prec('prefix', seq($._any_prefix_tilde, field('type', $.type))),
_parameter_type: $ => field('parameter', choice($.strict_field, $.lazy_field, $.quantified_type)),
/**
* We allow strict and lazy field types in function types so that GADTs don't need a separate rule tree.
*/
_qtype_function: $ => prec.right(seq(
$._parameter_type,
$._fun_arrow,
field('result', $.quantified_type),
)),
_qtype_linear_function: $ => prec.right(seq(
$._parameter_type,
$._linear_fun_arrow,
field('result', $.quantified_type),
)),
// ------------------------------------------------------------------------
// context
// ------------------------------------------------------------------------
_qtype_context: $ => prec.right('qtype-curried', seq(
$._context_inline,
field('type', $.quantified_type),
)),
// ------------------------------------------------------------------------
// top level
// ------------------------------------------------------------------------
/**
* This is a supertype.
*/
quantified_type: $ => choice(
alias($._qtype_function, $.function),
alias($._qtype_linear_function, $.linear_function),
alias($._qtype_forall, $.forall),
alias($._qtype_forall_required, $.forall_required),
alias($._qtype_context, $.context),
$.implicit_parameter,
prec.right($.type),
),
_type_annotation: $ => seq(
$._colon2,
field('type', $.quantified_type),
),
_kind_annotation: $ => seq(
$._colon2,
field('kind', $.quantified_type),
),
_type_signature: $ => prec.right('annotated', seq(
field('type', $.quantified_type),
$._kind_annotation,
)),
_ktype: $ => choice(
alias($._type_signature, $.signature),
$.quantified_type,
),
// ------------------------------------------------------------------------
// type head
// ------------------------------------------------------------------------
_type_head_name: $ => field('name', choice(
$._tycon,
$.unit,
alias($._plist, $.prefix_list),
)),
_type_head_parens: $ => parens(
$,
choice(
$._type_head,
$._type_head_params,
),
),
_type_head_params: $ => choice(
$._type_head_name,
alias($._type_head_parens, $.parens),
),
_type_head_infix: $ => prec('infix', seq(
field('left_operand', $.type_param),
field('operator', $._tyconops),
field('right_operand', $.type_param),
)),
/**
* A type head introduces the name and parameters in the declaration of a data type/family, type synonym/family, or
* class.
*
* It can be in prefix or infix form:
*
* > A a b
* > a +++ b
*
* Parameters can be visible or invisible, the latter marked by a prefix `@`.
* They can be plain or parenthesized variable names, the latter with an optional kind signature.
* They can be wildcards.
*
* Examples: `a`, `@a`, `(a :: Type)`, `@(_ :: Type -> Type)`
*
* The rules are slightly relaxed compared to GHC.
*/
_type_head: $ => choice(
seq($._type_head_params, optional(field('patterns', $.type_params))),
alias($._type_head_infix, $.infix),
),
// ------------------------------------------------------------------------
// type instance head
// ------------------------------------------------------------------------
_type_instance_head_parens: $ => parens(
$,
choice(
$._type_instance_head,
$._type_instance_head_params,
),
optional($._kind_annotation),
),
_type_instance_head_params: $ => choice(
field('name', $._tycons),
alias($._type_instance_head_parens, $.parens),
),
type_patterns: $ => repeat1(prec('patterns', $._type_apply_arg)),
/**
* The equivalent of a type head, for type instances, which can contain full type patterns rather than just variable
* binders.
*/
_type_instance_head: $ => choice(
seq($._type_instance_head_params, optional(field('patterns', $.type_patterns))),
seq($._cond_infix, alias($._type_infix, $.infix)),
),
// ------------------------------------------------------------------------
// type decl
// ------------------------------------------------------------------------
type_synomym: $ => seq(
'type',
$._type_head,
'=',
field('type', $._ktype),
),
kind_signature: $ => seq(
'type',
$._type_head,
$._kind_annotation,
),
// ------------------------------------------------------------------------
// type instance
// ------------------------------------------------------------------------
_type_instance_common: $ => seq(
$._type_instance_head,
'=',
$.quantified_type,
),
_type_instance: $ => seq(
forall($),
$._type_instance_common,
),
type_instance: $ => seq(
'type',
'instance',
$._type_instance,
),
// ------------------------------------------------------------------------
// type family
// ------------------------------------------------------------------------
type_family_result: $ => seq('=', field('result', $.quantified_type)),
type_family_injectivity: $ => seq(
$._bar,
field('result', $.variable),
$._arrow,
field('determined', repeat1($.variable)),
),
_tyfam_inj: $ => seq(
$.type_family_result,
optional($.type_family_injectivity),
),
_tyfam: $ => seq(
$._type_head,
optional(choice($._kind_annotation, $._tyfam_inj)),
),
_tyfam_equations: $ => layout($, field('equation', alias($._type_instance, $.equation))),
/**
* This syntax is valid in `.hs-boot` files.
*/
abstract_family: $ => layout_single($, '..'),
type_family: $ => seq(
'type',
'family',
$._tyfam,
optional_where($, field('closed_family', choice(
alias($._tyfam_equations, $.equations),
$.abstract_family,
))),
),
// ------------------------------------------------------------------------
// role
// ------------------------------------------------------------------------
type_role: _ => choice(
'representational',
'nominal',
'phantom',
'_',
),
role_annotation: $ => seq(
'type',
'role',
field('type', $._tycons),
repeat1(field('role', $.type_role)),
)
}
================================================
FILE: grammar/util.js
================================================
// ------------------------------------------------------------------------
// structure
// ------------------------------------------------------------------------
const sep1 = (s, rule) => seq(rule, repeat(seq(s, rule)))
const sep2 = (s, rule) => seq(rule, repeat1(seq(s, rule)))
const sep = (s, rule) => optional(sep1(s, rule))
// ------------------------------------------------------------------------
// syntax
// ------------------------------------------------------------------------
const parens = ($, ...rule) => seq($._paren_open, ...rule, $._paren_close)
const braces = ($, ...rule) => seq('{', $._cmd_brace_open, ...rule, '}', $._cmd_brace_close)
const brackets = ($, ...rule) => seq($._bracket_open, ...rule, $._bracket_close)
const ticked = (...rule) => seq('`', ...rule, '`')
const promoted = (...rule) => seq('\'', ...rule)
const prefix_at = ($, ...rule) => prec('prefix', seq($._prefix_at, ...rule))
const semi = $ => choice(repeat1(';'), $._cond_layout_semicolon)
const semi_opt = $ => optional(semi($))
const semis = ($, rule) => sep1(semi($), rule)
// ------------------------------------------------------------------------
// layout
// ------------------------------------------------------------------------
/**
* More general variant of `layout_sort`.
*/
const layout_sort_single = ($, start, rule) => seq(
choice(start, alias($._cmd_layout_start_explicit, '{')),
rule,
$._layout_end,
)
/**
* Wrap a repeated rule in a layout.
* This is used for `where`, `let`, `of`, `if` and `do`, and the toplevel module.
* The `start` rule must be one of the externals starting with `_cmd_layout_<type>`, which instruct the scanner to push
* a layout context with the current column as its indentation.
* When a `_cond_layout_end` or `_cond_layout_semicolon` is encountered by the scanner, the recorded indent is compared
* to the current one to make a decision.
*/
const layout_sort = ($, start, rule) => seq(
choice(start, alias($._cmd_layout_start_explicit, '{')),
optional(seq(
semi_opt($),
semis($, rule),
semi_opt($),
)),
$._layout_end,
)
/**
* Same as `layout`, but using `layout_sort_single`.
* This is necessary for braces without repeating layout elements.
* Usually it is enough to just use `braces` for this (e.g. records), but if the rule is in a choice with a full
* layout, we need to allow the layout start token since the scanner emits that unconditionally based on preceding
* tokens.
*/
const layout_single = ($, rule) => layout_sort_single($, $._cmd_layout_start, rule)
/**
* Alias for `layout_sort` using the common layout type for the start token, which corresponds to declarations and GADT
* constructors.
*/
const layout = ($, rule) => layout_sort($, $._cmd_layout_start, rule)
// ------------------------------------------------------------------------
// unboxed
// ------------------------------------------------------------------------
const unboxed = ($, ...rules) => seq($._unboxed_open, ...rules, $._unboxed_close)
/**
* At least one element is filled, for expressions.
*/
const unboxed_tuple_nonempty = ($, rule) => unboxed(
$,
repeat(','),
field('element', rule),
repeat(seq(',', optional(field('element', rule))))
)
/**
* All elements are filled in, for types and patterns.
*/
const unboxed_tuple_full = ($, rule) => unboxed($, sep1(',', field('element', rule)))
/**
* Exactly one element is filled in, used by expressions, patterns and the special data constructors.
*/
const unboxed_sum_single = ($, rule) => unboxed(
$,
choice(
seq(repeat1($._unboxed_bar), field('element', rule)),
seq(field('element', rule), $._unboxed_bar)
),
repeat($._unboxed_bar),
)
/**
* All elements are filled in, for types.
*/
const unboxed_sum_full = ($, rule) => unboxed($, sep2($._unboxed_bar, field('element', rule)))
// ------------------------------------------------------------------------
// where
// ------------------------------------------------------------------------
const optional_where = ($, rule) => optional(seq($._where, optional(rule)))
// ------------------------------------------------------------------------
// misc
// ------------------------------------------------------------------------
const qualified = ($, id) => prec('qualified-id', seq(
field('module', alias($._qualifying_module, $.module)),
field('id', id),
))
const context = $ => optional(field('context', $.context))
const forall = $ => optional(field('forall', $._forall))
module.exports = {
sep1,
sep2,
sep,
parens,
braces,
brackets,
ticked,
promoted,
prefix_at,
semi,
semi_opt,
semis,
layout_sort_single,
layout_sort,
layout_single,
layout,
unboxed,
unboxed_tuple_nonempty,
unboxed_tuple_full,
unboxed_sum_single,
unboxed_sum_full,
optional_where,
qualified,
context,
forall,
}
================================================
FILE: grammar.js
================================================
const
class_ = require('./grammar/class.js'),
conflicts = require('./grammar/conflicts.js'),
context = require('./grammar/context.js'),
data = require('./grammar/data.js'),
decl = require('./grammar/decl.js'),
exp = require('./grammar/exp.js'),
externals = require('./grammar/externals.js'),
general = require('./grammar/general.js'),
id = require('./grammar/id.js'),
inline = require('./grammar/inline.js'),
lexeme = require('./grammar/lexeme.js'),
literal = require('./grammar/literal.js'),
module_ = require('./grammar/module.js'),
operator = require('./grammar/operator.js'),
pat = require('./grammar/pat.js'),
patsyn = require('./grammar/patsyn.js'),
precedences = require('./grammar/precedences.js'),
th = require('./grammar/th.js'),
type = require('./grammar/type.js')
module.exports = grammar({
name: 'haskell',
rules: {
haskell: $ => seq(
optional($.header),
optional($._body),
),
...general,
...type,
...context,
...exp,
...pat,
...module_,
...data,
...class_,
...decl,
...patsyn,
...th,
...literal,
...id,
...operator,
...lexeme,
},
...externals,
...precedences,
...inline,
...conflicts,
/**
* These rules may occur anywhere in the grammar and don't have to be specified in productions.
*/
extras: $ => [
/\p{Zs}/,
/\n/,
/\r/,
$.cpp,
$.comment,
$.haddock,
$.pragma,
],
/**
* Rules with leading underscore are generally omitted from the AST, and can therefore not be used in queries.
* The rules listed in this attribute are omitted from the AST, but their names can be used in queries in place of
* their children; as well as in combination with them, using the syntax `expression/variable`.
* This is most useful for choice rules that represent syntactic categories, like expressions, patterns, and types in
* Haskell.
*
* See the readme for a detailed explanation.
*/
supertypes: $ => [
$.expression,
$.pattern,
$.type,
$.quantified_type,
$.constraint,
$.constraints,
$.type_param,
$.declaration,
$.decl,
$.class_decl,
$.instance_decl,
$.statement,
$.qualifier,
$.guard,
],
/**
* This rule is used to detect that a reserved keyword is a prefix of an identifier.
*
* For example, if the identifier `ifM` occurs in a position where the keyword `if` is valid (so most expressions),
* the fact that `ifM` matches `variable` prevents tree-sitter from lexing `if` followed by `M` as a `name`.
*/
word: $ => $.variable,
})
================================================
FILE: package.json
================================================
{
"name": "tree-sitter-haskell",
"version": "0.23.1",
"description": "Haskell grammar for tree-sitter",
"repository": "https://github.com/tree-sitter/tree-sitter-haskell",
"license": "MIT",
"author": {
"name": "Rick Winfrey"
},
"contributors": [
{
"name": "Max Brunsfeld",
"email": "maxbrunsfeld@gmail.com"
},
{
"name": "Owen Shepherd"
},
{
"name": "Torsten Schmits"
}
],
"main": "bindings/node",
"types": "bindings/node",
"keywords": [
"incremental",
"parsing",
"tree-sitter",
"haskell"
],
"files": [
"grammar.js",
"grammar/*.js",
"tree-sitter.json",
"binding.gyp",
"prebuilds/**",
"bindings/node/*",
"queries/*",
"src/**",
"*.wasm"
],
"dependencies": {
"node-addon-api": "^8.2.2",
"node-gyp-build": "^4.8.2"
},
"devDependencies": {
"prebuildify": "^6.0.1",
"tree-sitter-cli": "^0.24.4"
},
"peerDependencies": {
"tree-sitter": "^0.21.1"
},
"peerDependenciesMeta": {
"tree-sitter": {
"optional": true
}
},
"scripts": {
"install": "node-gyp-build",
"prestart": "tree-sitter build --wasm",
"start": "tree-sitter playground",
"test": "node --test bindings/node/*_test.js"
}
}
================================================
FILE: pyproject.toml
================================================
[build-system]
requires = ["setuptools>=42", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "tree-sitter-haskell"
description = "Haskell grammar for tree-sitter"
version = "0.23.1"
keywords = ["incremental", "parsing", "tree-sitter", "haskell"]
classifiers = [
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Topic :: Software Development :: Compilers",
"Topic :: Text Processing :: Linguistic",
"Typing :: Typed",
]
requires-python = ">=3.9"
license.text = "MIT"
readme = "README.md"
[[project.authors]]
name = "Rick Winfrey"
[[project.maintainers]]
name = "Torsten Schmits"
[project.urls]
Homepage = "https://github.com/tree-sitter/tree-sitter-haskell"
[project.optional-dependencies]
core = ["tree-sitter~=0.22"]
[tool.cibuildwheel]
build = "cp39-*"
build-frontend = "build"
================================================
FILE: queries/highlights.scm
================================================
; ----------------------------------------------------------------------------
; Parameters and variables
; NOTE: These are at the top, so that they have low priority,
; and don't override destructured parameters
(variable) @variable
(pattern/wildcard) @variable
(decl/function
patterns: (patterns
(_) @variable.parameter))
(expression/lambda
(_)+ @variable.parameter
"->")
(decl/function
(infix
(pattern) @variable.parameter))
; ----------------------------------------------------------------------------
; Literals and comments
(integer) @number
(negation) @number
(expression/literal
(float)) @number.float
(char) @character
(string) @string
(unit) @string.special.symbol ; unit, as in ()
(comment) @comment
((haddock) @comment.documentation)
; ----------------------------------------------------------------------------
; Punctuation
[
"("
")"
"{"
"}"
"["
"]"
] @punctuation.bracket
[
","
";"
] @punctuation.delimiter
; ----------------------------------------------------------------------------
; Keywords, operators, includes
[
"forall"
; "∀" ; utf-8 is not cross-platform safe
] @keyword.repeat
(pragma) @keyword.directive
[
"if"
"then"
"else"
"case"
"of"
] @keyword.conditional
[
"import"
"qualified"
"module"
] @keyword.import
[
(operator)
(constructor_operator)
(all_names)
(wildcard)
"."
".."
"="
"|"
"::"
"=>"
"->"
"<-"
"\\"
"`"
"@"
] @operator
; TODO broken, also huh?
; ((qualified_module
; (module) @constructor)
; .
; (module))
(module
(module_id) @module)
[
"where"
"let"
"in"
"class"
"instance"
"pattern"
"data"
"newtype"
"family"
"type"
"as"
"hiding"
"deriving"
"via"
"stock"
"anyclass"
"do"
"mdo"
"rec"
"infix"
"infixl"
"infixr"
] @keyword
; ----------------------------------------------------------------------------
; Functions and variables
(decl
[
name: (variable) @function
names: (binding_list (variable) @function)
])
(decl/bind
name: (variable) @variable)
; Consider signatures (and accompanying functions)
; with only one value on the rhs as variables
(decl/signature
name: (variable) @variable
type: (type))
((decl/signature
name: (variable) @_name
type: (type))
.
(decl
name: (variable) @variable)
match: (_)
(#eq? @_name @variable))
; but consider a type that involves 'IO' a decl/function
(decl/signature
name: (variable) @function
type: (type/apply
constructor: (name) @_type)
(#eq? @_type "IO"))
((decl/signature
name: (variable) @_name
type: (type/apply
constructor: (name) @_type)
(#eq? @_type "IO"))
.
(decl
name: (variable) @function)
match: (_)
(#eq? @_name @function))
((decl/signature) @function
.
(decl/function
name: (variable) @function))
(decl/bind
name: (variable) @function
(match
expression: (expression/lambda)))
; view patterns
(view_pattern
[
(expression/variable) @function.call
(expression/qualified
(variable) @function.call)
])
; consider infix functions as operators
(infix_id
[
(variable) @operator
(qualified
(variable) @operator)
])
; decl/function calls with an infix operator
; e.g. func <$> a <*> b
(infix
[
(variable) @function.call
(qualified
((module) @module
(variable) @function.call))
]
.
(operator))
; infix operators applied to variables
((expression/variable) @variable
.
(operator))
((operator)
.
[
(expression/variable) @variable
(expression/qualified
(variable) @variable)
])
; decl/function calls with infix operators
([
(expression/variable) @function.call
(expression/qualified
(variable) @function.call)
]
.
(operator) @_op
(#any-of? @_op "$" "<$>" ">>=" "=<<"))
; right hand side of infix operator
((infix
[
(operator)
(infix_id (variable))
] ; infix or `func`
.
[
(variable) @function.call
(qualified
(variable) @function.call)
])
.
(operator) @_op
(#any-of? @_op "$" "<$>" "=<<"))
; decl/function composition, arrows, monadic composition (lhs)
(
[
(expression/variable) @function
(expression/qualified
(variable) @function)
]
.
(operator) @_op
(#any-of? @_op "." ">>>" "***" ">=>" "<=<"))
; right hand side of infix operator
((infix
[
(operator)
(infix_id (variable))
] ; infix or `func`
.
[
(variable) @function
(qualified
(variable) @function)
])
.
(operator) @_op
(#any-of? @_op "." ">>>" "***" ">=>" "<=<"))
; function composition, arrows, monadic composition (rhs)
((operator) @_op
.
[
(expression/variable) @function
(expression/qualified
(variable) @function)
]
(#any-of? @_op "." ">>>" "***" ">=>" "<=<"))
; function defined in terms of a function composition
(decl/function
name: (variable) @function
(match
expression: (infix
operator: (operator) @_op
(#any-of? @_op "." ">>>" "***" ">=>" "<=<"))))
(apply
[
(expression/variable) @function.call
(expression/qualified
(variable) @function.call)
])
; function compositions, in parentheses, applied
; lhs
(apply
.
(expression/parens
(infix
[
(variable) @function.call
(qualified
(variable) @function.call)
]
.
(operator))))
; rhs
(apply
.
(expression/parens
(infix
(operator)
.
[
(variable) @function.call
(qualified
(variable) @function.call)
])))
; variables being passed to a function call
(apply
(_)
.
[
(expression/variable) @variable
(expression/qualified
(variable) @variable)
])
; main is always a function
; (this prevents `main = undefined` from being highlighted as a variable)
(decl/bind
name: (variable) @function
(#eq? @function "main"))
; scoped function types (func :: a -> b)
(signature
pattern: (pattern/variable) @function
type: (quantified_type))
; signatures that have a function type
; + binds that follow them
(decl/signature
name: (variable) @function
type: (quantified_type))
((decl/signature
name: (variable) @_name
type: (quantified_type))
.
(decl/bind
(variable) @function)
(#eq? @function @_name))
; ----------------------------------------------------------------------------
; Types
(name) @type
(type/star) @type
(variable) @type
(constructor) @constructor
; True or False
((constructor) @boolean
(#any-of? @boolean "True" "False"))
; otherwise (= True)
((variable) @boolean
(#eq? @boolean "otherwise"))
; ----------------------------------------------------------------------------
; Quasi-quotes
(quoter) @function.call
(quasiquote
[
(quoter) @_name
(_
(variable) @_name)
]
(#eq? @_name "qq")
(quasiquote_body) @string)
(quasiquote
(_
(variable) @_name)
(#eq? @_name "qq")
(quasiquote_body) @string)
; namespaced quasi-quoter
(quasiquote
(_
(module) @module
.
(variable) @function.call))
; Highlighting of quasiquote_body for other languages is handled by injections.scm
; ----------------------------------------------------------------------------
; Exceptions/error handling
((variable) @keyword.exception
(#any-of? @keyword.exception
"error" "undefined" "try" "tryJust" "tryAny" "catch" "catches" "catchJust" "handle" "handleJust"
"throw" "throwIO" "throwTo" "throwError" "ioError" "mask" "mask_" "uninterruptibleMask"
"uninterruptibleMask_" "bracket" "bracket_" "bracketOnErrorSource" "finally" "fail"
"onException" "expectationFailure"))
; ----------------------------------------------------------------------------
; Debugging
((variable) @keyword.debug
(#any-of? @keyword.debug
"trace" "traceId" "traceShow" "traceShowId" "traceWith" "traceShowWith" "traceStack" "traceIO"
"traceM" "traceShowM" "traceEvent" "traceEventWith" "traceEventIO" "flushEventLog" "traceMarker"
"traceMarkerIO"))
; ----------------------------------------------------------------------------
; Fields
(field_name
(variable) @variable.member)
(import_name
(name)
.
(children
(variable) @variable.member))
; ----------------------------------------------------------------------------
; Spell checking
(comment) @spell
================================================
FILE: queries/injections.scm
================================================
; -----------------------------------------------------------------------------
; General language injection
(quasiquote
(quoter) @injection.language
(quasiquote_body) @injection.content)
((comment) @injection.content
(#set! injection.language "comment"))
; -----------------------------------------------------------------------------
; shakespeare library
; NOTE: doesn't support templating
; TODO: add once CoffeeScript parser is added
; ; CoffeeScript: Text.Coffee
; (quasiquote
; (quoter) @_name
; (#eq? @_name "coffee")
; ((quasiquote_body) @injection.content
; (#set! injection.language "coffeescript")))
; CSS: Text.Cassius, Text.Lucius
(quasiquote
(quoter) @_name
(#any-of? @_name "cassius" "lucius")
(quasiquote_body) @injection.content
(#set! injection.language "css"))
; HTML: Text.Hamlet
(quasiquote
(quoter) @_name
(#any-of? @_name "shamlet" "xshamlet" "hamlet" "xhamlet" "ihamlet")
(quasiquote_body) @injection.content
(#set! injection.language "html"))
; JS: Text.Julius
(quasiquote
(quoter) @_name
(#any-of? @_name "js" "julius")
(quasiquote_body) @injection.content
(#set! injection.language "javascript"))
; TS: Text.TypeScript
(quasiquote
(quoter) @_name
(#any-of? @_name "tsc" "tscJSX")
(quasiquote_body) @injection.content
(#set! injection.language "typescript"))
; -----------------------------------------------------------------------------
; HSX
(quasiquote
(quoter) @_name
(#eq? @_name "hsx")
(quasiquote_body) @injection.content
(#set! injection.language "html"))
; -----------------------------------------------------------------------------
; Inline JSON from aeson
(quasiquote
(quoter) @_name
(#eq? @_name "aesonQQ")
(quasiquote_body) @injection.content
(#set! injection.language "json"))
; -----------------------------------------------------------------------------
; SQL
; postgresql-simple
(quasiquote
(quoter) @injection.language
(#eq? @injection.language "sql")
(quasiquote_body) @injection.content)
(quasiquote
(quoter) @_name
(#any-of? @_name "persistUpperCase" "persistLowerCase" "persistWith")
(quasiquote_body) @injection.content
(#set! injection.language "haskell_persistent"))
================================================
FILE: queries/locals.scm
================================================
(signature name: (variable)) @local.definition
(function name: (variable)) @local.definition
(pattern/variable) @local.definition
(expression/variable) @local.reference
================================================
FILE: setup.py
================================================
from os.path import isdir, join
from platform import system
from setuptools import Extension, find_packages, setup
from setuptools.command.build import build
from wheel.bdist_wheel import bdist_wheel
class Build(build):
def run(self):
if isdir("queries"):
dest = join(self.build_lib, "tree_sitter_haskell", "queries")
self.copy_tree("queries", dest)
super().run()
class BdistWheel(bdist_wheel):
def get_tag(self):
python, abi, platform = super().get_tag()
if python.startswith("cp"):
python, abi = "cp39", "abi3"
return python, abi, platform
setup(
packages=find_packages("bindings/python"),
package_dir={"": "bindings/python"},
package_data={
"tree_sitter_haskell": ["*.pyi", "py.typed"],
"tree_sitter_haskell.queries": ["*.scm"],
},
ext_package="tree_sitter_haskell",
ext_modules=[
Extension(
name="_binding",
sources=[
"bindings/python/tree_sitter_haskell/binding.c",
"src/parser.c",
"src/scanner.c",
],
extra_compile_args=[
"-std=c11",
"-fvisibility=hidden",
] if system() != "Windows" else [
"/std:c11",
"/utf-8",
],
define_macros=[
("Py_LIMITED_API", "0x03090000"),
("PY_SSIZE_T_CLEAN", None),
("TREE_SITTER_HIDE_SYMBOLS", None),
],
include_dirs=["src"],
py_limited_api=True,
)
],
cmdclass={
"build": Build,
"bdist_wheel": BdistWheel
},
zip_safe=False
)
================================================
FILE: src/grammar.json
================================================
{
"$schema": "https://tree-sitter.github.io/tree-sitter/assets/schemas/grammar.schema.json",
"name": "haskell",
"word": "variable",
"rules": {
"haskell": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "header"
},
{
"type": "BLANK"
}
]
},
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_body"
},
{
"type": "BLANK"
}
]
}
]
},
"generator": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "pattern",
"content": {
"type": "SYMBOL",
"name": "_pat"
}
},
{
"type": "FIELD",
"name": "arrow",
"content": {
"type": "SYMBOL",
"name": "_larrow"
}
},
{
"type": "FIELD",
"name": "expression",
"content": {
"type": "SYMBOL",
"name": "_exp"
}
}
]
},
"_let_binds": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_cmd_layout_start_let"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_cmd_layout_start_explicit"
},
"named": false,
"value": "{"
}
]
},
{
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "REPEAT1",
"content": {
"type": "STRING",
"value": ";"
}
},
{
"type": "SYMBOL",
"name": "_cond_layout_semicolon"
}
]
},
{
"type": "BLANK"
}
]
},
{
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "decl",
"content": {
"type": "SYMBOL",
"name": "decl"
}
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "REPEAT1",
"content": {
"type": "STRING",
"value": ";"
}
},
{
"type": "SYMBOL",
"name": "_cond_layout_semicolon"
}
]
},
{
"type": "FIELD",
"name": "decl",
"content": {
"type": "SYMBOL",
"name": "decl"
}
}
]
}
}
]
},
{
"type": "CHOICE",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "REPEAT1",
"content": {
"type": "STRING",
"value": ";"
}
},
{
"type": "SYMBOL",
"name": "_cond_layout_semicolon"
}
]
},
{
"type": "BLANK"
}
]
}
]
},
{
"type": "BLANK"
}
]
},
{
"type": "SYMBOL",
"name": "_layout_end"
}
]
},
"_let": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "let"
},
{
"type": "CHOICE",
"members": [
{
"type": "FIELD",
"name": "binds",
"content": {
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_let_binds"
},
"named": true,
"value": "local_binds"
}
},
{
"type": "BLANK"
}
]
}
]
},
"let": {
"type": "SYMBOL",
"name": "_let"
},
"guard": {
"type": "CHOICE",
"members": [
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "generator"
},
"named": true,
"value": "pattern_guard"
},
{
"type": "SYMBOL",
"name": "let"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_exp"
},
"named": true,
"value": "boolean"
}
]
},
"guards": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "guard",
"content": {
"type": "SYMBOL",
"name": "guard"
}
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "FIELD",
"name": "guard",
"content": {
"type": "SYMBOL",
"name": "guard"
}
}
]
}
}
]
},
"_guards": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_bar"
},
{
"type": "SYMBOL",
"name": "_cmd_texp_start"
},
{
"type": "FIELD",
"name": "guards",
"content": {
"type": "SYMBOL",
"name": "guards"
}
}
]
},
"_universal": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "splice"
},
{
"type": "SYMBOL",
"name": "quasiquote"
},
{
"type": "SYMBOL",
"name": "literal"
},
{
"type": "SYMBOL",
"name": "_unit_cons"
},
{
"type": "SYMBOL",
"name": "_tuple_cons"
}
]
},
"_inferred_tyvar": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "{"
},
{
"type": "SYMBOL",
"name": "_cmd_brace_open"
},
{
"type": "SYMBOL",
"name": "_ktype_param"
},
{
"type": "STRING",
"value": "}"
},
{
"type": "SYMBOL",
"name": "_cmd_brace_close"
}
]
},
"_type_param_parens": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_paren_open"
},
{
"type": "SYMBOL",
"name": "_ktype_param"
},
{
"type": "SYMBOL",
"name": "_paren_close"
}
]
},
"_type_param_wildcard": {
"type": "STRING",
"value": "_"
},
"_type_param_annotated": {
"type": "PREC",
"value": "annotated",
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "type_param"
},
{
"type": "SYMBOL",
"name": "_kind_annotation"
}
]
}
},
"_type_param_invisible": {
"type": "PREC",
"value": "prefix",
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_prefix_at"
},
{
"type": "FIELD",
"name": "bind",
"content": {
"type": "SYMBOL",
"name": "type_param"
}
}
]
}
},
"type_param": {
"type": "CHOICE",
"members": [
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_param_wildcard"
},
"named": true,
"value": "wildcard"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_param_invisible"
},
"named": true,
"value": "invisible"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_param_parens"
},
"named": true,
"value": "parens"
},
{
"type": "FIELD",
"name": "bind",
"content": {
"type": "SYMBOL",
"name": "variable"
}
}
]
},
"_ktype_param": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "type_param"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_param_annotated"
},
"named": true,
"value": "annotated"
}
]
},
"type_params": {
"type": "REPEAT1",
"content": {
"type": "PREC",
"value": "patterns",
"content": {
"type": "SYMBOL",
"name": "type_param"
}
}
},
"quantified_variables": {
"type": "REPEAT1",
"content": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "type_param"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_inferred_tyvar"
},
"named": true,
"value": "inferred"
}
]
}
},
"_type_parens": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_paren_open"
},
{
"type": "FIELD",
"name": "type",
"content": {
"type": "SYMBOL",
"name": "_ktype"
}
},
{
"type": "SYMBOL",
"name": "_paren_close"
}
]
},
"_type_tuple_elems": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "element",
"content": {
"type": "SYMBOL",
"name": "_ktype"
}
},
{
"type": "REPEAT1",
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "FIELD",
"name": "element",
"content": {
"type": "SYMBOL",
"name": "_ktype"
}
}
]
}
}
]
},
"_type_tuple": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_paren_open"
},
{
"type": "SYMBOL",
"name": "_type_tuple_elems"
},
{
"type": "SYMBOL",
"name": "_paren_close"
}
]
},
"_type_unboxed_tuple": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_unboxed_open"
},
{
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "element",
"content": {
"type": "SYMBOL",
"name": "_ktype"
}
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "FIELD",
"name": "element",
"content": {
"type": "SYMBOL",
"name": "_ktype"
}
}
]
}
}
]
},
{
"type": "SYMBOL",
"name": "_unboxed_close"
}
]
},
"_type_unboxed_sum": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_unboxed_open"
},
{
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "element",
"content": {
"type": "SYMBOL",
"name": "_ktype"
}
},
{
"type": "REPEAT1",
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_unboxed_bar"
},
{
"type": "FIELD",
"name": "element",
"content": {
"type": "SYMBOL",
"name": "_ktype"
}
}
]
}
}
]
},
{
"type": "SYMBOL",
"name": "_unboxed_close"
}
]
},
"_type_list": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_bracket_open"
},
{
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "element",
"content": {
"type": "SYMBOL",
"name": "_ktype"
}
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "FIELD",
"name": "element",
"content": {
"type": "SYMBOL",
"name": "_ktype"
}
}
]
}
}
]
},
{
"type": "SYMBOL",
"name": "_bracket_close"
}
]
},
"_type_promoted": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "'"
},
{
"type": "CHOICE",
"members": [
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_plist"
},
"named": true,
"value": "empty_list"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_tuple"
},
"named": true,
"value": "tuple"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_list"
},
"named": true,
"value": "list"
},
{
"type": "SYMBOL",
"name": "prefix_tuple"
},
{
"type": "SYMBOL",
"name": "unit"
}
]
}
]
},
"_type_name": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "variable"
},
{
"type": "SYMBOL",
"name": "_promoted_tycons"
},
{
"type": "PREC",
"value": "type-name",
"content": {
"type": "SYMBOL",
"name": "_tycons"
}
}
]
},
"_type_star": {
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "*"
},
{
"type": "STRING",
"value": "★"
}
]
},
"_type_wildcard": {
"type": "STRING",
"value": "_"
},
"_at_type": {
"type": "PREC",
"value": "prefix",
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_prefix_at"
},
{
"type": "FIELD",
"name": "type",
"content": {
"type": "SYMBOL",
"name": "type"
}
}
]
}
},
"_type_apply_arg": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "type"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_at_type"
},
"named": true,
"value": "kind_application"
}
]
},
"_type_apply": {
"type": "PREC_LEFT",
"value": "apply",
"content": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "constructor",
"content": {
"type": "SYMBOL",
"name": "type"
}
},
{
"type": "FIELD",
"name": "argument",
"content": {
"type": "SYMBOL",
"name": "_type_apply_arg"
}
}
]
}
},
"_type_infix": {
"type": "PREC_RIGHT",
"value": "infix",
"content": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "left_operand",
"content": {
"type": "SYMBOL",
"name": "type"
}
},
{
"type": "FIELD",
"name": "operator",
"content": {
"type": "SYMBOL",
"name": "_tyops"
}
},
{
"type": "FIELD",
"name": "right_operand",
"content": {
"type": "SYMBOL",
"name": "type"
}
}
]
}
},
"type": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_type_name"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_star"
},
"named": true,
"value": "star"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_wildcard"
},
"named": true,
"value": "wildcard"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_parens"
},
"named": true,
"value": "parens"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_promoted"
},
"named": true,
"value": "promoted"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_list"
},
"named": true,
"value": "list"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_plist"
},
"named": true,
"value": "prefix_list"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_unboxed_tuple"
},
"named": true,
"value": "unboxed_tuple"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_unboxed_sum"
},
"named": true,
"value": "unboxed_sum"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_tuple"
},
"named": true,
"value": "tuple"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_infix"
},
"named": true,
"value": "infix"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_apply"
},
"named": true,
"value": "apply"
},
{
"type": "SYMBOL",
"name": "_universal"
}
]
},
"_forall_keyword": {
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "forall"
},
{
"type": "STRING",
"value": "∀"
}
]
},
"_forall_body": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "quantifier",
"content": {
"type": "SYMBOL",
"name": "_forall_keyword"
}
},
{
"type": "CHOICE",
"members": [
{
"type": "FIELD",
"name": "variables",
"content": {
"type": "SYMBOL",
"name": "quantified_variables"
}
},
{
"type": "BLANK"
}
]
}
]
},
"forall": {
"type": "PREC",
"value": "qtype-single",
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_forall_body"
},
{
"type": "STRING",
"value": "."
}
]
}
},
"forall_required": {
"type": "PREC",
"value": "qtype-single",
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_forall_body"
},
{
"type": "SYMBOL",
"name": "_arrow"
}
]
}
},
"_forall": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "forall"
},
{
"type": "SYMBOL",
"name": "forall_required"
}
]
},
"_qtype_forall": {
"type": "PREC_RIGHT",
"value": "qtype-curried",
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_forall_body"
},
{
"type": "STRING",
"value": "."
},
{
"type": "FIELD",
"name": "type",
"content": {
"type": "SYMBOL",
"name": "quantified_type"
}
}
]
}
},
"_qtype_forall_required": {
"type": "PREC_RIGHT",
"value": "qtype-curried",
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_forall_body"
},
{
"type": "SYMBOL",
"name": "_arrow"
},
{
"type": "FIELD",
"name": "type",
"content": {
"type": "SYMBOL",
"name": "quantified_type"
}
}
]
}
},
"_fun_arrow": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_phantom_arrow"
},
{
"type": "BLANK"
}
]
},
{
"type": "FIELD",
"name": "arrow",
"content": {
"type": "SYMBOL",
"name": "_arrow"
}
}
]
},
"modifier": {
"type": "PREC",
"value": "prefix",
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_prefix_percent"
},
{
"type": "SYMBOL",
"name": "type"
}
]
}
},
"_linear_fun_arrow": {
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "multiplicity",
"content": {
"type": "SYMBOL",
"name": "modifier"
}
},
{
"type": "SYMBOL",
"name": "_fun_arrow"
}
]
},
{
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_phantom_arrow"
},
{
"type": "BLANK"
}
]
},
{
"type": "FIELD",
"name": "arrow",
"content": {
"type": "SYMBOL",
"name": "_linear_arrow"
}
}
]
}
]
},
"strict_field": {
"type": "PREC",
"value": "prefix",
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_any_prefix_bang"
},
{
"type": "FIELD",
"name": "type",
"content": {
"type": "SYMBOL",
"name": "type"
}
}
]
}
},
"lazy_field": {
"type": "PREC",
"value": "prefix",
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_any_prefix_tilde"
},
{
"type": "FIELD",
"name": "type",
"content": {
"type": "SYMBOL",
"name": "type"
}
}
]
}
},
"_parameter_type": {
"type": "FIELD",
"name": "parameter",
"content": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "strict_field"
},
{
"type": "SYMBOL",
"name": "lazy_field"
},
{
"type": "SYMBOL",
"name": "quantified_type"
}
]
}
},
"_qtype_function": {
"type": "PREC_RIGHT",
"value": 0,
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_parameter_type"
},
{
"type": "SYMBOL",
"name": "_fun_arrow"
},
{
"type": "FIELD",
"name": "result",
"content": {
"type": "SYMBOL",
"name": "quantified_type"
}
}
]
}
},
"_qtype_linear_function": {
"type": "PREC_RIGHT",
"value": 0,
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_parameter_type"
},
{
"type": "SYMBOL",
"name": "_linear_fun_arrow"
},
{
"type": "FIELD",
"name": "result",
"content": {
"type": "SYMBOL",
"name": "quantified_type"
}
}
]
}
},
"_qtype_context": {
"type": "PREC_RIGHT",
"value": "qtype-curried",
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_context_inline"
},
{
"type": "FIELD",
"name": "type",
"content": {
"type": "SYMBOL",
"name": "quantified_type"
}
}
]
}
},
"quantified_type": {
"type": "CHOICE",
"members": [
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_qtype_function"
},
"named": true,
"value": "function"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_qtype_linear_function"
},
"named": true,
"value": "linear_function"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_qtype_forall"
},
"named": true,
"value": "forall"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_qtype_forall_required"
},
"named": true,
"value": "forall_required"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_qtype_context"
},
"named": true,
"value": "context"
},
{
"type": "SYMBOL",
"name": "implicit_parameter"
},
{
"type": "PREC_RIGHT",
"value": 0,
"content": {
"type": "SYMBOL",
"name": "type"
}
}
]
},
"_type_annotation": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_colon2"
},
{
"type": "FIELD",
"name": "type",
"content": {
"type": "SYMBOL",
"name": "quantified_type"
}
}
]
},
"_kind_annotation": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_colon2"
},
{
"type": "FIELD",
"name": "kind",
"content": {
"type": "SYMBOL",
"name": "quantified_type"
}
}
]
},
"_type_signature": {
"type": "PREC_RIGHT",
"value": "annotated",
"content": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "type",
"content": {
"type": "SYMBOL",
"name": "quantified_type"
}
},
{
"type": "SYMBOL",
"name": "_kind_annotation"
}
]
}
},
"_ktype": {
"type": "CHOICE",
"members": [
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_signature"
},
"named": true,
"value": "signature"
},
{
"type": "SYMBOL",
"name": "quantified_type"
}
]
},
"_type_head_name": {
"type": "FIELD",
"name": "name",
"content": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_tycon"
},
{
"type": "SYMBOL",
"name": "unit"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_plist"
},
"named": true,
"value": "prefix_list"
}
]
}
},
"_type_head_parens": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_paren_open"
},
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_type_head"
},
{
"type": "SYMBOL",
"name": "_type_head_params"
}
]
},
{
"type": "SYMBOL",
"name": "_paren_close"
}
]
},
"_type_head_params": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_type_head_name"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_head_parens"
},
"named": true,
"value": "parens"
}
]
},
"_type_head_infix": {
"type": "PREC",
"value": "infix",
"content": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "left_operand",
"content": {
"type": "SYMBOL",
"name": "type_param"
}
},
{
"type": "FIELD",
"name": "operator",
"content": {
"type": "SYMBOL",
"name": "_tyconops"
}
},
{
"type": "FIELD",
"name": "right_operand",
"content": {
"type": "SYMBOL",
"name": "type_param"
}
}
]
}
},
"_type_head": {
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_type_head_params"
},
{
"type": "CHOICE",
"members": [
{
"type": "FIELD",
"name": "patterns",
"content": {
"type": "SYMBOL",
"name": "type_params"
}
},
{
"type": "BLANK"
}
]
}
]
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_head_infix"
},
"named": true,
"value": "infix"
}
]
},
"_type_instance_head_parens": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_paren_open"
},
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_type_instance_head"
},
{
"type": "SYMBOL",
"name": "_type_instance_head_params"
}
]
},
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_kind_annotation"
},
{
"type": "BLANK"
}
]
},
{
"type": "SYMBOL",
"name": "_paren_close"
}
]
},
"_type_instance_head_params": {
"type": "CHOICE",
"members": [
{
"type": "FIELD",
"name": "name",
"content": {
"type": "SYMBOL",
"name": "_tycons"
}
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_instance_head_parens"
},
"named": true,
"value": "parens"
}
]
},
"type_patterns": {
"type": "REPEAT1",
"content": {
"type": "PREC",
"value": "patterns",
"content": {
"type": "SYMBOL",
"name": "_type_apply_arg"
}
}
},
"_type_instance_head": {
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_type_instance_head_params"
},
{
"type": "CHOICE",
"members": [
{
"type": "FIELD",
"name": "patterns",
"content": {
"type": "SYMBOL",
"name": "type_patterns"
}
},
{
"type": "BLANK"
}
]
}
]
},
{
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_cond_infix"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_infix"
},
"named": true,
"value": "infix"
}
]
}
]
},
"type_synomym": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "type"
},
{
"type": "SYMBOL",
"name": "_type_head"
},
{
"type": "STRING",
"value": "="
},
{
"type": "FIELD",
"name": "type",
"content": {
"type": "SYMBOL",
"name": "_ktype"
}
}
]
},
"kind_signature": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "type"
},
{
"type": "SYMBOL",
"name": "_type_head"
},
{
"type": "SYMBOL",
"name": "_kind_annotation"
}
]
},
"_type_instance_common": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_type_instance_head"
},
{
"type": "STRING",
"value": "="
},
{
"type": "SYMBOL",
"name": "quantified_type"
}
]
},
"_type_instance": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "FIELD",
"name": "forall",
"content": {
"type": "SYMBOL",
"name": "_forall"
}
},
{
"type": "BLANK"
}
]
},
{
"type": "SYMBOL",
"name": "_type_instance_common"
}
]
},
"type_instance": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "type"
},
{
"type": "STRING",
"value": "instance"
},
{
"type": "SYMBOL",
"name": "_type_instance"
}
]
},
"type_family_result": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "="
},
{
"type": "FIELD",
"name": "result",
"content": {
"type": "SYMBOL",
"name": "quantified_type"
}
}
]
},
"type_family_injectivity": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_bar"
},
{
"type": "FIELD",
"name": "result",
"content": {
"type": "SYMBOL",
"name": "variable"
}
},
{
"type": "SYMBOL",
"name": "_arrow"
},
{
"type": "FIELD",
"name": "determined",
"content": {
"type": "REPEAT1",
"content": {
"type": "SYMBOL",
"name": "variable"
}
}
}
]
},
"_tyfam_inj": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "type_family_result"
},
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "type_family_injectivity"
},
{
"type": "BLANK"
}
]
}
]
},
"_tyfam": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_type_head"
},
{
"type": "CHOICE",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_kind_annotation"
},
{
"type": "SYMBOL",
"name": "_tyfam_inj"
}
]
},
{
"type": "BLANK"
}
]
}
]
},
"_tyfam_equations": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_cmd_layout_start"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_cmd_layout_start_explicit"
},
"named": false,
"value": "{"
}
]
},
{
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "REPEAT1",
"content": {
"type": "STRING",
"value": ";"
}
},
{
"type": "SYMBOL",
"name": "_cond_layout_semicolon"
}
]
},
{
"type": "BLANK"
}
]
},
{
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "equation",
"content": {
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_instance"
},
"named": true,
"value": "equation"
}
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "REPEAT1",
"content": {
"type": "STRING",
"value": ";"
}
},
{
"type": "SYMBOL",
"name": "_cond_layout_semicolon"
}
]
},
{
"type": "FIELD",
"name": "equation",
"content": {
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_type_instance"
},
"named": true,
"value": "equation"
}
}
]
}
}
]
},
{
"type": "CHOICE",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "REPEAT1",
"content": {
"type": "STRING",
"value": ";"
}
},
{
"type": "SYMBOL",
"name": "_cond_layout_semicolon"
}
]
},
{
"type": "BLANK"
}
]
}
]
},
{
"type": "BLANK"
}
]
},
{
"type": "SYMBOL",
"name": "_layout_end"
}
]
},
"abstract_family": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_cmd_layout_start"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_cmd_layout_start_explicit"
},
"named": false,
"value": "{"
}
]
},
{
"type": "STRING",
"value": ".."
},
{
"type": "SYMBOL",
"name": "_layout_end"
}
]
},
"type_family": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "type"
},
{
"type": "STRING",
"value": "family"
},
{
"type": "SYMBOL",
"name": "_tyfam"
},
{
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_where"
},
{
"type": "CHOICE",
"members": [
{
"type": "FIELD",
"name": "closed_family",
"content": {
"type": "CHOICE",
"members": [
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_tyfam_equations"
},
"named": true,
"value": "equations"
},
{
"type": "SYMBOL",
"name": "abstract_family"
gitextract_gnpzepxr/ ├── .editorconfig ├── .gitattributes ├── .github/ │ └── workflows/ │ ├── ci.yml │ ├── fuzz.yml │ └── publish.yml ├── .gitignore ├── CMakeLists.txt ├── 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/ │ ├── 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 ├── grammar.js ├── 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
SYMBOL INDEX (286 symbols across 17 files)
FILE: bindings/c/tree-sitter-haskell.h
type TSLanguage (line 4) | typedef struct TSLanguage TSLanguage;
FILE: bindings/go/binding.go
function Language (line 11) | func Language() unsafe.Pointer {
FILE: bindings/go/binding_test.go
function TestCanLoadGrammar (line 10) | func TestCanLoadGrammar(t *testing.T) {
FILE: bindings/node/binding.cc
type TSLanguage (line 3) | struct TSLanguage
function Init (line 12) | Napi::Object Init(Napi::Env env, Napi::Object exports) {
FILE: bindings/node/index.d.ts
type BaseNode (line 1) | type BaseNode = {
type ChildNode (line 6) | type ChildNode = {
type NodeInfo (line 12) | type NodeInfo =
type Language (line 21) | type Language = {
FILE: bindings/python/tests/test_binding.py
class TestLanguage (line 6) | class TestLanguage(TestCase):
method test_can_load_grammar (line 7) | def test_can_load_grammar(self):
FILE: bindings/python/tree_sitter_haskell/__init__.py
function _get_query (line 8) | def _get_query(name, file):
function __getattr__ (line 14) | def __getattr__(name):
function __dir__ (line 33) | def __dir__():
FILE: bindings/python/tree_sitter_haskell/__init__.pyi
function language (line 7) | def language() -> object: ...
FILE: bindings/python/tree_sitter_haskell/binding.c
type TSLanguage (line 3) | typedef struct TSLanguage TSLanguage;
function PyObject (line 7) | static PyObject* _binding_language(PyObject *Py_UNUSED(self), PyObject *...
type PyModuleDef (line 17) | struct PyModuleDef
function PyMODINIT_FUNC (line 25) | PyMODINIT_FUNC PyInit__binding(void) {
FILE: bindings/rust/build.rs
function main (line 1) | fn main() {
FILE: bindings/rust/lib.rs
function tree_sitter_haskell (line 29) | fn tree_sitter_haskell() -> *const ();
constant LANGUAGE (line 33) | pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitt...
constant NODE_TYPES (line 38) | pub const NODE_TYPES: &str = include_str!("../../src/node-types.json");
constant HIGHLIGHTS_QUERY (line 41) | pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlight...
constant INJECTIONS_QUERY (line 44) | pub const INJECTIONS_QUERY: &str = include_str!("../../queries/injection...
constant LOCALS_QUERY (line 47) | pub const LOCALS_QUERY: &str = include_str!("../../queries/locals.scm");
function test_can_load_grammar (line 52) | fn test_can_load_grammar() {
FILE: bindings/swift/TreeSitterHaskell/haskell.h
type TSLanguage (line 4) | typedef struct TSLanguage TSLanguage;
FILE: setup.py
class Build (line 9) | class Build(build):
method run (line 10) | def run(self):
class BdistWheel (line 17) | class BdistWheel(bdist_wheel):
method get_tag (line 18) | def get_tag(self):
FILE: src/scanner.c
type Symbol (line 115) | typedef enum {
type ParseLine (line 229) | typedef Array(int32_t) ParseLine;
type ParseLines (line 234) | typedef Array(ParseLine) ParseLines;
type Debug (line 240) | typedef struct {
function Debug (line 249) | Debug debug_new(TSLexer *l) {
type ContextSort (line 265) | typedef enum {
type Context (line 300) | typedef struct {
type Lexed (line 308) | typedef enum {
type NewlineState (line 399) | typedef enum {
type Newline (line 410) | typedef struct {
type Contexts (line 430) | typedef Array(Context) Contexts;
type Lookahead (line 568) | typedef struct {
type State (line 584) | typedef struct {
type Env (line 596) | typedef struct {
function Env (line 606) | static Env env_new(TSLexer *l, const bool * symbols, State *state) {
function reset_newline (line 618) | static void reset_newline(Env *env) { memset(&env->state->newline, 0, si...
function newline_active (line 620) | static bool newline_active(Env *env) { return env->state->newline.state ...
function newline_init (line 622) | static bool newline_init(Env *env) { return env->state->newline.state ==...
function is_eof (line 628) | static bool is_eof(Env *env) { return env->lexer->eof(env->lexer); }
function not_eof (line 630) | static bool not_eof(Env *env) { return !(is_eof(env)); }
function column (line 636) | static uint32_t column(Env *env) {
function advance (line 649) | static void advance(Env *env) {
function set_result_symbol (line 656) | static bool set_result_symbol(Env *env, Symbol result) {
function mark_debug (line 666) | static void mark_debug(Env *env, const char *restrict marked_by) {
function advance_debug (line 676) | static void advance_debug(Env *env) {
function skip_debug (line 681) | static void skip_debug(Env *env) {
function valid (line 691) | static inline bool valid(Env *env, Symbol s) { return env->symbols[s]; }
function Symbol (line 697) | static Symbol finish(Symbol s, const char *restrict desc) {
function Symbol (line 704) | static Symbol finish_if_valid(Env *env, Symbol s, const char *restrict d...
function Symbol (line 709) | static Symbol finish_marked(Env *env, Symbol s, const char *restrict des...
function Symbol (line 715) | static Symbol update_state(const char *restrict desc) {
function advance_over_abs (line 727) | static void advance_over_abs(Env *env, uint32_t abs) {
function advance_over (line 739) | static void advance_over(Env *env, uint32_t rel) {
function skip_over (line 762) | static void skip_over(Env *env, uint32_t rel) {
function advance_before (line 774) | static void advance_before(Env *env, uint32_t rel) {
function unsafe_peek_abs (line 786) | static int32_t unsafe_peek_abs(Env *env, uint32_t abs) {
function unsafe_peek (line 797) | static int32_t unsafe_peek(Env *env, uint32_t rel) {
function debug_peek (line 803) | static void debug_peek(Env *env, uint32_t rel) {
function peek (line 824) | static int32_t peek(Env *env, uint32_t rel) {
function peek0 (line 838) | static int32_t peek0(Env *env) { return peek(env, 0); }
function peek1 (line 844) | static int32_t peek1(Env *env) { return peek(env, 1); }
function peek2 (line 850) | static int32_t peek2(Env *env) { return peek(env, 2); }
function char_at (line 855) | static bool char_at(Env *env, uint32_t n, int32_t c) {
function char0 (line 862) | static bool char0(Env *env, int32_t c) {
function char1 (line 869) | static bool char1(Env *env, int32_t c) {
function char2 (line 876) | static bool char2(Env *env, int32_t c) {
function reset_lookahead_abs (line 888) | static void reset_lookahead_abs(Env *env, uint32_t abs) {
function reset_lookahead_to (line 894) | static void reset_lookahead_to(Env *env, uint32_t rel) {
function reset_lookahead (line 902) | static void reset_lookahead(Env *env) {
function no_lookahead (line 919) | static bool no_lookahead(Env *env) {
function start_column (line 927) | static uint32_t start_column(Env *env) {
function advance_while (line 936) | static uint32_t advance_while(Env *env, uint32_t i, bool (*pred)(int32_t...
function advance_until_char (line 945) | static uint32_t advance_until_char(Env *env, uint32_t i, int32_t c) {
function has_contexts (line 954) | static bool has_contexts(Env *env) { return env->state->contexts.size !=...
function push_context (line 959) | static void push_context(Env *env, ContextSort sort, uint32_t indent) {
function pop (line 968) | static void pop(Env *env) {
function ContextSort (line 975) | static ContextSort current_context(Env *env) {
function is_layout_context (line 979) | static bool is_layout_context(Env *env) {
function is_semicolon_context (line 987) | static bool is_semicolon_context(Env *env) {
function current_indent (line 995) | static uint32_t current_indent(Env *env) {
function indent_less (line 1003) | static bool indent_less(Env *env, uint32_t indent) {
function indent_lesseq (line 1007) | static bool indent_lesseq(Env *env, uint32_t indent) {
function top_layout (line 1011) | static bool top_layout(Env *env) {
function in_module_header (line 1015) | static bool in_module_header(Env *env) {
function Symbol (line 1022) | static Symbol context_end_sym(ContextSort s) {
function is_newline (line 1043) | static bool is_newline(int32_t c) {
function varid_start_char (line 1052) | static bool varid_start_char(const int32_t c) { return c == '_' || is_va...
function is_id_char (line 1056) | static bool is_id_char(const int32_t c) {
function is_inner_id_char (line 1061) | static bool is_inner_id_char(const int32_t c) {
function quoter_char (line 1065) | static bool quoter_char(const int32_t c) { return is_id_char(c) || c == ...
function reserved_symbolic (line 1067) | static bool reserved_symbolic(const int32_t c) {
function symop_char (line 1086) | static bool symop_char(const int32_t c) {
function symop_lookahead (line 1097) | static uint32_t symop_lookahead(Env *env) {
function is_symop (line 1106) | static bool is_symop(Env *env) {
function after_error (line 1115) | static bool after_error(Env *env) { return valid(env, FAIL); }
function push_parse_buffer_line (line 1123) | static void push_parse_buffer_line(Env *env) {
function ParseLine (line 1129) | static ParseLine *ensure_parse_buffer(Env *env) {
function append_parse_buffer (line 1136) | static void append_parse_buffer(Env *env) {
function fill_parse_buffer (line 1145) | static void fill_parse_buffer(Env *env) {
function print_lookahead (line 1152) | static void print_lookahead(Env *env) {
function print_lookahead_chars_from (line 1172) | static void print_lookahead_chars_from(Env *env, uint32_t start) {
function debug_contexts (line 1187) | static void debug_contexts(Env *env) {
function debug_newline (line 1208) | void debug_newline(Env *env) {
function debug_valid (line 1233) | static void debug_valid(Env *env, const bool *syms) {
function debug_init (line 1248) | static bool debug_init(Env *env) {
function sgr (line 1261) | void sgr(const char *restrict code) {
function color (line 1265) | void color(unsigned c) {
function palette (line 1271) | void palette() {
function dump_parse_metadata (line 1286) | static void dump_parse_metadata(Env *env) {
function debug_parse (line 1307) | void debug_parse(Env *env) {
function serialize_parse_lines (line 1346) | static unsigned serialize_parse_lines(char *cursor, ParseLines *parse, u...
function deserialize_parse_lines (line 1360) | static void deserialize_parse_lines(const char *cursor, ParseLines *pars...
function debug_finish (line 1382) | void debug_finish(Env *env, Symbol result) {
function seq_from (line 1404) | static bool seq_from(Env *env, const char *restrict s, uint32_t start) {
function seq (line 1418) | static bool seq(Env *env, const char *restrict s) {
function take_line (line 1425) | static void take_line(Env *env) {
function is_space_or_tab (line 1429) | static bool is_space_or_tab(int32_t c) {
function take_line_escaped_newline (line 1437) | static void take_line_escaped_newline(Env *env) {
function skip_space (line 1456) | static bool skip_space(Env *env) {
function skip_newlines (line 1467) | static bool skip_newlines(Env *env) {
type Space (line 1474) | typedef enum {
function Space (line 1486) | static Space skip_whitespace(Env *env) {
function take_space_from (line 1499) | static uint32_t take_space_from(Env *env, uint32_t start) {
function token_end (line 1507) | static bool token_end(int32_t c) { return !is_inner_id_char(c); }
function token_from (line 1513) | static bool token_from(Env *env, const char *restrict s, uint32_t start) {
function token (line 1520) | static bool token(Env *env, const char *restrict s) {
function any_token_from (line 1528) | static bool any_token_from(Env *env, size_t n, const char * tokens[], ui...
function match_symop (line 1535) | static bool match_symop(Env *env, const char *restrict target) {
function uninitialized (line 1539) | static bool uninitialized(Env *env) { return !has_contexts(env); }
function conid (line 1541) | static uint32_t conid(Env *env) {
type QualifiedName (line 1546) | typedef enum {
function QualifiedName (line 1552) | static QualifiedName qualified_name(Env *env, bool (*name)(Env *)) {
function odd_backslashes_before (line 1571) | static bool odd_backslashes_before(Env *env, int32_t index) {
function take_string_literal (line 1583) | static uint32_t take_string_literal(Env *env) {
function take_char_literal (line 1600) | static uint32_t take_char_literal(Env *env) {
type CppDirective (line 1609) | typedef enum {
function cpp_cond_start (line 1623) | static bool cpp_cond_start(Env *env, uint32_t start) {
function cpp_cond_else (line 1634) | static bool cpp_cond_else(Env *env, uint32_t start) {
function cpp_cond_end (line 1638) | static bool cpp_cond_end(Env *env, uint32_t start) { return token_from(e...
function cpp_directive_other (line 1650) | static bool cpp_directive_other(Env *env, uint32_t start) {
function CppDirective (line 1668) | static CppDirective cpp_directive(Env *env) {
function Symbol (line 1695) | static Symbol start_brace(Env *env) {
function Symbol (line 1706) | static Symbol end_brace(Env *env) {
function Symbol (line 1717) | static Symbol valid_layout_start_sym(Env *env) {
function ContextSort (line 1727) | static ContextSort layout_sort(Symbol s) {
type StartLayout (line 1744) | typedef struct {
function StartLayout (line 1758) | static StartLayout valid_layout_start(Env *env, Lexed next) {
function indent_can_start_layout (line 1789) | static bool indent_can_start_layout(Env *env, ContextSort sort, uint32_t...
function Symbol (line 1807) | static Symbol start_layout(Env *env, const StartLayout start, uint32_t i...
function Symbol (line 1822) | static Symbol start_layout_interior(Env *env, Lexed next) {
function Symbol (line 1832) | static Symbol start_layout_newline(Env *env) {
function Symbol (line 1843) | static Symbol texp_context(Env *env) {
function Symbol (line 1862) | static Symbol end_layout_unchecked(Env *env, const char *restrict desc) {
function Symbol (line 1870) | static Symbol end_layout(Env *env, const char *restrict desc) {
function Symbol (line 1879) | static Symbol end_layout_brace(Env *env) {
function Symbol (line 1899) | static Symbol end_layout_indent(Env *env) {
function Symbol (line 1928) | static Symbol end_layout_infix(Env *env) {
function Symbol (line 1949) | static Symbol end_layout_where(Env *env) {
function Symbol (line 1968) | static Symbol end_layout_in(Env *env) {
function Symbol (line 1976) | static Symbol end_layout_deriving(Env *env) {
function layouts_in_texp (line 1985) | static bool layouts_in_texp(Env *env) {
function Symbol (line 2018) | static Symbol token_end_layout_texp(Env *env) {
function Symbol (line 2022) | static Symbol force_end_context(Env *env) {
function opening_token (line 2040) | static bool opening_token(Env *env, uint32_t i) {
function valid_symop_two_chars (line 2060) | static bool valid_symop_two_chars(int32_t first_char, int32_t second_cha...
function Lexed (line 2076) | static Lexed lex_prefix(Env *env, Lexed t) {
function Lexed (line 2084) | static Lexed lex_splice(int32_t c) {
function Lexed (line 2106) | static Lexed lex_symop(Env *env) {
function Symbol (line 2222) | static Symbol left_section_op(Env *env, uint32_t start) {
function Symbol (line 2235) | static Symbol left_section_ticked(Env *env) {
function Symbol (line 2251) | static Symbol finish_symop(Env *env, Symbol s) {
function Symbol (line 2264) | static Symbol tight_op(Env *env, bool whitespace, Symbol s) {
function Symbol (line 2276) | static Symbol prefix_or_varsym(Env *env, bool whitespace, Symbol s) {
function Symbol (line 2289) | static Symbol tight_or_varsym(Env *env, bool whitespace, Symbol s) {
function Symbol (line 2302) | static Symbol infix_or_varsym(Env *env, bool whitespace, Symbol prefix, ...
function Symbol (line 2307) | static Symbol qualified_op(Env *env) {
function is_qq_start (line 2323) | static bool is_qq_start(Env *env) {
function Lexed (line 2331) | static Lexed try_end_token(Env *env, const char * restrict target, Lexed...
function only_minus (line 2339) | static bool only_minus(Env *env) {
function line_comment_herald (line 2348) | static bool line_comment_herald(Env *env) {
function Lexed (line 2352) | static Lexed lex_cpp(Env *env) {
function Lexed (line 2366) | static Lexed lex_extras(Env *env, bool bol) {
function Lexed (line 2387) | static Lexed lex(Env *env, bool bol) {
function Symbol (line 2434) | static Symbol cpp_else(Env *env, bool emit) {
function Symbol (line 2457) | static Symbol cpp_line(Env *env) {
function Symbol (line 2469) | static Symbol comment_type(Env *env) {
function Symbol (line 2484) | static Symbol inline_comment(Env *env) {
function consume_block_comment (line 2495) | static uint32_t consume_block_comment(Env *env, uint32_t col) {
function Symbol (line 2537) | static Symbol block_comment(Env *env) {
function consume_pragma (line 2547) | static bool consume_pragma(Env *env) {
function Symbol (line 2567) | static Symbol pragma(Env *env) {
function Symbol (line 2580) | static Symbol qq_body(Env *env) {
function Symbol (line 2653) | static Symbol explicit_semicolon(Env *env) {
function Symbol (line 2661) | static Symbol resolve_semicolon(Env *env, Lexed next) {
function Symbol (line 2688) | static Symbol semicolon(Env *env) {
function Symbol (line 2711) | static Symbol process_token_safe(Env *env, Lexed next) {
function Symbol (line 2759) | static Symbol process_token_symop(Env *env, bool whitespace, Lexed next) {
function Symbol (line 2802) | static Symbol process_token_splice(Env *env, Lexed next) {
function Symbol (line 2815) | static Symbol process_token_interior(Env *env, Lexed next) {
function Symbol (line 2837) | static Symbol process_token_init(Env *env, uint32_t indent, Lexed next) {
function Symbol (line 2861) | static Symbol newline_extras(Env *env, Space space) {
function Symbol (line 2873) | static Symbol newline_process(Env *env) {
function Symbol (line 2896) | static Symbol newline_post(Env *env) {
function newline_lookahead (line 2906) | static void newline_lookahead(Env *env, Newline *newline) {
function Symbol (line 2969) | static Symbol newline_start(Env *env) {
function Symbol (line 2980) | static Symbol newline_resume(Env *env) {
type CtrResult (line 3042) | typedef enum {
type CtrState (line 3073) | typedef struct {
function CtrResult (line 3091) | static CtrResult ctr_bracket_open(CtrState *state) {
function CtrResult (line 3101) | static CtrResult ctr_bracket_close(CtrState *state) {
function CtrResult (line 3111) | static CtrResult ctr_stop_on_token(Env *env, const char * restrict targe...
function CtrResult (line 3128) | static CtrResult ctr_top(Env *env, Lexed next) {
function CtrResult (line 3183) | static CtrResult ctr_lookahead_step(Env *env, CtrState *state, Lexed nex...
function Symbol (line 3243) | static Symbol constraint_lookahead(Env *env) {
function Symbol (line 3293) | static Symbol process_token_constraint(Env *env) {
function Symbol (line 3307) | static Symbol interior(Env *env, bool whitespace) {
function Symbol (line 3325) | static Symbol pre_ws_commands(Env *env) {
function Symbol (line 3336) | static Symbol scan_main(Env *env) {
function Symbol (line 3347) | static Symbol scan_debug(Env *env) {
function process_result (line 3356) | static bool process_result(Env *env, Symbol result) {
function scan (line 3373) | static bool scan(Env *env) {
type Persist (line 3387) | typedef struct {
function tree_sitter_haskell_external_scanner_scan (line 3412) | bool tree_sitter_haskell_external_scanner_scan(void *payload, TSLexer *l...
function tree_sitter_haskell_external_scanner_serialize (line 3417) | unsigned tree_sitter_haskell_external_scanner_serialize(void *payload, c...
function tree_sitter_haskell_external_scanner_deserialize (line 3434) | void tree_sitter_haskell_external_scanner_deserialize(void *payload, con...
function tree_sitter_haskell_external_scanner_destroy (line 3460) | void tree_sitter_haskell_external_scanner_destroy(void *payload) {
FILE: src/tree_sitter/array.h
type Array (line 159) | typedef Array(void) Array;
function _array__delete (line 162) | static inline void _array__delete(Array *self) {
function _array__erase (line 172) | static inline void _array__erase(Array *self, size_t element_size,
function _array__reserve (line 182) | static inline void _array__reserve(Array *self, size_t element_size, uin...
function _array__assign (line 194) | static inline void _array__assign(Array *self, const Array *other, size_...
function _array__swap (line 201) | static inline void _array__swap(Array *self, Array *other) {
function _array__grow (line 208) | static inline void _array__grow(Array *self, uint32_t count, size_t elem...
function _array__splice (line 219) | static inline void _array__splice(Array *self, size_t element_size,
FILE: src/tree_sitter/parser.h
type TSStateId (line 17) | typedef uint16_t TSStateId;
type TSSymbol (line 18) | typedef uint16_t TSSymbol;
type TSFieldId (line 19) | typedef uint16_t TSFieldId;
type TSLanguage (line 20) | typedef struct TSLanguage TSLanguage;
type TSFieldMapEntry (line 23) | typedef struct {
type TSFieldMapSlice (line 29) | typedef struct {
type TSSymbolMetadata (line 34) | typedef struct {
type TSLexer (line 40) | typedef struct TSLexer TSLexer;
type TSLexer (line 42) | struct TSLexer {
type TSParseActionType (line 53) | typedef enum {
type TSParseAction (line 60) | typedef union {
type TSLexMode (line 77) | typedef struct {
type TSParseActionEntry (line 82) | typedef union {
type TSCharacterRange (line 90) | typedef struct {
type TSLanguage (line 95) | struct TSLanguage {
function set_contains (line 134) | static inline bool set_contains(TSCharacterRange *ranges, uint32_t len, ...
FILE: src/unicode.h
function is_identifier_1_char (line 136) | static bool is_identifier_1_char(int32_t c) {
function is_identifier_2_char (line 168) | static bool is_identifier_2_char(int32_t c) {
function is_identifier_3_char (line 655) | static bool is_identifier_3_char(int32_t c) {
function is_identifier_4_char (line 867) | static bool is_identifier_4_char(int32_t c) {
function is_identifier_5_char (line 881) | static bool is_identifier_5_char(int32_t c) {
function is_identifier_char (line 886) | static bool is_identifier_char(int32_t c) {
function is_varid_start_1_char (line 1033) | static bool is_varid_start_1_char(int32_t c) {
function is_varid_start_2_char (line 1065) | static bool is_varid_start_2_char(int32_t c) {
function is_varid_start_3_char (line 1552) | static bool is_varid_start_3_char(int32_t c) {
function is_varid_start_4_char (line 1764) | static bool is_varid_start_4_char(int32_t c) {
function is_varid_start_char (line 1769) | static bool is_varid_start_char(int32_t c) {
function is_conid_start_1_char (line 1861) | static bool is_conid_start_1_char(int32_t c) {
function is_conid_start_2_char (line 1876) | static bool is_conid_start_2_char(int32_t c) {
function is_conid_start_3_char (line 1929) | static bool is_conid_start_3_char(int32_t c) {
function is_conid_start_4_char (line 1942) | static bool is_conid_start_4_char(int32_t c) {
function is_conid_start_5_char (line 1988) | static bool is_conid_start_5_char(int32_t c) {
function is_conid_start_char (line 1993) | static bool is_conid_start_char(int32_t c) {
function is_symop_1_char (line 2140) | static bool is_symop_1_char(int32_t c) {
function is_symop_2_char (line 2164) | static bool is_symop_2_char(int32_t c) {
function is_symop_3_char (line 2261) | static bool is_symop_3_char(int32_t c) {
function is_symop_4_char (line 2282) | static bool is_symop_4_char(int32_t c) {
function is_symop_5_char (line 2396) | static bool is_symop_5_char(int32_t c) {
function is_symop_char (line 2401) | static bool is_symop_char(int32_t c) {
function is_space_char (line 2500) | static bool is_space_char(int32_t c) {
Condensed preview — 101 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,414K chars).
[
{
"path": ".editorconfig",
"chars": 541,
"preview": "root = true\n\n[*]\ncharset = utf-8\n\n[*.{json,toml,yml,gyp}]\nindent_style = space\nindent_size = 2\n\n[*.js]\nindent_style = sp"
},
{
"path": ".gitattributes",
"chars": 862,
"preview": "* text=auto eol=lf\n\n# Generated source files\nsrc/*.json linguist-generated\nsrc/parser.c linguist-generated\nsrc/tree_sitt"
},
{
"path": ".github/workflows/ci.yml",
"chars": 3408,
"preview": "name: CI\n\non:\n push:\n branches: [master]\n paths:\n - grammar.js\n - src/**\n - test/**\n - bindin"
},
{
"path": ".github/workflows/fuzz.yml",
"chars": 323,
"preview": "name: Fuzz Parser\n\non:\n push:\n branches: [master]\n paths:\n - src/scanner.c\n pull_request:\n paths:\n "
},
{
"path": ".github/workflows/publish.yml",
"chars": 796,
"preview": "name: Publish packages\n\non:\n push:\n tags: [\"*\"]\n\npermissions:\n contents: write\n id-token: write\n attestations: wr"
},
{
"path": ".gitignore",
"chars": 324,
"preview": "# Rust artifacts\ntarget/\n\n# Node artifacts\nbuild/\nprebuilds/\nnode_modules/\n\n# Swift artifacts\n.build/\n\n# Go artifacts\n_o"
},
{
"path": "CMakeLists.txt",
"chars": 2461,
"preview": "cmake_minimum_required(VERSION 3.13)\n\nproject(tree-sitter-haskell\n VERSION \"0.23.1\"\n DESCRIPTION \"Haskell "
},
{
"path": "Cargo.toml",
"chars": 695,
"preview": "[package]\nname = \"tree-sitter-haskell\"\ndescription = \"Haskell grammar for tree-sitter\"\nversion = \"0.23.1\"\nauthors = [\"Ma"
},
{
"path": "LICENSE",
"chars": 1080,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2014 Max Brunsfeld\n\nPermission is hereby granted, free of charge, to any person obt"
},
{
"path": "Makefile",
"chars": 3185,
"preview": "ifeq ($(OS),Windows_NT)\n$(error Windows is not supported)\nendif\n\nLANGUAGE_NAME := tree-sitter-haskell\nHOMEPAGE_URL := ht"
},
{
"path": "Package.resolved",
"chars": 333,
"preview": "{\n \"object\": {\n \"pins\": [\n {\n \"package\": \"SwiftTreeSitter\",\n \"repositoryURL\": \"https://github.com"
},
{
"path": "Package.swift",
"chars": 1014,
"preview": "// swift-tools-version:5.3\nimport PackageDescription\n\nlet package = Package(\n name: \"TreeSitterHaskell\",\n products"
},
{
"path": "README.md",
"chars": 12556,
"preview": "# tree-sitter-haskell\n\n[![CI][ci]](https://github.com/tree-sitter/tree-sitter-haskell/actions/workflows/ci.yml)\n[![disco"
},
{
"path": "binding.gyp",
"chars": 602,
"preview": "{\n \"targets\": [\n {\n \"target_name\": \"tree_sitter_haskell_binding\",\n \"dependencies\": [\n \"<!(node -p \\"
},
{
"path": "bindings/c/tree-sitter-haskell.h",
"chars": 250,
"preview": "#ifndef TREE_SITTER_HASKELL_H_\n#define TREE_SITTER_HASKELL_H_\n\ntypedef struct TSLanguage TSLanguage;\n\n#ifdef __cplusplus"
},
{
"path": "bindings/c/tree-sitter-haskell.pc.in",
"chars": 299,
"preview": "prefix=@CMAKE_INSTALL_PREFIX@\nlibdir=${prefix}/@CMAKE_INSTALL_LIBDIR@\nincludedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@\n\nN"
},
{
"path": "bindings/go/binding.go",
"chars": 289,
"preview": "package tree_sitter_haskell\n\n// #cgo CFLAGS: -std=c11 -fPIC\n// #include \"../../src/parser.c\"\n// #include \"../../src/scan"
},
{
"path": "bindings/go/binding_test.go",
"chars": 369,
"preview": "package tree_sitter_haskell_test\n\nimport (\n\t\"testing\"\n\n\ttree_sitter \"github.com/tree-sitter/go-tree-sitter\"\n\ttree_sitter"
},
{
"path": "bindings/node/binding.cc",
"chars": 589,
"preview": "#include <napi.h>\n\ntypedef struct TSLanguage TSLanguage;\n\nextern \"C\" TSLanguage *tree_sitter_haskell();\n\n// \"tree-sitter"
},
{
"path": "bindings/node/binding_test.js",
"chars": 250,
"preview": "const assert = require(\"node:assert\");\nconst { test } = require(\"node:test\");\n\nconst Parser = require(\"tree-sitter\");\n\nt"
},
{
"path": "bindings/node/index.d.ts",
"chars": 452,
"preview": "type BaseNode = {\n type: string;\n named: boolean;\n};\n\ntype ChildNode = {\n multiple: boolean;\n required: boolean;\n t"
},
{
"path": "bindings/node/index.js",
"chars": 456,
"preview": "const root = require(\"path\").join(__dirname, \"..\", \"..\");\n\nmodule.exports =\n typeof process.versions.bun === \"string\"\n "
},
{
"path": "bindings/python/tests/test_binding.py",
"chars": 299,
"preview": "from unittest import TestCase\n\nimport tree_sitter, tree_sitter_haskell\n\n\nclass TestLanguage(TestCase):\n def test_can_"
},
{
"path": "bindings/python/tree_sitter_haskell/__init__.py",
"chars": 953,
"preview": "\"\"\"Haskell grammar for tree-sitter\"\"\"\n\nfrom importlib.resources import files as _files\n\nfrom ._binding import language\n\n"
},
{
"path": "bindings/python/tree_sitter_haskell/__init__.pyi",
"chars": 140,
"preview": "from typing import Final\n\nHIGHLIGHTS_QUERY: Final[str]\nINJECTIONS_QUERY: Final[str]\nLOCALS_QUERY: Final[str]\n\ndef langua"
},
{
"path": "bindings/python/tree_sitter_haskell/binding.c",
"chars": 685,
"preview": "#include <Python.h>\n\ntypedef struct TSLanguage TSLanguage;\n\nTSLanguage *tree_sitter_haskell(void);\n\nstatic PyObject* _bi"
},
{
"path": "bindings/python/tree_sitter_haskell/py.typed",
"chars": 0,
"preview": ""
},
{
"path": "bindings/rust/build.rs",
"chars": 635,
"preview": "fn main() {\n let src_dir = std::path::Path::new(\"src\");\n\n let mut c_config = cc::Build::new();\n c_config\n "
},
{
"path": "bindings/rust/lib.rs",
"chars": 2065,
"preview": "//! This crate provides Haskell language support for the [tree-sitter][] parsing library.\n//!\n//! Typically, you will us"
},
{
"path": "bindings/swift/TreeSitterHaskell/haskell.h",
"chars": 250,
"preview": "#ifndef TREE_SITTER_HASKELL_H_\n#define TREE_SITTER_HASKELL_H_\n\ntypedef struct TSLanguage TSLanguage;\n\n#ifdef __cplusplus"
},
{
"path": "bindings/swift/TreeSitterHaskellTests/TreeSitterHaskellTests.swift",
"chars": 371,
"preview": "import XCTest\nimport SwiftTreeSitter\nimport TreeSitterHaskell\n\nfinal class TreeSitterHaskellTests: XCTestCase {\n func"
},
{
"path": "examples/Basic.hs",
"chars": 18,
"preview": "a = 1\nb = 2\nc = 3\n"
},
{
"path": "go.mod",
"chars": 170,
"preview": "module github.com/tree-sitter/tree-sitter-haskell\n\ngo 1.22\n\nrequire github.com/tree-sitter/go-tree-sitter v0.24.0\n\nrequi"
},
{
"path": "go.sum",
"chars": 4176,
"preview": "github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.m"
},
{
"path": "grammar/class.js",
"chars": 3126,
"preview": "const {\n sep1,\n layout,\n context,\n forall,\n} = require('./util.js')\n\nmodule.exports = {\n\n // ----------------------"
},
{
"path": "grammar/conflicts.js",
"chars": 3841,
"preview": "module.exports = {\n\n conflicts: $ => [\n\n /**\n * For reference in GHC:\n * - Note [Ambiguous syntactic categor"
},
{
"path": "grammar/context.js",
"chars": 1969,
"preview": "const {\n parens,\n sep2,\n} = require('./util.js')\n\nmodule.exports = {\n\n // -------------------------------------------"
},
{
"path": "grammar/data.js",
"chars": 5745,
"preview": "const {\n sep1,\n sep,\n braces,\n layout,\n unboxed_sum_single,\n qualified,\n context,\n forall,\n} = require('./util.j"
},
{
"path": "grammar/decl.js",
"chars": 4656,
"preview": "const {\n sep1,\n sep2,\n parens,\n layout,\n} = require('./util.js')\n\nmodule.exports = {\n\n // -------------------------"
},
{
"path": "grammar/exp.js",
"chars": 11764,
"preview": "const {\n sep1,\n sep,\n parens,\n braces,\n brackets,\n layout_sort,\n layout,\n unboxed_tuple_nonempty,\n unboxed_sum_"
},
{
"path": "grammar/externals.js",
"chars": 9331,
"preview": "module.exports = {\n\n /**\n * These rules are handled manually by the custom lexer in `src/scanner.c`.\n * Whenever th"
},
{
"path": "grammar/general.js",
"chars": 1230,
"preview": "const {\n sep1,\n layout_sort,\n} = require('./util.js')\n\nmodule.exports = {\n\n // --------------------------------------"
},
{
"path": "grammar/id.js",
"chars": 3648,
"preview": "const {\n parens,\n ticked,\n promoted,\n qualified,\n} = require('./util.js')\n\nmodule.exports = {\n // -----------------"
},
{
"path": "grammar/inline.js",
"chars": 1978,
"preview": "module.exports = {\n\n inline: $ => [\n\n // ------------------------------------------------\n // variable\n // ---"
},
{
"path": "grammar/lexeme.js",
"chars": 2015,
"preview": "const id_char = /[\\pL\\p{Mn}\\pN_']*/\n\nconst varid_start_char = /[_\\p{Ll}\\p{Lo}]/\n\nconst conid_start_char = /[\\p{Lu}\\p{Lt}"
},
{
"path": "grammar/literal.js",
"chars": 1945,
"preview": "const {\n parens,\n brackets,\n unboxed,\n} = require('./util.js')\n\nconst decimal = /[0-9][0-9_]*/\nconst exponent = /[eE]"
},
{
"path": "grammar/module.js",
"chars": 4097,
"preview": "const {\n sep1,\n sep,\n parens,\n semi,\n semi_opt,\n semis,\n} = require('./util.js')\n\nmodule.exports = {\n\n // -------"
},
{
"path": "grammar/operator.js",
"chars": 2113,
"preview": "const {\n parens,\n qualified,\n} = require('./util.js')\n\nmodule.exports = {\n\n // --------------------------------------"
},
{
"path": "grammar/pat.js",
"chars": 4935,
"preview": "const {\n sep1,\n sep2,\n sep,\n parens,\n braces,\n brackets,\n unboxed_tuple_full,\n unboxed_sum_single,\n} = require('"
},
{
"path": "grammar/patsyn.js",
"chars": 1114,
"preview": "const {\n layout,\n optional_where,\n} = require('./util.js')\n\nmodule.exports = {\n // ----------------------------------"
},
{
"path": "grammar/precedences.js",
"chars": 2109,
"preview": "module.exports = {\n\n precedences: $ => [\n\n // ------------------------------------------------\n // associativity "
},
{
"path": "grammar/th.js",
"chars": 2473,
"preview": "const {\n layout_sort,\n} = require('./util.js')\n\nconst quote_bracket = ($, quoter) => seq(\n $._cond_quote_start,\n '[',"
},
{
"path": "grammar/type.js",
"chars": 11985,
"preview": "const {\n parens,\n braces,\n brackets,\n prefix_at,\n sep1,\n sep2,\n unboxed_tuple_full,\n unboxed_sum_full,\n forall,"
},
{
"path": "grammar/util.js",
"chars": 4861,
"preview": "// ------------------------------------------------------------------------\n// structure\n// ----------------------------"
},
{
"path": "grammar.js",
"chars": 2615,
"preview": "const\n class_ = require('./grammar/class.js'),\n conflicts = require('./grammar/conflicts.js'),\n context = require('./"
},
{
"path": "package.json",
"chars": 1277,
"preview": "{\n \"name\": \"tree-sitter-haskell\",\n \"version\": \"0.23.1\",\n \"description\": \"Haskell grammar for tree-sitter\",\n \"reposit"
},
{
"path": "pyproject.toml",
"chars": 843,
"preview": "[build-system]\nrequires = [\"setuptools>=42\", \"wheel\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"tree-si"
},
{
"path": "queries/highlights.scm",
"chars": 8294,
"preview": "; ----------------------------------------------------------------------------\n; Parameters and variables\n; NOTE: These "
},
{
"path": "queries/injections.scm",
"chars": 2205,
"preview": "; -----------------------------------------------------------------------------\n; General language injection\n(quasiquote"
},
{
"path": "queries/locals.scm",
"chars": 169,
"preview": "(signature name: (variable)) @local.definition\n(function name: (variable)) @local.definition\n(pattern/variable) @local.d"
},
{
"path": "setup.py",
"chars": 1719,
"preview": "from os.path import isdir, join\nfrom platform import system\n\nfrom setuptools import Extension, find_packages, setup\nfrom"
},
{
"path": "src/grammar.json",
"chars": 298379,
"preview": "{\n \"$schema\": \"https://tree-sitter.github.io/tree-sitter/assets/schemas/grammar.schema.json\",\n \"name\": \"haskell\",\n \"w"
},
{
"path": "src/node-types.json",
"chars": 113367,
"preview": "[\n {\n \"type\": \"class_decl\",\n \"named\": true,\n \"subtypes\": [\n {\n \"type\": \"data_family\",\n \"nam"
},
{
"path": "src/scanner.c",
"chars": 113845,
"preview": "/**\n * The scanner is an extension to the built-in lexer that handles cases that are hard or impossible to express with "
},
{
"path": "src/tree_sitter/alloc.h",
"chars": 985,
"preview": "#ifndef TREE_SITTER_ALLOC_H_\n#define TREE_SITTER_ALLOC_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdbool.h>\n"
},
{
"path": "src/tree_sitter/array.h",
"chars": 10420,
"preview": "#ifndef TREE_SITTER_ARRAY_H_\n#define TREE_SITTER_ARRAY_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include \"./alloc.h\"\n"
},
{
"path": "src/tree_sitter/parser.h",
"chars": 7039,
"preview": "#ifndef TREE_SITTER_PARSER_H_\n#define TREE_SITTER_PARSER_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdbool.h"
},
{
"path": "src/unicode.h",
"chars": 122709,
"preview": "#include <stdbool.h>\n#include <stdint.h>\n\nstatic uint8_t bitmap_identifier_1[] = {\n0xff,3,0xfe,0xff,0xff,7,0xfe,0xff,0xf"
},
{
"path": "test/corpus/char.txt",
"chars": 10992,
"preview": "================================================================================\nchar: [a-zA-Z0-9_]\n===================="
},
{
"path": "test/corpus/class.txt",
"chars": 10851,
"preview": "================================================================================\nclass: minimal\n========================"
},
{
"path": "test/corpus/comment.txt",
"chars": 5392,
"preview": "================================================================================\ncomment: line\n========================="
},
{
"path": "test/corpus/consym.txt",
"chars": 958,
"preview": "================================================================================\nconsym: valid\n========================="
},
{
"path": "test/corpus/context.txt",
"chars": 27403,
"preview": "================================================================================\ncontext: smoke\n========================"
},
{
"path": "test/corpus/cpp.txt",
"chars": 12234,
"preview": "================================================================================\ncpp: keep layout from first if branch\n="
},
{
"path": "test/corpus/data.txt",
"chars": 30222,
"preview": "================================================================================\ndata: empty\n==========================="
},
{
"path": "test/corpus/decl.txt",
"chars": 16081,
"preview": "================================================================================\ndecl: two trivial successive functions\n"
},
{
"path": "test/corpus/default.txt",
"chars": 427,
"preview": "================================================================================\ndefault: default decl\n================="
},
{
"path": "test/corpus/exp.txt",
"chars": 70340,
"preview": "================================================================================\nexp: application\n======================"
},
{
"path": "test/corpus/family.txt",
"chars": 18784,
"preview": "================================================================================\nfamily: closed, nullary\n==============="
},
{
"path": "test/corpus/foreign.txt",
"chars": 1413,
"preview": "================================================================================\nforeign: decl\n========================="
},
{
"path": "test/corpus/gadt.txt",
"chars": 10799,
"preview": "================================================================================\ngadt: empty\n==========================="
},
{
"path": "test/corpus/id.txt",
"chars": 2792,
"preview": "================================================================================\nid: variable\n=========================="
},
{
"path": "test/corpus/implicit.txt",
"chars": 4723,
"preview": "================================================================================\nimplicit: synonym plain\n==============="
},
{
"path": "test/corpus/import.txt",
"chars": 11744,
"preview": "================================================================================\nimport: unqualified module plain\n======"
},
{
"path": "test/corpus/instance.txt",
"chars": 11389,
"preview": "================================================================================\ninstance: minimal\n====================="
},
{
"path": "test/corpus/layout.txt",
"chars": 78782,
"preview": "================================================================================\nlayout: where on same level as case alt"
},
{
"path": "test/corpus/module.txt",
"chars": 8020,
"preview": "================================================================================\nmodule: exports empty\n================="
},
{
"path": "test/corpus/newtype.txt",
"chars": 4314,
"preview": "================================================================================\nnewtype: basic\n========================"
},
{
"path": "test/corpus/number.txt",
"chars": 3631,
"preview": "================================================================================\nnumber: decimal\n======================="
},
{
"path": "test/corpus/pat.txt",
"chars": 28512,
"preview": "================================================================================\npat: basic\n============================"
},
{
"path": "test/corpus/patsyn.txt",
"chars": 8005,
"preview": "================================================================================\npatsyn: unidirectional simple\n========="
},
{
"path": "test/corpus/pragma.txt",
"chars": 9228,
"preview": "================================================================================\npragma: inline\n========================"
},
{
"path": "test/corpus/prec.txt",
"chars": 37411,
"preview": "================================================================================\nprec: infix qualified varsym with leadi"
},
{
"path": "test/corpus/signature.txt",
"chars": 2819,
"preview": "================================================================================\nsignature: forall\n====================="
},
{
"path": "test/corpus/special.txt",
"chars": 413,
"preview": "================================================================================\nspecial: GHC fixity decl for -> in GHC."
},
{
"path": "test/corpus/string.txt",
"chars": 1504,
"preview": "================================================================================\nstring: special chars\n================="
},
{
"path": "test/corpus/th.txt",
"chars": 15438,
"preview": "================================================================================\nth: quasiquotes\n======================="
},
{
"path": "test/corpus/type.txt",
"chars": 28540,
"preview": "================================================================================\ntype: basic\n==========================="
},
{
"path": "test/corpus/varsym.txt",
"chars": 34108,
"preview": "================================================================================\nvarsym: error: |\n======================"
},
{
"path": "tree-sitter.json",
"chars": 899,
"preview": "{\n \"grammars\": [\n {\n \"name\": \"haskell\",\n \"camelcase\": \"Haskell\",\n \"scope\": \"source.haskell\",\n \"p"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the tree-sitter/tree-sitter-haskell GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 101 files (20.2 MB), approximately 351.2k tokens, and a symbol index with 286 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.