Update Elixir parser and use crate from crates.io

pull/816/head
Wilfred Hughes 2025-02-10 08:48:31 +07:00
parent 8f6484cf75
commit bd9c98050e
85 changed files with 19 additions and 459157 deletions

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

11
Cargo.lock generated

@ -279,6 +279,7 @@ dependencies = [
"tree-sitter-c-sharp",
"tree-sitter-cpp",
"tree-sitter-css",
"tree-sitter-elixir",
"tree-sitter-go",
"tree-sitter-haskell",
"tree-sitter-html",
@ -1049,6 +1050,16 @@ dependencies = [
"tree-sitter-language",
]
[[package]]
name = "tree-sitter-elixir"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e45d444647b4fd53d8fd32474c1b8bedc1baa22669ce3a78d083e365fa9a2d3f"
dependencies = [
"cc",
"tree-sitter-language",
]
[[package]]
name = "tree-sitter-go"
version = "0.23.4"

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

@ -102,11 +102,6 @@ fn main() {
src_dir: "vendored_parsers/tree-sitter-elisp-src",
extra_files: vec![],
},
TreeSitterParser {
name: "tree-sitter-elixir",
src_dir: "vendored_parsers/tree-sitter-elixir-src",
extra_files: vec!["scanner.c"],
},
TreeSitterParser {
name: "tree-sitter-elm",
src_dir: "vendored_parsers/tree-sitter-elm-src",

@ -67,7 +67,6 @@ extern "C" {
fn tree_sitter_dart() -> ts::Language;
fn tree_sitter_devicetree() -> ts::Language;
fn tree_sitter_elisp() -> ts::Language;
fn tree_sitter_elixir() -> ts::Language;
fn tree_sitter_elm() -> ts::Language;
fn tree_sitter_elvish() -> ts::Language;
fn tree_sitter_erlang() -> ts::Language;
@ -305,18 +304,17 @@ pub(crate) fn from_language(language: guess::Language) -> TreeSitterConfig {
}
}
Elixir => {
let language = unsafe { tree_sitter_elixir() };
let language_fn = tree_sitter_elixir::LANGUAGE;
let language = tree_sitter::Language::new(language_fn);
TreeSitterConfig {
language: language.clone(),
atom_nodes: ["string", "heredoc"].into_iter().collect(),
delimiter_tokens: vec![("(", ")"), ("{", "}"), ("do", "end")]
.into_iter()
.collect(),
highlight_query: ts::Query::new(
&language,
include_str!("../../vendored_parsers/highlights/elixir.scm"),
)
.unwrap(),
highlight_query: ts::Query::new(&language, tree_sitter_elixir::HIGHLIGHTS_QUERY)
.unwrap(),
sub_languages: vec![],
}
}

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

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

@ -1,12 +0,0 @@
AlignArrayOfStructures: Left
BasedOnStyle: LLVM
IndentCaseLabels: true
IndentGotoLabels: true
IndentPPDirectives: AfterHash
IndentWidth: 2
KeepEmptyLinesAtTheStartOfBlocks: false
SeparateDefinitionBlocks: Always
SortIncludes: CaseInsensitive
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceBeforeCaseColon: false

@ -1,4 +0,0 @@
/src/**/* linguist-generated=true
/src/scanner.c linguist-generated=false
# Exclude test files from language stats
/test/**/*.ex linguist-documentation=true

@ -1,10 +0,0 @@
<!--
This repository includes the Tree-sitter parser for Elixir,
whereas editor-specific integrations are separate projects.
If you're running into Tree-sitter related issues in your editor,
please report it on the respective repository (likely an editor
plugin responsible for Tree-sitter integration).
For example, when using Neovim, go to https://github.com/nvim-treesitter/nvim-treesitter
-->

@ -1,44 +0,0 @@
name: Generate
on:
push:
branches:
- main
jobs:
main:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Node
uses: actions/setup-node@v2
with:
node-version: "14.x"
- name: Cache npm dependencies
uses: actions/cache@v2
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
run: |
npx tree-sitter generate
npx tree-sitter build-wasm
- name: Update parser files
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: Generate parser
file_pattern: src
- name: Checkout gh-pages branch to ./gh-pages
uses: actions/checkout@v2
with:
ref: gh-pages
path: ./gh-pages
- run: mv *.wasm ./gh-pages
- name: Update WASM file on gh-pages branch
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: Generate WASM
file_pattern: "*.wasm"
repository: ./gh-pages

@ -1,34 +0,0 @@
name: Test
on:
pull_request:
push:
branches:
- main
schedule:
- cron: "0 0 * * *"
jobs:
main:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Node
uses: actions/setup-node@v2
with:
node-version: "14.x"
- name: Cache npm dependencies
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install npm dependencies
run: npm ci
- name: Check formatting
run: npm run format-check
# Ensure the generated parser is up to date
- run: npx tree-sitter generate
- name: Run Tree-sitter tests
run: npx tree-sitter test
- name: Run integration tests
run: scripts/integration_test.sh

@ -1,25 +0,0 @@
# Deps
/node_modules/
# Temporary files
/tmp/
# Temporary files generated by Tree-sitter
/build/
log.html
tree-sitter-elixir.wasm
# Files generated by Cargo
/target/
Cargo.lock
# C bindings/binaries
/*.a
/*.dylib
/*.so*
*.o
/bindings/c/*.h
/bindings/c/tree-sitter-*.pc
# Files generated by Swift
/.build/

@ -1,9 +0,0 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [v0.1.0](https://github.com/elixir-lang/tree-sitter-elixir/tree/v0.1.0) (2023-03-14)
Initial release.

@ -1,26 +0,0 @@
[package]
name = "tree-sitter-elixir"
description = "Elixir grammar for the tree-sitter parsing library"
version = "0.1.0"
keywords = ["incremental", "parsing", "elixir"]
categories = ["parsing", "text-editors"]
repository = "https://github.com/elixir-lang/tree-sitter-elixir"
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 = ">= 0.19, < 0.21"
[build-dependencies]
cc = "1.0"

@ -1,176 +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

@ -1,114 +0,0 @@
VERSION := 0.19.1
# Repository
SRC_DIR := src
PARSER_REPO_URL := $(shell git -C $(SRC_DIR) remote get-url origin )
ifeq (, $(PARSER_NAME))
PARSER_NAME := $(shell basename $(PARSER_REPO_URL))
PARSER_NAME := $(subst tree-sitter-,,$(PARSER_NAME))
PARSER_NAME := $(subst .git,,$(PARSER_NAME))
endif
ifeq (, $(PARSER_URL))
PARSER_URL := $(subst :,/,$(PARSER_REPO_URL))
PARSER_URL := $(subst git@,https://,$(PARSER_URL))
PARSER_URL := $(subst .git,,$(PARSER_URL))
endif
UPPER_PARSER_NAME := $(shell echo $(PARSER_NAME) | tr a-z A-Z )
# install directory layout
PREFIX ?= /usr/local
INCLUDEDIR ?= $(PREFIX)/include
LIBDIR ?= $(PREFIX)/lib
PCLIBDIR ?= $(LIBDIR)/pkgconfig
# collect C++ sources, and link if necessary
CPPSRC := $(wildcard $(SRC_DIR)/*.cc)
ifeq (, $(CPPSRC))
ADDITIONALLIBS :=
else
ADDITIONALLIBS := -lc++
endif
# collect sources
SRC := $(wildcard $(SRC_DIR)/*.c)
SRC += $(CPPSRC)
OBJ := $(addsuffix .o,$(basename $(SRC)))
# ABI versioning
SONAME_MAJOR := 0
SONAME_MINOR := 0
CFLAGS ?= -O3 -Wall -Wextra -I$(SRC_DIR)
CXXFLAGS ?= -O3 -Wall -Wextra -I$(SRC_DIR)
override CFLAGS += -std=gnu99 -fPIC
override CXXFLAGS += -fPIC
# OS-specific bits
ifeq ($(shell uname),Darwin)
SOEXT = dylib
SOEXTVER_MAJOR = $(SONAME_MAJOR).dylib
SOEXTVER = $(SONAME_MAJOR).$(SONAME_MINOR).dylib
LINKSHARED := $(LINKSHARED)-dynamiclib -Wl,
ifneq ($(ADDITIONALLIBS),)
LINKSHARED := $(LINKSHARED)$(ADDITIONALLIBS),
endif
LINKSHARED := $(LINKSHARED)-install_name,$(LIBDIR)/libtree-sitter-$(PARSER_NAME).$(SONAME_MAJOR).dylib,-rpath,@executable_path/../Frameworks
else
SOEXT = so
SOEXTVER_MAJOR = so.$(SONAME_MAJOR)
SOEXTVER = so.$(SONAME_MAJOR).$(SONAME_MINOR)
LINKSHARED := $(LINKSHARED)-shared -Wl,
ifneq ($(ADDITIONALLIBS),)
LINKSHARED := $(LINKSHARED)$(ADDITIONALLIBS),
endif
LINKSHARED := $(LINKSHARED)-soname,libtree-sitter-$(PARSER_NAME).so.$(SONAME_MAJOR)
endif
ifneq (,$(filter $(shell uname),FreeBSD NetBSD DragonFly))
PCLIBDIR := $(PREFIX)/libdata/pkgconfig
endif
all: libtree-sitter-$(PARSER_NAME).a libtree-sitter-$(PARSER_NAME).$(SOEXTVER) bindings/c/$(PARSER_NAME).h bindings/c/tree-sitter-$(PARSER_NAME).pc
libtree-sitter-$(PARSER_NAME).a: $(OBJ)
$(AR) rcs $@ $^
libtree-sitter-$(PARSER_NAME).$(SOEXTVER): $(OBJ)
$(CC) $(LDFLAGS) $(LINKSHARED) $^ $(LDLIBS) -o $@
ln -sf $@ libtree-sitter-$(PARSER_NAME).$(SOEXT)
ln -sf $@ libtree-sitter-$(PARSER_NAME).$(SOEXTVER_MAJOR)
bindings/c/$(PARSER_NAME).h:
sed -e 's|@UPPER_PARSERNAME@|$(UPPER_PARSER_NAME)|' \
-e 's|@PARSERNAME@|$(PARSER_NAME)|' \
bindings/c/tree-sitter.h.in > $@
bindings/c/tree-sitter-$(PARSER_NAME).pc:
sed -e 's|@LIBDIR@|$(LIBDIR)|;s|@INCLUDEDIR@|$(INCLUDEDIR)|;s|@VERSION@|$(VERSION)|' \
-e 's|=$(PREFIX)|=$${prefix}|' \
-e 's|@PREFIX@|$(PREFIX)|' \
-e 's|@ADDITIONALLIBS@|$(ADDITIONALLIBS)|' \
-e 's|@PARSERNAME@|$(PARSER_NAME)|' \
-e 's|@PARSERURL@|$(PARSER_URL)|' \
bindings/c/tree-sitter.pc.in > $@
install: all
install -d '$(DESTDIR)$(LIBDIR)'
install -m755 libtree-sitter-$(PARSER_NAME).a '$(DESTDIR)$(LIBDIR)'/libtree-sitter-$(PARSER_NAME).a
install -m755 libtree-sitter-$(PARSER_NAME).$(SOEXTVER) '$(DESTDIR)$(LIBDIR)'/libtree-sitter-$(PARSER_NAME).$(SOEXTVER)
ln -sf libtree-sitter-$(PARSER_NAME).$(SOEXTVER) '$(DESTDIR)$(LIBDIR)'/libtree-sitter-$(PARSER_NAME).$(SOEXTVER_MAJOR)
ln -sf libtree-sitter-$(PARSER_NAME).$(SOEXTVER) '$(DESTDIR)$(LIBDIR)'/libtree-sitter-$(PARSER_NAME).$(SOEXT)
install -d '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter
install -m644 bindings/c/$(PARSER_NAME).h '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/
install -d '$(DESTDIR)$(PCLIBDIR)'
install -m644 bindings/c/tree-sitter-$(PARSER_NAME).pc '$(DESTDIR)$(PCLIBDIR)'/
clean:
rm -f $(OBJ) libtree-sitter-$(PARSER_NAME).a libtree-sitter-$(PARSER_NAME).$(SOEXT) libtree-sitter-$(PARSER_NAME).$(SOEXTVER_MAJOR) libtree-sitter-$(PARSER_NAME).$(SOEXTVER)
rm -f bindings/c/$(PARSER_NAME).h bindings/c/tree-sitter-$(PARSER_NAME).pc
.PHONY: all install clean

@ -1,68 +0,0 @@
LEGAL NOTICE INFORMATION
------------------------
All the files in this distribution are copyright to the terms below.
== All files in src/ except scanner.cc (generated by tree-sitter-cli)
Copyright (c) 2018-2021 Max Brunsfeld
The MIT License (MIT)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
== Some file fragments in test/corpus/
Copyright (c) 2021 Anantha Kumaran
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
== All other files
Copyright 2021 The Elixir Team
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
https://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,41 +0,0 @@
// swift-tools-version:5.3
import PackageDescription
let package = Package(
name: "TreeSitterElixir",
platforms: [.macOS(.v10_13), .iOS(.v11)],
products: [
.library(name: "TreeSitterElixir", targets: ["TreeSitterElixir"]),
],
dependencies: [],
targets: [
.target(name: "TreeSitterElixir",
path: ".",
exclude: [
"binding.gyp",
"bindings",
"Cargo.toml",
"docs",
"grammar.js",
"LICENSE",
"Makefile",
"NOTICE",
"package.json",
"README.md",
"scripts",
"src/grammar.json",
"src/node-types.json",
"test",
],
sources: [
"src/parser.c",
"src/scanner.c",
],
resources: [
.copy("queries")
],
publicHeadersPath: "bindings/swift",
cSettings: [.headerSearchPath("src")])
]
)

@ -1,11 +0,0 @@
# tree-sitter-elixir
[![Test](https://github.com/elixir-lang/tree-sitter-elixir/actions/workflows/test.yml/badge.svg)](https://github.com/elixir-lang/tree-sitter-elixir/actions/workflows/test.yml)
Elixir grammar for [tree-sitter](https://github.com/tree-sitter/tree-sitter).
Ready for production. Currently used by GitHub itself for source code highlighting and code navigation.
## Development
See [the docs](./docs/index.md) for more details.

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

@ -1,16 +0,0 @@
#ifndef TREE_SITTER_@UPPER_PARSERNAME@_H_
#define TREE_SITTER_@UPPER_PARSERNAME@_H_
#include <tree_sitter/parser.h>
#ifdef __cplusplus
extern "C" {
#endif
extern TSLanguage *tree_sitter_@PARSERNAME@();
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_@UPPER_PARSERNAME@_H_

@ -1,11 +0,0 @@
prefix=@PREFIX@
libdir=@LIBDIR@
includedir=@INCLUDEDIR@
additionallibs=@ADDITIONALLIBS@
Name: tree-sitter-@PARSERNAME@
Description: A tree-sitter grammar for the @PARSERNAME@ programming language.
URL: @PARSERURL@
Version: @VERSION@
Libs: -L${libdir} ${additionallibs} -ltree-sitter-@PARSERNAME@
Cflags: -I${includedir}

@ -1,28 +0,0 @@
#include "tree_sitter/parser.h"
#include <node.h>
#include "nan.h"
using namespace v8;
extern "C" TSLanguage * tree_sitter_elixir();
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_elixir());
Nan::Set(instance, Nan::New("name").ToLocalChecked(), Nan::New("elixir").ToLocalChecked());
Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance);
}
NODE_MODULE(tree_sitter_elixir_binding, Init)
} // namespace

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

@ -1,19 +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);
println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap());
let scanner_path = src_dir.join("scanner.c");
c_config.file(&scanner_path);
println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap());
c_config.compile("parser-scanner");
}

@ -1,52 +0,0 @@
//! This crate provides elixir language support for the [tree-sitter][] parsing library.
//!
//! Typically, you will use the [language][language func] function to add this language to a
//! tree-sitter [Parser][], and then use the parser to parse some code:
//!
//! ```
//! let code = "";
//! let mut parser = tree_sitter::Parser::new();
//! parser.set_language(tree_sitter_elixir::language()).expect("Error loading elixir grammar");
//! let tree = parser.parse(code, None).unwrap();
//! ```
//!
//! [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html
//! [language func]: fn.language.html
//! [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html
//! [tree-sitter]: https://tree-sitter.github.io/
use tree_sitter::Language;
extern "C" {
fn tree_sitter_elixir() -> Language;
}
/// Get the tree-sitter [Language][] for this grammar.
///
/// [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html
pub fn language() -> Language {
unsafe { tree_sitter_elixir() }
}
/// The content of the [`node-types.json`][] file for this grammar.
///
/// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types
pub const NODE_TYPES: &'static str = include_str!("../../src/node-types.json");
// Uncomment these to include any queries that this grammar contains
pub const HIGHLIGHTS_QUERY: &'static str = include_str!("../../queries/highlights.scm");
// pub const INJECTIONS_QUERY: &'static str = include_str!("../../queries/injections.scm");
// pub const LOCALS_QUERY: &'static str = include_str!("../../queries/locals.scm");
pub const TAGS_QUERY: &'static str = include_str!("../../queries/tags.scm");
#[cfg(test)]
mod tests {
#[test]
fn test_can_load_grammar() {
let mut parser = tree_sitter::Parser::new();
parser
.set_language(super::language())
.expect("Error loading elixir language");
}
}

@ -1,16 +0,0 @@
#ifndef TREE_SITTER_ELIXIR_H_
#define TREE_SITTER_ELIXIR_H_
typedef struct TSLanguage TSLanguage;
#ifdef __cplusplus
extern "C" {
#endif
extern TSLanguage *tree_sitter_elixir();
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_ELIXIR_H_

@ -1,60 +0,0 @@
# Syntax highlighting
For detailed introduction see the official guide on [Syntax highlighting](https://tree-sitter.github.io/tree-sitter/syntax-highlighting).
Briefly speaking, Tree-sitter uses the rules in `queries/highlights.scm` to annotate nodes
with specific tokens, then it maps those tokens to formatting style according to user-defined
theme.
To test highlighting using the CLI, you need to create local configuration.
```shell
# Create the config file
npx tree-sitter init-config
```
The above command should print out the config location, so that you can further configure it.
Open the file and modify `"parser-directories"` to include the parent directory of `tree-sitter-elixir`.
Also, you can optionally customize the theme, here's a tiny subset of the One Dark theme:
```json
{
"number": {
"color": "#61afef",
"bold": true
},
"string": "#98c379",
"string.escape": "#56b6c2",
"string.special": "#61afef",
"string.regexp": "#e06c75",
"type": "#e06c75",
"comment": {
"color": "#5c6370",
"italic": true
},
"punctuation": "#abb2bf",
"punctuation.special": "#be5046",
"operator": {
"color": "#d19a66",
"bold": true
},
"variable": "#abb2bf",
"function": "#61afef",
"constant": "#61afef",
"constant.builtin": {
"color": "#e06c75",
"bold": true
},
"keyword": "#c678dd",
"attribute": "#e06c75",
"embedded": null
}
```
With this setup you can test highlighting on files using the Tree-sitter CLI.
```shell
npx tree-sitter highlight tmp/test.ex
npx tree-sitter highlight test/highlight/**/*.ex
```

@ -1,21 +0,0 @@
# Development notes
This documentation covers rationale behind some of the design and implementation decisions,
as well as basic Tree-sitter tips that are relevant.
## Pages
* [Parser](./parser.md)
* [Highlighting](./highlighting.md)
## Acknowledgements
While this parser is written from scratch, there were previous efforts that made
for a helpful reference:
* [tree-sitter-elixir](https://github.com/ananthakumaran/tree-sitter-elixir) developed
by [@ananthakumaran](https://github.com/ananthakumaran)
* [tree-sitter-elixir](https://github.com/wingyplus/tree-sitter-elixir) developed
by [@wingyplus](https://github.com/wingyplus) and [@Tuxified](https://github.com/Tuxified)
In particular, some test cases were sourced from [ananthakumaran/tree-sitter-elixir](https://github.com/ananthakumaran/tree-sitter-elixir).

@ -1,261 +0,0 @@
# Parser
## The AST
When it comes to AST Elixir is a rather specific language due to its macro system.
From the perspective of our parser, the important implication is that a seemingly
invalid code can be a valid syntax when used in a macro (or just put in the `quote`
expression). For example:
```elixir
quote do
def Bar.foo(x), definitely_not_do: 1
%{a}
*/2
end
```
As opposed to other languages, core constructs like `def`, `if` and `for` are not
particularly special either, since they are itself regular functions (or macros rather).
As a result, these constructs can be used "improperly" in a quoted expression, as shown above.
Consequently, to correctly parse all Elixir code, we need the AST to closely match
the Elixir AST. See [Elixir / Syntax reference](https://hexdocs.pm/elixir/syntax-reference.html)
for more details.
Whenever possible, we try using a more specific nodes (like binary/unary operator), but only
to the extent that doesn't lose on generality. To get a sense of what the AST looks like, have
a look at the tests in `test/corpus/`.
## Getting started with Tree-sitter
For detailed introduction see the official guide on [Creating parsers](https://tree-sitter.github.io/tree-sitter/creating-parsers).
Essentially, we define relevant language rules in `grammar.js`, based on which
Tree-sitter generates parser code (under `src/`). In some cases, we want to write
custom C code for tokenizing specific character sequences (in `src/scanner.c`).
The grammar rules may often conflict with each other, meaning that the given
sequence of tokens has multiple valid interpretations given one _token_ of lookahead.
In many conflicts we always want to pick one interpretation over the other and we can
do this by assigning different precedence and associativity to relevant rules, which
tells the parser which way to go.
For example given `expression1 * expression2 • *` the next token we _see_ ahead is `*`.
The parser needs to decide whether `expression1 * expression2` is a complete binary operator
node, or if it should await the next expression and interpret it as `expression1 * (expression2 * expression3)`.
Since the `*` operator is left-associative we can use `prec.left` on the corresponding
grammar rule, to inform the parser how to resolve this conflict.
However, in some cases looking at one token ahead isn't enough, in which case we can add
the conflicting rules to the `conflicts` list in the grammar. Whenever the parser stumbles
upon this conflict it uses its GLR algorithm, basically considering both interpretations
until one leads to parsing error. If both paths parse correctly (there's a genuine ambiguity)
we can use dynamic precedence (`prec.dynamic`) to decide on the preferred path.
## Using the CLI
### tree-sitter
```shell
# See CLI usage
npx tree-sitter -h
# Generate the the parser code based on grammar.js
npx tree-sitter generate
# Run tests
npx tree-sitter test
npx tree-sitter test --filter "access syntax"
# Parse a specific file
npx tree-sitter parse tmp/test.ex
npx tree-sitter parse -x tmp/test.ex
# Parse codebase to verify syntax coverage
npx tree-sitter parse --quiet --stat 'tmp/elixir/**/*.ex*'
```
Whenever you make a change to `grammar.js` remember to run `generate`,
before verifying the result. To test custom code, create an Elixir file
like `tmp/test.ex` and use `parse` on it. The `-x` flag prints out the
source grouped into AST nodes as XML.
### Additional scripts
```shell
# Format the grammar.js file
npm run format
# Run parser against the given repository
scripts/parse_repo.sh elixir-lang/elixir
# Run parser against a predefined list of popular repositories
scripts/integration_test.sh
```
## Implementation notes
This section covers some of the implementation decisions that have a more
elaborated rationale. The individual subsections are referenced in the code.
### Ref 1. External scanner for quoted content
We want to scan quoted content as a single token, but it requires lookahead.
Specifically the `#` character may no longer be quoted content if followed by `{`.
Also, inside heredoc string tokenizing `"` (or `'`) requires lookahead to know
if it's already part of the end delimiter or not.
Since we need to use external scanner, we need to know the delimiter type.
One way to achieve this is using external scanner to scan the start delimiter
and then storing its type on the parser stack. This approach requires the parser
to allocate enough memory upfront and implement serialization/deserialization,
which ideally would be avoided. To avoid this, we use a different approach!
Instead of having a single `quoted_content` token, we have specific tokens for
each quoted content type, such as `_quoted_content_i_single`, `_quoted_content_i_double`.
Once the start delimiter is tokenized, we know which quoted content should be
tokenized next, and from the token we can infer the end delimiter and whether
it supports interpolation. In other words, we extract the information from the
parsing state, rather than maintaining custom parser state.
### Ref 2. External scanner for newlines
Generally newlines may appear in the middle of expressions and we ignore them
as long as the expression is valid, that's why we list newline under extras.
When a newline follows a complete expression, most of the time it should be
treated as terminator. However, there are specific cases where the newline is
non-breaking and treated as if it was just a space. This cases are:
* call followed by newline and a `do end` block
* expression followed by newline and a binary operator
In both cases we want to tokenize the newline as non-breaking, so we use external
scanner for lookahead.
Note that the relevant rules already specify left/right associativity, so if we
simply added `optional("\n")` the conflicts would be resolved immediately rather
without using GLR.
Additionally, since comments may appear anywhere and don't change the context,
we also tokenize newlines before comments as non-breaking.
### Ref 3. External scanner for unary + and -
Plus and minus are either binary or unary operators, depending on the context.
Consider the following variants
```
a + b
a+b
a+ b
a +b
```
In the first three expressions `+` is a binary operator, while in the last one
`+` is an unary operator referring to local call argument.
To correctly tokenize all cases we use external scanner to tokenize a special empty
token (`_before_unary_operator`) when the spacing matches `a +b`, which forces the
parser to pick the unary operator path.
### Ref 4. External scanner for `not in`
The `not in` operator may have an arbitrary inline whitespace between `not` and `in`.
We cannot use a regular expression like `/not[ \t]+in/`, because it would also match
in expressions like `a not inn` as the longest matching token.
A possible solution could be `seq("not", "in")` with dynamic conflict resolution, but
then we tokenize two separate tokens. Also to properly handle `a not inn`, we would need
keyword extraction, which causes problems in our case (https://github.com/tree-sitter/tree-sitter/issues/1404).
In the end it's easiest to use external scanner, so that we can skip inline whitespace
and ensure token ends after `in`.
### Ref 5. External scanner for quoted atom start
For parsing quoted atom `:` we could make the `"` (or `'`) token immediate, however this
would require adding immediate rules for single/double quoted content and listing them
in relevant places. We could definitely do that, but using external scanner is actually
simpler.
### Ref 6. Identifier pattern
See [Elixir / Unicode Syntax](https://hexdocs.pm/elixir/unicode-syntax.html) for official
notes.
Tree-sitter already supports unicode properties in regular expressions, however character
class subtraction is not supported.
For the base `<Start>` and `<Continue>` we can use `[\p{ID_Start}]` and `[\p{ID_Continue}]`
respectively, since both are supported and according to the
[Unicode Annex #31](https://unicode.org/reports/tr31/#Table_Lexical_Classes_for_Identifiers)
they match the ranges listed in the Elixir docs.
For atoms this translates to a clean regular expression.
For variables however, we want to exclude uppercase (`\p{Lu}`) and titlecase (`\p{Lt}`)
categories from `\p{ID_Start}`. As already mentioned, we cannot use group subtraction
in the regular expression, so instead we need to create a suitable group of characters
on our own.
After removing the uppercase/titlecase categories from `[\p{ID_Start}]`, we obtain the
following group:
`[\p{Ll}\p{Lm}\p{Lo}\p{Nl}\p{Other_ID_Start}-\p{Pattern_Syntax}-\p{Pattern_White_Space}]`
At the time of writing the subtracted groups actually only remove a single character:
```elixir
Mix.install([{:unicode_set, "~> 1.1"}])
Unicode.Set.to_utf8_char(
"[[[:Ll:][:Lm:][:Lo:][:Nl:][:Other_ID_Start:]] & [[:Pattern_Syntax:][:Pattern_White_Space:]]]"
)
#=> {:ok, [11823]}
```
Consequently, by removing the subtraction we allow just one additional (not common) character,
which is perfectly acceptable.
It's important to note that JavaScript regular expressions don't support the `\p{Other_ID_Start}`
unicode category. Fortunately this category is a small set of characters introduces for
[backward compatibility](https://unicode.org/reports/tr31/#Backward_Compatibility), so we can
enumerate it manually:
```elixir
Mix.install([{:unicode_set, "~> 1.1"}])
Unicode.Set.to_utf8_char("[[[:Other_ID_Start:]] - [[:Pattern_Syntax:][:Pattern_White_Space:]]]")
|> elem(1)
|> Enum.flat_map(fn
n when is_number(n) -> [n]
range -> range
end)
|> Enum.map(&Integer.to_string(&1, 16))
#=> ["1885", "1886", "2118", "212E", "309B", "309C"]
```
Finally, we obtain this regular expression group for variable `<Start>`:
`[\p{Ll}\p{Lm}\p{Lo}\p{Nl}\u1885\u1886\u2118\u212E\u309B\u309C]`
### Ref 7. Keyword token
We tokenize the whole keyword sequence like `do: ` as a single token.
Ideally we wouldn't include the whitespace, but since we use `token`
it gets include. However, this is an intentionally accepted tradeoff,
because using `token` significantly simplifies the grammar and avoids
conflicts.
The alternative approach would be to define keyword as `seq(alias(choice(...), $._keyword_literal), $._keyword_end)`,
where we list all other tokens that make for for valid keyword literal
and use custom scanner for `_keyword_end` to look ahead without tokenizing
the whitespace. However, this approach generates a number of conflicts
because `:` is tokenized separately and phrases like `fun fun • do` or
`fun • {}` are ambiguous (interpretation depends on whether `:` comes next).
Resolving some of these conflicts (for instance special keywords like `{}` or `%{}`)
requires the use of external scanner. Given the complexities this approach
brings to the grammar, and consequently the parser, we stick to the simpler
approach.

@ -1,918 +0,0 @@
const PREC = {
// See https://github.com/elixir-lang/elixir/blob/master/lib/elixir/src/elixir_parser.yrl
IN_MATCH_OPS: 10,
WHEN_OP: 20,
TYPE_OP: 30,
BAR_OP: 40,
ASSOC_OP: 50,
CAPTURE_OP: 60,
MATCH_OP: 70,
OR_OPS: 80,
AND_OPS: 90,
COMP_OPS: 100,
REL_OPS: 110,
ARROW_OPS: 120,
IN_OPS: 130,
XOR_OP: 140,
TERNARY_OP: 150,
CONCAT_OPS: 160,
RANGE_OP: 160,
ADD_OPS: 170,
MULT_OPS: 180,
POWER_OP: 190,
UNARY_OPS: 200,
ACCESS: 205,
DOT_OP: 210,
AT_OP: 220,
CAPTURE_OPERAND: 235,
};
const IN_MATCH_OPS = ["<-", "\\\\"];
const OR_OPS = ["||", "|||", "or"];
const AND_OPS = ["&&", "&&&", "and"];
const COMP_OPS = ["==", "!=", "=~", "===", "!=="];
const REL_OPS = ["<", ">", "<=", ">="];
const ARROW_OPS = ["|>", "<<<", ">>>", "<<~", "~>>", "<~", "~>", "<~>", "<|>"];
const IN_OPS = ["in", "not in"];
const CONCAT_OPS = ["++", "--", "+++", "---", "<>"];
const ADD_OPS = ["+", "-"];
const MULT_OPS = ["*", "/"];
const UNARY_OPS = ["+", "-", "!", "^", "~~~", "not"];
const ALL_OPS = [
["->", "when", "::", "|", "=>", "&", "=", "^^^", "//", "..", "**", ".", "@"],
IN_MATCH_OPS,
OR_OPS,
AND_OPS,
COMP_OPS,
REL_OPS,
ARROW_OPS,
IN_OPS,
CONCAT_OPS,
ADD_OPS,
MULT_OPS,
UNARY_OPS,
].flat();
// Ignore word literals and "=>" which is not a valid atom
const ATOM_OPERATOR_LITERALS = ALL_OPS.filter(
(operator) => !/[a-z]/.test(operator) && operator !== "=>"
);
const ATOM_SPECIAL_LITERALS = ["...", "%{}", "{}", "%", "<<>>", "..//"];
// See Ref 6. in the docs
const ATOM_WORD_LITERAL = /[\p{ID_Start}_][\p{ID_Continue}@]*[?!]?/u;
// Word tokens used directly in the grammar
const RESERVED_WORD_TOKENS = [
// Operators
["and", "in", "not", "or", "when"],
// Literals
["true", "false", "nil"],
// Other
["after", "catch", "do", "else", "end", "fn", "rescue"],
].flat();
const DIGITS = /[0-9]+/;
const BIN_DIGITS = /[0-1]+/;
const OCT_DIGITS = /[0-7]+/;
const HEX_DIGITS = /[0-9a-fA-F]+/;
const NUMBER_DEC = sep1(DIGITS, "_");
const NUMBER_BIN = seq("0b", sep1(BIN_DIGITS, "_"));
const NUMBER_OCT = seq("0o", sep1(OCT_DIGITS, "_"));
const NUMBER_HEX = seq("0x", sep1(HEX_DIGITS, "_"));
const INTEGER = choice(NUMBER_DEC, NUMBER_BIN, NUMBER_OCT, NUMBER_HEX);
const FLOAT_SCIENTIFIC_PART = seq(/[eE]/, optional(choice("-", "+")), INTEGER);
const FLOAT = seq(NUMBER_DEC, ".", NUMBER_DEC, optional(FLOAT_SCIENTIFIC_PART));
const NEWLINE = /\r?\n/;
module.exports = grammar({
name: "elixir",
externals: ($) => [
// See Ref 1. in the docs
$._quoted_content_i_single,
$._quoted_content_i_double,
$._quoted_content_i_heredoc_single,
$._quoted_content_i_heredoc_double,
$._quoted_content_i_parenthesis,
$._quoted_content_i_curly,
$._quoted_content_i_square,
$._quoted_content_i_angle,
$._quoted_content_i_bar,
$._quoted_content_i_slash,
$._quoted_content_single,
$._quoted_content_double,
$._quoted_content_heredoc_single,
$._quoted_content_heredoc_double,
$._quoted_content_parenthesis,
$._quoted_content_curly,
$._quoted_content_square,
$._quoted_content_angle,
$._quoted_content_bar,
$._quoted_content_slash,
// See Ref 2. in the docs
$._newline_before_do,
$._newline_before_binary_operator,
$._newline_before_comment,
// See Ref 3. in the docs
$._before_unary_op,
// See Ref 4. in the docs
$._not_in,
// See Ref 5. in the docs
$._quoted_atom_start,
],
extras: ($) => [
NEWLINE,
/[ \t]|\r?\n|\\\r?\n/,
$.comment,
$._newline_before_comment,
// Placing this directly in the binary operator rule leads
// to conflicts, but we can place it here without any drawbacks.
// If we detect binary operator and the previous line is not a
// valid expression, it's a syntax error either way
$._newline_before_binary_operator,
],
conflicts: ($) => [
// Given `left • *`, `left` identifier can be either:
// * expression in `left * right`
// * call identifier in `left * / 2`
[$._expression, $._local_call_without_parentheses],
// Given `left • when`, `left` expression can be either:
// * binary operator operand in `left when right`
// * stab arguments item in `left when right ->`
//
// Given `arg1, left • when`, `left` expression can be either:
// * binary operator operand in `arg1, left when right, arg3`
// * stab arguments item in `arg1, left when right ->`
[$.binary_operator, $._stab_clause_arguments_without_parentheses],
// Given `((arg1, arg2 • ,`, `arg3` expression can be either:
// * stab parenthesised arguments item in `((arg1, arg2, arg3) ->)`
// * stab non-parenthesised arguments item in `((arg1, arg2, arg3 ->))`
[
$._stab_clause_arguments_without_parentheses,
$._stab_clause_arguments_with_parentheses,
],
// Given `(-> • /`, stab can be either:
// * stab clause operator in `(-> / / 2)`
// * operator identifier in `(-> / 2)`
[$.operator_identifier, $.stab_clause],
// Given `& /`, ampersand can be either:
// * capture operator in `& / / 2`
// * operator identifier in `& / 1`
[$.unary_operator, $.operator_identifier],
// Given `(arg -> expression • \n`, the newline could be either:
// * terminator separating expressions in `(arg -> expression \n expression)`
// * terminator separating clauses in `(arg -> expression \n arg -> expression)`
[$.body],
],
rules: {
source: ($) =>
seq(
optional($._terminator),
optional(
seq(sep1($._expression, $._terminator), optional($._terminator))
)
),
_terminator: ($) =>
// Right precedence, because we want to consume `;` after newlines if present
prec.right(choice(seq(repeat(NEWLINE), ";"), repeat1(NEWLINE))),
_expression: ($) =>
choice(
$.block,
$.identifier,
$.alias,
$.integer,
$.float,
$.char,
$.boolean,
$.nil,
$._atom,
$.string,
$.charlist,
$.sigil,
$.list,
$.tuple,
$.bitstring,
$.map,
$._nullary_operator,
$.unary_operator,
$.binary_operator,
$.dot,
$.call,
$.access_call,
$.anonymous_function
),
block: ($) =>
seq(
"(",
optional($._terminator),
optional(
choice(
sep1(choice($.stab_clause), $._terminator),
seq(
sep1(choice($._expression), $._terminator),
optional($._terminator)
)
)
),
")"
),
identifier: ($) =>
choice(
// See Ref 6. in the docs
/[_\p{Ll}\p{Lm}\p{Lo}\p{Nl}\u1885\u1886\u2118\u212E\u309B\u309C][\p{ID_Continue}]*[?!]?/u,
"..."
),
alias: ($) => token(sep1(/[A-Z][_a-zA-Z0-9]*/, /\s*\.\s*/)),
integer: ($) => token(INTEGER),
float: ($) => token(FLOAT),
char: ($) => /\?(.|\\.)/,
boolean: ($) => choice("true", "false"),
nil: ($) => "nil",
_atom: ($) => choice($.atom, $.quoted_atom),
atom: ($) =>
token(
seq(
":",
choice(
ATOM_WORD_LITERAL,
...ATOM_OPERATOR_LITERALS,
...ATOM_SPECIAL_LITERALS
)
)
),
quoted_atom: ($) =>
seq(
alias($._quoted_atom_start, ":"),
choice($._quoted_i_double, $._quoted_i_single)
),
// Defines $._quoted_content_i_{name} and $._quoted_content_{name} rules,
// content with and without interpolation respectively
...defineQuoted(`"`, `"`, "double"),
...defineQuoted(`'`, `'`, "single"),
...defineQuoted(`'''`, `'''`, "heredoc_single"),
...defineQuoted(`"""`, `"""`, "heredoc_double"),
...defineQuoted(`(`, `)`, "parenthesis"),
...defineQuoted(`{`, `}`, "curly"),
...defineQuoted(`[`, `]`, "square"),
...defineQuoted(`<`, `>`, "angle"),
...defineQuoted(`|`, `|`, "bar"),
...defineQuoted(`/`, `/`, "slash"),
string: ($) => choice($._quoted_i_double, $._quoted_i_heredoc_double),
charlist: ($) => choice($._quoted_i_single, $._quoted_i_heredoc_single),
interpolation: ($) => seq("#{", optional($._expression), "}"),
escape_sequence: ($) =>
token(
seq(
"\\",
choice(
// Single escaped character
/[^ux]/,
// Hex byte
/x[0-9a-fA-F]{1,2}/,
/x{[0-9a-fA-F]+}/,
// Unicode code point
/u{[0-9a-fA-F]+}/,
/u[0-9a-fA-F]{4}/
)
)
),
sigil: ($) =>
seq(
"~",
choice(
seq(
alias(token.immediate(/[a-z]/), $.sigil_name),
choice(
$._quoted_i_double,
$._quoted_i_single,
$._quoted_i_heredoc_single,
$._quoted_i_heredoc_double,
$._quoted_i_parenthesis,
$._quoted_i_curly,
$._quoted_i_square,
$._quoted_i_angle,
$._quoted_i_bar,
$._quoted_i_slash
)
),
seq(
alias(token.immediate(/[A-Z]+/), $.sigil_name),
choice(
$._quoted_double,
$._quoted_single,
$._quoted_heredoc_single,
$._quoted_heredoc_double,
$._quoted_parenthesis,
$._quoted_curly,
$._quoted_square,
$._quoted_angle,
$._quoted_bar,
$._quoted_slash
)
)
),
optional(alias(token.immediate(/[a-zA-Z0-9]+/), $.sigil_modifiers))
),
keywords: ($) =>
// Right precedence, because we want to consume next items as long
// as there is a comma ahead
prec.right(sep1($.pair, ",")),
_keywords_with_trailing_separator: ($) =>
seq(sep1($.pair, ","), optional(",")),
pair: ($) => seq(field("key", $._keyword), field("value", $._expression)),
_keyword: ($) => choice($.keyword, $.quoted_keyword),
keyword: ($) =>
// See Ref 7. in the docs
token(
seq(
choice(
ATOM_WORD_LITERAL,
...ATOM_OPERATOR_LITERALS.filter((op) => op !== "::"),
...ATOM_SPECIAL_LITERALS
),
/:\s/
)
),
quoted_keyword: ($) =>
seq(
choice($._quoted_i_double, $._quoted_i_single),
token.immediate(/:\s/)
),
list: ($) => seq("[", optional($._items_with_trailing_separator), "]"),
tuple: ($) => seq("{", optional($._items_with_trailing_separator), "}"),
bitstring: ($) =>
seq("<<", optional($._items_with_trailing_separator), ">>"),
map: ($) =>
// Precedence over tuple
prec(
1,
seq(
"%",
optional($.struct),
"{",
optional(alias($._items_with_trailing_separator, $.map_content)),
"}"
)
),
struct: ($) =>
// Left precedence, because if there is a conflict involving `{}`,
// we want to treat it as map continuation rather than tuple
prec.left(
choice(
$.alias,
$._atom,
$.identifier,
$.unary_operator,
$.dot,
alias($._call_with_parentheses, $.call)
)
),
_items_with_trailing_separator: ($) =>
seq(
choice(
seq(sep1($._expression, ","), optional(",")),
seq(
optional(seq(sep1($._expression, ","), ",")),
alias($._keywords_with_trailing_separator, $.keywords)
)
)
),
_nullary_operator: ($) =>
// Nullary operators don't have any child nodes, so we reuse the
// operator_identifier node
alias(prec(PREC.RANGE_OP, ".."), $.operator_identifier),
unary_operator: ($) =>
choice(
unaryOp($, prec, PREC.CAPTURE_OP, "&", $._capture_expression),
unaryOp($, prec, PREC.UNARY_OPS, choice(...UNARY_OPS)),
unaryOp($, prec, PREC.AT_OP, "@"),
// Capture operand like &1 is a special case with higher precedence
unaryOp($, prec, PREC.CAPTURE_OPERAND, "&", $.integer)
),
_capture_expression: ($) =>
choice(
// Note that block expression is not allowed as capture operand,
// so we have an explicit sequence with the parentheses and higher
// precedence
prec(1, seq("(", $._expression, ")")),
$._expression
),
binary_operator: ($) =>
choice(
binaryOp($, prec.left, PREC.IN_MATCH_OPS, choice(...IN_MATCH_OPS)),
binaryOp(
$,
prec.right,
PREC.WHEN_OP,
"when",
$._expression,
choice($._expression, $.keywords)
),
binaryOp($, prec.right, PREC.TYPE_OP, "::"),
binaryOp(
$,
prec.right,
PREC.BAR_OP,
"|",
$._expression,
choice($._expression, $.keywords)
),
binaryOp($, prec.right, PREC.ASSOC_OP, "=>"),
binaryOp($, prec.right, PREC.MATCH_OP, "="),
binaryOp($, prec.left, PREC.OR_OPS, choice(...OR_OPS)),
binaryOp($, prec.left, PREC.AND_OPS, choice(...AND_OPS)),
binaryOp($, prec.left, PREC.COMP_OPS, choice(...COMP_OPS)),
binaryOp($, prec.left, PREC.REL_OPS, choice(...REL_OPS)),
binaryOp($, prec.left, PREC.ARROW_OPS, choice(...ARROW_OPS)),
binaryOp(
$,
prec.left,
PREC.IN_OPS,
choice("in", alias($._not_in, "not in"))
),
binaryOp($, prec.left, PREC.XOR_OP, "^^^"),
binaryOp($, prec.right, PREC.TERNARY_OP, "//"),
binaryOp($, prec.right, PREC.CONCAT_OPS, choice(...CONCAT_OPS)),
binaryOp($, prec.right, PREC.RANGE_OP, ".."),
binaryOp($, prec.left, PREC.ADD_OPS, choice(...ADD_OPS)),
binaryOp($, prec.left, PREC.MULT_OPS, choice(...MULT_OPS)),
binaryOp($, prec.left, PREC.POWER_OP, "**"),
// Operator with arity
binaryOp(
$,
prec.left,
PREC.MULT_OPS,
"/",
$.operator_identifier,
$.integer
)
),
operator_identifier: ($) =>
// Operators with the following changes:
//
// * exclude "=>" since it's not a valid operator identifier
// * exclude // since it's only valid after ..
// * exclude binary "-" and "+" as they are handled as unary below
//
// For unary operator identifiers we use the same precedence as
// operators, so that we get conflicts and resolve them dynamically
// (see grammar.conflicts for more details)
choice(
// Unary operators
prec(PREC.CAPTURE_OP, "&"),
prec(PREC.UNARY_OPS, choice(...UNARY_OPS)),
prec(PREC.AT_OP, "@"),
// Binary operators
...IN_MATCH_OPS,
"when",
"::",
"|",
"=",
...OR_OPS,
...AND_OPS,
...COMP_OPS,
...REL_OPS,
...ARROW_OPS,
"in",
alias($._not_in, "not in"),
"^^",
...CONCAT_OPS,
// The range operator has both a binary and a nullary version.
// The nullary version is already parsed as operator_identifier,
// so it covers this case
// ".."
...MULT_OPS,
"**",
"->",
"."
),
dot: ($) =>
prec(
PREC.DOT_OP,
seq(
field("left", $._expression),
field("operator", "."),
field("right", choice($.alias, $.tuple))
)
),
call: ($) => choice($._call_without_parentheses, $._call_with_parentheses),
_call_without_parentheses: ($) =>
choice(
$._local_call_without_parentheses,
$._local_call_just_do_block,
$._remote_call_without_parentheses
),
_call_with_parentheses: ($) =>
choice(
$._local_call_with_parentheses,
$._remote_call_with_parentheses,
$._anonymous_call,
$._double_call
),
// Note, calls have left precedence, so that `do end` block sticks to
// the outermost call
_local_call_without_parentheses: ($) =>
prec.left(
seq(
field("target", $.identifier),
alias($._call_arguments_without_parentheses, $.arguments),
optional(seq(optional($._newline_before_do), $.do_block))
)
),
_local_call_with_parentheses: ($) =>
prec.left(
seq(
field("target", $.identifier),
alias($._call_arguments_with_parentheses_immediate, $.arguments),
optional(seq(optional($._newline_before_do), $.do_block))
)
),
_local_call_just_do_block: ($) =>
// Lower precedence than identifier, because `foo bar do` is `foo(bar) do end`
prec(-1, seq(field("target", $.identifier), $.do_block)),
_remote_call_without_parentheses: ($) =>
prec.left(
seq(
field("target", alias($._remote_dot, $.dot)),
optional(alias($._call_arguments_without_parentheses, $.arguments)),
optional(seq(optional($._newline_before_do), $.do_block))
)
),
_remote_call_with_parentheses: ($) =>
prec.left(
seq(
field("target", alias($._remote_dot, $.dot)),
alias($._call_arguments_with_parentheses_immediate, $.arguments),
optional(seq(optional($._newline_before_do), $.do_block))
)
),
_remote_dot: ($) =>
prec(
PREC.DOT_OP,
seq(
field("left", $._expression),
field("operator", "."),
field(
"right",
choice(
$.identifier,
alias(choice(...RESERVED_WORD_TOKENS), $.identifier),
$.operator_identifier,
alias($._quoted_i_double, $.string),
alias($._quoted_i_single, $.charlist)
)
)
)
),
_anonymous_call: ($) =>
seq(
field("target", alias($._anonymous_dot, $.dot)),
alias($._call_arguments_with_parentheses, $.arguments)
),
_anonymous_dot: ($) =>
prec(
PREC.DOT_OP,
seq(field("left", $._expression), field("operator", "."))
),
_double_call: ($) =>
prec.left(
seq(
field(
"target",
alias(
choice(
$._local_call_with_parentheses,
$._remote_call_with_parentheses,
$._anonymous_call
),
$.call
)
),
alias($._call_arguments_with_parentheses, $.arguments),
optional(seq(optional($._newline_before_do), $.do_block))
)
),
_call_arguments_with_parentheses: ($) =>
seq("(", optional($._call_arguments_with_trailing_separator), ")"),
_call_arguments_with_parentheses_immediate: ($) =>
seq(
token.immediate("("),
optional($._call_arguments_with_trailing_separator),
")"
),
_call_arguments_with_trailing_separator: ($) =>
choice(
seq(
sep1($._expression, ","),
optional(
seq(",", alias($._keywords_with_trailing_separator, $.keywords))
)
),
alias($._keywords_with_trailing_separator, $.keywords)
),
_call_arguments_without_parentheses: ($) =>
// In stab clauses a newline can either separate multiple body expressions
// or multiple stab clauses, this falls under the $.body conflict. Given a
// multiline stab clause with trailing identifier like `1 -> 1 \n x \n 2 -> x`,
// there are two matching interpretations:
// * `x` as identifier and `2` as stab argument
// * `x 2` call as stab argument
// Similarly for `Mod.fun` or `mod.fun` the newline should terminate the call.
// Consequently, we reject the second interpretation using dynamic precedence
prec.dynamic(
-1,
// Right precedence, because `fun1 fun2 x, y` is `fun1(fun2(x, y))`
prec.right(
choice(
seq(sep1($._expression, ","), optional(seq(",", $.keywords))),
$.keywords
)
)
),
do_block: ($) =>
seq(
callKeywordBlock($, "do"),
repeat(
choice($.after_block, $.rescue_block, $.catch_block, $.else_block)
),
"end"
),
after_block: ($) => callKeywordBlock($, "after"),
rescue_block: ($) => callKeywordBlock($, "rescue"),
catch_block: ($) => callKeywordBlock($, "catch"),
else_block: ($) => callKeywordBlock($, "else"),
access_call: ($) =>
prec(
PREC.ACCESS,
seq(
field("target", $._expression),
token.immediate("["),
field("key", $._expression),
"]"
)
),
stab_clause: ($) =>
// Right precedence, because we want to consume body if any
prec.right(
seq(
optional(field("left", $._stab_clause_left)),
field("operator", "->"),
optional(field("right", $.body))
)
),
_stab_clause_left: ($) =>
choice(
alias($._stab_clause_arguments_with_parentheses, $.arguments),
alias(
$._stab_clause_arguments_with_parentheses_with_guard,
$.binary_operator
),
alias($._stab_clause_arguments_without_parentheses, $.arguments),
alias(
$._stab_clause_arguments_without_parentheses_with_guard,
$.binary_operator
)
),
_stab_clause_arguments_with_parentheses: ($) =>
// Precedence over block expression
prec(
1,
seq(
"(",
optional(
choice(
seq(
// We need the same expression precedence as below, so that we don't
// discard this rule in favour of the one below. We use right precedence,
// because in this case we can consume expression until the next comma
sep1(prec.right(PREC.WHEN_OP, $._expression), ","),
optional(seq(",", $.keywords))
),
$.keywords
)
),
")"
)
),
_stab_clause_arguments_without_parentheses: ($) =>
// We give the arguments and expression the same precedence as "when"
// binary operator, so that we get conflicts and resolve them dynamically
// (see the grammar.conflicts for more details)
prec(
PREC.WHEN_OP,
choice(
seq(
sep1(prec(PREC.WHEN_OP, $._expression), ","),
optional(seq(",", $.keywords))
),
$.keywords
)
),
_stab_clause_arguments_with_parentheses_with_guard: ($) =>
seq(
field(
"left",
alias($._stab_clause_arguments_with_parentheses, $.arguments)
),
field("operator", "when"),
field("right", $._expression)
),
_stab_clause_arguments_without_parentheses_with_guard: ($) =>
// Given `a when b ->`, the left stab operand can be interpreted either
// as a single argument item, or as binary operator with arguments on
// the left and guard expression on the right. Using dynamic precedence
// we favour the latter interpretation during dynamic conflict resolution
prec.dynamic(
1,
seq(
field(
"left",
alias($._stab_clause_arguments_without_parentheses, $.arguments)
),
field("operator", "when"),
field("right", $._expression)
)
),
body: ($) =>
choice(
$._terminator,
seq(
optional($._terminator),
sep1($._expression, $._terminator),
optional($._terminator)
)
),
anonymous_function: ($) =>
seq(
"fn",
optional($._terminator),
sep1($.stab_clause, $._terminator),
"end"
),
// A comment may be anywhere, we give it a lower precedence,
// so it doesn't intercept interpolation
comment: ($) => token(prec(-1, seq("#", /.*/))),
},
});
function sep1(rule, separator) {
return seq(rule, repeat(seq(separator, rule)));
}
function unaryOp($, assoc, precedence, operator, right = null) {
// Expression such as `x + y` falls under the "expression vs local call"
// conflict that we already have. By using dynamic precedence we penalize
// unary operator, so `x + y` is interpreted as binary operator (unless
// _before_unary_op is tokenized and forces unary operator interpretation)
return prec.dynamic(
-1,
assoc(
precedence,
seq(
optional($._before_unary_op),
field("operator", operator),
field("operand", right || $._expression)
)
)
);
}
function binaryOp($, assoc, precedence, operator, left = null, right = null) {
return assoc(
precedence,
seq(
field("left", left || $._expression),
field("operator", operator),
field("right", right || $._expression)
)
);
}
function callKeywordBlock($, start) {
return seq(
start,
optional($._terminator),
optional(
choice(
sep1(choice($.stab_clause), $._terminator),
seq(sep1(choice($._expression), $._terminator), optional($._terminator))
)
)
);
}
function defineQuoted(start, end, name) {
return {
[`_quoted_i_${name}`]: ($) =>
seq(
field("quoted_start", start),
optional(alias($[`_quoted_content_i_${name}`], $.quoted_content)),
repeat(
seq(
choice($.interpolation, $.escape_sequence),
optional(alias($[`_quoted_content_i_${name}`], $.quoted_content))
)
),
field("quoted_end", end)
),
[`_quoted_${name}`]: ($) =>
seq(
field("quoted_start", start),
optional(alias($[`_quoted_content_${name}`], $.quoted_content)),
repeat(
seq(
// The end delimiter may be escaped in non-interpolating strings too
$.escape_sequence,
optional(alias($[`_quoted_content_${name}`], $.quoted_content))
)
),
field("quoted_end", end)
),
};
}

@ -1,406 +0,0 @@
{
"name": "tree-sitter-elixir",
"version": "0.1.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "tree-sitter-elixir",
"version": "0.1.0",
"license": "Apache-2.0",
"dependencies": {
"nan": "^2.15.0"
},
"devDependencies": {
"clang-format": "^1.8.0",
"prettier": "^2.3.2",
"tree-sitter-cli": "^0.20.7"
}
},
"node_modules/async": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
"integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==",
"dev": true
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/clang-format": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/clang-format/-/clang-format-1.8.0.tgz",
"integrity": "sha512-pK8gzfu55/lHzIpQ1givIbWfn3eXnU7SfxqIwVgnn5jEM6j4ZJYjpFqFs4iSBPNedzRMmfjYjuQhu657WAXHXw==",
"dev": true,
"dependencies": {
"async": "^3.2.3",
"glob": "^7.0.0",
"resolve": "^1.1.6"
},
"bin": {
"check-clang-format": "bin/check-clang-format.js",
"clang-format": "index.js",
"git-clang-format": "bin/git-clang-format"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
},
"node_modules/function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"dev": true,
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.1"
},
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"dev": true,
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"node_modules/is-core-module": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
"integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
"dev": true,
"dependencies": {
"has": "^1.0.3"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/nan": {
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz",
"integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ=="
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dev": true,
"dependencies": {
"wrappy": "1"
}
},
"node_modules/path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
"node_modules/prettier": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz",
"integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/resolve": {
"version": "1.22.2",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
"integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==",
"dev": true,
"dependencies": {
"is-core-module": "^2.11.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
},
"bin": {
"resolve": "bin/resolve"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/tree-sitter-cli": {
"version": "0.20.7",
"resolved": "https://registry.npmjs.org/tree-sitter-cli/-/tree-sitter-cli-0.20.7.tgz",
"integrity": "sha512-MHABT8oCPr4D0fatsPo6ATQ9H4h9vHpPRjlxkxJs80tpfAEKGn6A1zU3eqfCKBcgmfZDe9CiL3rKOGMzYHwA3w==",
"dev": true,
"hasInstallScript": true,
"bin": {
"tree-sitter": "cli.js"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true
}
},
"dependencies": {
"async": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
"integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==",
"dev": true
},
"balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"clang-format": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/clang-format/-/clang-format-1.8.0.tgz",
"integrity": "sha512-pK8gzfu55/lHzIpQ1givIbWfn3eXnU7SfxqIwVgnn5jEM6j4ZJYjpFqFs4iSBPNedzRMmfjYjuQhu657WAXHXw==",
"dev": true,
"requires": {
"async": "^3.2.3",
"glob": "^7.0.0",
"resolve": "^1.1.6"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
},
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
"glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dev": true,
"requires": {
"function-bind": "^1.1.1"
}
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"dev": true,
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"is-core-module": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
"integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
"dev": true,
"requires": {
"has": "^1.0.3"
}
},
"minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"nan": {
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz",
"integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ=="
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dev": true,
"requires": {
"wrappy": "1"
}
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"dev": true
},
"path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
"prettier": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz",
"integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==",
"dev": true
},
"resolve": {
"version": "1.22.2",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
"integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==",
"dev": true,
"requires": {
"is-core-module": "^2.11.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
}
},
"supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true
},
"tree-sitter-cli": {
"version": "0.20.7",
"resolved": "https://registry.npmjs.org/tree-sitter-cli/-/tree-sitter-cli-0.20.7.tgz",
"integrity": "sha512-MHABT8oCPr4D0fatsPo6ATQ9H4h9vHpPRjlxkxJs80tpfAEKGn6A1zU3eqfCKBcgmfZDe9CiL3rKOGMzYHwA3w==",
"dev": true
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true
}
}
}

