add generics

This commit is contained in:
paul committed 2026-10-23 02:13:30 -04:00
1 parent 79533e9537
commit 2204d58102
22 files changed
+47239 -37460

No files matched your search

+5 -4
View File
@@ -10,7 +10,9 @@ The public named-node and field contract is documented in
## Development
Tree-sitter 0.27 and Node.js are required.
Tree-sitter 0.27 is required. `tree-sitter generate` evaluates `grammar.js`
with Node.js by default; without Node.js, pass `--js-runtime native` to use the
CLI's bundled QuickJS runtime.
```sh
npm install
@@ -28,9 +30,8 @@ script: the adjacency-only `=-` and `!=` lexer errors, and recovery after a
repeated result operator. These need lexical or recovery handling rather than
a looser grammar rule.
The future-reserved word `context` is not yet emitted as a Tree-sitter keyword
because it has no grammar production. It should move into lexical handling with
the two adjacency checks above.
The future-reserved word `context` is a `reserved_word` token with no grammar
production, so it is rejected wherever an identifier is expected.
Generated parser sources under `src/` are committed so consumers do not need
Node.js or the Tree-sitter CLI.
+270 -13
View File
@@ -196,10 +196,10 @@ mod tests {
}
#[test]
fn exposes_wrappers_and_untyped_inputs() {
let source = "present: i32?: some 1\n\
fn exposes_sum_spelled_optionals_and_untyped_inputs() {
let source = "present: i32?: 1->|.some\n\
double :: @ value { value * 2 }\n\
unwrap :: @ result { match result { ok inner => inner; err _ => 0 } }\n";
unwrap :: @ result { match result { |.ok inner => inner; |.err _ => 0 } }\n";
let tree = parse(source);
assert!(
!tree.root_node().has_error(),
@@ -209,10 +209,22 @@ mod tests {
let present = tree.root_node().named_child(0).unwrap();
let wrapped = present.child_by_field_name("value").unwrap();
assert_eq!(wrapped.kind(), "unary_expression");
assert_eq!(wrapped.kind(), "pipeline_expression");
assert_eq!(
wrapped
.child_by_field_name("operator")
wrapped.child_by_field_name("input").unwrap().kind(),
"signed_numeric_literal"
);
let stage = wrapped.named_child(1).unwrap();
assert_eq!(stage.kind(), "direct_pipeline_stage");
let constructor = stage
.child_by_field_name("callable")
.unwrap()
.named_child(0)
.unwrap();
assert_eq!(constructor.kind(), "sum_constructor");
assert_eq!(
constructor
.child_by_field_name("variant")
.unwrap()
.utf8_text(source.as_bytes())
.unwrap(),
@@ -233,25 +245,270 @@ mod tests {
let body = function.child_by_field_name("body").unwrap();
let arm = body.named_child(0).unwrap().named_child(1).unwrap();
let pattern = arm.child_by_field_name("pattern").unwrap();
let wrapper = pattern.named_child(0).unwrap();
assert_eq!(wrapper.kind(), "wrapper_pattern");
let variant = pattern.named_child(0).unwrap();
assert_eq!(variant.kind(), "sum_pattern");
assert_eq!(
wrapper
.child_by_field_name("wrapper")
variant
.child_by_field_name("variant")
.unwrap()
.utf8_text(source.as_bytes())
.unwrap(),
"ok"
);
assert_eq!(
variant.child_by_field_name("payload").unwrap().kind(),
"identifier"
);
}
#[test]
fn rejects_removed_wrapper_forms() {
fn binds_same_line_stages_tighter_than_operators() {
let source = "mixed :: -3->add_ten + 2 * 3->double - {1 + 1}->double\n";
let tree = parse(source);
assert!(
!tree.root_node().has_error(),
"{}",
tree.root_node().to_sexp()
);
let declaration = tree.root_node().named_child(0).unwrap();
let subtraction = declaration.child_by_field_name("value").unwrap();
assert_eq!(subtraction.kind(), "binary_expression");
assert_eq!(
subtraction
.child_by_field_name("operator")
.unwrap()
.utf8_text(source.as_bytes())
.unwrap(),
"-"
);
let addition = subtraction.child_by_field_name("left").unwrap();
assert_eq!(addition.kind(), "binary_expression");
let negation = addition.child_by_field_name("left").unwrap();
assert_eq!(negation.kind(), "unary_expression");
let negated = negation.child_by_field_name("operand").unwrap();
assert_eq!(negated.kind(), "pipeline_expression");
assert_eq!(
negated
.child_by_field_name("input")
.unwrap()
.utf8_text(source.as_bytes())
.unwrap(),
"3"
);
let product = addition.child_by_field_name("right").unwrap();
assert_eq!(product.kind(), "binary_expression");
assert_eq!(
product.child_by_field_name("right").unwrap().kind(),
"pipeline_expression"
);
let grouped = subtraction.child_by_field_name("right").unwrap();
assert_eq!(grouped.kind(), "pipeline_expression");
assert_eq!(
grouped.child_by_field_name("input").unwrap().kind(),
"block"
);
}
#[test]
fn applies_continuation_stages_to_the_whole_preceding_expression() {
let source = "flat := value->first\n->second\nwhole := a + b->f\n->g\n";
let tree = parse(source);
assert!(
!tree.root_node().has_error(),
"{}",
tree.root_node().to_sexp()
);
let flat = tree
.root_node()
.named_child(0)
.unwrap()
.child_by_field_name("value")
.unwrap();
assert_eq!(flat.kind(), "pipeline_expression");
assert_eq!(
flat.child_by_field_name("input").unwrap().kind(),
"identifier"
);
assert_eq!(flat.named_child(1).unwrap().kind(), "direct_pipeline_stage");
assert_eq!(
flat.named_child(2).unwrap().kind(),
"continuation_pipeline_stage"
);
assert_eq!(flat.named_child_count(), 3);
let whole = tree
.root_node()
.named_child(1)
.unwrap()
.child_by_field_name("value")
.unwrap();
assert_eq!(whole.kind(), "pipeline_expression");
let head = whole.child_by_field_name("input").unwrap();
assert_eq!(head.kind(), "binary_expression");
assert_eq!(
head.child_by_field_name("right").unwrap().kind(),
"pipeline_expression"
);
assert_eq!(
whole.named_child(1).unwrap().kind(),
"continuation_pipeline_stage"
);
}
#[test]
fn exposes_generic_binders_constraints_and_output_types() {
let source = "Show :: <>{ to_str: str; ...Display }\n\
pick: <T: Show> (T, T) -> T: @ (first, second): (T, T) { first }\n\
Card :: &{ label: Output<make_label: Show>: }\n";
let tree = parse(source);
assert!(
!tree.root_node().has_error(),
"{}",
tree.root_node().to_sexp()
);
let show = tree.root_node().named_child(0).unwrap();
let definition = show.child_by_field_name("value").unwrap();
assert_eq!(definition.kind(), "type_definition");
let constraint = definition.named_child(0).unwrap();
assert_eq!(constraint.kind(), "constraint_body");
let entry = constraint.named_child(0).unwrap();
assert_eq!(entry.kind(), "constraint_entry");
assert_eq!(
entry
.child_by_field_name("name")
.unwrap()
.utf8_text(source.as_bytes())
.unwrap(),
"to_str"
);
assert_eq!(
entry.child_by_field_name("output").unwrap().kind(),
"primitive_type"
);
let spread = constraint.named_child(1).unwrap();
assert_eq!(spread.kind(), "constraint_spread");
assert_eq!(
spread
.child_by_field_name("constraint")
.unwrap()
.utf8_text(source.as_bytes())
.unwrap(),
"Display"
);
let pick = tree.root_node().named_child(1).unwrap();
let binder = pick.child_by_field_name("binder").unwrap();
assert_eq!(binder.kind(), "binder");
let parameter = binder.named_child(0).unwrap();
assert_eq!(parameter.kind(), "binder_entry");
assert_eq!(
parameter
.child_by_field_name("type")
.unwrap()
.utf8_text(source.as_bytes())
.unwrap(),
"T"
);
assert_eq!(
parameter
.child_by_field_name("constraint")
.unwrap()
.utf8_text(source.as_bytes())
.unwrap(),
"Show"
);
assert_eq!(
pick.child_by_field_name("type").unwrap().kind(),
"function_type"
);
assert_eq!(
pick.child_by_field_name("value").unwrap().kind(),
"function_literal"
);
let card = tree.root_node().named_child(2).unwrap();
let field = card
.child_by_field_name("value")
.unwrap()
.named_child(0)
.unwrap()
.named_child(0)
.unwrap();
assert_eq!(field.kind(), "product_field");
let output = field.child_by_field_name("type").unwrap();
assert_eq!(output.kind(), "output_type");
assert_eq!(
output
.child_by_field_name("function")
.unwrap()
.utf8_text(source.as_bytes())
.unwrap(),
"make_label"
);
assert_eq!(
output
.child_by_field_name("output")
.unwrap()
.utf8_text(source.as_bytes())
.unwrap(),
"Show"
);
}
#[test]
fn exposes_import_filters() {
let source = "use math.{sqrt for f64, pi}\nuse .shapes.area for Circle\npub { area for Circle; sqrt }\n";
let tree = parse(source);
assert!(
!tree.root_node().has_error(),
"{}",
tree.root_node().to_sexp()
);
let group = tree.root_node().named_child(0).unwrap();
assert_eq!(group.kind(), "use_declaration");
let member = group.named_child(1).unwrap();
assert_eq!(member.kind(), "import_member");
let filter = member.named_child(1).unwrap();
assert_eq!(filter.kind(), "import_filter");
assert_eq!(
filter.child_by_field_name("type").unwrap().kind(),
"primitive_type"
);
assert_eq!(group.named_child(2).unwrap().named_child_count(), 1);
let single = tree.root_node().named_child(1).unwrap();
assert_eq!(single.named_child(1).unwrap().kind(), "import_filter");
let publication = tree.root_node().named_child(2).unwrap();
assert_eq!(publication.kind(), "pub_declaration");
let filtered = publication.named_child(0).unwrap();
assert_eq!(filtered.kind(), "pub_entry");
assert_eq!(
filtered
.child_by_field_name("name")
.unwrap()
.utf8_text(source.as_bytes())
.unwrap(),
"area"
);
assert_eq!(filtered.named_child(1).unwrap().kind(), "import_filter");
assert_eq!(publication.named_child(1).unwrap().named_child_count(), 1);
}
#[test]
fn rejects_removed_wrapper_forms_and_reserved_words() {
for source in [
"old: i32?: 1->|.some\n",
"present: i32?: some 1\n",
"old :: @ value: i32 -> i32 ! str { value! }\n",
"old :: @ value: str -> i32 ! str { !value }\n",
"some := 1\n",
"context := 1\n",
] {
assert!(parse(source).root_node().has_error(), "accepted {source}");
}
+58 -15
View File
@@ -15,6 +15,7 @@ and `value_expression` rules are hidden supertypes.
- `name` for a named declaration;
- `pattern` for a destructuring declaration;
- `binder` for the type parameters of a generic function declaration;
- `type` for an explicit type;
- `value` for an initializer.
@@ -22,6 +23,21 @@ The punctuation distinguishes immutable, mutable, typed, and deferred forms.
Consumers should inspect that punctuation rather than infer the form from the
set of fields alone.
A `binder` holds one `binder_entry` per parameter or bound. Each entry exposes
`type` and, after `:`, an optional `constraint`, which is a constraint name or
an inline `constraint_body`. A `constraint_body` (`<>{ ... }`) also appears as
the whole initializer of a `::` declaration, inside `type_definition`. It
contains `constraint_entry` nodes with `name` and `output` fields and
`constraint_spread` nodes with a `constraint` field.
## Modules
`use_declaration` contains a `module_path` and either an `alias`, an
`import_filter`, or `import_member` nodes. An `import_member` exposes `name`
and either `alias` or an `import_filter`. `import_filter` wraps the `for`
clause and exposes its `type`. `pub_declaration` contains `pub_entry` nodes,
each with a `name` and an optional `import_filter`.
## Expressions
Only expressions that actually contain an operator produce an operator node:
@@ -39,16 +55,27 @@ Precedence-only rules are hidden. For example, `a + b * -c` has one outer and
one inner `binary_expression`, then a `unary_expression`; it does not contain a
wrapper for every precedence level.
Literal leaves are named. Boolean and nil values use `boolean_literal` and
`nil_literal`; numeric, string, character, and unit literals retain their
specific nodes. `default_expression` is also named.
Pipeline stages are postfix. A same-line stage binds to the operand
immediately to its left, tighter than every prefix and infix operator, so
`-x->abs` is a `unary_expression` whose operand is a `pipeline_expression`,
and `a + b->f` is a `binary_expression` whose right operand is one. A
`pipeline_expression` is one flat node: its `input` is followed by every stage
that applies to it, same-line and continuation alike. A leading-operator
continuation applies to the complete ordinary expression on the preceding
line, so in `a + b->f` followed by a continuation `->g` the outer
`pipeline_expression` has the `binary_expression` as its `input`. A negative
literal is never a stage input: `-3->f` negates the pipeline, while a bare `-3`
remains one `signed_numeric_literal`.
`some`, `ok`, and `err` construct optional and result values. They are prefix
operators, so `some value` and `ok {x->f}` appear as `unary_expression` nodes
whose `operator` is the keyword. They bind like `-` and `~`, so `ok x->f`
wraps `x` and then pipes the result into `f`, while `ok {x->f}` wraps the
pipeline. The older `|.some`/`|.ok`/`|.err`
constructors, postfix `value!`, and prefix `!error` are no longer accepted.
Literal leaves are named. Boolean values use `boolean_literal`; numeric,
string, character, and unit literals retain their specific nodes.
`default_expression` is also named.
Optionals and results are ordinary sums. `|.none` is a `sum_constructor`, and
`value->|.some`, `value->|.ok`, and `error->|.err` are pipelines whose stage
callable is a `sum_constructor`. `sum_constructor` exposes an optional `type`
and the `variant`. The former `some`, `ok`, `err`, and `nil` keywords are
ordinary identifiers. Postfix `value!` and prefix `!error` are not accepted.
`function_literal` takes one input and owns the `body` field. A pattern with
one annotation for the whole input, such as `@ value: i32` or
@@ -66,10 +93,10 @@ may also expose `effect` (`->` or `=>`) and `result`.
## Patterns
`wrapper_pattern` matches `some`, `ok`, or `err` applied to one pattern atom.
It exposes `wrapper` (the keyword) and `value` (the inner pattern). `nil` is
still a `nil_literal` pattern. Sum patterns retain `sum_pattern` with a
`variant` field.
`sum_pattern` matches a variant, including `|.none`, `|.some pattern`,
`|.ok pattern`, and `|.err pattern`. It exposes an optional `type`, the
`variant`, and an optional `payload` pattern atom. `bits_pattern` exposes the
optional `type` as well.
## Types
@@ -84,9 +111,13 @@ Meaningful type constructors are named directly:
| `map_type` | `key`, `value` |
| `grouped_type` | `value` |
| `type_application` | `constructor` followed by its type arguments |
| `output_type` | `constructor`, `function`, `output` |
Primitive, unit, tuple, product, sum, and bits types retain their corresponding
named nodes. Internal primary/container/result categories are hidden.
`output_type` is the `Output<f: U>` spelling: a type name applied to a
function name and a type. The grammar does not check that the constructor is
spelled `Output`. Primitive, unit, tuple, product, sum, and bits types retain
their corresponding named nodes. Internal primary/container/result categories
are hidden.
## Trivia and physical lines
@@ -96,6 +127,9 @@ alongside the tree. Leading-operator and pipeline continuations use composite
tokens containing their newline; this prevents a scope separator from stealing
a valid continuation and preserves the language's physical-line rules.
The future-reserved word `context` is a `reserved_word` token that no
production accepts, so it is rejected wherever an identifier is expected.
## Compatibility
Adding nodes or fields is compatible. Removing or renaming a named node or
@@ -103,5 +137,14 @@ field, changing its meaning, or changing which source construct owns it is a
breaking CST change. Until the package reaches 1.0, such changes require corpus
snapshot updates and a version change, and must be called out in release notes.
Version 0.2.0 made these breaking changes:
- `nil_literal` and `wrapper_pattern` are gone, and `some`, `ok`, `err`, and
`nil` are no longer keywords; optionals and results use `sum_constructor`
and `sum_pattern`.
- A same-line pipeline is an operand of prefix and infix operators rather than
taking an operator expression as its `input`.
- `pub_declaration` contains `pub_entry` nodes instead of bare identifiers.
The Tree-sitter tree is designed for source tooling and error recovery; it does
not perform semantic validation.
+150 -28
View File
@@ -17,10 +17,12 @@ const PREC = {
POSTFIX: 13,
};
// Hard keywords and the primitive type names; `reserved_word` adds the
// future-reserved `context`.
const RESERVED_WORDS = [
"and", "as", "bits", "break", "continue", "default", "distinct", "else",
"err", "false", "for", "if", "in", "loop", "match", "nil", "not", "ok", "or",
"pub", "return", "some", "true", "use",
"and", "as", "bits", "break", "continue", "default", "distinct",
"else", "false", "for", "if", "in", "loop", "match", "not", "or", "pub",
"return", "true", "use",
"bit", "chr", "f32", "f64", "i8", "i16", "i32", "i64", "nvr", "str",
"u8", "u16", "u32", "u64",
];
@@ -37,7 +39,7 @@ module.exports = grammar({
extras: $ => [/[ \t]/, $.comment],
word: $ => $.identifier,
reserved: {
global: _ => RESERVED_WORDS,
global: $ => [...RESERVED_WORDS, $.reserved_word],
},
supertypes: $ => [
@@ -67,6 +69,7 @@ module.exports = grammar({
[$.product_constructor, $._scope_separator],
[$.tuple_type],
[$.type_application],
[$.binder],
[$.tuple_pattern],
[$.product_pattern],
[$.array_pattern],
@@ -87,6 +90,7 @@ module.exports = grammar({
[$.pattern_atom, $.primary_expression, $.type_name],
[$.type_name, $.qualified_name],
[$.primary_expression, $.type_name],
[$._pipeline_input_primary, $.type_name],
[$.type_expression, $.function_type],
[$.array_type, $.collection_literal],
],
@@ -110,22 +114,29 @@ module.exports = grammar({
use_declaration: $ => seq(
"use",
choice(
seq($.module_path, optional(seq("as", field("alias", $.identifier)))),
seq(
$.module_path,
optional(choice(seq("as", field("alias", $.identifier)), $.import_filter)),
),
seq($.module_path, ".", "{", listBody($, $.import_member), "}"),
),
),
import_member: $ => seq(
field("name", $.identifier),
optional(seq("as", field("alias", $.identifier))),
optional(choice(seq("as", field("alias", $.identifier)), $.import_filter)),
),
import_filter: $ => seq("for", field("type", $.type_expression)),
module_path: $ => choice(
$.type_name,
seq(choice(".", ".."), $.type_name),
),
pub_declaration: $ => seq("pub", "{", scopeBody($, $.identifier), "}"),
pub_declaration: $ => seq("pub", "{", scopeBody($, $.pub_entry), "}"),
pub_entry: $ => seq(field("name", $.identifier), optional($.import_filter)),
expression: $ => choice(
$.declaration,
@@ -161,6 +172,14 @@ module.exports = grammar({
optional(seq("=", field("value", $.value_expression))),
),
),
seq(
field("name", $.identifier),
":",
field("binder", $.binder),
field("type", $.type_expression),
":",
field("value", $.value_expression),
),
seq(
field("pattern", choice($.tuple_pattern, $.product_pattern)),
choice("::", ":="),
@@ -168,7 +187,33 @@ module.exports = grammar({
),
),
type_definition: $ => seq(optional("distinct"), $.type_expression),
binder: $ => seq("<", listBodyOneOrMore($, $.binder_entry), ">"),
binder_entry: $ => seq(
field("type", $.type_expression),
optional(seq(":", field("constraint", choice($.type_name, $.constraint_body)))),
),
type_definition: $ => choice(
seq(optional("distinct"), $.type_expression),
$.constraint_body,
),
constraint_body: $ => seq(
"<",
">",
"{",
scopeBody($, choice($.constraint_entry, $.constraint_spread)),
"}",
),
constraint_entry: $ => seq(
field("name", $.identifier),
":",
field("output", $.type_expression),
),
constraint_spread: $ => seq("...", field("constraint", $.type_name)),
type_expression: $ => choice(
$.function_type,
@@ -226,6 +271,7 @@ module.exports = grammar({
$.sum_type,
$.bits_type,
$.type_application,
$.output_type,
$.grouped_type,
),
@@ -246,6 +292,15 @@ module.exports = grammar({
">",
),
output_type: $ => seq(
field("constructor", $.type_name),
"<",
field("function", $.type_name),
":",
field("output", $.type_expression),
">",
),
product_type: $ => seq("&", "{", scopeBody($, $.product_field), "}"),
product_field: $ => seq(
@@ -383,8 +438,6 @@ module.exports = grammar({
$.string_literal,
$.character_literal,
$.boolean_literal,
$.nil_literal,
$.wrapper_pattern,
$.sum_pattern,
$.bits_pattern,
$.unit_pattern,
@@ -401,20 +454,15 @@ module.exports = grammar({
sum_pattern: $ => seq(
"|",
optional($.type_name),
optional(field("type", $.type_name)),
".",
field("variant", $.identifier),
optional($.pattern_atom),
),
wrapper_pattern: $ => seq(
field("wrapper", choice("some", "ok", "err")),
field("value", $.pattern_atom),
optional(field("payload", $.pattern_atom)),
),
bits_pattern: $ => seq(
"|",
optional($.type_name),
optional(field("type", $.type_name)),
".",
"{",
listBody($, $.identifier),
@@ -424,11 +472,58 @@ module.exports = grammar({
array_pattern: $ => seq("[", listBody($, $.array_pattern_entry), "]"),
array_pattern_entry: $ => choice($.pattern, seq("...", choice($.identifier, "_"))),
pipeline_expression: $ => prec.dynamic(1, prec.left(choice(
seq(field("input", choice($._prefix_expression, $.function_literal)), $.inline_pipeline_stage, repeat($.pipeline_stage)),
seq(field("input", choice($._non_assignment_expression, $.function_literal)), $.continuation_pipeline_stage, repeat($.pipeline_stage)),
// A pipeline headed by a leading-operator continuation applies to the
// complete ordinary expression on the preceding line. Its input excludes
// a bare same-line pipeline, which instead absorbs the continuation
// stages itself, so every pipeline is one flat node.
pipeline_expression: $ => prec.dynamic(1, prec.left(seq(
field("input", $._pipeline_head),
$.continuation_pipeline_stage,
repeat($.pipeline_stage),
))),
_pipeline_head: $ => choice(
$.range_expression,
$.binary_expression,
$.unary_expression,
$.postfix_expression,
$.primary_expression,
),
// Same-line stages are postfix: they bind to the operand immediately to
// their left, tighter than every prefix and infix operator. The static
// precedence makes a stage sequence inside an operator expression close
// before a continuation stage, which then applies to the whole
// expression. The dynamic precedence reads a category-ambiguous
// `name :: a -> b` as a pipeline rather than a function type.
_inline_pipeline_expression: $ => prec.dynamic(1, prec.left(1, seq(
field("input", choice(
$.postfix_expression,
$._pipeline_input_primary,
$.function_literal,
)),
$.inline_pipeline_stage,
repeat($.pipeline_stage),
))),
// `-3->f` negates the pipeline, so a stage input is never a negative
// literal; a bare `-3` remains one `signed_numeric_literal`.
_pipeline_input_primary: $ => choice(
$._unsigned_literal,
$.identifier,
$.block,
$.if_expression,
$.match_expression,
$.loop_expression,
$.for_expression,
$.tuple_value,
$.collection_literal,
$.product_constructor,
$.sum_constructor,
$.bits_constructor,
$.default_expression,
),
pipeline_stage: $ => choice($.inline_pipeline_stage, $.continuation_pipeline_stage),
inline_pipeline_stage: $ => choice($.direct_pipeline_stage, $.aggregate_pipeline_stage),
continuation_pipeline_stage: $ => choice(
@@ -495,6 +590,7 @@ module.exports = grammar({
_prefix_expression: $ => choice(
$.unary_expression,
alias($._inline_pipeline_expression, $.pipeline_expression),
$.postfix_expression,
$.primary_expression,
),
@@ -529,7 +625,7 @@ module.exports = grammar({
),
unary_expression: $ => prec.right(PREC.PREFIX, seq(
field("operator", choice("not", "-", "~", "some", "ok", "err")),
field("operator", choice("not", "-", "~")),
field("operand", $._prefix_expression),
)),
@@ -580,27 +676,49 @@ module.exports = grammar({
seq("...", $.expression),
),
sum_constructor: $ => seq("|", optional($.type_name), ".", $.identifier),
bits_constructor: $ => seq("|", optional($.type_name), ".", "{", listBody($, $.identifier), "}"),
sum_constructor: $ => seq(
"|",
optional(field("type", $.type_name)),
".",
field("variant", $.identifier),
),
bits_constructor: $ => seq(
"|",
optional(field("type", $.type_name)),
".",
"{",
listBody($, $.identifier),
"}",
),
literal: $ => choice(
$.signed_numeric_literal,
$.string_literal,
$.character_literal,
$.boolean_literal,
$.nil_literal,
$.unit_literal,
),
_unsigned_literal: $ => choice(
alias($._unsigned_numeric_literal, $.signed_numeric_literal),
$.string_literal,
$.character_literal,
$.boolean_literal,
$.unit_literal,
),
boolean_literal: _ => choice("true", "false"),
nil_literal: _ => "nil",
default_expression: _ => "default",
unit_literal: _ => seq("(", ")"),
signed_numeric_literal: $ => seq(optional("-"), choice(
signed_numeric_literal: $ => choice(
prec.dynamic(1, seq("-", $._unsigned_numeric_literal)),
$._unsigned_numeric_literal,
),
_unsigned_numeric_literal: $ => choice(
$.integer_literal,
$.float_literal,
alias($._trailing_dot_float, $.float_literal),
)),
),
signed_integer_literal: $ => seq(optional("-"), $.integer_literal),
integer_literal: _ => token(choice(
@@ -627,6 +745,10 @@ module.exports = grammar({
_direct_pipeline_continuation: _ => token(seq(/\r?\n[ \t]*/, "->")),
_aggregate_pipeline_continuation: _ => token(seq(/\r?\n[ \t]*/, "|>")),
_comparison_continuation: _ => token(seq(/\r?\n[ \t]*/, choice("<=", ">=", "==", "<", ">"))),
// `context` is reserved for future language use and has no production,
// so this token exists only to keep it out of identifiers.
reserved_word: _ => "context",
_newline: _ => /\r?\n/,
_newlines: $ => repeat1($._newline),
_scope_separator: $ => choice($._newlines, ";"),
+5 -4
View File
@@ -6,18 +6,15 @@
"continue"
"distinct"
"else"
"err"
"for"
"if"
"in"
"loop"
"match"
"not"
"ok"
"or"
"pub"
"return"
"some"
"use"
] @keyword
@@ -26,7 +23,6 @@
(comment) @comment
(default_expression) @keyword
(boolean_literal) @constant.builtin
(nil_literal) @constant.builtin
(string_literal) @string
(character_literal) @character
(integer_literal) @number
@@ -39,7 +35,12 @@
(product_field name: (identifier) @property)
(product_entry (identifier) @property)
(sum_variant name: (identifier) @constructor)
(sum_constructor variant: (identifier) @constructor)
(sum_pattern variant: (identifier) @constructor)
(bits_member (identifier) @constant)
(constraint_entry name: (identifier) @function)
(output_type function: (identifier) @function)
(output_type function: (qualified_name (identifier) @function .))
[
"=" "+=" "-=" "*=" "/=" "%=" "&=" "^=" "|="
+618 -105
View File
@@ -89,6 +89,9 @@
"type": "SYMBOL",
"name": "module_path"
},
{
"type": "CHOICE",
"members": [
{
"type": "CHOICE",
"members": [
@@ -109,6 +112,12 @@
}
]
},
{
"type": "SYMBOL",
"name": "import_filter"
}
]
},
{
"type": "BLANK"
}
@@ -237,6 +246,9 @@
"name": "identifier"
}
},
{
"type": "CHOICE",
"members": [
{
"type": "CHOICE",
"members": [
@@ -257,6 +269,12 @@
}
]
},
{
"type": "SYMBOL",
"name": "import_filter"
}
]
},
{
"type": "BLANK"
}
@@ -264,6 +282,23 @@
}
]
},
"import_filter": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "for"
},
{
"type": "FIELD",
"name": "type",
"content": {
"type": "SYMBOL",
"name": "type_expression"
}
}
]
},
"module_path": {
"type": "CHOICE",
"members": [
@@ -324,7 +359,7 @@
"members": [
{
"type": "SYMBOL",
"name": "identifier"
"name": "pub_entry"
},
{
"type": "REPEAT",
@@ -337,7 +372,7 @@
},
{
"type": "SYMBOL",
"name": "identifier"
"name": "pub_entry"
}
]
}
@@ -364,6 +399,31 @@
}
]
},
"pub_entry": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "name",
"content": {
"type": "SYMBOL",
"name": "identifier"
}
},
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "import_filter"
},
{
"type": "BLANK"
}
]
}
]
},
"expression": {
"type": "CHOICE",
"members": [
@@ -544,6 +604,51 @@
}
]
},
{
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "name",
"content": {
"type": "SYMBOL",
"name": "identifier"
}
},
{
"type": "STRING",
"value": ":"
},
{
"type": "FIELD",
"name": "binder",
"content": {
"type": "SYMBOL",
"name": "binder"
}
},
{
"type": "FIELD",
"name": "type",
"content": {
"type": "SYMBOL",
"name": "type_expression"
}
},
{
"type": "STRING",
"value": ":"
},
{
"type": "FIELD",
"name": "value",
"content": {
"type": "SYMBOL",
"name": "value_expression"
}
}
]
},
{
"type": "SEQ",
"members": [
@@ -589,7 +694,142 @@
}
]
},
"binder": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "<"
},
{
"type": "SEQ",
"members": [
{
"type": "REPEAT",
"content": {
"type": "SYMBOL",
"name": "_newline"
}
},
{
"type": "SYMBOL",
"name": "binder_entry"
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "REPEAT",
"content": {
"type": "SYMBOL",
"name": "_newline"
}
}
]
},
{
"type": "SYMBOL",
"name": "_newlines"
}
]
},
{
"type": "SYMBOL",
"name": "binder_entry"
}
]
}
},
{
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "BLANK"
}
]
},
{
"type": "REPEAT",
"content": {
"type": "SYMBOL",
"name": "_newline"
}
}
]
},
{
"type": "STRING",
"value": ">"
}
]
},
"binder_entry": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "type",
"content": {
"type": "SYMBOL",
"name": "type_expression"
}
},
{
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": ":"
},
{
"type": "FIELD",
"name": "constraint",
"content": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "type_name"
},
{
"type": "SYMBOL",
"name": "constraint_body"
}
]
}
}
]
},
{
"type": "BLANK"
}
]
}
]
},
"type_definition": {
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
@@ -610,6 +850,145 @@
}
]
},
{
"type": "SYMBOL",
"name": "constraint_body"
}
]
},
"constraint_body": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "<"
},
{
"type": "STRING",
"value": ">"
},
{
"type": "STRING",
"value": "{"
},
{
"type": "SEQ",
"members": [
{
"type": "REPEAT",
"content": {
"type": "SYMBOL",
"name": "_newline"
}
},
{
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "constraint_entry"
},
{
"type": "SYMBOL",
"name": "constraint_spread"
}
]
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_scope_separator"
},
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "constraint_entry"
},
{
"type": "SYMBOL",
"name": "constraint_spread"
}
]
}
]
}
},
{
"type": "REPEAT",
"content": {
"type": "SYMBOL",
"name": "_newline"
}
}
]
},
{
"type": "BLANK"
}
]
}
]
},
{
"type": "STRING",
"value": "}"
}
]
},
"constraint_entry": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "name",
"content": {
"type": "SYMBOL",
"name": "identifier"
}
},
{
"type": "STRING",
"value": ":"
},
{
"type": "FIELD",
"name": "output",
"content": {
"type": "SYMBOL",
"name": "type_expression"
}
}
]
},
"constraint_spread": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "..."
},
{
"type": "FIELD",
"name": "constraint",
"content": {
"type": "SYMBOL",
"name": "type_name"
}
}
]
},
"type_expression": {
"type": "CHOICE",
"members": [
@@ -837,6 +1216,10 @@
"type": "SYMBOL",
"name": "type_application"
},
{
"type": "SYMBOL",
"name": "output_type"
},
{
"type": "SYMBOL",
"name": "grouped_type"
@@ -1097,6 +1480,47 @@
}
]
},
"output_type": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "constructor",
"content": {
"type": "SYMBOL",
"name": "type_name"
}
},
{
"type": "STRING",
"value": "<"
},
{
"type": "FIELD",
"name": "function",
"content": {
"type": "SYMBOL",
"name": "type_name"
}
},
{
"type": "STRING",
"value": ":"
},
{
"type": "FIELD",
"name": "output",
"content": {
"type": "SYMBOL",
"name": "type_expression"
}
},
{
"type": "STRING",
"value": ">"
}
]
},
"product_type": {
"type": "SEQ",
"members": [
@@ -2434,14 +2858,6 @@
"type": "SYMBOL",
"name": "boolean_literal"
},
{
"type": "SYMBOL",
"name": "nil_literal"
},
{
"type": "SYMBOL",
"name": "wrapper_pattern"
},
{
"type": "SYMBOL",
"name": "sum_pattern"
@@ -2734,8 +3150,12 @@
"type": "CHOICE",
"members": [
{
"type": "FIELD",
"name": "type",
"content": {
"type": "SYMBOL",
"name": "type_name"
}
},
{
"type": "BLANK"
@@ -2758,8 +3178,12 @@
"type": "CHOICE",
"members": [
{
"type": "FIELD",
"name": "payload",
"content": {
"type": "SYMBOL",
"name": "pattern_atom"
}
},
{
"type": "BLANK"
@@ -2768,40 +3192,6 @@
}
]
},
"wrapper_pattern": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "wrapper",
"content": {
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "some"
},
{
"type": "STRING",
"value": "ok"
},
{
"type": "STRING",
"value": "err"
}
]
}
},
{
"type": "FIELD",
"name": "value",
"content": {
"type": "SYMBOL",
"name": "pattern_atom"
}
}
]
},
"bits_pattern": {
"type": "SEQ",
"members": [
@@ -2813,8 +3203,12 @@
"type": "CHOICE",
"members": [
{
"type": "FIELD",
"name": "type",
"content": {
"type": "SYMBOL",
"name": "type_name"
}
},
{
"type": "BLANK"
@@ -3056,9 +3450,63 @@
"type": "PREC_LEFT",
"value": 0,
"content": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "input",
"content": {
"type": "SYMBOL",
"name": "_pipeline_head"
}
},
{
"type": "SYMBOL",
"name": "continuation_pipeline_stage"
},
{
"type": "REPEAT",
"content": {
"type": "SYMBOL",
"name": "pipeline_stage"
}
}
]
}
}
},
"_pipeline_head": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "range_expression"
},
{
"type": "SYMBOL",
"name": "binary_expression"
},
{
"type": "SYMBOL",
"name": "unary_expression"
},
{
"type": "SYMBOL",
"name": "postfix_expression"
},
{
"type": "SYMBOL",
"name": "primary_expression"
}
]
},
"_inline_pipeline_expression": {
"type": "PREC_DYNAMIC",
"value": 1,
"content": {
"type": "PREC_LEFT",
"value": 1,
"content": {
"type": "SEQ",
"members": [
{
@@ -3069,7 +3517,11 @@
"members": [
{
"type": "SYMBOL",
"name": "_prefix_expression"
"name": "postfix_expression"
},
{
"type": "SYMBOL",
"name": "_pipeline_input_primary"
},
{
"type": "SYMBOL",
@@ -3090,43 +3542,65 @@
}
}
]
}
}
},
{
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "input",
"content": {
"_pipeline_input_primary": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_non_assignment_expression"
"name": "_unsigned_literal"
},
{
"type": "SYMBOL",
"name": "function_literal"
}
]
}
"name": "identifier"
},
{
"type": "SYMBOL",
"name": "continuation_pipeline_stage"
"name": "block"
},
{
"type": "REPEAT",
"content": {
"type": "SYMBOL",
"name": "pipeline_stage"
}
"name": "if_expression"
},
{
"type": "SYMBOL",
"name": "match_expression"
},
{
"type": "SYMBOL",
"name": "loop_expression"
},
{
"type": "SYMBOL",
"name": "for_expression"
},
{
"type": "SYMBOL",
"name": "tuple_value"
},
{
"type": "SYMBOL",
"name": "collection_literal"
},
{
"type": "SYMBOL",
"name": "product_constructor"
},
{
"type": "SYMBOL",
"name": "sum_constructor"
},
{
"type": "SYMBOL",
"name": "bits_constructor"
},
{
"type": "SYMBOL",
"name": "default_expression"
}
]
}
]
}
}
},
"pipeline_stage": {
"type": "CHOICE",
@@ -3607,6 +4081,15 @@
"type": "SYMBOL",
"name": "unary_expression"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_inline_pipeline_expression"
},
"named": true,
"value": "pipeline_expression"
},
{
"type": "SYMBOL",
"name": "postfix_expression"
@@ -4324,18 +4807,6 @@
{
"type": "STRING",
"value": "~"
},
{
"type": "STRING",
"value": "some"
},
{
"type": "STRING",
"value": "ok"
},
{
"type": "STRING",
"value": "err"
}
]
}
@@ -4879,8 +5350,12 @@
"type": "CHOICE",
"members": [
{
"type": "FIELD",
"name": "type",
"content": {
"type": "SYMBOL",
"name": "type_name"
}
},
{
"type": "BLANK"
@@ -4892,9 +5367,13 @@
"value": "."
},
{
"type": "FIELD",
"name": "variant",
"content": {
"type": "SYMBOL",
"name": "identifier"
}
}
]
},
"bits_constructor": {
@@ -4908,8 +5387,12 @@
"type": "CHOICE",
"members": [
{
"type": "FIELD",
"name": "type",
"content": {
"type": "SYMBOL",
"name": "type_name"
}
},
{
"type": "BLANK"
@@ -5036,7 +5519,33 @@
},
{
"type": "SYMBOL",
"name": "nil_literal"
"name": "unit_literal"
}
]
},
"_unsigned_literal": {
"type": "CHOICE",
"members": [
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_unsigned_numeric_literal"
},
"named": true,
"value": "signed_numeric_literal"
},
{
"type": "SYMBOL",
"name": "string_literal"
},
{
"type": "SYMBOL",
"name": "character_literal"
},
{
"type": "SYMBOL",
"name": "boolean_literal"
},
{
"type": "SYMBOL",
@@ -5057,10 +5566,6 @@
}
]
},
"nil_literal": {
"type": "STRING",
"value": "nil"
},
"default_expression": {
"type": "STRING",
"value": "default"
@@ -5079,21 +5584,32 @@
]
},
"signed_numeric_literal": {
"type": "SEQ",
"type": "CHOICE",
"members": [
{
"type": "CHOICE",
"type": "PREC_DYNAMIC",
"value": 1,
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "-"
},
{
"type": "BLANK"
"type": "SYMBOL",
"name": "_unsigned_numeric_literal"
}
]
}
},
{
"type": "SYMBOL",
"name": "_unsigned_numeric_literal"
}
]
},
{
"_unsigned_numeric_literal": {
"type": "CHOICE",
"members": [
{
@@ -5114,8 +5630,6 @@
"value": "float_literal"
}
]
}
]
},
"signed_integer_literal": {
"type": "SEQ",
@@ -5323,6 +5837,10 @@
]
}
},
"reserved_word": {
"type": "STRING",
"value": "context"
},
"_newline": {
"type": "PATTERN",
"value": "\\r?\\n"
@@ -5403,6 +5921,9 @@
[
"type_application"
],
[
"binder"
],
[
"tuple_pattern"
],
@@ -5479,6 +6000,10 @@
"primary_expression",
"type_name"
],
[
"_pipeline_input_primary",
"type_name"
],
[
"type_expression",
"function_type"
@@ -5551,10 +6076,6 @@
"type": "STRING",
"value": "else"
},
{
"type": "STRING",
"value": "err"
},
{
"type": "STRING",
"value": "false"
@@ -5579,18 +6100,10 @@
"type": "STRING",
"value": "match"
},
{
"type": "STRING",
"value": "nil"
},
{
"type": "STRING",
"value": "not"
},
{
"type": "STRING",
"value": "ok"
},
{
"type": "STRING",
"value": "or"
@@ -5603,10 +6116,6 @@
"type": "STRING",
"value": "return"
},
{
"type": "STRING",
"value": "some"
},
{
"type": "STRING",
"value": "true"
@@ -5670,6 +6179,10 @@
{
"type": "STRING",
"value": "u64"
},
{
"type": "SYMBOL",
"name": "reserved_word"
}
]
}
+342 -89
View File
@@ -65,10 +65,6 @@
"type": "character_literal",
"named": true
},
{
"type": "nil_literal",
"named": true
},
{
"type": "signed_numeric_literal",
"named": true
@@ -129,10 +125,6 @@
"type": "identifier",
"named": true
},
{
"type": "nil_literal",
"named": true
},
{
"type": "product_pattern",
"named": true
@@ -156,10 +148,6 @@
{
"type": "unit_pattern",
"named": true
},
{
"type": "wrapper_pattern",
"named": true
}
]
},
@@ -263,6 +251,10 @@
"type": "optional_type",
"named": true
},
{
"type": "output_type",
"named": true
},
{
"type": "primitive_type",
"named": true
@@ -494,6 +486,10 @@
"type": "map_type",
"named": true
},
{
"type": "output_type",
"named": true
},
{
"type": "primitive_type",
"named": true
@@ -538,6 +534,10 @@
"type": "binary_expression",
"named": true
},
{
"type": "pipeline_expression",
"named": true
},
{
"type": "postfix_expression",
"named": true
@@ -654,6 +654,10 @@
"type": "binary_expression",
"named": true
},
{
"type": "pipeline_expression",
"named": true
},
{
"type": "postfix_expression",
"named": true
@@ -742,6 +746,10 @@
"type": "binary_expression",
"named": true
},
{
"type": "pipeline_expression",
"named": true
},
{
"type": "postfix_expression",
"named": true
@@ -759,15 +767,71 @@
}
},
{
"type": "bits_constructor",
"type": "binder",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "binder_entry",
"named": true
}
]
}
},
{
"type": "binder_entry",
"named": true,
"fields": {
"constraint": {
"multiple": false,
"required": false,
"types": [
{
"type": "constraint_body",
"named": true
},
{
"type": "type_name",
"named": true
}
]
},
"type": {
"multiple": false,
"required": true,
"types": [
{
"type": "type_expression",
"named": true
}
]
}
}
},
{
"type": "bits_constructor",
"named": true,
"fields": {
"type": {
"multiple": false,
"required": false,
"types": [
{
"type": "type_name",
"named": true
}
]
}
},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "type_name",
"type": "identifier",
"named": true
}
]
@@ -795,13 +859,24 @@
{
"type": "bits_pattern",
"named": true,
"fields": {},
"fields": {
"type": {
"multiple": false,
"required": false,
"types": [
{
"type": "type_name",
"named": true
}
]
}
},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "type_name",
"type": "identifier",
"named": true
}
]
@@ -895,6 +970,67 @@
]
}
},
{
"type": "constraint_body",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "constraint_entry",
"named": true
},
{
"type": "constraint_spread",
"named": true
}
]
}
},
{
"type": "constraint_entry",
"named": true,
"fields": {
"name": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
}
]
},
"output": {
"multiple": false,
"required": true,
"types": [
{
"type": "type_expression",
"named": true
}
]
}
}
},
{
"type": "constraint_spread",
"named": true,
"fields": {
"constraint": {
"multiple": false,
"required": true,
"types": [
{
"type": "type_name",
"named": true
}
]
}
}
},
{
"type": "continuation_pipeline_stage",
"named": true,
@@ -944,6 +1080,16 @@
"type": "declaration",
"named": true,
"fields": {
"binder": {
"multiple": false,
"required": false,
"types": [
{
"type": "binder",
"named": true
}
]
},
"name": {
"multiple": false,
"required": false,
@@ -1152,6 +1298,10 @@
"type": "optional_type",
"named": true
},
{
"type": "output_type",
"named": true
},
{
"type": "primitive_type",
"named": true
@@ -1254,6 +1404,22 @@
}
}
},
{
"type": "import_filter",
"named": true,
"fields": {
"type": {
"multiple": false,
"required": true,
"types": [
{
"type": "type_expression",
"named": true
}
]
}
}
},
{
"type": "import_member",
"named": true,
@@ -1278,6 +1444,16 @@
}
]
}
},
"children": {
"multiple": false,
"required": false,
"types": [
{
"type": "import_filter",
"named": true
}
]
}
},
{
@@ -1353,6 +1529,10 @@
"type": "map_type",
"named": true
},
{
"type": "output_type",
"named": true
},
{
"type": "primitive_type",
"named": true
@@ -1486,6 +1666,10 @@
"type": "map_type",
"named": true
},
{
"type": "output_type",
"named": true
},
{
"type": "primitive_type",
"named": true
@@ -1518,6 +1702,42 @@
}
}
},
{
"type": "output_type",
"named": true,
"fields": {
"constructor": {
"multiple": false,
"required": true,
"types": [
{
"type": "type_name",
"named": true
}
]
},
"function": {
"multiple": false,
"required": true,
"types": [
{
"type": "type_name",
"named": true
}
]
},
"output": {
"multiple": false,
"required": true,
"types": [
{
"type": "type_expression",
"named": true
}
]
}
}
},
{
"type": "pattern",
"named": true,
@@ -1564,6 +1784,14 @@
"type": "binary_expression",
"named": true
},
{
"type": "boolean_literal",
"named": true
},
{
"type": "character_literal",
"named": true
},
{
"type": "function_literal",
"named": true
@@ -1580,9 +1808,21 @@
"type": "range_expression",
"named": true
},
{
"type": "signed_numeric_literal",
"named": true
},
{
"type": "string_literal",
"named": true
},
{
"type": "unary_expression",
"named": true
},
{
"type": "unit_literal",
"named": true
}
]
}
@@ -1787,6 +2027,21 @@
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "pub_entry",
"named": true
}
]
}
},
{
"type": "pub_entry",
"named": true,
"fields": {
"name": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
@@ -1795,6 +2050,17 @@
]
}
},
"children": {
"multiple": false,
"required": false,
"types": [
{
"type": "import_filter",
"named": true
}
]
}
},
{
"type": "qualified_name",
"named": true,
@@ -1822,6 +2088,10 @@
"type": "binary_expression",
"named": true
},
{
"type": "pipeline_expression",
"named": true
},
{
"type": "postfix_expression",
"named": true
@@ -1858,6 +2128,10 @@
"type": "binary_expression",
"named": true
},
{
"type": "pipeline_expression",
"named": true
},
{
"type": "postfix_expression",
"named": true
@@ -1898,6 +2172,10 @@
"type": "map_type",
"named": true
},
{
"type": "output_type",
"named": true
},
{
"type": "primitive_type",
"named": true
@@ -1948,6 +2226,10 @@
"type": "map_type",
"named": true
},
{
"type": "output_type",
"named": true
},
{
"type": "primitive_type",
"named": true
@@ -2048,22 +2330,17 @@
{
"type": "sum_constructor",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"fields": {
"type": {
"multiple": false,
"required": false,
"types": [
{
"type": "type_name",
"named": true
}
]
}
},
{
"type": "sum_pattern",
"named": true,
"fields": {
"variant": {
"multiple": false,
"required": true,
@@ -2074,20 +2351,42 @@
}
]
}
}
},
"children": {
"multiple": true,
{
"type": "sum_pattern",
"named": true,
"fields": {
"payload": {
"multiple": false,
"required": false,
"types": [
{
"type": "pattern_atom",
"named": true
}
]
},
"type": {
"multiple": false,
"required": false,
"types": [
{
"type": "type_name",
"named": true
}
]
},
"variant": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
}
]
}
}
},
{
@@ -2224,6 +2523,10 @@
"multiple": false,
"required": true,
"types": [
{
"type": "constraint_body",
"named": true
},
{
"type": "type_expression",
"named": true
@@ -2269,6 +2572,10 @@
"type": "optional_type",
"named": true
},
{
"type": "output_type",
"named": true
},
{
"type": "primitive_type",
"named": true
@@ -2354,6 +2661,10 @@
"multiple": false,
"required": true,
"types": [
{
"type": "pipeline_expression",
"named": true
},
{
"type": "postfix_expression",
"named": true
@@ -2376,22 +2687,10 @@
"type": "-",
"named": false
},
{
"type": "err",
"named": false
},
{
"type": "not",
"named": false
},
{
"type": "ok",
"named": false
},
{
"type": "some",
"named": false
},
{
"type": "~",
"named": false
@@ -2439,6 +2738,10 @@
"multiple": true,
"required": true,
"types": [
{
"type": "import_filter",
"named": true
},
{
"type": "import_member",
"named": true
@@ -2450,40 +2753,6 @@
]
}
},
{
"type": "wrapper_pattern",
"named": true,
"fields": {
"value": {
"multiple": false,
"required": true,
"types": [
{
"type": "pattern_atom",
"named": true
}
]
},
"wrapper": {
"multiple": false,
"required": true,
"types": [
{
"type": "err",
"named": false
},
{
"type": "ok",
"named": false
},
{
"type": "some",
"named": false
}
]
}
}
},
{
"type": "!",
"named": false
@@ -2697,10 +2966,6 @@
"type": "else",
"named": false
},
{
"type": "err",
"named": false
},
{
"type": "f32",
"named": false
@@ -2761,10 +3026,6 @@
"type": "match",
"named": false
},
{
"type": "nil_literal",
"named": true
},
{
"type": "not",
"named": false
@@ -2773,10 +3034,6 @@
"type": "nvr",
"named": false
},
{
"type": "ok",
"named": false
},
{
"type": "or",
"named": false
@@ -2789,10 +3046,6 @@
"type": "return",
"named": false
},
{
"type": "some",
"named": false
},
{
"type": "str",
"named": false
+45540 -37130
View File
File diff suppressed because it is too large. Load diff
+240 -16
View File
@@ -36,7 +36,7 @@ Point :: &{
y: i32 = 0
}
point := &Point.{ x: 1; y = 2 }
maybe: []{i32?}: [nil, some 1]
maybe: []{i32?}: [|.none, 1->|.some]
---
@@ -73,11 +73,16 @@ maybe: []{i32?}: [nil, some 1]
(primitive_type))))
(collection_literal
(collection_entry
(nil_literal))
(sum_constructor
(identifier)))
(collection_entry
(unary_expression
(pipeline_expression
(signed_numeric_literal
(integer_literal)))))))
(integer_literal))
(direct_pipeline_stage
(pipeline_callable
(sum_constructor
(identifier)))))))))
==================
Control flow and patterns
@@ -302,17 +307,17 @@ unit :: @ () -> i32 { 42 }
Optional and result wrappers
==================
wrap :: @ value: i32 -> i32 ! str { ok value }
wrap :: @ value: i32 -> i32 ! str { value->|.ok }
first :: @ items: []i32 -> i32? {
match items {
[] => nil
[head, ...rest] => some head
[] => |.none
[head, ...rest] => head->|.some
}
}
unwrap :: @ result: i32 ! str -> i32 {
match result {
ok value => value
err _ => 0
|.ok value => value
|.err _ => 0
}
}
@@ -329,8 +334,12 @@ unwrap :: @ result: i32 ! str -> i32 {
(primitive_type)
(primitive_type))
(block
(unary_expression
(identifier)))))
(pipeline_expression
(identifier)
(direct_pipeline_stage
(pipeline_callable
(sum_constructor
(identifier))))))))
(declaration
(identifier)
(function_literal
@@ -346,7 +355,8 @@ unwrap :: @ result: i32 ! str -> i32 {
(match_arm
(pattern
(array_pattern))
(nil_literal))
(sum_constructor
(identifier)))
(match_arm
(pattern
(array_pattern
@@ -355,8 +365,12 @@ unwrap :: @ result: i32 ! str -> i32 {
(identifier)))
(array_pattern_entry
(identifier))))
(unary_expression
(identifier)))))))
(pipeline_expression
(identifier)
(direct_pipeline_stage
(pipeline_callable
(sum_constructor
(identifier))))))))))
(declaration
(identifier)
(function_literal
@@ -371,12 +385,14 @@ unwrap :: @ result: i32 ! str -> i32 {
(identifier)
(match_arm
(pattern
(wrapper_pattern
(sum_pattern
(identifier)
(identifier)))
(identifier))
(match_arm
(pattern
(wrapper_pattern))
(sum_pattern
(identifier)))
(signed_numeric_literal
(integer_literal))))))))
@@ -433,3 +449,211 @@ mixed :: @ (left: i32, right) -> i32 { left + right }
(binary_expression
(identifier)
(identifier))))))
==================
Postfix pipeline stages
==================
mixed :: -3->add_ten + 2 * 3->double - {1 + 1}->double
checked :: not c->is_digit
unwrapped :: input->fallible?->next
---
(source_file
(declaration
(identifier)
(binary_expression
(binary_expression
(unary_expression
(pipeline_expression
(signed_numeric_literal
(integer_literal))
(direct_pipeline_stage
(pipeline_callable
(identifier)))))
(binary_expression
(signed_numeric_literal
(integer_literal))
(pipeline_expression
(signed_numeric_literal
(integer_literal))
(direct_pipeline_stage
(pipeline_callable
(identifier))))))
(pipeline_expression
(block
(binary_expression
(signed_numeric_literal
(integer_literal))
(signed_numeric_literal
(integer_literal))))
(direct_pipeline_stage
(pipeline_callable
(identifier))))))
(declaration
(identifier)
(unary_expression
(pipeline_expression
(identifier)
(direct_pipeline_stage
(pipeline_callable
(identifier))))))
(declaration
(identifier)
(pipeline_expression
(identifier)
(direct_pipeline_stage
(pipeline_callable
(identifier)))
(direct_pipeline_stage
(pipeline_callable
(identifier))))))
==================
Continuations after same-line stages
==================
flat := value->first->second
->third
whole := a + b->f
->g
---
(source_file
(declaration
(identifier)
(pipeline_expression
(identifier)
(direct_pipeline_stage
(pipeline_callable
(identifier)))
(direct_pipeline_stage
(pipeline_callable
(identifier)))
(continuation_pipeline_stage
(pipeline_callable
(identifier)))))
(declaration
(identifier)
(pipeline_expression
(binary_expression
(identifier)
(pipeline_expression
(identifier)
(direct_pipeline_stage
(pipeline_callable
(identifier)))))
(continuation_pipeline_stage
(pipeline_callable
(identifier))))))
==================
Generic binders and constraints
==================
Show :: <>{
to_str: str
...Display
}
pick: <T: Show, (T, T): Ordered> (T, T) -> T: @ (first, second): (T, T) { first }
Card :: &{ label: Output<make_label: Show>: }
---
(source_file
(declaration
(identifier)
(type_definition
(constraint_body
(constraint_entry
(identifier)
(primitive_type))
(constraint_spread
(identifier)))))
(declaration
(identifier)
(binder
(binder_entry
(identifier)
(identifier))
(binder_entry
(tuple_type
(identifier)
(identifier))
(identifier)))
(function_type
(tuple_type
(identifier)
(identifier))
(identifier))
(function_literal
(typed_parameter
(tuple_pattern
(pattern
(identifier))
(pattern
(identifier)))
(tuple_type
(identifier)
(identifier)))
(block
(identifier))))
(declaration
(identifier)
(type_definition
(product_type
(product_field
(identifier)
(output_type
(identifier)
(identifier)
(identifier)))))))
==================
Import filters
==================
use math.{sqrt for f64, pi as p}
use .shapes.area for Circle
pub { area for Circle; sqrt }
---
(source_file
(use_declaration
(module_path
(identifier))
(import_member
(identifier)
(import_filter
(primitive_type)))
(import_member
(identifier)
(identifier)))
(use_declaration
(module_path
(qualified_name
(identifier)
(identifier)))
(import_filter
(identifier)))
(pub_declaration
(pub_entry
(identifier)
(import_filter
(identifier)))
(pub_entry
(identifier))))
==================
Reserved word
:error
==================
context := 1
---
-1
View File
@@ -1 +0,0 @@
value :: @ x: i32 -> i32 ! str { x! }
-1
View File
@@ -1 +0,0 @@
value :: @ x: str -> i32 ! str { !x }
-1
View File
@@ -1 +0,0 @@
ok :: @ value { value }
-1
View File
@@ -1 +0,0 @@
some := 1
-1
View File
@@ -1 +0,0 @@
value: i32?: 1->|.some
-1
View File
@@ -1 +0,0 @@
value :: @ x: i32? { match x { |.some y => y; nil => 0 } }
-1
View File
@@ -1 +0,0 @@
value :: 1 + 2->to_str
+2 -2
View File
@@ -6,8 +6,8 @@ more_codes := [...codes, 'failed' => 500]
empty_numbers: []i32: []
empty_codes: [str]i32: []
optional_numbers: []i32?: nil
optional_elements: []{i32?}: [nil, some 1]
optional_numbers: []i32?: |.none
optional_elements: []{i32?}: [|.none, 1->|.some]
Options :: &{
name: str: 'default'
+2 -2
View File
@@ -11,10 +11,10 @@ choose_block: (bit, i32, i32) -> i32: @ (condition: bit, when_true: i32, when_fa
first_positive: []i32 -> i32?: @ values: []i32 {
for value in values {
if value > 0 {
return some value
return value->|.some
}
}
nil
|.none
}
labelled_search: []i32 -> i32: @ values: []i32 { loop `outer {
+5
View File
@@ -0,0 +1,5 @@
add_ten: i32 -> i32: @ value: i32 { value + 10 }
double: i32 -> i32: @ value: i32 { value * 2 }
# Stages bind tighter than prefix and infix operators: -{3->add_ten} + 2 * {3->double}.
mixed: i32: -3->add_ten + 2 * 3->double - {1 + 1}->double
+2 -2
View File
@@ -15,9 +15,9 @@ commented := 'value' # an inline comment preserves continuation
computed := 1 + 2
->to_str
fallible: i32 -> i32 ! Error: @ value: i32 { ok value }
fallible: i32 -> i32 ! Error: @ value: i32 { value->|.ok }
propagate: i32 -> i32 ! Error: @ value: i32 {
result := {value->fallible}?
ok result
result->|.ok
}
-19
View File
@@ -1,19 +0,0 @@
use math.{pi, sqrt}
use math as m
use random.{Pcg32, pcg32, draw_u32}
use time.{Duration, TimeError, duration_neg}
use time as t
circle: f64: pi
root: f64: 4.0->sqrt
# Host overloads are selected by the operand, so the literal is typed first.
nine: f32: 9.0
qualified_root: f32: nine->m.sqrt
qualified_pi: f32: m.pi
seed: u64: 42
generator: Pcg32: seed->pcg32
draw: u32: generator->draw_u32
negate: Duration => Duration ! TimeError: duration_neg
qualified_negate: t.Duration => t.Duration ! t.TimeError: t.duration_neg
-24
View File
@@ -1,24 +0,0 @@
present: i32?: some 1
absent: i32?: nil
success: i32 ! str: ok 1
failure: i32 ! str: err 'failed'
piped: i32?: some 4->double
grouped: i32?: some {4->double}
double :: @ value { value * 2 }
describe :: @ (label: str, count) -> str { label }
unwrap_or: i32? -> i32: @ value {
match value {
some inner => inner
nil => 0
}
}
handle: i32 ! str -> i32: @ result {
match result {
ok value if value > 0 => value
ok _ => 0
err message => message->length
}
}