Unvendor tree-sitter-gleam

For #891.
pull/896/head
Antonin Delpeuch 2025-10-07 08:10:12 +07:00 committed by Wilfred Hughes
parent 8bb43e5fec
commit 6047469f71
66 changed files with 17 additions and 104884 deletions

@ -2,7 +2,7 @@
### Parsing
Added support for protocol buffer files. Updated CMake, Solidity, HCL, Dart, Elm, Devicetree and R parsers.
Added support for protocol buffer files. Updated CMake, Solidity, HCL, Dart, Elm, Devicetree, Gleam and R parsers.
### Display

11
Cargo.lock generated

@ -288,6 +288,7 @@ dependencies = [
"tree-sitter-elm",
"tree-sitter-erlang",
"tree-sitter-fsharp",
"tree-sitter-gleam",
"tree-sitter-go",
"tree-sitter-haskell",
"tree-sitter-hcl",
@ -1161,6 +1162,16 @@ dependencies = [
"tree-sitter-language",
]
[[package]]
name = "tree-sitter-gleam"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0175c53793bda5d444360dd5add25463d18d66afb7f521d6791e2fc61bf2fb3"
dependencies = [
"cc",
"tree-sitter-language",
]
[[package]]
name = "tree-sitter-go"
version = "0.23.4"

@ -89,6 +89,7 @@ tree-sitter-elixir = "0.3.4"
tree-sitter-elm = "5.8.0"
tree-sitter-erlang = "0.13.0"
tree-sitter-fsharp = "0.1.0"
tree-sitter-gleam = "1.0.0"
tree-sitter-go = "0.23.4"
tree-sitter-haskell = "0.23.1"
tree-sitter-hcl = "1.1.0"

@ -92,11 +92,6 @@ fn main() {
src_dir: "vendored_parsers/tree-sitter-elvish-src",
extra_files: vec![],
},
TreeSitterParser {
name: "tree-sitter-gleam",
src_dir: "vendored_parsers/tree-sitter-gleam-src",
extra_files: vec!["scanner.c"],
},
TreeSitterParser {
name: "tree-sitter-hack",
src_dir: "vendored_parsers/tree-sitter-hack-src",

@ -75,7 +75,6 @@ extern "C" {
fn tree_sitter_commonlisp() -> ts::Language;
fn tree_sitter_elisp() -> ts::Language;
fn tree_sitter_elvish() -> ts::Language;
fn tree_sitter_gleam() -> ts::Language;
fn tree_sitter_hare() -> ts::Language;
fn tree_sitter_hack() -> ts::Language;
fn tree_sitter_janet_simple() -> ts::Language;
@ -393,16 +392,14 @@ pub(crate) fn from_language(language: guess::Language) -> TreeSitterConfig {
}
}
Gleam => {
let language = unsafe { tree_sitter_gleam() };
let language_fn = tree_sitter_gleam::LANGUAGE;
let language = tree_sitter::Language::new(language_fn);
TreeSitterConfig {
language: language.clone(),
atom_nodes: ["string"].into_iter().collect(),
delimiter_tokens: vec![("(", ")"), ("[", "]"), ("{", "}")],
highlight_query: ts::Query::new(
&language,
include_str!("../../vendored_parsers/highlights/gleam.scm"),
)
.unwrap(),
highlight_query: ts::Query::new(&language, tree_sitter_gleam::HIGHLIGHT_QUERY)
.unwrap(),
sub_languages: vec![],
}
}

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

@ -1,3 +0,0 @@
src/** linguist-generated
src/scanner.c -linguist-generated
test/** linguist-documentation

@ -1,12 +0,0 @@
---
name: Issue
about: A problem or suggestion
title: ''
labels: ''
assignees: ''
---
> [!IMPORTANT]
> Please ensure you are using the latest commit in this repo.
> Older versions are not supported.

@ -1,67 +0,0 @@
name: CI
on: [push, pull_request]
jobs:
test:
name: Test
runs-on: ${{ matrix.os }}
strategy:
matrix:
os:
- macos-latest
- ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Node
uses: actions/setup-node@v4
- name: Cache npm dependencies
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install npm dependencies
run: npm ci
- name: Ensure generated parser files are up to date
run: npx tree-sitter generate
- name: Run tree-sitter tests
run: npx tree-sitter test
- name: Check formatting
run: npm run check-formatted
integration-test:
name: Integration Test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Node
uses: actions/setup-node@v4
- name: Cache npm dependencies
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install npm dependencies
run: npm ci
- name: Ensure generated parser files are up to date
run: npx tree-sitter generate
- name: Run integration tests
run: ./scripts/integration_test.sh

@ -1,41 +0,0 @@
# generates the parser with 'tree-sitter generate' if the parser is out of date
name: Generate Parser
on:
push:
branches:
- main
jobs:
generate:
name: Generate Parser
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Node
uses: actions/setup-node@v4
- name: Cache npm dependencies
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install npm dependencies
run: npm ci
- name: Generate parser files
run: npx tree-sitter generate
- name: Commit generated parser files
run: |
git config --local user.email "$(git log --format='%ae' HEAD^!)"
git config --local user.name "$(git log --format='%an' HEAD^!)"
git add src
git commit -m "Generate parser" || true
git push

@ -1,56 +0,0 @@
name: release
on:
push:
tags:
- "v*"
jobs:
build-release:
name: build-release
runs-on: ${{ matrix.os }}
strategy:
matrix:
os:
- macos-latest
- ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Install Node
uses: actions/setup-node@v4
- name: Install npm dependencies
run: npm ci
- name: Ensure generated parser files are up to date
run: npx tree-sitter generate
- name: Ensure tests pass
run: npx tree-sitter test
- name: Compile library file
run: cc -shared -fPIC -g -O2 -I src src/parser.c src/scanner.c -o tree-sitter-gleam.so
- name: Create archive
run: |
VERSION="${GITHUB_REF#refs/tags/}"
case ${{ matrix.os }} in
"ubuntu-latest") FAMILY="linux";;
"macos-latest") FAMILY="macos";;
esac
ARCHIVE="tree-sitter-gleam-$VERSION-$FAMILY.tar.gz"
tar -czf $ARCHIVE tree-sitter-gleam.so
echo "ASSET=$ARCHIVE" >> $GITHUB_ENV
- name: Upload release archive
uses: softprops/action-gh-release@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
draft: true
prerelease: false
fail_on_unmatched_files: true
files: |
${{ env.ASSET }}

@ -1,6 +0,0 @@
*.wasm
build
gleam.so*
log.html
node_modules
target

@ -1,89 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "cc"
version = "1.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0"
dependencies = [
"shlex",
]
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "regex"
version = "1.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "tree-sitter"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20f4cd3642c47a85052a887d86704f4eac272969f61b686bdd3f772122aabaff"
dependencies = [
"cc",
"regex",
"regex-syntax",
"tree-sitter-language",
]
[[package]]
name = "tree-sitter-gleam"
version = "1.0.0"
dependencies = [
"cc",
"tree-sitter",
"tree-sitter-language",
]
[[package]]
name = "tree-sitter-language"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2545046bd1473dac6c626659cc2567c6c0ff302fc8b84a56c4243378276f7f57"

@ -1,29 +0,0 @@
[package]
name = "tree-sitter-gleam"
description = "gleam grammar for the tree-sitter parsing library"
version = "1.0.0"
keywords = ["incremental", "parsing", "gleam"]
categories = ["parsing", "text-editors"]
repository = "https://github.com/tree-sitter/tree-sitter-gleam"
edition = "2018"
license = "Apache-2.0"
build = "bindings/rust/build.rs"
include = [
"bindings/rust/*",
"grammar.js",
"queries/*",
"src/*",
]
[lib]
path = "bindings/rust/lib.rs"
[dependencies]
tree-sitter-language = "0.1.0"
[dev-dependencies]
tree-sitter = "0.23"
[build-dependencies]
cc = "1.0"

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

@ -1,103 +0,0 @@
tree-sitter-gleam
=================
A [tree-sitter] grammar for the [Gleam programming language]
[tree-sitter]: https://tree-sitter.github.io
[Gleam programming language]: https://gleam.run
This grammar is able to parse the entire Gleam language. It is largely based
on the Gleam parser itself, and deviations from that are noted throughout the
codebase.
Usage
-----
tree-sitter-gleam, as with all tree-sitter grammars, is of limited utility on
its own. Instead, tree-sitter-gleam is best used as a Gleam parser that can be
embedded in other projects. An example of such a project is
[tree-sitter-gleam-rust-example].
However, [tree-sitter-cli] can be used with this grammar to show generated parse
trees and syntax highlighting for a given Gleam file.
1. [Install tree-sitter-cli]
2. Create a `tree-sitters` directory in your home directory.
3. Clone this repository (or symlink it) into the new `~/tree-sitters/` directory.
4. Run `tree-sitter parse path/to/file.gleam` to be shown the parse tree for the
file.
5. Run `tree-sitter highlight path/to/file.gleam` to be shown the file with
syntax highlighting applied.
[tree-sitter-gleam-rust-example]: https://github.com/J3RN/tree-sitter-gleam-rust-example
[tree-sitter-cli]: https://github.com/tree-sitter/tree-sitter/blob/master/cli/README.md
[Install tree-sitter-cli]: https://github.com/tree-sitter/tree-sitter/blob/master/cli/README.md#installation
Various Gotchas
---------------
There are a few nodes in the generated AST that may be confusing at first:
- `type` :: A very ambiguous name, but this refers to a concrete type such as
`List(#(String, Int))`
- `type_name` :: Refers to essentially the left side of a type declaration and
includes parameters, e.g. `MyType(foo, bar)`.
- `type_identifier` :: Known in the parser as "UpName", this is what you would
intuitively think of as a type's name, such as `List` or `Result`.
- `function_call` :: The name is not confusing, but its structure may be. Since
Gleam supports first-class functions, the function being invoked could be a
variable, a field of a record, an element of a tuple, etc. Some of these are
ambiguous without context that tree-sitter does not have. e.g.
In `string.replace(x, y, z)`, `string` could be a record with a field
`replace` that is a function or it could be a module with a function `replace`
—there's no way for the parser to know. In this case, it will be parsed to
`(function_call function: (field_access ...) ...)` , as I arbitrarily decided
to always assume the code is accessing a field on a record.
- `constant_field_access` :: Recognizes when a reference to a remote function is used as a constant's value. Generally field accesses are indistinguishable from remote function invocations by the parser so `field_access` is the node name used for both (hence this misnomer).
This is not a comprehensive list. If you find a node confusing, search for it
in `grammar.js`, as it might have an explanatory comment. Either way, feel free
to add it to this list and send a PR! ✨
To-do List
----------
- [x] Add ability to parse all language constructs
- [x] Syntax highlighting queries
- [ ] Have an issue? Let me know! Please [open an issue] 💁
[open an issue]: https://github.com/J3RN/tree-sitter-gleam/issues/new
Contributing
------------
1. Change files such as `grammar.js` and `queries/highlight.scm`.
2. The grammar needs to be generated from the `grammar.js` file by running `npm run generate`.
3. Add parser feature tests to the relevant file(s) in `test/corpus/`, or make a new one.
4. Run `npm run test` and fix any failing tests.
Policies
--------
### Backwards-Compatibility Policy
Per the conversation in [#55](https://github.com/gleam-lang/tree-sitter-gleam/pull/55), we have decided that from v0.28.0 forward, tree-sitter-gleam will maintain backwards compatibility with the previous two minor versions; meaning that each release will support three versions:
- 0.x.0
- 0.x-1.*
- 0.x-2.*
e.g. The v0.30.0 release of tree-sitter gleam will support the following version of the Gleam language:
- v0.30.0
- v0.29.*
- v0.28.*
Style
-----
To prevent headaches from stylistic differences, I request that you please
follow these style suggestions. 🙏
- Remove all non-mandatory trailing whitespace.
- Ensure a final newline is present at the end of all files (this is the default
in Vim, Emacs).
- Format JavaScript by running `npm run format`.

@ -1,19 +0,0 @@
{
"targets": [
{
"target_name": "tree_sitter_gleam_binding",
"include_dirs": [
"<!(node -e \"require('nan')\")",
"src"
],
"sources": [
"bindings/node/binding.cc",
"src/parser.c",
"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_gleam();
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_gleam());
Nan::Set(instance, Nan::New("name").ToLocalChecked(), Nan::New("gleam").ToLocalChecked());
Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance);
}
NODE_MODULE(tree_sitter_gleam_binding, Init)
} // namespace

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

@ -1,35 +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);
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,62 +0,0 @@
//! This crate provides Gleam 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#"
//! import gleam/io
//!
//! pub fn main() {
//! io.println("hello, friend!")
//! }
//! "#;
//! let mut parser = Parser::new();
//! let language = tree_sitter_gleam::LANGUAGE;
//! parser
//! .set_language(&language.into())
//! .expect("Error loading Gleam 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_gleam() -> *const ();
}
/// The tree-sitter [`LanguageFn`] for this grammar.
pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_gleam) };
/// 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");
/// The syntax highlighting query for this language.
pub const HIGHLIGHT_QUERY: &'static str = include_str!("../../queries/highlights.scm");
// The locals tagging query for this language.
pub const LOCALS_QUERY: &'static str = include_str!("../../queries/locals.scm");
/// The symbol tagging query for this language.
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.into())
.expect("Error loading Gleam parser");
}
}

@ -1,902 +0,0 @@
const NEWLINE = /\r?\n/;
module.exports = grammar({
name: "gleam",
externals: ($) => [$.quoted_content],
extras: ($) => [
NEWLINE,
/\s/,
$.module_comment,
$.statement_comment,
$.comment,
],
conflicts: ($) => [
[$._maybe_record_expression, $._maybe_tuple_expression],
[
$._maybe_record_expression,
$._maybe_tuple_expression,
$.remote_constructor_name,
],
[$.case_subjects],
[$.source_file],
[$._constant_value, $._case_clause_guard_unit],
[$.integer],
[$.echo],
],
rules: {
/* General rules */
source_file: ($) =>
repeat(choice($.target_group, $._module_statement, $._statement_seq)),
_module_statement: ($) =>
choice(
$.import,
$.constant,
$.external_type,
$.external_function,
$.function,
$.type_definition,
$.type_alias,
$.attribute
),
/* Comments */
module_comment: ($) => token(seq("////", /.*/)),
statement_comment: ($) => token(seq("///", /.*/)),
comment: ($) => token(seq("//", /.*/)),
/* Target groups
* DEPRECATED: This syntax was replaced with attributes in v0.30.
*/
target_group: ($) =>
seq(
"if",
field("target", $.target),
"{",
repeat($._module_statement),
"}"
),
target: ($) => choice("erlang", "javascript"),
/* Attributes */
attribute: ($) =>
seq(
"@",
field("name", $.identifier),
optional(field("arguments", alias($._attribute_arguments, $.arguments)))
),
_attribute_arguments: ($) =>
seq("(", series_of($.attribute_value, ","), ")"),
attribute_value: ($) =>
choice(
$._constant_value,
seq(field("label", $.label), ":", field("value", $._constant_value))
),
/* Import statements */
import: ($) =>
seq(
"import",
field("module", $.module),
optional(seq(".", field("imports", $.unqualified_imports))),
optional(seq("as", field("alias", choice($.identifier, $.discard))))
),
module: ($) => seq($._name, repeat(seq("/", $._name))),
unqualified_imports: ($) =>
seq("{", optional(series_of($.unqualified_import, ",")), "}"),
unqualified_import: ($) =>
choice(
seq(
field("name", $.identifier),
optional(seq("as", field("alias", $.identifier)))
),
seq(
"type",
field("name", $.type_identifier),
optional(seq("as", field("alias", $.type_identifier)))
),
seq(
field("name", $.constructor_name),
optional(seq("as", field("alias", $.constructor_name)))
)
),
/* Constant statements */
constant: ($) =>
seq(
optional($.visibility_modifier),
"const",
field("name", $.identifier),
optional($._constant_type_annotation),
"=",
field("value", $._constant_value)
),
_constant_value: ($) =>
choice(
$.string,
$.float,
$.integer,
alias($.constant_tuple, $.tuple),
alias($.constant_list, $.list),
alias($._constant_bit_string, $.bit_string),
alias($.constant_record, $.record),
$.identifier,
alias($.constant_field_access, $.field_access)
),
constant_tuple: ($) =>
seq("#", "(", optional(series_of($._constant_value, ",")), ")"),
constant_list: ($) =>
seq("[", optional(series_of($._constant_value, ",")), "]"),
...bit_string_rules("constant", "_constant_value", "integer"),
constant_record: ($) =>
seq(
field("name", choice($.constructor_name, $.remote_constructor_name)),
optional(
field("arguments", alias($.constant_record_arguments, $.arguments))
)
),
constant_record_arguments: ($) =>
seq(
"(",
optional(series_of(alias($.constant_record_argument, $.argument), ",")),
")"
),
constant_record_argument: ($) =>
choice(
seq(
optional(seq(field("label", $.label), ":")),
field("value", $._constant_value)
),
seq(field("label", $.label), ":")
),
// This rule exists to parse remote function references which are generally
// indistinguishable from field accesses and so share an AST node.
constant_field_access: ($) =>
seq(field("record", $.identifier), ".", field("field", $.label)),
/* Special constant types */
// Versions of $._type, $._type_annotation, etc, that have constraints
// specific to constants.
_constant_type: ($) =>
choice(
$.type_hole,
alias($.constant_tuple_type, $.tuple_type),
alias($.constant_function_type, $.function_type),
alias($.constant_type, $.type)
),
_constant_type_annotation: ($) => seq(":", field("type", $._constant_type)),
constant_tuple_type: ($) =>
seq("#", "(", optional(series_of($._constant_type, ",")), ")"),
constant_function_type: ($) =>
seq(
"fn",
optional(
field(
"parameter_types",
alias(
$.constant_function_parameter_types,
$.function_parameter_types
)
)
),
"->",
field("return_type", $._constant_type)
),
constant_function_parameter_types: ($) =>
seq("(", optional(series_of($._constant_type, ",")), ")"),
constant_type: ($) =>
seq(
field("name", choice($.type_identifier, $.remote_type_identifier)),
optional(
field("arguments", alias($.constant_type_arguments, $.type_arguments))
)
),
constant_type_arguments: ($) =>
seq(
"(",
optional(
series_of(alias($.constant_type_argument, $.type_argument), ",")
),
")"
),
constant_type_argument: ($) => $._constant_type,
external_type: ($) =>
prec.right(
seq(
optional($.visibility_modifier),
// DEPRECATED: the external token was removed in v0.30.
optional("external"),
"type",
$.type_name
)
),
/* External function */
external_function: ($) =>
seq(
optional($.visibility_modifier),
"external",
"fn",
field("name", $.identifier),
field(
"parameters",
alias($.external_function_parameters, $.function_parameters)
),
"->",
field("return_type", $._type),
"=",
field("body", $.external_function_body)
),
// Different from module function parameters in that module function
// parameters may be labeled whereas external function parameters cannot.
external_function_parameters: ($) =>
seq(
"(",
optional(
series_of(
alias($.external_function_parameter, $.function_parameter),
","
)
),
")"
),
external_function_parameter: ($) =>
seq(
optional(seq(field("name", $.identifier), ":")),
field("type", $._type)
),
external_function_body: ($) => seq($.string, $.string),
/* Functions */
function: ($) =>
prec.right(
seq(
optional($.visibility_modifier),
"fn",
field("name", $.identifier),
field("parameters", $.function_parameters),
optional(seq("->", field("return_type", $._type))),
optional(field("body", $.block))
)
),
function_parameters: ($) =>
seq("(", optional(series_of($.function_parameter, ",")), ")"),
function_parameter: ($) =>
seq(
choice(
$._labeled_discard_param,
$._discard_param,
$._labeled_name_param,
$._name_param
),
optional($._type_annotation)
),
_labeled_discard_param: ($) =>
seq(field("label", $.label), field("name", $.discard)),
_discard_param: ($) => field("name", $.discard),
_labeled_name_param: ($) =>
seq(field("label", $.label), field("name", $.identifier)),
_name_param: ($) => field("name", $.identifier),
_statement_seq: ($) => repeat1($._statement),
_statement: ($) =>
choice($._expression, $.let, $.let_assert, $.use, $.assert),
_expression: ($) => choice($._expression_unit, $.binary_expression),
binary_expression: ($) =>
choice(
binaryExpr(prec.left, 1, "||", $._expression),
binaryExpr(prec.left, 2, "&&", $._expression),
binaryExpr(prec.left, 3, "==", $._expression),
binaryExpr(prec.left, 3, "!=", $._expression),
binaryExpr(prec.left, 4, "<", $._expression),
binaryExpr(prec.left, 4, "<=", $._expression),
binaryExpr(prec.left, 4, "<.", $._expression),
binaryExpr(prec.left, 4, "<=.", $._expression),
binaryExpr(prec.left, 4, ">", $._expression),
binaryExpr(prec.left, 4, ">=", $._expression),
binaryExpr(prec.left, 4, ">.", $._expression),
binaryExpr(prec.left, 4, ">=.", $._expression),
binaryExpr(
prec.left,
5,
"|>",
$._expression,
choice($.pipeline_echo, $._expression)
),
binaryExpr(prec.left, 6, "+", $._expression),
binaryExpr(prec.left, 6, "+.", $._expression),
binaryExpr(prec.left, 6, "-", $._expression),
binaryExpr(prec.left, 6, "-.", $._expression),
binaryExpr(prec.left, 7, "*", $._expression),
binaryExpr(prec.left, 7, "*.", $._expression),
binaryExpr(prec.left, 7, "/", $._expression),
binaryExpr(prec.left, 7, "/.", $._expression),
binaryExpr(prec.left, 7, "%", $._expression),
binaryExpr(prec.left, 7, "<>", $._expression)
),
// The way that this function is written in the Gleam parser is essentially
// incompatible with tree-sitter. It first parses some base expression,
// then potentially parses tuple access, field access, record updates, or
// function calls as an extension of that base expression that was
// previously parsed. tree-sitter provides no facility to amend a node that
// was already successfully parsed. Therefore, tuple access, field access,
// record updates, and function calls must be parsed as alternatives to the
// expressions they build upon rather than extensions thereof.
_expression_unit: ($) =>
choice(
$.string,
$.integer,
$.float,
// If we decide that record constructors (value constructors) are
// actually functions, this will require a refactor.
$.record,
$.identifier,
$.todo,
$.panic,
$.tuple,
$.echo,
$.list,
alias($._expression_bit_string, $.bit_string),
$.anonymous_function,
$.block,
$.case,
$.boolean_negation,
$.integer_negation,
$.record_update,
$.tuple_access,
$.field_access,
$.function_call
),
record: ($) =>
seq(
field("name", choice($.constructor_name, $.remote_constructor_name)),
optional(field("arguments", $.arguments))
),
todo: ($) =>
prec.left(
seq(
"todo",
optional(
choice(
// DEPRECATED: The 'as' syntax was introduced in v0.30.
seq("(", field("message", $.string), ")"),
seq("as", field("message", $._expression))
)
)
)
),
panic: ($) =>
prec.left(
seq(
"panic",
optional(
choice(
seq("(", field("message", $.string), ")"),
seq("as", field("message", $._expression))
)
)
)
),
pipeline_echo: (_$) => prec.left("echo"),
echo: ($) => seq("echo", $._expression),
tuple: ($) => seq("#", "(", optional(series_of($._expression, ",")), ")"),
list: ($) =>
seq(
"[",
optional(
seq(
$._expression,
optional(repeat(seq(",", $._expression))),
optional(","),
optional(seq("..", field("spread", $._expression)))
)
),
"]"
),
...bit_string_rules("expression", "_expression_unit", "_expression"),
anonymous_function: ($) =>
seq(
"fn",
field(
"parameters",
alias($.anonymous_function_parameters, $.function_parameters)
),
optional(seq("->", field("return_type", $._type))),
field("body", $.block)
),
anonymous_function_parameters: ($) =>
seq(
"(",
optional(
series_of(
alias($.anonymous_function_parameter, $.function_parameter),
","
)
),
")"
),
anonymous_function_parameter: ($) =>
seq(
choice($._discard_param, $._name_param),
optional($._type_annotation)
),
block: ($) => seq("{", optional($._statement_seq), "}"),
case: ($) =>
seq(
"case",
field("subjects", $.case_subjects),
"{",
optional(field("clauses", $.case_clauses)),
"}"
),
case_subjects: ($) => seq(series_of($._expression, ",")),
case_clauses: ($) => repeat1($.case_clause),
case_clause: ($) =>
seq(
field("patterns", $.case_clause_patterns),
optional(field("guard", $.case_clause_guard)),
"->",
field("value", $._expression)
),
// Technically the Gleam parser does support something like this:
// 1 | | 5 -> True
// However, that will cause an error further into the compiler. That format
// is not supported by this function.
case_clause_patterns: ($) => seq(series_of($.case_clause_pattern, "|")),
// The issue above comes from the fact that the parser equivalent of this
// function supports 0 patterns. This function does not.
case_clause_pattern: ($) => series_of($._pattern, ","),
case_clause_guard: ($) => seq("if", $._case_clause_guard_expression),
_case_clause_guard_expression: ($) =>
choice(
$._case_clause_guard_unit,
alias($._case_clause_guard_binary_expression, $.binary_expression),
$.boolean_negation
),
_case_clause_guard_binary_expression: ($) =>
choice(
binaryExpr(prec.left, 1, "||", $._case_clause_guard_expression),
binaryExpr(prec.left, 2, "&&", $._case_clause_guard_expression),
binaryExpr(prec.left, 3, "==", $._case_clause_guard_expression),
binaryExpr(prec.left, 3, "!=", $._case_clause_guard_expression),
binaryExpr(prec.left, 4, "<", $._case_clause_guard_expression),
binaryExpr(prec.left, 4, "<=", $._case_clause_guard_expression),
binaryExpr(prec.left, 4, "<.", $._case_clause_guard_expression),
binaryExpr(prec.left, 4, "<=.", $._case_clause_guard_expression),
binaryExpr(prec.left, 4, ">", $._case_clause_guard_expression),
binaryExpr(prec.left, 4, ">=", $._case_clause_guard_expression),
binaryExpr(prec.left, 4, ">.", $._case_clause_guard_expression),
binaryExpr(prec.left, 4, ">=.", $._case_clause_guard_expression),
binaryExpr(prec.left, 5, "+", $._case_clause_guard_expression),
binaryExpr(prec.left, 5, "+.", $._case_clause_guard_expression),
binaryExpr(prec.left, 5, "-", $._case_clause_guard_expression),
binaryExpr(prec.left, 5, "-.", $._case_clause_guard_expression),
binaryExpr(prec.left, 6, "*", $._case_clause_guard_expression),
binaryExpr(prec.left, 6, "*.", $._case_clause_guard_expression),
binaryExpr(prec.left, 6, "/", $._case_clause_guard_expression),
binaryExpr(prec.left, 6, "/.", $._case_clause_guard_expression),
binaryExpr(prec.left, 6, "%", $._case_clause_guard_expression)
),
_case_clause_guard_unit: ($) =>
choice(
$.identifier,
prec(1, alias($._case_clause_tuple_access, $.tuple_access)),
seq("{", $._case_clause_guard_expression, "}"),
$._constant_value
),
_case_clause_tuple_access: ($) =>
seq(field("tuple", $.identifier), ".", field("index", $.integer)),
let_assert: ($) =>
seq(
"let",
"assert",
$._assignment,
optional(seq("as", field("message", $._expression)))
),
assert: ($) =>
seq(
"assert",
field("value", $._expression),
optional(seq("as", field("message", $._expression)))
),
let: ($) => seq("let", $._assignment),
use: ($) =>
seq(
"use",
optional(field("assignments", $.use_assignments)),
"<-",
field("value", $._expression)
),
use_assignments: ($) => series_of($.use_assignment, ","),
use_assignment: ($) => seq($._pattern, optional($._type_annotation)),
boolean_negation: ($) => seq("!", $._expression_unit),
integer_negation: ($) => seq("-", $._expression_unit),
_assignment: ($) =>
seq(
field("pattern", $._pattern),
optional($._type_annotation),
"=",
field("value", $._expression)
),
record_update: ($) =>
seq(
field(
"constructor",
choice($.constructor_name, $.remote_constructor_name)
),
"(",
"..",
field("spread", $._expression),
",",
field("arguments", $.record_update_arguments),
")"
),
record_update_arguments: ($) => series_of($.record_update_argument, ","),
record_update_argument: ($) =>
choice(
seq(field("label", $.label), ":", field("value", $._expression)),
seq(field("label", $.label), ":")
),
// As with other AST nodes in this section, `_maybe_record_expression`,
// `_maybe_tuple_expression`, and `_maybe_function_expresssion` have no
// corollaries in the Gleam parser. These anonymous AST node denote any
// expression whose return type could be a record, tuple, or function,
// respectively.
//
// `let` and `assert` are exempted because in order to parse correctly,
// they would have to be wrapped in an expression group anyways.
_maybe_tuple_expression: ($) =>
choice(
$.identifier,
$.function_call,
$.tuple,
$.block,
$.case,
$.field_access,
$.tuple_access
),
tuple_access: ($) =>
prec.left(
seq(
field("tuple", $._maybe_tuple_expression),
".",
field("index", $.integer)
)
),
_maybe_record_expression: ($) =>
choice(
$.record,
$.identifier,
$.function_call,
$.block,
$.case,
$.record_update,
$.field_access,
$.tuple_access
),
field_access: ($) =>
prec.left(
seq(
field("record", $._maybe_record_expression),
".",
field("field", $.label)
)
),
// Remote functions (e.g. int.to_string) is parsed as a field access
// (accessing field to_string on record int) as it is impossible for the
// parser to determine with int is a module (and thus to_string a member
// function) or a local variable containing a record (and thus to_string is
// a field of that record).
// Similarly, the function name in local function calls (e.g. foo(arg)) is
// parsed as an $.identifier which is used to refer to both local variables
// and module functions, embodying the same ambiguity.
_maybe_function_expression: ($) =>
choice(
$.identifier,
$.anonymous_function,
$.block,
$.case,
$.tuple_access,
$.field_access,
$.function_call
),
// Interestingly, the code that parses function arguments also parses
// record arguments, hence the ambiguous name.
arguments: ($) => seq("(", optional(series_of($.argument, ",")), ")"),
argument: ($) =>
choice(
seq(
optional(seq(field("label", $.label), ":")),
field("value", choice($.hole, $._expression))
),
seq(field("label", $.label), ":")
),
hole: ($) => $._discard_name,
function_call: ($) =>
seq(
field("function", $._maybe_function_expression),
field("arguments", $.arguments)
),
_pattern_expression: ($) =>
choice(
$.identifier,
$.discard,
$.record_pattern,
$.string,
$.integer,
$.float,
$.tuple_pattern,
alias($._pattern_bit_string, $.bit_string_pattern),
$.list_pattern,
alias($._pattern_binary_expression, $.binary_expression)
),
_pattern_binary_expression: ($) =>
choice(
binaryExpr(prec.left, 1, "<>", $._pattern_expression),
binaryExpr(prec.left, 1, "as", $.string, $.identifier)
),
_pattern: ($) =>
seq(
$._pattern_expression,
optional(field("assign", seq("as", $.identifier)))
),
record_pattern: ($) =>
seq(
field("name", choice($.constructor_name, $.remote_constructor_name)),
optional(field("arguments", $.record_pattern_arguments))
),
record_pattern_arguments: ($) =>
seq(
"(",
optional(series_of($.record_pattern_argument, ",")),
optional($.pattern_spread),
")"
),
record_pattern_argument: ($) =>
choice(
seq(
optional(seq(field("label", $.label), ":")),
field("pattern", $._pattern)
),
seq(field("label", $.label), ":")
),
pattern_spread: ($) => seq("..", optional(",")),
tuple_pattern: ($) =>
seq("#", "(", optional(series_of($._pattern, ",")), ")"),
// The Gleam parser has a special catch for nested bitstrings here, which
// is interesting as the same error does not exist on constants. Anyhow, I
// wasn't really sure how to implement that easily here, and so didn't.
...bit_string_rules(
"pattern",
"_pattern",
"_pattern_bit_string_segment_argument"
),
_pattern_bit_string_segment_argument: ($) =>
choice($.identifier, $.integer),
list_pattern: ($) =>
seq(
"[",
optional(series_of($._pattern, ",")),
optional($.list_pattern_tail),
"]"
),
list_pattern_tail: ($) =>
seq("..", optional(choice($.identifier, $.discard))),
visibility_modifier: ($) => "pub",
opacity_modifier: ($) => "opaque",
/* Custom type definitions */
type_definition: ($) =>
seq(
optional($.visibility_modifier),
optional($.opacity_modifier),
"type",
$.type_name,
"{",
$.data_constructors,
"}"
),
data_constructors: ($) => repeat1($.data_constructor),
data_constructor: ($) =>
seq(
optional($.attribute),
field("name", $.constructor_name),
optional(field("arguments", $.data_constructor_arguments))
),
data_constructor_arguments: ($) =>
seq("(", optional(series_of($.data_constructor_argument, ",")), ")"),
data_constructor_argument: ($) =>
seq(optional(seq(field("label", $.label), ":")), field("value", $._type)),
/* Type aliases */
type_alias: ($) =>
seq(
optional($.visibility_modifier),
optional($.opacity_modifier),
"type",
$.type_name,
"=",
$._type
),
/* Literals */
string: ($) =>
seq(
'"',
repeat(choice($.escape_sequence, $.quoted_content)),
token.immediate('"')
),
escape_sequence: ($) =>
choice(
token.immediate(/\\[efnrt\"\\]/),
token.immediate(/\\u\{[0-9a-fA-F]{1,6}\}/)
),
float: ($) => /-?[0-9_]+\.[0-9_]*(e-?[0-9_]+)?/,
integer: ($) =>
seq(optional("-"), choice($._hex, $._decimal, $._octal, $._binary)),
_hex: ($) => /0[xX][0-9a-fA-F_]+/,
_decimal: ($) => /[0-9][0-9_]*/,
_octal: ($) => /0[oO][0-7_]+/,
_binary: ($) => /0[bB][0-1_]+/,
_bit_string_segment_option: ($) =>
choice(
"binary",
"bytes",
"int",
"float",
"bit_string",
"bits",
"utf8",
"utf16",
"utf32",
"utf8_codepoint",
"utf16_codepoint",
"utf32_codepoint",
"signed",
"unsigned",
"big",
"little",
"native",
seq("unit", "(", $.integer, ")")
),
/* Types */
_type: ($) =>
choice($.type_hole, $.tuple_type, $.function_type, $.type, $.type_var),
_type_annotation: ($) => seq(":", field("type", $._type)),
type_hole: ($) => $._discard_name,
// If you're wondering why there isn't a `list_type` here, the answer is
// that the "type" form for lists is `List`, which is identical to
// user-defined types etc and thus is not parsed specially.
tuple_type: ($) => seq("#", "(", optional(series_of($._type, ",")), ")"),
function_type: ($) =>
seq(
"fn",
optional(field("parameter_types", $.function_parameter_types)),
"->",
field("return_type", $._type)
),
function_parameter_types: ($) =>
seq("(", optional(series_of($._type, ",")), ")"),
// "type" is a somewhat ambiguous name, but it refers to a concrete type
// such as `Bool` or `List(Int)` or even `result.Result(#(Int, Int), Nil)`.
type: ($) =>
seq(
field("name", choice($.type_identifier, $.remote_type_identifier)),
optional(field("arguments", $.type_arguments))
),
type_arguments: ($) =>
seq("(", optional(series_of($.type_argument, ",")), ")"),
type_argument: ($) => $._type,
type_var: ($) => $._name,
// "type_name" essentially refers to the declaration of a type. The type
// parameters are part of the "name." Bit odd, but 🤷
// e.g. MyType(a, b)
type_name: ($) =>
seq(
field("name", choice($.type_identifier, $.remote_type_identifier)),
optional(field("parameters", $.type_parameters))
),
type_parameters: ($) =>
seq("(", optional(series_of($.type_parameter, ",")), ")"),
type_parameter: ($) => $._name,
/* Shared AST nodes */
identifier: ($) => $._name,
label: ($) => $._name,
discard: ($) => $._discard_name,
type_identifier: ($) => $._upname,
remote_type_identifier: ($) =>
seq(field("module", $.identifier), ".", field("name", $.type_identifier)),
constructor_name: ($) => $._upname,
remote_constructor_name: ($) =>
seq(
field("module", $.identifier),
".",
field("name", $.constructor_name)
),
/* Reused types from the Gleam lexer */
_discard_name: ($) => /_[_0-9a-z]*/,
_name: ($) => /[_a-z][_0-9a-z]*/,
_upname: ($) => /[A-Z][0-9a-zA-Z]*/,
},
});
// This function and the following function are vaguely congruent with the
// `parse_bit_string_segment` function of the Gleam parser.
function bit_string_rules(name, value_parser, arg_parser) {
return {
[`_${name}_bit_string`]: ($) =>
seq(
"<<",
optional(
series_of(
alias($[`${name}_bit_string_segment`], $.bit_string_segment),
","
)
),
">>"
),
[`${name}_bit_string_segment`]: ($) =>
seq(
field("value", $[value_parser]),
optional(
field(
"options",
seq(
":",
alias(
$[`${name}_bit_string_segment_options`],
$.bit_string_segment_options
)
)
)
)
),
...bit_string_segment_options(name, arg_parser),
};
}
function bit_string_segment_options(name, arg_parser) {
return {
[`${name}_bit_string_segment_options`]: ($) =>
series_of($[`_${name}_bit_string_segment_option`], "-"),
[`_${name}_bit_string_segment_option`]: ($) =>
choice($[`_${name}_bit_string_named_segment_option`], $.integer),
[`_${name}_bit_string_named_segment_option`]: ($) =>
alias(
choice(
$._bit_string_segment_option,
$[`_${name}_bit_string_segment_option_size`]
),
$.bit_string_segment_option
),
[`_${name}_bit_string_segment_option_size`]: ($) =>
seq("size", "(", $[arg_parser], ")"),
};
}
// Shamelessly stolen "sep1" from tree-sitter-elixir, renamed to match a similar
// function in the Gleam parser.
// https://github.com/elixir-lang/tree-sitter-elixir/blob/de3ec57591aebf451e710fc9c984cf601258baf5/grammar.js#L817-L819
function series_of(rule, separator) {
return seq(rule, repeat(seq(separator, rule)), optional(separator));
}
// A binary expression with a left-hand side, infix operator, and then right-hand-side
// https://github.com/elixir-lang/tree-sitter-elixir/blob/de20391afe5cb03ef1e8a8e43167e7b58cc52869/grammar.js#L850-L859
function binaryExpr(assoc, precedence, operator, left, right = null) {
return assoc(
precedence,
seq(
field("left", left),
field("operator", operator),
field("right", right || left)
)
);
}

File diff suppressed because it is too large Load Diff

@ -1,46 +0,0 @@
{
"name": "tree-sitter-gleam",
"version": "1.0.0",
"description": "A tree-sitter grammar for the Gleam programming language",
"main": "bindings/node",
"scripts": {
"generate": "tree-sitter generate",
"test": "tree-sitter test",
"format": "prettier --write grammar.js",
"check-formatted": "prettier --check grammar.js",
"build-wasm": "tree-sitter build-wasm"
},
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/J3RN/tree-sitter-gleam.git"
},
"keywords": [
"gleam",
"parser",
"lexer",
"tree-sitter"
],
"author": "Jonathan Arnett",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/J3RN/tree-sitter-gleam/issues"
},
"homepage": "https://github.com/J3RN/tree-sitter-gleam#readme",
"dependencies": {
"nan": "^2.18.0"
},
"devDependencies": {
"prettier": "^2.5.1",
"tree-sitter-cli": "^0.20.6",
"node-gyp": "^10.0.1"
},
"tree-sitter": [
{
"scope": "source.gleam",
"file-types": [
"gleam"
],
"injection-regex": "^gleam$"
}
]
}

