1use std::ops::Range;
2
3use crate::{
4 error::{ErrorInfo, SyntaxError},
5 lexer::{self, Lexer, Token},
6 parser::{
7 ast::{Block, Element, Lines, Node, Slice, Text, TextBlock},
8 call::{self, CallParseContext},
9 ParseState,
10 },
11 SyntaxResult,
12};
13
14pub(crate) fn until<'source>(
16 lexer: &mut Lexer<'source>,
17 state: &mut ParseState,
18 mut span: Range<usize>,
19 end: &dyn Fn(&Token) -> bool,
20) -> (Range<usize>, Option<Token>) {
21 let mut next_token: Option<Token> = None;
22 while let Some(t) = lexer.next() {
23 if t.is_newline() {
24 *state.line_mut() += 1;
25 }
26 if !end(&t) {
27 *state.byte_mut() = t.span().end - 1;
28 span.end = t.span().end;
29 } else {
30 next_token = Some(t);
31 break;
32 }
33 }
34 return (span, next_token);
35}
36
37pub(crate) fn text_until<'source>(
39 source: &'source str,
40 lexer: &mut Lexer<'source>,
41 state: &mut ParseState,
42 span: Range<usize>,
43 end: &dyn Fn(&Token) -> bool,
44 wrap: &dyn Fn(TextBlock<'source>) -> Node<'source>,
45) -> Option<(Node<'source>, Option<Token>)> {
46 let text = span.end..span.end;
47 let open = span;
48 let line_range = state.line_range();
49 let (span, next_token) = until(lexer, state, text, end);
50 if let Some(ref close) = next_token {
51 let mut text = Text::new(source, span, line_range);
52 text.lines_end(state.line());
53 let block = TextBlock::new(source, text, open, close.span().clone());
54 return Some((wrap(block), next_token));
55 }
56 None
57}
58
59pub(crate) fn raw<'source>(
61 source: &'source str,
62 lexer: &mut Lexer<'source>,
63 state: &mut ParseState,
64 span: Range<usize>,
65) -> SyntaxResult<Node<'source>> {
66 let mut block = Block::new(source, span.clone(), true, state.line_range());
67
68 let call =
69 call::parse(source, lexer, state, span.clone(), CallParseContext::Raw)?;
70
71 if !call.is_closed() {
72 return Err(SyntaxError::RawBlockOpenNotTerminated(
73 ErrorInfo::from((source, state)).into(),
74 ));
75 }
76
77 let end_span = call.close_span().clone().unwrap();
79
80 let open_name = call.target().as_str();
81
82 block.set_call(call);
83
84 let end = |t: &Token| match t {
85 Token::Block(lex, _) => match lex {
86 lexer::Block::EndRawBlock => true,
87 _ => false,
88 },
89 _ => false,
90 };
91
92 let wrap = |t: TextBlock<'source>| Node::Text(t.into());
93
94 let maybe_node = text_until(source, lexer, state, end_span, &end, &wrap);
95 if let Some((node, next_token)) = maybe_node {
96 let span = if let Some(token) = next_token {
97 match token {
98 Token::Block(lex, span) => match lex {
99 lexer::Block::EndRawBlock => span,
100 _ => {
101 return Err(SyntaxError::TokenEndRawBlock(
102 ErrorInfo::from((source, state)).into(),
103 ))
104 }
105 },
106 _ => {
107 return Err(SyntaxError::RawBlockNotTerminated(
108 ErrorInfo::from((source, state)).into(),
109 ))
110 }
111 }
112 } else {
113 return Err(SyntaxError::RawBlockNotTerminated(
114 ErrorInfo::from((source, state)).into(),
115 ));
116 };
117
118 block.push(node);
119
120 let end_tag =
121 call::parse(source, lexer, state, span, CallParseContext::Raw)?;
122
123 if let Some(close_span) = end_tag.close_span() {
124 let exit_span = end_tag.open_span().start..close_span.end;
125 block.exit(exit_span);
126 } else {
127 return Err(SyntaxError::RawBlockNotTerminated(
128 ErrorInfo::from((source, state)).into(),
129 ));
130 }
131
132 let end_name = end_tag.target().as_str();
133
134 if open_name != end_name {
135 let notes = vec![format!("opening name is '{}'", open_name)];
136 return Err(SyntaxError::TagNameMismatch(
137 ErrorInfo::from((source, state, notes)).into(),
138 ));
139 }
140
141 block.lines_end(state.line());
142
143 Ok(Node::Block(block))
144 } else {
145 Err(SyntaxError::RawBlockNotTerminated(
146 ErrorInfo::from((source, state)).into(),
147 ))
148 }
149}
150
151pub(crate) fn raw_comment<'source>(
153 source: &'source str,
154 lexer: &mut Lexer<'source>,
155 state: &mut ParseState,
156 span: Range<usize>,
157) -> SyntaxResult<Node<'source>> {
158 let end = |t: &Token| match t {
159 Token::RawComment(lex, _) => match lex {
160 lexer::RawComment::End => true,
161 _ => false,
162 },
163 _ => false,
164 };
165
166 let wrap = |t: TextBlock<'source>| Node::RawComment(t);
167 let maybe_node = text_until(source, lexer, state, span, &end, &wrap);
168 if let Some((node, _)) = maybe_node {
169 Ok(node)
170 } else {
171 Err(SyntaxError::RawCommentNotTerminated(
172 ErrorInfo::from((source, state)).into(),
173 ))
174 }
175}
176
177pub(crate) fn raw_statement<'source>(
179 source: &'source str,
180 lexer: &mut Lexer<'source>,
181 state: &mut ParseState,
182 span: Range<usize>,
183) -> SyntaxResult<Node<'source>> {
184 let end = |t: &Token| match t {
185 Token::RawStatement(lex, _) => match lex {
186 lexer::RawStatement::End => true,
187 _ => false,
188 },
189 _ => false,
190 };
191
192 let wrap = |t: TextBlock<'source>| Node::RawStatement(t);
193 let maybe_node = text_until(source, lexer, state, span, &end, &wrap);
194 if let Some((node, _)) = maybe_node {
195 Ok(node)
196 } else {
197 Err(SyntaxError::RawStatementNotTerminated(
198 ErrorInfo::from((source, state)).into(),
199 ))
200 }
201}
202
203pub(crate) fn comment<'source>(
205 source: &'source str,
206 lexer: &mut Lexer<'source>,
207 state: &mut ParseState,
208 span: Range<usize>,
209) -> SyntaxResult<Node<'source>> {
210 let end = |t: &Token| match t {
211 Token::Comment(lex, _) => match lex {
212 lexer::Comment::End => true,
213 _ => false,
214 },
215 _ => false,
216 };
217
218 let wrap = |t: TextBlock<'source>| Node::Comment(t);
219 let maybe_node = text_until(source, lexer, state, span, &end, &wrap);
220 if let Some((node, _)) = maybe_node {
221 Ok(node)
222 } else {
223 Err(SyntaxError::CommentNotTerminated(
224 ErrorInfo::from((source, state)).into(),
225 ))
226 }
227}
228
229pub(crate) fn scope<'source>(
231 source: &'source str,
232 lexer: &mut Lexer<'source>,
233 state: &mut ParseState,
234 span: Range<usize>,
235) -> SyntaxResult<Block<'source>> {
236 let mut block = Block::new(source, span.clone(), false, state.line_range());
237 let call =
238 call::parse(source, lexer, state, span, CallParseContext::Block)?;
239 block.set_call(call);
240 Ok(block)
241}