init
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
//! LScript language support for the Tree-sitter parsing library.
|
||||
|
||||
use tree_sitter_language::LanguageFn;
|
||||
|
||||
unsafe extern "C" {
|
||||
fn tree_sitter_lscript() -> *const ();
|
||||
}
|
||||
|
||||
/// The Tree-sitter language function for LScript.
|
||||
pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_lscript) };
|
||||
|
||||
/// Generated descriptions of the grammar's named node types.
|
||||
pub const NODE_TYPES: &str = include_str!("../../src/node-types.json");
|
||||
|
||||
/// The default syntax-highlighting query.
|
||||
pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm");
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
fn parse(source: &str) -> tree_sitter::Tree {
|
||||
let mut parser = tree_sitter::Parser::new();
|
||||
parser
|
||||
.set_language(&super::LANGUAGE.into())
|
||||
.expect("generated LScript grammar must load");
|
||||
parser
|
||||
.parse(source, None)
|
||||
.expect("parser must produce a tree")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn loads_and_parses_lscript() {
|
||||
let tree = parse("answer :: 42\n");
|
||||
assert!(!tree.root_node().has_error());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exposes_stable_expression_fields_without_precedence_wrappers() {
|
||||
let source = "answer := left + right * -value\n";
|
||||
let tree = parse(source);
|
||||
let declaration = tree.root_node().named_child(0).unwrap();
|
||||
let addition = declaration.child_by_field_name("value").unwrap();
|
||||
|
||||
assert_eq!(addition.kind(), "binary_expression");
|
||||
assert_eq!(
|
||||
addition
|
||||
.child_by_field_name("operator")
|
||||
.unwrap()
|
||||
.utf8_text(source.as_bytes())
|
||||
.unwrap(),
|
||||
"+"
|
||||
);
|
||||
assert_eq!(
|
||||
addition.child_by_field_name("left").unwrap().kind(),
|
||||
"identifier"
|
||||
);
|
||||
|
||||
let multiplication = addition.child_by_field_name("right").unwrap();
|
||||
assert_eq!(multiplication.kind(), "binary_expression");
|
||||
let negation = multiplication.child_by_field_name("right").unwrap();
|
||||
assert_eq!(negation.kind(), "unary_expression");
|
||||
assert_eq!(
|
||||
negation.child_by_field_name("operand").unwrap().kind(),
|
||||
"identifier"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exposes_meaningful_type_constructor_fields() {
|
||||
let source = "Transform :: []{i32?} -> [str]i32 ! Error\n";
|
||||
let tree = parse(source);
|
||||
let declaration = tree.root_node().named_child(0).unwrap();
|
||||
let definition = declaration.child_by_field_name("value").unwrap();
|
||||
let function = definition.named_child(0).unwrap();
|
||||
|
||||
assert_eq!(function.kind(), "function_type");
|
||||
assert_eq!(
|
||||
function
|
||||
.child_by_field_name("effect")
|
||||
.unwrap()
|
||||
.utf8_text(source.as_bytes())
|
||||
.unwrap(),
|
||||
"->"
|
||||
);
|
||||
assert_eq!(
|
||||
function.child_by_field_name("input").unwrap().kind(),
|
||||
"array_type"
|
||||
);
|
||||
let result = function.child_by_field_name("result").unwrap();
|
||||
assert_eq!(result.kind(), "result_type");
|
||||
assert_eq!(
|
||||
result.child_by_field_name("value").unwrap().kind(),
|
||||
"map_type"
|
||||
);
|
||||
assert_eq!(
|
||||
result.child_by_field_name("error").unwrap().kind(),
|
||||
"identifier"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exposes_typed_function_headers() {
|
||||
let source =
|
||||
"named :: @ value: i32 => i32 { value }\nadd :: @ (a: i32, b: i32) { a + b }\n";
|
||||
let tree = parse(source);
|
||||
assert!(
|
||||
!tree.root_node().has_error(),
|
||||
"{}",
|
||||
tree.root_node().to_sexp()
|
||||
);
|
||||
|
||||
let named = tree.root_node().named_child(0).unwrap();
|
||||
let function = named.child_by_field_name("value").unwrap();
|
||||
assert_eq!(function.kind(), "function_literal");
|
||||
let parameter = function.child_by_field_name("parameter").unwrap();
|
||||
assert_eq!(parameter.kind(), "typed_parameter");
|
||||
assert_eq!(
|
||||
parameter
|
||||
.child_by_field_name("pattern")
|
||||
.unwrap()
|
||||
.utf8_text(source.as_bytes())
|
||||
.unwrap(),
|
||||
"value"
|
||||
);
|
||||
assert_eq!(
|
||||
function
|
||||
.child_by_field_name("effect")
|
||||
.unwrap()
|
||||
.utf8_text(source.as_bytes())
|
||||
.unwrap(),
|
||||
"=>"
|
||||
);
|
||||
assert_eq!(
|
||||
function.child_by_field_name("result").unwrap().kind(),
|
||||
"primitive_type"
|
||||
);
|
||||
assert_eq!(
|
||||
function.child_by_field_name("body").unwrap().kind(),
|
||||
"block"
|
||||
);
|
||||
|
||||
let tuple_declaration = tree.root_node().named_child(1).unwrap();
|
||||
let tuple_function = tuple_declaration.child_by_field_name("value").unwrap();
|
||||
let tuple_input = tuple_function.child_by_field_name("parameter").unwrap();
|
||||
assert_eq!(tuple_input.kind(), "typed_tuple_pattern");
|
||||
assert!(tuple_function.child_by_field_name("parameters").is_none());
|
||||
assert_eq!(tuple_input.named_child_count(), 2);
|
||||
for index in 0..2 {
|
||||
assert_eq!(
|
||||
tuple_input.named_child(index).unwrap().kind(),
|
||||
"typed_tuple_component"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[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",
|
||||
] {
|
||||
assert!(parse(source).root_node().has_error(), "accepted {source}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn distinguishes_compact_ranges_floats_and_word_prefixes() {
|
||||
let source = "value := (item.value, 0..<limit)->slice\n\
|
||||
trailing_dot := 1.\n\
|
||||
anchor := value\n\
|
||||
android := value\n\
|
||||
order: []Item = []\n\
|
||||
ready := first\n\
|
||||
and second\n\
|
||||
or fallback\n";
|
||||
let tree = parse(source);
|
||||
|
||||
assert!(
|
||||
!tree.root_node().has_error(),
|
||||
"{}",
|
||||
tree.root_node().to_sexp()
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user