add generics
This commit is contained in:
1 parent
79533e9537
commit
2204d58102
22 files changed
+47358
-37579
No files matched your search
+150
-28
@@ -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, ";"),
|
||||
|
||||
Reference in new issue
Block a user