Support some, ok and err wrappers and untyped function inputs

Track the LScript changes since the grammar was first written:

- some, ok and err are reserved prefix operators and wrapper patterns;
  the old |.some/|.ok/|.err forms and postfix/prefix ! are rejected
- function literal inputs may omit their type annotation, and tuple
  components may omit theirs; an empty typed tuple pattern is now just
  the unit pattern
- migrate fixtures, corpus, queries, CST contract and Rust tests

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
paulandClaude Sonnet 5.5 committed 2026-10-18 14:54:48 -04:00
1 parent 6e4f9cd65a
commit 61ea7166e3
20 files changed
+36068 -35287

No files matched your search

+105 -1
View File
@@ -152,12 +152,116 @@ mod tests {
} }
} }
#[test]
fn distinguishes_whole_argument_annotation_from_tuple_component_annotations() {
let source = "whole :: @ (left, right): (i32, i32) { left + right }\n\
components :: @ (left: i32, right: i32) { left + right }\n\
product :: @ {value}: &{value: i32:} { value }\n";
let tree = parse(source);
assert!(
!tree.root_node().has_error(),
"{}",
tree.root_node().to_sexp()
);
let whole = tree.root_node().named_child(0).unwrap();
let whole_function = whole.child_by_field_name("value").unwrap();
let whole_input = whole_function.child_by_field_name("parameter").unwrap();
assert_eq!(whole_input.kind(), "typed_parameter");
assert_eq!(
whole_input.child_by_field_name("pattern").unwrap().kind(),
"tuple_pattern"
);
assert_eq!(
whole_input.child_by_field_name("type").unwrap().kind(),
"tuple_type"
);
let components = tree.root_node().named_child(1).unwrap();
let components_function = components.child_by_field_name("value").unwrap();
let component_input = components_function
.child_by_field_name("parameter")
.unwrap();
assert_eq!(component_input.kind(), "typed_tuple_pattern");
assert_eq!(component_input.named_child_count(), 2);
let product = tree.root_node().named_child(2).unwrap();
let product_function = product.child_by_field_name("value").unwrap();
let product_input = product_function.child_by_field_name("parameter").unwrap();
assert_eq!(product_input.kind(), "typed_parameter");
assert_eq!(
product_input.child_by_field_name("pattern").unwrap().kind(),
"product_pattern"
);
}
#[test]
fn exposes_wrappers_and_untyped_inputs() {
let source = "present: i32?: some 1\n\
double :: @ value { value * 2 }\n\
unwrap :: @ result { match result { ok inner => inner; err _ => 0 } }\n";
let tree = parse(source);
assert!(
!tree.root_node().has_error(),
"{}",
tree.root_node().to_sexp()
);
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
.child_by_field_name("operator")
.unwrap()
.utf8_text(source.as_bytes())
.unwrap(),
"some"
);
let double = tree.root_node().named_child(1).unwrap();
let input = double
.child_by_field_name("value")
.unwrap()
.child_by_field_name("parameter")
.unwrap();
assert_eq!(input.kind(), "typed_parameter");
assert!(input.child_by_field_name("type").is_none());
let unwrap = tree.root_node().named_child(2).unwrap();
let function = unwrap.child_by_field_name("value").unwrap();
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");
assert_eq!(
wrapper
.child_by_field_name("wrapper")
.unwrap()
.utf8_text(source.as_bytes())
.unwrap(),
"ok"
);
}
#[test]
fn rejects_removed_wrapper_forms() {
for source in [
"old: i32?: 1->|.some\n",
"old :: @ value: i32 -> i32 ! str { value! }\n",
"old :: @ value: str -> i32 ! str { !value }\n",
"some := 1\n",
] {
assert!(parse(source).root_node().has_error(), "accepted {source}");
}
}
#[test] #[test]
fn rejects_removed_function_literal_forms() { fn rejects_removed_function_literal_forms() {
for source in [ for source in [
"old: i32 -> i32: value@ value\n", "old: i32 -> i32: value@ value\n",
"old: i32 -> i32:\n@ value: i32 { value }\n", "old: i32 -> i32:\n@ value: i32 { value }\n",
"old :: @ value\n",
"old :: @ (value:i32) { value }\n", "old :: @ (value:i32) { value }\n",
"old :: @ (value:i32,) { value }\n", "old :: @ (value:i32,) { value }\n",
"old :: @ (\nvalue:i32\n) -> i32 { value }\n", "old :: @ (\nvalue:i32\n) -> i32 { value }\n",
+27 -7
View File
@@ -43,13 +43,33 @@ Literal leaves are named. Boolean and nil values use `boolean_literal` and
`nil_literal`; numeric, string, character, and unit literals retain their `nil_literal`; numeric, string, character, and unit literals retain their
specific nodes. `default_expression` is also named. specific nodes. `default_expression` is also named.
`function_literal` takes one input and owns the `body` field. Direct binding `some`, `ok`, and `err` construct optional and result values. They are prefix
appears as `parameter: (typed_parameter)`; tuple destructuring appears as operators, so `some value` and `ok {x->f}` appear as `unary_expression` nodes
`parameter: (typed_tuple_pattern)`. A `typed_tuple_pattern` contains zero or at whose `operator` is the keyword. They bind like `-` and `~`, so `ok x->f`
least two `typed_tuple_component` nodes. These bind components of one tuple wraps `x` and then pipes the result into `f`, while `ok {x->f}` wraps the
input, not separate function arguments. `()` matches unit; singleton tuple pipeline. The older `|.some`/`|.ok`/`|.err`
patterns are invalid. Typed bindings expose `pattern` and `type`; a header may constructors, postfix `value!`, and prefix `!error` are no longer accepted.
also expose `effect` (`->` or `=>`) and `result`.
`function_literal` takes one input and owns the `body` field. A pattern with
one annotation for the whole input, such as `@ value: i32` or
`@ (left, right): (i32, i32)`, appears as `parameter: (typed_parameter)`.
The annotation is optional: an input whose type comes from the expected
function type, such as `@ value` or `@ (left, right)`, is also a
`typed_parameter` without a `type` field. Component-annotated tuple
destructuring, such as `@ (left: i32, right)`, appears as
`parameter: (typed_tuple_pattern)`. A `typed_tuple_pattern` contains at least
two `typed_tuple_component` nodes, each with an optional `type`. These bind
components of one tuple input, not separate function arguments. `()` matches
unit and is a `typed_parameter` over a `unit_pattern`; singleton tuple patterns
are invalid. Bindings expose `pattern` and, when annotated, `type`; a header
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.
## Types ## Types
+19 -15
View File
@@ -19,8 +19,8 @@ const PREC = {
const RESERVED_WORDS = [ const RESERVED_WORDS = [
"and", "as", "bits", "break", "continue", "default", "distinct", "else", "and", "as", "bits", "break", "continue", "default", "distinct", "else",
"false", "for", "if", "in", "loop", "match", "nil", "not", "or", "pub", "err", "false", "for", "if", "in", "loop", "match", "nil", "not", "ok", "or",
"return", "true", "use", "pub", "return", "some", "true", "use",
"bit", "chr", "f32", "f64", "i8", "i16", "i32", "i64", "nvr", "str", "bit", "chr", "f32", "f64", "i8", "i16", "i32", "i64", "nvr", "str",
"u8", "u16", "u32", "u64", "u8", "u16", "u32", "u64",
]; ];
@@ -55,6 +55,7 @@ module.exports = grammar({
], ],
conflicts: $ => [ conflicts: $ => [
[$.binding_pattern, $.pattern_atom],
[$.product_pattern_field, $.primary_expression], [$.product_pattern_field, $.primary_expression],
[$.pattern_atom, $.literal], [$.pattern_atom, $.literal],
[$.pattern_atom, $.primary_expression], [$.pattern_atom, $.primary_expression],
@@ -312,18 +313,16 @@ module.exports = grammar({
prec(1, seq("@", field("body", $.block))), prec(1, seq("@", field("body", $.block))),
), ),
typed_tuple_pattern: $ => seq("(", optional(listBodyAtLeastTwo($, $.typed_tuple_component)), ")"), typed_tuple_pattern: $ => seq("(", listBodyAtLeastTwo($, $.typed_tuple_component), ")"),
typed_parameter: $ => seq( typed_parameter: $ => prec.dynamic(1, seq(
field("pattern", $.binding_pattern), field("pattern", $.binding_pattern),
":", optional(seq(":", field("type", $._result_type))),
field("type", $._result_type), )),
),
typed_tuple_component: $ => seq( typed_tuple_component: $ => seq(
field("pattern", $.binding_pattern), field("pattern", $.binding_pattern),
":", optional(seq(":", field("type", $.type_expression))),
field("type", $.type_expression),
), ),
return_expression: $ => prec.right(seq("return", optional($.expression))), return_expression: $ => prec.right(seq("return", optional($.expression))),
@@ -385,6 +384,7 @@ module.exports = grammar({
$.character_literal, $.character_literal,
$.boolean_literal, $.boolean_literal,
$.nil_literal, $.nil_literal,
$.wrapper_pattern,
$.sum_pattern, $.sum_pattern,
$.bits_pattern, $.bits_pattern,
$.unit_pattern, $.unit_pattern,
@@ -407,6 +407,11 @@ module.exports = grammar({
optional($.pattern_atom), optional($.pattern_atom),
), ),
wrapper_pattern: $ => seq(
field("wrapper", choice("some", "ok", "err")),
field("value", $.pattern_atom),
),
bits_pattern: $ => seq( bits_pattern: $ => seq(
"|", "|",
optional($.type_name), optional($.type_name),
@@ -430,27 +435,27 @@ module.exports = grammar({
seq( seq(
$._direct_pipeline_continuation, $._direct_pipeline_continuation,
field("callable", $.pipeline_callable), field("callable", $.pipeline_callable),
repeat(choice("?", "!")), repeat("?"),
), ),
seq( seq(
$._aggregate_pipeline_continuation, $._aggregate_pipeline_continuation,
field("callable", $.aggregate_pipeline_callable), field("callable", $.aggregate_pipeline_callable),
field("arguments", $.aggregate_tail), field("arguments", $.aggregate_tail),
repeat(choice("?", "!")), repeat("?"),
), ),
), ),
direct_pipeline_stage: $ => seq( direct_pipeline_stage: $ => seq(
"->", "->",
field("callable", $.pipeline_callable), field("callable", $.pipeline_callable),
repeat(choice("?", "!")), repeat("?"),
), ),
aggregate_pipeline_stage: $ => seq( aggregate_pipeline_stage: $ => seq(
"|>", "|>",
field("callable", $.aggregate_pipeline_callable), field("callable", $.aggregate_pipeline_callable),
field("arguments", $.aggregate_tail), field("arguments", $.aggregate_tail),
repeat(choice("?", "!")), repeat("?"),
), ),
aggregate_tail: $ => choice( aggregate_tail: $ => choice(
@@ -524,7 +529,7 @@ module.exports = grammar({
), ),
unary_expression: $ => prec.right(PREC.PREFIX, seq( unary_expression: $ => prec.right(PREC.PREFIX, seq(
field("operator", choice("not", "!", "-", "~")), field("operator", choice("not", "-", "~", "some", "ok", "err")),
field("operand", $._prefix_expression), field("operand", $._prefix_expression),
)), )),
@@ -534,7 +539,6 @@ module.exports = grammar({
seq(".", field("member", $.identifier)), seq(".", field("member", $.identifier)),
seq("[", field("index", $.expression), "]"), seq("[", field("index", $.expression), "]"),
"?", "?",
"!",
))), ))),
)), )),
+4 -1
View File
@@ -6,15 +6,18 @@
"continue" "continue"
"distinct" "distinct"
"else" "else"
"err"
"for" "for"
"if" "if"
"in" "in"
"loop" "loop"
"match" "match"
"not" "not"
"ok"
"or" "or"
"pub" "pub"
"return" "return"
"some"
"use" "use"
] @keyword ] @keyword
@@ -41,6 +44,6 @@
[ [
"=" "+=" "-=" "*=" "/=" "%=" "&=" "^=" "|=" "=" "+=" "-=" "*=" "/=" "%=" "&=" "^=" "|="
"==" "<" "<=" ">" ">=" "==" "<" "<=" ">" ">="
"+" "-" "*" "/" "%" "&" "|" "^" "~" "!" "+" "-" "*" "/" "%" "&" "|" "^" "~"
"->" "=>" "|>" "..<" "..=" "@" "->" "=>" "|>" "..<" "..=" "@"
] @operator ] @operator
+96 -52
View File
@@ -1741,9 +1741,6 @@
"type": "STRING", "type": "STRING",
"value": "(" "value": "("
}, },
{
"type": "CHOICE",
"members": [
{ {
"type": "SEQ", "type": "SEQ",
"members": [ "members": [
@@ -1845,11 +1842,6 @@
} }
] ]
}, },
{
"type": "BLANK"
}
]
},
{ {
"type": "STRING", "type": "STRING",
"value": ")" "value": ")"
@@ -1857,6 +1849,9 @@
] ]
}, },
"typed_parameter": { "typed_parameter": {
"type": "PREC_DYNAMIC",
"value": 1,
"content": {
"type": "SEQ", "type": "SEQ",
"members": [ "members": [
{ {
@@ -1867,6 +1862,12 @@
"name": "binding_pattern" "name": "binding_pattern"
} }
}, },
{
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{ {
"type": "STRING", "type": "STRING",
"value": ":" "value": ":"
@@ -1881,6 +1882,14 @@
} }
] ]
}, },
{
"type": "BLANK"
}
]
}
]
}
},
"typed_tuple_component": { "typed_tuple_component": {
"type": "SEQ", "type": "SEQ",
"members": [ "members": [
@@ -1892,6 +1901,12 @@
"name": "binding_pattern" "name": "binding_pattern"
} }
}, },
{
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{ {
"type": "STRING", "type": "STRING",
"value": ":" "value": ":"
@@ -1906,6 +1921,13 @@
} }
] ]
}, },
{
"type": "BLANK"
}
]
}
]
},
"return_expression": { "return_expression": {
"type": "PREC_RIGHT", "type": "PREC_RIGHT",
"value": 0, "value": 0,
@@ -2416,6 +2438,10 @@
"type": "SYMBOL", "type": "SYMBOL",
"name": "nil_literal" "name": "nil_literal"
}, },
{
"type": "SYMBOL",
"name": "wrapper_pattern"
},
{ {
"type": "SYMBOL", "type": "SYMBOL",
"name": "sum_pattern" "name": "sum_pattern"
@@ -2742,6 +2768,40 @@
} }
] ]
}, },
"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": { "bits_pattern": {
"type": "SEQ", "type": "SEQ",
"members": [ "members": [
@@ -3115,17 +3175,8 @@
{ {
"type": "REPEAT", "type": "REPEAT",
"content": { "content": {
"type": "CHOICE",
"members": [
{
"type": "STRING", "type": "STRING",
"value": "?" "value": "?"
},
{
"type": "STRING",
"value": "!"
}
]
} }
} }
] ]
@@ -3156,17 +3207,8 @@
{ {
"type": "REPEAT", "type": "REPEAT",
"content": { "content": {
"type": "CHOICE",
"members": [
{
"type": "STRING", "type": "STRING",
"value": "?" "value": "?"
},
{
"type": "STRING",
"value": "!"
}
]
} }
} }
] ]
@@ -3191,17 +3233,8 @@
{ {
"type": "REPEAT", "type": "REPEAT",
"content": { "content": {
"type": "CHOICE",
"members": [
{
"type": "STRING", "type": "STRING",
"value": "?" "value": "?"
},
{
"type": "STRING",
"value": "!"
}
]
} }
} }
] ]
@@ -3232,17 +3265,8 @@
{ {
"type": "REPEAT", "type": "REPEAT",
"content": { "content": {
"type": "CHOICE",
"members": [
{
"type": "STRING", "type": "STRING",
"value": "?" "value": "?"
},
{
"type": "STRING",
"value": "!"
}
]
} }
} }
] ]
@@ -4293,10 +4317,6 @@
"type": "STRING", "type": "STRING",
"value": "not" "value": "not"
}, },
{
"type": "STRING",
"value": "!"
},
{ {
"type": "STRING", "type": "STRING",
"value": "-" "value": "-"
@@ -4304,6 +4324,18 @@
{ {
"type": "STRING", "type": "STRING",
"value": "~" "value": "~"
},
{
"type": "STRING",
"value": "some"
},
{
"type": "STRING",
"value": "ok"
},
{
"type": "STRING",
"value": "err"
} }
] ]
} }
@@ -4382,10 +4414,6 @@
{ {
"type": "STRING", "type": "STRING",
"value": "?" "value": "?"
},
{
"type": "STRING",
"value": "!"
} }
] ]
} }
@@ -5331,6 +5359,10 @@
} }
], ],
"conflicts": [ "conflicts": [
[
"binding_pattern",
"pattern_atom"
],
[ [
"product_pattern_field", "product_pattern_field",
"primary_expression" "primary_expression"
@@ -5519,6 +5551,10 @@
"type": "STRING", "type": "STRING",
"value": "else" "value": "else"
}, },
{
"type": "STRING",
"value": "err"
},
{ {
"type": "STRING", "type": "STRING",
"value": "false" "value": "false"
@@ -5551,6 +5587,10 @@
"type": "STRING", "type": "STRING",
"value": "not" "value": "not"
}, },
{
"type": "STRING",
"value": "ok"
},
{ {
"type": "STRING", "type": "STRING",
"value": "or" "value": "or"
@@ -5563,6 +5603,10 @@
"type": "STRING", "type": "STRING",
"value": "return" "value": "return"
}, },
{
"type": "STRING",
"value": "some"
},
{ {
"type": "STRING", "type": "STRING",
"value": "true" "value": "true"
+65 -11
View File
@@ -156,6 +156,10 @@
{ {
"type": "unit_pattern", "type": "unit_pattern",
"named": true "named": true
},
{
"type": "wrapper_pattern",
"named": true
} }
] ]
}, },
@@ -1622,10 +1626,6 @@
"multiple": true, "multiple": true,
"required": true, "required": true,
"types": [ "types": [
{
"type": "!",
"named": false
},
{ {
"type": ".", "type": ".",
"named": false "named": false
@@ -2247,7 +2247,7 @@
}, },
"type": { "type": {
"multiple": false, "multiple": false,
"required": true, "required": false,
"types": [ "types": [
{ {
"type": "array_type", "type": "array_type",
@@ -2321,7 +2321,7 @@
}, },
"type": { "type": {
"multiple": false, "multiple": false,
"required": true, "required": false,
"types": [ "types": [
{ {
"type": "type_expression", "type": "type_expression",
@@ -2337,7 +2337,7 @@
"fields": {}, "fields": {},
"children": { "children": {
"multiple": true, "multiple": true,
"required": false, "required": true,
"types": [ "types": [
{ {
"type": "typed_tuple_component", "type": "typed_tuple_component",
@@ -2372,18 +2372,26 @@
"multiple": false, "multiple": false,
"required": true, "required": true,
"types": [ "types": [
{
"type": "!",
"named": false
},
{ {
"type": "-", "type": "-",
"named": false "named": false
}, },
{
"type": "err",
"named": false
},
{ {
"type": "not", "type": "not",
"named": false "named": false
}, },
{
"type": "ok",
"named": false
},
{
"type": "some",
"named": false
},
{ {
"type": "~", "type": "~",
"named": false "named": false
@@ -2442,6 +2450,40 @@
] ]
} }
}, },
{
"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": "!", "type": "!",
"named": false "named": false
@@ -2655,6 +2697,10 @@
"type": "else", "type": "else",
"named": false "named": false
}, },
{
"type": "err",
"named": false
},
{ {
"type": "f32", "type": "f32",
"named": false "named": false
@@ -2727,6 +2773,10 @@
"type": "nvr", "type": "nvr",
"named": false "named": false
}, },
{
"type": "ok",
"named": false
},
{ {
"type": "or", "type": "or",
"named": false "named": false
@@ -2739,6 +2789,10 @@
"type": "return", "type": "return",
"named": false "named": false
}, },
{
"type": "some",
"named": false
},
{ {
"type": "str", "type": "str",
"named": false "named": false
+35492 -35188
View File
File diff suppressed because it is too large. Load diff
+207 -7
View File
@@ -36,7 +36,7 @@ Point :: &{
y: i32 = 0 y: i32 = 0
} }
point := &Point.{ x: 1; y = 2 } point := &Point.{ x: 1; y = 2 }
maybe: []{i32?}: [nil, 1->|.some] maybe: []{i32?}: [nil, some 1]
--- ---
@@ -75,13 +75,9 @@ maybe: []{i32?}: [nil, 1->|.some]
(collection_entry (collection_entry
(nil_literal)) (nil_literal))
(collection_entry (collection_entry
(pipeline_expression (unary_expression
(signed_numeric_literal (signed_numeric_literal
(integer_literal)) (integer_literal)))))))
(direct_pipeline_stage
(pipeline_callable
(sum_constructor
(identifier)))))))))
================== ==================
Control flow and patterns Control flow and patterns
@@ -157,6 +153,7 @@ ready :: first
(binary_expression (binary_expression
(identifier) (identifier)
(identifier)))) (identifier))))
================== ==================
Compact range after an integer Compact range after an integer
================== ==================
@@ -233,3 +230,206 @@ unit :: @ { () }
(function_literal (function_literal
(block (block
(unit_literal))))) (unit_literal)))))
==================
Whole-argument function patterns
==================
pair :: @ (left, right): (i32, i32) { left + right }
product :: @ {value}: &{value: i32:} { value }
callback :: @ operation: {i32 -> i32} { 1->operation }
unit :: @ () -> i32 { 42 }
---
(source_file
(declaration
(identifier)
(function_literal
(typed_parameter
(tuple_pattern
(pattern
(identifier))
(pattern
(identifier)))
(tuple_type
(primitive_type)
(primitive_type)))
(block
(binary_expression
(identifier)
(identifier)))))
(declaration
(identifier)
(function_literal
(typed_parameter
(product_pattern
(product_pattern_field
(identifier)))
(product_type
(product_field
(identifier)
(primitive_type))))
(block
(identifier))))
(declaration
(identifier)
(function_literal
(typed_parameter
(identifier)
(grouped_type
(function_type
(primitive_type)
(primitive_type))))
(block
(pipeline_expression
(signed_numeric_literal
(integer_literal))
(direct_pipeline_stage
(pipeline_callable
(identifier)))))))
(declaration
(identifier)
(function_literal
(typed_parameter
(unit_pattern))
(primitive_type)
(block
(signed_numeric_literal
(integer_literal))))))
==================
Optional and result wrappers
==================
wrap :: @ value: i32 -> i32 ! str { ok value }
first :: @ items: []i32 -> i32? {
match items {
[] => nil
[head, ...rest] => some head
}
}
unwrap :: @ result: i32 ! str -> i32 {
match result {
ok value => value
err _ => 0
}
}
---
(source_file
(declaration
(identifier)
(function_literal
(typed_parameter
(identifier)
(primitive_type))
(result_type
(primitive_type)
(primitive_type))
(block
(unary_expression
(identifier)))))
(declaration
(identifier)
(function_literal
(typed_parameter
(identifier)
(array_type
(primitive_type)))
(optional_type
(primitive_type))
(block
(match_expression
(identifier)
(match_arm
(pattern
(array_pattern))
(nil_literal))
(match_arm
(pattern
(array_pattern
(array_pattern_entry
(pattern
(identifier)))
(array_pattern_entry
(identifier))))
(unary_expression
(identifier)))))))
(declaration
(identifier)
(function_literal
(typed_parameter
(identifier)
(result_type
(primitive_type)
(primitive_type)))
(primitive_type)
(block
(match_expression
(identifier)
(match_arm
(pattern
(wrapper_pattern
(identifier)))
(identifier))
(match_arm
(pattern
(wrapper_pattern))
(signed_numeric_literal
(integer_literal))))))))
==================
Untyped function inputs
==================
double :: @ value { value * 2 }
sum: (i32, i32) -> i32: @ (left, right) { left + right }
mixed :: @ (left: i32, right) -> i32 { left + right }
---
(source_file
(declaration
(identifier)
(function_literal
(typed_parameter
(identifier))
(block
(binary_expression
(identifier)
(signed_numeric_literal
(integer_literal))))))
(declaration
(identifier)
(function_type
(tuple_type
(primitive_type)
(primitive_type))
(primitive_type))
(function_literal
(typed_parameter
(tuple_pattern
(pattern
(identifier))
(pattern
(identifier))))
(block
(binary_expression
(identifier)
(identifier)))))
(declaration
(identifier)
(function_literal
(typed_tuple_pattern
(typed_tuple_component
(identifier)
(primitive_type))
(typed_tuple_component
(identifier)))
(primitive_type)
(block
(binary_expression
(identifier)
(identifier))))))
-1
View File
@@ -1 +0,0 @@
identity :: @ value { value }
+1
View File
@@ -0,0 +1 @@
value :: @ x: i32 -> i32 ! str { x! }
+1
View File
@@ -0,0 +1 @@
value :: @ x: str -> i32 ! str { !x }
+1
View File
@@ -0,0 +1 @@
ok :: @ value { value }
+1
View File
@@ -0,0 +1 @@
some := 1
+1
View File
@@ -0,0 +1 @@
value: i32?: 1->|.some
+1
View File
@@ -0,0 +1 @@
value :: @ x: i32? { match x { |.some y => y; nil => 0 } }
+1 -1
View File
@@ -7,7 +7,7 @@ more_codes := [...codes, 'failed' => 500]
empty_numbers: []i32: [] empty_numbers: []i32: []
empty_codes: [str]i32: [] empty_codes: [str]i32: []
optional_numbers: []i32?: nil optional_numbers: []i32?: nil
optional_elements: []{i32?}: [nil, 1->|.some] optional_elements: []{i32?}: [nil, some 1]
Options :: &{ Options :: &{
name: str: 'default' name: str: 'default'
+1 -1
View File
@@ -11,7 +11,7 @@ choose_block: (bit, i32, i32) -> i32: @ (condition: bit, when_true: i32, when_fa
first_positive: []i32 -> i32?: @ values: []i32 { first_positive: []i32 -> i32?: @ values: []i32 {
for value in values { for value in values {
if value > 0 { if value > 0 {
return value->|.some return some value
} }
} }
nil nil
+2 -2
View File
@@ -15,9 +15,9 @@ commented := 'value' # an inline comment preserves continuation
computed := 1 + 2 computed := 1 + 2
->to_str ->to_str
fallible: i32 -> i32 ! Error: @ value: i32 { value! } fallible: i32 -> i32 ! Error: @ value: i32 { ok value }
propagate: i32 -> i32 ! Error: @ value: i32 { propagate: i32 -> i32 ! Error: @ value: i32 {
result := {value->fallible}? result := {value->fallible}?
result! ok result
} }
+19
View File
@@ -0,0 +1,19 @@
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
@@ -0,0 +1,24 @@
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
}
}