@ -4,7 +4,6 @@ module.exports = grammar({
name : "gleam" ,
externals : ( $ ) => [ $ . quoted _content ] ,
extras : ( $ ) => [
";" ,
NEWLINE ,
/\s/ ,
$ . module _comment ,
@ -13,11 +12,6 @@ module.exports = grammar({
] ,
conflicts : ( $ ) => [
[ $ . _maybe _record _expression , $ . _maybe _tuple _expression ] ,
[
$ . _maybe _record _expression ,
$ . _maybe _tuple _expression ,
$ . remote _type _identifier ,
] ,
[
$ . _maybe _record _expression ,
$ . _maybe _tuple _expression ,
@ -25,13 +19,16 @@ module.exports = grammar({
] ,
[ $ . case _subjects ] ,
[ $ . source _file ] ,
[ $ . _constant _value , $ . _case _clause _guard _unit ] ,
[ $ . integer ] ,
[ $ . echo ] ,
] ,
rules : {
/* General rules */
source _file : ( $ ) =>
repeat ( choice ( $ . target _group , $ . _ statement, $ . _expression _seq ) ) ,
repeat ( choice ( $ . target _group , $ . _ module_statement , $ . _statement _seq ) ) ,
_ statement: ( $ ) =>
_ module_ statement: ( $ ) =>
choice (
$ . import ,
$ . constant ,
@ -39,7 +36,8 @@ module.exports = grammar({
$ . external _function ,
$ . function ,
$ . type _definition ,
$ . type _alias
$ . type _alias ,
$ . attribute
) ,
/* Comments */
@ -47,18 +45,43 @@ module.exports = grammar({
statement _comment : ( $ ) => token ( seq ( "///" , /.*/ ) ) ,
comment : ( $ ) => token ( seq ( "//" , /.*/ ) ) ,
/* Target groups */
/ * T a r g e t g r o u p s
* DEPRECATED : This syntax was replaced with attributes in v0 . 30.
* /
target _group : ( $ ) =>
seq ( "if" , field ( "target" , $ . target ) , "{" , repeat ( $ . _statement ) , "}" ) ,
seq (
"if" ,
field ( "target" , $ . target ) ,
"{" ,
repeat ( $ . _module _statement ) ,
"}"
) ,
target : ( $ ) => choice ( "erlang" , "javascript" ) ,
/* Attributes */
attribute : ( $ ) =>
seq (
"@" ,
field ( "name" , $ . identifier ) ,
optional ( field ( "arguments" , alias ( $ . _attribute _arguments , $ . arguments ) ) )
) ,
_attribute _arguments : ( $ ) =>
seq ( "(" , series _of ( $ . attribute _value , "," ) , ")" ) ,
attribute _value : ( $ ) =>
choice (
$ . _constant _value ,
seq ( field ( "label" , $ . label ) , ":" , field ( "value" , $ . _constant _value ) )
) ,
/* Import statements */
import : ( $ ) =>
seq (
"import" ,
field ( "module" , $ . module ) ,
optional ( seq ( "." , field ( "imports" , $ . unqualified _imports ) ) ) ,
optional ( seq ( "as" , field ( "alias" , $ . identifier ) ) )
optional ( seq ( "as" , field ( "alias" , choice( $. identifier , $ . discard ) ) ) )
) ,
module : ( $ ) => seq ( $ . _name , repeat ( seq ( "/" , $ . _name ) ) ) ,
unqualified _imports : ( $ ) =>
@ -70,8 +93,13 @@ module.exports = grammar({
optional ( seq ( "as" , field ( "alias" , $ . identifier ) ) )
) ,
seq (
"type" ,
field ( "name" , $ . type _identifier ) ,
optional ( seq ( "as" , field ( "alias" , $ . type _identifier ) ) )
) ,
seq (
field ( "name" , $ . constructor _name ) ,
optional ( seq ( "as" , field ( "alias" , $ . constructor _name ) ) )
)
) ,
@ -93,7 +121,9 @@ module.exports = grammar({
alias ( $ . constant _tuple , $ . tuple ) ,
alias ( $ . constant _list , $ . list ) ,
alias ( $ . _constant _bit _string , $ . bit _string ) ,
alias ( $ . constant _record , $ . record )
alias ( $ . constant _record , $ . record ) ,
$ . identifier ,
alias ( $ . constant _field _access , $ . field _access )
) ,
constant _tuple : ( $ ) =>
seq ( "#" , "(" , optional ( series _of ( $ . _constant _value , "," ) ) , ")" ) ,
@ -114,10 +144,17 @@ module.exports = grammar({
")"
) ,
constant _record _argument : ( $ ) =>
seq (
optional ( seq ( field ( "label" , $ . label ) , ":" ) ) ,
field ( "value" , $ . _constant _value )
choice (
seq (
optional ( seq ( field ( "label" , $ . label ) , ":" ) ) ,
field ( "value" , $ . _constant _value )
) ,
seq ( field ( "label" , $ . label ) , ":" )
) ,
// This rule exists to parse remote function references which are generally
// indistinguishable from field accesses and so share an AST node.
constant _field _access : ( $ ) =>
seq ( field ( "record" , $ . identifier ) , "." , field ( "field" , $ . label ) ) ,
/* Special constant types */
// Versions of $._type, $._type_annotation, etc, that have constraints
@ -126,11 +163,29 @@ module.exports = grammar({
choice (
$ . type _hole ,
alias ( $ . constant _tuple _type , $ . tuple _type ) ,
alias ( $ . constant _function _type , $ . function _type ) ,
alias ( $ . constant _type , $ . type )
) ,
_constant _type _annotation : ( $ ) => seq ( ":" , field ( "type" , $ . _constant _type ) ) ,
constant _tuple _type : ( $ ) =>
seq ( "#" , "(" , optional ( series _of ( $ . _constant _type , "," ) ) , ")" ) ,
constant _function _type : ( $ ) =>
seq (
"fn" ,
optional (
field (
"parameter_types" ,
alias (
$ . constant _function _parameter _types ,
$ . function _parameter _types
)
)
) ,
"->" ,
field ( "return_type" , $ . _constant _type )
) ,
constant _function _parameter _types : ( $ ) =>
seq ( "(" , optional ( series _of ( $ . _constant _type , "," ) ) , ")" ) ,
constant _type : ( $ ) =>
seq (
field ( "name" , choice ( $ . type _identifier , $ . remote _type _identifier ) ) ,
@ -149,7 +204,15 @@ module.exports = grammar({
constant _type _argument : ( $ ) => $ . _constant _type ,
external _type : ( $ ) =>
seq ( optional ( $ . visibility _modifier ) , "external" , "type" , $ . type _name ) ,
prec . right (
seq (
optional ( $ . visibility _modifier ) ,
// DEPRECATED: the external token was removed in v0.30.
optional ( "external" ) ,
"type" ,
$ . type _name
)
) ,
/* External function */
external _function : ( $ ) =>
@ -189,15 +252,15 @@ module.exports = grammar({
/* 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 ) ) ,
"}"
prec. right (
seq(
optional ( $ . visibility _modifier ) ,
"fn" ,
field ( "name" , $ . identifier ) ,
field ( "parameters" , $ . function _parameters ) ,
optional ( seq ( "->" , field ( "return_type" , $ . _type ) ) ) ,
optional ( field ( "body" , $. block ) )
)
) ,
function _parameters : ( $ ) =>
seq ( "(" , optional ( series _of ( $ . function _parameter , "," ) ) , ")" ) ,
@ -217,36 +280,9 @@ module.exports = grammar({
_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 )
) ,
_statement _seq : ( $ ) => repeat1 ( $ . _statement ) ,
_statement : ( $ ) =>
choice ( $ . _expression , $ . let , $ . let _assert , $ . use , $ . assert ) ,
_expression : ( $ ) => choice ( $ . _expression _unit , $ . binary _expression ) ,
binary _expression : ( $ ) =>
choice (
@ -262,7 +298,13 @@ module.exports = grammar({
binaryExpr ( prec . left , 4 , ">=" , $ . _expression ) ,
binaryExpr ( prec . left , 4 , ">." , $ . _expression ) ,
binaryExpr ( prec . left , 4 , ">=." , $ . _expression ) ,
binaryExpr ( prec . left , 5 , "|>" , $ . _expression ) ,
binaryExpr (
prec . left ,
5 ,
"|>" ,
$ . _expression ,
choice ( $ . pipeline _echo , $ . _expression )
) ,
binaryExpr ( prec . left , 6 , "+" , $ . _expression ) ,
binaryExpr ( prec . left , 6 , "+." , $ . _expression ) ,
binaryExpr ( prec . left , 6 , "-" , $ . _expression ) ,
@ -271,7 +313,8 @@ module.exports = grammar({
binaryExpr ( prec . left , 7 , "*." , $ . _expression ) ,
binaryExpr ( prec . left , 7 , "/" , $ . _expression ) ,
binaryExpr ( prec . left , 7 , "/." , $ . _expression ) ,
binaryExpr ( prec . left , 7 , "%" , $ . _expression )
binaryExpr ( prec . left , 7 , "%" , $ . _expression ) ,
binaryExpr ( prec . left , 7 , "<>" , $ . _expression )
) ,
// The way that this function is written in the Gleam parser is essentially
// incompatible with tree-sitter. It first parses some base expression,
@ -291,15 +334,16 @@ module.exports = grammar({
$ . record ,
$ . identifier ,
$ . todo ,
$ . panic ,
$ . tuple ,
$ . echo ,
$ . list ,
alias ( $ . _expression _bit _string , $ . bit _string ) ,
$ . anonymous _function ,
$ . expression_group ,
$ . block ,
$ . case ,
$ . let ,
$ . assert ,
$ . negation ,
$ . boolean _negation ,
$ . integer _negation ,
$ . record _update ,
$ . tuple _access ,
$ . field _access ,
@ -311,7 +355,32 @@ module.exports = grammar({
optional ( field ( "arguments" , $ . arguments ) )
) ,
todo : ( $ ) =>
seq ( "todo" , optional ( seq ( "(" , field ( "message" , $ . string ) , ")" ) ) ) ,
prec . left (
seq (
"todo" ,
optional (
choice (
// DEPRECATED: The 'as' syntax was introduced in v0.30.
seq ( "(" , field ( "message" , $ . string ) , ")" ) ,
seq ( "as" , field ( "message" , $ . _expression ) )
)
)
)
) ,
panic : ( $ ) =>
prec . left (
seq (
"panic" ,
optional (
choice (
seq ( "(" , field ( "message" , $ . string ) , ")" ) ,
seq ( "as" , field ( "message" , $ . _expression ) )
)
)
)
) ,
pipeline _echo : ( _$ ) => prec . left ( "echo" ) ,
echo : ( $ ) => seq ( "echo" , $ . _expression ) ,
tuple : ( $ ) => seq ( "#" , "(" , optional ( series _of ( $ . _expression , "," ) ) , ")" ) ,
list : ( $ ) =>
seq (
@ -335,9 +404,7 @@ module.exports = grammar({
alias ( $ . anonymous _function _parameters , $ . function _parameters )
) ,
optional ( seq ( "->" , field ( "return_type" , $ . _type ) ) ) ,
"{" ,
field ( "body" , alias ( $ . _expression _seq , $ . function _body ) ) ,
"}"
field ( "body" , $ . block )
) ,
anonymous _function _parameters : ( $ ) =>
seq (
@ -355,13 +422,13 @@ module.exports = grammar({
choice ( $ . _discard _param , $ . _name _param ) ,
optional ( $ . _type _annotation )
) ,
expression_group : ( $ ) => seq ( "{" , $. _expression _seq , "}" ) ,
block : ( $ ) => seq ( "{" , optional( $ . _statement _seq ) , "}" ) ,
case : ( $ ) =>
seq (
"case" ,
field ( "subjects" , $ . case _subjects ) ,
"{" ,
field( "clauses" , $ . case _clauses ) ,
optional( field( "clauses" , $ . case _clauses ) ) ,
"}"
) ,
case _subjects : ( $ ) => seq ( series _of ( $ . _expression , "," ) ) ,
@ -385,7 +452,8 @@ module.exports = grammar({
_case _clause _guard _expression : ( $ ) =>
choice (
$ . _case _clause _guard _unit ,
alias ( $ . _case _clause _guard _binary _expression , $ . binary _expression )
alias ( $ . _case _clause _guard _binary _expression , $ . binary _expression ) ,
$ . boolean _negation
) ,
_case _clause _guard _binary _expression : ( $ ) =>
choice (
@ -400,7 +468,16 @@ module.exports = grammar({
binaryExpr ( prec . left , 4 , ">" , $ . _case _clause _guard _expression ) ,
binaryExpr ( prec . left , 4 , ">=" , $ . _case _clause _guard _expression ) ,
binaryExpr ( prec . left , 4 , ">." , $ . _case _clause _guard _expression ) ,
binaryExpr ( prec . left , 4 , ">=." , $ . _case _clause _guard _expression )
binaryExpr ( prec . left , 4 , ">=." , $ . _case _clause _guard _expression ) ,
binaryExpr ( prec . left , 5 , "+" , $ . _case _clause _guard _expression ) ,
binaryExpr ( prec . left , 5 , "+." , $ . _case _clause _guard _expression ) ,
binaryExpr ( prec . left , 5 , "-" , $ . _case _clause _guard _expression ) ,
binaryExpr ( prec . left , 5 , "-." , $ . _case _clause _guard _expression ) ,
binaryExpr ( prec . left , 6 , "*" , $ . _case _clause _guard _expression ) ,
binaryExpr ( prec . left , 6 , "*." , $ . _case _clause _guard _expression ) ,
binaryExpr ( prec . left , 6 , "/" , $ . _case _clause _guard _expression ) ,
binaryExpr ( prec . left , 6 , "/." , $ . _case _clause _guard _expression ) ,
binaryExpr ( prec . left , 6 , "%" , $ . _case _clause _guard _expression )
) ,
_case _clause _guard _unit : ( $ ) =>
choice (
@ -411,9 +488,31 @@ module.exports = grammar({
) ,
_case _clause _tuple _access : ( $ ) =>
seq ( field ( "tuple" , $ . identifier ) , "." , field ( "index" , $ . integer ) ) ,
let _assert : ( $ ) =>
seq (
"let" ,
"assert" ,
$ . _assignment ,
optional ( seq ( "as" , field ( "message" , $ . _expression ) ) )
) ,
assert : ( $ ) =>
seq (
"assert" ,
field ( "value" , $ . _expression ) ,
optional ( seq ( "as" , field ( "message" , $ . _expression ) ) )
) ,
let : ( $ ) => seq ( "let" , $ . _assignment ) ,
assert : ( $ ) => seq ( "assert" , $ . _assignment ) ,
negation : ( $ ) => seq ( "!" , $ . _expression _unit ) ,
use : ( $ ) =>
seq (
"use" ,
optional ( field ( "assignments" , $ . use _assignments ) ) ,
"<-" ,
field ( "value" , $ . _expression )
) ,
use _assignments : ( $ ) => series _of ( $ . use _assignment , "," ) ,
use _assignment : ( $ ) => seq ( $ . _pattern , optional ( $ . _type _annotation ) ) ,
boolean _negation : ( $ ) => seq ( "!" , $ . _expression _unit ) ,
integer _negation : ( $ ) => seq ( "-" , $ . _expression _unit ) ,
_assignment : ( $ ) =>
seq (
field ( "pattern" , $ . _pattern ) ,
@ -436,7 +535,10 @@ module.exports = grammar({
) ,
record _update _arguments : ( $ ) => series _of ( $ . record _update _argument , "," ) ,
record _update _argument : ( $ ) =>
seq ( field ( "label" , $ . label ) , ":" , field ( "value" , $ . _expression ) ) ,
choice (
seq ( field ( "label" , $ . label ) , ":" , field ( "value" , $ . _expression ) ) ,
seq ( field ( "label" , $ . label ) , ":" )
) ,
// As with other AST nodes in this section, `_maybe_record_expression`,
// `_maybe_tuple_expression`, and `_maybe_function_expresssion` have no
// corollaries in the Gleam parser. These anonymous AST node denote any
@ -450,7 +552,7 @@ module.exports = grammar({
$ . identifier ,
$ . function _call ,
$ . tuple ,
$ . expression_group ,
$ . block ,
$ . case ,
$ . field _access ,
$ . tuple _access
@ -468,7 +570,7 @@ module.exports = grammar({
$ . record ,
$ . identifier ,
$ . function _call ,
$ . expression_group ,
$ . block ,
$ . case ,
$ . record _update ,
$ . field _access ,
@ -494,7 +596,7 @@ module.exports = grammar({
choice (
$ . identifier ,
$ . anonymous _function ,
$ . expression_group ,
$ . block ,
$ . case ,
$ . tuple _access ,
$ . field _access ,
@ -504,9 +606,12 @@ module.exports = grammar({
// record arguments, hence the ambiguous name.
arguments : ( $ ) => seq ( "(" , optional ( series _of ( $ . argument , "," ) ) , ")" ) ,
argument : ( $ ) =>
seq (
optional ( seq ( field ( "label" , $ . label ) , ":" ) ) ,
field ( "value" , choice ( $ . hole , $ . _expression ) )
choice (
seq (
optional ( seq ( field ( "label" , $ . label ) , ":" ) ) ,
field ( "value" , choice ( $ . hole , $ . _expression ) )
) ,
seq ( field ( "label" , $ . label ) , ":" )
) ,
hole : ( $ ) => $ . _discard _name ,
function _call : ( $ ) =>
@ -514,19 +619,27 @@ module.exports = grammar({
field ( "function" , $ . _maybe _function _expression ) ,
field ( "arguments" , $ . arguments )
) ,
_pattern _expression : ( $ ) =>
choice (
$ . identifier ,
$ . discard ,
$ . record _pattern ,
$ . string ,
$ . integer ,
$ . float ,
$ . tuple _pattern ,
alias ( $ . _pattern _bit _string , $ . bit _string _pattern ) ,
$ . list _pattern ,
alias ( $ . _pattern _binary _expression , $ . binary _expression )
) ,
_pattern _binary _expression : ( $ ) =>
choice (
binaryExpr ( prec . left , 1 , "<>" , $ . _pattern _expression ) ,
binaryExpr ( prec . left , 1 , "as" , $ . string , $ . identifier )
) ,
_pattern : ( $ ) =>
seq (
choice (
$ . identifier ,
$ . discard ,
$ . record _pattern ,
$ . string ,
$ . integer ,
$ . float ,
$ . tuple _pattern ,
alias ( $ . _pattern _bit _string , $ . bit _string _pattern ) ,
$ . list _pattern
) ,
$ . _pattern _expression ,
optional ( field ( "assign" , seq ( "as" , $ . identifier ) ) )
) ,
record _pattern : ( $ ) =>
@ -542,9 +655,12 @@ module.exports = grammar({
")"
) ,
record _pattern _argument : ( $ ) =>
seq (
optional ( seq ( field ( "label" , $ . label ) , ":" ) ) ,
field ( "pattern" , $ . _pattern )
choice (
seq (
optional ( seq ( field ( "label" , $ . label ) , ":" ) ) ,
field ( "pattern" , $ . _pattern )
) ,
seq ( field ( "label" , $ . label ) , ":" )
) ,
pattern _spread : ( $ ) => seq ( ".." , optional ( "," ) ) ,
tuple _pattern : ( $ ) =>
@ -586,6 +702,7 @@ module.exports = grammar({
data _constructors : ( $ ) => repeat1 ( $ . data _constructor ) ,
data _constructor : ( $ ) =>
seq (
optional ( $ . attribute ) ,
field ( "name" , $ . constructor _name ) ,
optional ( field ( "arguments" , $ . data _constructor _arguments ) )
) ,
@ -612,8 +729,12 @@ module.exports = grammar({
repeat ( choice ( $ . escape _sequence , $ . quoted _content ) ) ,
token . immediate ( '"' )
) ,
escape _sequence : ( $ ) => token . immediate ( /\\[efnrt\"\\]/ ) ,
float : ( $ ) => / - ? [ 0 - 9_ ] + \ . [ 0 - 9_ ] * / ,
escape _sequence : ( $ ) =>
choice (
token . immediate ( /\\[efnrt\"\\]/ ) ,
token . immediate ( /\\u\{[0-9a-fA-F]{1,6}\}/ )
) ,
float : ( $ ) => / - ? [ 0 - 9_ ] + \ . [ 0 - 9_ ] * ( e - ? [ 0 - 9_ ] + ) ? / ,
integer : ( $ ) =>
seq ( optional ( "-" ) , choice ( $ . _hex , $ . _decimal , $ . _octal , $ . _binary ) ) ,
_hex : ( $ ) => / 0 [ xX ] [ 0 - 9 a - fA - F _ ] + / ,
@ -769,9 +890,13 @@ function series_of(rule, 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 ) {
function binaryExpr ( assoc , precedence , operator , left, right = null ) {
return assoc (
precedence ,
seq ( field ( "left" , expr ) , field ( "operator" , operator ) , field ( "right" , expr ) )
seq (
field ( "left" , left ) ,
field ( "operator" , operator ) ,
field ( "right" , right || left )
)
) ;
}