mod annotation;
mod brace_family;
mod choice;
mod content;
mod declaration;
mod divert;
mod element;
mod expression;
mod markup;
mod statement;
mod trivia;
use super::*;
use crate::SyntaxNode;
use crate::ast::{self, AstNode as _};
fn assert_lossless(source: &str) -> Parse {
let parsed = parse(source);
assert_eq!(parsed.syntax().text().to_string(), source);
parsed
}
fn find_child<N: crate::ast::AstNode>(node: &SyntaxNode) -> Option<N> {
node.children().find_map(N::cast)
}
fn has_node_kind(root: &SyntaxNode, kind: SyntaxKind) -> bool {
root.descendants().any(|node| node.kind() == kind)
}
fn expect_prose_body(body: Option<ast::Body>) -> ast::Block {
body.and_then(|b| match b {
ast::Body::Prose(block) => Some(block),
ast::Body::Code(_) => None,
})
.expect("expected a prose-ground (BLOCK) body")
}
fn expect_code_body(body: Option<ast::Body>) -> ast::StmtBlock {
body.and_then(|b| match b {
ast::Body::Code(block) => Some(block),
ast::Body::Prose(_) => None,
})
.expect("expected a code-ground (STMT_BLOCK) body")
}
fn has_token_kind(root: &SyntaxNode, kind: SyntaxKind) -> bool {
root.descendants_with_tokens()
.filter_map(rowan::NodeOrToken::into_token)
.any(|token| token.kind() == kind)
}
fn count_node_kind(root: &SyntaxNode, kind: SyntaxKind) -> usize {
root.descendants()
.filter(|node| node.kind() == kind)
.count()
}
fn text_run_concat(root: &SyntaxNode) -> String {
root.descendants()
.filter(|node| node.kind() == SyntaxKind::TEXT)
.map(|node| node.text().to_string())
.collect()
}
#[test]
fn empty_source_parses() {
let p = assert_lossless("");
assert_eq!(p.syntax().kind(), SyntaxKind::SOURCE_FILE);
assert!(p.errors().is_empty());
}
#[test]
fn charter_exhibit_fogg_passage_respelling() {
let src = concat!(
"flow fogg_wager() {\n",
" \"We are going on a trip,\" said Monsieur Fogg.\n",
" {?\n",
" * [The wager.] -> know_about_wager\n",
" * [I was surprised.] -> i_stared\n",
" }\n",
"}\n",
"\n",
"flow know_about_wager() {\n",
" I had heard about the wager.\n",
" -> i_stared\n",
"}\n",
"\n",
"flow i_stared() {\n",
" I stared at Monsieur Fogg.\n",
" {if know_about_wager {\n",
" <> \"But surely you are not serious?\" I demanded.\n",
" } else {\n",
" <> \"But there must be a reason for this trip,\" I observed.\n",
" }}\n",
" He said nothing in reply, merely considering his newspaper ",
"with as much thoroughness as entomologist considering his ",
"latest pinned addition.\n",
" -> END\n",
"}\n",
);
let p = assert_lossless(src);
assert!(p.errors().is_empty(), "errors: {:?}", p.errors());
assert!(has_node_kind(&p.syntax(), SyntaxKind::CHOICE_POINT));
assert!(has_node_kind(&p.syntax(), SyntaxKind::CONDITIONAL_BLOCK));
assert_eq!(count_node_kind(&p.syntax(), SyntaxKind::DIVERT_STMT), 4);
}