2 个不稳定版本
0.21.0 | 2024 年 5 月 5 日 |
---|---|
0.15.0 | 2024 年 2 月 26 日 |
在 文本编辑器 中排名第 445
每月下载量 1,943 次
在 4 个 crate 中使用
20MB
680K SLoC
tree-sitter-haskell
Haskell 语法 for tree-sitter.
参考
支持的语言扩展
这些扩展是支持的 ✅,不受支持的 ❌ 或不适用,因为它们不涉及解析 ➖️
- 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 ✅
- 模式守卫 ✅
- 模式同义词 ✅
- 多类型 ➖️
- 后缀运算符 ➖️
- 带资格的do ✅
- 量化约束 ✅
- 准引号 ✅
- Rank2类型 ✅
- RankN类型 ✅
- 可重新绑定语法 ➖️
- 记录通配符 ➖️
- 递归do ✅
- 必需类型参数 ✅
- 角色注解 ✅
- 安全 ➖️
- 作用域类型变量 ✅
- 独立推导 ✅
- 独立类型签名 ✅
- 星号是类型 ✅
- 静态指针 ❌
- 严格 ➖️
- 严格数据 ✅
- 模板Haskell ✅
- 模板Haskell引号 ✅
- 传统记录语法 ➖️
- 转换列表推导 ✅
- 可信 ➖️
- 元组部分 ✅
- 类型抽象 ✅
- 类型应用 ✅
- 类型数据 ✅
- 类型族 ✅
- 类型族依赖 ✅
- 类型在类型中 ✅
- 类型运算符 ✅
- 类型同义词实例 ➖️
- 无包装求和 ✅
- 无包装元组 ✅
- 不可判定的实例 ➖️
- 不可判定的超类 ➖️
- Unicode语法 ✅
- 非提升FFI类型 ➖️
- 非提升新类型 ✅
- 不安全 ➖️
- 视图模式 ✅
错误
CPP
预处理器 #elif
和 #else
指令无法正确处理,因为解析器状态必须手动重置为 #if
时的状态。作为 workaround,替代分支中的代码块被视为指令的一部分进行解析。
查询
语法包含几个 超类型,这些超类型将多个其他节点类型组合成一个单一的名称。
超类型名称不会在解析树中作为额外节点出现,但它们可以用特殊方式在查询中使用
- 作为一个别名,匹配它们的任何子类型
- 作为它们子类型的前缀,只有当它作为超类型的产生式出现时才匹配其符号
例如,查询 (expression)
匹配节点 infix
、record
、projection
、constructor
,以及此树中 cats <> Cat {mood = moods.sleepy}
的第二个和第三个 variable
(infix
(variable)
(operator)
(record
(constructor)
(field_update
(field_name (variable))
(projection (variable) (field_name (variable)))))))))
variable
在 field_name
(mood
和 sleepy
)中的两个出现不是表达式,而是复合 record
表达式的一部分的记录字段名称。
使用第二种特殊形式可以特别匹配 variable
节点,这些节点是表达式。查询 (expression/variable)
将仅匹配另外两个,cats
和 moods
。
语法的超类型包括以下集合
-
在任何表达式位置都有效的规则,不包括类型应用、显式类型和表达式签名。
-
在任何模式位置都有效的规则,不包括类型绑定器、显式类型和模式签名。
-
类型是原子类型(没有歧义的结合性,如括号构造、变量和类型构造函数)、应用类型或中缀类型。
-
以
forall
、上下文或函数参数为前缀的类型。 -
几乎与
类型
的规则相同,但用于上下文时进行了镜像。 -
quantified_type
的类似物,用于具有forall
或上下文的约束。 -
类型和类头中的原子节点,例如在
data A @k a (b :: k)
中的A
之后的三个节点。 -
所有顶层声明,如函数和数据类型。
-
在局部绑定(
let
和where
)以及类和实例体中有效的声明的缩写。它由signature
、function
和bind
组成。 -
在类和实例中有效的所有声明,包括关联的类型和数据族。
-
do
-表示语句的不同形式。 -
列表推导限定符的不同形式。
-
函数方程和情况替代中的守卫的不同形式。
开发
生成和测试此语法解析器的驱动程序主要是 tree-sitter CLI。项目的其他组件需要额外的工具,如下所述。
其中一些通过 npm
提供 – 例如,npx tree-sitter
运行 CLI。如果您没有其他方式获得 tree-sitter
,请在以下章节中的所有命令前加上 npx
。
输出路径
CLI 将包含解析器的共享库写入由 $TREE_SITTER_LIBDIR
表示的目录。如果该变量未设置,则默认为 $HOME/.cache/tree-sitter/lib
。
为了避免将开发版本覆盖此全局目录,您可以设置环境变量为本地路径
export TREE_SITTER_LIBDIR=$PWD/.lib
语法
JavaScript 文件 grammar.js
包含语法生产规则的入口点。请参阅 tree-sitter 文档 了解语法和语义的全面介绍。
解析从 rules
字段中的第一个条目开始。
{
rules: {
haskell: $ => seq(
optional($.header),
optional($._body),
),
}
}
生成解析器
开发工作流程的第一步是将 JavaScript 规则定义转换为 src/parser.c
中的 C 代码。
$ tree-sitter generate
此过程的两个副产品被写入 src/grammar.json
和 src/node-types.json
。
编译解析器
大多数提到的测试工具会自动编译 C 代码,但您可以指示 tree-sitter 一次性完成。
$ tree-sitter generate --build
如果您已设置 $TREE_SITTER_LIBDIR
,如前所述,共享对象将写入 $PWD/.lib/haskell.so
。
除了生成的 src/parser.c
之外,tree-sitter 还会将 src/scanner.c
编译并链接到这个对象中。该文件包含 外部扫描器,这是内置词法分析器的自定义扩展,其目的是处理在 JavaScript 语法中无法(高效)表示的语言结构,例如 Haskell 布局。
WebAssembly
解析器也可以编译成 WebAssembly,这需要 emscripten
$ tree-sitter build --wasm
生成的二进制文件将写入到 $PWD/tree-sitter-haskell.wasm
。
测试解析器
tree-sitter 语法最基本测试基础设施是一组代码片段及其关联的参考 AST,存储在 ./test/corpus/*.txt
中。
$ tree-sitter test
可以通过指定(描述的子串)来运行单个测试 -f
$ tree-sitter test -f 'module: exports empty'
该项目还包含其他几种类型的测试
-
test/parse/run.bash [update] [测试名称 ...]
解析test/parse/*.hs
中的文件,并将输出与test/parse/*.target
进行比较。如果将update
指定为第一个参数,则将更新第一个失败的测试的.target
文件。 -
test/query/run.bash [update] [测试名称 ...]
解析test/query/*.hs
中的文件,应用test/query/*.query
中的查询,并将输出与test/query/*.target
进行比较,类似于test/parse
。 -
test/rust/parse-test.rs
包含一些测试,这些测试使用 tree-sitter 的 Rust API 以稍微方便的方式提取终端的测试范围。这需要安装cargo
,可以用cargo test
(它也会运行bindings/rust
中的测试)来执行。 -
test/parse-libs [wasm]
将一组 Haskell 库克隆到test/libs
,并解析整个代码库。当以test/parse-libs wasm
调用时,它将使用 WebAssembly 解析器。这需要安装bc
。 -
test/parse-lib name [wasm]
仅解析该目录中的库name
(而不克隆存储库)。
调试
tree-sitter test
构建的共享库包含调试符号,所以如果扫描器崩溃,你可以运行 coredumpctl debug
来检查回溯和内存。
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 ()
为了获得更多控制,启动 gdb tree-sitter
并使用 run test -f 'some test'
开始进程,并使用 break tree_sitter_haskell_external_scanner_scan
设置断点。
要禁用优化,运行 tree-sitter test --debug-build
。
跟踪
test
和 parse
命令提供了两种模式来获取关于解析过程的详细信息。
使用 tree-sitter test --debug
,每个词法分析步骤和移位/归约操作都会打印到标准错误。
使用 tree-sitter test --debug-graph
,CLI 将生成一个 HTML 文件,显示每一步的图形表示。这需要已安装 graphviz
。
依赖项
~2.8–4MB
~72K SLoC