use brink_syntax::ast::{self, AstNode};
use crate::{Block, ChoiceSet, ChoiceSetContext, Stmt};
use super::super::backbone::BranchChild;
use super::super::backbone::classify_branch_child;
use super::super::choice::LowerChoice;
use super::super::content::{ContentAccumulator, DirectBackend};
use super::super::context::{LowerScope, LowerSink, Lowered};
use super::LowerBlock;
impl LowerBlock for ast::BranchlessCondBody {
fn lower_block(&self, scope: &LowerScope, sink: &mut impl LowerSink) -> Lowered<Block> {
let mut acc = ContentAccumulator::new(DirectBackend::new());
let mut is_multiline = false;
for child in self.syntax().children_with_tokens() {
match classify_branch_child(&child) {
BranchChild::ContentLine(cl) => {
acc.handle(&cl, scope, sink);
}
BranchChild::LogicLine(ll) => {
acc.handle(&ll, scope, sink);
}
BranchChild::TagLine(tl) => {
acc.handle(&tl, scope, sink);
}
BranchChild::DivertNode(dn) => {
acc.handle(&dn, scope, sink);
}
BranchChild::InlineLogic(il) => {
acc.handle(&il, scope, sink);
}
BranchChild::Text(t) => acc.push_text(t),
BranchChild::Glue => acc.push_glue(),
BranchChild::Escape(t) => acc.push_escape(&t),
BranchChild::Choice(c) => {
acc.flush();
if let Ok(choice) = c.lower_choice(scope, sink) {
acc.push_stmt(Stmt::ChoiceSet(Box::new(ChoiceSet {
choices: vec![choice],
continuation: Block::default(),
context: ChoiceSetContext::Inline,
depth: 0,
gather_id: None,
})));
}
}
BranchChild::Whitespace(_) | BranchChild::Trivia => {}
BranchChild::Stop => break,
BranchChild::Newline => {
let was_multiline = is_multiline;
is_multiline = true;
if acc.has_buffered_parts() {
let ends_glue = acc.ends_with_glue();
acc.flush();
if !ends_glue {
acc.push_eol();
}
} else if acc.last_was_content() || !was_multiline {
acc.push_eol();
}
}
}
}
acc.flush();
if is_multiline && acc.last_was_content() {
acc.push_eol();
}
let mut block = acc.finish();
move_trailing_into_choice_body(&mut block.stmts);
Ok(block)
}
}
fn move_trailing_into_choice_body(stmts: &mut Vec<Stmt>) {
if let Some(pos) = stmts.iter().rposition(|s| matches!(s, Stmt::ChoiceSet(_)))
&& pos < stmts.len() - 1
{
let trailing: Vec<Stmt> = stmts.drain(pos + 1..).collect();
if let Stmt::ChoiceSet(cs) = &mut stmts[pos]
&& let Some(choice) = cs.choices.last_mut()
{
choice.body.stmts.extend(trailing);
}
}
}