mirror of https://github.com/Wilfred/difftastic/
Merge #205
commit
28c6e35943
@ -0,0 +1,52 @@
|
||||
import todomvc/web/routes
|
||||
import todomvc/log
|
||||
import gleam/int
|
||||
import gleam/string
|
||||
import gleam/result
|
||||
import gleam/erlang/os
|
||||
import gleam/http/elli
|
||||
import gleam/option
|
||||
import gleam/pgo
|
||||
|
||||
pub fn main() {
|
||||
log.configure_backend()
|
||||
|
||||
let port = load_port()
|
||||
let application_secret = load_application_secret()
|
||||
let db = start_database_connection_pool()
|
||||
let web = routes.stack(application_secret, db)
|
||||
|
||||
let log_string =
|
||||
string.concat(["Listening on localhost:", int.to_string(port), " ✨"])
|
||||
log.info(log_string)
|
||||
|
||||
assert Ok(_) = elli.become(web, on_port: port)
|
||||
}
|
||||
|
||||
pub fn start_database_connection_pool() -> pgo.Connection {
|
||||
let config =
|
||||
os.get_env("DATABASE_URL")
|
||||
|> result.then(pgo.url_config)
|
||||
|> result.lazy_unwrap(fn() {
|
||||
pgo.Config(
|
||||
..pgo.default_config(),
|
||||
host: "0.0.0.0",
|
||||
database: "gleam_todomvc_dev",
|
||||
user: "postgres",
|
||||
password: option.Some("postgres"),
|
||||
)
|
||||
})
|
||||
|
||||
pgo.connect(pgo.Config(..config, pool_size: 15))
|
||||
}
|
||||
|
||||
fn load_application_secret() -> String {
|
||||
os.get_env("APPLICATION_SECRET")
|
||||
|> result.unwrap("27434b28994f498182d459335258fb6e")
|
||||
}
|
||||
|
||||
fn load_port() -> Int {
|
||||
os.get_env("PORT")
|
||||
|> result.then(int.parse)
|
||||
|> result.unwrap(8080)
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
import todomvc/web/routes
|
||||
import todomvc/log
|
||||
import gleam/int
|
||||
import gleam/string
|
||||
import gleam/result
|
||||
import gleam/erlang/os
|
||||
import gleam/http/elli
|
||||
import gleam/option
|
||||
import gleam/pgo
|
||||
|
||||
pub fn main() {
|
||||
log.configure_backend()
|
||||
|
||||
let port = load_port()
|
||||
let application_secret = load_application_secret()
|
||||
let db = start_database_connection_pool()
|
||||
let web = routes.stack(application_secret, db)
|
||||
|
||||
string.concat(["Listening on localhost:", int.to_string(port), " ✨"])
|
||||
|> log.info
|
||||
|
||||
assert Ok(_) = elli.become(web, on_port: port)
|
||||
}
|
||||
|
||||
pub fn start_database_connection_pool() -> pgo.Connection {
|
||||
let config =
|
||||
os.get_env("DATABASE_URL")
|
||||
|> result.then(pgo.url_config)
|
||||
|> result.lazy_unwrap(fn() {
|
||||
pgo.Config(
|
||||
..pgo.default_config(),
|
||||
host: "localhost",
|
||||
database: "gleam_todomvc_dev",
|
||||
user: "postgres",
|
||||
password: option.Some("postgres"),
|
||||
)
|
||||
})
|
||||
|
||||
pgo.connect(pgo.Config(..config, pool_size: 15))
|
||||
}
|
||||
|
||||
fn load_application_secret() -> String {
|
||||
os.get_env("APPLICATION_SECRET")
|
||||
|> result.unwrap("27434b28994f498182d459335258fb6e")
|
||||
}
|
||||
|
||||
fn load_port() -> Int {
|
||||
os.get_env("PORT")
|
||||
|> result.then(int.parse)
|
||||
|> result.unwrap(3000)
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
../tree-sitter-gleam/queries/highlights.scm
|
||||
@ -0,0 +1 @@
|
||||
tree-sitter-gleam/src
|
||||
@ -0,0 +1,2 @@
|
||||
src/** linguist-generated
|
||||
test/** linguist-documentation
|
||||
@ -0,0 +1,37 @@
|
||||
name: CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
bless:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
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: Ensure generated parser files are up to date
|
||||
run: npx tree-sitter generate
|
||||
|
||||
- name: Run tree-sitter tests
|
||||
run: npx tree-sitter test
|
||||
|
||||
- name: Check formatting
|
||||
run: npm run check-formatted
|
||||
@ -0,0 +1,43 @@
|
||||
# generates the parser with 'tree-sitter generate' if the parser is out of date
|
||||
name: Generate Parser
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
generate:
|
||||
name: Generate Parser
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@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 files
|
||||
run: npx tree-sitter generate
|
||||
|
||||
- name: Commit generated parser files
|
||||
run: |
|
||||
git config --local user.email "$(git log --format='%ae' HEAD^!)"
|
||||
git config --local user.name "$(git log --format='%an' HEAD^!)"
|
||||
git add src
|
||||
git commit -m "Generate parser" || true
|
||||
git push
|
||||
@ -0,0 +1,58 @@
|
||||
name: release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
jobs:
|
||||
build-release:
|
||||
name: build-release
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- macos-latest
|
||||
- ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: "14.x"
|
||||
|
||||
- name: Install npm dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Ensure generated parser files are up to date
|
||||
run: npx tree-sitter generate
|
||||
|
||||
- name: Ensure tests pass
|
||||
run: npx tree-sitter test
|
||||
|
||||
- name: Compile library file
|
||||
run: cc -shared -fPIC -g -O2 -I src src/parser.c -o tree-sitter-gleam.so
|
||||
|
||||
- name: Create archive
|
||||
run: |
|
||||
VERSION="${GITHUB_REF#refs/tags/}"
|
||||
case ${{ matrix.os }} in
|
||||
"ubuntu-latest") FAMILY="linux";;
|
||||
"macos-latest") FAMILY="macos";;
|
||||
esac
|
||||
ARCHIVE="tree-sitter-gleam-$VERSION-$FAMILY.tar.gz"
|
||||
|
||||
tar -czf $ARCHIVE tree-sitter-gleam.so
|
||||
|
||||
echo "ASSET=$ARCHIVE" >> $GITHUB_ENV
|
||||
|
||||
- name: Upload release archive
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
draft: true
|
||||
prerelease: false
|
||||
fail_on_unmatched_files: true
|
||||
files: |
|
||||
${{ env.ASSET }}
|
||||
@ -0,0 +1,5 @@
|
||||
node_modules
|
||||
target
|
||||
build
|
||||
*.wasm
|
||||
log.html
|
||||
@ -0,0 +1,59 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter"
|
||||
version = "0.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c36be3222512d85a112491ae0cc280a38076022414f00b64582da1b7565ffd82"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter-gleam"
|
||||
version = "0.20.1"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"tree-sitter",
|
||||
]
|
||||
@ -0,0 +1,26 @@
|
||||
[package]
|
||||
name = "tree-sitter-gleam"
|
||||
description = "gleam grammar for the tree-sitter parsing library"
|
||||
version = "0.20.1"
|
||||
keywords = ["incremental", "parsing", "gleam"]
|
||||
categories = ["parsing", "text-editors"]
|
||||
repository = "https://github.com/tree-sitter/tree-sitter-gleam"
|
||||
edition = "2018"
|
||||
license = "Apache-2.0"
|
||||
|
||||
build = "bindings/rust/build.rs"
|
||||
include = [
|
||||
"bindings/rust/*",
|
||||
"grammar.js",
|
||||
"queries/*",
|
||||
"src/*",
|
||||
]
|
||||
|
||||
[lib]
|
||||
path = "bindings/rust/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
tree-sitter = "~0.20"
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.0"
|
||||
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@ -0,0 +1,78 @@
|
||||
tree-sitter-gleam
|
||||
=================
|
||||
|
||||
A [tree-sitter] grammar for the [Gleam programming language]
|
||||
|
||||
[tree-sitter]: https://tree-sitter.github.io
|
||||
[Gleam programming language]: https://gleam.run
|
||||
|
||||
This grammar is able to parse the entire Gleam language. It is largely based
|
||||
on the Gleam parser itself, and deviations from that are noted throughout the
|
||||
codebase.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
tree-sitter-gleam, as with all tree-sitter grammars, is of limited utility on
|
||||
its own. Instead, tree-sitter-gleam is best used as a Gleam parser that can be
|
||||
embedded in other projects. An example of such a project is
|
||||
[tree-sitter-gleam-rust-example].
|
||||
|
||||
However, [tree-sitter-cli] can be used with this grammar to show generated parse
|
||||
trees and syntax highlighting for a given Gleam file.
|
||||
|
||||
1. [Install tree-sitter-cli]
|
||||
2. Create a `tree-sitters` directory in your home directory.
|
||||
3. Clone this repository (or symlink it) into the new `~/tree-sitters/` directory.
|
||||
4. Run `tree-sitter parse path/to/file.gleam` to be shown the parse tree for the
|
||||
file.
|
||||
5. Run `tree-sitter highlight path/to/file.gleam` to be shown the file with
|
||||
syntax highlighting applied.
|
||||
|
||||
[tree-sitter-gleam-rust-example]: https://github.com/J3RN/tree-sitter-gleam-rust-example
|
||||
[tree-sitter-cli]: https://github.com/tree-sitter/tree-sitter/blob/master/cli/README.md
|
||||
[Install tree-sitter-cli]: https://github.com/tree-sitter/tree-sitter/blob/master/cli/README.md#installation
|
||||
|
||||
Various Gotchas
|
||||
---------------
|
||||
|
||||
There are a few nodes in the generated AST that may be confusing at first:
|
||||
- `type` :: A very ambiguous name, but this refers to a concrete type such as
|
||||
`List(#(String, Int))`
|
||||
- `type_name` :: Refers to essentially the left side of a type declaration and
|
||||
includes parameters, e.g. `MyType(foo, bar)`.
|
||||
- `type_identifier` :: Known in the parser as "UpName", this is what you would
|
||||
intuitively think of as a type's name, such as `List` or `Result`.
|
||||
- `function_call` :: The name is not confusing, but its structure may be. Since
|
||||
Gleam supports first-class functions, the function being invoked could be a
|
||||
variable, a field of a record, an element of a tuple, etc. Some of these are
|
||||
ambiguous without context that tree-sitter does not have. e.g.
|
||||
In `string.replace(x, y, z)`, `string` could be a record with a field
|
||||
`replace` that is a function or it could be a module with a function `replace`
|
||||
—there's no way for the parser to know. In this case, it will be parsed to
|
||||
`(function_call function: (field_access ...) ...)` , as I arbitrarily decided
|
||||
to always assume the code is accessing a field on a record.
|
||||
|
||||
This is not a comprehensive list. If you find a node confusing, search for it
|
||||
in `grammar.js`, as it might have an explanatory comment. Either way, feel free
|
||||
to add it to this list and send a PR! ✨
|
||||
|
||||
To-do List
|
||||
----------
|
||||
|
||||
- [x] Add ability to parse all language constructs
|
||||
- [x] Syntax highlighting queries
|
||||
- [ ] Have an issue? Let me know! Please [open an issue] 💁
|
||||
|
||||
[open an issue]: https://github.com/J3RN/tree-sitter-gleam/issues/new
|
||||
|
||||
Style
|
||||
-----
|
||||
|
||||
To prevent headaches from stylistic differences, I request that you please
|
||||
follow these style suggestions. 🙏
|
||||
|
||||
- Remove all non-mandatory trailing whitespace
|
||||
- Ensure a final newline is present at the end of all files (this is the default
|
||||
in Vim, Emacs)
|
||||
- Format JavaScript by running `npm run format`
|
||||
@ -0,0 +1,19 @@
|
||||
{
|
||||
"targets": [
|
||||
{
|
||||
"target_name": "tree_sitter_gleam_binding",
|
||||
"include_dirs": [
|
||||
"<!(node -e \"require('nan')\")",
|
||||
"src"
|
||||
],
|
||||
"sources": [
|
||||
"bindings/node/binding.cc",
|
||||
"src/parser.c",
|
||||
# If your language uses an external scanner, add it here.
|
||||
],
|
||||
"cflags_c": [
|
||||
"-std=c99",
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
#include "tree_sitter/parser.h"
|
||||
#include <node.h>
|
||||
#include "nan.h"
|
||||
|
||||
using namespace v8;
|
||||
|
||||
extern "C" TSLanguage * tree_sitter_gleam();
|
||||
|
||||
namespace {
|
||||
|
||||
NAN_METHOD(New) {}
|
||||
|
||||
void Init(Local<Object> exports, Local<Object> module) {
|
||||
Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
|
||||
tpl->SetClassName(Nan::New("Language").ToLocalChecked());
|
||||
tpl->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
|
||||
Local<Function> constructor = Nan::GetFunction(tpl).ToLocalChecked();
|
||||
Local<Object> instance = constructor->NewInstance(Nan::GetCurrentContext()).ToLocalChecked();
|
||||
Nan::SetInternalFieldPointer(instance, 0, tree_sitter_gleam());
|
||||
|
||||
Nan::Set(instance, Nan::New("name").ToLocalChecked(), Nan::New("gleam").ToLocalChecked());
|
||||
Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance);
|
||||
}
|
||||
|
||||
NODE_MODULE(tree_sitter_gleam_binding, Init)
|
||||
|
||||
} // namespace
|
||||
@ -0,0 +1,19 @@
|
||||
try {
|
||||
module.exports = require("../../build/Release/tree_sitter_gleam_binding");
|
||||
} catch (error1) {
|
||||
if (error1.code !== 'MODULE_NOT_FOUND') {
|
||||
throw error1;
|
||||
}
|
||||
try {
|
||||
module.exports = require("../../build/Debug/tree_sitter_gleam_binding");
|
||||
} catch (error2) {
|
||||
if (error2.code !== 'MODULE_NOT_FOUND') {
|
||||
throw error2;
|
||||
}
|
||||
throw error1
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
module.exports.nodeTypeInfo = require("../../src/node-types.json");
|
||||
} catch (_) {}
|
||||
@ -0,0 +1,40 @@
|
||||
fn main() {
|
||||
let src_dir = std::path::Path::new("src");
|
||||
|
||||
let mut c_config = cc::Build::new();
|
||||
c_config.include(&src_dir);
|
||||
c_config
|
||||
.flag_if_supported("-Wno-unused-parameter")
|
||||
.flag_if_supported("-Wno-unused-but-set-variable")
|
||||
.flag_if_supported("-Wno-trigraphs");
|
||||
let parser_path = src_dir.join("parser.c");
|
||||
c_config.file(&parser_path);
|
||||
|
||||
// If your language uses an external scanner written in C,
|
||||
// then include this block of code:
|
||||
|
||||
/*
|
||||
let scanner_path = src_dir.join("scanner.c");
|
||||
c_config.file(&scanner_path);
|
||||
println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap());
|
||||
*/
|
||||
|
||||
c_config.compile("parser");
|
||||
println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap());
|
||||
|
||||
// If your language uses an external scanner written in C++,
|
||||
// then include this block of code:
|
||||
|
||||
/*
|
||||
let mut cpp_config = cc::Build::new();
|
||||
cpp_config.cpp(true);
|
||||
cpp_config.include(&src_dir);
|
||||
cpp_config
|
||||
.flag_if_supported("-Wno-unused-parameter")
|
||||
.flag_if_supported("-Wno-unused-but-set-variable");
|
||||
let scanner_path = src_dir.join("scanner.cc");
|
||||
cpp_config.file(&scanner_path);
|
||||
cpp_config.compile("scanner");
|
||||
println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap());
|
||||
*/
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
//! This crate provides gleam language support for the [tree-sitter][] parsing library.
|
||||
//!
|
||||
//! Typically, you will use the [language][language func] function to add this language to a
|
||||
//! tree-sitter [Parser][], and then use the parser to parse some code:
|
||||
//!
|
||||
//! ```
|
||||
//! let code = "";
|
||||
//! let mut parser = tree_sitter::Parser::new();
|
||||
//! parser.set_language(tree_sitter_gleam::language()).expect("Error loading gleam 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_gleam() -> 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_gleam() }
|
||||
}
|
||||
|
||||
/// The content of the [`node-types.json`][] file for this grammar.
|
||||
///
|
||||
/// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types
|
||||
pub const NODE_TYPES: &'static str = include_str!("../../src/node-types.json");
|
||||
|
||||
// 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 gleam language");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,740 @@
|
||||
const NEWLINE = /\r?\n/;
|
||||
|
||||
module.exports = grammar({
|
||||
name: "gleam",
|
||||
extras: ($) => [
|
||||
";",
|
||||
NEWLINE,
|
||||
/\s/,
|
||||
$.module_comment,
|
||||
$.statement_comment,
|
||||
$.comment,
|
||||
],
|
||||
conflicts: ($) => [
|
||||
[$._maybe_record_expression, $._maybe_tuple_expression],
|
||||
[
|
||||
$._maybe_record_expression,
|
||||
$._maybe_tuple_expression,
|
||||
$.remote_type_identifier,
|
||||
],
|
||||
[$.case_subjects],
|
||||
[$.source_file],
|
||||
],
|
||||
rules: {
|
||||
/* General rules */
|
||||
source_file: ($) =>
|
||||
repeat(choice($.target_group, $._statement, $._expression_seq)),
|
||||
|
||||
_statement: ($) =>
|
||||
choice(
|
||||
$.import,
|
||||
$.constant,
|
||||
$.external_type,
|
||||
$.external_function,
|
||||
$.function,
|
||||
$.type_definition,
|
||||
$.type_alias
|
||||
),
|
||||
|
||||
/* Comments */
|
||||
module_comment: ($) => token(seq("////", /.*/)),
|
||||
statement_comment: ($) => token(seq("///", /.*/)),
|
||||
comment: ($) => token(seq("//", /.*/)),
|
||||
|
||||
/* Target groups */
|
||||
target_group: ($) =>
|
||||
seq("if", field("target", $.target), "{", repeat($._statement), "}"),
|
||||
target: ($) => choice("erlang", "javascript"),
|
||||
|
||||
/* Import statements */
|
||||
import: ($) =>
|
||||
seq(
|
||||
"import",
|
||||
field("module", $.module),
|
||||
optional(seq(".", field("imports", $.unqualified_imports))),
|
||||
optional(seq("as", field("alias", $.identifier)))
|
||||
),
|
||||
module: ($) => seq($._name, repeat(seq("/", $._name))),
|
||||
unqualified_imports: ($) =>
|
||||
seq("{", optional(series_of($.unqualified_import, ",")), "}"),
|
||||
unqualified_import: ($) =>
|
||||
choice(
|
||||
seq(
|
||||
field("name", $.identifier),
|
||||
optional(seq("as", field("alias", $.identifier)))
|
||||
),
|
||||
seq(
|
||||
field("name", $.type_identifier),
|
||||
optional(seq("as", field("alias", $.type_identifier)))
|
||||
)
|
||||
),
|
||||
|
||||
/* Constant statements */
|
||||
constant: ($) =>
|
||||
seq(
|
||||
optional($.visibility_modifier),
|
||||
"const",
|
||||
field("name", $.identifier),
|
||||
optional($._constant_type_annotation),
|
||||
"=",
|
||||
field("value", $._constant_value)
|
||||
),
|
||||
_constant_value: ($) =>
|
||||
choice(
|
||||
$.string,
|
||||
$.float,
|
||||
$.integer,
|
||||
alias($.constant_tuple, $.tuple),
|
||||
alias($.constant_list, $.list),
|
||||
alias($._constant_bit_string, $.bit_string),
|
||||
alias($.constant_record, $.record)
|
||||
),
|
||||
constant_tuple: ($) =>
|
||||
seq("#", "(", optional(series_of($._constant_value, ",")), ")"),
|
||||
constant_list: ($) =>
|
||||
seq("[", optional(series_of($._constant_value, ",")), "]"),
|
||||
...bit_string_rules("constant", "_constant_value", "integer"),
|
||||
constant_record: ($) =>
|
||||
seq(
|
||||
field("name", choice($.type_identifier, $.remote_type_identifier)),
|
||||
optional(
|
||||
field("arguments", alias($.constant_record_arguments, $.arguments))
|
||||
)
|
||||
),
|
||||
constant_record_arguments: ($) =>
|
||||
seq(
|
||||
"(",
|
||||
optional(series_of(alias($.constant_record_argument, $.argument), ",")),
|
||||
")"
|
||||
),
|
||||
constant_record_argument: ($) =>
|
||||
seq(
|
||||
optional(seq(field("label", $.label), ":")),
|
||||
field("value", $._constant_value)
|
||||
),
|
||||
|
||||
/* Special constant types */
|
||||
// Versions of $._type, $._type_annotation, etc, that have constraints
|
||||
// specific to constants.
|
||||
_constant_type: ($) =>
|
||||
choice(
|
||||
$.type_hole,
|
||||
alias($.constant_tuple_type, $.tuple_type),
|
||||
alias($.constant_type, $.type)
|
||||
),
|
||||
_constant_type_annotation: ($) => seq(":", field("type", $._constant_type)),
|
||||
constant_tuple_type: ($) =>
|
||||
seq("#", "(", optional(series_of($._constant_type, ",")), ")"),
|
||||
constant_type: ($) =>
|
||||
seq(
|
||||
field("name", choice($.type_identifier, $.remote_type_identifier)),
|
||||
optional(
|
||||
field("arguments", alias($.constant_type_arguments, $.type_arguments))
|
||||
)
|
||||
),
|
||||
constant_type_arguments: ($) =>
|
||||
seq(
|
||||
"(",
|
||||
optional(
|
||||
series_of(alias($.constant_type_argument, $.type_argument), ",")
|
||||
),
|
||||
")"
|
||||
),
|
||||
constant_type_argument: ($) => $._constant_type,
|
||||
|
||||
external_type: ($) =>
|
||||
seq(optional($.visibility_modifier), "external", "type", $.type_name),
|
||||
|
||||
/* External function */
|
||||
external_function: ($) =>
|
||||
seq(
|
||||
optional($.visibility_modifier),
|
||||
"external",
|
||||
"fn",
|
||||
field("name", $.identifier),
|
||||
field(
|
||||
"parameters",
|
||||
alias($.external_function_parameters, $.function_parameters)
|
||||
),
|
||||
"->",
|
||||
field("return_type", $._type),
|
||||
"=",
|
||||
field("body", $.external_function_body)
|
||||
),
|
||||
// Different from module function parameters in that module function
|
||||
// parameters may be labeled whereas external function parameters cannot.
|
||||
external_function_parameters: ($) =>
|
||||
seq(
|
||||
"(",
|
||||
optional(
|
||||
series_of(
|
||||
alias($.external_function_parameter, $.function_parameter),
|
||||
","
|
||||
)
|
||||
),
|
||||
")"
|
||||
),
|
||||
external_function_parameter: ($) =>
|
||||
seq(
|
||||
optional(seq(field("name", $.identifier), ":")),
|
||||
field("type", $._type)
|
||||
),
|
||||
external_function_body: ($) => seq($.string, $.string),
|
||||
|
||||
/* Functions */
|
||||
function: ($) =>
|
||||
seq(
|
||||
optional($.visibility_modifier),
|
||||
"fn",
|
||||
field("name", $.identifier),
|
||||
field("parameters", $.function_parameters),
|
||||
optional(seq("->", field("return_type", $._type))),
|
||||
"{",
|
||||
field("body", alias($._expression_seq, $.function_body)),
|
||||
"}"
|
||||
),
|
||||
function_parameters: ($) =>
|
||||
seq("(", optional(series_of($.function_parameter, ",")), ")"),
|
||||
function_parameter: ($) =>
|
||||
seq(
|
||||
choice(
|
||||
$._labeled_discard_param,
|
||||
$._discard_param,
|
||||
$._labeled_name_param,
|
||||
$._name_param
|
||||
),
|
||||
optional($._type_annotation)
|
||||
),
|
||||
_labeled_discard_param: ($) =>
|
||||
seq(field("label", $.label), field("name", $.discard)),
|
||||
_discard_param: ($) => field("name", $.discard),
|
||||
_labeled_name_param: ($) =>
|
||||
seq(field("label", $.label), field("name", $.identifier)),
|
||||
_name_param: ($) => field("name", $.identifier),
|
||||
// This method diverges from the parser's `parse_expression_seq` somewhat.
|
||||
// The parser considers all expressions after a `try` to be part of its AST
|
||||
// node, namely the "then" section. Gleam code like this:
|
||||
//
|
||||
// try int_a = parse(a)
|
||||
// try int_b = parse(b)
|
||||
// Ok(int_a + int_b)
|
||||
//
|
||||
// is parsed as:
|
||||
//
|
||||
// (try
|
||||
// pattern: (pattern)
|
||||
// value: (call (identifier))
|
||||
// then: (try
|
||||
// pattern: (pattern)
|
||||
// value: (call (identifier))
|
||||
// then: (record (...))))
|
||||
//
|
||||
// This makes sense for the parser, but (IMO) would be more confusing for
|
||||
// users and tooling which don't think about `try`s as having a "then". Thus,
|
||||
// `try`s are essentially treated the same as any other expression.
|
||||
_expression_seq: ($) => repeat1(choice($._expression, $.try)),
|
||||
try: ($) =>
|
||||
seq(
|
||||
"try",
|
||||
field("pattern", $._pattern),
|
||||
optional($._type_annotation),
|
||||
"=",
|
||||
field("value", $._expression)
|
||||
),
|
||||
_expression: ($) => choice($._expression_unit, $.binary_expression),
|
||||
binary_expression: ($) =>
|
||||
choice(
|
||||
binaryExpr(prec.left, 1, "||", $._expression),
|
||||
binaryExpr(prec.left, 2, "&&", $._expression),
|
||||
binaryExpr(prec.left, 3, "==", $._expression),
|
||||
binaryExpr(prec.left, 3, "!=", $._expression),
|
||||
binaryExpr(prec.left, 4, "<", $._expression),
|
||||
binaryExpr(prec.left, 4, "<=", $._expression),
|
||||
binaryExpr(prec.left, 4, "<.", $._expression),
|
||||
binaryExpr(prec.left, 4, "<=.", $._expression),
|
||||
binaryExpr(prec.left, 4, ">", $._expression),
|
||||
binaryExpr(prec.left, 4, ">=", $._expression),
|
||||
binaryExpr(prec.left, 4, ">.", $._expression),
|
||||
binaryExpr(prec.left, 4, ">=.", $._expression),
|
||||
binaryExpr(prec.left, 5, "|>", $._expression),
|
||||
binaryExpr(prec.left, 6, "+", $._expression),
|
||||
binaryExpr(prec.left, 6, "+.", $._expression),
|
||||
binaryExpr(prec.left, 6, "-", $._expression),
|
||||
binaryExpr(prec.left, 6, "-.", $._expression),
|
||||
binaryExpr(prec.left, 7, "*", $._expression),
|
||||
binaryExpr(prec.left, 7, "*.", $._expression),
|
||||
binaryExpr(prec.left, 7, "/", $._expression),
|
||||
binaryExpr(prec.left, 7, "/.", $._expression),
|
||||
binaryExpr(prec.left, 7, "%", $._expression)
|
||||
),
|
||||
// The way that this function is written in the Gleam parser is essentially
|
||||
// incompatible with tree-sitter. It first parses some base expression,
|
||||
// then potentially parses tuple access, field access, record updates, or
|
||||
// function calls as an extension of that base expression that was
|
||||
// previously parsed. tree-sitter provides no facility to amend a node that
|
||||
// was already successfully parsed. Therefore, tuple access, field access,
|
||||
// record updates, and function calls must be parsed as alternatives to the
|
||||
// expressions they build upon rather than extensions thereof.
|
||||
_expression_unit: ($) =>
|
||||
choice(
|
||||
$.string,
|
||||
$.integer,
|
||||
$.float,
|
||||
// If we decide that record constructors (value constructors) are
|
||||
// actually functions, this will require a refactor.
|
||||
$.record,
|
||||
$.identifier,
|
||||
$.todo,
|
||||
$.tuple,
|
||||
$.list,
|
||||
alias($._expression_bit_string, $.bit_string),
|
||||
$.anonymous_function,
|
||||
$.expression_group,
|
||||
$.case,
|
||||
$.let,
|
||||
$.assert,
|
||||
$.record_update,
|
||||
$.tuple_access,
|
||||
$.field_access,
|
||||
$.function_call
|
||||
),
|
||||
record: ($) =>
|
||||
seq(
|
||||
field("name", choice($.type_identifier, $.remote_type_identifier)),
|
||||
optional(field("arguments", $.arguments))
|
||||
),
|
||||
todo: ($) =>
|
||||
seq("todo", optional(seq("(", field("message", $.string), ")"))),
|
||||
tuple: ($) => seq("#", "(", optional(series_of($._expression, ",")), ")"),
|
||||
list: ($) =>
|
||||
seq(
|
||||
"[",
|
||||
optional(
|
||||
seq(
|
||||
$._expression,
|
||||
optional(repeat(seq(",", $._expression))),
|
||||
optional(","),
|
||||
optional(seq("..", field("spread", $._expression)))
|
||||
)
|
||||
),
|
||||
"]"
|
||||
),
|
||||
...bit_string_rules("expression", "_expression_unit", "_expression"),
|
||||
anonymous_function: ($) =>
|
||||
seq(
|
||||
"fn",
|
||||
field("parameters", $.function_parameters),
|
||||
optional(seq("->", field("return_type", $._type))),
|
||||
"{",
|
||||
field("body", alias($._expression_seq, $.function_body)),
|
||||
"}"
|
||||
),
|
||||
expression_group: ($) => seq("{", $._expression_seq, "}"),
|
||||
case: ($) =>
|
||||
seq(
|
||||
"case",
|
||||
field("subjects", $.case_subjects),
|
||||
"{",
|
||||
field("clauses", $.case_clauses),
|
||||
"}"
|
||||
),
|
||||
case_subjects: ($) => seq(series_of($._expression, ",")),
|
||||
case_clauses: ($) => repeat1($.case_clause),
|
||||
case_clause: ($) =>
|
||||
seq(
|
||||
field("patterns", $.case_clause_patterns),
|
||||
optional(field("guard", $.case_clause_guard)),
|
||||
"->",
|
||||
field("value", $._expression)
|
||||
),
|
||||
// Technically the Gleam parser does support something like this:
|
||||
// 1 | | 5 -> True
|
||||
// However, that will cause an error further into the compiler. That format
|
||||
// is not supported by this function.
|
||||
case_clause_patterns: ($) => seq(series_of($.case_clause_pattern, "|")),
|
||||
// The issue above comes from the fact that the parser equivalent of this
|
||||
// function supports 0 patterns. This function does not.
|
||||
case_clause_pattern: ($) => series_of($._pattern, ","),
|
||||
case_clause_guard: ($) => seq("if", $._case_clause_guard_expression),
|
||||
_case_clause_guard_expression: ($) =>
|
||||
choice(
|
||||
$._case_clause_guard_unit,
|
||||
alias($._case_clause_guard_binary_expression, $.binary_expression)
|
||||
),
|
||||
_case_clause_guard_binary_expression: ($) =>
|
||||
choice(
|
||||
binaryExpr(prec.left, 1, "||", $._case_clause_guard_expression),
|
||||
binaryExpr(prec.left, 2, "&&", $._case_clause_guard_expression),
|
||||
binaryExpr(prec.left, 3, "==", $._case_clause_guard_expression),
|
||||
binaryExpr(prec.left, 3, "!=", $._case_clause_guard_expression),
|
||||
binaryExpr(prec.left, 4, "<", $._case_clause_guard_expression),
|
||||
binaryExpr(prec.left, 4, "<=", $._case_clause_guard_expression),
|
||||
binaryExpr(prec.left, 4, "<.", $._case_clause_guard_expression),
|
||||
binaryExpr(prec.left, 4, "<=.", $._case_clause_guard_expression),
|
||||
binaryExpr(prec.left, 4, ">", $._case_clause_guard_expression),
|
||||
binaryExpr(prec.left, 4, ">=", $._case_clause_guard_expression),
|
||||
binaryExpr(prec.left, 4, ">.", $._case_clause_guard_expression),
|
||||
binaryExpr(prec.left, 4, ">=.", $._case_clause_guard_expression)
|
||||
),
|
||||
_case_clause_guard_unit: ($) =>
|
||||
choice(
|
||||
$.identifier,
|
||||
prec(1, alias($._case_clause_tuple_access, $.tuple_access)),
|
||||
seq("{", $._case_clause_guard_expression, "}"),
|
||||
$._constant_value
|
||||
),
|
||||
_case_clause_tuple_access: ($) =>
|
||||
seq(field("tuple", $.identifier), ".", field("index", $.integer)),
|
||||
let: ($) => seq("let", $._assignment),
|
||||
assert: ($) => seq("assert", $._assignment),
|
||||
_assignment: ($) =>
|
||||
seq(
|
||||
field("pattern", $._pattern),
|
||||
optional($._type_annotation),
|
||||
"=",
|
||||
field("value", $._expression)
|
||||
),
|
||||
record_update: ($) =>
|
||||
seq(
|
||||
field(
|
||||
"constructor",
|
||||
choice($.type_identifier, $.remote_type_identifier)
|
||||
),
|
||||
"(",
|
||||
"..",
|
||||
field("spread", $._expression),
|
||||
",",
|
||||
field("arguments", $.record_update_arguments),
|
||||
")"
|
||||
),
|
||||
record_update_arguments: ($) => series_of($.record_update_argument, ","),
|
||||
record_update_argument: ($) =>
|
||||
seq(field("label", $.label), ":", field("value", $._expression)),
|
||||
// As with other AST nodes in this section, `_maybe_record_expression`,
|
||||
// `_maybe_tuple_expression`, and `_maybe_function_expresssion` have no
|
||||
// corollaries in the Gleam parser. These anonymous AST node denote any
|
||||
// expression whose return type could be a record, tuple, or function,
|
||||
// respectively.
|
||||
//
|
||||
// `let` and `assert` are exempted because in order to parse correctly,
|
||||
// they would have to be wrapped in an expression group anyways.
|
||||
_maybe_tuple_expression: ($) =>
|
||||
choice(
|
||||
$.identifier,
|
||||
$.function_call,
|
||||
$.tuple,
|
||||
$.expression_group,
|
||||
$.case,
|
||||
$.field_access,
|
||||
$.tuple_access
|
||||
),
|
||||
tuple_access: ($) =>
|
||||
prec.left(
|
||||
seq(
|
||||
field("tuple", $._maybe_tuple_expression),
|
||||
".",
|
||||
field("index", $.integer)
|
||||
)
|
||||
),
|
||||
_maybe_record_expression: ($) =>
|
||||
choice(
|
||||
$.record,
|
||||
$.identifier,
|
||||
$.function_call,
|
||||
$.expression_group,
|
||||
$.case,
|
||||
$.record_update,
|
||||
$.field_access,
|
||||
$.tuple_access
|
||||
),
|
||||
field_access: ($) =>
|
||||
prec.left(
|
||||
seq(
|
||||
field("record", $._maybe_record_expression),
|
||||
".",
|
||||
field("field", $.label)
|
||||
)
|
||||
),
|
||||
// Remote functions (e.g. int.to_string) is parsed as a field access
|
||||
// (accessing field to_string on record int) as it is impossible for the
|
||||
// parser to determine with int is a module (and thus to_string a member
|
||||
// function) or a local variable containing a record (and thus to_string is
|
||||
// a field of that record).
|
||||
// Similarly, the function name in local function calls (e.g. foo(arg)) is
|
||||
// parsed as an $.identifier which is used to refer to both local variables
|
||||
// and module functions, embodying the same ambiguity.
|
||||
_maybe_function_expression: ($) =>
|
||||
choice(
|
||||
$.identifier,
|
||||
$.anonymous_function,
|
||||
$.expression_group,
|
||||
$.case,
|
||||
$.tuple_access,
|
||||
$.field_access,
|
||||
$.function_call
|
||||
),
|
||||
// Interestingly, the code that parses function arguments also parses
|
||||
// record arguments, hence the ambiguous name.
|
||||
arguments: ($) => seq("(", optional(series_of($.argument, ",")), ")"),
|
||||
argument: ($) =>
|
||||
seq(
|
||||
optional(seq(field("label", $.label), ":")),
|
||||
field("value", choice($.hole, $._expression))
|
||||
),
|
||||
hole: ($) => $._discard_name,
|
||||
function_call: ($) =>
|
||||
seq(
|
||||
field("function", $._maybe_function_expression),
|
||||
field("arguments", $.arguments)
|
||||
),
|
||||
_pattern: ($) =>
|
||||
seq(
|
||||
choice(
|
||||
$.identifier,
|
||||
$.discard,
|
||||
$.record_pattern,
|
||||
$.string,
|
||||
$.integer,
|
||||
$.float,
|
||||
$.tuple_pattern,
|
||||
alias($._pattern_bit_string, $.bit_string_pattern),
|
||||
$.list_pattern
|
||||
),
|
||||
optional(field("assign", seq("as", $.identifier)))
|
||||
),
|
||||
record_pattern: ($) =>
|
||||
seq(
|
||||
field("name", choice($.type_identifier, $.remote_type_identifier)),
|
||||
optional(field("arguments", $.record_pattern_arguments))
|
||||
),
|
||||
record_pattern_arguments: ($) =>
|
||||
seq(
|
||||
"(",
|
||||
optional(series_of($.record_pattern_argument, ",")),
|
||||
optional($.pattern_spread),
|
||||
")"
|
||||
),
|
||||
record_pattern_argument: ($) =>
|
||||
seq(
|
||||
optional(seq(field("label", $.label), ":")),
|
||||
field("pattern", $._pattern)
|
||||
),
|
||||
pattern_spread: ($) => seq("..", optional(",")),
|
||||
tuple_pattern: ($) =>
|
||||
seq("#", "(", optional(series_of($._pattern, ",")), ")"),
|
||||
// The Gleam parser has a special catch for nested bitstrings here, which
|
||||
// is interesting as the same error does not exist on constants. Anyhow, I
|
||||
// wasn't really sure how to implement that easily here, and so didn't.
|
||||
...bit_string_rules(
|
||||
"pattern",
|
||||
"_pattern",
|
||||
"_pattern_bit_string_segment_argument"
|
||||
),
|
||||
_pattern_bit_string_segment_argument: ($) =>
|
||||
choice($.identifier, $.integer),
|
||||
list_pattern: ($) =>
|
||||
seq(
|
||||
"[",
|
||||
optional(series_of($._pattern, ",")),
|
||||
optional($.list_pattern_tail),
|
||||
"]"
|
||||
),
|
||||
list_pattern_tail: ($) =>
|
||||
seq("..", optional(choice($.identifier, $.discard))),
|
||||
|
||||
visibility_modifier: ($) => "pub",
|
||||
opacity_modifier: ($) => "opaque",
|
||||
|
||||
/* Custom type definitions */
|
||||
type_definition: ($) =>
|
||||
seq(
|
||||
optional($.visibility_modifier),
|
||||
optional($.opacity_modifier),
|
||||
"type",
|
||||
$.type_name,
|
||||
"{",
|
||||
$.data_constructors,
|
||||
"}"
|
||||
),
|
||||
data_constructors: ($) => repeat1($.data_constructor),
|
||||
data_constructor: ($) =>
|
||||
seq(
|
||||
field("name", $.type_identifier),
|
||||
optional(field("arguments", $.data_constructor_arguments))
|
||||
),
|
||||
data_constructor_arguments: ($) =>
|
||||
seq("(", optional(series_of($.data_constructor_argument, ",")), ")"),
|
||||
data_constructor_argument: ($) =>
|
||||
seq(optional(seq(field("label", $.label), ":")), field("value", $._type)),
|
||||
|
||||
/* Type aliases */
|
||||
type_alias: ($) =>
|
||||
seq(
|
||||
optional($.visibility_modifier),
|
||||
optional($.opacity_modifier),
|
||||
"type",
|
||||
$.type_name,
|
||||
"=",
|
||||
$._type
|
||||
),
|
||||
|
||||
/* Literals */
|
||||
string: ($) => seq('"', repeat($._string_part), '"'),
|
||||
_string_part: ($) => choice($.escape_sequence, $.quoted_content),
|
||||
escape_sequence: ($) => /\\[efnrt\"\\]/,
|
||||
quoted_content: ($) => /(?:[^\\\"]|\\[^efnrt\"\\])+/,
|
||||
float: ($) => /-?[0-9_]+\.[0-9_]+/,
|
||||
integer: ($) =>
|
||||
seq(optional("-"), choice($._hex, $._decimal, $._octal, $._binary)),
|
||||
_hex: ($) => /0[xX][0-9a-fA-F_]+/,
|
||||
_decimal: ($) => /[0-9][0-9_]*/,
|
||||
_octal: ($) => /0[oO][0-7_]+/,
|
||||
_binary: ($) => /0[bB][0-1_]+/,
|
||||
_bit_string_segment_option: ($) =>
|
||||
choice(
|
||||
"binary",
|
||||
"bytes",
|
||||
"int",
|
||||
"float",
|
||||
"bit_string",
|
||||
"bits",
|
||||
"utf8",
|
||||
"utf16",
|
||||
"utf32",
|
||||
"utf8_codepoint",
|
||||
"utf16_codepoint",
|
||||
"utf32_codepoint",
|
||||
"signed",
|
||||
"unsigned",
|
||||
"big",
|
||||
"little",
|
||||
"native",
|
||||
seq("unit", "(", $.integer, ")")
|
||||
),
|
||||
|
||||
/* Types */
|
||||
_type: ($) =>
|
||||
choice($.type_hole, $.tuple_type, $.function_type, $.type, $.type_var),
|
||||
_type_annotation: ($) => seq(":", field("type", $._type)),
|
||||
type_hole: ($) => $._discard_name,
|
||||
// If you're wondering why there isn't a `list_type` here, the answer is
|
||||
// that the "type" form for lists is `List`, which is identical to
|
||||
// user-defined types etc and thus is not parsed specially.
|
||||
tuple_type: ($) => seq("#", "(", optional(series_of($._type, ",")), ")"),
|
||||
function_type: ($) =>
|
||||
seq(
|
||||
"fn",
|
||||
optional(field("parameter_types", $.function_parameter_types)),
|
||||
"->",
|
||||
field("return_type", $._type)
|
||||
),
|
||||
function_parameter_types: ($) =>
|
||||
seq("(", optional(series_of($._type, ",")), ")"),
|
||||
// "type" is a somewhat ambiguous name, but it refers to a concrete type
|
||||
// such as `Bool` or `List(Int)` or even `result.Result(#(Int, Int), Nil)`.
|
||||
type: ($) =>
|
||||
seq(
|
||||
field("name", choice($.type_identifier, $.remote_type_identifier)),
|
||||
optional(field("arguments", $.type_arguments))
|
||||
),
|
||||
type_arguments: ($) =>
|
||||
seq("(", optional(series_of($.type_argument, ",")), ")"),
|
||||
type_argument: ($) => $._type,
|
||||
type_var: ($) => $._name,
|
||||
|
||||
// "type_name" essentially refers to the declaration of a type. The type
|
||||
// parameters are part of the "name." Bit odd, but 🤷
|
||||
// e.g. MyType(a, b)
|
||||
type_name: ($) =>
|
||||
seq(
|
||||
field("name", choice($.type_identifier, $.remote_type_identifier)),
|
||||
optional(field("parameters", $.type_parameters))
|
||||
),
|
||||
type_parameters: ($) =>
|
||||
seq("(", optional(series_of($.type_parameter, ",")), ")"),
|
||||
type_parameter: ($) => $._name,
|
||||
|
||||
/* Shared AST nodes */
|
||||
identifier: ($) => $._name,
|
||||
label: ($) => $._name,
|
||||
discard: ($) => $._discard_name,
|
||||
type_identifier: ($) => $._upname,
|
||||
remote_type_identifier: ($) =>
|
||||
seq(field("module", $.identifier), ".", field("name", $.type_identifier)),
|
||||
|
||||
/* Reused types from the Gleam lexer */
|
||||
_discard_name: ($) => /_[_0-9a-z]*/,
|
||||
_name: ($) => /[_a-z][_0-9a-z]*/,
|
||||
_upname: ($) => /[A-Z][0-9a-zA-Z]*/,
|
||||
},
|
||||
});
|
||||
|
||||
// This function and the following function are vaguely congruent with the
|
||||
// `parse_bit_string_segment` function of the Gleam parser.
|
||||
function bit_string_rules(name, value_parser, arg_parser) {
|
||||
return {
|
||||
[`_${name}_bit_string`]: ($) =>
|
||||
seq(
|
||||
"<<",
|
||||
optional(
|
||||
series_of(
|
||||
alias($[`${name}_bit_string_segment`], $.bit_string_segment),
|
||||
","
|
||||
)
|
||||
),
|
||||
">>"
|
||||
),
|
||||
[`${name}_bit_string_segment`]: ($) =>
|
||||
seq(
|
||||
field("value", $[value_parser]),
|
||||
optional(
|
||||
field(
|
||||
"options",
|
||||
seq(
|
||||
":",
|
||||
alias(
|
||||
$[`${name}_bit_string_segment_options`],
|
||||
$.bit_string_segment_options
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
...bit_string_segment_options(name, arg_parser),
|
||||
};
|
||||
}
|
||||
|
||||
function bit_string_segment_options(name, arg_parser) {
|
||||
return {
|
||||
[`${name}_bit_string_segment_options`]: ($) =>
|
||||
series_of($[`_${name}_bit_string_segment_option`], "-"),
|
||||
[`_${name}_bit_string_segment_option`]: ($) =>
|
||||
choice($[`_${name}_bit_string_named_segment_option`], $.integer),
|
||||
[`_${name}_bit_string_named_segment_option`]: ($) =>
|
||||
alias(
|
||||
choice(
|
||||
$._bit_string_segment_option,
|
||||
$[`_${name}_bit_string_segment_option_size`]
|
||||
),
|
||||
$.bit_string_segment_option
|
||||
),
|
||||
[`_${name}_bit_string_segment_option_size`]: ($) =>
|
||||
seq("size", "(", $[arg_parser], ")"),
|
||||
};
|
||||
}
|
||||
|
||||
// Shamelessly stolen "sep1" from tree-sitter-elixir, renamed to match a similar
|
||||
// function in the Gleam parser.
|
||||
// https://github.com/elixir-lang/tree-sitter-elixir/blob/de3ec57591aebf451e710fc9c984cf601258baf5/grammar.js#L817-L819
|
||||
function series_of(rule, separator) {
|
||||
return seq(rule, repeat(seq(separator, rule)), optional(separator));
|
||||
}
|
||||
|
||||
// A binary expression with a left-hand side, infix operator, and then right-hand-side
|
||||
// https://github.com/elixir-lang/tree-sitter-elixir/blob/de20391afe5cb03ef1e8a8e43167e7b58cc52869/grammar.js#L850-L859
|
||||
function binaryExpr(assoc, precedence, operator, expr) {
|
||||
return assoc(
|
||||
precedence,
|
||||
seq(field("left", expr), field("operator", operator), field("right", expr))
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
{
|
||||
"name": "tree-sitter-gleam",
|
||||
"version": "0.20.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "tree-sitter-gleam",
|
||||
"version": "0.20.1",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"nan": "^2.15.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^2.5.1",
|
||||
"tree-sitter-cli": "^0.20.6"
|
||||
}
|
||||
},
|
||||
"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/prettier": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
|
||||
"integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"prettier": "bin-prettier.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tree-sitter-cli": {
|
||||
"version": "0.20.6",
|
||||
"resolved": "https://registry.npmjs.org/tree-sitter-cli/-/tree-sitter-cli-0.20.6.tgz",
|
||||
"integrity": "sha512-tjbAeuGSMhco/EnsThjWkQbDIYMDmdkWsTPsa/NJAW7bjaki9P7oM9TkLxfdlnm4LXd1wR5wVSM2/RTLtZbm6A==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"tree-sitter": "cli.js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"nan": {
|
||||
"version": "2.15.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz",
|
||||
"integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ=="
|
||||
},
|
||||
"prettier": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
|
||||
"integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
|
||||
"dev": true
|
||||
},
|
||||
"tree-sitter-cli": {
|
||||
"version": "0.20.6",
|
||||
"resolved": "https://registry.npmjs.org/tree-sitter-cli/-/tree-sitter-cli-0.20.6.tgz",
|
||||
"integrity": "sha512-tjbAeuGSMhco/EnsThjWkQbDIYMDmdkWsTPsa/NJAW7bjaki9P7oM9TkLxfdlnm4LXd1wR5wVSM2/RTLtZbm6A==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "tree-sitter-gleam",
|
||||
"version": "0.20.1",
|
||||
"description": "A tree-sitter grammar for the Gleam programming language",
|
||||
"main": "bindings/node",
|
||||
"scripts": {
|
||||
"generate": "tree-sitter generate",
|
||||
"test": "tree-sitter test",
|
||||
"format": "prettier --write grammar.js",
|
||||
"check-formatted": "prettier --check grammar.js",
|
||||
"build-wasm": "tree-sitter build-wasm"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+ssh://git@github.com/J3RN/tree-sitter-gleam.git"
|
||||
},
|
||||
"keywords": [
|
||||
"gleam",
|
||||
"parser",
|
||||
"lexer",
|
||||
"tree-sitter"
|
||||
],
|
||||
"author": "Jonathan Arnett",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/J3RN/tree-sitter-gleam/issues"
|
||||
},
|
||||
"homepage": "https://github.com/J3RN/tree-sitter-gleam#readme",
|
||||
"dependencies": {
|
||||
"nan": "^2.15.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^2.5.1",
|
||||
"tree-sitter-cli": "^0.20.6"
|
||||
},
|
||||
"tree-sitter": [
|
||||
{
|
||||
"scope": "source.gleam",
|
||||
"file-types": [
|
||||
"gleam"
|
||||
],
|
||||
"injection-regex": "^gleam$"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,101 @@
|
||||
; Comments
|
||||
(module_comment) @comment
|
||||
(statement_comment) @comment
|
||||
(comment) @comment
|
||||
|
||||
; Constants
|
||||
(constant
|
||||
name: (identifier) @constant)
|
||||
|
||||
; Modules
|
||||
(module) @module
|
||||
(import alias: (identifier) @module)
|
||||
(remote_type_identifier
|
||||
module: (identifier) @module)
|
||||
((field_access
|
||||
record: (identifier) @module
|
||||
field: (label) @function)
|
||||
(#is-not? local))
|
||||
|
||||
; Functions
|
||||
(unqualified_import (identifier) @function)
|
||||
(function
|
||||
name: (identifier) @function)
|
||||
(external_function
|
||||
name: (identifier) @function)
|
||||
(function_parameter
|
||||
name: (identifier) @variable.parameter)
|
||||
((function_call
|
||||
function: (identifier) @function)
|
||||
(#is-not? local))
|
||||
((binary_expression
|
||||
operator: "|>"
|
||||
right: (identifier) @function)
|
||||
(#is-not? local))
|
||||
|
||||
; "Properties"
|
||||
; Assumed to be intended to refer to a name for a field; something that comes
|
||||
; before ":" or after "."
|
||||
; e.g. record field names, tuple indices, names for named arguments, etc
|
||||
(label) @property
|
||||
(tuple_access
|
||||
index: (integer) @property)
|
||||
|
||||
; Type names
|
||||
(remote_type_identifier) @type
|
||||
(type_identifier) @type
|
||||
|
||||
; Literals
|
||||
(string) @string
|
||||
(bit_string_segment_option) @function.builtin
|
||||
(integer) @number
|
||||
(float) @number
|
||||
|
||||
; Variables
|
||||
(identifier) @variable
|
||||
(discard) @comment.unused
|
||||
|
||||
; Operators
|
||||
(binary_expression
|
||||
operator: _ @operator)
|
||||
|
||||
; Keywords
|
||||
[
|
||||
(visibility_modifier) ; "pub"
|
||||
(opacity_modifier) ; "opaque"
|
||||
"as"
|
||||
"assert"
|
||||
"case"
|
||||
"const"
|
||||
"external"
|
||||
"fn"
|
||||
"if"
|
||||
"import"
|
||||
"let"
|
||||
"todo"
|
||||
"try"
|
||||
"type"
|
||||
] @keyword
|
||||
|
||||
; Punctuation
|
||||
[
|
||||
"("
|
||||
")"
|
||||
"["
|
||||
"]"
|
||||
"{"
|
||||
"}"
|
||||
"<<"
|
||||
">>"
|
||||
] @punctuation.bracket
|
||||
[
|
||||
"."
|
||||
","
|
||||
;; Controversial -- maybe some are operators?
|
||||
":"
|
||||
"#"
|
||||
"="
|
||||
"->"
|
||||
".."
|
||||
"-"
|
||||
] @punctuation.delimiter
|
||||
@ -0,0 +1,15 @@
|
||||
; Scopes
|
||||
(function_body) @local.scope
|
||||
|
||||
(case_clause) @local.scope
|
||||
|
||||
; Definitions
|
||||
(let pattern: (identifier) @local.definition)
|
||||
(function_parameter name: (identifier) @local.definition)
|
||||
(list_pattern (identifier) @local.definition)
|
||||
(list_pattern assign: (identifier) @local.definition)
|
||||
(tuple_pattern (identifier) @local.definition)
|
||||
(record_pattern_argument pattern: (identifier) @local.definition)
|
||||
|
||||
; References
|
||||
(identifier) @local.reference
|
||||
@ -0,0 +1,40 @@
|
||||
; Modules
|
||||
(module) @name @reference.module
|
||||
(import alias: (identifier) @name) @reference.module
|
||||
(remote_type_identifier
|
||||
module: (identifier) @name) @reference.module
|
||||
((field_access
|
||||
record: (identifier) @name)
|
||||
(#is-not? local)) @reference.module
|
||||
|
||||
; Functions
|
||||
(function
|
||||
name: (identifier) @name) @definition.function
|
||||
(external_function
|
||||
name: (identifier) @name) @definition.function
|
||||
(unqualified_import (identifier) @name) @reference.function
|
||||
((function_call
|
||||
function: (identifier) @name) @reference.function
|
||||
(#is-not? local))
|
||||
((field_access
|
||||
record: (identifier) @ignore
|
||||
field: (label) @name)
|
||||
(#is-not? local)) @reference.function
|
||||
((binary_expression
|
||||
operator: "|>"
|
||||
right: (identifier) @name)
|
||||
(#is-not? local)) @reference.function
|
||||
|
||||
; Types
|
||||
(type_definition
|
||||
(type_name
|
||||
name: (type_identifier) @name)) @definition.type
|
||||
(type_definition
|
||||
(data_constructors
|
||||
(data_constructor
|
||||
name: (type_identifier) @name))) @definition.type
|
||||
(external_type
|
||||
(type_name
|
||||
name: (type_identifier) @name)) @definition.type
|
||||
|
||||
(type_identifier) @name @reference.type
|
||||
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
@ -0,0 +1,224 @@
|
||||
#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_
|
||||
@ -0,0 +1,382 @@
|
||||
================================================================================
|
||||
Constants
|
||||
================================================================================
|
||||
|
||||
const a = "hello"
|
||||
const a = "hello\nworld\!"
|
||||
const a = 1_234
|
||||
const a = 0b110
|
||||
const a = 0o7224
|
||||
const a = 0xBEef
|
||||
const a: Int = 1234
|
||||
const a: Float = -1_234.53__23
|
||||
const a: #(Int, String) = #(1, "Hello!")
|
||||
const a: #() = #()
|
||||
const a: List(Int) = [1, 2]
|
||||
const a: List(_) = []
|
||||
const a = <<3>>
|
||||
const a = <<0:4, 1:3, 1:1>>
|
||||
const a = <<3:size(8)>>
|
||||
const a = <<52:size(4)-unit(4)>>
|
||||
const a = <<"Hello Gleam 💫":utf8>>
|
||||
const a = Node
|
||||
const a = Node()
|
||||
const a = Cat("Ginny", 1950)
|
||||
const a = Person(name: "Billy", age: 52)
|
||||
const a = uri.Uri(host: "github.com")
|
||||
const a: option.Option(String) = option.Some("Hello, World!")
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(source_file
|
||||
(constant
|
||||
name: (identifier)
|
||||
value: (string
|
||||
(quoted_content)))
|
||||
(constant
|
||||
name: (identifier)
|
||||
value: (string
|
||||
(quoted_content)
|
||||
(escape_sequence)
|
||||
(quoted_content)))
|
||||
(constant
|
||||
name: (identifier)
|
||||
value: (integer))
|
||||
(constant
|
||||
name: (identifier)
|
||||
value: (integer))
|
||||
(constant
|
||||
name: (identifier)
|
||||
value: (integer))
|
||||
(constant
|
||||
name: (identifier)
|
||||
value: (integer))
|
||||
(constant
|
||||
name: (identifier)
|
||||
type: (type
|
||||
name: (type_identifier))
|
||||
value: (integer))
|
||||
(constant
|
||||
name: (identifier)
|
||||
type: (type
|
||||
name: (type_identifier))
|
||||
value: (float))
|
||||
(constant
|
||||
name: (identifier)
|
||||
type: (tuple_type
|
||||
(type
|
||||
name: (type_identifier))
|
||||
(type
|
||||
name: (type_identifier)))
|
||||
value: (tuple
|
||||
(integer)
|
||||
(string
|
||||
(quoted_content))))
|
||||
(constant
|
||||
name: (identifier)
|
||||
type: (tuple_type)
|
||||
value: (tuple))
|
||||
(constant
|
||||
name: (identifier)
|
||||
type: (type
|
||||
name: (type_identifier)
|
||||
arguments: (type_arguments
|
||||
(type_argument
|
||||
(type
|
||||
name: (type_identifier)))))
|
||||
value: (list
|
||||
(integer)
|
||||
(integer)))
|
||||
(constant
|
||||
name: (identifier)
|
||||
type: (type
|
||||
name: (type_identifier)
|
||||
arguments: (type_arguments
|
||||
(type_argument
|
||||
(type_hole))))
|
||||
value: (list))
|
||||
(constant
|
||||
name: (identifier)
|
||||
value: (bit_string
|
||||
(bit_string_segment
|
||||
value: (integer))))
|
||||
(constant
|
||||
name: (identifier)
|
||||
value: (bit_string
|
||||
(bit_string_segment
|
||||
value: (integer)
|
||||
options: (bit_string_segment_options
|
||||
(integer)))
|
||||
(bit_string_segment
|
||||
value: (integer)
|
||||
options: (bit_string_segment_options
|
||||
(integer)))
|
||||
(bit_string_segment
|
||||
value: (integer)
|
||||
options: (bit_string_segment_options
|
||||
(integer)))))
|
||||
(constant
|
||||
name: (identifier)
|
||||
value: (bit_string
|
||||
(bit_string_segment
|
||||
value: (integer)
|
||||
options: (bit_string_segment_options
|
||||
(bit_string_segment_option
|
||||
(integer))))))
|
||||
(constant
|
||||
name: (identifier)
|
||||
value: (bit_string
|
||||
(bit_string_segment
|
||||
value: (integer)
|
||||
options: (bit_string_segment_options
|
||||
(bit_string_segment_option
|
||||
(integer))
|
||||
(bit_string_segment_option
|
||||
(integer))))))
|
||||
(constant
|
||||
name: (identifier)
|
||||
value: (bit_string
|
||||
(bit_string_segment
|
||||
value: (string
|
||||
(quoted_content))
|
||||
options: (bit_string_segment_options
|
||||
(bit_string_segment_option)))))
|
||||
(constant
|
||||
name: (identifier)
|
||||
value: (record
|
||||
name: (type_identifier)))
|
||||
(constant
|
||||
name: (identifier)
|
||||
value: (record
|
||||
name: (type_identifier)
|
||||
arguments: (arguments)))
|
||||
(constant
|
||||
name: (identifier)
|
||||
value: (record
|
||||
name: (type_identifier)
|
||||
arguments: (arguments
|
||||
(argument
|
||||
value: (string
|
||||
(quoted_content)))
|
||||
(argument
|
||||
value: (integer)))))
|
||||
(constant
|
||||
name: (identifier)
|
||||
value: (record
|
||||
name: (type_identifier)
|
||||
arguments: (arguments
|
||||
(argument
|
||||
label: (label)
|
||||
value: (string
|
||||
(quoted_content)))
|
||||
(argument
|
||||
label: (label)
|
||||
value: (integer)))))
|
||||
(constant
|
||||
name: (identifier)
|
||||
value: (record
|
||||
name: (remote_type_identifier
|
||||
module: (identifier)
|
||||
name: (type_identifier))
|
||||
arguments: (arguments
|
||||
(argument
|
||||
label: (label)
|
||||
value: (string
|
||||
(quoted_content))))))
|
||||
(constant
|
||||
name: (identifier)
|
||||
type: (type
|
||||
name: (remote_type_identifier
|
||||
module: (identifier)
|
||||
name: (type_identifier))
|
||||
arguments: (type_arguments
|
||||
(type_argument
|
||||
(type
|
||||
name: (type_identifier)))))
|
||||
value: (record
|
||||
name: (remote_type_identifier
|
||||
module: (identifier)
|
||||
name: (type_identifier))
|
||||
arguments: (arguments
|
||||
(argument
|
||||
value: (string
|
||||
(quoted_content)))))))
|
||||
|
||||
================================================================================
|
||||
Public constants
|
||||
================================================================================
|
||||
|
||||
pub const a = "hello"
|
||||
pub const a: Int = 1234
|
||||
pub const a: Float = -1_234.53__23
|
||||
pub const a: #(Int, String) = #(1, "Hello!")
|
||||
pub const a: #() = #()
|
||||
pub const a: List(Int) = [1, 2]
|
||||
pub const a: List(_) = []
|
||||
pub const a = <<3>>
|
||||
pub const a = <<0:4, 1:3, 1:1>>
|
||||
pub const a = <<3:size(8)>>
|
||||
pub const a = <<52:size(4)-unit(4)>>
|
||||
pub const a = <<"Hello Gleam 💫":utf8>>
|
||||
pub const a = Node
|
||||
pub const a = Node()
|
||||
pub const a = Cat("Ginny", 1950)
|
||||
pub const a = Person(name: "Billy", age: 52)
|
||||
pub const a = uri.Uri(host: "github.com")
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(source_file
|
||||
(constant
|
||||
(visibility_modifier)
|
||||
name: (identifier)
|
||||
value: (string
|
||||
(quoted_content)))
|
||||
(constant
|
||||
(visibility_modifier)
|
||||
name: (identifier)
|
||||
type: (type
|
||||
name: (type_identifier))
|
||||
value: (integer))
|
||||
(constant
|
||||
(visibility_modifier)
|
||||
name: (identifier)
|
||||
type: (type
|
||||
name: (type_identifier))
|
||||
value: (float))
|
||||
(constant
|
||||
(visibility_modifier)
|
||||
name: (identifier)
|
||||
type: (tuple_type
|
||||
(type
|
||||
name: (type_identifier))
|
||||
(type
|
||||
name: (type_identifier)))
|
||||
value: (tuple
|
||||
(integer)
|
||||
(string
|
||||
(quoted_content))))
|
||||
(constant
|
||||
(visibility_modifier)
|
||||
name: (identifier)
|
||||
type: (tuple_type)
|
||||
value: (tuple))
|
||||
(constant
|
||||
(visibility_modifier)
|
||||
name: (identifier)
|
||||
type: (type
|
||||
name: (type_identifier)
|
||||
arguments: (type_arguments
|
||||
(type_argument
|
||||
(type
|
||||
name: (type_identifier)))))
|
||||
value: (list
|
||||
(integer)
|
||||
(integer)))
|
||||
(constant
|
||||
(visibility_modifier)
|
||||
name: (identifier)
|
||||
type: (type
|
||||
name: (type_identifier)
|
||||
arguments: (type_arguments
|
||||
(type_argument
|
||||
(type_hole))))
|
||||
value: (list))
|
||||
(constant
|
||||
(visibility_modifier)
|
||||
name: (identifier)
|
||||
value: (bit_string
|
||||
(bit_string_segment
|
||||
value: (integer))))
|
||||
(constant
|
||||
(visibility_modifier)
|
||||
name: (identifier)
|
||||
value: (bit_string
|
||||
(bit_string_segment
|
||||
value: (integer)
|
||||
options: (bit_string_segment_options
|
||||
(integer)))
|
||||
(bit_string_segment
|
||||
value: (integer)
|
||||
options: (bit_string_segment_options
|
||||
(integer)))
|
||||
(bit_string_segment
|
||||
value: (integer)
|
||||
options: (bit_string_segment_options
|
||||
(integer)))))
|
||||
(constant
|
||||
(visibility_modifier)
|
||||
name: (identifier)
|
||||
value: (bit_string
|
||||
(bit_string_segment
|
||||
value: (integer)
|
||||
options: (bit_string_segment_options
|
||||
(bit_string_segment_option
|
||||
(integer))))))
|
||||
(constant
|
||||
(visibility_modifier)
|
||||
name: (identifier)
|
||||
value: (bit_string
|
||||
(bit_string_segment
|
||||
value: (integer)
|
||||
options: (bit_string_segment_options
|
||||
(bit_string_segment_option
|
||||
(integer))
|
||||
(bit_string_segment_option
|
||||
(integer))))))
|
||||
(constant
|
||||
(visibility_modifier)
|
||||
name: (identifier)
|
||||
value: (bit_string
|
||||
(bit_string_segment
|
||||
value: (string
|
||||
(quoted_content))
|
||||
options: (bit_string_segment_options
|
||||
(bit_string_segment_option)))))
|
||||
(constant
|
||||
(visibility_modifier)
|
||||
name: (identifier)
|
||||
value: (record
|
||||
name: (type_identifier)))
|
||||
(constant
|
||||
(visibility_modifier)
|
||||
name: (identifier)
|
||||
value: (record
|
||||
name: (type_identifier)
|
||||
arguments: (arguments)))
|
||||
(constant
|
||||
(visibility_modifier)
|
||||
name: (identifier)
|
||||
value: (record
|
||||
name: (type_identifier)
|
||||
arguments: (arguments
|
||||
(argument
|
||||
value: (string
|
||||
(quoted_content)))
|
||||
(argument
|
||||
value: (integer)))))
|
||||
(constant
|
||||
(visibility_modifier)
|
||||
name: (identifier)
|
||||
value: (record
|
||||
name: (type_identifier)
|
||||
arguments: (arguments
|
||||
(argument
|
||||
label: (label)
|
||||
value: (string
|
||||
(quoted_content)))
|
||||
(argument
|
||||
label: (label)
|
||||
value: (integer)))))
|
||||
(constant
|
||||
(visibility_modifier)
|
||||
name: (identifier)
|
||||
value: (record
|
||||
name: (remote_type_identifier
|
||||
module: (identifier)
|
||||
name: (type_identifier))
|
||||
arguments: (arguments
|
||||
(argument
|
||||
label: (label)
|
||||
value: (string
|
||||
(quoted_content)))))))
|
||||
@ -0,0 +1,249 @@
|
||||
================================================================================
|
||||
Parser example custom types
|
||||
================================================================================
|
||||
|
||||
type A { A }
|
||||
type A { A(String) }
|
||||
type Box(inner_type) { Box(inner: inner_type) }
|
||||
type NamedBox(inner_type) { Box(String, inner: inner_type) }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(source_file
|
||||
(type_definition
|
||||
(type_name
|
||||
name: (type_identifier))
|
||||
(data_constructors
|
||||
(data_constructor
|
||||
name: (type_identifier))))
|
||||
(type_definition
|
||||
(type_name
|
||||
name: (type_identifier))
|
||||
(data_constructors
|
||||
(data_constructor
|
||||
name: (type_identifier)
|
||||
arguments: (data_constructor_arguments
|
||||
(data_constructor_argument
|
||||
value: (type
|
||||
name: (type_identifier)))))))
|
||||
(type_definition
|
||||
(type_name
|
||||
name: (type_identifier)
|
||||
parameters: (type_parameters
|
||||
(type_parameter)))
|
||||
(data_constructors
|
||||
(data_constructor
|
||||
name: (type_identifier)
|
||||
arguments: (data_constructor_arguments
|
||||
(data_constructor_argument
|
||||
label: (label)
|
||||
value: (type_var))))))
|
||||
(type_definition
|
||||
(type_name
|
||||
name: (type_identifier)
|
||||
parameters: (type_parameters
|
||||
(type_parameter)))
|
||||
(data_constructors
|
||||
(data_constructor
|
||||
name: (type_identifier)
|
||||
arguments: (data_constructor_arguments
|
||||
(data_constructor_argument
|
||||
value: (type
|
||||
name: (type_identifier)))
|
||||
(data_constructor_argument
|
||||
label: (label)
|
||||
value: (type_var)))))))
|
||||
|
||||
================================================================================
|
||||
Other custom type examples
|
||||
================================================================================
|
||||
|
||||
type Cat {
|
||||
Cat(name: String, cuteness: Int)
|
||||
}
|
||||
|
||||
type Animal() {
|
||||
Cat(name: String, cuteness: Int)
|
||||
Dog(name: String, cuteness: Int)
|
||||
}
|
||||
|
||||
type Result(success_type, failure_type) {
|
||||
Ok(success_type)
|
||||
Error(failure_type)
|
||||
}
|
||||
|
||||
type Ord {
|
||||
LT
|
||||
EQ
|
||||
GT
|
||||
}
|
||||
|
||||
type Boring {
|
||||
Boring
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(source_file
|
||||
(type_definition
|
||||
(type_name
|
||||
name: (type_identifier))
|
||||
(data_constructors
|
||||
(data_constructor
|
||||
name: (type_identifier)
|
||||
arguments: (data_constructor_arguments
|
||||
(data_constructor_argument
|
||||
label: (label)
|
||||
value: (type
|
||||
name: (type_identifier)))
|
||||
(data_constructor_argument
|
||||
label: (label)
|
||||
value: (type
|
||||
name: (type_identifier)))))))
|
||||
(type_definition
|
||||
(type_name
|
||||
name: (type_identifier)
|
||||
parameters: (type_parameters))
|
||||
(data_constructors
|
||||
(data_constructor
|
||||
name: (type_identifier)
|
||||
arguments: (data_constructor_arguments
|
||||
(data_constructor_argument
|
||||
label: (label)
|
||||
value: (type
|
||||
name: (type_identifier)))
|
||||
(data_constructor_argument
|
||||
label: (label)
|
||||
value: (type
|
||||
name: (type_identifier)))))
|
||||
(data_constructor
|
||||
name: (type_identifier)
|
||||
arguments: (data_constructor_arguments
|
||||
(data_constructor_argument
|
||||
label: (label)
|
||||
value: (type
|
||||
name: (type_identifier)))
|
||||
(data_constructor_argument
|
||||
label: (label)
|
||||
value: (type
|
||||
name: (type_identifier)))))))
|
||||
(type_definition
|
||||
(type_name
|
||||
name: (type_identifier)
|
||||
parameters: (type_parameters
|
||||
(type_parameter)
|
||||
(type_parameter)))
|
||||
(data_constructors
|
||||
(data_constructor
|
||||
name: (type_identifier)
|
||||
arguments: (data_constructor_arguments
|
||||
(data_constructor_argument
|
||||
value: (type_var))))
|
||||
(data_constructor
|
||||
name: (type_identifier)
|
||||
arguments: (data_constructor_arguments
|
||||
(data_constructor_argument
|
||||
value: (type_var))))))
|
||||
(type_definition
|
||||
(type_name
|
||||
name: (type_identifier))
|
||||
(data_constructors
|
||||
(data_constructor
|
||||
name: (type_identifier))
|
||||
(data_constructor
|
||||
name: (type_identifier))
|
||||
(data_constructor
|
||||
name: (type_identifier))))
|
||||
(type_definition
|
||||
(type_name
|
||||
name: (type_identifier))
|
||||
(data_constructors
|
||||
(data_constructor
|
||||
name: (type_identifier)))))
|
||||
|
||||
================================================================================
|
||||
Public custom type definitions
|
||||
================================================================================
|
||||
|
||||
pub type Animal(name, cuteness) {
|
||||
Cat(name: String, cuteness: Int)
|
||||
Dog(name: String, cuteness: Int)
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(source_file
|
||||
(type_definition
|
||||
(visibility_modifier)
|
||||
(type_name
|
||||
name: (type_identifier)
|
||||
parameters: (type_parameters
|
||||
(type_parameter)
|
||||
(type_parameter)))
|
||||
(data_constructors
|
||||
(data_constructor
|
||||
name: (type_identifier)
|
||||
arguments: (data_constructor_arguments
|
||||
(data_constructor_argument
|
||||
label: (label)
|
||||
value: (type
|
||||
name: (type_identifier)))
|
||||
(data_constructor_argument
|
||||
label: (label)
|
||||
value: (type
|
||||
name: (type_identifier)))))
|
||||
(data_constructor
|
||||
name: (type_identifier)
|
||||
arguments: (data_constructor_arguments
|
||||
(data_constructor_argument
|
||||
label: (label)
|
||||
value: (type
|
||||
name: (type_identifier)))
|
||||
(data_constructor_argument
|
||||
label: (label)
|
||||
value: (type
|
||||
name: (type_identifier))))))))
|
||||
|
||||
================================================================================
|
||||
Public opaque custom type definitions
|
||||
================================================================================
|
||||
|
||||
pub opaque type Animal(name, cuteness) {
|
||||
Cat(name: String, cuteness: Int)
|
||||
Dog(name: String, cuteness: Int)
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(source_file
|
||||
(type_definition
|
||||
(visibility_modifier)
|
||||
(opacity_modifier)
|
||||
(type_name
|
||||
name: (type_identifier)
|
||||
parameters: (type_parameters
|
||||
(type_parameter)
|
||||
(type_parameter)))
|
||||
(data_constructors
|
||||
(data_constructor
|
||||
name: (type_identifier)
|
||||
arguments: (data_constructor_arguments
|
||||
(data_constructor_argument
|
||||
label: (label)
|
||||
value: (type
|
||||
name: (type_identifier)))
|
||||
(data_constructor_argument
|
||||
label: (label)
|
||||
value: (type
|
||||
name: (type_identifier)))))
|
||||
(data_constructor
|
||||
name: (type_identifier)
|
||||
arguments: (data_constructor_arguments
|
||||
(data_constructor_argument
|
||||
label: (label)
|
||||
value: (type
|
||||
name: (type_identifier)))
|
||||
(data_constructor_argument
|
||||
label: (label)
|
||||
value: (type
|
||||
name: (type_identifier))))))))
|
||||
@ -0,0 +1,50 @@
|
||||
================================================================================
|
||||
Case with spread
|
||||
================================================================================
|
||||
|
||||
pub fn main() {
|
||||
case xs {
|
||||
[[]] -> io.println("one")
|
||||
[[], ..] -> io.println("many")
|
||||
}
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(source_file
|
||||
(function
|
||||
(visibility_modifier)
|
||||
(identifier)
|
||||
(function_parameters)
|
||||
(function_body
|
||||
(case
|
||||
(case_subjects
|
||||
(identifier))
|
||||
(case_clauses
|
||||
(case_clause
|
||||
(case_clause_patterns
|
||||
(case_clause_pattern
|
||||
(list_pattern
|
||||
(list_pattern))))
|
||||
(function_call
|
||||
(field_access
|
||||
(identifier)
|
||||
(label))
|
||||
(arguments
|
||||
(argument
|
||||
(string
|
||||
(quoted_content))))))
|
||||
(case_clause
|
||||
(case_clause_patterns
|
||||
(case_clause_pattern
|
||||
(list_pattern
|
||||
(list_pattern)
|
||||
(list_pattern_tail))))
|
||||
(function_call
|
||||
(field_access
|
||||
(identifier)
|
||||
(label))
|
||||
(arguments
|
||||
(argument
|
||||
(string
|
||||
(quoted_content)))))))))))
|
||||
@ -0,0 +1,22 @@
|
||||
================================================================================
|
||||
Bit-string expression
|
||||
================================================================================
|
||||
|
||||
<<code:int-size(8)-unit(2), reason:utf8>>
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(source_file
|
||||
(bit_string
|
||||
(bit_string_segment
|
||||
(identifier)
|
||||
(bit_string_segment_options
|
||||
(bit_string_segment_option)
|
||||
(bit_string_segment_option
|
||||
(integer))
|
||||
(bit_string_segment_option
|
||||
(integer))))
|
||||
(bit_string_segment
|
||||
(identifier)
|
||||
(bit_string_segment_options
|
||||
(bit_string_segment_option)))))
|
||||
@ -0,0 +1,138 @@
|
||||
================================================================================
|
||||
External functions
|
||||
================================================================================
|
||||
|
||||
external fn read_file(String) -> Result(String, Reason) =
|
||||
"file" "open"
|
||||
external fn a(name: String) -> String = "x" "y"
|
||||
external fn a() -> #(List(Int), fn(Int) -> String) = "x" "y"
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(source_file
|
||||
(external_function
|
||||
name: (identifier)
|
||||
parameters: (function_parameters
|
||||
(function_parameter
|
||||
type: (type
|
||||
name: (type_identifier))))
|
||||
return_type: (type
|
||||
name: (type_identifier)
|
||||
arguments: (type_arguments
|
||||
(type_argument
|
||||
(type
|
||||
name: (type_identifier)))
|
||||
(type_argument
|
||||
(type
|
||||
name: (type_identifier)))))
|
||||
body: (external_function_body
|
||||
(string
|
||||
(quoted_content))
|
||||
(string
|
||||
(quoted_content))))
|
||||
(external_function
|
||||
name: (identifier)
|
||||
parameters: (function_parameters
|
||||
(function_parameter
|
||||
name: (identifier)
|
||||
type: (type
|
||||
name: (type_identifier))))
|
||||
return_type: (type
|
||||
name: (type_identifier))
|
||||
body: (external_function_body
|
||||
(string
|
||||
(quoted_content))
|
||||
(string
|
||||
(quoted_content))))
|
||||
(external_function
|
||||
name: (identifier)
|
||||
parameters: (function_parameters)
|
||||
return_type: (tuple_type
|
||||
(type
|
||||
name: (type_identifier)
|
||||
arguments: (type_arguments
|
||||
(type_argument
|
||||
(type
|
||||
name: (type_identifier)))))
|
||||
(function_type
|
||||
parameter_types: (function_parameter_types
|
||||
(type
|
||||
name: (type_identifier)))
|
||||
return_type: (type
|
||||
name: (type_identifier))))
|
||||
body: (external_function_body
|
||||
(string
|
||||
(quoted_content))
|
||||
(string
|
||||
(quoted_content)))))
|
||||
|
||||
================================================================================
|
||||
Public external functions
|
||||
================================================================================
|
||||
|
||||
pub external fn read_file(String) -> Result(String, Reason) =
|
||||
"file" "open"
|
||||
pub external fn a(name: String) -> String = "x" "y"
|
||||
pub external fn a() -> #(List(Int), fn(Int) -> String) = "x" "y"
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(source_file
|
||||
(external_function
|
||||
(visibility_modifier)
|
||||
name: (identifier)
|
||||
parameters: (function_parameters
|
||||
(function_parameter
|
||||
type: (type
|
||||
name: (type_identifier))))
|
||||
return_type: (type
|
||||
name: (type_identifier)
|
||||
arguments: (type_arguments
|
||||
(type_argument
|
||||
(type
|
||||
name: (type_identifier)))
|
||||
(type_argument
|
||||
(type
|
||||
name: (type_identifier)))))
|
||||
body: (external_function_body
|
||||
(string
|
||||
(quoted_content))
|
||||
(string
|
||||
(quoted_content))))
|
||||
(external_function
|
||||
(visibility_modifier)
|
||||
name: (identifier)
|
||||
parameters: (function_parameters
|
||||
(function_parameter
|
||||
name: (identifier)
|
||||
type: (type
|
||||
name: (type_identifier))))
|
||||
return_type: (type
|
||||
name: (type_identifier))
|
||||
body: (external_function_body
|
||||
(string
|
||||
(quoted_content))
|
||||
(string
|
||||
(quoted_content))))
|
||||
(external_function
|
||||
(visibility_modifier)
|
||||
name: (identifier)
|
||||
parameters: (function_parameters)
|
||||
return_type: (tuple_type
|
||||
(type
|
||||
name: (type_identifier)
|
||||
arguments: (type_arguments
|
||||
(type_argument
|
||||
(type
|
||||
name: (type_identifier)))))
|
||||
(function_type
|
||||
parameter_types: (function_parameter_types
|
||||
(type
|
||||
name: (type_identifier)))
|
||||
return_type: (type
|
||||
name: (type_identifier))))
|
||||
body: (external_function_body
|
||||
(string
|
||||
(quoted_content))
|
||||
(string
|
||||
(quoted_content)))))
|
||||
@ -0,0 +1,52 @@
|
||||
================================================================================
|
||||
External types
|
||||
================================================================================
|
||||
|
||||
external type IODevice
|
||||
external type IODevice()
|
||||
external type Map(key, value)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(source_file
|
||||
(external_type
|
||||
(type_name
|
||||
name: (type_identifier)))
|
||||
(external_type
|
||||
(type_name
|
||||
name: (type_identifier)
|
||||
parameters: (type_parameters)))
|
||||
(external_type
|
||||
(type_name
|
||||
name: (type_identifier)
|
||||
parameters: (type_parameters
|
||||
(type_parameter)
|
||||
(type_parameter)))))
|
||||
|
||||
================================================================================
|
||||
Public external types
|
||||
================================================================================
|
||||
|
||||
pub external type IODevice
|
||||
pub external type IODevice()
|
||||
pub external type Map(key, value)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(source_file
|
||||
(external_type
|
||||
(visibility_modifier)
|
||||
(type_name
|
||||
name: (type_identifier)))
|
||||
(external_type
|
||||
(visibility_modifier)
|
||||
(type_name
|
||||
name: (type_identifier)
|
||||
parameters: (type_parameters)))
|
||||
(external_type
|
||||
(visibility_modifier)
|
||||
(type_name
|
||||
name: (type_identifier)
|
||||
parameters: (type_parameters
|
||||
(type_parameter)
|
||||
(type_parameter)))))
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,88 @@
|
||||
================================================================================
|
||||
Imports
|
||||
================================================================================
|
||||
|
||||
import a
|
||||
import a/b
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(source_file
|
||||
(import
|
||||
module: (module))
|
||||
(import
|
||||
module: (module)))
|
||||
|
||||
================================================================================
|
||||
Unqualified imports
|
||||
================================================================================
|
||||
|
||||
import a.{b}
|
||||
import a/b.{c, d}
|
||||
import a/b.{c as d, e}
|
||||
import a/b.{c, D as E}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(source_file
|
||||
(import
|
||||
module: (module)
|
||||
imports: (unqualified_imports
|
||||
(unqualified_import
|
||||
name: (identifier))))
|
||||
(import
|
||||
module: (module)
|
||||
imports: (unqualified_imports
|
||||
(unqualified_import
|
||||
name: (identifier))
|
||||
(unqualified_import
|
||||
name: (identifier))))
|
||||
(import
|
||||
module: (module)
|
||||
imports: (unqualified_imports
|
||||
(unqualified_import
|
||||
name: (identifier)
|
||||
alias: (identifier))
|
||||
(unqualified_import
|
||||
name: (identifier))))
|
||||
(import
|
||||
module: (module)
|
||||
imports: (unqualified_imports
|
||||
(unqualified_import
|
||||
name: (identifier))
|
||||
(unqualified_import
|
||||
name: (type_identifier)
|
||||
alias: (type_identifier)))))
|
||||
|
||||
================================================================================
|
||||
Aliased imports
|
||||
================================================================================
|
||||
|
||||
import a/b.{c as d} as e
|
||||
import animal/cat as kitty
|
||||
import animal.{Cat as Kitty} as a
|
||||
import animal.{}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(source_file
|
||||
(import
|
||||
module: (module)
|
||||
imports: (unqualified_imports
|
||||
(unqualified_import
|
||||
name: (identifier)
|
||||
alias: (identifier)))
|
||||
alias: (identifier))
|
||||
(import
|
||||
module: (module)
|
||||
alias: (identifier))
|
||||
(import
|
||||
module: (module)
|
||||
imports: (unqualified_imports
|
||||
(unqualified_import
|
||||
name: (type_identifier)
|
||||
alias: (type_identifier)))
|
||||
alias: (identifier))
|
||||
(import
|
||||
module: (module)
|
||||
imports: (unqualified_imports)))
|
||||
@ -0,0 +1,48 @@
|
||||
==============
|
||||
Target groups
|
||||
==============
|
||||
|
||||
if erlang {
|
||||
const a = 1
|
||||
}
|
||||
|
||||
if javascript {
|
||||
const a = 1
|
||||
const b = "Hello"
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
(source_file
|
||||
(target_group
|
||||
target: (target)
|
||||
(constant
|
||||
name: (identifier)
|
||||
value: (integer)))
|
||||
(target_group
|
||||
target: (target)
|
||||
(constant
|
||||
name: (identifier)
|
||||
value: (integer))
|
||||
(constant
|
||||
name: (identifier)
|
||||
value: (string
|
||||
(quoted_content)))))
|
||||
|
||||
========================
|
||||
Target group edge cases
|
||||
========================
|
||||
|
||||
if erlang {}
|
||||
if javascript {const a = 1}
|
||||
|
||||
---
|
||||
|
||||
(source_file
|
||||
(target_group
|
||||
target: (target))
|
||||
(target_group
|
||||
target: (target)
|
||||
(constant
|
||||
name: (identifier)
|
||||
value: (integer))))
|
||||
@ -0,0 +1,131 @@
|
||||
================================================================================
|
||||
Type aliases
|
||||
================================================================================
|
||||
|
||||
type Headers =
|
||||
List(#(String, String))
|
||||
type Box(a) = #(a)
|
||||
type NamedBox(a) = #(String, a)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(source_file
|
||||
(type_alias
|
||||
(type_name
|
||||
name: (type_identifier))
|
||||
(type
|
||||
name: (type_identifier)
|
||||
arguments: (type_arguments
|
||||
(type_argument
|
||||
(tuple_type
|
||||
(type
|
||||
name: (type_identifier))
|
||||
(type
|
||||
name: (type_identifier)))))))
|
||||
(type_alias
|
||||
(type_name
|
||||
name: (type_identifier)
|
||||
parameters: (type_parameters
|
||||
(type_parameter)))
|
||||
(tuple_type
|
||||
(type_var)))
|
||||
(type_alias
|
||||
(type_name
|
||||
name: (type_identifier)
|
||||
parameters: (type_parameters
|
||||
(type_parameter)))
|
||||
(tuple_type
|
||||
(type
|
||||
name: (type_identifier))
|
||||
(type_var))))
|
||||
|
||||
================================================================================
|
||||
Public type aliases
|
||||
================================================================================
|
||||
|
||||
pub type Headers =
|
||||
List(#(String, String))
|
||||
pub type Box(a) = #(a)
|
||||
pub type NamedBox(a) = #(String, a)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(source_file
|
||||
(type_alias
|
||||
(visibility_modifier)
|
||||
(type_name
|
||||
name: (type_identifier))
|
||||
(type
|
||||
name: (type_identifier)
|
||||
arguments: (type_arguments
|
||||
(type_argument
|
||||
(tuple_type
|
||||
(type
|
||||
name: (type_identifier))
|
||||
(type
|
||||
name: (type_identifier)))))))
|
||||
(type_alias
|
||||
(visibility_modifier)
|
||||
(type_name
|
||||
name: (type_identifier)
|
||||
parameters: (type_parameters
|
||||
(type_parameter)))
|
||||
(tuple_type
|
||||
(type_var)))
|
||||
(type_alias
|
||||
(visibility_modifier)
|
||||
(type_name
|
||||
name: (type_identifier)
|
||||
parameters: (type_parameters
|
||||
(type_parameter)))
|
||||
(tuple_type
|
||||
(type
|
||||
name: (type_identifier))
|
||||
(type_var))))
|
||||
|
||||
================================================================================
|
||||
Public opaque type aliases
|
||||
================================================================================
|
||||
|
||||
pub opaque type Headers =
|
||||
List(#(String, String))
|
||||
pub opaque type Box(a) = #(a)
|
||||
pub opaque type NamedBox(a) = #(String, a)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(source_file
|
||||
(type_alias
|
||||
(visibility_modifier)
|
||||
(opacity_modifier)
|
||||
(type_name
|
||||
name: (type_identifier))
|
||||
(type
|
||||
name: (type_identifier)
|
||||
arguments: (type_arguments
|
||||
(type_argument
|
||||
(tuple_type
|
||||
(type
|
||||
name: (type_identifier))
|
||||
(type
|
||||
name: (type_identifier)))))))
|
||||
(type_alias
|
||||
(visibility_modifier)
|
||||
(opacity_modifier)
|
||||
(type_name
|
||||
name: (type_identifier)
|
||||
parameters: (type_parameters
|
||||
(type_parameter)))
|
||||
(tuple_type
|
||||
(type_var)))
|
||||
(type_alias
|
||||
(visibility_modifier)
|
||||
(opacity_modifier)
|
||||
(type_name
|
||||
name: (type_identifier)
|
||||
parameters: (type_parameters
|
||||
(type_parameter)))
|
||||
(tuple_type
|
||||
(type
|
||||
name: (type_identifier))
|
||||
(type_var))))
|
||||
@ -0,0 +1,323 @@
|
||||
================================================================================
|
||||
Excerpt from stdlib's base.gleam
|
||||
================================================================================
|
||||
|
||||
import gleam/bit_string
|
||||
import gleam/string
|
||||
|
||||
/// Encodes a BitString into a base 64 encoded string.
|
||||
///
|
||||
pub fn encode64(input: BitString, padding: Bool) -> String {
|
||||
let encoded = do_encode64(input)
|
||||
case padding {
|
||||
True -> encoded
|
||||
False -> string.replace(encoded, "=", "")
|
||||
}
|
||||
}
|
||||
|
||||
if erlang {
|
||||
external fn do_encode64(BitString) -> String =
|
||||
"base64" "encode"
|
||||
}
|
||||
|
||||
if javascript {
|
||||
external fn do_encode64(BitString) -> String =
|
||||
"../gleam_stdlib.mjs" "encode64"
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(source_file
|
||||
(import
|
||||
module: (module))
|
||||
(import
|
||||
module: (module))
|
||||
(statement_comment)
|
||||
(statement_comment)
|
||||
(function
|
||||
(visibility_modifier)
|
||||
name: (identifier)
|
||||
parameters: (function_parameters
|
||||
(function_parameter
|
||||
name: (identifier)
|
||||
type: (type
|
||||
name: (type_identifier)))
|
||||
(function_parameter
|
||||
name: (identifier)
|
||||
type: (type
|
||||
name: (type_identifier))))
|
||||
return_type: (type
|
||||
name: (type_identifier))
|
||||
body: (function_body
|
||||
(let
|
||||
pattern: (identifier)
|
||||
value: (function_call
|
||||
function: (identifier)
|
||||
arguments: (arguments
|
||||
(argument
|
||||
value: (identifier)))))
|
||||
(case
|
||||
subjects: (case_subjects
|
||||
(identifier))
|
||||
clauses: (case_clauses
|
||||
(case_clause
|
||||
patterns: (case_clause_patterns
|
||||
(case_clause_pattern
|
||||
(record_pattern
|
||||
name: (type_identifier))))
|
||||
value: (identifier))
|
||||
(case_clause
|
||||
patterns: (case_clause_patterns
|
||||
(case_clause_pattern
|
||||
(record_pattern
|
||||
name: (type_identifier))))
|
||||
value: (function_call
|
||||
function: (field_access
|
||||
record: (identifier)
|
||||
field: (label))
|
||||
arguments: (arguments
|
||||
(argument
|
||||
value: (identifier))
|
||||
(argument
|
||||
value: (string
|
||||
(quoted_content)))
|
||||
(argument
|
||||
value: (string)))))))))
|
||||
(target_group
|
||||
target: (target)
|
||||
(external_function
|
||||
name: (identifier)
|
||||
parameters: (function_parameters
|
||||
(function_parameter
|
||||
type: (type
|
||||
name: (type_identifier))))
|
||||
return_type: (type
|
||||
name: (type_identifier))
|
||||
body: (external_function_body
|
||||
(string
|
||||
(quoted_content))
|
||||
(string
|
||||
(quoted_content)))))
|
||||
(target_group
|
||||
target: (target)
|
||||
(external_function
|
||||
name: (identifier)
|
||||
parameters: (function_parameters
|
||||
(function_parameter
|
||||
type: (type
|
||||
name: (type_identifier))))
|
||||
return_type: (type
|
||||
name: (type_identifier))
|
||||
body: (external_function_body
|
||||
(string
|
||||
(quoted_content))
|
||||
(string
|
||||
(quoted_content))))))
|
||||
|
||||
================================================================================
|
||||
Excerpt from stdlib's bool.gleam
|
||||
================================================================================
|
||||
|
||||
//// A type with two possible values, `True` and `False`. Used to indicate whether
|
||||
//// things are... true or false!
|
||||
////
|
||||
//// Often is it clearer and offers more type safety to define a custom type
|
||||
//// than to use `Bool`. For example, rather than having a `is_teacher: Bool`
|
||||
//// field consider having a `role: SchoolRole` field where `SchoolRole` is a custom
|
||||
//// type that can be either `Student` or `Teacher`.
|
||||
|
||||
import gleam/order.{Order}
|
||||
|
||||
/// Returns the opposite bool value.
|
||||
///
|
||||
/// This is the same as the `!` or `not` operators in some other languages.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// > negate(True)
|
||||
/// False
|
||||
///
|
||||
/// > negate(False)
|
||||
/// True
|
||||
///
|
||||
pub fn negate(bool: Bool) -> Bool {
|
||||
case bool {
|
||||
True -> False
|
||||
False -> True
|
||||
}
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(source_file
|
||||
(module_comment)
|
||||
(module_comment)
|
||||
(module_comment)
|
||||
(module_comment)
|
||||
(module_comment)
|
||||
(module_comment)
|
||||
(module_comment)
|
||||
(import
|
||||
module: (module)
|
||||
imports: (unqualified_imports
|
||||
(unqualified_import
|
||||
name: (type_identifier))))
|
||||
(statement_comment)
|
||||
(statement_comment)
|
||||
(statement_comment)
|
||||
(statement_comment)
|
||||
(statement_comment)
|
||||
(statement_comment)
|
||||
(statement_comment)
|
||||
(statement_comment)
|
||||
(statement_comment)
|
||||
(statement_comment)
|
||||
(statement_comment)
|
||||
(statement_comment)
|
||||
(function
|
||||
(visibility_modifier)
|
||||
name: (identifier)
|
||||
parameters: (function_parameters
|
||||
(function_parameter
|
||||
name: (identifier)
|
||||
type: (type
|
||||
name: (type_identifier))))
|
||||
return_type: (type
|
||||
name: (type_identifier))
|
||||
body: (function_body
|
||||
(case
|
||||
subjects: (case_subjects
|
||||
(identifier))
|
||||
clauses: (case_clauses
|
||||
(case_clause
|
||||
patterns: (case_clause_patterns
|
||||
(case_clause_pattern
|
||||
(record_pattern
|
||||
name: (type_identifier))))
|
||||
value: (record
|
||||
name: (type_identifier)))
|
||||
(case_clause
|
||||
patterns: (case_clause_patterns
|
||||
(case_clause_pattern
|
||||
(record_pattern
|
||||
name: (type_identifier))))
|
||||
value: (record
|
||||
name: (type_identifier))))))))
|
||||
|
||||
================================================================================
|
||||
Trailing commas
|
||||
================================================================================
|
||||
|
||||
import animal.{Cat,}
|
||||
|
||||
const foo: #(Int,) = #(1,)
|
||||
const bar = [1,]
|
||||
const cat:Cat(String,) = Cat(name: "Nubi",)
|
||||
|
||||
type Thing {
|
||||
First(name: String,)
|
||||
}
|
||||
|
||||
external fn foo(String,) -> String = "foo" "bar"
|
||||
|
||||
fn foo(a,) {
|
||||
myfun(a,)
|
||||
let Cat(name: name,) = Cat(..a, name: "George",)
|
||||
let #(a) = #(a,)
|
||||
let [x,] = [1,]
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(source_file
|
||||
(import
|
||||
(module)
|
||||
(unqualified_imports
|
||||
(unqualified_import
|
||||
(type_identifier))))
|
||||
(constant
|
||||
(identifier)
|
||||
(tuple_type
|
||||
(type
|
||||
(type_identifier)))
|
||||
(tuple
|
||||
(integer)))
|
||||
(constant
|
||||
(identifier)
|
||||
(list
|
||||
(integer)))
|
||||
(constant
|
||||
(identifier)
|
||||
(type
|
||||
(type_identifier)
|
||||
(type_arguments
|
||||
(type_argument
|
||||
(type
|
||||
(type_identifier)))))
|
||||
(record
|
||||
(type_identifier)
|
||||
(arguments
|
||||
(argument
|
||||
(label)
|
||||
(string
|
||||
(quoted_content))))))
|
||||
(type_definition
|
||||
(type_name
|
||||
(type_identifier))
|
||||
(data_constructors
|
||||
(data_constructor
|
||||
(type_identifier)
|
||||
(data_constructor_arguments
|
||||
(data_constructor_argument
|
||||
(label)
|
||||
(type
|
||||
(type_identifier)))))))
|
||||
(external_function
|
||||
(identifier)
|
||||
(function_parameters
|
||||
(function_parameter
|
||||
(type
|
||||
(type_identifier))))
|
||||
(type
|
||||
(type_identifier))
|
||||
(external_function_body
|
||||
(string
|
||||
(quoted_content))
|
||||
(string
|
||||
(quoted_content))))
|
||||
(function
|
||||
(identifier)
|
||||
(function_parameters
|
||||
(function_parameter
|
||||
(identifier)))
|
||||
(function_body
|
||||
(function_call
|
||||
(identifier)
|
||||
(arguments
|
||||
(argument
|
||||
(identifier))))
|
||||
(let
|
||||
(record_pattern
|
||||
(type_identifier)
|
||||
(record_pattern_arguments
|
||||
(record_pattern_argument
|
||||
(label)
|
||||
(identifier))))
|
||||
(record_update
|
||||
(type_identifier)
|
||||
(identifier)
|
||||
(record_update_arguments
|
||||
(record_update_argument
|
||||
(label)
|
||||
(string
|
||||
(quoted_content))))))
|
||||
(let
|
||||
(tuple_pattern
|
||||
(identifier))
|
||||
(tuple
|
||||
(identifier)))
|
||||
(let
|
||||
(list_pattern
|
||||
(identifier))
|
||||
(list
|
||||
(integer))))))
|
||||
@ -0,0 +1,25 @@
|
||||
<<3>>
|
||||
// <- punctuation.bracket
|
||||
//^ number
|
||||
// ^ punctuation.bracket
|
||||
<<3:8>>
|
||||
//^ number
|
||||
// ^ punctuation.delimiter
|
||||
// ^ number
|
||||
<<3:size(8)>>
|
||||
//^ number
|
||||
// ^ punctuation.delimiter
|
||||
// ^ function.builtin
|
||||
// ^ punctuation.bracket
|
||||
// ^ number
|
||||
// ^ punctuation.bracket
|
||||
<<code:int-size(8)-unit(2), reason:utf8>>
|
||||
// ^ variable
|
||||
// ^ function.builtin
|
||||
// ^ punctuation.delimiter
|
||||
// ^ function.builtin
|
||||
// ^ number
|
||||
// ^ function.builtin
|
||||
// ^ number
|
||||
// ^ variable
|
||||
// ^ function.builtin
|
||||
@ -0,0 +1,24 @@
|
||||
fn case_case(x: Option(String)) {
|
||||
// ^ variable.parameter
|
||||
// ^ type
|
||||
case #(x, x) {
|
||||
// ^ variable.parameter
|
||||
// ^ variable.parameter
|
||||
#(None, None) -> None
|
||||
// ^ type
|
||||
// ^ type
|
||||
// ^ type
|
||||
#(Some(y), Some(z)) -> #(y, z)
|
||||
// ^ type
|
||||
// ^ variable
|
||||
// ^ type
|
||||
// ^ variable
|
||||
// ^ variable
|
||||
// ^ variable
|
||||
}
|
||||
|
||||
// this is bound above but no longer in scope,
|
||||
// so it should be interpereted as a module
|
||||
z.foo()
|
||||
// <- module
|
||||
}
|
||||
@ -0,0 +1,89 @@
|
||||
pub fn replace(
|
||||
// <- keyword
|
||||
// <- keyword
|
||||
// ^ function
|
||||
// ^ punctuation.bracket
|
||||
in original: String,
|
||||
// <- property
|
||||
// ^ variable.parameter
|
||||
// ^ type
|
||||
// ^ punctuation.delimiter
|
||||
each pattern: String,
|
||||
// <- property
|
||||
// ^ variable.parameter
|
||||
// ^ type
|
||||
// ^ punctuation.delimiter
|
||||
with replacement: String,
|
||||
// <- property
|
||||
// ^ variable.parameter
|
||||
// ^ type
|
||||
// ^ punctuation.delimiter
|
||||
) -> String {
|
||||
// <- punctuation.delimiter
|
||||
// ^ type
|
||||
// ^ punctuation.bracket
|
||||
string.replace(in: original, each: pattern, with: replacement)
|
||||
// <- module
|
||||
// ^ function
|
||||
// ^ property
|
||||
// ^ variable.parameter
|
||||
// ^ property
|
||||
// ^ variable.parameter
|
||||
// ^ property
|
||||
// ^ variable.parameter
|
||||
original
|
||||
// ^ variable.parameter
|
||||
|> string.replace(pattern, replacement)
|
||||
// <- operator
|
||||
// ^ module
|
||||
// ^ function
|
||||
// ^ variable.parameter
|
||||
// ^ variable.parameter
|
||||
}
|
||||
|
||||
fn record_with_fun_field(record) {
|
||||
let foo = Bar(baz: fn(x) { x + 1 })
|
||||
foo.baz(41)
|
||||
// <- variable
|
||||
// ^ property
|
||||
record.foobar("hello")
|
||||
// ^ variable.parameter
|
||||
// ^ property
|
||||
string.replace("hello", "l", "o")
|
||||
// ^ module
|
||||
// ^ function
|
||||
}
|
||||
|
||||
fn trial(uri) {
|
||||
// ^ variable.parameter
|
||||
case uri {
|
||||
// ^ variable.parameter
|
||||
Uri(scheme: None) -> True
|
||||
// <- type
|
||||
// ^ property
|
||||
// ^ type
|
||||
// ^ type
|
||||
_ -> False
|
||||
// <- comment.unused
|
||||
}
|
||||
}
|
||||
|
||||
fn myfun(argument) {
|
||||
let local_fun = fn(x) { x + 1 }
|
||||
// ^ variable
|
||||
// ^ variable.parameter
|
||||
// ^ variable.parameter
|
||||
|
||||
argument
|
||||
// ^ variable.parameter
|
||||
|> local_fun
|
||||
// <- operator
|
||||
// ^ variable
|
||||
|> module_fun
|
||||
// ^ function
|
||||
|
||||
module_fun(local_fun(argument))
|
||||
// ^ function
|
||||
// ^ variable
|
||||
// ^ variable.parameter
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
import gleam/io
|
||||
// ^ module
|
||||
// ^ module
|
||||
// ^ module
|
||||
import animal/cat as kitty
|
||||
// ^ module
|
||||
// ^ module
|
||||
|
||||
pub fn main() {
|
||||
io.println("hello world")
|
||||
// <- module
|
||||
}
|
||||
|
||||
type MyType {
|
||||
MyType(func: fn() -> Int)
|
||||
}
|
||||
|
||||
fn record_access_case(param: MyType) {
|
||||
let binding = MyType(func: fn() { 42 })
|
||||
let _ = binding.func()
|
||||
// ^ comment.unused
|
||||
// ^ variable
|
||||
let _ = param.func()
|
||||
// ^ comment.unused
|
||||
// ^ variable.parameter
|
||||
}
|
||||
|
||||
fn pipe_operator_case(string: String) {
|
||||
string
|
||||
// <- variable.parameter
|
||||
|> iodata.new
|
||||
// ^ module
|
||||
|> iodata.reverse
|
||||
// ^ module
|
||||
}
|
||||
|
||||
fn remote_type_case() {
|
||||
gleam.Ok(1)
|
||||
// <- module
|
||||
// ^ punctuation.delimiter
|
||||
// ^ type
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
pub type User {
|
||||
User(name: String)
|
||||
// <- type
|
||||
// ^ property
|
||||
// ^ type
|
||||
}
|
||||
|
||||
pub fn new(name: String) {
|
||||
// ^ variable.parameter
|
||||
User(name: name)
|
||||
// ^ property
|
||||
// ^ variable.parameter
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
import gleam/option.{Option, Some, None}
|
||||
// ^ reference.module
|
||||
// ^ reference.type
|
||||
// ^ reference.type
|
||||
// ^ reference.type
|
||||
import gleam/bit_builder
|
||||
// ^ reference.module
|
||||
|
||||
pub type FrameData {
|
||||
// ^ definition.type
|
||||
Text(String)
|
||||
// <- definition.type
|
||||
// ^ reference.type
|
||||
Binary(BitString)
|
||||
Continuation(BitString)
|
||||
Ping(BitString)
|
||||
Pong(BitString)
|
||||
Close(code: Option(Int), reason: Option(String))
|
||||
// <- definition.type
|
||||
// ^ reference.type
|
||||
// ^ reference.type
|
||||
// ^ reference.type
|
||||
// ^ reference.type
|
||||
}
|
||||
|
||||
pub type Frame {
|
||||
// ^ definition.type
|
||||
Frame(reserved: BitString, mask: Option(BitString), data: FrameData, fin: Bool)
|
||||
}
|
||||
|
||||
fn encode_frame(frame: Frame) -> bit_builder.BitBuilder {
|
||||
// ^ definition.function
|
||||
// ^ reference.type
|
||||
// ^ reference.module
|
||||
// ^ reference.type
|
||||
let fin =
|
||||
case frame.fin {
|
||||
True -> <<1:size(1)>>
|
||||
False -> <<0:size(1)>>
|
||||
}
|
||||
|
||||
let opcode =
|
||||
case frame.data {
|
||||
Continuation(_) -> <<0x0:size(1)>>
|
||||
// <- reference.type
|
||||
Text(_) -> <<0x1:size(1)>>
|
||||
Binary(_) -> <<0x2:size(1)>>
|
||||
// 0x3-7 reserved for future non-control frames
|
||||
Close(..) -> <<0x8:size(1)>>
|
||||
Pong(_) -> <<0x9:size(1)>>
|
||||
Pong(_) -> <<0xA:size(1)>>
|
||||
}
|
||||
|
||||
let is_masked_bit =
|
||||
case frame.mask {
|
||||
Some(_) -> <<1:size(1)>>
|
||||
None -> <<0:size(1)>>
|
||||
}
|
||||
|
||||
bit_builder.new()
|
||||
// <- reference.module
|
||||
// ^ reference.function
|
||||
|> bit_builder.append(fin)
|
||||
// ^ reference.function
|
||||
|> bit_builder.append(frame.reserved)
|
||||
|> bit_builder.append(opcode)
|
||||
|> bit_builder.append(is_masked_bit)
|
||||
|> bit_builder.append(option.unwrap(frame.mask, <<>>))
|
||||
// ^ reference.module
|
||||
// ^ reference.module
|
||||
// ^ reference.function
|
||||
|> bit_builder.append(mask_data(frame))
|
||||
// ^ reference.function
|
||||
}
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
fn record_with_fun_field(record) {
|
||||
let foo = Bar(baz: fn(x) { x + 1 })
|
||||
// ^ reference.type
|
||||
foo.baz(41)
|
||||
record.foobar("hello")
|
||||
|
||||
string.replace("hello", "l", "o")
|
||||
// ^ reference.module
|
||||
// ^ reference.function
|
||||
}
|
||||
Loading…
Reference in New Issue