use crate::parser::tests::cst::{ExpectedNode, assert_equivalent};
use crate::{SyntaxKind, parse};
#[test]
fn return_bare() {
assert_equivalent(
parse("~ return\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
RETURN_STMT
}
}),
);
}
#[test]
fn return_integer() {
assert_equivalent(
parse("~ return 5\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
RETURN_STMT {
INTEGER_LIT
}
}
}),
);
}
#[test]
fn return_infix_expr() {
assert_equivalent(
parse("~ return x + 1\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
RETURN_STMT {
INFIX_EXPR {
PATH
INTEGER_LIT
}
}
}
}),
);
}
#[test]
fn return_string() {
assert_equivalent(
parse("~ return \"hello\"\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
RETURN_STMT {
STRING_LIT
}
}
}),
);
}
#[test]
fn return_boolean() {
assert_equivalent(
parse("~ return true\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
RETURN_STMT {
BOOLEAN_LIT
}
}
}),
);
}
#[test]
fn return_function_call() {
assert_equivalent(
parse("~ return foo()\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
RETURN_STMT {
FUNCTION_CALL {
IDENTIFIER
}
}
}
}),
);
}
#[test]
fn return_function_call_with_arg() {
assert_equivalent(
parse("~ return foo(1)\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
RETURN_STMT {
FUNCTION_CALL {
IDENTIFIER
ARG_LIST {
INTEGER_LIT
}
}
}
}
}),
);
}
#[test]
fn return_paren_expr() {
assert_equivalent(
parse("~ return (1 + 2)\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
RETURN_STMT {
PAREN_EXPR {
INFIX_EXPR {
INTEGER_LIT
INTEGER_LIT
}
}
}
}
}),
);
}
#[test]
fn temp_integer() {
assert_equivalent(
parse("~ temp x = 5\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
TEMP_DECL {
IDENTIFIER
INTEGER_LIT
}
}
}),
);
}
#[test]
fn temp_float() {
assert_equivalent(
parse("~ temp x = 3.14\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
TEMP_DECL {
IDENTIFIER
FLOAT_LIT
}
}
}),
);
}
#[test]
fn temp_string() {
assert_equivalent(
parse("~ temp x = \"hello\"\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
TEMP_DECL {
IDENTIFIER
STRING_LIT
}
}
}),
);
}
#[test]
fn temp_boolean() {
assert_equivalent(
parse("~ temp x = true\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
TEMP_DECL {
IDENTIFIER
BOOLEAN_LIT
}
}
}),
);
}
#[test]
fn temp_infix_expr() {
assert_equivalent(
parse("~ temp x = a + b\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
TEMP_DECL {
IDENTIFIER
INFIX_EXPR {
PATH
PATH
}
}
}
}),
);
}
#[test]
fn temp_function_call() {
assert_equivalent(
parse("~ temp x = foo(1)\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
TEMP_DECL {
IDENTIFIER
FUNCTION_CALL {
IDENTIFIER
ARG_LIST {
INTEGER_LIT
}
}
}
}
}),
);
}
#[test]
fn assign_integer() {
assert_equivalent(
parse("~ x = 10\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
ASSIGNMENT {
PATH
INTEGER_LIT
}
}
}),
);
}
#[test]
fn assign_plus_eq() {
assert_equivalent(
parse("~ x += 1\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
ASSIGNMENT {
PATH
INTEGER_LIT
}
}
}),
);
}
#[test]
fn assign_minus_eq() {
assert_equivalent(
parse("~ x -= 1\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
ASSIGNMENT {
PATH
INTEGER_LIT
}
}
}),
);
}
#[test]
fn assign_infix_expr() {
assert_equivalent(
parse("~ x = a + b\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
ASSIGNMENT {
PATH
INFIX_EXPR {
PATH
PATH
}
}
}
}),
);
}
#[test]
fn assign_function_call() {
assert_equivalent(
parse("~ x = foo()\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
ASSIGNMENT {
PATH
FUNCTION_CALL {
IDENTIFIER
}
}
}
}),
);
}
#[test]
fn assign_string() {
assert_equivalent(
parse("~ x = \"hello\"\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
ASSIGNMENT {
PATH
STRING_LIT
}
}
}),
);
}
#[test]
fn assign_list_expr() {
assert_equivalent(
parse("~ x = (a, b, c)\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
ASSIGNMENT {
PATH
LIST_EXPR {
PATH
PATH
PATH
}
}
}
}),
);
}
#[test]
fn assign_boolean() {
assert_equivalent(
parse("~ x = true\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
ASSIGNMENT {
PATH
BOOLEAN_LIT
}
}
}),
);
}
#[test]
fn bare_function_call_no_args() {
assert_equivalent(
parse("~ foo()\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
FUNCTION_CALL {
IDENTIFIER
}
}
}),
);
}
#[test]
fn bare_postfix_increment() {
assert_equivalent(
parse("~ x++\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
POSTFIX_EXPR {
PATH
}
}
}),
);
}
#[test]
fn bare_postfix_decrement() {
assert_equivalent(
parse("~ x--\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
POSTFIX_EXPR {
PATH
}
}
}),
);
}
#[test]
fn bare_function_call_with_args() {
assert_equivalent(
parse("~ foo(1, 2)\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
FUNCTION_CALL {
IDENTIFIER
ARG_LIST {
INTEGER_LIT
INTEGER_LIT
}
}
}
}),
);
}
#[test]
fn bare_function_call_path_args() {
assert_equivalent(
parse("~ foo(x, y)\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
FUNCTION_CALL {
IDENTIFIER
ARG_LIST {
PATH
PATH
}
}
}
}),
);
}
#[test]
fn inline_inner_expr_path() {
assert_equivalent(
parse("Hello {x}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
TEXT
INLINE_LOGIC {
INNER_EXPRESSION {
PATH
}
}
}
}
}),
);
}
#[test]
fn inline_inner_expr_integer() {
assert_equivalent(
parse("Hello {5}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
TEXT
INLINE_LOGIC {
INNER_EXPRESSION {
INTEGER_LIT
}
}
}
}
}),
);
}
#[test]
fn inline_inner_expr_infix() {
assert_equivalent(
parse("Hello {x + 1}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
TEXT
INLINE_LOGIC {
INNER_EXPRESSION {
INFIX_EXPR {
PATH
INTEGER_LIT
}
}
}
}
}
}),
);
}
#[test]
fn inline_inner_expr_function_call() {
assert_equivalent(
parse("Hello {greet(name)}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
TEXT
INLINE_LOGIC {
INNER_EXPRESSION {
FUNCTION_CALL {
IDENTIFIER
ARG_LIST {
PATH
}
}
}
}
}
}
}),
);
}
#[test]
fn conditional_true_only() {
assert_equivalent(
parse("{x: yes}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
CONDITIONAL_WITH_EXPR {
PATH
INLINE_BRANCHES_COND {
BRANCH_CONTENT {
TEXT
}
}
}
}
}
}
}),
);
}
#[test]
fn conditional_true_and_false() {
assert_equivalent(
parse("{x: yes|no}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
CONDITIONAL_WITH_EXPR {
PATH
INLINE_BRANCHES_COND {
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
}
}
}
}
}
}),
);
}
#[test]
fn conditional_infix_condition() {
assert_equivalent(
parse("{x > 5: big|small}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
CONDITIONAL_WITH_EXPR {
INFIX_EXPR {
PATH
INTEGER_LIT
}
INLINE_BRANCHES_COND {
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
}
}
}
}
}
}),
);
}
#[test]
fn conditional_empty() {
assert_equivalent(
parse("{x:}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
CONDITIONAL_WITH_EXPR {
PATH
INLINE_BRANCHES_COND {
BRANCH_CONTENT
}
}
}
}
}
}),
);
}
#[test]
fn conditional_true_content_false_empty() {
assert_equivalent(
parse("{x: yes|}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
CONDITIONAL_WITH_EXPR {
PATH
INLINE_BRANCHES_COND {
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT
}
}
}
}
}
}),
);
}
#[test]
fn conditional_true_empty_false_content() {
assert_equivalent(
parse("{x: |no}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
CONDITIONAL_WITH_EXPR {
PATH
INLINE_BRANCHES_COND {
BRANCH_CONTENT
BRANCH_CONTENT {
TEXT
}
}
}
}
}
}
}),
);
}
#[test]
fn conditional_content_with_spaces() {
assert_equivalent(
parse("{x: content with spaces}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
CONDITIONAL_WITH_EXPR {
PATH
INLINE_BRANCHES_COND {
BRANCH_CONTENT {
TEXT
}
}
}
}
}
}
}),
);
}
#[test]
fn conditional_nested_inline_logic() {
assert_equivalent(
parse("{x: {y}|no}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
CONDITIONAL_WITH_EXPR {
PATH
INLINE_BRANCHES_COND {
BRANCH_CONTENT {
INLINE_LOGIC {
INNER_EXPRESSION {
PATH
}
}
}
BRANCH_CONTENT {
TEXT
}
}
}
}
}
}
}),
);
}
#[test]
fn sequence_symbol_amp_three() {
assert_equivalent(
parse("{&a|b|c}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
SEQUENCE_WITH_ANNOTATION {
SEQUENCE_SYMBOL_ANNOTATION
INLINE_BRANCHES_SEQ {
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
}
}
}
}
}
}),
);
}
#[test]
fn sequence_symbol_bang() {
assert_equivalent(
parse("{!a|b}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
SEQUENCE_WITH_ANNOTATION {
SEQUENCE_SYMBOL_ANNOTATION
INLINE_BRANCHES_SEQ {
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
}
}
}
}
}
}),
);
}
#[test]
fn sequence_symbol_tilde() {
assert_equivalent(
parse("{~a|b}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
SEQUENCE_WITH_ANNOTATION {
SEQUENCE_SYMBOL_ANNOTATION
INLINE_BRANCHES_SEQ {
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
}
}
}
}
}
}),
);
}
#[test]
fn sequence_symbol_dollar() {
assert_equivalent(
parse("{$a|b}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
SEQUENCE_WITH_ANNOTATION {
SEQUENCE_SYMBOL_ANNOTATION
INLINE_BRANCHES_SEQ {
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
}
}
}
}
}
}),
);
}
#[test]
fn sequence_symbol_amp_two() {
assert_equivalent(
parse("{&a|b}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
SEQUENCE_WITH_ANNOTATION {
SEQUENCE_SYMBOL_ANNOTATION
INLINE_BRANCHES_SEQ {
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
}
}
}
}
}
}),
);
}
#[test]
fn sequence_symbol_amp_four() {
assert_equivalent(
parse("{&a|b|c|d}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
SEQUENCE_WITH_ANNOTATION {
SEQUENCE_SYMBOL_ANNOTATION
INLINE_BRANCHES_SEQ {
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
}
}
}
}
}
}),
);
}
#[test]
fn sequence_word_stopping() {
assert_equivalent(
parse("{stopping: a|b}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
SEQUENCE_WITH_ANNOTATION {
SEQUENCE_WORD_ANNOTATION
INLINE_BRANCHES_SEQ {
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
}
}
}
}
}
}),
);
}
#[test]
fn sequence_word_cycle() {
assert_equivalent(
parse("{cycle: a|b|c}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
SEQUENCE_WITH_ANNOTATION {
SEQUENCE_WORD_ANNOTATION
INLINE_BRANCHES_SEQ {
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
}
}
}
}
}
}),
);
}
#[test]
fn sequence_word_shuffle() {
assert_equivalent(
parse("{shuffle: a|b}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
SEQUENCE_WITH_ANNOTATION {
SEQUENCE_WORD_ANNOTATION
INLINE_BRANCHES_SEQ {
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
}
}
}
}
}
}),
);
}
#[test]
fn sequence_word_once() {
assert_equivalent(
parse("{once: a|b}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
SEQUENCE_WITH_ANNOTATION {
SEQUENCE_WORD_ANNOTATION
INLINE_BRANCHES_SEQ {
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
}
}
}
}
}
}),
);
}
#[test]
fn sequence_word_stopping_four() {
assert_equivalent(
parse("{stopping: a|b|c|d}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
SEQUENCE_WITH_ANNOTATION {
SEQUENCE_WORD_ANNOTATION
INLINE_BRANCHES_SEQ {
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
}
}
}
}
}
}),
);
}
#[test]
fn implicit_sequence_three() {
assert_equivalent(
parse("{a|b|c}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
IMPLICIT_SEQUENCE {
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
}
}
}
}
}),
);
}
#[test]
fn implicit_sequence_two() {
assert_equivalent(
parse("{a|b}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
IMPLICIT_SEQUENCE {
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
}
}
}
}
}),
);
}
#[test]
fn implicit_sequence_sentences() {
assert_equivalent(
parse("{Hello world.|Goodbye.}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
IMPLICIT_SEQUENCE {
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
}
}
}
}
}),
);
}
#[test]
fn implicit_sequence_five() {
assert_equivalent(
parse("{a|b|c|d|e}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
IMPLICIT_SEQUENCE {
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
}
}
}
}
}),
);
}
#[test]
fn implicit_sequence_with_spaces() {
assert_equivalent(
parse("{text with spaces|more text}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
IMPLICIT_SEQUENCE {
BRANCH_CONTENT {
TEXT
}
BRANCH_CONTENT {
TEXT
}
}
}
}
}
}),
);
}
#[test]
fn multiline_conditional_bare_branches() {
assert_equivalent(
parse("{\n- x > 5:\n Big.\n- else:\n Small.\n}\n"),
cst!(SOURCE_FILE {
MULTILINE_BLOCK {
MULTILINE_BRANCHES_COND {
MULTILINE_BRANCH_COND {
INFIX_EXPR {
PATH
INTEGER_LIT
}
MULTILINE_BRANCH_BODY {
TEXT
}
}
MULTILINE_BRANCH_COND {
MULTILINE_BRANCH_BODY {
TEXT
}
}
}
}
}),
);
}
#[test]
fn multiline_block_conditional() {
assert_equivalent(
parse("{\n- x:\n Yes.\n}\n"),
cst!(SOURCE_FILE {
MULTILINE_BLOCK {
MULTILINE_BRANCHES_COND {
MULTILINE_BRANCH_COND {
PATH
MULTILINE_BRANCH_BODY {
TEXT
}
}
}
}
}),
);
}
#[test]
fn multiline_conditional_multi_body() {
assert_equivalent(
parse("{\n- x:\n Line one.\n Line two.\n}\n"),
cst!(SOURCE_FILE {
MULTILINE_BLOCK {
MULTILINE_BRANCHES_COND {
MULTILINE_BRANCH_COND {
PATH
MULTILINE_BRANCH_BODY {
TEXT
TEXT
}
}
}
}
}),
);
}
#[test]
fn multiline_conditional_three_branches() {
assert_equivalent(
parse("{\n- x:\n A.\n- y:\n B.\n- else:\n C.\n}\n"),
cst!(SOURCE_FILE {
MULTILINE_BLOCK {
MULTILINE_BRANCHES_COND {
MULTILINE_BRANCH_COND {
PATH
MULTILINE_BRANCH_BODY {
TEXT
}
}
MULTILINE_BRANCH_COND {
PATH
MULTILINE_BRANCH_BODY {
TEXT
}
}
MULTILINE_BRANCH_COND {
MULTILINE_BRANCH_BODY {
TEXT
}
}
}
}
}),
);
}
#[test]
fn multiline_sequence_symbol() {
assert_equivalent(
parse("{&\n- first\n- second\n}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
SEQUENCE_WITH_ANNOTATION {
SEQUENCE_SYMBOL_ANNOTATION
MULTILINE_BRANCHES_SEQ {
MULTILINE_BRANCH_SEQ {
MULTILINE_BRANCH_BODY {
TEXT
}
}
MULTILINE_BRANCH_SEQ {
MULTILINE_BRANCH_BODY {
TEXT
}
}
}
}
}
}
}
}),
);
}
#[test]
fn multiline_sequence_word() {
assert_equivalent(
parse("{stopping:\n- first\n- second\n}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
SEQUENCE_WITH_ANNOTATION {
SEQUENCE_WORD_ANNOTATION
MULTILINE_BRANCHES_SEQ {
MULTILINE_BRANCH_SEQ {
MULTILINE_BRANCH_BODY {
TEXT
}
}
MULTILINE_BRANCH_SEQ {
MULTILINE_BRANCH_BODY {
TEXT
}
}
}
}
}
}
}
}),
);
}
#[test]
fn multiline_sequence_three_branches() {
assert_equivalent(
parse("{&\n- a\n- b\n- c\n}\n"),
cst!(SOURCE_FILE {
CONTENT_LINE {
MIXED_CONTENT {
INLINE_LOGIC {
SEQUENCE_WITH_ANNOTATION {
SEQUENCE_SYMBOL_ANNOTATION
MULTILINE_BRANCHES_SEQ {
MULTILINE_BRANCH_SEQ {
MULTILINE_BRANCH_BODY {
TEXT
}
}
MULTILINE_BRANCH_SEQ {
MULTILINE_BRANCH_BODY {
TEXT
}
}
MULTILINE_BRANCH_SEQ {
MULTILINE_BRANCH_BODY {
TEXT
}
}
}
}
}
}
}
}),
);
}
const LOGIC_LINE_STATEMENT_KINDS: [SyntaxKind; 3] = [
SyntaxKind::RETURN_STMT,
SyntaxKind::TEMP_DECL,
SyntaxKind::ASSIGNMENT,
];
const INLINE_LOGIC_DISPATCH_KINDS: [SyntaxKind; 5] = [
SyntaxKind::INNER_EXPRESSION,
SyntaxKind::CONDITIONAL_WITH_EXPR,
SyntaxKind::SEQUENCE_WITH_ANNOTATION,
SyntaxKind::IMPLICIT_SEQUENCE,
SyntaxKind::MULTILINE_CONDITIONAL,
];
fn assert_logic_line_uniformity(src: &str) {
let p = parse(src);
assert!(p.errors().is_empty(), "unexpected errors: {:?}", p.errors());
for node in p.syntax().descendants() {
if node.kind() == SyntaxKind::LOGIC_LINE {
let stmt_children: Vec<_> = node
.children()
.filter(|c| LOGIC_LINE_STATEMENT_KINDS.contains(&c.kind()))
.collect();
assert!(
stmt_children.len() <= 1,
"LOGIC_LINE should have at most one statement child, found {} in `{src}`:\n {:?}",
stmt_children.len(),
stmt_children
.iter()
.map(crate::SyntaxNode::kind)
.collect::<Vec<_>>(),
);
}
}
}
fn assert_inline_logic_uniformity(src: &str) {
let p = parse(src);
assert!(p.errors().is_empty(), "unexpected errors: {:?}", p.errors());
for node in p.syntax().descendants() {
if node.kind() == SyntaxKind::INLINE_LOGIC {
let dispatch_children: Vec<_> = node
.children()
.filter(|c| INLINE_LOGIC_DISPATCH_KINDS.contains(&c.kind()))
.collect();
assert_eq!(
dispatch_children.len(),
1,
"INLINE_LOGIC should have exactly one dispatch child, found {} in `{src}`:\n {:?}",
dispatch_children.len(),
dispatch_children
.iter()
.map(crate::SyntaxNode::kind)
.collect::<Vec<_>>(),
);
}
}
}
#[test]
fn uniformity_logic_line_return() {
assert_logic_line_uniformity("~ return 5\n");
}
#[test]
fn uniformity_logic_line_temp() {
assert_logic_line_uniformity("~ temp x = 5\n");
}
#[test]
fn uniformity_logic_line_assignment() {
assert_logic_line_uniformity("~ x = 10\n");
}
#[test]
fn uniformity_logic_line_bare_expr() {
assert_logic_line_uniformity("~ foo()\n");
}
#[test]
fn uniformity_logic_line_postfix() {
assert_logic_line_uniformity("~ x++\n");
}
#[test]
fn uniformity_logic_line_bare_return() {
assert_logic_line_uniformity("~ return\n");
}
#[test]
fn uniformity_inline_logic_inner_expr() {
assert_inline_logic_uniformity("Hello {x}\n");
}
#[test]
fn uniformity_inline_logic_conditional() {
assert_inline_logic_uniformity("{x: yes|no}\n");
}
#[test]
fn uniformity_inline_logic_sequence_symbol() {
assert_inline_logic_uniformity("{&a|b}\n");
}
#[test]
fn uniformity_inline_logic_sequence_word() {
assert_inline_logic_uniformity("{stopping: a|b}\n");
}
#[test]
fn uniformity_inline_logic_implicit_seq() {
assert_inline_logic_uniformity("{a|b|c}\n");
}
#[test]
fn uniformity_inline_logic_multiline_cond() {
assert_inline_logic_uniformity("Hello {\n- x:\n Yes.\n}\n");
}
fn has_kind(src: &str, kind: SyntaxKind) -> bool {
let p = parse(src);
p.syntax().descendants().any(|n| n.kind() == kind)
}
#[test]
fn exclusivity_return_has_return_stmt() {
let src = "~ return 5\n";
assert!(has_kind(src, SyntaxKind::RETURN_STMT));
assert!(!has_kind(src, SyntaxKind::TEMP_DECL));
assert!(!has_kind(src, SyntaxKind::ASSIGNMENT));
}
#[test]
fn exclusivity_temp_has_temp_decl() {
let src = "~ temp x = 5\n";
assert!(has_kind(src, SyntaxKind::TEMP_DECL));
assert!(!has_kind(src, SyntaxKind::RETURN_STMT));
assert!(!has_kind(src, SyntaxKind::ASSIGNMENT));
}
#[test]
fn exclusivity_assign_has_assignment() {
let src = "~ x = 5\n";
assert!(has_kind(src, SyntaxKind::ASSIGNMENT));
assert!(!has_kind(src, SyntaxKind::RETURN_STMT));
assert!(!has_kind(src, SyntaxKind::TEMP_DECL));
}
#[test]
fn exclusivity_bare_expr_has_no_statement() {
let src = "~ x++\n";
assert!(!has_kind(src, SyntaxKind::RETURN_STMT));
assert!(!has_kind(src, SyntaxKind::TEMP_DECL));
assert!(!has_kind(src, SyntaxKind::ASSIGNMENT));
assert!(has_kind(src, SyntaxKind::POSTFIX_EXPR));
}
#[test]
fn exclusivity_inner_expression() {
let src = "Hello {x}\n";
assert!(has_kind(src, SyntaxKind::INNER_EXPRESSION));
assert!(!has_kind(src, SyntaxKind::CONDITIONAL_WITH_EXPR));
assert!(!has_kind(src, SyntaxKind::SEQUENCE_WITH_ANNOTATION));
assert!(!has_kind(src, SyntaxKind::IMPLICIT_SEQUENCE));
}
#[test]
fn exclusivity_conditional() {
let src = "{x: y}\n";
assert!(has_kind(src, SyntaxKind::CONDITIONAL_WITH_EXPR));
assert!(!has_kind(src, SyntaxKind::INNER_EXPRESSION));
assert!(!has_kind(src, SyntaxKind::SEQUENCE_WITH_ANNOTATION));
assert!(!has_kind(src, SyntaxKind::IMPLICIT_SEQUENCE));
}
#[test]
fn exclusivity_sequence_symbol() {
let src = "{&a|b}\n";
assert!(has_kind(src, SyntaxKind::SEQUENCE_WITH_ANNOTATION));
assert!(!has_kind(src, SyntaxKind::CONDITIONAL_WITH_EXPR));
assert!(!has_kind(src, SyntaxKind::INNER_EXPRESSION));
assert!(!has_kind(src, SyntaxKind::IMPLICIT_SEQUENCE));
}
#[test]
fn exclusivity_implicit_sequence() {
let src = "{a|b}\n";
assert!(has_kind(src, SyntaxKind::IMPLICIT_SEQUENCE));
assert!(!has_kind(src, SyntaxKind::CONDITIONAL_WITH_EXPR));
assert!(!has_kind(src, SyntaxKind::SEQUENCE_WITH_ANNOTATION));
assert!(!has_kind(src, SyntaxKind::INNER_EXPRESSION));
}
#[test]
fn exclusivity_sequence_word_not_implicit() {
let src = "{stopping: a|b}\n";
assert!(has_kind(src, SyntaxKind::SEQUENCE_WITH_ANNOTATION));
assert!(!has_kind(src, SyntaxKind::IMPLICIT_SEQUENCE));
}
#[test]
fn exclusivity_multiline_conditional() {
let src = "{\n- x:\n Yes.\n}\n";
assert!(has_kind(src, SyntaxKind::MULTILINE_BLOCK));
assert!(has_kind(src, SyntaxKind::MULTILINE_BRANCHES_COND));
assert!(!has_kind(src, SyntaxKind::CONDITIONAL_WITH_EXPR));
assert!(!has_kind(src, SyntaxKind::IMPLICIT_SEQUENCE));
assert!(!has_kind(src, SyntaxKind::INNER_EXPRESSION));
}
#[test]
fn error_return_bare_is_valid() {
let src = "~ return\n";
let p = parse(src);
assert_eq!(src, p.syntax().text().to_string(), "lossless round-trip");
assert!(
p.errors().is_empty(),
"bare return should not produce errors"
);
}
#[test]
fn error_temp_missing_ident() {
let src = "~ temp = 5\n";
let p = parse(src);
assert_eq!(src, p.syntax().text().to_string(), "lossless round-trip");
assert!(
!p.errors().is_empty(),
"expected error for missing identifier in temp decl"
);
}
#[test]
fn error_unclosed_brace() {
let src = "{x:\n";
let p = parse(src);
assert_eq!(src, p.syntax().text().to_string(), "lossless round-trip");
}
#[test]
fn error_unclosed_brace_with_pipe() {
let src = "{x: yes|";
let p = parse(src);
assert_eq!(src, p.syntax().text().to_string(), "lossless round-trip");
}
#[test]
fn error_sequence_empty_branches() {
let src = "{&}\n";
let p = parse(src);
assert_eq!(src, p.syntax().text().to_string(), "lossless round-trip");
}
#[test]
fn await_infix_condition() {
assert_equivalent(
parse("~ await gold > 100\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
AWAIT_STMT {
INFIX_EXPR {
PATH
INTEGER_LIT
}
}
}
}),
);
}
#[test]
fn await_bare_name_condition() {
assert_equivalent(
parse("~ await alarm_raised\n"),
cst!(SOURCE_FILE {
LOGIC_LINE {
AWAIT_STMT {
PATH
}
}
}),
);
}