use std::ops::Range;
use crate::{
lexer::{self, Lexer, Token},
parser::{
ast::{Block, Element, Node, Slice, Text, TextBlock},
call::{self, CallParseContext},
ParseState,
},
SyntaxResult,
};
pub(crate) fn until<'source>(
lexer: &mut Lexer<'source>,
state: &mut ParseState,
mut span: Range<usize>,
end: &dyn Fn(&Token) -> bool,
) -> (Range<usize>, Option<Token>) {
let mut next_token: Option<Token> = None;
while let Some(t) = lexer.next() {
if t.is_newline() {
*state.line_mut() += 1;
}
if !end(&t) {
span.end = t.span().end;
} else {
next_token = Some(t);
break;
}
}
return (span, next_token);
}
pub(crate) fn text_until<'source>(
source: &'source str,
lexer: &mut Lexer<'source>,
state: &mut ParseState,
span: Range<usize>,
end: &dyn Fn(&Token) -> bool,
wrap: &dyn Fn(TextBlock<'source>) -> Node<'source>,
) -> Option<(Node<'source>, Option<Token>)> {
let text = span.end..span.end;
let open = span;
let (span, next_token) = until(lexer, state, text, end);
if let Some(ref close) = next_token {
let block = TextBlock::new(
source,
Text(source, span),
open,
close.span().clone(),
);
return Some((wrap(block), next_token));
}
None
}
pub(crate) fn raw<'source>(
source: &'source str,
lexer: &mut Lexer<'source>,
state: &mut ParseState,
span: Range<usize>,
) -> SyntaxResult<Node<'source>> {
let mut block = Block::new(source, span.clone(), true);
let call =
call::parse(source, lexer, state, span.clone(), CallParseContext::Raw)?;
if !call.is_closed() {
panic!("Raw block start tag was not terminated");
}
let start_name = call.target().as_str();
let end_span = call.close_span().clone().unwrap();
block.set_call(call);
let end = |t: &Token| match t {
Token::Block(lex, _) => match lex {
lexer::Block::EndRawBlock => true,
_ => false,
},
_ => false,
};
let wrap = |t: TextBlock<'source>| Node::Text(t.into());
let maybe_node = text_until(source, lexer, state, end_span, &end, &wrap);
if let Some((node, next_token)) = maybe_node {
let span = if let Some(token) = next_token {
match token {
Token::Block(lex, span) => match lex {
lexer::Block::EndRawBlock => span,
_ => panic!("Expecting end raw block!"),
},
_ => panic!("Expecting block token in end raw block!"),
}
} else {
panic!("Unable to get end raw block span")
};
block.push(node);
let end_tag =
call::parse(source, lexer, state, span, CallParseContext::Raw)?;
if let Some(close_span) = end_tag.close_span() {
let exit_span = end_tag.open_span().start..close_span.end;
block.exit(exit_span);
} else {
panic!("Raw block was not terminated correctly!");
}
let end_name = end_tag.target().as_str();
if start_name != end_name {
panic!(
"Raw block start '{}' does not match end name '{}'",
start_name, end_name
);
}
Ok(Node::Block(block))
} else {
panic!("Raw block was not terminated");
}
}
pub(crate) fn raw_comment<'source>(
source: &'source str,
lexer: &mut Lexer<'source>,
state: &mut ParseState,
span: Range<usize>,
) -> SyntaxResult<Node<'source>> {
let end = |t: &Token| match t {
Token::RawComment(lex, _) => match lex {
lexer::RawComment::End => true,
_ => false,
},
_ => false,
};
let wrap = |t: TextBlock<'source>| Node::RawComment(t);
let maybe_node = text_until(source, lexer, state, span, &end, &wrap);
if let Some((node, _)) = maybe_node {
return Ok(node);
} else {
panic!("Raw comment was not terminated");
}
}
pub(crate) fn raw_statement<'source>(
source: &'source str,
lexer: &mut Lexer<'source>,
state: &mut ParseState,
span: Range<usize>,
) -> SyntaxResult<Node<'source>> {
let end = |t: &Token| match t {
Token::RawStatement(lex, _) => match lex {
lexer::RawStatement::End => true,
_ => false,
},
_ => false,
};
let wrap = |t: TextBlock<'source>| Node::RawStatement(t);
let maybe_node = text_until(source, lexer, state, span, &end, &wrap);
if let Some((node, _)) = maybe_node {
return Ok(node);
} else {
panic!("Raw statement was not terminated");
}
}
pub(crate) fn comment<'source>(
source: &'source str,
lexer: &mut Lexer<'source>,
state: &mut ParseState,
span: Range<usize>,
) -> SyntaxResult<Node<'source>> {
let end = |t: &Token| match t {
Token::Comment(lex, _) => match lex {
lexer::Comment::End => true,
_ => false,
},
_ => false,
};
let wrap = |t: TextBlock<'source>| Node::Comment(t);
let maybe_node = text_until(source, lexer, state, span, &end, &wrap);
if let Some((node, _)) = maybe_node {
return Ok(node);
} else {
panic!("Comment was not terminated");
}
}
pub(crate) fn scope<'source>(
source: &'source str,
lexer: &mut Lexer<'source>,
state: &mut ParseState,
span: Range<usize>,
) -> SyntaxResult<Block<'source>> {
let mut block = Block::new(source, span.clone(), false);
let call =
call::parse(source, lexer, state, span, CallParseContext::Block)?;
block.set_call(call);
Ok(block)
}