@ -1,40 +0,0 @@
{
"name": "tree-sitter-elixir",
"version": "0.1.0",
"description": "Elixir grammar for the tree-sitter parsing library",
"main": "bindings/node",
"keywords": [
"parser",
"lexer",
"elixir",
"tree-sitter"
],
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/elixir-lang/tree-sitter-elixir.git"
},
"scripts": {
"test": "tree-sitter test",
"format": "prettier --trailing-comma es5 --write grammar.js && clang-format -i src/scanner.c",
"format-check": "prettier --trailing-comma es5 --check grammar.js && cat src/scanner.c | clang-format src/scanner.c | diff src/scanner.c -"
},
"dependencies": {
"nan": "^2.15.0"
},
"devDependencies": {
"clang-format": "^1.8.0",
"prettier": "^2.3.2",
"tree-sitter-cli": "^0.20.7"
},
"tree-sitter": [
{
"scope": "source.elixir",
"file-types": [
"ex",
"exs"
],
"injection-regex": "^(ex|elixir)$"
}
]
}

@ -1,199 +0,0 @@
; Reserved keywords
["when" "and" "or" "not" "in" "not in" "fn" "do" "end" "catch" "rescue" "after" "else"] @keyword
; Operators
; * doc string
(unary_operator
operator: "@" @comment.doc
operand: (call
target: (identifier) @comment.doc.__attribute__
(arguments
[
(string) @comment.doc
(charlist) @comment.doc
(sigil
quoted_start: _ @comment.doc
quoted_end: _ @comment.doc) @comment.doc
(boolean) @comment.doc
]))
(#match? @comment.doc.__attribute__ "^(moduledoc|typedoc|doc)$"))
; * module attribute
(unary_operator
operator: "@" @attribute
operand: [
(identifier) @attribute
(call
target: (identifier) @attribute)
(boolean) @attribute
(nil) @attribute
])
; * capture operand
(unary_operator
operator: "&"
operand: (integer) @operator)
(operator_identifier) @operator
(unary_operator
operator: _ @operator)
(binary_operator
operator: _ @operator)
(dot
operator: _ @operator)
(stab_clause
operator: _ @operator)
; Literals
[
(boolean)
(nil)
] @constant
[
(integer)
(float)
] @number
(alias) @module
(call
target: (dot
left: (atom) @module))
(char) @constant
; Quoted content
(interpolation "#{" @punctuation.special "}" @punctuation.special) @embedded
(escape_sequence) @string.escape
[
(atom)
(quoted_atom)
(keyword)
(quoted_keyword)
] @string.special.symbol
[
(string)
(charlist)
] @string
; Note that we explicitly target sigil quoted start/end, so they are not overridden by delimiters
(sigil
(sigil_name) @__name__
quoted_start: _ @string
quoted_end: _ @string
(#match? @__name__ "^[sS]$")) @string
(sigil
(sigil_name) @__name__
quoted_start: _ @string.regex
quoted_end: _ @string.regex
(#match? @__name__ "^[rR]$")) @string.regex
(sigil
(sigil_name) @__name__
quoted_start: _ @string.special
quoted_end: _ @string.special) @string.special
; Calls
; * definition keyword
(call
target: (identifier) @keyword
(#match? @keyword "^(def|defdelegate|defexception|defguard|defguardp|defimpl|defmacro|defmacrop|defmodule|defn|defnp|defoverridable|defp|defprotocol|defstruct)$"))
; * kernel or special forms keyword
(call
target: (identifier) @keyword
(#match? @keyword "^(alias|case|cond|else|for|if|import|quote|raise|receive|require|reraise|super|throw|try|unless|unquote|unquote_splicing|use|with)$"))
; * function call
(call
target: [
; local
(identifier) @function
; remote
(dot
right: (identifier) @function)
])
; * just identifier in function definition
(call
target: (identifier) @keyword
(arguments
[
(identifier) @function
(binary_operator
left: (identifier) @function
operator: "when")
])
(#match? @keyword "^(def|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defp)$"))
; * pipe into identifier (definition)
(call
target: (identifier) @keyword
(arguments
(binary_operator
operator: "|>"
right: (identifier) @variable))
(#match? @keyword "^(def|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defp)$"))
; * pipe into identifier (function call)
(binary_operator
operator: "|>"
right: (identifier) @function)
; Identifiers
; * special
(
(identifier) @constant.builtin
(#match? @constant.builtin "^(__MODULE__|__DIR__|__ENV__|__CALLER__|__STACKTRACE__)$")
)
; * unused
(
(identifier) @comment.unused
(#match? @comment.unused "^_")
)
; * regular
(identifier) @variable
; Comment
(comment) @comment
; Punctuation
[
"%"
] @punctuation
[
","
";"
] @punctuation.delimiter
[
"("
")"
"["
"]"
"{"
"}"
"<<"
">>"
] @punctuation.bracket

@ -1,7 +0,0 @@
; Phoenix HTML template
((sigil
(sigil_name) @_sigil_name
(quoted_content) @injection.content)
(#eq? @_sigil_name "H")
(#set! injection.language "heex")
(#set! injection.combined))

@ -1,54 +0,0 @@
; Definitions
; * modules and protocols
(call
target: (identifier) @ignore
(arguments (alias) @name)
(#match? @ignore "^(defmodule|defprotocol)$")) @definition.module
; * functions/macros
(call
target: (identifier) @ignore
(arguments
[
; zero-arity functions with no parentheses
(identifier) @name
; regular function clause
(call target: (identifier) @name)
; function clause with a guard clause
(binary_operator
left: (call target: (identifier) @name)
operator: "when")
])
(#match? @ignore "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @definition.function
; References
; ignore calls to kernel/special-forms keywords
(call
target: (identifier) @ignore
(#match? @ignore "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defmodule|defprotocol|defimpl|defstruct|defexception|defoverridable|alias|case|cond|else|for|if|import|quote|raise|receive|require|reraise|super|throw|try|unless|unquote|unquote_splicing|use|with)$"))
; ignore module attributes
(unary_operator
operator: "@"
operand: (call
target: (identifier) @ignore))
; * function call
(call
target: [
; local
(identifier) @name
; remote
(dot
right: (identifier) @name)
]) @reference.call
; * pipe into function call
(binary_operator
operator: "|>"
right: (identifier) @name) @reference.call
; * modules
(alias) @name @reference.module

@ -1,23 +0,0 @@
#!/bin/bash
set -e
cd "$(dirname "$0")/.."
print_usage_and_exit() {
echo "Usage: $0"
echo ""
echo "Runs the parser against a predefined list of popular Elixir repositories"
echo ""
exit 1
}
if [ $# -ne 0 ]; then
print_usage_and_exit
fi
repos="elixir-lang/elixir elixir-lang/ex_doc elixir-plug/plug elixir-ecto/ecto dashbitco/broadway elixir-nx/nx elixir-nx/axon livebook-dev/livebook"
for repo in $repos; do
./scripts/parse_repo.sh $repo
done

@ -1,34 +0,0 @@
#!/bin/bash
set -e
cd "$(dirname "$0")/.."
print_usage_and_exit() {
echo "Usage: $0 <github-repo>"
echo ""
echo "Clones the given repository and runs the parser against all Elixir files"
echo ""
echo "## Examples"
echo ""
echo " $0 elixir-lang/elixir"
echo ""
exit 1
}
if [ $# -ne 1 ]; then
print_usage_and_exit
fi
gh_repo="$1"
dir="tmp/gh/${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/**/*.ex*"

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,636 +0,0 @@
#include <tree_sitter/parser.h>
// See references in grammar.externals
enum TokenType {
QUOTED_CONTENT_I_SINGLE,
QUOTED_CONTENT_I_DOUBLE,
QUOTED_CONTENT_I_HEREDOC_SINGLE,
QUOTED_CONTENT_I_HEREDOC_DOUBLE,
QUOTED_CONTENT_I_PARENTHESIS,
QUOTED_CONTENT_I_CURLY,
QUOTED_CONTENT_I_SQUARE,
QUOTED_CONTENT_I_ANGLE,
QUOTED_CONTENT_I_BAR,
QUOTED_CONTENT_I_SLASH,
QUOTED_CONTENT_SINGLE,
QUOTED_CONTENT_DOUBLE,
QUOTED_CONTENT_HEREDOC_SINGLE,
QUOTED_CONTENT_HEREDOC_DOUBLE,
QUOTED_CONTENT_PARENTHESIS,
QUOTED_CONTENT_CURLY,
QUOTED_CONTENT_SQUARE,
QUOTED_CONTENT_ANGLE,
QUOTED_CONTENT_BAR,
QUOTED_CONTENT_SLASH,
NEWLINE_BEFORE_DO,
NEWLINE_BEFORE_BINARY_OPERATOR,
NEWLINE_BEFORE_COMMENT,
BEFORE_UNARY_OPERATOR,
NOT_IN,
QUOTED_ATOM_START
};
static inline void advance(TSLexer *lexer) { lexer->advance(lexer, false); }
static inline void skip(TSLexer *lexer) { lexer->advance(lexer, true); }
// Note: some checks require several lexer steps of lookahead
// and alter its state, for these we use names check_*
static inline bool is_whitespace(int32_t c) {
return c == ' ' || c == '\t' || c == '\n' || c == '\r';
}
static inline bool is_inline_whitespace(int32_t c) {
return c == ' ' || c == '\t';
}
static inline bool is_newline(int32_t c) {
// Note: this implies \r\n is treated as two line breaks,
// but in our case it's fine, since multiple line breaks
// make no difference
return c == '\n' || c == '\r';
}
static inline bool is_digit(int32_t c) { return '0' <= c && c <= '9'; }
static inline bool check_keyword_end(TSLexer *lexer) {
if (lexer->lookahead == ':') {
advance(lexer);
return is_whitespace(lexer->lookahead);
}
return false;
}
static bool check_operator_end(TSLexer *lexer) {
// Keyword
if (lexer->lookahead == ':') {
return !check_keyword_end(lexer);
}
while (is_inline_whitespace(lexer->lookahead)) {
advance(lexer);
}
// Operator identifier with arity
if (lexer->lookahead == '/') {
advance(lexer);
while (is_whitespace(lexer->lookahead)) {
advance(lexer);
}
if (is_digit(lexer->lookahead)) {
return false;
}
}
return true;
}
const char token_terminators[] = {
// Operator starts
'@', '.', '+', '-', '^', '-', '*', '/', '<', '>', '|', '~', '=', '&', '\\',
'%',
// Delimiters
'{', '}', '[', ']', '(', ')', '"', '\'',
// Separators
',', ';',
// Comment
'#'};
const uint8_t token_terminators_length =
sizeof(token_terminators) / sizeof(char);
// Note: this is a heuristic as we only use this to distinguish word
// operators and we don't want to include complex Unicode ranges
static inline bool is_token_end(int32_t c) {
for (uint8_t i = 0; i < token_terminators_length; i++) {
if (c == token_terminators[i]) {
return true;
}
}
return is_whitespace(c);
}
typedef struct {
const enum TokenType token_type;
const bool supports_interpol;
const int32_t end_delimiter;
const uint8_t delimiter_length;
} QuotedContentInfo;
const QuotedContentInfo quoted_content_infos[] = {
{QUOTED_CONTENT_I_SINGLE, true, '\'', 1},
{QUOTED_CONTENT_I_DOUBLE, true, '"', 1},
{QUOTED_CONTENT_I_HEREDOC_SINGLE, true, '\'', 3},
{QUOTED_CONTENT_I_HEREDOC_DOUBLE, true, '"', 3},
{QUOTED_CONTENT_I_PARENTHESIS, true, ')', 1},
{QUOTED_CONTENT_I_CURLY, true, '}', 1},
{QUOTED_CONTENT_I_SQUARE, true, ']', 1},
{QUOTED_CONTENT_I_ANGLE, true, '>', 1},
{QUOTED_CONTENT_I_BAR, true, '|', 1},
{QUOTED_CONTENT_I_SLASH, true, '/', 1},
{QUOTED_CONTENT_SINGLE, false, '\'', 1},
{QUOTED_CONTENT_DOUBLE, false, '"', 1},
{QUOTED_CONTENT_HEREDOC_SINGLE, false, '\'', 3},
{QUOTED_CONTENT_HEREDOC_DOUBLE, false, '"', 3},
{QUOTED_CONTENT_PARENTHESIS, false, ')', 1},
{QUOTED_CONTENT_CURLY, false, '}', 1},
{QUOTED_CONTENT_SQUARE, false, ']', 1},
{QUOTED_CONTENT_ANGLE, false, '>', 1},
{QUOTED_CONTENT_BAR, false, '|', 1},
{QUOTED_CONTENT_SLASH, false, '/', 1},
};
const uint8_t quoted_content_infos_length =
sizeof(quoted_content_infos) / sizeof(QuotedContentInfo);
static inline int8_t find_quoted_token_info(const bool *valid_symbols) {
// Quoted tokens are mutually exclusive and only one should be valid
// at a time. If multiple are valid it means we parse an arbitrary
// code outside quotes, in which case we don't want to tokenize it as
// quoted content.
if (valid_symbols[QUOTED_CONTENT_I_SINGLE] &&
valid_symbols[QUOTED_CONTENT_I_DOUBLE]) {
return -1;
}
for (uint8_t i = 0; i < quoted_content_infos_length; i++) {
if (valid_symbols[quoted_content_infos[i].token_type]) {
return i;
}
}
return -1;
}
static bool scan_quoted_content(TSLexer *lexer, const QuotedContentInfo *info) {
lexer->result_symbol = info->token_type;
bool is_heredoc = (info->delimiter_length == 3);
for (bool has_content = false; true; has_content = true) {
bool newline = false;
if (is_newline(lexer->lookahead)) {
advance(lexer);
has_content = true;
newline = true;
while (is_whitespace(lexer->lookahead)) {
advance(lexer);
}
}
lexer->mark_end(lexer);
if (lexer->lookahead == info->end_delimiter) {
uint8_t length = 1;
while (length < info->delimiter_length) {
advance(lexer);
if (lexer->lookahead == info->end_delimiter) {
length++;
} else {
break;
}
}
if (length == info->delimiter_length && (!is_heredoc || newline)) {
return has_content;
}
} else {
if (lexer->lookahead == '#') {
advance(lexer);
if (info->supports_interpol && lexer->lookahead == '{') {
return has_content;
}
} else if (lexer->lookahead == '\\') {
advance(lexer);
if (is_heredoc && lexer->lookahead == '\n') {
// We need to know about the newline to correctly recognise
// heredoc end delimiter, so we intentionally ignore
// escaping
} else if (info->supports_interpol ||
lexer->lookahead == info->end_delimiter) {
return has_content;
}
} else if (lexer->lookahead == '\0') {
// If we reached the end of the file, this means there is no
// end delimiter, so the syntax is invalid. In that case we
// want to treat all the scanned content as quoted content.
return has_content;
} else {
advance(lexer);
}
}
}
return false;
}
static bool scan_newline(TSLexer *lexer, const bool *valid_symbols) {
advance(lexer);
while (is_whitespace(lexer->lookahead)) {
advance(lexer);
}
// Note we include all the whitespace after newline, so that the
// parser doesn't have to go through it again
lexer->mark_end(lexer);
if (lexer->lookahead == '#') {
lexer->result_symbol = NEWLINE_BEFORE_COMMENT;
return true;
}
if (lexer->lookahead == 'd' && valid_symbols[NEWLINE_BEFORE_DO]) {
lexer->result_symbol = NEWLINE_BEFORE_DO;
advance(lexer);
if (lexer->lookahead == 'o') {
advance(lexer);
return is_token_end(lexer->lookahead);
}
return false;
}
if (valid_symbols[NEWLINE_BEFORE_BINARY_OPERATOR]) {
lexer->result_symbol = NEWLINE_BEFORE_BINARY_OPERATOR;
// &&, &&&
if (lexer->lookahead == '&') {
advance(lexer);
if (lexer->lookahead == '&') {
advance(lexer);
if (lexer->lookahead == '&') {
advance(lexer);
return check_operator_end(lexer);
} else {
return check_operator_end(lexer);
}
}
// =, ==, ===, =~, =>
} else if (lexer->lookahead == '=') {
advance(lexer);
if (lexer->lookahead == '=') {
advance(lexer);
if (lexer->lookahead == '=') {
advance(lexer);
return check_operator_end(lexer);
} else {
return check_operator_end(lexer);
}
} else if (lexer->lookahead == '~') {
advance(lexer);
return check_operator_end(lexer);
} else if (lexer->lookahead == '>') {
advance(lexer);
return check_operator_end(lexer);
} else {
return check_operator_end(lexer);
}
// ::
} else if (lexer->lookahead == ':') {
advance(lexer);
if (lexer->lookahead == ':') {
advance(lexer);
// Ignore ::: atom
if (lexer->lookahead == ':')
return false;
return check_operator_end(lexer);
}
// ++, +++
} else if (lexer->lookahead == '+') {
advance(lexer);
if (lexer->lookahead == '+') {
advance(lexer);
if (lexer->lookahead == '+') {
advance(lexer);
return check_operator_end(lexer);
} else {
return check_operator_end(lexer);
}
}
// --, ---, ->
} else if (lexer->lookahead == '-') {
advance(lexer);
if (lexer->lookahead == '-') {
advance(lexer);
if (lexer->lookahead == '-') {
advance(lexer);
return check_operator_end(lexer);
} else {
return check_operator_end(lexer);
}
} else if (lexer->lookahead == '>') {
advance(lexer);
return check_operator_end(lexer);
}
// <, <=, <-, <>, <~, <~>, <|>, <<<, <<~
} else if (lexer->lookahead == '<') {
advance(lexer);
if (lexer->lookahead == '=' || lexer->lookahead == '-' ||
lexer->lookahead == '>') {
advance(lexer);
return check_operator_end(lexer);
} else if (lexer->lookahead == '~') {
advance(lexer);
if (lexer->lookahead == '>') {
advance(lexer);
return check_operator_end(lexer);
} else {
return check_operator_end(lexer);
}
} else if (lexer->lookahead == '|') {
advance(lexer);
if (lexer->lookahead == '>') {
advance(lexer);
return check_operator_end(lexer);
}
} else if (lexer->lookahead == '<') {
advance(lexer);
if (lexer->lookahead == '<' || lexer->lookahead == '~') {
advance(lexer);
return check_operator_end(lexer);
}
} else {
return check_operator_end(lexer);
}
// >, >=, >>>
} else if (lexer->lookahead == '>') {
advance(lexer);
if (lexer->lookahead == '=') {
advance(lexer);
return check_operator_end(lexer);
} else if (lexer->lookahead == '>') {
advance(lexer);
if (lexer->lookahead == '>') {
advance(lexer);
return check_operator_end(lexer);
}
} else {
return check_operator_end(lexer);
}
// ^^^
} else if (lexer->lookahead == '^') {
advance(lexer);
if (lexer->lookahead == '^') {
advance(lexer);
if (lexer->lookahead == '^') {
advance(lexer);
return check_operator_end(lexer);
}
}
// !=, !==
} else if (lexer->lookahead == '!') {
advance(lexer);
if (lexer->lookahead == '=') {
advance(lexer);
if (lexer->lookahead == '=') {
advance(lexer);
return check_operator_end(lexer);
} else {
return check_operator_end(lexer);
}
}
// ~>, ~>>
} else if (lexer->lookahead == '~') {
advance(lexer);
if (lexer->lookahead == '>') {
advance(lexer);
if (lexer->lookahead == '>') {
advance(lexer);
return check_operator_end(lexer);
} else {
return check_operator_end(lexer);
}
}
// |, ||, |||, |>
} else if (lexer->lookahead == '|') {
advance(lexer);
if (lexer->lookahead == '|') {
advance(lexer);
if (lexer->lookahead == '|') {
advance(lexer);
return check_operator_end(lexer);
} else {
return check_operator_end(lexer);
}
} else if (lexer->lookahead == '>') {
advance(lexer);
return check_operator_end(lexer);
} else {
return check_operator_end(lexer);
}
// *, **
} else if (lexer->lookahead == '*') {
advance(lexer);
if (lexer->lookahead == '*') {
advance(lexer);
return check_operator_end(lexer);
} else {
return check_operator_end(lexer);
}
// / //
} else if (lexer->lookahead == '/') {
advance(lexer);
if (lexer->lookahead == '/') {
advance(lexer);
return check_operator_end(lexer);
} else {
return check_operator_end(lexer);
}
// ., ..
} else if (lexer->lookahead == '.') {
advance(lexer);
if (lexer->lookahead == '.') {
advance(lexer);
// Ignore ... identifier
if (lexer->lookahead == '.')
return false;
return check_operator_end(lexer);
} else {
return check_operator_end(lexer);
}
// double slash
} else if (lexer->lookahead == '\\') {
advance(lexer);
if (lexer->lookahead == '\\') {
advance(lexer);
return check_operator_end(lexer);
}
} else if (lexer->lookahead == 'w') {
advance(lexer);
if (lexer->lookahead == 'h') {
advance(lexer);
if (lexer->lookahead == 'e') {
advance(lexer);
if (lexer->lookahead == 'n') {
advance(lexer);
return is_token_end(lexer->lookahead) && check_operator_end(lexer);
}
}
}
} else if (lexer->lookahead == 'a') {
advance(lexer);
if (lexer->lookahead == 'n') {
advance(lexer);
if (lexer->lookahead == 'd') {
advance(lexer);
return is_token_end(lexer->lookahead) && check_operator_end(lexer);
}
}
// or
} else if (lexer->lookahead == 'o') {
advance(lexer);
if (lexer->lookahead == 'r') {
advance(lexer);
return is_token_end(lexer->lookahead) && check_operator_end(lexer);
}
// in
} else if (lexer->lookahead == 'i') {
advance(lexer);
if (lexer->lookahead == 'n') {
advance(lexer);
return is_token_end(lexer->lookahead) && check_operator_end(lexer);
}
// not in
} else if (lexer->lookahead == 'n') {
advance(lexer);
if (lexer->lookahead == 'o') {
advance(lexer);
if (lexer->lookahead == 't') {
advance(lexer);
while (is_inline_whitespace(lexer->lookahead)) {
advance(lexer);
}
if (lexer->lookahead == 'i') {
advance(lexer);
if (lexer->lookahead == 'n') {
advance(lexer);
return is_token_end(lexer->lookahead) &&
check_operator_end(lexer);
}
}
}
}
}
}
return false;
}
static bool scan(TSLexer *lexer, const bool *valid_symbols) {
int8_t quoted_content_info_idx = find_quoted_token_info(valid_symbols);
// Quoted content, which matches any character except for close
// delimiters, escapes and interpolations
if (quoted_content_info_idx != -1) {
const QuotedContentInfo info =
quoted_content_infos[quoted_content_info_idx];
return scan_quoted_content(lexer, &info);
}
bool skipped_whitespace = false;
while (is_inline_whitespace(lexer->lookahead)) {
skipped_whitespace = true;
skip(lexer);
}
// Newline, which is either tokenized as a special newline or ignored
if (is_newline(lexer->lookahead) &&
(valid_symbols[NEWLINE_BEFORE_DO] ||
valid_symbols[NEWLINE_BEFORE_BINARY_OPERATOR] ||
valid_symbols[NEWLINE_BEFORE_COMMENT])) {
return scan_newline(lexer, valid_symbols);
}
// before unary +
if (lexer->lookahead == '+') {
if (skipped_whitespace && valid_symbols[BEFORE_UNARY_OPERATOR]) {
lexer->mark_end(lexer);
advance(lexer);
if (lexer->lookahead == '+' || lexer->lookahead == ':' ||
lexer->lookahead == '/') {
return false;
}
if (is_whitespace(lexer->lookahead)) {
return false;
}
lexer->result_symbol = BEFORE_UNARY_OPERATOR;
return true;
}
// before unary -
} else if (lexer->lookahead == '-') {
if (skipped_whitespace && valid_symbols[BEFORE_UNARY_OPERATOR]) {
lexer->mark_end(lexer);
lexer->result_symbol = BEFORE_UNARY_OPERATOR;
advance(lexer);
if (lexer->lookahead == '-' || lexer->lookahead == '>' ||
lexer->lookahead == ':' || lexer->lookahead == '/') {
return false;
}
if (is_whitespace(lexer->lookahead)) {
return false;
}
return true;
}
// not in
} else if (lexer->lookahead == 'n') {
if (valid_symbols[NOT_IN]) {
lexer->result_symbol = NOT_IN;
advance(lexer);
if (lexer->lookahead == 'o') {
advance(lexer);
if (lexer->lookahead == 't') {
advance(lexer);
while (is_inline_whitespace(lexer->lookahead)) {
advance(lexer);
}
if (lexer->lookahead == 'i') {
advance(lexer);
if (lexer->lookahead == 'n') {
advance(lexer);
return is_token_end(lexer->lookahead);
}
}
}
}
}
// quoted atom start
} else if (lexer->lookahead == ':') {
if (valid_symbols[QUOTED_ATOM_START]) {
advance(lexer);
lexer->mark_end(lexer);
lexer->result_symbol = QUOTED_ATOM_START;
if (lexer->lookahead == '"' || lexer->lookahead == '\'') {
return true;
}
}
}
return false;
}
void *tree_sitter_elixir_external_scanner_create() { return NULL; }
bool tree_sitter_elixir_external_scanner_scan(void *payload, TSLexer *lexer,
const bool *valid_symbols) {
return scan(lexer, valid_symbols);
}
unsigned tree_sitter_elixir_external_scanner_serialize(void *payload,
char *buffer) {
return 0;
}
void tree_sitter_elixir_external_scanner_deserialize(void *payload,
const char *buffer,
unsigned length) {}
void tree_sitter_elixir_external_scanner_destroy(void *payload) {}

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

@ -1,97 +0,0 @@
=====================================
empty
=====================================
#
---
(source
(comment))
=====================================
single line
=====================================
# single comment
---
(source
(comment))
=====================================
multiple start symbols
=====================================
### multiple "#"
---
(source
(comment))
=====================================
many consecutive lines
=====================================
# many
# consecutive
1
# lines
---
(source
(comment)
(comment)
(integer)
(comment))
=====================================
in the same line as regular code
=====================================
1 # comment
---
(source
(integer)
(comment))
=====================================
matches inside a nested structure
=====================================
[ 1 ## inside a list
, { 2 # and a tuple, too!
, 3 }
]
---
(source
(list
(integer)
(comment)
(tuple
(integer)
(comment)
(integer))))
=====================================
does not match inside a string
=====================================
"# string"
"this is #{interpolation}"
---
(source
(string
(quoted_content))
(string
(quoted_content)
(interpolation (identifier))))

@ -1,939 +0,0 @@
=====================================
call without arguments
=====================================
fun do
a
end
---
(source
(call
(identifier)
(do_block
(identifier))))
=====================================
call with arguments in parentheses
=====================================
fun(a, b) do
c
end
---
(source
(call
(identifier)
(arguments
(identifier)
(identifier))
(do_block
(identifier))))
=====================================
call with arguments without parentheses
=====================================
fun a, b do
c
end
---
(source
(call
(identifier)
(arguments
(identifier)
(identifier))
(do_block
(identifier))))
=====================================
remote call
=====================================
Mod.fun do
a
end
---
(source
(call
(dot
(alias)
(identifier))
(do_block
(identifier))))
=====================================
sticks to the outermost call
=====================================
outer_fun inner_fun arg do
a
end
---
(source
(call
(identifier)
(arguments
(call
(identifier)
(arguments
(identifier))))
(do_block
(identifier))))
=====================================
newline before do
=====================================
fun x
do
x
end
fun x
# comment
do
x
end
fun()
do
x
end
Mod.fun x
do
x
end
---
(source
(call
(identifier)
(arguments
(identifier))
(do_block
(identifier)))
(call
(identifier)
(arguments
(identifier))
(comment)
(do_block
(identifier)))
(call
(identifier)
(arguments)
(do_block
(identifier)))
(call
(dot
(alias)
(identifier))
(arguments
(identifier))
(do_block
(identifier))))
=====================================
stab clause / no arguments
=====================================
fun do
() -> x
end
---
(source
(call
(identifier)
(do_block
(stab_clause
(arguments)
(body
(identifier))))))
=====================================
stab clause / no arguments without parentheses
=====================================
fun do
-> x
end
---
(source
(call
(identifier)
(do_block
(stab_clause
(body
(identifier))))))
=====================================
stab clause / one argument
=====================================
fun do
x -> x
end
---
(source
(call
(identifier)
(do_block
(stab_clause
(arguments
(identifier))
(body
(identifier))))))
=====================================
stab clause / many arguments
=====================================
fun do
x, y, 1 -> :ok
end
---
(source
(call
(identifier)
(do_block
(stab_clause
(arguments
(identifier)
(identifier)
(integer))
(body
(atom))))))
=====================================
stab clause / arguments in parentheses
=====================================
fun do
(x, y) -> :ok
end
---
(source
(call
(identifier)
(do_block
(stab_clause
(arguments
(identifier)
(identifier))
(body
(atom))))))
=====================================
stab clause / many clauses
=====================================
fun do
1 -> :yes
2 -> :no
other -> :maybe
end
---
(source
(call
(identifier)
(do_block
(stab_clause
(arguments
(integer))
(body
(atom)))
(stab_clause
(arguments
(integer))
(body
(atom)))
(stab_clause
(arguments
(identifier))
(body
(atom))))))
=====================================
stab clause / multiline expression
=====================================
fun do
x ->
y
x
end
---
(source
(call
(identifier)
(do_block
(stab_clause
(arguments
(identifier))
(body
(identifier)
(identifier))))))
=====================================
stab clause / with guard / no arguments
=====================================
fun do
() when node() == :nonode@nohost -> true
end
---
(source
(call
(identifier)
(do_block
(stab_clause
(binary_operator
(arguments)
(binary_operator
(call
(identifier)
(arguments))
(atom)))
(body
(boolean))))))
=====================================
stab clause / with guard / one argument
=====================================
fun do
x when x == [] -> x
end
---
(source
(call
(identifier)
(do_block
(stab_clause
(binary_operator
(arguments
(identifier))
(binary_operator
(identifier)
(list)))
(body
(identifier))))))
=====================================
stab clause / with guard / multiple arguments
=====================================
fun do
x, y when x == [] -> x
end
---
(source
(call
(identifier)
(do_block
(stab_clause
(binary_operator
(arguments
(identifier)
(identifier))
(binary_operator
(identifier)
(list)))
(body
(identifier))))))
=====================================
stab clause / with guard / arguments in parentheses
=====================================
fun do
(x, y) when y == [] -> y
end
---
(source
(call
(identifier)
(do_block
(stab_clause
(binary_operator
(arguments
(identifier)
(identifier))
(binary_operator
(identifier)
(list)))
(body
(identifier))))))
=====================================
stab clause / with guard / multiple guards
=====================================
fun do
x when x > 10 when x < 5 -> x
end
---
(source
(call
(identifier)
(do_block
(stab_clause
(binary_operator
(arguments
(identifier))
(binary_operator
(binary_operator
(identifier)
(integer))
(binary_operator
(identifier)
(integer))))
(body
(identifier))))))
=====================================
stab clause / edge cases / no stab
=====================================
foo do
a when a
end
foo do
([])
end
---
(source
(call
(identifier)
(do_block
(binary_operator
(identifier)
(identifier))))
(call
(identifier)
(do_block
(block
(list)))))
=====================================
stab clause / edge cases / "when" in arguments
=====================================
foo do
a when b, c when d == e -> 1
(a, a when b) -> 1
end
---
(source
(call
(identifier)
(do_block
(stab_clause
(binary_operator
(arguments
(binary_operator
(identifier)
(identifier))
(identifier))
(binary_operator
(identifier)
(identifier)))
(body
(integer)))
(stab_clause
(arguments
(identifier)
(binary_operator
(identifier)
(identifier)))
(body
(integer))))))
=====================================
stab clause / edge cases / block argument
=====================================
foo do
(x; y) -> 1
((x; y)) -> 1
end
---
(source
(call
(identifier)
(do_block
(stab_clause
(arguments
(block
(identifier)
(identifier)))
(body
(integer)))
(stab_clause
(arguments
(block
(identifier)
(identifier)))
(body
(integer))))))
=====================================
stab clause / edge cases / operator with lower precedence than "when"
=====================================
foo do
x <- y when x -> y
end
foo do
(x <- y) when x -> y
end
---
(source
(call
(identifier)
(do_block
(stab_clause
(arguments
(binary_operator
(identifier)
(binary_operator
(identifier)
(identifier))))
(body
(identifier)))))
(call
(identifier)
(do_block
(stab_clause
(binary_operator
(arguments
(binary_operator
(identifier)
(identifier)))
(identifier))
(body
(identifier))))))
=====================================
stab clause / edge cases / empty
=====================================
fun do->end
---
(source
(call
(identifier)
(do_block
(stab_clause))))
=====================================
stab clause / edge cases / trailing call in multiline clause
=====================================
fun do
1 ->
1
x
1 ->
1
end
fun do
1 ->
1
Mod.fun
1 ->
1
end
fun do
1 ->
1
mod.fun
1 ->
1
end
fun do
1 ->
1
x 1 ->
1
end
---
(source
(call
(identifier)
(do_block
(stab_clause
(arguments
(integer))
(body
(integer)
(identifier)))
(stab_clause
(arguments
(integer))
(body
(integer)))))
(call
(identifier)
(do_block
(stab_clause
(arguments
(integer))
(body
(integer)
(call
(dot
(alias)
(identifier)))))
(stab_clause
(arguments
(integer))
(body
(integer)))))
(call
(identifier)
(do_block
(stab_clause
(arguments
(integer))
(body
(integer)
(call
(dot
(identifier)
(identifier)))))
(stab_clause
(arguments
(integer))
(body
(integer)))))
(call
(identifier)
(do_block
(stab_clause
(arguments
(integer))
(body
(integer)))
(stab_clause
(arguments
(call
(identifier)
(arguments
(integer))))
(body
(integer))))))
=====================================
stab clause / edge cases / empty right-hand-side
=====================================
fun do
x ->
end
---
(source
(call
(identifier)
(do_block
(stab_clause
(arguments
(identifier))
(body)))))
=====================================
pattern matching
=====================================
fun do
[h | tail] -> {h, tail}
end
---
(source
(call
(identifier)
(do_block
(stab_clause
(arguments
(list
(binary_operator
(identifier)
(identifier))))
(body
(tuple
(identifier)
(identifier)))))))
=====================================
child blocks / after
=====================================
fun do
x
after
y
end
---
(source
(call
(identifier)
(do_block
(identifier)
(after_block
(identifier)))))
=====================================
child blocks / catch
=====================================
fun do
x
catch
y
end
---
(source
(call
(identifier)
(do_block
(identifier)
(catch_block
(identifier)))))
=====================================
child blocks / else
=====================================
fun do
x
else
y
end
---
(source
(call
(identifier)
(do_block
(identifier)
(else_block
(identifier)))))
=====================================
child blocks / rescue
=====================================
fun do
x
rescue
y
end
---
(source
(call
(identifier)
(do_block
(identifier)
(rescue_block
(identifier)))))
=====================================
child blocks / duplicated
=====================================
fun do
x
after
y
after
z
end
---
(source
(call
(identifier)
(do_block
(identifier)
(after_block
(identifier))
(after_block
(identifier)))))
=====================================
child blocks / mixed
=====================================
fun do
x
else
y
after
z
end
---
(source
(call
(identifier)
(do_block
(identifier)
(else_block
(identifier))
(after_block
(identifier)))))
=====================================
child blocks / stab clause
=====================================
fun do
x
rescue
y -> y
end
---
(source
(call
(identifier)
(do_block
(identifier)
(rescue_block
(stab_clause
(arguments
(identifier))
(body
(identifier)))))))
=====================================
child blocks / keyword pattern with child block start token
=====================================
fun do
x
after
after
after: 1 -> y
end
---
(source
(call
(identifier)
(do_block
(identifier)
(after_block)
(after_block
(stab_clause
(arguments
(keywords
(pair
(keyword)
(integer))))
(body
(identifier)))))))
=====================================
[field names]
=====================================
fun do
x -> x
x when x == [] -> x
end
---
(source
(call
target: (identifier)
(do_block
(stab_clause
left: (arguments
(identifier))
right: (body
(identifier)))
(stab_clause
left: (binary_operator
left: (arguments
(identifier))
right: (binary_operator
left: (identifier)
right: (list)))
right: (body
(identifier))))))

@ -1,118 +0,0 @@
=====================================
operator with arity (valid and supported by IEx.Helpers.h)
=====================================
::/2
@ / 1
& / 1
not / 1
not in / 2
* / 2
h +/2
---
(source
(binary_operator
(operator_identifier)
(integer))
(binary_operator
(operator_identifier)
(integer))
(binary_operator
(operator_identifier)
(integer))
(binary_operator
(operator_identifier)
(integer))
(binary_operator
(operator_identifier)
(integer))
(binary_operator
(operator_identifier)
(integer))
(call
(identifier)
(arguments
(binary_operator
(operator_identifier)
(integer)))))
=====================================
stab and slash ambiguity
=====================================
(-> / 2)
(-> / / 2)
---
(source
(block
(binary_operator
(operator_identifier)
(integer)))
(block
(stab_clause
(body
(binary_operator
(operator_identifier)
(integer))))))
=====================================
unary operator and slash ambiguity
=====================================
& / 2
& / / 2
---
(source
(binary_operator
(operator_identifier)
(integer))
(unary_operator
(binary_operator
(operator_identifier)
(integer))))
=====================================
map with identifiers
=====================================
%{a}
%{a, b}
---
(source
(map
(map_content
(identifier)))
(map
(map_content
(identifier)
(identifier))))
=====================================
def with remote call
=====================================
def Mod.fun(x), do: 1
---
(source
(call
(identifier)
(arguments
(call
(dot
(alias)
(identifier))
(arguments
(identifier)))
(keywords
(pair
(keyword)
(integer))))))

@ -1,311 +0,0 @@
=====================================
no arguments
=====================================
fn() -> 1 end
fn () -> 1 end
---
(source
(anonymous_function
(stab_clause
(arguments)
(body
(integer))))
(anonymous_function
(stab_clause
(arguments)
(body
(integer)))))
=====================================
no arguments without parentheses
=====================================
fn -> 1 end
---
(source
(anonymous_function
(stab_clause
(body
(integer)))))
=====================================
one argument
=====================================
fn(x) -> x end
---
(source
(anonymous_function
(stab_clause
(arguments
(identifier))
(body
(identifier)))))
=====================================
one argument without parentheses
=====================================
fn x -> x end
---
(source
(anonymous_function
(stab_clause
(arguments
(identifier))
(body
(identifier)))))
=====================================
many arguments
=====================================
fn(x, y, z) -> x + y end
---
(source
(anonymous_function
(stab_clause
(arguments
(identifier)
(identifier)
(identifier))
(body
(binary_operator
(identifier)
(identifier))))))
=====================================
many arguments without parentheses
=====================================
fn x, y -> x + y end
---
(source
(anonymous_function
(stab_clause
(arguments
(identifier)
(identifier))
(body
(binary_operator
(identifier)
(identifier))))))
=====================================
multiline body
=====================================
fn x, y ->
y
x
end
---
(source
(anonymous_function
(stab_clause
(arguments
(identifier)
(identifier))
(body
(identifier)
(identifier)))))
=====================================
many clauses
=====================================
fn
1 -> :yes
2 -> :no
other -> :maybe
end
---
(source
(anonymous_function
(stab_clause
(arguments
(integer))
(body
(atom)))
(stab_clause
(arguments
(integer))
(body
(atom)))
(stab_clause
(arguments
(identifier))
(body
(atom)))))
=====================================
with guard / no arguments
=====================================
fn
() when node() == :nonode@nohost -> true
end
---
(source
(anonymous_function
(stab_clause
(binary_operator
(arguments)
(binary_operator
(call
(identifier)
(arguments))
(atom)))
(body
(boolean)))))
=====================================
with guard / one argument
=====================================
fn
x when x == [] -> x
end
---
(source
(anonymous_function
(stab_clause
(binary_operator
(arguments
(identifier))
(binary_operator
(identifier)
(list)))
(body
(identifier)))))
=====================================
with guard / multiple arguments
=====================================
fn
x, y when x == [] -> x
end
---
(source
(anonymous_function
(stab_clause
(binary_operator
(arguments
(identifier)
(identifier))
(binary_operator
(identifier)
(list)))
(body
(identifier)))))
=====================================
with guard / arguments in parentheses
=====================================
fn
(x, y) when y == [] -> y
end
---
(source
(anonymous_function
(stab_clause
(binary_operator
(arguments
(identifier)
(identifier))
(binary_operator
(identifier)
(list)))
(body
(identifier)))))
=====================================
with guard / multiple guards
=====================================
fn
x when x > 10 when x < 5 -> x
end
---
(source
(anonymous_function
(stab_clause
(binary_operator
(arguments
(identifier))
(binary_operator
(binary_operator
(identifier)
(integer))
(binary_operator
(identifier)
(integer))))
(body
(identifier)))))
=====================================
pattern matching
=====================================
fn
[h | tail] -> {h, tail}
%{x: x} when x == 1 -> 1
end
---
(source
(anonymous_function
(stab_clause
(arguments
(list
(binary_operator
(identifier)
(identifier))))
(body
(tuple
(identifier)
(identifier))))
(stab_clause
(binary_operator
(arguments
(map
(map_content
(keywords
(pair
(keyword)
(identifier))))))
(binary_operator
(identifier)
(integer)))
(body
(integer)))))

@ -1,230 +0,0 @@
=====================================
empty
=====================================
()
---
(source
(block))
=====================================
single expression
=====================================
(1)
---
(source
(block
(integer)))
=====================================
multiple expressions separated by newline
=====================================
(
1
2
)
---
(source
(block
(integer)
(integer)))
=====================================
multiple expressions separated by semicolon
=====================================
(1;2)
---
(source
(block
(integer)
(integer)))
=====================================
multiple expressions separated by mixed separators
=====================================
(
1
;
2
)
---
(source
(block
(integer)
(integer)))
=====================================
leading semicolon
=====================================
(;1;2)
---
(source
(block
(integer)
(integer)))
=====================================
trailing semicolon
=====================================
(1;2;)
---
(source
(block
(integer)
(integer)))
=====================================
stab clause / multiple clauses
=====================================
(x -> x; y -> y
z -> z)
---
(source
(block
(stab_clause
(arguments
(identifier))
(body
(identifier)))
(stab_clause
(arguments
(identifier))
(body
(identifier)))
(stab_clause
(arguments
(identifier))
(body
(identifier)))))
=====================================
stab clause / multiple arguments
=====================================
(x, y, z -> x)
((x, y, z) -> x)
---
(source
(block
(stab_clause
(arguments
(identifier)
(identifier)
(identifier))
(body
(identifier))))
(block
(stab_clause
(arguments
(identifier)
(identifier)
(identifier))
(body
(identifier)))))
=====================================
stab clause / guard
=====================================
(x, y when x == y -> 1)
((x, y when x == y -> 1))
((x, y when x == y) -> 1)
(x, y when x, z -> 1)
((x, y when x, z -> 1))
((x, y when x, z) -> 1)
---
(source
(block
(stab_clause
(binary_operator
(arguments
(identifier)
(identifier))
(binary_operator
(identifier)
(identifier)))
(body
(integer))))
(block
(block
(stab_clause
(binary_operator
(arguments
(identifier)
(identifier))
(binary_operator
(identifier)
(identifier)))
(body
(integer)))))
(block
(stab_clause
(arguments
(identifier)
(binary_operator
(identifier)
(binary_operator
(identifier)
(identifier))))
(body
(integer))))
(block
(stab_clause
(arguments
(identifier)
(binary_operator
(identifier)
(identifier))
(identifier))
(body
(integer))))
(block
(block
(stab_clause
(arguments
(identifier)
(binary_operator
(identifier)
(identifier))
(identifier))
(body
(integer)))))
(block
(stab_clause
(arguments
(identifier)
(binary_operator
(identifier)
(identifier))
(identifier))
(body
(integer)))))

@ -1,987 +0,0 @@
=====================================
local call / no arguments
=====================================
fun()
---
(source
(call
(identifier)
(arguments)))
=====================================
local call / arguments in parentheses
=====================================
fun(a)
fun([1, 2], option: true, other: 5)
---
(source
(call
(identifier)
(arguments
(identifier)))
(call
(identifier)
(arguments
(list
(integer)
(integer))
(keywords
(pair
(keyword)
(boolean))
(pair
(keyword)
(integer))))))
=====================================
local call / arguments without parentheses
=====================================
fun a
fun {}
fun [1, 2], option: true, other: 5
fun +: 1
---
(source
(call
(identifier)
(arguments
(identifier)))
(call
(identifier)
(arguments
(tuple)))
(call
(identifier)
(arguments
(list
(integer)
(integer))
(keywords
(pair
(keyword)
(boolean))
(pair
(keyword)
(integer)))))
(call
(identifier)
(arguments
(keywords
(pair
(keyword)
(integer))))))
=====================================
local call / arguments without parentheses / multiline
=====================================
fun [1, 2],
option: true,
other: 5
---
(source
(call
(identifier)
(arguments
(list
(integer)
(integer))
(keywords
(pair
(keyword)
(boolean))
(pair
(keyword)
(integer))))))
=====================================
local call / nested with parentheses
=====================================
outer_fun(inner_fun(a))
---
(source
(call
(identifier)
(arguments
(call
(identifier)
(arguments
(identifier))))))
=====================================
local call / nested without parentheses (right associativity)
=====================================
outer_fun inner_fun a, b
outer_fun inner_fun do: 1
---
(source
(call
(identifier)
(arguments
(call
(identifier)
(arguments
(identifier)
(identifier)))))
(call
(identifier)
(arguments
(call
(identifier)
(arguments
(keywords
(pair
(keyword)
(integer))))))))
=====================================
local call / precedence with operator
=====================================
outer_fun 1 + 1
1 + inner_fun 1
outer_fun 1 + inner_fun 1
fun 1, 2 |> other_fun
---
(source
(call
(identifier)
(arguments
(binary_operator
(integer)
(integer))))
(binary_operator
(integer)
(call
(identifier)
(arguments
(integer))))
(call
(identifier)
(arguments
(binary_operator
(integer)
(call
(identifier)
(arguments
(integer))))))
(call
(identifier)
(arguments
(integer)
(binary_operator
(integer)
(identifier)))))
=====================================
local call / treats nonimmediate parentheses as a block argument
=====================================
fun (x)
---
(source
(call
(identifier)
(arguments
(block
(identifier)))))
=====================================
remote call / no arguments
=====================================
Mod.fun()
---
(source
(call
(dot
(alias)
(identifier))
(arguments)))
=====================================
remote call / no arguments without parentheses
=====================================
Mod.fun
---
(source
(call
(dot
(alias)
(identifier))))
=====================================
remote call / arguments in parentheses
=====================================
Mod.fun(a)
Mod.fun([1, 2], option: true, other: 5)
---
(source
(call
(dot
(alias)
(identifier))
(arguments
(identifier)))
(call
(dot
(alias)
(identifier))
(arguments
(list
(integer)
(integer))
(keywords
(pair
(keyword)
(boolean))
(pair
(keyword)
(integer))))))
=====================================
remote call / arguments without parentheses
=====================================
Mod.fun a
Mod.fun [1, 2], option: true, other: 5
---
(source
(call
(dot
(alias)
(identifier))
(arguments
(identifier)))
(call
(dot
(alias)
(identifier))
(arguments
(list
(integer)
(integer))
(keywords
(pair
(keyword)
(boolean))
(pair
(keyword)
(integer))))))
=====================================
remote call / nested with parentheses
=====================================
Mod.outer_fun(Mod.inner_fun(a))
---
(source
(call
(dot
(alias)
(identifier))
(arguments
(call
(dot
(alias)
(identifier))
(arguments
(identifier))))))
=====================================
remote call / nested without parentheses (right associativity)
=====================================
Mod.outer_fun Mod.inner_fun a
---
(source
(call
(dot
(alias)
(identifier))
(arguments
(call
(dot
(alias)
(identifier))
(arguments
(identifier))))))
=====================================
remote call / precedence with operator
=====================================
Mod.outer_fun 1 + 1
1 + Mod.inner_fun 1
Mod.outer_fun 1 + Mod.inner_fun 1
---
(source
(call
(dot
(alias)
(identifier))
(arguments
(binary_operator
(integer)
(integer))))
(binary_operator
(integer)
(call
(dot
(alias)
(identifier))
(arguments
(integer))))
(call
(dot
(alias)
(identifier))
(arguments
(binary_operator
(integer)
(call
(dot
(alias)
(identifier))
(arguments
(integer)))))))
=====================================
remote call / treats nonimmediate parentheses as a block argument
=====================================
Mod.fun (x)
---
(source
(call
(dot
(alias)
(identifier))
(arguments
(block
(identifier)))))
=====================================
remote call / multi-level alias
=====================================
Mod1.Mod2.Mod3.fun(a)
---
(source
(call
(dot
(alias)
(identifier))
(arguments
(identifier))))
=====================================
remote call / operator
=====================================
Kernel.+(a, b)
---
(source
(call
(dot
(alias)
(operator_identifier))
(arguments
(identifier)
(identifier))))
=====================================
remote call / quoted function name
=====================================
Mod."fun"(a)
Mod.'fun'(a)
---
(source
(call
(dot
(alias)
(string
(quoted_content)))
(arguments
(identifier)))
(call
(dot
(alias)
(charlist
(quoted_content)))
(arguments
(identifier))))
=====================================
remote call / atom literal module
=====================================
:mod.fun(a)
:"Elixir.Mod".fun(a)
---
(source
(call
(dot
(atom)
(identifier))
(arguments
(identifier)))
(call
(dot
(quoted_atom
(quoted_content))
(identifier))
(arguments
(identifier))))
=====================================
anonymous call / no arguments
=====================================
fun.()
---
(source
(call
(dot
(identifier))
(arguments)))
=====================================
anonymous call / arguments in parentheses
=====================================
fun.(a)
fun.([1, 2], option: true, other: 5)
---
(source
(call
(dot
(identifier))
(arguments
(identifier)))
(call
(dot
(identifier))
(arguments
(list
(integer)
(integer))
(keywords
(pair
(keyword)
(boolean))
(pair
(keyword)
(integer))))))
=====================================
anonymous call / nested with parentheses
=====================================
outer_fun.(inner_fun.(a))
---
(source
(call
(dot
(identifier))
(arguments
(call
(dot
(identifier))
(arguments
(identifier))))))
=====================================
mixed call types
=====================================
Mod.outer_fun mid_fun inner_fun.(a)
---
(source
(call
(dot
(alias)
(identifier))
(arguments
(call
(identifier)
(arguments
(call
(dot
(identifier))
(arguments
(identifier))))))))
=====================================
identifier call
=====================================
mod.fun(a)
---
(source
(call
(dot
(identifier)
(identifier))
(arguments
(identifier))))
=====================================
nested identifier call
=====================================
map.mod.fun(a)
---
(source
(call
(dot
(call
(dot
(identifier)
(identifier)))
(identifier))
(arguments
(identifier))))
=====================================
reserved word call
=====================================
a.and
---
(source
(call
(dot
(identifier)
(identifier))))
=====================================
range call
=====================================
(1..2).step
(1..2//3).step
---
(source
(call
(dot
(block
(binary_operator
(integer)
(integer)))
(identifier)))
(call
(dot
(block
(binary_operator
(binary_operator
(integer)
(integer))
(integer)))
(identifier))))
=====================================
multi-expression block call
=====================================
(
x
1..2
).step
---
(source
(call
(dot
(block
(identifier)
(binary_operator
(integer)
(integer)))
(identifier))))
=====================================
map call
=====================================
%{}.field
---
(source
(call
(dot
(map)
(identifier))))
=====================================
struct call
=====================================
%Mod{}.field
---
(source
(call
(dot
(map
(struct
(alias)))
(identifier))))
=====================================
arbitrary term call
=====================================
1.(1, 2)
---
(source
(call
(dot
(integer))
(arguments
(integer)
(integer))))
=====================================
escaped newline call
=====================================
fun \
a
---
(source
(call
(identifier)
(arguments
(identifier))))
=====================================
keyword list trailing separator
=====================================
fun(option: true, other: 5,)
---
(source
(call
(identifier)
(arguments
(keywords
(pair
(keyword)
(boolean))
(pair
(keyword)
(integer))))))
=====================================
newline before dot
=====================================
Mod
.fun(a)
---
(source
(call
(dot
(alias)
(identifier))
(arguments
(identifier))))
=====================================
newline after dot
=====================================
Mod.
fun(a)
---
(source
(call
(dot
(alias)
(identifier))
(arguments
(identifier))))
=====================================
access syntax
=====================================
map[key]
map[:key]
---
(source
(access_call
(identifier)
(identifier))
(access_call
(identifier)
(atom)))
=====================================
access syntax / does not allow whitespace
=====================================
map [key]
---
(source
(call
(identifier)
(arguments
(list
(identifier)))))
=====================================
access syntax / precedence with dot call
=====================================
map.map[:key]
map[:mod].fun
---
(source
(access_call
(call
(dot
(identifier)
(identifier)))
(atom))
(call
(dot
(access_call
(identifier)
(atom))
(identifier))))
=====================================
access syntax / precedence with operators
=====================================
-x[:key]
@x[:key]
&x[:key]
&1[:key]
---
(source
(unary_operator
(access_call
(identifier)
(atom)))
(access_call
(unary_operator
(identifier))
(atom))
(unary_operator
(access_call
(identifier)
(atom)))
(access_call
(unary_operator
(integer))
(atom)))
=====================================
double parenthesised call
=====================================
fun()()
fun() ()
fun(1)(1)
Mod.fun()()
fun.()()
unquote(name)()
---
(source
(call
(call
(identifier)
(arguments))
(arguments))
(call
(call
(identifier)
(arguments))
(arguments))
(call
(call
(identifier)
(arguments
(integer)))
(arguments
(integer)))
(call
(call
(dot
(alias)
(identifier))
(arguments))
(arguments))
(call
(call
(dot
(identifier))
(arguments))
(arguments))
(call
(call
(identifier)
(arguments
(identifier)))
(arguments)))
=====================================
[field names]
=====================================
fun()
fun a
Mod.fun a
fun()()
fun.()
map[key]
---
(source
(call
target: (identifier)
(arguments))
(call
target: (identifier)
(arguments
(identifier)))
(call
target: (dot
left: (alias)
right: (identifier))
(arguments
(identifier)))
(call
target: (call
target: (identifier)
(arguments))
(arguments))
(call
target: (dot
left: (identifier))
(arguments))
(access_call
target: (identifier)
key: (identifier)))
=====================================
[error] leading argument separator
=====================================
fun(, a)
---
(source
(call
(identifier)
(arguments
(ERROR)
(identifier))))
=====================================
[error] trailing argument separator
=====================================
fun(a,)
---
(source
(call
(identifier)
(arguments
(identifier)
(ERROR))))

@ -1,131 +0,0 @@
=====================================
anonymous function
=====================================
& &1 + &2
&(&1 + &2)
&foo(&1, a, &2)
---
(source
(unary_operator
(binary_operator
(unary_operator
(integer))
(unary_operator
(integer))))
(unary_operator
(binary_operator
(unary_operator
(integer))
(unary_operator
(integer))))
(unary_operator
(call
(identifier)
(arguments
(unary_operator
(integer))
(identifier)
(unary_operator
(integer))))))
=====================================
argument call
=====================================
& &1.some_fun
&(&1.some_fun)
& &1.(&2)
---
(source
(unary_operator
(call
(dot
(unary_operator
(integer))
(identifier))))
(unary_operator
(call
(dot
(unary_operator
(integer))
(identifier))))
(unary_operator
(call
(dot
(unary_operator
(integer)))
(arguments
(unary_operator
(integer))))))
=====================================
remote MFA
=====================================
&Mod.fun/1
---
(source
(unary_operator
(binary_operator
(call
(dot
(alias)
(identifier)))
(integer))))
=====================================
remote operator MFA
=====================================
&Kernel.>=/2
---
(source
(unary_operator
(binary_operator
(call
(dot
(alias)
(operator_identifier)))
(integer))))
=====================================
local MFA
=====================================
&fun/1
---
(source
(unary_operator
(binary_operator
(identifier)
(integer))))
=====================================
local operator MFA
=====================================
&>=/2
&//2
---
(source
(unary_operator
(binary_operator
(operator_identifier)
(integer)))
(unary_operator
(binary_operator
(operator_identifier)
(integer))))

@ -1,785 +0,0 @@
=====================================
unary
=====================================
@arg
+arg
-arg
!arg
^arg
not arg
~~~arg
&arg
---
(source
(unary_operator (identifier))
(unary_operator (identifier))
(unary_operator (identifier))
(unary_operator (identifier))
(unary_operator (identifier))
(unary_operator (identifier))
(unary_operator (identifier))
(unary_operator (identifier)))
=====================================
binary left associative
=====================================
a ** b ** c
a * b * c
a / b / c
a + b + c
a - b - c
a ^^^ b ^^^ c
a in b in c
a not in b not in c
a |> b |> c
a <<< b <<< c
a >>> b >>> c
a <<~ b <<~ c
a ~>> b ~>> c
a <~ b <~ c
a ~> b ~> c
a <~> b <~> c
a <|> b <|> c
a < b < c
a > b > c
a <= b <= c
a >= b >= c
a == b == c
a != b != c
a =~ b =~ c
a === b === c
a !== b !== c
a && b && c
a &&& b &&& c
a and b and c
a || b || c
a ||| b ||| c
a or b or c
a <- b <- c
a \\ b \\ c
---
(source
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier)))
=====================================
binary right associative
=====================================
a ++ b ++ c
a -- b -- c
a +++ b +++ c
a --- b --- c
a .. b .. c
a <> b <> c
a = b = c
a | b | c
a :: b :: c
a when b when c
---
(source
(binary_operator (identifier) (binary_operator (identifier) (identifier)))
(binary_operator (identifier) (binary_operator (identifier) (identifier)))
(binary_operator (identifier) (binary_operator (identifier) (identifier)))
(binary_operator (identifier) (binary_operator (identifier) (identifier)))
(binary_operator (identifier) (binary_operator (identifier) (identifier)))
(binary_operator (identifier) (binary_operator (identifier) (identifier)))
(binary_operator (identifier) (binary_operator (identifier) (identifier)))
(binary_operator (identifier) (binary_operator (identifier) (identifier)))
(binary_operator (identifier) (binary_operator (identifier) (identifier)))
(binary_operator (identifier) (binary_operator (identifier) (identifier))))
=====================================
precedence on the same level falls back to associativity
=====================================
a * b / c
a + b - c
a in b not in c
a <<< b >>> c
a < b > c
a == b != c
a &&& b && c
a ||| b || c
a <- b \\ c
a ++ b -- c
---
(source
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (binary_operator (identifier) (identifier)) (identifier))
(binary_operator (identifier) (binary_operator (identifier) (identifier))))
=====================================
precedence on different levels
=====================================
& @ a - b
a -- b + c
a - b ++ c
a = b <<< c
a + b * c - d
a ** b + c ** d
---
(source
(unary_operator
(binary_operator
(unary_operator
(identifier))
(identifier)))
(binary_operator
(identifier)
(binary_operator
(identifier)
(identifier)))
(binary_operator
(binary_operator
(identifier)
(identifier))
(identifier))
(binary_operator
(identifier)
(binary_operator
(identifier)
(identifier)))
(binary_operator
(binary_operator
(identifier)
(binary_operator
(identifier)
(identifier)))
(identifier))
(binary_operator
(binary_operator
(identifier)
(identifier))
(binary_operator
(identifier)
(identifier))))
=====================================
precedence determined by parentheses
=====================================
(& a) - b
(a + b) * (c - d)
---
(source
(binary_operator
(block
(unary_operator
(identifier)))
(identifier))
(binary_operator
(block
(binary_operator
(identifier)
(identifier)))
(block
(binary_operator
(identifier)
(identifier)))))
=====================================
"not in" spacing
=====================================
a not in b
---
(source
(binary_operator
(identifier)
(identifier)))
=====================================
"not in" boundary
=====================================
fun not inARG
---
(source
(call
(identifier)
(arguments
(unary_operator
(identifier)))))
=====================================
multiline / unary
=====================================
@
arg
+
arg
-
arg
!
arg
^
arg
not
arg
~~~
arg
&
arg
---
(source
(unary_operator (identifier))
(unary_operator (identifier))
(unary_operator (identifier))
(unary_operator (identifier))
(unary_operator (identifier))
(unary_operator (identifier))
(unary_operator (identifier))
(unary_operator (identifier)))
=====================================
multiline / binary
=====================================
a
**
b
a
*
b
a
/
b
a
++
b
a
--
b
a
+++
b
a
---
b
a
..
b
a
<>
b
a
^^^
b
a
in
b
a
not in
b
a
|>
b
a
<<<
b
a
>>>
b
a
<<~
b
a
~>>
b
a
<~
b
a
~>
b
a
<~>
b
a
<|>
b
a
<
b
a
>
b
a
<=
b
a
>=
b
a
==
b
a
!=
b
a
=~
b
a
===
b
a
!==
b
a
&&
b
a
&&&
b
a
and
b
a
||
b
a
|||
b
a
or
b
a
=
b
a
|
b
a
::
b
a
when
b
a
<-
b
a
\\
b
---
(source
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier))
(binary_operator (identifier) (identifier)))
=====================================
multiline / unary over binary
=====================================
a
+
b
a
-
b
---
(source
(identifier)
(unary_operator
(identifier))
(identifier)
(unary_operator
(identifier)))
=====================================
multiline / right operands
=====================================
x
not in
[y]
x
not in[y]
:a
++:b
:a++
:b
---
(source
(binary_operator
(identifier)
(list
(identifier)))
(binary_operator
(identifier)
(list
(identifier)))
(binary_operator
(atom)
(atom))
(binary_operator
(atom)
(atom)))
=====================================
multiline / unary over binary (precedence)
=====================================
x
-
y
x
+
y
---
(source
(identifier)
(unary_operator
(identifier))
(identifier)
(unary_operator
(identifier)))
=====================================
plus minus
=====================================
x+y
x + y
x+ y
x +y
x +y +z
---
(source
(binary_operator
(identifier)
(identifier))
(binary_operator
(identifier)
(identifier))
(binary_operator
(identifier)
(identifier))
(call
(identifier)
(arguments
(unary_operator
(identifier))))
(call
(identifier)
(arguments
(unary_operator
(call
(identifier)
(arguments
(unary_operator
(identifier))))))))
=====================================
nullary range
=====================================
..
Enum.to_list(..)
not ..
range = ..
---
(source
(operator_identifier)
(call
(dot
(alias)
(identifier))
(arguments
(operator_identifier)))
(unary_operator
(operator_identifier))
(binary_operator
(identifier)
(operator_identifier)))
=====================================
stepped range
=====================================
1 .. 2 // 3
1..2//3
0..1//-1
---
(source
(binary_operator
(binary_operator
(integer)
(integer))
(integer))
(binary_operator
(binary_operator
(integer)
(integer))
(integer))
(binary_operator
(binary_operator
(integer)
(integer))
(unary_operator
(integer))))
=====================================
stepped range / multiline
=====================================
1..2
// 4
---
(source
(binary_operator
(binary_operator
(integer)
(integer))
(integer)))
=====================================
stepped ranges / blocks
=====================================
foo do end..bar do end//baz do end
1..(2//3)
(1..2)//3
(1..2)//(3)
---
(source
(binary_operator
(binary_operator
(call
(identifier)
(do_block))
(call
(identifier)
(do_block)))
(call
(identifier)
(do_block)))
(binary_operator
(integer)
(block
(binary_operator
(integer)
(integer))))
(binary_operator
(block
(binary_operator
(integer)
(integer)))
(integer))
(binary_operator
(block
(binary_operator
(integer)
(integer)))
(block
(integer))))
=====================================
[field names]
=====================================
a + b
@a
---
(source
(binary_operator
left: (identifier)
right: (identifier))
(unary_operator
operand: (identifier)))

@ -1,270 +0,0 @@
=====================================
simple literal
=====================================
~s(content)
~r{content}
~w[content]
~a<content>
~b"content"
~c'content'
~d|content|
~e/content/
---
(source
(sigil (sigil_name) (quoted_content))
(sigil (sigil_name) (quoted_content))
(sigil (sigil_name) (quoted_content))
(sigil (sigil_name) (quoted_content))
(sigil (sigil_name) (quoted_content))
(sigil (sigil_name) (quoted_content))
(sigil (sigil_name) (quoted_content))
(sigil (sigil_name) (quoted_content)))
=====================================
multiple lines
=====================================
~s"line 1
line 2"
---
(source
(sigil
(sigil_name)
(quoted_content)))
=====================================
interpolation
=====================================
~s"hey #{name}!"
~r/hey #{
name
}!/
~w{##{name}#}
---
(source
(sigil
(sigil_name)
(quoted_content)
(interpolation
(identifier))
(quoted_content))
(sigil
(sigil_name)
(quoted_content)
(interpolation
(identifier))
(quoted_content))
(sigil
(sigil_name)
(quoted_content)
(interpolation
(identifier))
(quoted_content)))
=====================================
nested interpolation
=====================================
~s{this is #{~s{number #{1}}}!}
---
(source
(sigil
(sigil_name)
(quoted_content)
(interpolation
(sigil
(sigil_name)
(quoted_content)
(interpolation
(integer))))
(quoted_content)))
=====================================
escape sequence
=====================================
~s{_\}_\n_\t_\r_\e_\\_\1_\x3f_\u0065\u0301_}
---
(source
(sigil
(sigil_name)
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(escape_sequence)
(quoted_content)))
=====================================
escaped interpolation
=====================================
~s/\#{1}/
---
(source
(sigil
(sigil_name)
(escape_sequence)
(quoted_content)))
=====================================
upper sigil / no interpolation
=====================================
~S"hey #{name}!"
---
(source
(sigil
(sigil_name)
(quoted_content)))
=====================================
upper sigil / no escape sequence
=====================================
~S"\n"
---
(source
(sigil
(sigil_name)
(quoted_content)))
=====================================
upper sigil / escape terminator
=====================================
~S"content \" content"
~S{content \} content}
~S/content \/ content/
---
(source
(sigil
(sigil_name)
(quoted_content)
(escape_sequence)
(quoted_content))
(sigil
(sigil_name)
(quoted_content)
(escape_sequence)
(quoted_content))
(sigil
(sigil_name)
(quoted_content)
(escape_sequence)
(quoted_content)))
=====================================
upper sigil / multiple characters
=====================================
~MAT"1 2"
---
(source
(sigil
(sigil_name)
(quoted_content)))
=====================================
heredoc delimiter
=====================================
~s"""
text
with "quotes"
"""
~s'''
text
with 'quotes'
'''
---
(source
(sigil
(sigil_name)
(quoted_content))
(sigil
(sigil_name)
(quoted_content)))
=====================================
modifiers
=====================================
~r/left|right/i
~r/left|right/iUx
~r/left|right/0
~r/left|right/u8
---
(source
(sigil
(sigil_name)
(quoted_content)
(sigil_modifiers))
(sigil
(sigil_name)
(quoted_content)
(sigil_modifiers))
(sigil
(sigil_name)
(quoted_content)
(sigil_modifiers))
(sigil
(sigil_name)
(quoted_content)
(sigil_modifiers)))
=====================================
[error] accepts only a single character
=====================================
~mysigil"content"
---
(source
(sigil
(sigil_name)
(ERROR)
(quoted_content)))

@ -1,392 +0,0 @@
=====================================
def / no arguments
=====================================
def fun() do
end
---
(source
(call
(identifier)
(arguments
(call
(identifier)
(arguments)))
(do_block)))
=====================================
def / no arguments without parentheses
=====================================
def fun do
end
---
(source
(call
(identifier)
(arguments
(identifier))
(do_block)))
=====================================
def / one argument
=====================================
def fun(x) do
x
end
---
(source
(call
(identifier)
(arguments
(call
(identifier)
(arguments
(identifier))))
(do_block
(identifier))))
=====================================
def / one argument without parentheses
=====================================
def fun x do
x
end
---
(source
(call
(identifier)
(arguments
(call
(identifier)
(arguments
(identifier))))
(do_block
(identifier))))
=====================================
def / many arguments
=====================================
def fun(x, y) do
x + y
end
---
(source
(call
(identifier)
(arguments
(call
(identifier)
(arguments
(identifier)
(identifier))))
(do_block
(binary_operator
(identifier)
(identifier)))))
=====================================
def / many arguments without parentheses
=====================================
def fun x, y do
x + y
end
---
(source
(call
(identifier)
(arguments
(call
(identifier)
(arguments
(identifier)
(identifier))))
(do_block
(binary_operator
(identifier)
(identifier)))))
=====================================
def / default arguments
=====================================
def fun x, y \\ 1 do
x + y
end
def fun(x, y \\ 1) do
x + y
end
---
(source
(call
(identifier)
(arguments
(call
(identifier)
(arguments
(identifier)
(binary_operator
(identifier)
(integer)))))
(do_block
(binary_operator
(identifier)
(identifier))))
(call
(identifier)
(arguments
(call
(identifier)
(arguments
(identifier)
(binary_operator
(identifier)
(integer)))))
(do_block
(binary_operator
(identifier)
(identifier)))))
=====================================
def / keyword do block
=====================================
def fun(), do: 1
def fun(x), do: x
---
(source
(call
(identifier)
(arguments
(call
(identifier)
(arguments))
(keywords
(pair
(keyword)
(integer)))))
(call
(identifier)
(arguments
(call
(identifier)
(arguments
(identifier)))
(keywords
(pair
(keyword)
(identifier))))))
=====================================
def / pattern matching
=====================================
def fun([{x, y} | tail]) do
x + y
end
---
(source
(call
(identifier)
(arguments
(call
(identifier)
(arguments
(list
(binary_operator
(tuple
(identifier)
(identifier))
(identifier))))))
(do_block
(binary_operator
(identifier)
(identifier)))))
=====================================
def / with guard
=====================================
def fun(x) when x == 1 do
x
end
---
(source
(call
(identifier)
(arguments
(binary_operator
(call
(identifier)
(arguments
(identifier)))
(binary_operator
(identifier)
(integer))))
(do_block
(identifier))))
=====================================
def / with guard / multiple guards
=====================================
def fun(x) when x > 10 when x < 5 do
x
end
---
(source
(call
(identifier)
(arguments
(binary_operator
(call
(identifier)
(arguments
(identifier)))
(binary_operator
(binary_operator
(identifier)
(integer))
(binary_operator
(identifier)
(integer)))))
(do_block
(identifier))))
=====================================
defp
=====================================
defp fun(x) do
x
end
---
(source
(call
(identifier)
(arguments
(call
(identifier)
(arguments
(identifier))))
(do_block
(identifier))))
=====================================
defmacro
=====================================
defmacro fun(x) do
quote do
[unquote(x)]
end
end
---
(source
(call
(identifier)
(arguments
(call
(identifier)
(arguments
(identifier))))
(do_block
(call
(identifier)
(do_block
(list
(call
(identifier)
(arguments
(identifier)))))))))
=====================================
defguard
=====================================
defguard is_even(term) when is_integer(term) and rem(term, 2) == 0
---
(source
(call
(identifier)
(arguments
(binary_operator
(call
(identifier)
(arguments
(identifier)))
(binary_operator
(call
(identifier)
(arguments
(identifier)))
(binary_operator
(call
(identifier)
(arguments
(identifier)
(integer)))
(integer)))))))
=====================================
def in macro
=====================================
def unquote(name)(unquote_splicing(args)) do
unquote(compiled)
end
---
(source
(call
(identifier)
(arguments
(call
(call
(identifier)
(arguments
(identifier)))
(arguments
(call
(identifier)
(arguments
(identifier))))))
(do_block
(call
(identifier)
(arguments
(identifier))))))

@ -1,132 +0,0 @@
=====================================
for / enumerable
=====================================
for n <- [1, 2], do: n * 2
---
(source
(call
(identifier)
(arguments
(binary_operator
(identifier)
(list
(integer)
(integer)))
(keywords
(pair
(keyword)
(binary_operator
(identifier)
(integer)))))))
=====================================
for / enumerable / with options and block
=====================================
for line <- IO.stream(), into: IO.stream() do
String.upcase(line)
end
---
(source
(call
(identifier)
(arguments
(binary_operator
(identifier)
(call
(dot
(alias)
(identifier))
(arguments)))
(keywords
(pair
(keyword)
(call
(dot
(alias)
(identifier))
(arguments)))))
(do_block
(call
(dot
(alias)
(identifier))
(arguments
(identifier))))))
=====================================
for / binary
=====================================
for <<c <- " hello world ">>, c != ?\s, into: "", do: <<c>>
---
(source
(call
(identifier)
(arguments
(bitstring
(binary_operator
(identifier)
(string
(quoted_content))))
(binary_operator
(identifier)
(char))
(keywords
(pair
(keyword)
(string))
(pair
(keyword)
(bitstring
(identifier)))))))
=====================================
for / reduce
=====================================
for x <- [1, 2, 1], reduce: %{} do
acc -> Map.update(acc, x, 1, & &1 + 1)
end
---
(source
(call
(identifier)
(arguments
(binary_operator
(identifier)
(list
(integer)
(integer)
(integer)))
(keywords
(pair
(keyword)
(map))))
(do_block
(stab_clause
(arguments
(identifier))
(body
(call
(dot
(alias)
(identifier))
(arguments
(identifier)
(identifier)
(integer)
(unary_operator
(binary_operator
(unary_operator
(integer))
(integer))))))))))

@ -1,138 +0,0 @@
=====================================
empty module definition
=====================================
defmodule Mod do
end
defmodule Mod.Child do
end
---
(source
(call
(identifier)
(arguments
(alias))
(do_block))
(call
(identifier)
(arguments
(alias))
(do_block)))
=====================================
module definition with atom literal
=====================================
defmodule :mod do
end
---
(source
(call
(identifier)
(arguments
(atom))
(do_block)))
=====================================
full module definition
=====================================
defmodule Mod do
@moduledoc """
Example module
"""
use UseMod
@attribute 1
@doc """
Example function
"""
@spec func(integer) :: integer
def func(x) when is_integer(x) do
priv(x) + priv(x)
end
defp priv(x), do: x * x
end
---
(source
(call
(identifier)
(arguments
(alias))
(do_block
(unary_operator
(call
(identifier)
(arguments
(string
(quoted_content)))))
(call
(identifier)
(arguments
(alias)))
(unary_operator
(call
(identifier)
(arguments
(integer))))
(unary_operator
(call
(identifier)
(arguments
(string
(quoted_content)))))
(unary_operator
(call
(identifier)
(arguments
(binary_operator
(call
(identifier)
(arguments
(identifier)))
(identifier)))))
(call
(identifier)
(arguments
(binary_operator
(call
(identifier)
(arguments
(identifier)))
(call
(identifier)
(arguments
(identifier)))))
(do_block
(binary_operator
(call
(identifier)
(arguments
(identifier)))
(call
(identifier)
(arguments
(identifier))))))
(call
(identifier)
(arguments
(call
(identifier)
(arguments
(identifier)))
(keywords
(pair
(keyword)
(binary_operator
(identifier)
(identifier)))))))))

@ -1,245 +0,0 @@
=====================================
without type parentheses
=====================================
@spec fun(atom, integer, keyword) :: string
---
(source
(unary_operator
(call
(identifier)
(arguments
(binary_operator
(call
(identifier)
(arguments
(identifier)
(identifier)
(identifier)))
(identifier))))))
=====================================
with type parentheses
=====================================
@spec fun(atom(), integer(), keyword()) :: string()
---
(source
(unary_operator
(call
(identifier)
(arguments
(binary_operator
(call
(identifier)
(arguments
(call
(identifier)
(arguments))
(call
(identifier)
(arguments))
(call
(identifier)
(arguments))))
(call
(identifier)
(arguments)))))))
=====================================
with literals
=====================================
@spec fun(%{key: atom}) :: {:ok, atom} | {:error, binary}
---
(source
(unary_operator
(call
(identifier)
(arguments
(binary_operator
(call
(identifier)
(arguments
(map
(map_content
(keywords
(pair
(keyword)
(identifier)))))))
(binary_operator
(tuple
(atom)
(identifier))
(tuple
(atom)
(identifier))))))))
=====================================
with function reference
=====================================
@spec fun((-> atom), (atom -> integer)) :: integer
---
(source
(unary_operator
(call
(identifier)
(arguments
(binary_operator
(call
(identifier)
(arguments
(block
(stab_clause
(body
(identifier))))
(block
(stab_clause
(arguments
(identifier))
(body
(identifier))))))
(identifier))))))
=====================================
with remote type
=====================================
@spec fun(Keyword.t()) :: String.t()
---
(source
(unary_operator
(call
(identifier)
(arguments
(binary_operator
(call
(identifier)
(arguments
(call
(dot
(alias)
(identifier))
(arguments))))
(call
(dot
(alias)
(identifier))
(arguments)))))))
=====================================
with type guard
=====================================
@spec fun(arg1, arg2) :: {arg1, arg2} when arg1: atom, arg2: integer
---
(source
(unary_operator
(call
(identifier)
(arguments
(binary_operator
(binary_operator
(call
(identifier)
(arguments
(identifier)
(identifier)))
(tuple
(identifier)
(identifier)))
(keywords
(pair
(keyword)
(identifier))
(pair
(keyword)
(identifier))))))))
=====================================
with named arguments
=====================================
@spec days_since_epoch(year :: integer, month :: integer, day :: integer) :: integer
---
(source
(unary_operator
(call
(identifier)
(arguments
(binary_operator
(call
(identifier)
(arguments
(binary_operator
(identifier)
(identifier))
(binary_operator
(identifier)
(identifier))
(binary_operator
(identifier)
(identifier))))
(identifier))))))
=====================================
nonempty list
=====================================
@spec fun() :: [integer, ...]
---
(source
(unary_operator
(call
(identifier)
(arguments
(binary_operator
(call
(identifier)
(arguments))
(list
(identifier)
(identifier)))))))
=====================================
[error] type guard cannot end with keyword separator
=====================================
@spec fun(arg) :: arg when arg: atom,
---
(source
(unary_operator
(call
(identifier)
(arguments
(binary_operator
(binary_operator
(call
(identifier)
(arguments
(identifier)))
(identifier))
(keywords
(pair
(keyword)
(identifier)))))))
(ERROR))

@ -1,32 +0,0 @@
=====================================
separates expressions in the same line
=====================================
1 ; 1
---
(source (integer) (integer))
=====================================
trailing
=====================================
1;
2;
---
(source (integer) (integer))
=====================================
with comment
=====================================
1 ; # comment
---
(source
(integer)
(comment))

@ -1,84 +0,0 @@
=====================================
single part
=====================================
Mod
AZ_az_19_
---
(source
(alias)
(alias))
=====================================
multiple parts
=====================================
Mod.Child
Mod.Child.Child
---
(source
(alias)
(alias))
=====================================
spacing
=====================================
Mod . Child
Mod
.
Child
---
(source
(alias)
(alias))
=====================================
qualified tuples
=====================================
Mod.{Child1, Child2}
---
(source
(dot
(alias)
(tuple
(alias)
(alias))))
=====================================
dot on identifier
=====================================
name.Mod
name.Mod.Child
---
(source
(dot
(identifier)
(alias))
(dot
(identifier)
(alias)))
=====================================
dot on special identifier
=====================================
__MODULE__.Child
(source
(dot
(identifier)
(alias)))

@ -1,84 +0,0 @@
=====================================
simple literal
=====================================
:atom
:_az_AZ_19_
:nonode@nohost
:bang!
:question?
---
(source
(atom)
(atom)
(atom)
(atom)
(atom))
=====================================
operators
=====================================
[:~~~, :~>>, :~>, :|||, :||, :|>, :|, :>>>, :>=, :>, :=~, :===, :==, :=, :<~>, :<~, :<|>, :<>, :<=, :<<~, :<<<, :<-, :<, :+++, :++, :+, :^^^, :^, :&&&, :&&, :&, :\\, :/, :**, :*, :@, :.., :., :!==, :!=, :!, :::, :->, :---, :--, :-]
---
(source
(list (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom) (atom)))
=====================================
special operator-like atoms
=====================================
[:..., :%{}, :{}, :%, :<<>>, :..//]
---
(source
(list
(atom)
(atom)
(atom)
(atom)
(atom)
(atom)))
=====================================
quoted atom
=====================================
:"atom ?? !! ' \n"
:'atom ?? !! " \n'
---
(source
(quoted_atom
(quoted_content)
(escape_sequence))
(quoted_atom
(quoted_content)
(escape_sequence)))
=====================================
interpolation
=====================================
:"hey #{name}!"
:'hey #{name}!'
---
(source
(quoted_atom
(quoted_content)
(interpolation
(identifier))
(quoted_content))
(quoted_atom
(quoted_content)
(interpolation
(identifier))
(quoted_content)))

@ -1,192 +0,0 @@
=====================================
single item
=====================================
<<>>
<<10>>
<<10.0>>
<<"string">>
---
(source
(bitstring)
(bitstring
(integer))
(bitstring
(float))
(bitstring
(string
(quoted_content))))
=====================================
multiple items
=====================================
<<
10,
10.0,
"string"
>>
---
(source
(bitstring
(integer)
(float)
(string
(quoted_content))))
=====================================
size modifiers
=====================================
<<10::4>>
<<10::size(4)>>
---
(source
(bitstring
(binary_operator
(integer)
(integer)))
(bitstring
(binary_operator
(integer)
(call
(identifier)
(arguments
(integer))))))
=====================================
multiple modifiers
=====================================
<<"string"::utf8-big>>
<<"string"::utf16-big>>
<<"string"::utf32-big>>
<<10::32-little-unsigned>>
<<10::integer-signed-big>>
<<10.10::float-signed-native>>
---
(source
(bitstring
(binary_operator
(string
(quoted_content))
(binary_operator
(identifier)
(identifier))))
(bitstring
(binary_operator
(string
(quoted_content))
(binary_operator
(identifier)
(identifier))))
(bitstring
(binary_operator
(string
(quoted_content))
(binary_operator
(identifier)
(identifier))))
(bitstring
(binary_operator
(integer)
(binary_operator
(binary_operator
(integer)
(identifier))
(identifier))))
(bitstring
(binary_operator
(integer)
(binary_operator
(binary_operator
(identifier)
(identifier))
(identifier))))
(bitstring
(binary_operator
(float)
(binary_operator
(binary_operator
(identifier)
(identifier))
(identifier)))))
=====================================
multiple components with modifiers
=====================================
<<10::8-native, "string", 3.14::float, a::8, b::binary-size(known_size)>>
---
(source
(bitstring
(binary_operator
(integer)
(binary_operator
(integer)
(identifier)))
(string
(quoted_content))
(binary_operator
(float)
(identifier))
(binary_operator
(identifier)
(integer))
(binary_operator
(identifier)
(binary_operator
(identifier)
(call
(identifier)
(arguments
(identifier)))))))
=====================================
spacing
=====================================
<<
10 :: 8-native,
b :: binary - size(known_size)
>>
---
(source
(bitstring
(binary_operator
(integer)
(binary_operator
(integer)
(identifier)))
(binary_operator
(identifier)
(binary_operator
(identifier)
(call
(identifier)
(arguments
(identifier)))))))
=====================================
trailing separator
=====================================
<<1,>>
---
(source
(bitstring
(integer)))

@ -1,12 +0,0 @@
=====================================
simple literal
=====================================
true
false
---
(source
(boolean)
(boolean))

@ -1,55 +0,0 @@
=====================================
regular character
=====================================
?a
?Z
?0
?9
?_
??
---
(source
(char)
(char)
(char)
(char)
(char)
(char))
=====================================
escaped character
=====================================
?\n
?\t
?\s
?\\
?\a
?\b
---
(source
(char)
(char)
(char)
(char)
(char)
(char))
=====================================
list of char literals
=====================================
[?a, ?b, ?c]
---
(source
(list
(char)
(char)
(char)))

@ -1,214 +0,0 @@
=====================================
single line
=====================================
'Hello, 123!'
---
(source
(charlist
(quoted_content)))
=====================================
multiple lines
=====================================
'line 1
line 2'
---
(source
(charlist
(quoted_content)))
=====================================
interpolation
=====================================
'hey #{name}!'
'hey #{
name
}!'
'##{name}#'
---
(source
(charlist
(quoted_content)
(interpolation
(identifier))
(quoted_content))
(charlist
(quoted_content)
(interpolation
(identifier))
(quoted_content))
(charlist
(quoted_content)
(interpolation
(identifier))
(quoted_content)))
=====================================
nested interpolation
=====================================
'this is #{'number #{1}'}!'
---
(source
(charlist
(quoted_content)
(interpolation
(charlist
(quoted_content)
(interpolation
(integer))))
(quoted_content)))
=====================================
escape sequence
=====================================
'_\'_\n_\t_\r_\e_\\_\1_\x3f_\u0065\u0301_'
---
(source
(charlist
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(escape_sequence)
(quoted_content)))
=====================================
escaped interpolation
=====================================
'\#{1}'
---
(source
(charlist
(escape_sequence)
(quoted_content)))
=====================================
heredoc / charlist
=====================================
'''
text
with 'quotes'
'''
---
(source
(charlist
(quoted_content)))
=====================================
heredoc / interpolation
=====================================
'''
hey #{name}!
'''
---
(source
(charlist
(quoted_content)
(interpolation
(identifier))
(quoted_content)))
=====================================
heredoc / nested interpolation
=====================================
'''
this is #{
'''
number #{1}
'''
}!
'''
---
(source
(charlist
(quoted_content)
(interpolation
(charlist
(quoted_content)
(interpolation
(integer))
(quoted_content)))
(quoted_content)))
=====================================
heredoc / escaped delimiter
=====================================
'''
\'''
'''
'''
\'\'\'
'''
---
(source
(charlist
(quoted_content)
(escape_sequence)
(quoted_content))
(charlist
(quoted_content)
(escape_sequence)
(escape_sequence)
(escape_sequence)
(quoted_content)))
=====================================
heredoc / escaped interpolation
=====================================
'''
\#{1}
'''
---
(source
(charlist
(quoted_content)
(escape_sequence)
(quoted_content)))

@ -1,48 +0,0 @@
=====================================
simple literal
=====================================
1234567890.1234567890
-1234567890.1234567890
-1_234_567_890.123_456_789_0
---
(source
(float)
(unary_operator
(float))
(unary_operator
(float)))
=====================================
scientific notation
=====================================
1.0e6
1.0e+6
1.0e-6
-1.0e6
-1.0e+6
-1.0e-6
1.0E6
1.0E+6
1.0E-6
1_234_567_890.123_456_789_0e1_234_567_890
---
(source
(float)
(float)
(float)
(unary_operator
(float))
(unary_operator
(float))
(unary_operator
(float))
(float)
(float)
(float)
(float))

@ -1,65 +0,0 @@
=====================================
decimal
=====================================
1234567890
-1234567890
1_234_567_890
019
---
(source
(integer)
(unary_operator
(integer))
(integer)
(integer))
=====================================
binary
=====================================
0b0101011
-0b0101011
0b0_10_10_11
---
(source
(integer)
(unary_operator
(integer))
(integer))
=====================================
octal
=====================================
0o1234567
-0o1234567
0o1_23_45_67
---
(source
(integer)
(unary_operator
(integer))
(integer))
=====================================
hexadecimal
=====================================
0x123456789abcdefABCDEF
-0x123456789abcdefABCDEF
0x123456789_abcdef_ABCDEF
---
(source
(integer)
(unary_operator
(integer))
(integer))

@ -1,234 +0,0 @@
=====================================
simple literal
=====================================
[a: 1, a_b@12?: 2, A_B@12!: 3, Mod: 4, __struct__: 5]
---
(source
(list
(keywords
(pair
(keyword)
(integer))
(pair
(keyword)
(integer))
(pair
(keyword)
(integer))
(pair
(keyword)
(integer))
(pair
(keyword)
(integer)))))
=====================================
trailing separator
=====================================
[a: 1,]
---
(source
(list
(keywords
(pair
(keyword)
(integer)))))
=====================================
with leading items
=====================================
[1, {:c, 1}, a: 1, b: 2]
---
(source
(list
(integer)
(tuple
(atom)
(integer))
(keywords
(pair
(keyword)
(integer))
(pair
(keyword)
(integer)))))
=====================================
operator key
=====================================
[~~~: 1, ==: 2, >: 3]
---
(source
(list
(keywords
(pair
(keyword)
(integer))
(pair
(keyword)
(integer))
(pair
(keyword)
(integer)))))
=====================================
special atom key
=====================================
[...: 1, %{}: 2, {}: 3, %: 4, <<>>: 5, ..//: 6]
---
(source
(list
(keywords
(pair
(keyword)
(integer))
(pair
(keyword)
(integer))
(pair
(keyword)
(integer))
(pair
(keyword)
(integer))
(pair
(keyword)
(integer))
(pair
(keyword)
(integer)))))
=====================================
reserved token key
=====================================
[not: 1, and: 2]
[nil: 1, true: 2]
---
(source
(list
(keywords
(pair
(keyword)
(integer))
(pair
(keyword)
(integer))))
(list
(keywords
(pair
(keyword)
(integer))
(pair
(keyword)
(integer)))))
=====================================
quoted key
=====================================
[
"key1 ?? !! ' \n": 1,
'key2 ?? !! " \n': 2
]
---
(source
(list
(keywords
(pair
(quoted_keyword
(quoted_content)
(escape_sequence))
(integer))
(pair
(quoted_keyword
(quoted_content)
(escape_sequence))
(integer)))))
=====================================
key interpolation
=====================================
[
"hey #{name}!": 1,
'hey #{name}!': 2
]
---
(source
(list
(keywords
(pair
(quoted_keyword
(quoted_content)
(interpolation
(identifier))
(quoted_content))
(integer))
(pair
(quoted_keyword
(quoted_content)
(interpolation
(identifier))
(quoted_content))
(integer)))))
=====================================
[field names]
=====================================
[a: 1, b: 2]
---
(source
(list
(keywords
(pair
key: (keyword)
value: (integer))
(pair
key: (keyword)
value: (integer)))))
=====================================
[error] with trailing items
=====================================
[a: 1, b: 2, 1 => 1]
---
(source
(list
(ERROR
(keywords
(pair
(keyword)
(integer))
(pair
(keyword)
(integer))))
(binary_operator
(integer)
(integer))))

@ -1,88 +0,0 @@
=====================================
simple literal
=====================================
[]
[a]
[A]
[1]
[1, 2]
[1,2]
[ 1 , 2 ]
---
(source
(list)
(list
(identifier))
(list
(alias))
(list
(integer))
(list
(integer)
(integer))
(list
(integer)
(integer))
(list
(integer)
(integer)))
=====================================
nested
=====================================
[[1], 1]
---
(source
(list
(list
(integer))
(integer)))
=====================================
trailing separator
=====================================
[1,]
[1,2,]
---
(source
(list
(integer))
(list
(integer)
(integer)))
=====================================
[error] missing element
=====================================
[, 1]
---
(source
(list
(ERROR)
(integer)))
=====================================
[error] missing separator
=====================================
[1 2]
---
(source
(list
(integer)
(ERROR
(integer))))

@ -1,166 +0,0 @@
=====================================
empty
=====================================
%{}
---
(source
(map))
=====================================
from keywords
=====================================
%{a: 1, b: 2}
---
(source
(map
(map_content
(keywords
(pair
(keyword)
(integer))
(pair
(keyword)
(integer))))))
=====================================
from arrow entries
=====================================
%{:a => 1, "b" => 2, c => 3}
---
(source
(map
(map_content
(binary_operator
(atom)
(integer))
(binary_operator
(string
(quoted_content))
(integer))
(binary_operator
(identifier)
(integer)))))
=====================================
from both arrow entries and keywords
=====================================
%{"a" => 1, b: 2, c: 3}
---
(source
(map
(map_content
(binary_operator
(string
(quoted_content))
(integer))
(keywords
(pair
(keyword)
(integer))
(pair
(keyword)
(integer))))))
=====================================
trailing separator
=====================================
%{"a" => 1,}
---
(source
(map
(map_content
(binary_operator
(string
(quoted_content))
(integer)))))
=====================================
update syntax
=====================================
%{user | name: "Jane", email: "jane@example.com"}
%{user | "name" => "Jane"}
---
(source
(map
(map_content
(binary_operator
(identifier)
(keywords
(pair
(keyword)
(string
(quoted_content)))
(pair
(keyword)
(string
(quoted_content)))))))
(map
(map_content
(binary_operator
(identifier)
(binary_operator
(string
(quoted_content))
(string
(quoted_content)))))))
=====================================
[error] ordering
=====================================
%{b: 2, c: 3, 1 => 1}
---
(source
(map
(ERROR
(keywords
(pair
(keyword)
(integer))
(pair
(keyword)
(integer))))
(map_content
(binary_operator
(integer)
(integer)))))
=====================================
[error] missing separator
=====================================
%{"a" => 1 "b" => 2}
---
(source
(map
(map_content
(binary_operator
(string
(quoted_content))
(ERROR (integer))
(binary_operator
(string
(quoted_content))
(integer))))))

@ -1,10 +0,0 @@
=====================================
simple literal
=====================================
nil
---
(source
(nil))

@ -1,278 +0,0 @@
=====================================
empty
=====================================
""
---
(source
(string))
=====================================
single line
=====================================
"Hello, 123!"
---
(source
(string
(quoted_content)))
=====================================
multiple lines
=====================================
"line 1
line 2"
---
(source
(string
(quoted_content)))
=====================================
interpolation
=====================================
"hey #{name}!"
"hey #{
name
}!"
"##{name}#"
---
(source
(string
(quoted_content)
(interpolation
(identifier))
(quoted_content))
(string
(quoted_content)
(interpolation
(identifier))
(quoted_content))
(string
(quoted_content)
(interpolation
(identifier))
(quoted_content)))
=====================================
nested interpolation
=====================================
"this is #{"number #{1}"}!"
---
(source
(string
(quoted_content)
(interpolation
(string
(quoted_content)
(interpolation
(integer))))
(quoted_content)))
=====================================
empty interpolation
=====================================
"#{}"
---
(source
(string
(interpolation)))
=====================================
escape sequence
=====================================
"_\"_\n_\t_\r_\e_\\_\1_\x3f_\u0065\u0301_"
---
(source
(string
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(quoted_content)
(escape_sequence)
(escape_sequence)
(quoted_content)))
=====================================
escaped interpolation
=====================================
"\#{1}"
---
(source
(string
(escape_sequence)
(quoted_content)))
=====================================
heredoc / string
=====================================
"""
text
with "quotes"
"""
---
(source
(string
(quoted_content)))
=====================================
heredoc / interpolation
=====================================
"""
hey #{name}!
"""
---
(source
(string
(quoted_content)
(interpolation
(identifier))
(quoted_content)))
=====================================
heredoc / nested interpolation
=====================================
"""
this is #{
"""
number #{1}
"""
}!
"""
---
(source
(string
(quoted_content)
(interpolation
(string
(quoted_content)
(interpolation
(integer))
(quoted_content)))
(quoted_content)))
=====================================
heredoc / delimiter in the middle
=====================================
"""
hey """
"""
---
(source
(string
(quoted_content)))
=====================================
heredoc / escaped newline (ignored)
=====================================
"""
hey \
"""
"""
hey \
"""
"""
hey \
there
"""
---
(source
(string
(quoted_content))
(string
(quoted_content))
(string
(quoted_content)))
=====================================
heredoc / escaped delimiter
=====================================
"""
\"""
"""
"""
\"\"\"
"""
---
(source
(string
(quoted_content)
(escape_sequence)
(quoted_content))
(string
(quoted_content)
(escape_sequence)
(escape_sequence)
(escape_sequence)
(quoted_content)))
=====================================
heredoc / escaped interpolation
=====================================
"""
\#{1}
"""
---
(source
(string
(quoted_content)
(escape_sequence)
(quoted_content)))

@ -1,239 +0,0 @@
=====================================
empty
=====================================
%User{}
---
(source
(map
(struct
(alias))))
=====================================
from keywords
=====================================
%User{a: 1, b: 2}
---
(source
(map
(struct
(alias))
(map_content
(keywords
(pair
(keyword)
(integer))
(pair
(keyword)
(integer))))))
=====================================
from arrow entries
=====================================
%User{:a => 1, "b" => 2, c => 3}
---
(source
(map
(struct
(alias))
(map_content
(binary_operator
(atom)
(integer))
(binary_operator
(string
(quoted_content))
(integer))
(binary_operator
(identifier)
(integer)))))
=====================================
from both arrow entries and keywords
=====================================
%User{"a" => 1, b: 2, c: 3}
---
(source
(map
(struct
(alias))
(map_content
(binary_operator
(string
(quoted_content))
(integer))
(keywords
(pair
(keyword)
(integer))
(pair
(keyword)
(integer))))))
=====================================
trailing separator
=====================================
%User{"a" => 1,}
---
(source
(map
(struct
(alias))
(map_content
(binary_operator
(string
(quoted_content))
(integer)))))
=====================================
update syntax
=====================================
%User{user | name: "Jane", email: "jane@example.com"}
%User{user | "name" => "Jane"}
---
(source
(map
(struct (alias))
(map_content
(binary_operator
(identifier)
(keywords
(pair
(keyword)
(string
(quoted_content)))
(pair
(keyword)
(string
(quoted_content)))))))
(map
(struct
(alias))
(map_content
(binary_operator
(identifier)
(binary_operator
(string
(quoted_content))
(string
(quoted_content)))))))
=====================================
unused struct identifier
=====================================
%_{}
---
(source
(map
(struct
(identifier))))
=====================================
matching struct identifier
=====================================
%name{}
---
(source
(map
(struct
(identifier))))
=====================================
pinned struct identifier
=====================================
%^name{}
---
(source
(map
(struct
(unary_operator
(identifier)))))
=====================================
with special identifier
=====================================
%__MODULE__{}
%__MODULE__.Child{}
---
(source
(map
(struct
(identifier)))
(map
(struct
(dot
(identifier)
(alias)))))
=====================================
with atom
=====================================
%:"Elixir.Mod"{}
---
(source
(map
(struct
(quoted_atom
(quoted_content)))))
=====================================
with call
=====================================
%fun(){}
%Mod.fun(){}
%fun.(){}
---
(source
(map
(struct
(call
(identifier)
(arguments))))
(map
(struct
(call
(dot
(alias)
(identifier))
(arguments))))
(map
(struct
(call
(dot
(identifier))
(arguments)))))

@ -1,82 +0,0 @@
=====================================
simple literal
=====================================
{}
{1}
{1, 2}
{1,2}
{ 1 , 2 }
---
(source
(tuple)
(tuple
(integer))
(tuple
(integer)
(integer))
(tuple
(integer)
(integer))
(tuple
(integer)
(integer)))
=====================================
nested
=====================================
{{1}, 1}
---
(source
(tuple
(tuple
(integer))
(integer)))
=====================================
trailing separator
=====================================
{1,}
{1,2,}
---
(source
(tuple
(integer))
(tuple
(integer)
(integer)))
=====================================
[error] missing element
=====================================
{, 1}
---
(source
(tuple
(ERROR)
(integer)))
=====================================
[error] missing separator
=====================================
{1 2}
---
(source
(tuple
(integer)
(ERROR
(integer))))

@ -1,109 +0,0 @@
=====================================
atom
=====================================
:time_μs
:"£"
:'£'
:こんにちは世界
:Ólá
:olá
:Olá
---
(source
(atom)
(quoted_atom
(quoted_content))
(quoted_atom
(quoted_content))
(atom)
(atom)
(atom)
(atom))
=====================================
string
=====================================
"time_μs"
"£"
"こんにちは世界"
"Ólá"
"olá"
"Olá"
---
(source
(string
(quoted_content))
(string
(quoted_content))
(string
(quoted_content))
(string
(quoted_content))
(string
(quoted_content))
(string
(quoted_content)))
=====================================
charlist
=====================================
'time_μs'
'£'
'こんにちは世界'
'Ólá'
'olá'
'Olá'
---
(source
(charlist
(quoted_content))
(charlist
(quoted_content))
(charlist
(quoted_content))
(charlist
(quoted_content))
(charlist
(quoted_content))
(charlist
(quoted_content)))
=====================================
char
=====================================
?こ
---
(source
(char)
(char)
(char)
(char))
=====================================
variable
=====================================
time_μs
こんにちは世界
olá
---
(source
(identifier)
(identifier)
(identifier))

@ -1,63 +0,0 @@
=====================================
regular
=====================================
snake_case
camelCase
az_AZ_19
bang!
question?
doctest
not1
notfalse
---
(source
(identifier)
(identifier)
(identifier)
(identifier)
(identifier)
(identifier)
(identifier)
(identifier))
=====================================
unused
=====================================
_
_number
__TEST__
---
(source
(identifier)
(identifier)
(identifier))
=====================================
three dots identifier
=====================================
...
---
(source
(identifier))
=====================================
special identifier
=====================================
__MODULE__
__DIR__
---
(source
(identifier)
(identifier))

@ -1,72 +0,0 @@
fn x, y, z ->
# <- keyword
# ^ variable
# ^ punctuation.delimiter
# ^ variable
# ^ punctuation.delimiter
# ^ variable
# ^ operator
fn(a, b, c) ->
# <- keyword
# ^ punctuation.bracket
# ^ variable
# ^ punctuation.delimiter
# ^ variable
# ^ punctuation.delimiter
# ^ variable
# ^ punctuation.bracket
# ^ operator
&(x + y - z * a / &1 + b + div(&2, c))
#<- operator
#^ punctuation.bracket
# ^ variable
# ^ operator
# ^ variable
# ^ operator
# ^ variable
# ^ operator
# ^ variable
# ^ operator
# ^ operator
# ^ operator
# ^ variable
# ^ operator
# ^ function
# ^ punctuation.bracket
# ^ operator
# ^ punctuation.delimiter
# ^ variable
# ^ punctuation.bracket
# ^ punctuation.bracket
end
end
fn ->
# <- keyword
# ^ operator
end
# <- keyword
&Set.put(&1, &2)
# <- operator
# ^ module
# ^ operator
# ^ function
# ^ punctuation.bracket
# ^ operator
# ^ punctuation.delimiter
# ^ operator
# ^ punctuation.bracket
&( Set.put(&1, &1) )
#<- operator
#^ punctuation.bracket
# ^ module
# ^ operator
# ^ function
# ^ punctuation.bracket
# ^ operator
# ^ punctuation.delimiter
# ^ operator
# ^ punctuation.bracket
# ^ punctuation.bracket

@ -1,90 +0,0 @@
Path.expand("..", __DIR__)
# ^ module
# ^ operator
# ^ function
# ^ punctuation.bracket
# ^ string
# ^ punctuation.delimiter
# ^ constant.builtin
# ^ punctuation.bracket
func.(1)
# ^ variable
# ^ operator
# ^ punctuation.bracket
# ^ number
# ^ punctuation.bracket
arg |> func
# ^ variable
# ^ operator
# ^ function
func 1
# ^ function
# ^ number
hd([1,2])
# <- function
# ^ punctuation.bracket
# ^ punctuation.bracket
# ^ number
# ^ punctuation.delimiter
# ^ number
# ^ punctuation.bracket
# ^ punctuation.bracket
Kernel.spawn(fn -> :ok end)
# ^ module
# ^ operator
# ^ function
# ^ punctuation.bracket
# ^ keyword
# ^ operator
# ^ string.special.symbol
# ^ keyword
# ^ punctuation.bracket
IO.ANSI.black
# ^ module
# ^ operator
# ^ function
Kernel.-(number)
# ^ module
# ^ operator
# ^ operator
# ^ punctuation.bracket
# ^ variable
# ^ punctuation.bracket
Enum.map([1, 2], fn x ->
# ^ module
# ^ operator
# ^ function
# ^ punctuation.bracket
# ^ punctuation.bracket
# ^ number
# ^ punctuation.delimiter
# ^ number
# ^ punctuation.bracket
# ^ punctuation.delimiter
# ^ keyword
# ^ variable
# ^ operator
x * 2
# <- variable
# ^ operator
# ^ number
end)
# <- keyword
# ^ punctuation.bracket
:erlang.abs(-1)
# ^ module
# ^ operator
# ^ function
# ^ punctuation.bracket
# ^ operator
# ^ number
# ^ punctuation.bracket

@ -1,200 +0,0 @@
<<1, 2, 3>>
# <- punctuation.bracket
# ^ number
# ^ punctuation.delimiter
# ^ number
# ^ punctuation.delimiter
# ^ number
# ^ punctuation.bracket
<< header :: size(8), data :: binary >>
# <- punctuation.bracket
# ^ variable
# ^ operator
# ^ function
# ^ punctuation.bracket
# ^ number
# ^ punctuation.bracket
# ^ punctuation.delimiter
# ^ variable
# ^ operator
# ^ variable
# ^ punctuation.bracket
<<"hello"::binary, c :: utf8, x::[4, unit(2)]>> = "hello™1"
# <- punctuation.bracket
# ^ string
# ^ operator
# ^ variable
# ^ punctuation.delimiter
# ^ variable
# ^ operator
# ^ variable
# ^ punctuation.delimiter
# ^ variable
# ^ operator
# ^ punctuation.bracket
# ^ number
# ^ punctuation.delimiter
# ^ function
# ^ punctuation.bracket
# ^ number
# ^ punctuation.bracket
# ^ punctuation.bracket
# ^ punctuation.bracket
# ^ operator
# ^ string
[1, :a, 'hello'] ++ [2, 3]
# <- punctuation.bracket
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ punctuation.delimiter
# ^ string
# ^ punctuation.bracket
# ^ operator
# ^ punctuation.bracket
# ^ number
# ^ punctuation.delimiter
# ^ number
# ^ punctuation.bracket
[:head | [?t, ?a]]
# <- punctuation.bracket
# ^ string.special.symbol
# ^ operator
# ^ punctuation.bracket
# ^ constant
# ^ punctuation.delimiter
# ^ constant
# ^ punctuation.bracket
# ^ punctuation.bracket
{:one, 2.0, "three"}
# <- punctuation.bracket
# ^ string.special.symbol
# ^ punctuation.delimiter
# ^ number
# ^ punctuation.delimiter
# ^ string
# ^ punctuation.bracket
[option: "value", key: :word]
# <- punctuation.bracket
# ^ string.special.symbol
# ^ string
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ string.special.symbol
# ^ punctuation.bracket
[++: "operator", ~~~: :&&&]
# <- punctuation.bracket
# ^ string.special.symbol
# ^ string
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ string.special.symbol
# ^ punctuation.bracket
[...: 1, <<>>: 2, %{}: 3, %: 4, {}: 5]
# <- punctuation.bracket
# ^ string.special.symbol
# ^ number
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ number
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ number
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ number
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ number
# ^ punctuation.bracket
["this is an atom too": 1, "so is #{1} this": 2]
# <- punctuation.bracket
# ^ string.special.symbol
# ^ number
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ punctuation.special
# ^ number
# ^ punctuation.special
# ^ number
# ^ punctuation.bracket
%{shortcut: "syntax"}
#<- punctuation
#^ punctuation.bracket
# ^ string.special.symbol
# ^ string
# ^ punctuation.bracket
%{map | "update" => "me"}
#<- punctuation
#^ punctuation.bracket
# ^ variable
# ^ operator
# ^ string
# ^ operator
# ^ string
# ^ punctuation.bracket
%{ 12 => 13, :weird => ['thing'] }
#<- punctuation
#^ punctuation.bracket
# ^ number
# ^ operator
# ^ number
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ operator
# ^ punctuation.bracket
# ^ string
# ^ punctuation.bracket
# ^ punctuation.bracket
%Long.Module.Name{name: "Silly"}
# <- punctuation
# ^ module
# ^ module
# ^ punctuation.bracket
# ^ string.special.symbol
# ^ string
# ^ punctuation.bracket
%Long.Module.Name{s | height: {192, :cm}}
# <- punctuation
# ^ module
# ^ punctuation.bracket
# ^ variable
# ^ operator
# ^ string.special.symbol
# ^ punctuation.bracket
# ^ number
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ punctuation.bracket
# ^ punctuation.bracket
".. #{%Long.Module.Name{s | height: {192, :cm}}} .."
# ^ string
# ^ punctuation.special
# ^ punctuation
# ^ module
# ^ punctuation.bracket
# ^ variable
# ^ operator
# ^ string.special.symbol
# ^ punctuation.bracket
# ^ number
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ punctuation.bracket
# ^ punctuation.bracket
# ^ punctuation.special
# ^ string

@ -1,15 +0,0 @@
abc_123
# ^ variable
_018OP
# ^ comment.unused
A__0
# ^ module
__MODULE__ ; __STACKTRACE__
# ^ constant.builtin
# ^ constant.builtin
__OTHER__
# ^ comment.unused

@ -1,175 +0,0 @@
for x <- 1..10, x < 5, do: {x, x}
# <- keyword
# ^ variable
# ^ operator
# ^ number
# ^ operator
# ^ number
# ^ punctuation.delimiter
# ^ variable
# ^ operator
# ^ number
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ punctuation.bracket
# ^ variable
# ^ punctuation.delimiter
# ^ variable
# ^ punctuation.bracket
for << <<r::4, g::4, b::4, a::size(4)>> <- pixels >> do
# <- keyword
# ^ punctuation.bracket
# ^ punctuation.bracket
# ^ variable
# ^ operator
# ^ number
# ^ punctuation.delimiter
# ^ variable
# ^ operator
# ^ number
# ^ punctuation.delimiter
# ^ variable
# ^ operator
# ^ number
# ^ punctuation.delimiter
# ^ variable
# ^ operator
# ^ function
# ^ punctuation.bracket
# ^ number
# ^ punctuation.bracket
# ^ punctuation.bracket
# ^ operator
# ^ variable
# ^ punctuation.bracket
# ^ keyword
end
# <- keyword
if :this do
# <- keyword
# ^ string.special.symbol
# ^ keyword
:that
# ^ string.special.symbol
else
# <- keyword
:otherwise
# ^ string.special.symbol
end
# <- keyword
receive do
# ^ keyword
# ^ keyword
{:EXIT, _} -> :done
# <- punctuation.bracket
# ^ string.special.symbol
# ^ punctuation.delimiter
# ^ comment.unused
# ^ punctuation.bracket
# ^ operator
# ^ string.special.symbol
{ ^pid, :_ } -> nil
# <- punctuation.bracket
# ^ operator
# ^ variable
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ punctuation.bracket
# ^ operator
# ^ constant
after 100 -> :no_luck
# ^ keyword
# ^ number
# ^ operator
# ^ string.special.symbol
end
# <- keyword
case __ENV__.line do
# ^ keyword
# ^ constant.builtin
# ^ operator
# ^ function
# ^ keyword
x when is_integer(x) -> x
# <- variable
# ^ keyword
# ^ function
# ^ punctuation.bracket
# ^ variable
# ^ punctuation.bracket
# ^ operator
# ^ variable
x when x in 1..12 -> -x
# <- variable
# ^ keyword
# ^ variable
# ^ keyword
# ^ number
# ^ operator
# ^ number
# ^ operator
# ^ operator
# ^ variable
end
# <- keyword
cond do
# <- keyword
# ^ keyword
false -> "too bad"
# ^ constant
# ^ operator
# ^ string
4 > 5 -> "oops"
# <- number
# ^ operator
# ^ number
# ^ operator
# ^ string
true -> nil
# ^ constant
# ^ operator
# ^ constant
end
# <- keyword
raise RuntimeError, message: "This is not an error"
# ^ keyword
# ^ module
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ string
import Kernel, except: [spawn: 1, +: 2, /: 2, Unless: 2]
# ^ keyword
# ^ module
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ punctuation.bracket
# ^ string.special.symbol
# ^ number
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ number
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ number
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ number
# ^ punctuation.bracket
alias Long.Module.Name, as: N0men123_and4
# ^ keyword
# ^ module
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ module
use Bitwise
# ^ keyword
# ^ module

@ -1,173 +0,0 @@
1234 ; 01234
# ^ number
# ^ punctuation.delimiter
# ^ number
1.23 ; 1.23e10 ; 1.23e-10
# ^ number
# ^ number
# ^ number
0xab ; 0o171 ; 0b01001
# ^ number
# ^ number
# ^ number
100_000_000 ; 0b1111_0000
# ^ number
# ^ number
?a ; ?1 ; ?\n ; ?\s ; ?\c ; ? ; ?,
# <- constant
# ^ constant
# ^ constant
# ^ constant
# ^ constant
# ^ constant
# ^ constant
# ^ constant
true ; false ; nil
# ^ constant
# ^ constant
# ^ constant
:this ; :that
# ^ string.special.symbol
# ^ string.special.symbol
:'complex atom'
# ^ string.special.symbol
:"with' \" 'quotes \u0301"
# ^ string.special.symbol
# ^ string.escape
# ^ string.escape
# ^ string.special.symbol
# ^ string.escape
# ^ string.escape
:"with #{1 + 1} interpol"
# ^ punctuation.special
# ^ number
# ^ operator
# ^ number
# ^ punctuation.special
:... ; :<<>> ; :%{} ; :% ; :{}
# ^ string.special.symbol
# ^ string.special.symbol
# ^ string.special.symbol
# ^ string.special.symbol
# ^ string.special.symbol
:++ ; :-- ; :* ; :~~~ ; :::
# ^ string.special.symbol
# ^ string.special.symbol
# ^ string.special.symbol
# ^ string.special.symbol
# ^ string.special.symbol
:% ; :. ; :<-
# <- string.special.symbol
# ^ string.special.symbol
# ^ string.special.symbol
"simple string"
# ^ string
# ^ string
"with \x{ff} code"
# ^ string
# ^ string.escape
# ^ string.escape
# ^ string
"with \7 \016 \t \\s"
# ^ string
# ^ string.escape
# ^ string.escape
# ^ string
# ^ string.escape
# ^ string
# ^ string.escape
# ^ string
"with #{inspect "inner"} interpolation"
# ^ string
# ^ punctuation.special
# ^ function
# ^ string
# ^ punctuation.special
# ^ string
"Multiline
string"
# <- string
# ^ string
"""
Heredoc
"""
# ^ string
'charlist'
# ^ string
~s(string sigil #{1})
# <- string
# ^ string
# ^ string
# ^ number
~S/string #{1}/
# ^ string
~r/x?/iu
# <- string.regex
# ^ string.regex
# ^ string.regex
~R{noescapes\}[a-z]*}
# ^ string.regex
# ^ string.escape
# ^ string.regex
~w(hello #{ ["has" <> "123", '\c\d', "\123 interpol" | []] } world)s
#<- string.special
# ^ string.special
# ^ punctuation.special
# ^ punctuation.bracket
# ^ string
# ^ operator
# ^ string
# ^ punctuation.delimiter
# ^ string
# ^ string.escape
# ^ string.escape
# ^ string
# ^ punctuation.delimiter
# ^ string
# ^ string.escape
# ^ string
# ^ operator
# ^ punctuation.bracket
# ^ punctuation.bracket
# ^ punctuation.bracket
# ^ punctuation.special
# ^ string.special
~w/yoo \\ \/ =)/
# ^ string.special
# ^ string.escape
# ^ string.escape
# ^ string.special
~W/yoo \\ \/ =)/
# ^ string.special
# ^ string.special
# ^ string.escape
# ^ string.special
~D/2020-01-01/d
# ^ string.special

@ -1,319 +0,0 @@
defmodule Long.Module.Name do
# ^ keyword
# ^ module
# ^ module
# ^ keyword
@moduledoc "Simple doc"
# <- comment.doc
# ^ comment.doc.__attribute__
# ^ comment.doc
@moduledoc false
# <- comment.doc
# ^ comment.doc.__attribute__
# ^ comment.doc
@moduledoc """
Heredoc doc
"""
# ^ comment.doc
@moduledoc ~S'''
Sigil doc
'''
# ^ comment.doc
@moduledoc "With #{1} interpolation"
# ^ punctuation.special
# ^ number
# ^ punctuation.special
@typedoc "Type doc"
# <- comment.doc
@doc "Type doc"
# <- comment.doc
@doc """
Multiline docstring
"with quotes"
and #{ inspect %{"interpolation" => "in" <> "action"} }
now with #{ {:a, 'tuple'} }
and #{ inspect {
:tuple,
%{ with: "nested #{ inspect %{ :interpolation => %{} } }" }
} }
"""
# <- comment.doc
@spec func(type, integer()) :: :ok | :fail
# <- attribute
# ^ attribute
# ^ function
# ^ punctuation.bracket
# ^ variable
# ^ punctuation.delimiter
# ^ function
# ^ punctuation.bracket
# ^ punctuation.bracket
# ^ punctuation.bracket
# ^ operator
# ^ string.special.symbol
# ^ operator
# ^ string.special.symbol
defstruct items: []
# ^ keyword
# ^ string.special.symbol
# ^ punctuation.bracket
# ^ punctuation.bracket
defexception [:message]
# ^ keyword
# ^ punctuation.bracket
# ^ string.special.symbol
# ^ punctuation.bracket
@type item :: String.t()
# <- attribute
# ^ attribute
# ^ variable
# ^ operator
# ^ module
# ^ operator
# ^ function
# ^ punctuation.bracket
# ^ punctuation.bracket
@attr "value"
# <- attribute
# ^ attribute
# ^ string
@true
# ^ attribute
@nil
# ^ attribute
def f, do: nil
# ^ keyword
# ^ function
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ constant
def f(x), do: x
# ^ keyword
# ^ function
# ^ punctuation.bracket
# ^ variable
# ^ punctuation.bracket
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ variable
def f(10), do: nil
# ^ keyword
# ^ function
# ^ punctuation.bracket
# ^ punctuation.bracket
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ constant
def f(a, b \\ []), do: nil
# <- keyword
# ^ function
# ^ punctuation.bracket
# ^ variable
# ^ punctuation.delimiter
# ^ variable
# ^ operator
# ^ punctuation.bracket
# ^ punctuation.bracket
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ constant
def __before_compile__(_) do
# <- keyword
# ^ function
# ^ punctuation.bracket
# ^ comment.unused
# ^ punctuation.bracket
# ^ keyword
end
# <- keyword
def with_guard(x) when x == 1 do: nil
# <- keyword
# ^ function
# ^ variable
# ^ keyword
# ^ variable
# ^ operator
# ^ number
# ^ keyword
# <- keyword
def with_guard when is_integer(1), do: nil
# <- keyword
# ^ function
# ^ keyword
# ^ function
# ^ punctuation.bracket
# ^ number
# ^ punctuation.bracket
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ constant
def x + y, do: nil
# ^ keyword
# ^ variable
# ^ operator
# ^ variable
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ constant
def x |> y, do: nil
# ^ keyword
# ^ variable
# ^ operator
# ^ variable
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ constant
def x and y, do: nil
# ^ keyword
# ^ variable
# ^ keyword
# ^ variable
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ constant
def unquote(f)(x), do: nil
# ^ keyword
# ^ keyword
# ^ punctuation.bracket
# ^ variable
# ^ punctuation.bracket
# ^ punctuation.bracket
# ^ variable
# ^ punctuation.bracket
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ constant
def unquote(name)(unquote_splicing(args)), do: nil
# ^ keyword
# ^ keyword
# ^ punctuation.bracket
# ^ variable
# ^ punctuation.bracket
# ^ punctuation.bracket
# ^ keyword
# ^ punctuation.bracket
# ^ variable
# ^ punctuation.bracket
# ^ punctuation.bracket
# ^ string.special.symbol
# ^ constant
def(test(x), do: x)
# ^ keyword
# ^ punctuation.bracket
# ^ punctuation.bracket
# ^ variable
# ^ punctuation.bracket
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ variable
# ^ punctuation.bracket
defguard is_something(one), do: one != nil
# ^ keyword
# ^ function
# ^ punctuation.bracket
# ^ variable
# ^ punctuation.bracket
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ variable
# ^ operator
# ^ constant
defdelegate empty?(list), to: Enum
# ^ keyword
# ^ function
# ^ punctuation.bracket
# ^ variable
# ^ punctuation.bracket
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ module
defmacro meta_function(name) do
# ^ keyword
# ^ function
# ^ punctuation.bracket
# ^ variable
# ^ punctuation.bracket
# ^ keyword
quote do
# ^ keyword
# ^ keyword
def unquote(:"#{name}_foo")() do
# ^ keyword
# ^ keyword
# ^ punctuation.bracket
# ^ string.special.symbol
# ^ punctuation.special
# ^ variable
# ^ punctuation.special
# ^ string.special.symbol
# ^ punctuation.bracket
# ^ punctuation.bracket
# ^ punctuation.bracket
# ^ keyword
unquote("yessir")
# ^ keyword
# ^ punctuation.bracket
# ^ string
# ^ punctuation.bracket
end
# <- keyword
end
# <- keyword
end
# <- keyword
end
# <- keyword
defprotocol Useless do
# ^ keyword
# ^ module
# ^ keyword
def func(this)
# ^ keyword
# ^ function
# ^ punctuation.bracket
# ^ variable
# ^ punctuation.bracket
end
# <- keyword
defimpl Useless, for: Atom do
# ^ keyword
# ^ module
# ^ punctuation.delimiter
# ^ string.special.symbol
# ^ module
# ^ keyword
end
# <- keyword

@ -1,89 +0,0 @@
a in b
# <- variable
# ^ keyword
# ^ variable
a not in b
# <- variable
# ^ keyword
# ^ keyword
# ^ variable
a not in b
# <- variable
# ^ keyword
# ^ keyword
# ^ variable
a ~>> b = bind(a, b)
# <- variable
# ^ operator
# ^ variable
# ^ operator
# ^ function
# ^ punctuation.bracket
# ^ variable
# ^ punctuation.delimiter
# ^ variable
# ^ punctuation.bracket
a ~> b
# ^ operator
a + b
# ^ operator
... == !x && y || z
# <- variable
# ^ operator
# ^ operator
# ^ variable
# ^ operator
# ^ variable
# ^ operator
# ^ variable
x = 1 + 2.0 * 3
# <- variable
# ^ operator
# ^ number
# ^ operator
# ^ number
# ^ operator
# ^ number
y = true and false
# <- variable
# ^ operator
# ^ constant
# ^ keyword
# ^ constant
{ ^z, a } = {true, x}
# <- punctuation.bracket
# ^ operator
# ^ variable
# ^ punctuation.delimiter
# ^ variable
# ^ operator
# ^ punctuation.bracket
# ^ constant
# ^ punctuation.delimiter
# ^ variable
# ^ punctuation.bracket
"hello" |> String.upcase |> String.downcase()
# ^ string
# ^ operator
# ^ module
# ^ operator
# ^ function
# ^ operator
# ^ module
# ^ operator
# ^ function
range = ..
# <- variable
# ^ operator
# ^ operator

@ -1,31 +0,0 @@
defmodule Foo.Bar.Baz do
# ^ definition.module
# ^ definition.module
# ^ definition.module
def init(arg) do
# ^ definition.function
state =
arg
|> map(&(&1 * 2))
# ^ reference.call
|> map(&(&1 + 1))
# ^ reference.call
{:ok, arg}
end
def map(list, fun, acc \\ [])
# ^ definition.function
def map([head | rest], fun, acc) do
# ^ definition.function
map(rest, fun, [fun.(head) | acc])
# <- reference.call
end
def map([], _fun, acc), do: Enum.reverse(acc)
# ^ definition.function
# ^ reference.module
# ^ reference.call
end

@ -1,21 +0,0 @@
defprotocol Countable do
# ^ definition.module
def count(data)
# ^ definition.function
end
defimpl Countable, for: Binary do
# ^ reference.module
# ^ reference.module
def count(binary), do: byte_size(binary)
# ^ definition.function
# ^ reference.call
end
defimpl Countable, for: List do
# ^ reference.module
# ^ reference.module
def count(list), do: length(list)
# ^ definition.function
# ^ reference.call
end