use crate::cst::{CSTStream, Event, SyntaxKind, Utf16, Utf32, Utf8, CST};
use crate::{Parser, Span};
#[test]
fn cst_1() {
let cst: CST =
Parser::new(b"rule test { condition: true }").try_into().unwrap();
let source_file = cst.root();
assert_eq!(source_file.kind(), SyntaxKind::SOURCE_FILE);
assert_eq!(source_file.parent(), None);
assert_eq!(source_file.prev_sibling(), None);
assert_eq!(source_file.next_sibling(), None);
let rule_decl = source_file.first_child();
assert_eq!(source_file.last_child(), rule_decl);
let mut children = source_file.children();
assert_eq!(children.next(), rule_decl);
assert_eq!(children.next(), None);
let rule_decl = rule_decl.unwrap();
assert_eq!(rule_decl.parent(), Some(source_file.clone()));
let condition_blk = rule_decl.first_child();
assert_eq!(rule_decl.last_child(), condition_blk);
let condition_blk = condition_blk.unwrap();
assert_eq!(condition_blk.root(), source_file.clone());
assert_eq!(condition_blk.span(), Span(12..27));
let mut ancestors = condition_blk.ancestors();
assert_eq!(ancestors.next(), Some(rule_decl.clone()));
assert_eq!(ancestors.next(), Some(source_file.clone()));
assert_eq!(ancestors.next(), None);
let mut c = condition_blk.children_with_tokens();
assert_eq!(c.next().map(|c| c.kind()), Some(SyntaxKind::CONDITION_KW));
assert_eq!(c.next().map(|c| c.kind()), Some(SyntaxKind::COLON));
assert_eq!(c.next().map(|c| c.kind()), Some(SyntaxKind::WHITESPACE));
assert_eq!(c.next().map(|c| c.kind()), Some(SyntaxKind::BOOLEAN_EXPR));
assert_eq!(c.next().map(|c| c.kind()), None);
let mut t = condition_blk.first_token().unwrap();
assert_eq!(t.kind(), SyntaxKind::CONDITION_KW);
t = t.next_token().unwrap();
assert_eq!(t.kind(), SyntaxKind::COLON);
t = t.next_token().unwrap();
assert_eq!(t.kind(), SyntaxKind::WHITESPACE);
t = t.next_token().unwrap();
assert_eq!(t.kind(), SyntaxKind::TRUE_KW);
t = t.next_token().unwrap();
assert_eq!(t.kind(), SyntaxKind::WHITESPACE);
t = t.next_token().unwrap();
assert_eq!(t.kind(), SyntaxKind::R_BRACE);
assert_eq!(t.next_token(), None);
let mut ancestors = t.ancestors();
assert_eq!(ancestors.next(), Some(rule_decl.clone()));
assert_eq!(ancestors.next(), Some(source_file.clone()));
assert_eq!(ancestors.next(), None);
}
#[test]
fn cst_2() {
let cst: CST =
Parser::new(b"rule test { condition: true }").try_into().unwrap();
let mut c = cst.root().first_child().unwrap().children_with_tokens();
assert_eq!(c.next().map(|n| n.kind()), Some(SyntaxKind::RULE_KW));
assert_eq!(c.next().map(|n| n.kind()), Some(SyntaxKind::WHITESPACE));
assert_eq!(c.next().map(|n| n.kind()), Some(SyntaxKind::IDENT));
assert_eq!(c.next().map(|n| n.kind()), Some(SyntaxKind::WHITESPACE));
assert_eq!(c.next().map(|n| n.kind()), Some(SyntaxKind::L_BRACE));
assert_eq!(c.next().map(|n| n.kind()), Some(SyntaxKind::WHITESPACE));
assert_eq!(c.next().map(|n| n.kind()), Some(SyntaxKind::CONDITION_BLK));
assert_eq!(c.next().map(|n| n.kind()), Some(SyntaxKind::WHITESPACE));
assert_eq!(c.next().map(|n| n.kind()), Some(SyntaxKind::R_BRACE));
assert_eq!(c.next().map(|n| n.kind()), None);
let c = cst.root().first_child().unwrap().first_child_or_token().unwrap();
assert_eq!(c.parent().map(|n| n.kind()), Some(SyntaxKind::RULE_DECL));
let mut a = c.ancestors();
assert_eq!(a.next().map(|n| n.kind()), Some(SyntaxKind::RULE_DECL));
assert_eq!(a.next().map(|n| n.kind()), Some(SyntaxKind::SOURCE_FILE));
assert_eq!(a.next().map(|n| n.kind()), None);
assert_eq!(
c.next_sibling_or_token().map(|n| n.kind()),
Some(SyntaxKind::WHITESPACE)
);
let c = cst.root().first_child().unwrap().last_child_or_token().unwrap();
assert_eq!(
c.prev_sibling_or_token().map(|n| n.kind()),
Some(SyntaxKind::WHITESPACE)
);
}
#[test]
fn cst_3() {
let cst: CST =
Parser::new(b"rule test { condition: true }").try_into().unwrap();
let condition_blk =
cst.root().first_child().unwrap().first_child().unwrap();
let text = condition_blk.text();
assert!(!text.is_empty());
assert_eq!(text.len(), 15);
let chunks = text
.try_fold_chunks::<_, _, anyhow::Error>(Vec::new(), |mut acc, s| {
acc.push(s.to_string());
Ok(acc)
})
.unwrap();
assert_eq!(chunks, ["condition", ":", " ", "true"]);
let mut chunks = Vec::new();
text.for_each_chunks(|s| {
chunks.push(s.to_string());
});
assert_eq!(chunks, ["condition", ":", " ", "true"]);
let result = text.try_for_each_chunks(|s| {
if s == ":" {
anyhow::bail!("colon found")
} else {
Ok(())
}
});
assert!(result.is_err());
}
#[test]
fn cst_4() {
let cst: CST =
Parser::new(b"rule test { condition: true }").try_into().unwrap();
let source_file = cst.root().into_mut();
source_file.first_token().unwrap().detach();
assert_eq!(
source_file.first_token().map(|x| x.kind()),
Some(SyntaxKind::WHITESPACE)
);
source_file.last_token().unwrap().detach();
assert_eq!(
source_file.last_token().map(|x| x.kind()),
Some(SyntaxKind::WHITESPACE)
);
source_file.first_child_or_token().unwrap().detach();
assert_eq!(source_file.last_token().map(|x| x.kind()), None);
}
#[test]
fn cst_5() {
let cst: CST = Parser::new(
r#"rule test {
/*
Comment
*/
condition:
true or
/* 😊 */ false
}"#
.as_bytes(),
)
.try_into()
.unwrap();
let mut c = cst.root().first_child().unwrap().children_with_tokens();
let n = c.next().unwrap();
assert_eq!(n.kind(), SyntaxKind::RULE_KW);
assert_eq!(n.start_pos::<Utf32>(), (0, 0).into());
assert_eq!(n.start_pos::<Utf16>(), (0, 0).into());
assert_eq!(n.start_pos::<Utf8>(), (0, 0).into());
let n = c.next().unwrap();
assert_eq!(n.kind(), SyntaxKind::WHITESPACE);
assert_eq!(n.start_pos::<Utf32>(), (0, 4).into());
assert_eq!(n.start_pos::<Utf16>(), (0, 4).into());
assert_eq!(n.start_pos::<Utf8>(), (0, 4).into());
let n = c.next().unwrap();
assert_eq!(n.kind(), SyntaxKind::IDENT);
assert_eq!(n.start_pos::<Utf32>(), (0, 5).into());
assert_eq!(n.start_pos::<Utf16>(), (0, 5).into());
assert_eq!(n.start_pos::<Utf8>(), (0, 5).into());
let n = c.next().unwrap();
assert_eq!(n.kind(), SyntaxKind::WHITESPACE);
assert_eq!(n.start_pos::<Utf32>(), (0, 9).into());
assert_eq!(n.start_pos::<Utf16>(), (0, 9).into());
assert_eq!(n.start_pos::<Utf8>(), (0, 9).into());
let n = c.next().unwrap();
assert_eq!(n.kind(), SyntaxKind::L_BRACE);
assert_eq!(n.start_pos::<Utf32>(), (0, 10).into());
assert_eq!(n.start_pos::<Utf16>(), (0, 10).into());
assert_eq!(n.start_pos::<Utf8>(), (0, 10).into());
let n = c.next().unwrap();
assert_eq!(n.kind(), SyntaxKind::NEWLINE);
assert_eq!(n.start_pos::<Utf32>(), (0, 11).into());
assert_eq!(n.start_pos::<Utf16>(), (0, 11).into());
assert_eq!(n.start_pos::<Utf8>(), (0, 11).into());
let n = c.next().unwrap();
assert_eq!(n.kind(), SyntaxKind::WHITESPACE);
assert_eq!(n.start_pos::<Utf32>(), (1, 0).into());
assert_eq!(n.start_pos::<Utf16>(), (1, 0).into());
assert_eq!(n.start_pos::<Utf8>(), (1, 0).into());
let n = c.next().unwrap();
assert_eq!(n.kind(), SyntaxKind::COMMENT);
assert_eq!(n.start_pos::<Utf32>(), (1, 4).into());
assert_eq!(n.start_pos::<Utf16>(), (1, 4).into());
assert_eq!(n.start_pos::<Utf8>(), (1, 4).into());
assert_eq!(n.end_pos::<Utf32>(), (3, 6).into());
assert_eq!(n.end_pos::<Utf16>(), (3, 6).into());
assert_eq!(n.end_pos::<Utf8>(), (3, 6).into());
let n = c.next().unwrap();
assert_eq!(n.kind(), SyntaxKind::NEWLINE);
assert_eq!(n.start_pos::<Utf32>(), (3, 6).into());
assert_eq!(n.start_pos::<Utf16>(), (3, 6).into());
let n = c.next().unwrap();
assert_eq!(n.kind(), SyntaxKind::WHITESPACE);
assert_eq!(n.start_pos::<Utf32>(), (4, 0).into());
assert_eq!(n.start_pos::<Utf16>(), (4, 0).into());
assert_eq!(n.start_pos::<Utf8>(), (4, 0).into());
let n = c.next().unwrap();
assert_eq!(n.kind(), SyntaxKind::CONDITION_BLK);
assert_eq!(n.start_pos::<Utf32>(), (4, 4).into());
assert_eq!(n.start_pos::<Utf16>(), (4, 4).into());
assert_eq!(n.start_pos::<Utf8>(), (4, 4).into());
assert_eq!(n.end_pos::<Utf32>(), (6, 21).into());
assert_eq!(n.end_pos::<Utf16>(), (6, 22).into());
assert_eq!(n.end_pos::<Utf8>(), (6, 24).into());
let n1 = n.first_child_or_token().unwrap();
assert_eq!(n1.kind(), SyntaxKind::CONDITION_KW);
assert_eq!(n1.start_pos::<Utf32>(), (4, 4).into());
assert_eq!(n1.start_pos::<Utf16>(), (4, 4).into());
assert_eq!(n1.start_pos::<Utf8>(), (4, 4).into());
let n1 = n1.next_sibling_or_token().unwrap();
assert_eq!(n1.kind(), SyntaxKind::COLON);
assert_eq!(n1.start_pos::<Utf32>(), (4, 13).into());
assert_eq!(n1.start_pos::<Utf16>(), (4, 13).into());
assert_eq!(n1.start_pos::<Utf8>(), (4, 13).into());
let n1 = n1.next_sibling_or_token().unwrap();
assert_eq!(n1.kind(), SyntaxKind::NEWLINE);
assert_eq!(n1.start_pos::<Utf32>(), (4, 14).into());
assert_eq!(n1.start_pos::<Utf16>(), (4, 14).into());
assert_eq!(n1.start_pos::<Utf8>(), (4, 14).into());
let n1 = n1.next_sibling_or_token().unwrap();
assert_eq!(n1.kind(), SyntaxKind::WHITESPACE);
assert_eq!(n1.start_pos::<Utf32>(), (5, 0).into());
assert_eq!(n1.start_pos::<Utf16>(), (5, 0).into());
assert_eq!(n1.start_pos::<Utf8>(), (5, 0).into());
let n1 = n1.next_sibling_or_token().unwrap();
assert_eq!(n1.kind(), SyntaxKind::BOOLEAN_EXPR);
assert_eq!(n1.start_pos::<Utf32>(), (5, 8).into());
assert_eq!(n1.start_pos::<Utf16>(), (5, 8).into());
assert_eq!(n1.start_pos::<Utf8>(), (5, 8).into());
let n = c.next().unwrap();
assert_eq!(n.kind(), SyntaxKind::NEWLINE);
assert_eq!(n.start_pos::<Utf32>(), (6, 21).into());
assert_eq!(n.start_pos::<Utf16>(), (6, 22).into());
assert_eq!(n.start_pos::<Utf8>(), (6, 24).into());
assert_eq!(n.end_pos::<Utf32>(), (7, 0).into());
assert_eq!(n.end_pos::<Utf16>(), (7, 0).into());
assert_eq!(n.end_pos::<Utf8>(), (7, 0).into());
let n = c.next().unwrap();
assert_eq!(n.kind(), SyntaxKind::WHITESPACE);
assert_eq!(n.start_pos::<Utf32>(), (7, 0).into());
assert_eq!(n.start_pos::<Utf16>(), (7, 0).into());
assert_eq!(n.start_pos::<Utf8>(), (7, 0).into());
let n = c.next().unwrap();
assert_eq!(n.kind(), SyntaxKind::R_BRACE);
assert_eq!(n.start_pos::<Utf32>(), (7, 4).into());
assert_eq!(n.start_pos::<Utf16>(), (7, 4).into());
assert_eq!(n.start_pos::<Utf8>(), (7, 4).into());
}
#[test]
fn cst_6() {
let cst: CST = Parser::new(
r#"rule test {
/*
Comment
*/
condition:
true or
/* 😊 */ false
}"#
.as_bytes(),
)
.try_into()
.unwrap();
let root_node = cst.root();
assert_eq!(
root_node.token_at_position::<Utf32, _>((0, 0)).unwrap().kind(),
SyntaxKind::RULE_KW
);
assert_eq!(
root_node.token_at_position::<Utf16, _>((0, 0)).unwrap().kind(),
SyntaxKind::RULE_KW
);
assert_eq!(
root_node.token_at_position::<Utf8, _>((0, 0)).unwrap().kind(),
SyntaxKind::RULE_KW
);
assert_eq!(
root_node.token_at_position::<Utf32, _>((0, 4)).unwrap().kind(),
SyntaxKind::WHITESPACE
);
assert_eq!(
root_node.token_at_position::<Utf32, _>((0, 11)).unwrap().kind(),
SyntaxKind::NEWLINE
);
assert!(root_node.token_at_position::<Utf32, _>((0, 12)).is_none());
assert_eq!(
root_node.token_at_position::<Utf32, _>((1, 4)).unwrap().kind(),
SyntaxKind::COMMENT
);
assert_eq!(
root_node.token_at_position::<Utf32, _>((2, 8)).unwrap().kind(),
SyntaxKind::COMMENT
);
assert_eq!(
root_node.token_at_position::<Utf32, _>((2, 20)).unwrap().kind(),
SyntaxKind::COMMENT
);
assert_eq!(
root_node.token_at_position::<Utf32, _>((3, 5)).unwrap().kind(),
SyntaxKind::COMMENT
);
assert_eq!(
root_node.token_at_position::<Utf32, _>((3, 6)).unwrap().kind(),
SyntaxKind::NEWLINE
);
assert_eq!(
root_node.token_at_position::<Utf32, _>((4, 4)).unwrap().kind(),
SyntaxKind::CONDITION_KW
);
assert!(root_node.token_at_position::<Utf32, _>((4, 15)).is_none());
assert_eq!(
root_node.token_at_position::<Utf32, _>((6, 16)).unwrap().kind(),
SyntaxKind::FALSE_KW
);
assert_eq!(
root_node.token_at_position::<Utf16, _>((6, 17)).unwrap().kind(),
SyntaxKind::FALSE_KW
);
assert_eq!(
root_node.token_at_position::<Utf8, _>((6, 19)).unwrap().kind(),
SyntaxKind::FALSE_KW
);
assert_eq!(
root_node.token_at_position::<Utf32, _>((6, 20)).unwrap().kind(),
SyntaxKind::FALSE_KW
);
assert_eq!(
root_node.token_at_position::<Utf16, _>((6, 21)).unwrap().kind(),
SyntaxKind::FALSE_KW
);
assert_eq!(
root_node.token_at_position::<Utf8, _>((6, 23)).unwrap().kind(),
SyntaxKind::FALSE_KW
);
assert_eq!(
root_node.token_at_position::<Utf32, _>((6, 21)).unwrap().kind(),
SyntaxKind::NEWLINE
);
assert_eq!(
root_node.token_at_position::<Utf16, _>((6, 22)).unwrap().kind(),
SyntaxKind::NEWLINE
);
assert_eq!(
root_node.token_at_position::<Utf8, _>((6, 24)).unwrap().kind(),
SyntaxKind::NEWLINE
);
}
#[test]
fn cst_stream() {
let parser = Parser::new(
br#"
rule /* comment */
test {
condition: true
}"#,
);
let mut cst = CSTStream::from(parser).comments(false);
assert_eq!(
cst.next(),
Some(Event::Begin {
kind: SyntaxKind::SOURCE_FILE,
span: Span(0..48)
})
);
assert_eq!(
cst.next(),
Some(Event::Token { kind: SyntaxKind::NEWLINE, span: Span(0..1) })
);
let mut cst = cst.newlines(false);
assert_eq!(
cst.next(),
Some(Event::Begin { kind: SyntaxKind::RULE_DECL, span: Span(1..48) })
);
assert_eq!(
cst.next(),
Some(Event::Token { kind: SyntaxKind::RULE_KW, span: Span(1..5) })
);
assert_eq!(
cst.next(),
Some(Event::Token { kind: SyntaxKind::WHITESPACE, span: Span(5..6) })
);
let mut cst = cst.whitespaces(false);
assert_eq!(
cst.next(),
Some(Event::Token { kind: SyntaxKind::IDENT, span: Span(20..24) })
);
assert_eq!(
cst.next(),
Some(Event::Token { kind: SyntaxKind::L_BRACE, span: Span(25..26) })
);
}