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
+36187 -35406

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]
fn rejects_removed_function_literal_forms() {
for source in [
"old: i32 -> i32: value@ value\n",
"old: i32 -> i32:\n@ value: i32 { value }\n",
"old :: @ value\n",
"old :: @ (value:i32) { value }\n",
"old :: @ (value:i32,) { value }\n",
"old :: @ (\nvalue:i32\n) -> i32 { value }\n",