Update Nix parser and use the crate from crates.io

pull/816/head
Wilfred Hughes 2025-02-10 08:59:31 +07:00
parent bd9c98050e
commit d42797fa7e
35 changed files with 70 additions and 28473 deletions

@ -19,8 +19,8 @@ effect since 0.46.
File detection now supports Windows-1252 encoded text (an extension of File detection now supports Windows-1252 encoded text (an extension of
ISO-8859-1), and is stricter about UTF-16 detection. ISO-8859-1), and is stricter about UTF-16 detection.
Updated to the latest tree-sitter parser for Elixir, LaTeX, Make, Rust Updated to the latest tree-sitter parser for Elixir, LaTeX, Make, Nix,
and YAML. Rust and YAML.
### Build ### Build

11
Cargo.lock generated

@ -290,6 +290,7 @@ dependencies = [
"tree-sitter-language", "tree-sitter-language",
"tree-sitter-lua", "tree-sitter-lua",
"tree-sitter-make", "tree-sitter-make",
"tree-sitter-nix",
"tree-sitter-objc", "tree-sitter-objc",
"tree-sitter-ocaml", "tree-sitter-ocaml",
"tree-sitter-php", "tree-sitter-php",
@ -1156,6 +1157,16 @@ dependencies = [
"tree-sitter-language", "tree-sitter-language",
] ]
[[package]]
name = "tree-sitter-nix"
version = "0.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a8d4f8705d377d63242a075331d2d8c1dcc9828fd74aa13d7145185b3d9c004"
dependencies = [
"cc",
"tree-sitter-language",
]
[[package]] [[package]]
name = "tree-sitter-objc" name = "tree-sitter-objc"
version = "3.0.2" version = "3.0.2"

@ -100,6 +100,7 @@ tree-sitter-yaml = "0.7.0"
encoding_rs = "0.8.35" encoding_rs = "0.8.35"
tree-sitter-rust = "0.23.2" tree-sitter-rust = "0.23.2"
tree-sitter-elixir = "0.3.4" tree-sitter-elixir = "0.3.4"
tree-sitter-nix = "0.0.2"
[dev-dependencies] [dev-dependencies]
# assert_cmd 2.0.10 requires predicates 3. # assert_cmd 2.0.10 requires predicates 3.