@ -1,131 +0,0 @@
; Comments
(module_comment) @comment
(statement_comment) @comment
(comment) @comment
; Constants
(constant
name: (identifier) @constant)
; Modules
(module) @module
(import alias: (identifier) @module)
(remote_type_identifier
module: (identifier) @module)
(remote_constructor_name
module: (identifier) @module)
((field_access
record: (identifier) @module
field: (label) @function)
(#is-not? local))
; Functions
(unqualified_import (identifier) @function)
(unqualified_import "type" (type_identifier) @type)
(unqualified_import (type_identifier) @constructor)
(function
name: (identifier) @function)
(external_function
name: (identifier) @function)
(function_parameter
name: (identifier) @variable.parameter)
((function_call
function: (identifier) @function)
(#is-not? local))
((binary_expression
operator: "|>"
right: (identifier) @function)
(#is-not? local))
; "Properties"
; Assumed to be intended to refer to a name for a field; something that comes
; before ":" or after "."
; e.g. record field names, tuple indices, names for named arguments, etc
(label) @property
(tuple_access
index: (integer) @property)
; Attributes
(attribute
"@" @attribute
name: (identifier) @attribute)
(attribute_value (identifier) @constant)
; Type names
(remote_type_identifier) @type
(type_identifier) @type
; Data constructors
(constructor_name) @constructor
; Literals
(string) @string
((escape_sequence) @warning
; Deprecated in v0.33.0-rc2:
(#eq? @warning "\\e"))
(escape_sequence) @string.escape
(bit_string_segment_option) @function.builtin
(integer) @number
(float) @number
; Reserved identifiers
; TODO: when tree-sitter supports `#any-of?` in the Rust bindings,
; refactor this to use `#any-of?` rather than `#match?`
((identifier) @error
(#match? @error "^(auto|delegate|derive|else|implement|macro|test)$"))
; Variables
(identifier) @variable
(discard) @comment.unused
; Keywords
[
(visibility_modifier) ; "pub"
(opacity_modifier) ; "opaque"
"as"
"assert"
"case"
"const"
"echo"
; DEPRECATED: 'external' was removed in v0.30.
"external"
"fn"
"if"
"import"
"let"
"panic"
"todo"
"type"
"use"
] @keyword
; Operators
(binary_expression
operator: _ @operator)
(boolean_negation "!" @operator)
(integer_negation "-" @operator)
; Punctuation
[
"("
")"
"["
"]"
"{"
"}"
"<<"
">>"
] @punctuation.bracket
[
"."
","
;; Controversial -- maybe some are operators?
":"
"#"
"="
"->"
".."
"-"
"<-"
] @punctuation.delimiter

@ -1,17 +0,0 @@
; Scopes
(block) @local.scope
(function) @local.scope
(case_clause) @local.scope
; Definitions
(let pattern: (identifier) @local.definition)
(function_parameter name: (identifier) @local.definition)
(list_pattern (identifier) @local.definition)
(list_pattern assign: (identifier) @local.definition)
(tuple_pattern (identifier) @local.definition)
(record_pattern_argument pattern: (identifier) @local.definition)
; References
(identifier) @local.reference

@ -1,41 +0,0 @@
; Modules
(module) @name @reference.module
(import alias: (identifier) @name) @reference.module
(remote_type_identifier
module: (identifier) @name) @reference.module
((field_access
record: (identifier) @name)
(#is-not? local)) @reference.module
; Functions
(function
name: (identifier) @name) @definition.function
(external_function
name: (identifier) @name) @definition.function
(unqualified_import (identifier) @name) @reference.function
((function_call
function: (identifier) @name) @reference.function
(#is-not? local))
((field_access
record: (identifier) @ignore
field: (label) @name)
(#is-not? local)) @reference.function
((binary_expression
operator: "|>"
right: (identifier) @name)
(#is-not? local)) @reference.function
; Types
(type_definition
(type_name
name: (type_identifier) @name)) @definition.type
(type_definition
(data_constructors
(data_constructor
name: (constructor_name) @name))) @definition.constructor
(external_type
(type_name
name: (type_identifier) @name)) @definition.type
(type_identifier) @name @reference.type
(constructor_name) @name @reference.constructor

@ -1,24 +0,0 @@
#! /usr/bin/env bash
set -e
cd "$(dirname "$0")/.."
usage() {
echo "$0"
echo ""
echo "Tests that the parser does not create error nodes"
echo "when tested against real Gleam repos"
echo ""
exit 1
}
if [ $# -ne 0 ]; then
usage
fi
repos="gleam-lang/stdlib gleam-lang/json gleam-lang/http gleam-lang/example-todomvc gleam-lang/bitwise gleam-lang/erlang gleam-lang/otp gleam-lang/cowboy gleam-lang/hackney gleam-lang/httpc gleam-lang/elli gleam-lang/javascript gleam-lang/example-echo-server gleam-lang/plug"
for repo in $repos; do
./scripts/parse_repo.sh $repo
done

@ -1,29 +0,0 @@
#! /usr/bin/env bash
set -e
cd "$(dirname "$0")/.."
usage() {
echo "$0 owner/repository"
echo ""
echo "Runs the parser against Gleam files in a GitHub repository"
echo ""
exit 1
}
if [ $# -ne 1 ]; then
usage
fi
gh_repo="$1"
dir="test/integration/${gh_repo//[\/-]/_}"
if [[ ! -d "$dir" ]]; then
mkdir -p "$(dirname "$dir")"
git clone --depth 1 "https://github.com/$gh_repo.git" "$dir"
fi
echo "Running parser against $gh_repo"
npx tree-sitter parse --quiet --stat "$dir/**/*.gleam"

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,29 +0,0 @@
#include <tree_sitter/parser.h>
enum TokenType {
QUOTED_CONTENT
};
void * tree_sitter_gleam_external_scanner_create() {return NULL;}
void tree_sitter_gleam_external_scanner_destroy(void * payload) {}
unsigned tree_sitter_gleam_external_scanner_serialize(void * payload, char * buffer) {return 0;}
void tree_sitter_gleam_external_scanner_deserialize(void * payload, const char * buffer, unsigned length) {}
bool tree_sitter_gleam_external_scanner_scan(void * payload, TSLexer *lexer, const bool * valid_symbols) {
if (valid_symbols[QUOTED_CONTENT]) {
bool has_content = false;
while (true) {
if (lexer->lookahead == '\"' || lexer->lookahead == '\\') {
break;
} else if (lexer->lookahead == 0) {
return false;
}
has_content = true;
lexer->advance(lexer, false);
}
lexer->result_symbol = QUOTED_CONTENT;
return has_content;
}
return false;
}

@ -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,101 +0,0 @@
================================================================================
Target attribute
================================================================================
@target(erlang)
pub fn main() { todo }
--------------------------------------------------------------------------------
(source_file
(attribute
name: (identifier)
arguments: (arguments
(attribute_value
(identifier))))
(function
(visibility_modifier)
name: (identifier)
parameters: (function_parameters)
body: (block
(todo))))
================================================================================
Attribute with multiple values
================================================================================
@deprecated(since: "1.2.0", replacement: wobble)
pub fn wibble() { todo }
--------------------------------------------------------------------------------
(source_file
(attribute
name: (identifier)
arguments: (arguments
(attribute_value
label: (label)
value: (string
(quoted_content)))
(attribute_value
label: (label)
value: (identifier))))
(function
(visibility_modifier)
name: (identifier)
parameters: (function_parameters)
body: (block
(todo))))
================================================================================
Attribute without arguments
================================================================================
@internal
pub fn wibble() { todo }
--------------------------------------------------------------------------------
(source_file
(attribute
name: (identifier))
(function
(visibility_modifier)
name: (identifier)
parameters: (function_parameters)
body: (block
(todo))))
================================================================================
Individually deprecated constructors
================================================================================
pub type SomeType {
NotDeprecated
@deprecated("Please use the NotDeprecated variant")
Deprecated(reason: String)
}
--------------------------------------------------------------------------------
(source_file
(type_definition
(visibility_modifier)
(type_name
name: (type_identifier))
(data_constructors
(data_constructor
name: (constructor_name))
(data_constructor
(attribute
name: (identifier)
arguments: (arguments
(attribute_value
(string
(quoted_content)))))
name: (constructor_name)
arguments: (data_constructor_arguments
(data_constructor_argument
label: (label)
value: (type
name: (type_identifier))))))))

@ -1,255 +0,0 @@
================================================================================
Case examples
================================================================================
case value {
"A" -> True
_ -> False
}
case value {}
--------------------------------------------------------------------------------
(source_file
(case
(case_subjects
(identifier))
(case_clauses
(case_clause
(case_clause_patterns
(case_clause_pattern
(string
(quoted_content))))
(record
(constructor_name)))
(case_clause
(case_clause_patterns
(case_clause_pattern
(discard)))
(record
(constructor_name)))))
(case
(case_subjects
(identifier))))
================================================================================
Case examples
================================================================================
// From https://gleam.run/news/v0.31-keeping-dependencies-explicit/#quality-of-life-improvements
pub fn listed(names: List(String), person: Person) -> String {
case names {
[name, ..names] if name == person.name -> True
[_, ..names] -> listed(names, person)
[] -> False
}
}
--------------------------------------------------------------------------------
(source_file
(comment)
(function
(visibility_modifier)
(identifier)
(function_parameters
(function_parameter
(identifier)
(type
(type_identifier)
(type_arguments
(type_argument
(type
(type_identifier))))))
(function_parameter
(identifier)
(type
(type_identifier))))
(type
(type_identifier))
(block
(case
(case_subjects
(identifier))
(case_clauses
(case_clause
(case_clause_patterns
(case_clause_pattern
(list_pattern
(identifier)
(list_pattern_tail
(identifier)))))
(case_clause_guard
(binary_expression
(identifier)
(field_access
(identifier)
(label))))
(record
(constructor_name)))
(case_clause
(case_clause_patterns
(case_clause_pattern
(list_pattern
(discard)
(list_pattern_tail
(identifier)))))
(function_call
(identifier)
(arguments
(argument
(identifier))
(argument
(identifier)))))
(case_clause
(case_clause_patterns
(case_clause_pattern
(list_pattern)))
(record
(constructor_name))))))))
================================================================================
Pattern matching binaries with 'as'
================================================================================
// From https://gleam.run/news/v0.31-keeping-dependencies-explicit/#quality-of-life-improvements
case tag {
"category " as key <> value
| "region " as key <> value
| "priority " as key <> value -> {
let key = string.trim(key)
Ok(Tag(key, value))
}
_ -> Error(Nil)
}
--------------------------------------------------------------------------------
(source_file
(comment)
(case
(case_subjects
(identifier))
(case_clauses
(case_clause
(case_clause_patterns
(case_clause_pattern
(binary_expression
(binary_expression
(string
(quoted_content))
(identifier))
(identifier)))
(case_clause_pattern
(binary_expression
(binary_expression
(string
(quoted_content))
(identifier))
(identifier)))
(case_clause_pattern
(binary_expression
(binary_expression
(string
(quoted_content))
(identifier))
(identifier))))
(block
(let
(identifier)
(function_call
(field_access
(identifier)
(label))
(arguments
(argument
(identifier)))))
(record
(constructor_name)
(arguments
(argument
(record
(constructor_name)
(arguments
(argument
(identifier))
(argument
(identifier)))))))))
(case_clause
(case_clause_patterns
(case_clause_pattern
(discard)))
(record
(constructor_name)
(arguments
(argument
(record
(constructor_name)))))))))
================================================================================
Case with boolean negation in a guard
================================================================================
case var {
1 if !other_var -> True
_ -> False
}
--------------------------------------------------------------------------------
(source_file
(case
(case_subjects
(identifier))
(case_clauses
(case_clause
(case_clause_patterns
(case_clause_pattern
(integer)))
(case_clause_guard
(boolean_negation
(identifier)))
(record
(constructor_name)))
(case_clause
(case_clause_patterns
(case_clause_pattern
(discard)))
(record
(constructor_name))))))
================================================================================
Case with int remainder in guard
================================================================================
case var {
_ if 11 % 2 == 0 -> True
_ -> False
}
--------------------------------------------------------------------------------
(source_file
(case
(case_subjects
(identifier))
(case_clauses
(case_clause
(case_clause_patterns
(case_clause_pattern
(discard)))
(case_clause_guard
(binary_expression
(binary_expression
(integer)
(integer))
(integer)))
(record
(constructor_name)))
(case_clause
(case_clause_patterns
(case_clause_pattern
(discard)))
(record
(constructor_name))))))

@ -1,465 +0,0 @@
================================================================================
Constants
================================================================================
const a = "hello"
const a = "hello\nworld!"
const a = 1_234
const a = 0b110
const a = 0o7224
const a = 0xBEef
const a: Int = 1234
const a: Float = -1_234.53__23
const a: Float = 0.
const a: #(Int, String) = #(1, "Hello!")
const a: #() = #()
const a: List(Int) = [1, 2]
const a: List(_) = []
const a = <<3>>
const a = <<0:4, 1:3, 1:1>>
const a = <<3:size(8)>>
const a = <<52:size(4)-unit(4)>>
const a = <<"Hello Gleam 💫":utf8>>
const a = Node
const a = Node()
const a = Cat("Ginny", 1950)
const a = Person(name: "Billy", age: 52)
const a = uri.Uri(host: "github.com")
const a: option.Option(String) = option.Some("Hello, World!")
const var_alias = b
const int_identity_alias: fn(Int) -> Int = int_identity
const fun_tuple: #(fn(Float) -> String, fn(Int) -> String) = #(float.to_string, int.to_string)
--------------------------------------------------------------------------------
(source_file
(constant
name: (identifier)
value: (string
(quoted_content)))
(constant
name: (identifier)
value: (string
(quoted_content)
(escape_sequence)
(quoted_content)))
(constant
name: (identifier)
value: (integer))
(constant
name: (identifier)
value: (integer))
(constant
name: (identifier)
value: (integer))
(constant
name: (identifier)
value: (integer))
(constant
name: (identifier)
type: (type
name: (type_identifier))
value: (integer))
(constant
name: (identifier)
type: (type
name: (type_identifier))
value: (float))
(constant
name: (identifier)
type: (type
name: (type_identifier))
value: (float))
(constant
name: (identifier)
type: (tuple_type
(type
name: (type_identifier))
(type
name: (type_identifier)))
value: (tuple
(integer)
(string
(quoted_content))))
(constant
name: (identifier)
type: (tuple_type)
value: (tuple))
(constant
name: (identifier)
type: (type
name: (type_identifier)
arguments: (type_arguments
(type_argument
(type
name: (type_identifier)))))
value: (list
(integer)
(integer)))
(constant
name: (identifier)
type: (type
name: (type_identifier)
arguments: (type_arguments
(type_argument
(type_hole))))
value: (list))
(constant
name: (identifier)
value: (bit_string
(bit_string_segment
value: (integer))))
(constant
name: (identifier)
value: (bit_string
(bit_string_segment
value: (integer)
options: (bit_string_segment_options
(integer)))
(bit_string_segment
value: (integer)
options: (bit_string_segment_options
(integer)))
(bit_string_segment
value: (integer)
options: (bit_string_segment_options
(integer)))))
(constant
name: (identifier)
value: (bit_string
(bit_string_segment
value: (integer)
options: (bit_string_segment_options
(bit_string_segment_option
(integer))))))
(constant
name: (identifier)
value: (bit_string
(bit_string_segment
value: (integer)
options: (bit_string_segment_options
(bit_string_segment_option
(integer))
(bit_string_segment_option
(integer))))))
(constant
name: (identifier)
value: (bit_string
(bit_string_segment
value: (string
(quoted_content))
options: (bit_string_segment_options
(bit_string_segment_option)))))
(constant
name: (identifier)
value: (record
name: (constructor_name)))
(constant
name: (identifier)
value: (record
name: (constructor_name)
arguments: (arguments)))
(constant
name: (identifier)
value: (record
name: (constructor_name)
arguments: (arguments
(argument
value: (string
(quoted_content)))
(argument
value: (integer)))))
(constant
name: (identifier)
value: (record
name: (constructor_name)
arguments: (arguments
(argument
label: (label)
value: (string
(quoted_content)))
(argument
label: (label)
value: (integer)))))
(constant
name: (identifier)
value: (record
name: (remote_constructor_name
module: (identifier)
name: (constructor_name))
arguments: (arguments
(argument
label: (label)
value: (string
(quoted_content))))))
(constant
name: (identifier)
type: (type
name: (remote_type_identifier
module: (identifier)
name: (type_identifier))
arguments: (type_arguments
(type_argument
(type
name: (type_identifier)))))
value: (record
name: (remote_constructor_name
module: (identifier)
name: (constructor_name))
arguments: (arguments
(argument
value: (string
(quoted_content))))))
(constant
name: (identifier)
value: (identifier))
(constant
name: (identifier)
type: (function_type
parameter_types: (function_parameter_types
(type
name: (type_identifier)))
return_type: (type
name: (type_identifier)))
value: (identifier))
(constant
name: (identifier)
type: (tuple_type
(function_type
parameter_types: (function_parameter_types
(type
name: (type_identifier)))
return_type: (type
name: (type_identifier)))
(function_type
parameter_types: (function_parameter_types
(type
name: (type_identifier)))
return_type: (type
name: (type_identifier))))
value: (tuple
(field_access
record: (identifier)
field: (label))
(field_access
record: (identifier)
field: (label)))))
================================================================================
Public constants
================================================================================
pub const a = "hello"
pub const a: Int = 1234
pub const a: Float = -1_234.53__23
pub const a: #(Int, String) = #(1, "Hello!")
pub const a: #() = #()
pub const a: List(Int) = [1, 2]
pub const a: List(_) = []
pub const a = <<3>>
pub const a = <<0:4, 1:3, 1:1>>
pub const a = <<3:size(8)>>
pub const a = <<52:size(4)-unit(4)>>
pub const a = <<"Hello Gleam 💫":utf8>>
pub const a = Node
pub const a = Node()
pub const a = Cat("Ginny", 1950)
pub const a = Person(name: "Billy", age: 52)
pub const a = uri.Uri(host: "github.com")
--------------------------------------------------------------------------------
(source_file
(constant
(visibility_modifier)
name: (identifier)
value: (string
(quoted_content)))
(constant
(visibility_modifier)
name: (identifier)
type: (type
name: (type_identifier))
value: (integer))
(constant
(visibility_modifier)
name: (identifier)
type: (type
name: (type_identifier))
value: (float))
(constant
(visibility_modifier)
name: (identifier)
type: (tuple_type
(type
name: (type_identifier))
(type
name: (type_identifier)))
value: (tuple
(integer)
(string
(quoted_content))))
(constant
(visibility_modifier)
name: (identifier)
type: (tuple_type)
value: (tuple))
(constant
(visibility_modifier)
name: (identifier)
type: (type
name: (type_identifier)
arguments: (type_arguments
(type_argument
(type
name: (type_identifier)))))
value: (list
(integer)
(integer)))
(constant
(visibility_modifier)
name: (identifier)
type: (type
name: (type_identifier)
arguments: (type_arguments
(type_argument
(type_hole))))
value: (list))
(constant
(visibility_modifier)
name: (identifier)
value: (bit_string
(bit_string_segment
value: (integer))))
(constant
(visibility_modifier)
name: (identifier)
value: (bit_string
(bit_string_segment
value: (integer)
options: (bit_string_segment_options
(integer)))
(bit_string_segment
value: (integer)
options: (bit_string_segment_options
(integer)))
(bit_string_segment
value: (integer)
options: (bit_string_segment_options
(integer)))))
(constant
(visibility_modifier)
name: (identifier)
value: (bit_string
(bit_string_segment
value: (integer)
options: (bit_string_segment_options
(bit_string_segment_option
(integer))))))
(constant
(visibility_modifier)
name: (identifier)
value: (bit_string
(bit_string_segment
value: (integer)
options: (bit_string_segment_options
(bit_string_segment_option
(integer))
(bit_string_segment_option
(integer))))))
(constant
(visibility_modifier)
name: (identifier)
value: (bit_string
(bit_string_segment
value: (string
(quoted_content))
options: (bit_string_segment_options
(bit_string_segment_option)))))
(constant
(visibility_modifier)
name: (identifier)
value: (record
name: (constructor_name)))
(constant
(visibility_modifier)
name: (identifier)
value: (record
name: (constructor_name)
arguments: (arguments)))
(constant
(visibility_modifier)
name: (identifier)
value: (record
name: (constructor_name)
arguments: (arguments
(argument
value: (string
(quoted_content)))
(argument
value: (integer)))))
(constant
(visibility_modifier)
name: (identifier)
value: (record
name: (constructor_name)
arguments: (arguments
(argument
label: (label)
value: (string
(quoted_content)))
(argument
label: (label)
value: (integer)))))
(constant
(visibility_modifier)
name: (identifier)
value: (record
name: (remote_constructor_name
module: (identifier)
name: (constructor_name))
arguments: (arguments
(argument
label: (label)
value: (string
(quoted_content)))))))
================================================================================
Scientific notation
================================================================================
const a = 0.0e0
const a = 1.0e123_456
const a = -100.001e-1_230
--------------------------------------------------------------------------------
(source_file
(constant
(identifier)
(float))
(constant
(identifier)
(float))
(constant
(identifier)
(float)))
================================================================================
Constant with shorthand labels
================================================================================
const b = Wibble(arg:, arg:)
--------------------------------------------------------------------------------
(source_file
(constant
(identifier)
(record
(constructor_name)
(arguments
(argument
(label))
(argument
(label))))))

@ -1,272 +0,0 @@
================================================================================
Parser example custom types
================================================================================
type A { A }
type A { A(String) }
type Box(inner_type) { Box(inner: inner_type) }
type NamedBox(inner_type) { Box(String, inner: inner_type) }
--------------------------------------------------------------------------------
(source_file
(type_definition
(type_name
name: (type_identifier))
(data_constructors
(data_constructor
name: (constructor_name))))
(type_definition
(type_name
name: (type_identifier))
(data_constructors
(data_constructor
name: (constructor_name)
arguments: (data_constructor_arguments
(data_constructor_argument
value: (type
name: (type_identifier)))))))
(type_definition
(type_name
name: (type_identifier)
parameters: (type_parameters
(type_parameter)))
(data_constructors
(data_constructor
name: (constructor_name)
arguments: (data_constructor_arguments
(data_constructor_argument
label: (label)
value: (type_var))))))
(type_definition
(type_name
name: (type_identifier)
parameters: (type_parameters
(type_parameter)))
(data_constructors
(data_constructor
name: (constructor_name)
arguments: (data_constructor_arguments
(data_constructor_argument
value: (type
name: (type_identifier)))
(data_constructor_argument
label: (label)
value: (type_var)))))))
================================================================================
Other custom type examples
================================================================================
type Cat {
Cat(name: String, cuteness: Int)
}
type Animal() {
Cat(name: String, cuteness: Int)
Dog(name: String, cuteness: Int)
}
type Result(success_type, failure_type) {
Ok(success_type)
Error(failure_type)
}
type Ord {
LT
EQ
GT
}
type Boring {
Boring
}
--------------------------------------------------------------------------------
(source_file
(type_definition
(type_name
name: (type_identifier))
(data_constructors
(data_constructor
name: (constructor_name)
arguments: (data_constructor_arguments
(data_constructor_argument
label: (label)
value: (type
name: (type_identifier)))
(data_constructor_argument
label: (label)
value: (type
name: (type_identifier)))))))
(type_definition
(type_name
name: (type_identifier)
parameters: (type_parameters))
(data_constructors
(data_constructor
name: (constructor_name)
arguments: (data_constructor_arguments
(data_constructor_argument
label: (label)
value: (type
name: (type_identifier)))
(data_constructor_argument
label: (label)
value: (type
name: (type_identifier)))))
(data_constructor
name: (constructor_name)
arguments: (data_constructor_arguments
(data_constructor_argument
label: (label)
value: (type
name: (type_identifier)))
(data_constructor_argument
label: (label)
value: (type
name: (type_identifier)))))))
(type_definition
(type_name
name: (type_identifier)
parameters: (type_parameters
(type_parameter)
(type_parameter)))
(data_constructors
(data_constructor
name: (constructor_name)
arguments: (data_constructor_arguments
(data_constructor_argument
value: (type_var))))
(data_constructor
name: (constructor_name)
arguments: (data_constructor_arguments
(data_constructor_argument
value: (type_var))))))
(type_definition
(type_name
name: (type_identifier))
(data_constructors
(data_constructor
name: (constructor_name))
(data_constructor
name: (constructor_name))
(data_constructor
name: (constructor_name))))
(type_definition
(type_name
name: (type_identifier))
(data_constructors
(data_constructor
name: (constructor_name)))))
================================================================================
Public custom type definitions
================================================================================
pub type Animal(name, cuteness) {
Cat(name: String, cuteness: Int)
Dog(name: String, cuteness: Int)
}
--------------------------------------------------------------------------------
(source_file
(type_definition
(visibility_modifier)
(type_name
name: (type_identifier)
parameters: (type_parameters
(type_parameter)
(type_parameter)))
(data_constructors
(data_constructor
name: (constructor_name)
arguments: (data_constructor_arguments
(data_constructor_argument
label: (label)
value: (type
name: (type_identifier)))
(data_constructor_argument
label: (label)
value: (type
name: (type_identifier)))))
(data_constructor
name: (constructor_name)
arguments: (data_constructor_arguments
(data_constructor_argument
label: (label)
value: (type
name: (type_identifier)))
(data_constructor_argument
label: (label)
value: (type
name: (type_identifier))))))))
================================================================================
Public opaque custom type definitions
================================================================================
pub opaque type Animal(name, cuteness) {
Cat(name: String, cuteness: Int)
Dog(name: String, cuteness: Int)
}
--------------------------------------------------------------------------------
(source_file
(type_definition
(visibility_modifier)
(opacity_modifier)
(type_name
name: (type_identifier)
parameters: (type_parameters
(type_parameter)
(type_parameter)))
(data_constructors
(data_constructor
name: (constructor_name)
arguments: (data_constructor_arguments
(data_constructor_argument
label: (label)
value: (type
name: (type_identifier)))
(data_constructor_argument
label: (label)
value: (type
name: (type_identifier)))))
(data_constructor
name: (constructor_name)
arguments: (data_constructor_arguments
(data_constructor_argument
label: (label)
value: (type
name: (type_identifier)))
(data_constructor_argument
label: (label)
value: (type
name: (type_identifier))))))))
================================================================================
Record update with shorthand labels
================================================================================
Wibble(..wibble, arg:, arg:, arg: todo as "no shorthand")
--------------------------------------------------------------------------------
(source_file
(record_update
(constructor_name)
(identifier)
(record_update_arguments
(record_update_argument
(label))
(record_update_argument
(label))
(record_update_argument
(label)
(todo
(string
(quoted_content)))))))

@ -1,78 +0,0 @@
================================================================================
Case with spread
================================================================================
pub fn main() {
case xs {
[[]] -> io.println("one")
[[], ..] -> io.println("many")
}
}
--------------------------------------------------------------------------------
(source_file
(function
(visibility_modifier)
(identifier)
(function_parameters)
(block
(case
(case_subjects
(identifier))
(case_clauses
(case_clause
(case_clause_patterns
(case_clause_pattern
(list_pattern
(list_pattern))))
(function_call
(field_access
(identifier)
(label))
(arguments
(argument
(string
(quoted_content))))))
(case_clause
(case_clause_patterns
(case_clause_pattern
(list_pattern
(list_pattern)
(list_pattern_tail))))
(function_call
(field_access
(identifier)
(label))
(arguments
(argument
(string
(quoted_content)))))))))))
================================================================================
Pattern with label shorthand
================================================================================
pub fn main() {
let Wibble(arg1:, arg2:) = todo as "a"
}
--------------------------------------------------------------------------------
(source_file
(function
(visibility_modifier)
(identifier)
(function_parameters)
(block
(let
(record_pattern
(constructor_name)
(record_pattern_arguments
(record_pattern_argument
(label))
(record_pattern_argument
(label))))
(todo
(string
(quoted_content)))))))

@ -1,112 +0,0 @@
================================================================================
Echo with expression
================================================================================
pub fn main() {
echo 1
}
--------------------------------------------------------------------------------
(source_file
(function
(visibility_modifier)
(identifier)
(function_parameters)
(block
(echo
(integer)))))
================================================================================
Echo in pipeline
================================================================================
pub fn main() {
[]
|> echo
|> panic
}
--------------------------------------------------------------------------------
(source_file
(function
(visibility_modifier)
(identifier)
(function_parameters)
(block
(binary_expression
(binary_expression
(list)
(pipeline_echo))
(panic)))))
================================================================================
Echo last in pipeline
================================================================================
pub fn main() {
[]
|> echo
1
}
--------------------------------------------------------------------------------
(source_file
(function
(visibility_modifier)
(identifier)
(function_parameters)
(block
(binary_expression
(list)
(pipeline_echo))
(integer))))
================================================================================
Echo precedence with pipes
================================================================================
pub fn main() {
echo 1 |> 2
3
}
--------------------------------------------------------------------------------
(source_file
(function
(visibility_modifier)
(identifier)
(function_parameters)
(block
(echo
(binary_expression
(integer)
(integer)))
(integer))))
================================================================================
Echo precedence with binop
================================================================================
pub fn main() {
echo 1 + 2
3
}
--------------------------------------------------------------------------------
(source_file
(function
(visibility_modifier)
(identifier)
(function_parameters)
(block
(echo
(binary_expression
(integer)
(integer)))
(integer))))

@ -1,179 +0,0 @@
================================================================================
Bit-string expression
================================================================================
<<code:int-size(8)-unit(2), reason:utf8>>
--------------------------------------------------------------------------------
(source_file
(bit_string
(bit_string_segment
(identifier)
(bit_string_segment_options
(bit_string_segment_option)
(bit_string_segment_option
(integer))
(bit_string_segment_option
(integer))))
(bit_string_segment
(identifier)
(bit_string_segment_options
(bit_string_segment_option)))))
================================================================================
Boolean Negation
================================================================================
!False
True && !False
--------------------------------------------------------------------------------
(source_file
(boolean_negation
(record
(constructor_name)))
(binary_expression
(record
(constructor_name))
(boolean_negation
(record
(constructor_name)))))
================================================================================
Integer Negation
================================================================================
{-x}
{-{5*30}}
{-my_fun()}
--------------------------------------------------------------------------------
(source_file
(block
(integer_negation
(identifier)))
(block
(integer_negation
(block
(binary_expression
(integer)
(integer)))))
(block
(integer_negation
(function_call
(identifier)
(arguments)))))
================================================================================
Concatenation
================================================================================
let concat = "a" <> "b"
case "12345" {
"0" <> rest -> rest
"12" <> "34" <> "5" -> "match"
_ -> ""
}
--------------------------------------------------------------------------------
(source_file
(let
(identifier)
(binary_expression
(string
(quoted_content))
(string
(quoted_content))))
(case
(case_subjects
(string
(quoted_content)))
(case_clauses
(case_clause
(case_clause_patterns
(case_clause_pattern
(binary_expression
(string
(quoted_content))
(identifier))))
(identifier))
(case_clause
(case_clause_patterns
(case_clause_pattern
(binary_expression
(binary_expression
(string
(quoted_content))
(string
(quoted_content)))
(string
(quoted_content)))))
(string
(quoted_content)))
(case_clause
(case_clause_patterns
(case_clause_pattern
(discard)))
(string)))))
================================================================================
Todo and panic 'as' with string expressions
================================================================================
todo as { "Hello, " <> "world!" }
panic as { "Hello, " <> "world!" }
--------------------------------------------------------------------------------
(source_file
(todo
(block
(binary_expression
(string
(quoted_content))
(string
(quoted_content)))))
(panic
(block
(binary_expression
(string
(quoted_content))
(string
(quoted_content))))))
================================================================================
Todo and panic in function application style
================================================================================
todo("don't panic")
panic("aaaah!")
--------------------------------------------------------------------------------
(source_file
(todo
(string
(quoted_content)))
(panic
(string
(quoted_content))))
================================================================================
Nested field access
================================================================================
config.connection.host
--------------------------------------------------------------------------------
(source_file
(field_access
(field_access
(identifier)
(label))
(label)))

@ -1,175 +0,0 @@
================================================================================
External functions
================================================================================
external fn read_file(String) -> Result(String, Reason) =
"file" "open"
external fn a(name: String) -> String = "x" "y"
external fn a() -> #(List(Int), fn(Int) -> String) = "x" "y"
--------------------------------------------------------------------------------
(source_file
(external_function
name: (identifier)
parameters: (function_parameters
(function_parameter
type: (type
name: (type_identifier))))
return_type: (type
name: (type_identifier)
arguments: (type_arguments
(type_argument
(type
name: (type_identifier)))
(type_argument
(type
name: (type_identifier)))))
body: (external_function_body
(string
(quoted_content))
(string
(quoted_content))))
(external_function
name: (identifier)
parameters: (function_parameters
(function_parameter
name: (identifier)
type: (type
name: (type_identifier))))
return_type: (type
name: (type_identifier))
body: (external_function_body
(string
(quoted_content))
(string
(quoted_content))))
(external_function
name: (identifier)
parameters: (function_parameters)
return_type: (tuple_type
(type
name: (type_identifier)
arguments: (type_arguments
(type_argument
(type
name: (type_identifier)))))
(function_type
parameter_types: (function_parameter_types
(type
name: (type_identifier)))
return_type: (type
name: (type_identifier))))
body: (external_function_body
(string
(quoted_content))
(string
(quoted_content)))))
================================================================================
Public external functions
================================================================================
pub external fn read_file(String) -> Result(String, Reason) =
"file" "open"
pub external fn a(name: String) -> String = "x" "y"
pub external fn a() -> #(List(Int), fn(Int) -> String) = "x" "y"
--------------------------------------------------------------------------------
(source_file
(external_function
(visibility_modifier)
name: (identifier)
parameters: (function_parameters
(function_parameter
type: (type
name: (type_identifier))))
return_type: (type
name: (type_identifier)
arguments: (type_arguments
(type_argument
(type
name: (type_identifier)))
(type_argument
(type
name: (type_identifier)))))
body: (external_function_body
(string
(quoted_content))
(string
(quoted_content))))
(external_function
(visibility_modifier)
name: (identifier)
parameters: (function_parameters
(function_parameter
name: (identifier)
type: (type
name: (type_identifier))))
return_type: (type
name: (type_identifier))
body: (external_function_body
(string
(quoted_content))
(string
(quoted_content))))
(external_function
(visibility_modifier)
name: (identifier)
parameters: (function_parameters)
return_type: (tuple_type
(type
name: (type_identifier)
arguments: (type_arguments
(type_argument
(type
name: (type_identifier)))))
(function_type
parameter_types: (function_parameter_types
(type
name: (type_identifier)))
return_type: (type
name: (type_identifier))))
body: (external_function_body
(string
(quoted_content))
(string
(quoted_content)))))
================================================================================
External function with attribute syntax
================================================================================
@external(erlang, "erlang", "integer_to_list")
fn integer_to_list(int int: Int, base base: Int) -> String
---
(source_file
(attribute
(identifier)
(arguments
(attribute_value
(identifier))
(attribute_value
(string
(quoted_content)))
(attribute_value
(string
(quoted_content)))))
(function
(identifier)
(function_parameters
(function_parameter
(label)
(identifier)
(type
(type_identifier)))
(function_parameter
(label)
(identifier)
(type
(type_identifier))))
(type
(type_identifier))))

@ -1,52 +0,0 @@
================================================================================
External types
================================================================================
type IODevice
type IODevice()
type Map(key, value)
--------------------------------------------------------------------------------
(source_file
(external_type
(type_name
name: (type_identifier)))
(external_type
(type_name
name: (type_identifier)
parameters: (type_parameters)))
(external_type
(type_name
name: (type_identifier)
parameters: (type_parameters
(type_parameter)
(type_parameter)))))
================================================================================
Public external types
================================================================================
pub type IODevice
pub type IODevice()
pub type Map(key, value)
--------------------------------------------------------------------------------
(source_file
(external_type
(visibility_modifier)
(type_name
name: (type_identifier)))
(external_type
(visibility_modifier)
(type_name
name: (type_identifier)
parameters: (type_parameters)))
(external_type
(visibility_modifier)
(type_name
name: (type_identifier)
parameters: (type_parameters
(type_parameter)
(type_parameter)))))

File diff suppressed because it is too large Load Diff

@ -1,73 +0,0 @@
================================================================================
Guard Expressions
================================================================================
case value {
n if n + 1 > 10 -> True
n if n / 2 < 5 -> False
}
case value {
n if n -. 1.0 <. 10.0 -> True
n if n *. 2 >. 5 -> False
}
--------------------------------------------------------------------------------
(source_file
(case
(case_subjects
(identifier))
(case_clauses
(case_clause
(case_clause_patterns
(case_clause_pattern
(identifier)))
(case_clause_guard
(binary_expression
(binary_expression
(identifier)
(integer))
(integer)))
(record
(constructor_name)))
(case_clause
(case_clause_patterns
(case_clause_pattern
(identifier)))
(case_clause_guard
(binary_expression
(binary_expression
(identifier)
(integer))
(integer)))
(record
(constructor_name)))))
(case
(case_subjects
(identifier))
(case_clauses
(case_clause
(case_clause_patterns
(case_clause_pattern
(identifier)))
(case_clause_guard
(binary_expression
(binary_expression
(identifier)
(float))
(float)))
(record
(constructor_name)))
(case_clause
(case_clause_patterns
(case_clause_pattern
(identifier)))
(case_clause_guard
(binary_expression
(binary_expression
(identifier)
(integer))
(integer)))
(record
(constructor_name))))))

@ -1,144 +0,0 @@
================================================================================
Imports
================================================================================
import a
import a/b
--------------------------------------------------------------------------------
(source_file
(import
module: (module))
(import
module: (module)))
================================================================================
Unqualified imports
================================================================================
import a.{b}
import a/b.{c, d}
import a/b.{c as d, e}
import a/b.{c, D as E}
import a/b.{A as B, type C as D}
--------------------------------------------------------------------------------
(source_file
(import
module: (module)
imports: (unqualified_imports
(unqualified_import
name: (identifier))))
(import
module: (module)
imports: (unqualified_imports
(unqualified_import
name: (identifier))
(unqualified_import
name: (identifier))))
(import
module: (module)
imports: (unqualified_imports
(unqualified_import
name: (identifier)
alias: (identifier))
(unqualified_import
name: (identifier))))
(import
module: (module)
imports: (unqualified_imports
(unqualified_import
name: (identifier))
(unqualified_import
name: (constructor_name)
alias: (constructor_name))))
(import
module: (module)
imports: (unqualified_imports
(unqualified_import
name: (constructor_name)
alias: (constructor_name))
(unqualified_import
name: (type_identifier)
alias: (type_identifier)))))
================================================================================
Aliased imports
================================================================================
import a/b.{c as d} as e
import animal/cat as kitty
import animal.{Cat as Kitty} as a
import animal.{type Cat as Kitty} as a
import animal.{}
--------------------------------------------------------------------------------
(source_file
(import
module: (module)
imports: (unqualified_imports
(unqualified_import
name: (identifier)
alias: (identifier)))
alias: (identifier))
(import
module: (module)
alias: (identifier))
(import
module: (module)
imports: (unqualified_imports
(unqualified_import
name: (constructor_name)
alias: (constructor_name)))
alias: (identifier))
(import
module: (module)
imports: (unqualified_imports
(unqualified_import
name: (type_identifier)
alias: (type_identifier)))
alias: (identifier))
(import
module: (module)
imports: (unqualified_imports)))
================================================================================
Type imports
================================================================================
import a/b.{type C}
import animal.{type Cat as Kitty}
--------------------------------------------------------------------------------
(source_file
(import
module: (module)
imports: (unqualified_imports
(unqualified_import
name: (type_identifier))))
(import
module: (module)
imports: (unqualified_imports
(unqualified_import
name: (type_identifier)
alias: (type_identifier)))))
================================================================================
Discard module imports
================================================================================
import wibble.{wobble} as _
--------------------------------------------------------------------------------
(source_file
(import
(module)
(unqualified_imports
(unqualified_import
(identifier)))
(discard)))

@ -1,20 +0,0 @@
================================================================================
Pipes
================================================================================
string
|> iodata.new
|> iodata.reverse
--------------------------------------------------------------------------------
(source_file
(binary_expression
(binary_expression
(identifier)
(field_access
(identifier)
(label)))
(field_access
(identifier)
(label))))

@ -1,59 +0,0 @@
================================================================================
Use
================================================================================
use <- f()
use a <- f()
use a, b, c, d, e <- f()
use #(a, b) <- blah
use x : OfType <- f()
--------------------------------------------------------------------------------
(source_file
(use
(function_call
(identifier)
(arguments)))
(use
(use_assignments
(use_assignment
(identifier)))
(function_call
(identifier)
(arguments)))
(use
(use_assignments
(use_assignment
(identifier))
(use_assignment
(identifier))
(use_assignment
(identifier))
(use_assignment
(identifier))
(use_assignment
(identifier)))
(function_call
(identifier)
(arguments)))
(use
(use_assignments
(use_assignment
(tuple_pattern
(identifier)
(identifier))))
(identifier))
(use
(use_assignments
(use_assignment
(identifier)
(type
(type_identifier))))
(function_call
(identifier)
(arguments))))

@ -1,38 +0,0 @@
================================================================================
Escape sequences
================================================================================
"\t\t\r\nHello, CRLF!"
"¯\\_(ツ)_/¯"
"\"\""
"Hello, \e\f"
// 🏴‍☠️ is 🏴 and ☠️ joined with a zero-width joiner (U+200D)
"🏴‍☠️ == \u{1F3F4}\u{200D}\u{2620}\u{FE0F}"
--------------------------------------------------------------------------------
(source_file
(string
(escape_sequence)
(escape_sequence)
(escape_sequence)
(escape_sequence)
(quoted_content))
(string
(quoted_content)
(escape_sequence)
(quoted_content))
(string
(escape_sequence)
(escape_sequence))
(string
(quoted_content)
(escape_sequence)
(escape_sequence))
(comment)
(string
(quoted_content)
(escape_sequence)
(escape_sequence)
(escape_sequence)
(escape_sequence)))

@ -1,48 +0,0 @@
==============
Target groups
==============
if erlang {
const a = 1
}
if javascript {
const a = 1
const b = "Hello"
}
---
(source_file
(target_group
target: (target)
(constant
name: (identifier)
value: (integer)))
(target_group
target: (target)
(constant
name: (identifier)
value: (integer))
(constant
name: (identifier)
value: (string
(quoted_content)))))
========================
Target group edge cases
========================
if erlang {}
if javascript {const a = 1}
---
(source_file
(target_group
target: (target))
(target_group
target: (target)
(constant
name: (identifier)
value: (integer))))

@ -1,131 +0,0 @@
================================================================================
Type aliases
================================================================================
type Headers =
List(#(String, String))
type Box(a) = #(a)
type NamedBox(a) = #(String, a)
--------------------------------------------------------------------------------
(source_file
(type_alias
(type_name
name: (type_identifier))
(type
name: (type_identifier)
arguments: (type_arguments
(type_argument
(tuple_type
(type
name: (type_identifier))
(type
name: (type_identifier)))))))
(type_alias
(type_name
name: (type_identifier)
parameters: (type_parameters
(type_parameter)))
(tuple_type
(type_var)))
(type_alias
(type_name
name: (type_identifier)
parameters: (type_parameters
(type_parameter)))
(tuple_type
(type
name: (type_identifier))
(type_var))))
================================================================================
Public type aliases
================================================================================
pub type Headers =
List(#(String, String))
pub type Box(a) = #(a)
pub type NamedBox(a) = #(String, a)
--------------------------------------------------------------------------------
(source_file
(type_alias
(visibility_modifier)
(type_name
name: (type_identifier))
(type
name: (type_identifier)
arguments: (type_arguments
(type_argument
(tuple_type
(type
name: (type_identifier))
(type
name: (type_identifier)))))))
(type_alias
(visibility_modifier)
(type_name
name: (type_identifier)
parameters: (type_parameters
(type_parameter)))
(tuple_type
(type_var)))
(type_alias
(visibility_modifier)
(type_name
name: (type_identifier)
parameters: (type_parameters
(type_parameter)))
(tuple_type
(type
name: (type_identifier))
(type_var))))
================================================================================
Public opaque type aliases
================================================================================
pub opaque type Headers =
List(#(String, String))
pub opaque type Box(a) = #(a)
pub opaque type NamedBox(a) = #(String, a)
--------------------------------------------------------------------------------
(source_file
(type_alias
(visibility_modifier)
(opacity_modifier)
(type_name
name: (type_identifier))
(type
name: (type_identifier)
arguments: (type_arguments
(type_argument
(tuple_type
(type
name: (type_identifier))
(type
name: (type_identifier)))))))
(type_alias
(visibility_modifier)
(opacity_modifier)
(type_name
name: (type_identifier)
parameters: (type_parameters
(type_parameter)))
(tuple_type
(type_var)))
(type_alias
(visibility_modifier)
(opacity_modifier)
(type_name
name: (type_identifier)
parameters: (type_parameters
(type_parameter)))
(tuple_type
(type
name: (type_identifier))
(type_var))))

@ -1,323 +0,0 @@
================================================================================
Excerpt from stdlib's base.gleam
================================================================================
import gleam/bit_string
import gleam/string
/// Encodes a BitString into a base 64 encoded string.
///
pub fn encode64(input: BitString, padding: Bool) -> String {
let encoded = do_encode64(input)
case padding {
True -> encoded
False -> string.replace(encoded, "=", "")
}
}
if erlang {
external fn do_encode64(BitString) -> String =
"base64" "encode"
}
if javascript {
external fn do_encode64(BitString) -> String =
"../gleam_stdlib.mjs" "encode64"
}
--------------------------------------------------------------------------------
(source_file
(import
module: (module))
(import
module: (module))
(statement_comment)
(statement_comment)
(function
(visibility_modifier)
name: (identifier)
parameters: (function_parameters
(function_parameter
name: (identifier)
type: (type
name: (type_identifier)))
(function_parameter
name: (identifier)
type: (type
name: (type_identifier))))
return_type: (type
name: (type_identifier))
body: (block
(let
pattern: (identifier)
value: (function_call
function: (identifier)
arguments: (arguments
(argument
value: (identifier)))))
(case
subjects: (case_subjects
(identifier))
clauses: (case_clauses
(case_clause
patterns: (case_clause_patterns
(case_clause_pattern
(record_pattern
name: (constructor_name))))
value: (identifier))
(case_clause
patterns: (case_clause_patterns
(case_clause_pattern
(record_pattern
name: (constructor_name))))
value: (function_call
function: (field_access
record: (identifier)
field: (label))
arguments: (arguments
(argument
value: (identifier))
(argument
value: (string
(quoted_content)))
(argument
value: (string)))))))))
(target_group
target: (target)
(external_function
name: (identifier)
parameters: (function_parameters
(function_parameter
type: (type
name: (type_identifier))))
return_type: (type
name: (type_identifier))
body: (external_function_body
(string
(quoted_content))
(string
(quoted_content)))))
(target_group
target: (target)
(external_function
name: (identifier)
parameters: (function_parameters
(function_parameter
type: (type
name: (type_identifier))))
return_type: (type
name: (type_identifier))
body: (external_function_body
(string
(quoted_content))
(string
(quoted_content))))))
================================================================================
Excerpt from stdlib's bool.gleam
================================================================================
//// A type with two possible values, `True` and `False`. Used to indicate whether
//// things are... true or false!
////
//// Often is it clearer and offers more type safety to define a custom type
//// than to use `Bool`. For example, rather than having a `is_teacher: Bool`
//// field consider having a `role: SchoolRole` field where `SchoolRole` is a custom
//// type that can be either `Student` or `Teacher`.
import gleam/order.{Order}
/// Returns the opposite bool value.
///
/// This is the same as the `!` or `not` operators in some other languages.
///
/// ## Examples
///
/// > negate(True)
/// False
///
/// > negate(False)
/// True
///
pub fn negate(bool: Bool) -> Bool {
case bool {
True -> False
False -> True
}
}
--------------------------------------------------------------------------------
(source_file
(module_comment)
(module_comment)
(module_comment)
(module_comment)
(module_comment)
(module_comment)
(module_comment)
(import
module: (module)
imports: (unqualified_imports
(unqualified_import
name: (constructor_name))))
(statement_comment)
(statement_comment)
(statement_comment)
(statement_comment)
(statement_comment)
(statement_comment)
(statement_comment)
(statement_comment)
(statement_comment)
(statement_comment)
(statement_comment)
(statement_comment)
(function
(visibility_modifier)
name: (identifier)
parameters: (function_parameters
(function_parameter
name: (identifier)
type: (type
name: (type_identifier))))
return_type: (type
name: (type_identifier))
body: (block
(case
subjects: (case_subjects
(identifier))
clauses: (case_clauses
(case_clause
patterns: (case_clause_patterns
(case_clause_pattern
(record_pattern
name: (constructor_name))))
value: (record
name: (constructor_name)))
(case_clause
patterns: (case_clause_patterns
(case_clause_pattern
(record_pattern
name: (constructor_name))))
value: (record
name: (constructor_name))))))))
================================================================================
Trailing commas
================================================================================
import animal.{Cat,}
const foo: #(Int,) = #(1,)
const bar = [1,]
const cat:Cat(String,) = Cat(name: "Nubi",)
type Thing {
First(name: String,)
}
external fn foo(String,) -> String = "foo" "bar"
fn foo(a,) {
myfun(a,)
let Cat(name: name,) = Cat(..a, name: "George",)
let #(a) = #(a,)
let [x,] = [1,]
}
--------------------------------------------------------------------------------
(source_file
(import
(module)
(unqualified_imports
(unqualified_import
(constructor_name))))
(constant
(identifier)
(tuple_type
(type
(type_identifier)))
(tuple
(integer)))
(constant
(identifier)
(list
(integer)))
(constant
(identifier)
(type
(type_identifier)
(type_arguments
(type_argument
(type
(type_identifier)))))
(record
(constructor_name)
(arguments
(argument
(label)
(string
(quoted_content))))))
(type_definition
(type_name
(type_identifier))
(data_constructors
(data_constructor
(constructor_name)
(data_constructor_arguments
(data_constructor_argument
(label)
(type
(type_identifier)))))))
(external_function
(identifier)
(function_parameters
(function_parameter
(type
(type_identifier))))
(type
(type_identifier))
(external_function_body
(string
(quoted_content))
(string
(quoted_content))))
(function
(identifier)
(function_parameters
(function_parameter
(identifier)))
(block
(function_call
(identifier)
(arguments
(argument
(identifier))))
(let
(record_pattern
(constructor_name)
(record_pattern_arguments
(record_pattern_argument
(label)
(identifier))))
(record_update
(constructor_name)
(identifier)
(record_update_arguments
(record_update_argument
(label)
(string
(quoted_content))))))
(let
(tuple_pattern
(identifier))
(tuple
(identifier)))
(let
(list_pattern
(identifier))
(list
(integer))))))

@ -1,25 +0,0 @@
<<3>>
// <- punctuation.bracket
//^ number
// ^ punctuation.bracket
<<3:8>>
//^ number
// ^ punctuation.delimiter
// ^ number
<<3:size(8)>>
//^ number
// ^ punctuation.delimiter
// ^ function.builtin
// ^ punctuation.bracket
// ^ number
// ^ punctuation.bracket
<<code:int-size(8)-unit(2), reason:utf8>>
// ^ variable
// ^ function.builtin
// ^ punctuation.delimiter
// ^ function.builtin
// ^ number
// ^ function.builtin
// ^ number
// ^ variable
// ^ function.builtin

@ -1,11 +0,0 @@
pub fn case_with_remainder() {
case todo {
_ if 1 % 2 == 0 -> todo
// ^ number
// ^ operator
// ^ number
// ^ operator
// ^ number
_ -> todo
}
}

@ -1,10 +0,0 @@
const f = 100.001e523
// ^ number
// ^ number
// ^ number
const s = "Hello, \e\t\n"
// ^ warning
// ^ warning
// ^ string.escape
// ^ string.escape

@ -1,32 +0,0 @@
fn case_case(x: Option(String)) {
// ^ variable.parameter
// ^ type
case #(x, x) {
// ^ variable.parameter
// ^ variable.parameter
#(None, None) -> None
// ^ constructor
// ^ constructor
// ^ constructor
#(Some(y), Some(z)) -> #(y, z)
// ^ constructor
// ^ variable
// ^ constructor
// ^ variable
// ^ variable
// ^ variable
}
// this is bound above but no longer in scope,
// so it should be interpereted as a module
z.foo()
// <- module
}
fn shorthand_label_pattern_arg() {
case todo {
Wibble(arg1:, arg2:) -> todo
// ^ property
// ^ property
}
}

@ -1,4 +0,0 @@
pub fn main() {
echo 2
// ^ keyword
}

@ -1,16 +0,0 @@
case "12345" {
"123" <> rest -> rest
// <- string
// ^ operator
// ^ variable
_ -> ""
// ^ string
}
-x
// ^ operator
// ^ variable
panic as "aaah!"
// <- keyword
// ^ keyword
// ^ string

@ -1,129 +0,0 @@
pub fn replace(
// <- keyword
// <- keyword
// ^ function
// ^ punctuation.bracket
in original: String,
// <- property
// ^ variable.parameter
// ^ type
// ^ punctuation.delimiter
each pattern: String,
// <- property
// ^ variable.parameter
// ^ type
// ^ punctuation.delimiter
with replacement: String,
// <- property
// ^ variable.parameter
// ^ type
// ^ punctuation.delimiter
) -> String {
// <- punctuation.delimiter
// ^ type
// ^ punctuation.bracket
string.replace(in: original, each: pattern, with: replacement)
// <- module
// ^ function
// ^ property
// ^ variable.parameter
// ^ property
// ^ variable.parameter
// ^ property
// ^ variable.parameter
original
// ^ variable.parameter
|> string.replace(pattern, replacement)
// <- operator
// ^ module
// ^ function
// ^ variable.parameter
// ^ variable.parameter
}
fn record_with_fun_field(record) {
let foo = Bar(baz: fn(x) { x + 1 })
// ^ constructor
foo.baz(41)
// <- variable
// ^ property
record.foobar("hello")
// ^ variable.parameter
// ^ property
string.replace("hello", "l", "o")
// ^ module
// ^ function
}
fn trial(uri) {
// ^ variable.parameter
case uri {
// ^ variable.parameter
Uri(scheme: None) -> True
// <- constructor
// ^ property
// ^ constructor
// ^ constructor
_ -> False
// <- comment.unused
}
}
fn my_uri_to_string(my_uri) -> String {
uri.to_string(my_uri)
// <- module
// ^ function
// ^ variable.parameter
}
fn myfun(argument) {
let local_fun = fn(x) { x + 1 }
// ^ variable
// ^ variable.parameter
// ^ variable.parameter
argument
// ^ variable.parameter
|> local_fun
// <- operator
// ^ variable
|> module_fun
// ^ function
module_fun(local_fun(argument))
// ^ function
// ^ variable
// ^ variable.parameter
}
fn negate(arg) {
!arg
// <- operator
// ^ variable.parameter
}
fn comment_string_test() {
io.println("// hello world!")
// <- module
// ^ function
// ^ string
}
fn let_assert_test() {
let assert #(x, _) = #(1, 2)
// <- keyword
// ^ keyword
}
fn assert_test() {
assert x == add(1, 4)
// <- keyword
// ^ function
}
fn punned_call_arg_test() {
wibble(arg:, arg2:)
// ^ function
// ^ property
// ^ property
}

@ -1,84 +0,0 @@
import gleam/io
// ^ module
// ^ module
// ^ module
import animal/cat as kitty
// ^ module
// ^ module
import animal/cat.{Cat, type Cat}
// ^ constructor
// ^ keyword
// ^ type
import wibble.{wobble} as _
// ^ module
// ^ function
// ^ comment.unused
pub fn main() {
io.println("hello world")
// <- module
}
type MyType {
MyType(func: fn() -> Int)
}
fn record_access_case(param: MyType) {
let binding = MyType(func: fn() { 42 })
let _ = binding.func()
// ^ comment.unused
// ^ variable
let _ = param.func()
// ^ comment.unused
// ^ variable.parameter
}
fn pipe_operator_case(string: String) {
string
// <- variable.parameter
|> iodata.new
// ^ module
|> iodata.reverse
// ^ module
}
fn remote_type_case() {
gleam.Ok(1)
// <- module
// ^ punctuation.delimiter
// ^ constructor
}
fn make_cat() -> kitty.Cat {
// ^ module
// ^ type
kitty.Cat(name: "Nubi")
// ^ module
// ^ constructor
}
@target(erlang)
// <- attribute
// ^ attribute
// ^ constant
pub external fn display() -> Bool = "erlang" "display"
@target(erlang)
@external(erlang, "wobble", "main")
// <- attribute
// ^ attribute
// ^ constant
// ^ string
// string
pub fn main() -> Int
@deprecated(since: "1.2.0", replacement: wobble)
// <- attribute
// ^ attribute
// ^ property
// ^ string
// ^ property
// ^constant
pub fn wibble() { todo }

@ -1,28 +0,0 @@
pub type User {
// ^ type
User(name: String)
// <- constructor
// ^ property
// ^ type
}
pub fn new(name: String) {
// ^ variable.parameter
User(name: name)
// ^ property
// ^ variable.parameter
}
pub fn access() {
let config = Config()
config.connection.host
// ^ variable
// ^ property
// ^ property
}
pub fn record_update_shorthand_label() {
User(..user, name:)
// ^ constructor
// ^ property
}

@ -1,14 +0,0 @@
auto
// <- error
delegate
// <- error
derive
// <- error
else
// <- error
implement
// <- error
macro
// <- error
test
// <- error

@ -1,75 +0,0 @@
import gleam/option.{type Option, Some, None}
// ^ reference.module
// ^ reference.type
// ^ reference.constructor
// ^ reference.constructor
import gleam/bit_builder
// ^ reference.module
pub type FrameData {
// ^ definition.type
Text(String)
// <- definition.constructor
// ^ reference.type
Binary(BitString)
Continuation(BitString)
Ping(BitString)
Pong(BitString)
Close(code: Option(Int), reason: Option(String))
// <- definition.constructor
// ^ reference.type
// ^ reference.type
// ^ reference.type
// ^ reference.type
}
pub type Frame {
// ^ definition.type
Frame(reserved: BitString, mask: Option(BitString), data: FrameData, fin: Bool)
}
fn encode_frame(frame: Frame) -> bit_builder.BitBuilder {
// ^ definition.function
// ^ reference.type
// ^ reference.module
// ^ reference.type
let fin =
case frame.fin {
True -> <<1:size(1)>>
False -> <<0:size(1)>>
}
let opcode =
case frame.data {
Continuation(_) -> <<0x0:size(1)>>
// <- reference.constructor
Text(_) -> <<0x1:size(1)>>
Binary(_) -> <<0x2:size(1)>>
// 0x3-7 reserved for future non-control frames
Close(..) -> <<0x8:size(1)>>
Pong(_) -> <<0x9:size(1)>>
Pong(_) -> <<0xA:size(1)>>
}
let is_masked_bit =
case frame.mask {
Some(_) -> <<1:size(1)>>
None -> <<0:size(1)>>
}
bit_builder.new()
// <- reference.module
// ^ reference.function
|> bit_builder.append(fin)
// ^ reference.function
|> bit_builder.append(frame.reserved)
|> bit_builder.append(opcode)
|> bit_builder.append(is_masked_bit)
|> bit_builder.append(option.unwrap(frame.mask, <<>>))
// ^ reference.module
// ^ reference.module
// ^ reference.function
|> bit_builder.append(mask_data(frame))
// ^ reference.function
}

@ -1,10 +0,0 @@
fn record_with_fun_field(record) {
let foo = Bar(baz: fn(x) { x + 1 })
// ^ reference.constructor
foo.baz(41)
record.foobar("hello")
string.replace("hello", "l", "o")
// ^ reference.module
// ^ reference.function
}