@ -162,11 +162,6 @@ fn main() {
src_dir: "vendored_parsers/tree-sitter-newick-src", src_dir: "vendored_parsers/tree-sitter-newick-src",
extra_files: vec![], extra_files: vec![],
}, },
TreeSitterParser {
name: "tree-sitter-nix",
src_dir: "vendored_parsers/tree-sitter-nix-src",
extra_files: vec!["scanner.c"],
},
TreeSitterParser { TreeSitterParser {
name: "tree-sitter-pascal", name: "tree-sitter-pascal",
src_dir: "vendored_parsers/tree-sitter-pascal-src", src_dir: "vendored_parsers/tree-sitter-pascal-src",

@ -6,57 +6,57 @@ with `difft --list-languages`.
## Programming Languages ## Programming Languages
| Language | Parser Used | | Language | Parser Used |
|-----------------|-------------------------------------------------------------------------------------------------| |-----------------|---------------------------------------------------------------------------------------------------|
| Ada | [briot/tree-sitter-ada](https://github.com/briot/tree-sitter-ada) | | Ada | [briot/tree-sitter-ada](https://github.com/briot/tree-sitter-ada) |
| Apex | [aheber/tree-sitter-sfapex](https://github.com/aheber/tree-sitter-sfapex) | | Apex | [aheber/tree-sitter-sfapex](https://github.com/aheber/tree-sitter-sfapex) |
| Bash | [tree-sitter/tree-sitter-bash](https://github.com/tree-sitter/tree-sitter-bash) | | Bash | [tree-sitter/tree-sitter-bash](https://github.com/tree-sitter/tree-sitter-bash) |
| C | [tree-sitter/tree-sitter-c](https://github.com/tree-sitter/tree-sitter-c) | | C | [tree-sitter/tree-sitter-c](https://github.com/tree-sitter/tree-sitter-c) |
| C++ | [tree-sitter/tree-sitter-cpp](https://github.com/tree-sitter/tree-sitter-cpp) | | C++ | [tree-sitter/tree-sitter-cpp](https://github.com/tree-sitter/tree-sitter-cpp) |
| C# | [tree-sitter/tree-sitter-c-sharp](https://github.com/tree-sitter/tree-sitter-c-sharp) | | C# | [tree-sitter/tree-sitter-c-sharp](https://github.com/tree-sitter/tree-sitter-c-sharp) |
| Clojure | [sogaiu/tree-sitter-clojure](https://github.com/sogaiu/tree-sitter-clojure) | | Clojure | [sogaiu/tree-sitter-clojure](https://github.com/sogaiu/tree-sitter-clojure) |
| CMake | [uyha/tree-sitter-cmake](https://github.com/uyha/tree-sitter-cmake) | | CMake | [uyha/tree-sitter-cmake](https://github.com/uyha/tree-sitter-cmake) |
| Common Lisp | [theHamsta/tree-sitter-commonlisp](https://github.com/theHamsta/tree-sitter-commonlisp) | | Common Lisp | [theHamsta/tree-sitter-commonlisp](https://github.com/theHamsta/tree-sitter-commonlisp) |
| Dart | [UserNobody14/tree-sitter-dart](https://github.com/UserNobody14/tree-sitter-dart) | | Dart | [UserNobody14/tree-sitter-dart](https://github.com/UserNobody14/tree-sitter-dart) |
| Device Tree | [joelspadin/tree-sitter-devicetree](https://github.com/joelspadin/tree-sitter-devicetree) | | Device Tree | [joelspadin/tree-sitter-devicetree](https://github.com/joelspadin/tree-sitter-devicetree) |
| Elixir | [elixir-lang/tree-sitter-elixir](https://github.com/elixir-lang/tree-sitter-elixir) | | Elixir | [elixir-lang/tree-sitter-elixir](https://github.com/elixir-lang/tree-sitter-elixir) |
| Elm | [elm-tooling/tree-sitter-elm](https://github.com/elm-tooling/tree-sitter-elm) | | Elm | [elm-tooling/tree-sitter-elm](https://github.com/elm-tooling/tree-sitter-elm) |
| Elvish | [ckafi/tree-sitter-elvish](https://github.com/ckafi/tree-sitter-elvish) | | Elvish | [ckafi/tree-sitter-elvish](https://github.com/ckafi/tree-sitter-elvish) |
| Erlang | [WhatsApp/tree-sitter-erlang](https://github.com/WhatsApp/tree-sitter-erlang) | | Erlang | [WhatsApp/tree-sitter-erlang](https://github.com/WhatsApp/tree-sitter-erlang) |
| Emacs Lisp | [wilfred/tree-sitter-elisp](https://github.com/Wilfred/tree-sitter-elisp) | | Emacs Lisp | [wilfred/tree-sitter-elisp](https://github.com/Wilfred/tree-sitter-elisp) |
| F# | [ionide/tree-sitter-fsharp](https://github.com/ionide/tree-sitter-fsharp) | | F# | [ionide/tree-sitter-fsharp](https://github.com/ionide/tree-sitter-fsharp) |
| Gleam | [gleam-lang/tree-sitter-gleam](https://github.com/gleam-lang/tree-sitter-gleam) | | Gleam | [gleam-lang/tree-sitter-gleam](https://github.com/gleam-lang/tree-sitter-gleam) |
| Go | [tree-sitter/tree-sitter-go](https://github.com/tree-sitter/tree-sitter-go) | | Go | [tree-sitter/tree-sitter-go](https://github.com/tree-sitter/tree-sitter-go) |
| Hack | [slackhq/tree-sitter-hack](https://github.com/slackhq/tree-sitter-hack) | | Hack | [slackhq/tree-sitter-hack](https://github.com/slackhq/tree-sitter-hack) |
| Hare | [ecmma/tree-sitter-hare](https://git.sr.ht/~ecmma/tree-sitter-hare) | | Hare | [ecmma/tree-sitter-hare](https://git.sr.ht/~ecmma/tree-sitter-hare) |
| Haskell | [tree-sitter/tree-sitter-haskell](https://github.com/tree-sitter/tree-sitter-haskell) | | Haskell | [tree-sitter/tree-sitter-haskell](https://github.com/tree-sitter/tree-sitter-haskell) |
| Janet | [sogaiu/tree-sitter-janet-simple](https://github.com/sogaiu/tree-sitter-janet-simple) | | Janet | [sogaiu/tree-sitter-janet-simple](https://github.com/sogaiu/tree-sitter-janet-simple) |
| Java | [tree-sitter/tree-sitter-java](https://github.com/tree-sitter/tree-sitter-java) | | Java | [tree-sitter/tree-sitter-java](https://github.com/tree-sitter/tree-sitter-java) |
| JavaScript, JSX | [tree-sitter/tree-sitter-javascript](https://github.com/tree-sitter/tree-sitter-javascript) | | JavaScript, JSX | [tree-sitter/tree-sitter-javascript](https://github.com/tree-sitter/tree-sitter-javascript) |
| Julia | [tree-sitter/tree-sitter-julia](https://github.com/tree-sitter/tree-sitter-julia) | | Julia | [tree-sitter/tree-sitter-julia](https://github.com/tree-sitter/tree-sitter-julia) |
| Kotlin | [fwcd/tree-sitter-kotlin](https://github.com/fwcd/tree-sitter-kotlin) | | Kotlin | [fwcd/tree-sitter-kotlin](https://github.com/fwcd/tree-sitter-kotlin) |
| Lua | [tree-sitter-grammars/tree-sitter-lua](https://github.com/tree-sitter-grammars/tree-sitter-lua) | | Lua | [tree-sitter-grammars/tree-sitter-lua](https://github.com/tree-sitter-grammars/tree-sitter-lua) |
| Make | [tree-sitter-grammars/tree-sitter-make](https://github.com/tree-sitter-grammars/tree-sitter-make) | | Make | [tree-sitter-grammars/tree-sitter-make](https://github.com/tree-sitter-grammars/tree-sitter-make) |
| Nix | [cstrahan/tree-sitter-nix](https://github.com/cstrahan/tree-sitter-nix) | | Nix | [nix-community/tree-sitter-nix](https://github.com/nix-community/tree-sitter-nix) |
| Objective-C | [amaanq/tree-sitter-objc](https://github.com/amaanq/tree-sitter-objc) | | Objective-C | [amaanq/tree-sitter-objc](https://github.com/amaanq/tree-sitter-objc) |
| OCaml | [tree-sitter/tree-sitter-ocaml](https://github.com/tree-sitter/tree-sitter-ocaml) | | OCaml | [tree-sitter/tree-sitter-ocaml](https://github.com/tree-sitter/tree-sitter-ocaml) |
| Perl | [ganezdragon/tree-sitter-perl](https://github.com/ganezdragon/tree-sitter-perl) | | Perl | [ganezdragon/tree-sitter-perl](https://github.com/ganezdragon/tree-sitter-perl) |
| PHP | [tree-sitter/tree-sitter-php](https://github.com/tree-sitter/tree-sitter-php) | | PHP | [tree-sitter/tree-sitter-php](https://github.com/tree-sitter/tree-sitter-php) |
| Python | [tree-sitter/tree-sitter-python](https://github.com/tree-sitter/tree-sitter-python) | | Python | [tree-sitter/tree-sitter-python](https://github.com/tree-sitter/tree-sitter-python) |
| QML | [yuja/tree-sitter-qmljs](https://github.com/yuja/tree-sitter-qmljs) | | QML | [yuja/tree-sitter-qmljs](https://github.com/yuja/tree-sitter-qmljs) |
| R | [r-lib/tree-sitter-r](https://github.com/r-lib/tree-sitter-r) | | R | [r-lib/tree-sitter-r](https://github.com/r-lib/tree-sitter-r) |
| Racket | [6cdh/tree-sitter-racket](https://github.com/6cdh/tree-sitter-racket) | | Racket | [6cdh/tree-sitter-racket](https://github.com/6cdh/tree-sitter-racket) |
| Ruby | [tree-sitter/tree-sitter-ruby](https://github.com/tree-sitter/tree-sitter-ruby) | | Ruby | [tree-sitter/tree-sitter-ruby](https://github.com/tree-sitter/tree-sitter-ruby) |
| Rust | [tree-sitter/tree-sitter-rust](https://github.com/tree-sitter/tree-sitter-rust) | | Rust | [tree-sitter/tree-sitter-rust](https://github.com/tree-sitter/tree-sitter-rust) |
| Scala | [tree-sitter/tree-sitter-scala](https://github.com/tree-sitter/tree-sitter-scala) | | Scala | [tree-sitter/tree-sitter-scala](https://github.com/tree-sitter/tree-sitter-scala) |
| Scheme | [6cdh/tree-sitter-scheme](https://github.com/6cdh/tree-sitter-scheme) | | Scheme | [6cdh/tree-sitter-scheme](https://github.com/6cdh/tree-sitter-scheme) |
| Smali | [amaanq/tree-sitter-smali](https://github.com/amaanq/tree-sitter-smali) | | Smali | [amaanq/tree-sitter-smali](https://github.com/amaanq/tree-sitter-smali) |
| Solidity | [JoranHonig/tree-sitter-solidity](https://github.com/JoranHonig/tree-sitter-solidity) | | Solidity | [JoranHonig/tree-sitter-solidity](https://github.com/JoranHonig/tree-sitter-solidity) |
| SQL | [m-novikov/tree-sitter-sql](https://github.com/m-novikov/tree-sitter-sql) | | SQL | [m-novikov/tree-sitter-sql](https://github.com/m-novikov/tree-sitter-sql) |
| Swift | [alex-pinkus/tree-sitter-swift](https://github.com/alex-pinkus/tree-sitter-swift) | | Swift | [alex-pinkus/tree-sitter-swift](https://github.com/alex-pinkus/tree-sitter-swift) |
| TypeScript, TSX | [tree-sitter/tree-sitter-typescript](https://github.com/tree-sitter/tree-sitter-typescript) | | TypeScript, TSX | [tree-sitter/tree-sitter-typescript](https://github.com/tree-sitter/tree-sitter-typescript) |
| VHDL | [JLeemaster/tree-sitter-vhdl](https://github.com/JLeemaster/tree-sitter-vhdl) | | VHDL | [JLeemaster/tree-sitter-vhdl](https://github.com/JLeemaster/tree-sitter-vhdl) |
| Zig | [maxxnino/tree-sitter-zig](https://github.com/maxxnino/tree-sitter-zig) | | Zig | [maxxnino/tree-sitter-zig](https://github.com/maxxnino/tree-sitter-zig) |
## Structured Text Formats ## Structured Text Formats

@ -79,7 +79,6 @@ extern "C" {
fn tree_sitter_kotlin() -> ts::Language; fn tree_sitter_kotlin() -> ts::Language;
fn tree_sitter_latex() -> ts::Language; fn tree_sitter_latex() -> ts::Language;
fn tree_sitter_newick() -> ts::Language; fn tree_sitter_newick() -> ts::Language;
fn tree_sitter_nix() -> ts::Language;
fn tree_sitter_pascal() -> ts::Language; fn tree_sitter_pascal() -> ts::Language;
fn tree_sitter_perl() -> ts::Language; fn tree_sitter_perl() -> ts::Language;
fn tree_sitter_qmljs() -> ts::Language; fn tree_sitter_qmljs() -> ts::Language;
@ -716,18 +715,17 @@ pub(crate) fn from_language(language: guess::Language) -> TreeSitterConfig {
} }
} }
Nix => { Nix => {
let language = unsafe { tree_sitter_nix() }; let language_fn = tree_sitter_nix::LANGUAGE;
let language = tree_sitter::Language::new(language_fn);
TreeSitterConfig { TreeSitterConfig {
language: language.clone(), language: language.clone(),
atom_nodes: ["string_expression", "indented_string_expression"] atom_nodes: ["string_expression", "indented_string_expression"]
.into_iter() .into_iter()
.collect(), .collect(),
delimiter_tokens: vec![("{", "}"), ("[", "]")].into_iter().collect(), delimiter_tokens: vec![("{", "}"), ("[", "]")].into_iter().collect(),
highlight_query: ts::Query::new( highlight_query: ts::Query::new(&language, tree_sitter_nix::HIGHLIGHTS_QUERY)
&language, .unwrap(),
include_str!("../../vendored_parsers/highlights/nix.scm"),
)
.unwrap(),
sub_languages: vec![], sub_languages: vec![],
} }
} }

@ -1 +0,0 @@
../tree-sitter-nix/queries/highlights.scm

@ -1 +0,0 @@
tree-sitter-nix/src

@ -1,18 +0,0 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = false
# for testing purposes, the corpus may have trailing whitespace
# and may have mixed EOL.
# Still want a final newline though, as that makes no semantic difference.
[corpus/*]
trim_trailing_whitespace = false
end_of_line = unset
[**.{js,json,cc,css}]
indent_style = space
indent_size = 2

@ -1,2 +0,0 @@
/src/** linguist-vendored
/src/scanner.cc linguist-vendored=false

@ -1,33 +0,0 @@
name: build
on:
workflow_dispatch:
pull_request:
push:
jobs:
build:
name: build
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Setup Node
uses: actions/setup-node@v2-beta
with:
node-version: '16'
- name: Display Node versions
run: |
node --version
npm --version
- name: Install dependencies
run: npm install
- name: Check generated parser is checked in
run: npm run generate && git diff --exit-code src
- name: Test corpus
run: npm test

@ -1,3 +0,0 @@
build
node_modules
Cargo.lock

@ -1,21 +0,0 @@
language: node_js
sudo: false
node_js:
- node
os:
- linux
matrix:
include:
- os: osx
osx_image: xcode9.2
- os: linux
env: CXX=clang++
branches:
only:
- master
- /^v.*$/

@ -1,26 +0,0 @@
[package]
name = "tree-sitter-nix"
description = "nix grammar for the tree-sitter parsing library"
version = "0.0.1"
keywords = ["incremental", "parsing", "nix"]
categories = ["parsing", "text-editors"]
repository = "https://github.com/cstrahan/tree-sitter-nix"
edition = "2018"
license = "MIT"
build = "bindings/rust/build.rs"
include = [
"bindings/rust/*",
"grammar.js",
"queries/*",
"src/*",
]
[lib]
path = "bindings/rust/lib.rs"
[dependencies]
tree-sitter = "0.20"
[build-dependencies]
cc = "1.0"

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2019 Charles Strahan
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.

@ -1,7 +0,0 @@
tree-sitter-nix
================
[![Build Status](https://travis-ci.org/cstrahan/tree-sitter-nix.svg?branch=master)](https://travis-ci.org/cstrahan/tree-sitter-nix)
[![Build Status](https://github.com/cstrahan/tree-sitter-nix/workflows/build/badge.svg)](https://github.com/cstrahan/tree-sitter-nix/actions?query=workflow%3Abuild)
Nix grammar for [tree-sitter](https://github.com/tree-sitter/tree-sitter).

@ -1,19 +0,0 @@
{
"targets": [
{
"target_name": "tree_sitter_nix_binding",
"include_dirs": [
"<!(node -e \"require('nan')\")",
"src"
],
"sources": [
"src/parser.c",
"bindings/node/binding.cc",
"src/scanner.c"
],
"cflags_c": [
"-std=c99",
]
}
]
}

@ -1,28 +0,0 @@
#include "tree_sitter/parser.h"
#include <node.h>
#include "nan.h"
using namespace v8;
extern "C" TSLanguage * tree_sitter_nix();
namespace {
NAN_METHOD(New) {}
void Init(Local<Object> exports, Local<Object> module) {
Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
tpl->SetClassName(Nan::New("Language").ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);
Local<Function> constructor = Nan::GetFunction(tpl).ToLocalChecked();
Local<Object> instance = constructor->NewInstance(Nan::GetCurrentContext()).ToLocalChecked();
Nan::SetInternalFieldPointer(instance, 0, tree_sitter_nix());
Nan::Set(instance, Nan::New("name").ToLocalChecked(), Nan::New("nix").ToLocalChecked());
Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance);
}
NODE_MODULE(tree_sitter_nix_binding, Init)
} // namespace

@ -1,19 +0,0 @@
try {
module.exports = require("../../build/Release/tree_sitter_nix_binding");
} catch (error1) {
if (error1.code !== 'MODULE_NOT_FOUND') {
throw error1;
}
try {
module.exports = require("../../build/Debug/tree_sitter_nix_binding");
} catch (error2) {
if (error2.code !== 'MODULE_NOT_FOUND') {
throw error2;
}
throw error1
}
}
try {
module.exports.nodeTypeInfo = require("../../src/node-types.json");
} catch (_) {}

@ -1,38 +0,0 @@
fn main() {
let src_dir = std::path::Path::new("src");
let mut c_config = cc::Build::new();
c_config.include(&src_dir);
c_config
.flag_if_supported("-Wno-unused-parameter")
.flag_if_supported("-Wno-unused-but-set-variable")
.flag_if_supported("-Wno-trigraphs");
let parser_path = src_dir.join("parser.c");
c_config.file(&parser_path);
// If your language uses an external scanner written in C,
// then include this block of code:
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("parser");
println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap());
// If your language uses an external scanner written in C++,
// then include this block of code:
/*
let mut cpp_config = cc::Build::new();
cpp_config.cpp(true);
cpp_config.include(&src_dir);
cpp_config
.flag_if_supported("-Wno-unused-parameter")
.flag_if_supported("-Wno-unused-but-set-variable");
let scanner_path = src_dir.join("scanner.cc");
cpp_config.file(&scanner_path);
cpp_config.compile("scanner");
println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap());
*/
}

@ -1,52 +0,0 @@
//! This crate provides nix 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:
//!
//! ```
//! let code = "";
//! let mut parser = tree_sitter::Parser::new();
//! parser.set_language(tree_sitter_nix::language()).expect("Error loading nix grammar");
//! let tree = parser.parse(code, None).unwrap();
//! ```
//!
//! [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;
extern "C" {
fn tree_sitter_nix() -> Language;
}
/// Get the tree-sitter [Language][] for this grammar.
///
/// [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html
pub fn language() -> Language {
unsafe { tree_sitter_nix() }
}
/// 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: &'static str = include_str!("../../src/node-types.json");
// Uncomment these to include any queries that this grammar contains
// pub const HIGHLIGHTS_QUERY: &'static str = include_str!("../../queries/highlights.scm");
// pub const INJECTIONS_QUERY: &'static str = include_str!("../../queries/injections.scm");
// pub const LOCALS_QUERY: &'static str = include_str!("../../queries/locals.scm");
// pub const TAGS_QUERY: &'static str = include_str!("../../queries/tags.scm");
#[cfg(test)]
mod tests {
#[test]
fn test_can_load_grammar() {
let mut parser = tree_sitter::Parser::new();
parser
.set_language(super::language())
.expect("Error loading nix language");
}
}

@ -1,528 +0,0 @@
====================
empty source
====================
---
(source_code)
====================
comments
====================
# This is a comment.
/*
This is also a comment.
*/
/*This as well, even with two asterisks.**/
"This is a string."
---
(source_code (comment) (comment) (comment) (string_expression (string_fragment)))
====================
identifier
====================
abc
---
(source_code (variable_expression (identifier)))
====================
integer_expression
====================
123
---
(source_code (integer_expression))
====================
float_expression
====================
123.456
---
(source_code (float_expression))
====================
uri
====================
http://foobar.com:80?baz=quux&blarg=etc
---
(source_code (uri_expression))
====================
list (empty)
====================
[ ]
---
(source_code (list_expression))
====================
list
====================
[ a 1 2.0 ]
---
(source_code (list_expression (variable_expression (identifier)) (integer_expression) (float_expression)))
====================
if
====================
if a then b else c
---
(source_code (if_expression (variable_expression (identifier)) (variable_expression (identifier)) (variable_expression (identifier))))
====================
assert
====================
assert a; b
---
(source_code (assert_expression (variable_expression (identifier)) (variable_expression (identifier))))
====================
with
====================
with a; b
---
(source_code (with_expression (variable_expression (identifier)) (variable_expression (identifier))))
====================
let (empty)
====================
let in a
---
(source_code (let_expression (variable_expression (identifier))))
====================
let (binding)
====================
let a = b; in c
---
(source_code
(let_expression
(binding_set
(binding
(attrpath (identifier))
(variable_expression (identifier))))
(variable_expression (identifier))))
====================
let (binding, comments)
====================
let
# foo
a = b;
# bar
x = y;
in
# baz
c
---
(source_code
(let_expression
(comment)
(binding_set
(binding (attrpath (identifier)) (variable_expression (identifier)))
(comment)
(binding (attrpath (identifier)) (variable_expression (identifier))))
(comment)
(variable_expression (identifier))))
====================
let (inherit)
====================
let inherit a; in c
---
(source_code
(let_expression
(binding_set
(inherit
(inherited_attrs
(identifier))))
(variable_expression (identifier))))
====================
let (inherit from)
====================
let inherit (a) b "c" ${d}; in 123
---
(source_code
(let_expression
(binding_set
(inherit_from
(variable_expression (identifier))
(inherited_attrs
(identifier) (string_expression (string_fragment)) (interpolation (variable_expression (identifier))))))
(integer_expression)))
====================
function_expression
====================
a: b
---
(source_code (function_expression (identifier) (variable_expression (identifier))))
====================
function_expression (with_expression formals)
====================
a@{ /*1*/ b, /*2*/ c ? 123, /*3*/ ... }: 1.234
---
(source_code
(function_expression
(identifier)
(formals
(comment)
(formal (identifier))
(comment)
(formal (identifier) (integer_expression))
(comment)
(ellipses))
(float_expression)))
====================
rec. attrset (empty)
====================
rec { }
---
(source_code (rec_attrset_expression))
====================
let attrset (empty)
====================
let { }
---
(source_code (let_attrset_expression))
====================
attrset (empty)
====================
{ }
---
(source_code (attrset_expression))
====================
attr set
====================
{ a = 1; ${b} = "quux"; "c" = 3.14; x.y.z = <foo>; }
---
(source_code
(attrset_expression
(binding_set
(binding (attrpath (identifier)) (integer_expression))
(binding (attrpath (interpolation (variable_expression (identifier)))) (string_expression (string_fragment)))
(binding (attrpath (string_expression (string_fragment))) (float_expression))
(binding (attrpath (identifier) (identifier) (identifier)) (spath_expression)))))
====================
select_expression
====================
u.v.${w}."x${y}z"
---
(source_code
(select_expression
(variable_expression (identifier))
(attrpath
(identifier)
(interpolation (variable_expression (identifier)))
(string_expression
(string_fragment)
(interpolation (variable_expression (identifier)))
(string_fragment)))))
====================
hasAttr operator
====================
a ? ${b}.c."d"
---
(source_code
(has_attr_expression
(variable_expression (identifier))
(attrpath
(interpolation (variable_expression (identifier)))
(identifier)
(string_expression (string_fragment)))))
====================
apply_expressionlication
====================
a 1 2.0
---
(source_code
(apply_expression
(apply_expression
(variable_expression (identifier))
(integer_expression))
(float_expression)))
====================
path_expression test
====================
a/c${x}c
---
(source_code
(path_expression
(path_fragment)
(interpolation
(variable_expression (identifier)))
(path_fragment)))
====================
path_expression1
====================
x/a${x}a.a${123}
---
(source_code
(path_expression
(path_fragment)
(interpolation
(variable_expression (identifier)))
(path_fragment)
(interpolation
(integer_expression))))
====================
path_expression2
====================
x/a${x}a/a${123}
---
(source_code
(path_expression
(path_fragment)
(interpolation
(variable_expression (identifier)))
(path_fragment)
(interpolation
(integer_expression))))
====================
path_expression3
====================
/abc
---
(source_code
(path_expression
(path_fragment)))
====================
path_expression4
====================
-123/abc
---
(source_code
(path_expression
(path_fragment)))
====================
path_expression5
====================
dir/${name}.${extension}
---
(source_code
(path_expression
(path_fragment)
(interpolation
(variable_expression (identifier)))
(path_fragment)
(interpolation
(variable_expression (identifier)))))
====================
path_expression6
====================
a/b${c} d/e${f}
---
(source_code
(apply_expression
(path_expression
(path_fragment)
(interpolation
(variable_expression (identifier))))
(path_expression
(path_fragment)
(interpolation
(variable_expression (identifier))))))
====================
hpath_expression1
====================
~/.
---
(source_code
(hpath_expression
(path_fragment)))
====================
hpath_expression2
====================
~/a${x}a/a${123}
---
(source_code
(hpath_expression
(path_fragment)
(interpolation
(variable_expression (identifier)))
(path_fragment)
(interpolation
(integer_expression))))
====================
division not mistaken for path_expressions (1)
====================
a/ b
---
(source_code
(binary_expression
(variable_expression (identifier))
(variable_expression (identifier))))
====================
path_expression craziness - see https://github.com/NixOS/nix/pull/5066#issuecomment-1071918251
====================
a.${foo}/b.${bar}
---
(source_code
(apply_expression
(select_expression
(variable_expression (identifier))
(attrpath
(interpolation
(variable_expression (identifier)))))
(path_expression
(path_fragment)
(interpolation
(variable_expression (identifier))))))
====================
operators
====================
square 2 + -pi - 42.0
---
(source_code
(binary_expression
(binary_expression
(apply_expression (variable_expression (identifier)) (integer_expression))
(unary_expression (variable_expression (identifier))))
(float_expression)))
====================
parens
====================
(123)
---
(source_code
(parenthesized_expression (integer_expression)))

@ -1,268 +0,0 @@
================================================================================
attrset typing field
================================================================================
{
a = "foo";
b = 42;
typing
c = {};
d = x: x;
}
--------------------------------------------------------------------------------
(source_code
(attrset_expression
(binding_set
(binding
(attrpath
(identifier))
(string_expression (string_fragment)))
(binding
(attrpath
(identifier))
(integer_expression))
(binding
(attrpath
(identifier))
(ERROR
(identifier))
(attrset_expression))
(binding
(attrpath
(identifier))
(function_expression
(identifier)
(variable_expression (identifier)))))))
================================================================================
attrset typing field following string
================================================================================
{
typing
inputs.nixpkgs.url = "github:nixos/nixpkgs";
inputs.nixpkgs-21-05.url = "github:nixos/nixpkgs/nixos-21.05";
}
--------------------------------------------------------------------------------
(source_code
(attrset_expression
(ERROR
(identifier))
(binding_set
(binding
(attrpath
(identifier)
(identifier)
(identifier))
(string_expression (string_fragment)))
(binding
(attrpath
(identifier)
(identifier)
(identifier))
(string_expression (string_fragment))))))
================================================================================
attrset typing attrpath
================================================================================
{
a = "foo";
b = 42;
typing.path_expression
c = {};
d = x: x;
}
--------------------------------------------------------------------------------
(source_code
(attrset_expression
(binding_set
(binding
(attrpath
(identifier))
(string_expression (string_fragment)))
(binding
(attrpath
(identifier))
(integer_expression))
(binding
(attrpath
(identifier)
(identifier))
(ERROR
(identifier))
(attrset_expression))
(binding
(attrpath
(identifier))
(function_expression
(identifier)
(variable_expression (identifier)))))))
================================================================================
attrset missing value
================================================================================
{
a = "foo";
b = 42;
typing =
c = {};
d = x: x;
}
--------------------------------------------------------------------------------
(source_code
(attrset_expression
(binding_set
(binding
(attrpath
(identifier))
(string_expression (string_fragment)))
(binding
(attrpath
(identifier))
(integer_expression))
(binding
(attrpath
(identifier))
(apply_expression
(variable_expression (identifier))
(ERROR)
(attrset_expression)))
(binding
(attrpath
(identifier))
(function_expression
(identifier)
(variable_expression (identifier)))))))
================================================================================
bind typing parenthesis
================================================================================
{
a = "foo";
b = a: 42;
typing = (a:
c = {};
d = x: x;
}
--------------------------------------------------------------------------------
(source_code
(attrset_expression
(binding_set
(binding
(attrpath
(identifier))
(string_expression (string_fragment)))
(binding
(attrpath
(identifier))
(function_expression
(identifier)
(integer_expression)))
(binding
(attrpath
(identifier))
(ERROR
(function_expression
(identifier)
(variable_expression (identifier))))
(attrset_expression))
(binding
(attrpath
(identifier))
(function_expression
(identifier)
(variable_expression (identifier)))))))
================================================================================
let typing field
================================================================================
let
a = "foo";
b = 42;
typing
c = {};
d = x: x;
in {}
--------------------------------------------------------------------------------
(source_code
(let_expression
(binding_set
(binding
(attrpath
(identifier))
(string_expression (string_fragment)))
(binding
(attrpath
(identifier))
(integer_expression))
(binding
(attrpath
(identifier))
(ERROR
(identifier))
(attrset_expression))
(binding
(attrpath
(identifier))
(function_expression
(identifier)
(variable_expression (identifier)))))
(attrset_expression)))
================================================================================
let missing value
================================================================================
let
a = "foo";
b = 42;
typing =
c = {};
d = x: x;
in
a
--------------------------------------------------------------------------------
(source_code
(let_expression
(binding_set
(binding
(attrpath
(identifier))
(string_expression (string_fragment)))
(binding
(attrpath
(identifier))
(integer_expression))
(binding
(attrpath
(identifier))
(apply_expression
(variable_expression (identifier))
(ERROR)
(attrset_expression)))
(binding
(attrpath
(identifier))
(function_expression
(identifier)
(variable_expression (identifier)))))
(variable_expression (identifier))))

@ -1,168 +0,0 @@
================================================================================
string
================================================================================
"abcdef"
--------------------------------------------------------------------------------
(source_code
(string_expression (string_fragment)))
================================================================================
string (complex)
================================================================================
"
${bob} likes crisp $ bills. escape newline \
\${don't interpolate here!}"
--------------------------------------------------------------------------------
(source_code
(string_expression
(string_fragment)
(interpolation
(variable_expression (identifier)))
(string_fragment)
(escape_sequence)
(escape_sequence)
(string_fragment)))
================================================================================
indented string
================================================================================
''
abc
def
ghi
''
--------------------------------------------------------------------------------
(source_code
(indented_string_expression (string_fragment)))
================================================================================
indented string (complex)
================================================================================
''
This is just a couple of quotes: '''
A lone $ doesn't throw things off.
And of course, ''\${this shouldn't be an interpolation}.
But ${this} is.
This works, too: ''$
''
--------------------------------------------------------------------------------
(source_code
(indented_string_expression
(string_fragment)
(escape_sequence)
(string_fragment)
(escape_sequence)
(string_fragment)
(interpolation
(variable_expression (identifier)))
(string_fragment)
(escape_sequence)
(string_fragment)))
================================================================================
string ($)
================================================================================
[
"$"
"$\n"
"${x}"
"$${x}"
"$$${x}"
"$$$${x}"
]
--------------------------------------------------------------------------------
(source_code
(list_expression
(string_expression (string_fragment))
(string_expression
(string_fragment)
(escape_sequence))
(string_expression
(interpolation
(variable_expression (identifier))))
(string_expression (string_fragment))
(string_expression
(string_fragment)
(interpolation
(variable_expression (identifier))))
(string_expression (string_fragment))))
================================================================================
indented string ($)
================================================================================
[
''$''
''$''\n''
''${x}''
''$${x}''
''$$${x}''
''$$$${x}''
]
--------------------------------------------------------------------------------
(source_code
(list_expression
(indented_string_expression (string_fragment))
(indented_string_expression
(string_fragment)
(escape_sequence))
(indented_string_expression
(interpolation
(variable_expression (identifier))))
(indented_string_expression (string_fragment))
(indented_string_expression
(string_fragment)
(interpolation
(variable_expression (identifier))))
(indented_string_expression (string_fragment))))
================================================================================
unterminated string
================================================================================
"foo ${bar} \n
--------------------------------------------------------------------------------
(source_code
(string_expression
(string_fragment)
(interpolation
(variable_expression (identifier)))
(string_fragment)
(escape_sequence)
(MISSING """)))
================================================================================
unterminated string escape
================================================================================
"foo ${bar} \n \
--------------------------------------------------------------------------------
(source_code
(ERROR
(string_fragment)
(interpolation
(variable_expression (identifier)))
(string_fragment)
(escape_sequence)
(string_fragment)
(UNEXPECTED '\0')))

@ -1,299 +0,0 @@
const PREC = {
impl: 1,
or: 2,
and: 3,
eq: 4,
neq: 4,
'<': 5,
'>': 5,
leq: 5,
geq: 5,
update: 6,
not: 7,
'+': 8,
'-': 8,
'*': 9,
'/': 9,
concat: 10,
'?': 11,
negate: 12
}
module.exports = grammar({
name: 'nix',
extras: $ => [
/\s/,
$.comment,
],
supertypes: $ => [
$._expression
],
inline: $ => [
],
externals: $ => [
$.string_fragment,
$._indented_string_fragment,
$._path_start,
$.path_fragment,
],
word: $ => $.keyword,
conflicts: $ => [
],
rules: {
source_code: $ => optional(field('expression', $._expression)),
_expression: $ => $._expr_function_expression,
// Keywords go before identifiers to let them take precedence when both are expected.
// Workaround before https://github.com/tree-sitter/tree-sitter/pull/246
keyword: $ => /if|then|else|let|inherit|in|rec|with|assert/,
identifier: $ => /[a-zA-Z_][a-zA-Z0-9_\'\-]*/,
variable_expression: $ => field('name', $.identifier),
integer_expression: $ => /[0-9]+/,
float_expression: $ => /(([1-9][0-9]*\.[0-9]*)|(0?\.[0-9]+))([Ee][+-]?[0-9]+)?/,
path_expression: $=> seq(
alias($._path_start, $.path_fragment),
repeat(
choice(
$.path_fragment,
alias($._immediate_interpolation, $.interpolation),
)
),
),
_hpath_start: $ => /\~\/[a-zA-Z0-9\._\-\+\/]+/,
hpath_expression: $=> seq(
alias($._hpath_start, $.path_fragment),
repeat(
choice(
$.path_fragment,
alias($._immediate_interpolation, $.interpolation),
)
),
),
spath_expression: $ => /<[a-zA-Z0-9\._\-\+]+(\/[a-zA-Z0-9\._\-\+]+)*>/,
uri_expression: $ => /[a-zA-Z][a-zA-Z0-9\+\-\.]*:[a-zA-Z0-9%\/\?:@\&=\+\$,\-_\.\!\~\*\']+/,
_expr_function_expression: $ => choice(
$.function_expression,
$.assert_expression,
$.with_expression,
$.let_expression,
$._expr_if
),
function_expression: $ => choice(
seq(field('universal', $.identifier), ':', field('body', $._expr_function_expression)),
seq(field('formals', $.formals), ":", field('body', $._expr_function_expression)),
seq(field('formals', $.formals), '@', field('universal', $.identifier), ':', field('body', $._expr_function_expression)),
seq(field('universal', $.identifier), '@', field('formals', $.formals), ':', field('body', $._expr_function_expression)),
),
formals: $ => choice(
seq('{', '}'),
seq('{', commaSep1(field('formal', $.formal)), '}'),
seq('{', commaSep1(field('formal', $.formal)), ',', field('ellipses', $.ellipses), '}'),
seq('{', field('ellipses', $.ellipses), '}'),
),
formal: $ => seq(field("name", $.identifier), optional(seq('?', field('default', $._expression)))),
ellipses: $ => '...',
assert_expression: $ => seq('assert', field('condition', $._expression), ';', field('body', $._expr_function_expression)),
with_expression: $ => seq('with', field('environment', $._expression), ';', field('body', $._expr_function_expression)),
let_expression: $ => seq('let', optional($.binding_set), 'in', field('body', $._expr_function_expression)),
_expr_if: $ => choice(
$.if_expression,
$._expr_op
),
if_expression: $ => seq('if', field('condition', $._expression), 'then', field('consequence', $._expression), 'else', field('alternative', $._expression)),
_expr_op: $ => choice(
$.has_attr_expression,
$.unary_expression,
$.binary_expression,
$._expr_apply_expression
),
// I choose to *not* have this among the binary operators because
// this is the sole exception that takes an attrpath (instead of expression)
// as its right operand.
// My gut feeling is that this is:
// 1) better in theory, and
// 2) will be easier to work with in practice.
has_attr_expression: $ => prec(PREC['?'],
seq(
field('expression', $._expr_op),
field('operator', '?'),
field('attrpath', $.attrpath)
)
),
unary_expression: $ => choice(
...[
['!', PREC.not],
['-', PREC.negate],
].map(([operator, precedence]) =>
prec(precedence, seq(
field('operator', operator),
field('argument', $._expr_op)
))
)
),
binary_expression: $ => choice(
// left assoc.
...[
['==', PREC.eq],
['!=', PREC.neq],
['<', PREC['<']],
['<=', PREC.leq],
['>', PREC['>']],
['>=', PREC.geq],
['&&', PREC.and],
['||', PREC.or],
['+', PREC['+']],
['-', PREC['-']],
['*', PREC['*']],
['/', PREC['/']],
].map(([operator, precedence]) =>
prec.left(precedence, seq(
field('left', $._expr_op),
field('operator', operator),
field('right', $._expr_op)
))),
// right assoc.
...[
['->', PREC.impl],
['//', PREC.update],
['++', PREC.concat],
].map(([operator, precedence]) =>
prec.right(precedence, seq(
field('left', $._expr_op),
field('operator', operator),
field('right', $._expr_op)
)))
),
_expr_apply_expression: $ => choice(
$.apply_expression,
$._expr_select_expression
),
apply_expression: $ => seq(field('function', $._expr_apply_expression), field('argument', $._expr_select_expression)),
_expr_select_expression: $ => choice(
$.select_expression,
$._expr_simple
),
select_expression: $ => choice(
seq(field('expression', $._expr_simple), '.', field('attrpath', $.attrpath)),
seq(field('expression', $._expr_simple), '.', field('attrpath', $.attrpath), 'or', field('default', $._expr_select_expression)),
),
_expr_simple: $ => choice(
$.variable_expression,
$.integer_expression,
$.float_expression,
$.string_expression,
$.indented_string_expression,
$.path_expression,
$.hpath_expression,
$.spath_expression,
$.uri_expression,
$.parenthesized_expression,
$.attrset_expression,
$.let_attrset_expression,
$.rec_attrset_expression,
$.list_expression
),
parenthesized_expression: $ => seq('(', field('expression', $._expression), ')'),
attrset_expression: $ => seq('{', optional($.binding_set), '}'),
let_attrset_expression: $ => seq('let', '{', optional($.binding_set), '}'),
rec_attrset_expression: $ => seq('rec', '{', optional($.binding_set), '}'),
string_expression: $ => seq(
'"',
repeat(choice(
$.string_fragment,
$.interpolation,
$.escape_sequence
)),
'"'
),
escape_sequence: $ => token.immediate(/\\(.|\s)/), // Can also escape newline.
indented_string_expression: $ => seq(
"''",
repeat(choice(
alias($._indented_string_fragment, $.string_fragment),
$.interpolation,
alias($._indented_escape_sequence, $.escape_sequence),
)),
"''"
),
_indented_escape_sequence: $ => token.immediate(/'''|''\$|''\\(.|\s)/), // Can also escape newline.
binding_set: $ => repeat1(field('binding', choice($.binding, $.inherit, $.inherit_from))),
binding: $ => seq(field('attrpath', $.attrpath), '=', field('expression', $._expression), ';'),
inherit: $ => seq('inherit', field('attrs', $.inherited_attrs), ';'),
inherit_from: $ =>
seq('inherit', '(', field('expression', $._expression), ')', field('attrs', $.inherited_attrs), ';'),
attrpath: $ => sep1(field('attr', choice(
$.identifier,
$.string_expression,
$.interpolation,
)), "."),
inherited_attrs: $ => repeat1(field('attr', choice(
$.identifier,
$.string_expression,
$.interpolation,
))),
_immediate_interpolation: $ => seq(token.immediate('${'), field('expression', $._expression), '}'),
interpolation: $ => seq('${', field('expression', $._expression), '}'),
list_expression: $ => seq('[', repeat(field('element', $._expr_select_expression)), ']'),
comment: $ => token(choice(
seq('#', /.*/),
seq(
'/*',
/[^*]*\*+([^/*][^*]*\*+)*/,
'/'
)
)),
},
});
function sep(rule, separator) {
return optional(sep1(rule, separator));
}
function sep1(rule, separator) {
return seq(rule, repeat(seq(separator, rule)));
}
function commaSep1(rule) {
return sep1(rule, ',');
}
function commaSep(rule) {
return optional(commaSep1(rule));
}

@ -1,47 +0,0 @@
{
"name": "tree-sitter-nix",
"version": "0.0.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "tree-sitter-nix",
"version": "0.0.2",
"license": "MIT",
"dependencies": {
"nan": "^2.14.2"
},
"devDependencies": {
"tree-sitter-cli": "^0.20.0"
}
},
"node_modules/nan": {
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz",
"integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ=="
},
"node_modules/tree-sitter-cli": {
"version": "0.20.6",
"resolved": "https://registry.npmjs.org/tree-sitter-cli/-/tree-sitter-cli-0.20.6.tgz",
"integrity": "sha512-tjbAeuGSMhco/EnsThjWkQbDIYMDmdkWsTPsa/NJAW7bjaki9P7oM9TkLxfdlnm4LXd1wR5wVSM2/RTLtZbm6A==",
"dev": true,
"hasInstallScript": true,
"bin": {
"tree-sitter": "cli.js"
}
}
},
"dependencies": {
"nan": {
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz",
"integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ=="
},
"tree-sitter-cli": {
"version": "0.20.6",
"resolved": "https://registry.npmjs.org/tree-sitter-cli/-/tree-sitter-cli-0.20.6.tgz",
"integrity": "sha512-tjbAeuGSMhco/EnsThjWkQbDIYMDmdkWsTPsa/NJAW7bjaki9P7oM9TkLxfdlnm4LXd1wR5wVSM2/RTLtZbm6A==",
"dev": true
}
}
}

@ -1,41 +0,0 @@
{
"name": "tree-sitter-nix",
"version": "0.0.2",
"description": "Tree Sitter grammar for Nix",
"main": "bindings/node",
"scripts": {
"generate": "tree-sitter generate",
"test": "tree-sitter test"
},
"repository": {
"type": "git",
"url": "git+https://github.com/cstrahan/tree-sitter-nix.git"
},
"author": "Charles Strahan",
"license": "MIT",
"bugs": {
"url": "https://github.com/cstrahan/tree-sitter-nix/issues"
},
"homepage": "https://github.com/cstrahan/tree-sitter-nix#readme",
"dependencies": {
"nan": "^2.14.2"
},
"devDependencies": {
"tree-sitter-cli": "^0.20.6"
},
"tree-sitter": [
{
"file-types": [
"nix"
],
"highlights": [
"queries/highlights.scm"
],
"injection-regex": "^(nix)$",
"locals": [
"queries/locals.scm"
],
"scope": "source.nix"
}
]
}

@ -1,97 +0,0 @@
(comment) @comment
[
"if"
"then"
"else"
"let"
"inherit"
"in"
"rec"
"with"
"assert"
"or"
] @keyword
((identifier) @variable.builtin
(#match? @variable.builtin "^(__currentSystem|__currentTime|__nixPath|__nixVersion|__storeDir|builtins|false|null|true)$")
(#is-not? local))
((identifier) @function.builtin
(#match? @function.builtin "^(__add|__addErrorContext|__all|__any|__appendContext|__attrNames|__attrValues|__bitAnd|__bitOr|__bitXor|__catAttrs|__compareVersions|__concatLists|__concatMap|__concatStringsSep|__deepSeq|__div|__elem|__elemAt|__fetchurl|__filter|__filterSource|__findFile|__foldl'|__fromJSON|__functionArgs|__genList|__genericClosure|__getAttr|__getContext|__getEnv|__hasAttr|__hasContext|__hashFile|__hashString|__head|__intersectAttrs|__isAttrs|__isBool|__isFloat|__isFunction|__isInt|__isList|__isPath|__isString|__langVersion|__length|__lessThan|__listToAttrs|__mapAttrs|__match|__mul|__parseDrvName|__partition|__path|__pathExists|__readDir|__readFile|__replaceStrings|__seq|__sort|__split|__splitVersion|__storePath|__stringLength|__sub|__substring|__tail|__toFile|__toJSON|__toPath|__toXML|__trace|__tryEval|__typeOf|__unsafeDiscardOutputDependency|__unsafeDiscardStringContext|__unsafeGetAttrPos|__valueSize|abort|baseNameOf|derivation|derivationStrict|dirOf|fetchGit|fetchMercurial|fetchTarball|fromTOML|import|isNull|map|placeholder|removeAttrs|scopedImport|throw|toString)$")
(#is-not? local))
[
(string_expression)
(indented_string_expression)
] @string
[
(path_expression)
(hpath_expression)
(spath_expression)
] @string.special.path
(uri_expression) @string.special.uri
[
(integer_expression)
(float_expression)
] @number
(interpolation
"${" @punctuation.special
"}" @punctuation.special) @embedded
(escape_sequence) @escape
(function_expression
universal: (identifier) @variable.parameter
)
(formal
name: (identifier) @variable.parameter
"?"? @punctuation.delimiter)
(select_expression
attrpath: (attrpath (identifier)) @property)
(apply_expression
function: [
(variable_expression (identifier)) @function
(select_expression
attrpath: (attrpath
attr: (identifier) @function .))])
(unary_expression
operator: _ @operator)
(binary_expression
operator: _ @operator)
(variable_expression (identifier) @variable)
(binding
attrpath: (attrpath (identifier)) @property)
(identifier) @property
(inherit_from attrs: (inherited_attrs attr: (identifier) @property) )
[
";"
"."
","
"="
] @punctuation.delimiter
[
"("
")"
"["
"]"
"{"
"}"
] @punctuation.bracket
(identifier) @variable

@ -1,33 +0,0 @@
;; when using @local.reference, tree-sitter seems to
;; apply the scope from the identifier it has looked up,
;; which makes sense for most languages.
;; however, we want to highlight things as function based on their call-site,
;; not their definition; therefore using TS's support for tracking locals
;; impedes our ability to get the highlighting we want.
;;
;; also, TS doesn't seem to support scoping as implemented in languages
;; with lazy let bindings, which results in syntax highlighting/goto-reference
;; results that depend on the order of definitions, which is counter to the
;; semantics of Nix.
;;
;; so for now we'll opt for not having any locals queries.
;;
;; see: https://github.com/tree-sitter/tree-sitter/issues/918
;(function_expression
; universal: (identifier)? @local.definition
; formals: (formals (formal name: (identifier) @local.definition)*)
; universal: (identifier)? @local.definition
; ) @local.scope
;
;(rec_attrset_expression
; bind: (binding
; attrpath: (attrpath . (attr_identifier) @local.definition))
;) @local.scope
;
;(let_expression
; bind: (binding
; attrpath: (attrpath . (attr_identifier) @local.definition))
;) @local.scope
;
;(identifier) @local.reference

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,192 +0,0 @@
#include <tree_sitter/parser.h>
enum TokenType {
STRING_FRAGMENT,
INDENTED_STRING_FRAGMENT,
PATH_START,
PATH_FRAGMENT,
};
static void advance(TSLexer *lexer) {
lexer->advance(lexer, false);
}
static void skip(TSLexer *lexer) {
lexer->advance(lexer, true);
}
// Here we only parse literal fragment inside a string.
// Delimiter, interpolation and escape sequence are handled by the parser and we simply stop at them.
//
// The implementation is inspired by tree-sitter-javascript:
// https://github.com/tree-sitter/tree-sitter-javascript/blob/fdeb68ac8d2bd5a78b943528bb68ceda3aade2eb/src/scanner.c#L19
static bool scan_string_fragment(TSLexer *lexer) {
lexer->result_symbol = STRING_FRAGMENT;
for (bool has_content = false;; has_content = true) {
lexer->mark_end(lexer);
switch (lexer->lookahead) {
case '"':
case '\\':
return has_content;
case '$':
advance(lexer);
if (lexer->lookahead == '{') {
return has_content;
} else if (lexer->lookahead != '"' && lexer->lookahead != '\\') {
// Any char following '$' other than '"', '\\' and '{' (which was handled above)
// should be consumed as additional string content.
// This means `$${` doesn't start an interpolation, but `$$${` does.
advance(lexer);
}
break;
// Simply give up on EOF or '\0'.
case '\0':
return false;
default:
advance(lexer);
}
}
}
// See comments of scan_string_fragment.
static bool scan_indented_string_fragment(TSLexer *lexer) {
lexer->result_symbol = INDENTED_STRING_FRAGMENT;
for (bool has_content = false;; has_content = true) {
lexer->mark_end(lexer);
switch (lexer->lookahead) {
case '$':
advance(lexer);
if (lexer->lookahead == '{') {
return has_content;
} else if (lexer->lookahead != '\'') {
// Any char following '$' other than '\'' and '{' (which was handled above)
// should be consumed as additional string content.
// This means `$${` doesn't start an interpolation, but `$$${` does.
advance(lexer);
}
break;
case '\'':
advance(lexer);
if (lexer->lookahead == '\'') {
// Two single quotes always stop current string fragment.
// It can be either an end delimiter '', or escape sequences ''', ''$, ''\<any>
return has_content;
}
break;
// Simply give up on EOF or '\0'.
case '\0':
return false;
default:
advance(lexer);
}
}
}
static bool is_path_char(char c) {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '-' || c == '+' || c == '_' || c == '.' || c == '/';
}
static bool scan_path_start(TSLexer *lexer) {
lexer->result_symbol = PATH_START;
bool have_sep = false;
bool have_after_sep = false;
char c = lexer->lookahead;
// unlike string_fragments which which are preceded by initial token (i.e. '"')
// and thus will have all leading external whitespace consumed,
// we have no such luxury with the path_start token.
//
// so we must skip over any leading whitespace here.
while (c == ' ' || c == '\n' || c == '\r' || c == '\t') {
skip(lexer);
c = lexer->lookahead;
}
while (true) {
lexer->mark_end(lexer);
c = lexer->lookahead;
if (c == '/') {
have_sep = true;
} else if (is_path_char(c)) {
if (have_sep) {
have_after_sep = true;
}
} else if (c == '$') {
// starting a interpolation,
// so we have a valid token as long as we've seen a separator.
// example: a/${x}
return have_sep;
} else {
// we have a valid token if we've consumed anything after a separator.
// example: a/b
return have_after_sep;
}
advance(lexer);
}
}
static bool scan_path_fragment(TSLexer *lexer) {
lexer->result_symbol = PATH_FRAGMENT;
for (bool has_content = false;; has_content = true) {
lexer->mark_end(lexer);
if (!is_path_char(lexer->lookahead)) {
return has_content;
}
advance(lexer);
}
}
void *tree_sitter_nix_external_scanner_create() {
return NULL;
}
bool tree_sitter_nix_external_scanner_scan(void *payload, TSLexer *lexer,
const bool *valid_symbols) {
// This never happens in valid grammar. Only during error recovery, everything becomes valid.
// See: https://github.com/tree-sitter/tree-sitter/issues/1259
//
// We should not consume any content as string fragment during error recovery, or we'll break
// more valid grammar below.
// The test 'attrset typing field following string' covers this.
if (valid_symbols[STRING_FRAGMENT] && valid_symbols[INDENTED_STRING_FRAGMENT] && valid_symbols[PATH_START] && valid_symbols[PATH_FRAGMENT] ) {
return false;
} else if (valid_symbols[STRING_FRAGMENT]) {
return scan_string_fragment(lexer);
} else if (valid_symbols[INDENTED_STRING_FRAGMENT]) {
return scan_indented_string_fragment(lexer);
} else if (valid_symbols[PATH_FRAGMENT] && is_path_char(lexer->lookahead)) {
// path_fragments should be scanned as immediate tokens, with no preceding extras.
// so we assert that the very first token is a path character,
// and otherwise we fall through to the case below.
// example:
// a/b${c} d/e${f}
// ^--- note that scanning for the path_fragment will start here.
// this *should* be parsed as a function application.
// so we want to fall through to the path_start case below,
// which will skip the whitespace and correctly scan the following path_start.
//
// also, we want this above path_start, because wherever there's ambiguity we want to parse another fragment
// instead of starting a new path.
// example:
// a/b${c}d/e${f}
// if we swap the precedence, we'd effectively parse the above as the following function application:
// (a/b${c}) (d/e${f})
return scan_path_fragment(lexer);
} else if (valid_symbols[PATH_START]) {
return scan_path_start(lexer);
}
return false;
}
unsigned tree_sitter_nix_external_scanner_serialize(void *payload, char *buffer) {
return 0;
}
void tree_sitter_nix_external_scanner_deserialize(void *payload, const char *buffer, unsigned length) { }
void tree_sitter_nix_external_scanner_destroy(void *payload) { }

@ -1,224 +0,0 @@
#ifndef TREE_SITTER_PARSER_H_
#define TREE_SITTER_PARSER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#define ts_builtin_sym_error ((TSSymbol)-1)
#define ts_builtin_sym_end 0
#define TREE_SITTER_SERIALIZATION_BUFFER_SIZE 1024
typedef uint16_t TSStateId;
#ifndef TREE_SITTER_API_H_
typedef uint16_t TSSymbol;
typedef uint16_t TSFieldId;
typedef struct TSLanguage TSLanguage;
#endif
typedef struct {
TSFieldId field_id;
uint8_t child_index;
bool inherited;
} TSFieldMapEntry;
typedef struct {
uint16_t index;
uint16_t length;
} TSFieldMapSlice;
typedef struct {
bool visible;
bool named;
bool supertype;
} TSSymbolMetadata;
typedef struct TSLexer TSLexer;
struct TSLexer {
int32_t lookahead;
TSSymbol result_symbol;
void (*advance)(TSLexer *, bool);
void (*mark_end)(TSLexer *);
uint32_t (*get_column)(TSLexer *);
bool (*is_at_included_range_start)(const TSLexer *);
bool (*eof)(const TSLexer *);
};
typedef enum {
TSParseActionTypeShift,
TSParseActionTypeReduce,
TSParseActionTypeAccept,
TSParseActionTypeRecover,
} TSParseActionType;
typedef union {
struct {
uint8_t type;
TSStateId state;
bool extra;
bool repetition;
} shift;
struct {
uint8_t type;
uint8_t child_count;
TSSymbol symbol;
int16_t dynamic_precedence;
uint16_t production_id;
} reduce;
uint8_t type;
} TSParseAction;
typedef struct {
uint16_t lex_state;
uint16_t external_lex_state;
} TSLexMode;
typedef union {
TSParseAction action;
struct {
uint8_t count;
bool reusable;
} entry;
} TSParseActionEntry;
struct TSLanguage {
uint32_t version;
uint32_t symbol_count;
uint32_t alias_count;
uint32_t token_count;
uint32_t external_token_count;
uint32_t state_count;
uint32_t large_state_count;
uint32_t production_id_count;
uint32_t field_count;
uint16_t max_alias_sequence_length;
const uint16_t *parse_table;
const uint16_t *small_parse_table;
const uint32_t *small_parse_table_map;
const TSParseActionEntry *parse_actions;
const char * const *symbol_names;
const char * const *field_names;
const TSFieldMapSlice *field_map_slices;
const TSFieldMapEntry *field_map_entries;
const TSSymbolMetadata *symbol_metadata;
const TSSymbol *public_symbol_map;
const uint16_t *alias_map;
const TSSymbol *alias_sequences;
const TSLexMode *lex_modes;
bool (*lex_fn)(TSLexer *, TSStateId);
bool (*keyword_lex_fn)(TSLexer *, TSStateId);
TSSymbol keyword_capture_token;
struct {
const bool *states;
const TSSymbol *symbol_map;
void *(*create)(void);
void (*destroy)(void *);
bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist);
unsigned (*serialize)(void *, char *);
void (*deserialize)(void *, const char *, unsigned);
} external_scanner;
const TSStateId *primary_state_ids;
};
/*
* Lexer Macros
*/
#define START_LEXER() \
bool result = false; \
bool skip = false; \
bool eof = false; \
int32_t lookahead; \
goto start; \
next_state: \
lexer->advance(lexer, skip); \
start: \
skip = false; \
lookahead = lexer->lookahead;
#define ADVANCE(state_value) \
{ \
state = state_value; \
goto next_state; \
}
#define SKIP(state_value) \
{ \
skip = true; \
state = state_value; \
goto next_state; \
}
#define ACCEPT_TOKEN(symbol_value) \
result = true; \
lexer->result_symbol = symbol_value; \
lexer->mark_end(lexer);
#define END_STATE() return result;
/*
* Parse Table Macros
*/
#define SMALL_STATE(id) id - LARGE_STATE_COUNT
#define STATE(id) id
#define ACTIONS(id) id
#define SHIFT(state_value) \
{{ \
.shift = { \
.type = TSParseActionTypeShift, \
.state = state_value \
} \
}}
#define SHIFT_REPEAT(state_value) \
{{ \
.shift = { \
.type = TSParseActionTypeShift, \
.state = state_value, \
.repetition = true \
} \
}}
#define SHIFT_EXTRA() \
{{ \
.shift = { \
.type = TSParseActionTypeShift, \
.extra = true \
} \
}}
#define REDUCE(symbol_val, child_count_val, ...) \
{{ \
.reduce = { \
.type = TSParseActionTypeReduce, \
.symbol = symbol_val, \
.child_count = child_count_val, \
__VA_ARGS__ \
}, \
}}
#define RECOVER() \
{{ \
.type = TSParseActionTypeRecover \
}}
#define ACCEPT_INPUT() \
{{ \
.type = TSParseActionTypeAccept \
}}
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_PARSER_H_

@ -1,80 +0,0 @@
{
or = { or = 1; }.or or 42;
# <- property
# ^ punctuation.delimiter
# ^ property
# ^ property
# ^ keyword
the-question = if builtins.true then "to be" else "not to be";
# <- property
# ^ property
# ^ property
# ^ keyword
# ^ variable.builtin
# ^ property
# ^ keyword
# ^ string
# ^ keyword
# ^ string
null = if null then true else false;
# <- property
# ^ variable.builtin
# ^ variable.builtin
# ^ variable.builtin
pkgs' = { inherit (pkgs) stdenv lib; };
# <- property
# ^ property
# ^ keyword
# ^ variable
# ^ property
# ^ property
thing' =
# <- property
let inherit (pkgs) stdenv lib;
# <- keyword
# ^ keyword
# ^ variable
# ^ property
# ^ property
in derivation rec {
# <- keyword
# ^ function.builtin
# ^ keyword
pname = "thing";
# <- property
# ^ string
version = "v1.2.3";
name = "${pname}-${version}";
# <- property
# ^ string
# ^ punctuation.special
# ^ variable
# ^ punctuation.special
# ^ string
# ^ variable
# ^ string
buildInputs = with pkgs; [ thing_a thing_b ];
# <- property
# ^ keyword
# ^ variable
# ^ variable
# ^ variable
};
assert_bool = bool: assert lib.isBool bool; bool;
# <- property
# ^ variable.parameter
# ^ keyword
# ^ variable
# ^ function
# ^ variable
# ^ variable
import = import ./overlays.nix { inherit pkgs; };
# <- property
# ^ function.builtin
# ^ string.special.path
# ^ keyword
# ^ property
uri = https://github.com;
# ^ string.special.uri
# ^ string.special.uri
}