1use std::borrow::Cow;
2use std::str;
3
4use nom::branch::alt;
5use nom::bytes::complete::{tag, take_until};
6use nom::character::complete::char;
7use nom::combinator::{
8 complete, consumed, cut, eof, map, map_res, not, opt, peek, recognize, value,
9};
10use nom::error::{Error, ErrorKind};
11use nom::error_position;
12use nom::multi::{fold_many0, many0, many1, separated_list0, separated_list1};
13use nom::sequence::{delimited, pair, preceded, terminated, tuple};
14
15use crate::{ErrorContext, ParseResult};
16
17use super::{
18 bool_lit, char_lit, identifier, is_ws, keyword, num_lit, path_or_identifier, skip_till,
19 str_lit, ws, Expr, PathOrIdentifier, State,
20};
21
22#[derive(Debug, PartialEq)]
23pub enum Node<'a> {
24 Lit(Lit<'a>),
25 Comment(Comment<'a>),
26 Expr(Ws, Expr<'a>),
27 Call(Call<'a>),
28 Let(Let<'a>),
29 If(If<'a>),
30 Match(Match<'a>),
31 Loop(Box<Loop<'a>>),
32 Extends(Extends<'a>),
33 BlockDef(BlockDef<'a>),
34 Include(Include<'a>),
35 Import(Import<'a>),
36 Macro(Macro<'a>),
37 Raw(Raw<'a>),
38 Break(Ws),
39 Continue(Ws),
40}
41
42impl<'a> Node<'a> {
43 pub(super) fn many(i: &'a str, s: &State<'_>) -> ParseResult<'a, Vec<Self>> {
44 complete(many0(alt((
45 map(|i| Lit::parse(i, s), Self::Lit),
46 map(|i| Comment::parse(i, s), Self::Comment),
47 |i| Self::expr(i, s),
48 |i| Self::parse(i, s),
49 ))))(i)
50 }
51
52 fn parse(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
53 let mut p = delimited(
54 |i| s.tag_block_start(i),
55 alt((
56 map(|i| Call::parse(i, s), Self::Call),
57 map(|i| Let::parse(i, s), Self::Let),
58 map(|i| If::parse(i, s), Self::If),
59 map(|i| Loop::parse(i, s), |l| Self::Loop(Box::new(l))),
60 map(|i| Match::parse(i, s), Self::Match),
61 map(Extends::parse, Self::Extends),
62 map(Include::parse, Self::Include),
63 map(Import::parse, Self::Import),
64 map(|i| BlockDef::parse(i, s), Self::BlockDef),
65 map(|i| Macro::parse(i, s), Self::Macro),
66 map(|i| Raw::parse(i, s), Self::Raw),
67 |i| Self::r#break(i, s),
68 |i| Self::r#continue(i, s),
69 )),
70 cut(|i| s.tag_block_end(i)),
71 );
72
73 s.nest(i)?;
74 let result = p(i);
75 s.leave();
76
77 result
78 }
79
80 fn r#break(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
81 let mut p = tuple((
82 opt(Whitespace::parse),
83 ws(keyword("break")),
84 opt(Whitespace::parse),
85 ));
86 let (j, (pws, _, nws)) = p(i)?;
87 if !s.is_in_loop() {
88 return Err(nom::Err::Failure(error_position!(i, ErrorKind::Tag)));
89 }
90 Ok((j, Self::Break(Ws(pws, nws))))
91 }
92
93 fn r#continue(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
94 let mut p = tuple((
95 opt(Whitespace::parse),
96 ws(keyword("continue")),
97 opt(Whitespace::parse),
98 ));
99 let (j, (pws, _, nws)) = p(i)?;
100 if !s.is_in_loop() {
101 return Err(nom::Err::Failure(error_position!(i, ErrorKind::Tag)));
102 }
103 Ok((j, Self::Continue(Ws(pws, nws))))
104 }
105
106 fn expr(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
107 let mut p = tuple((
108 |i| s.tag_expr_start(i),
109 cut(tuple((
110 opt(Whitespace::parse),
111 ws(|i| Expr::parse(i, s.level.get())),
112 opt(Whitespace::parse),
113 |i| s.tag_expr_end(i),
114 ))),
115 ));
116 let (i, (_, (pws, expr, nws, _))) = p(i)?;
117 Ok((i, Self::Expr(Ws(pws, nws), expr)))
118 }
119}
120
121#[derive(Clone, Debug, PartialEq)]
122pub enum Target<'a> {
123 Name(&'a str),
124 Tuple(Vec<&'a str>, Vec<Target<'a>>),
125 Struct(Vec<&'a str>, Vec<(&'a str, Target<'a>)>),
126 NumLit(&'a str),
127 StrLit(&'a str),
128 CharLit(&'a str),
129 BoolLit(&'a str),
130 Path(Vec<&'a str>),
131 OrChain(Vec<Target<'a>>),
132}
133
134impl<'a> Target<'a> {
135 /// Parses multiple targets with `or` separating them
136 pub(super) fn parse(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
137 map(
138 separated_list1(ws(tag("or")), |i| {
139 s.nest(i)?;
140 let ret = Self::parse_one(i, s)?;
141 s.leave();
142 Ok(ret)
143 }),
144 |mut opts| match opts.len() {
145 1 => opts.pop().unwrap(),
146 _ => Self::OrChain(opts),
147 },
148 )(i)
149 }
150
151 /// Parses a single target without an `or`, unless it is wrapped in parentheses.
152 fn parse_one(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
153 let mut opt_opening_paren = map(opt(ws(char('('))), |o| o.is_some());
154 let mut opt_closing_paren = map(opt(ws(char(')'))), |o| o.is_some());
155 let mut opt_opening_brace = map(opt(ws(char('{'))), |o| o.is_some());
156
157 let (i, lit) = opt(Self::lit)(i)?;
158 if let Some(lit) = lit {
159 return Ok((i, lit));
160 }
161
162 // match tuples and unused parentheses
163 let (i, target_is_tuple) = opt_opening_paren(i)?;
164 if target_is_tuple {
165 let (i, is_empty_tuple) = opt_closing_paren(i)?;
166 if is_empty_tuple {
167 return Ok((i, Self::Tuple(Vec::new(), Vec::new())));
168 }
169
170 let (i, first_target) = Self::parse(i, s)?;
171 let (i, is_unused_paren) = opt_closing_paren(i)?;
172 if is_unused_paren {
173 return Ok((i, first_target));
174 }
175
176 let mut targets = vec![first_target];
177 let (i, _) = cut(tuple((
178 fold_many0(
179 preceded(ws(char(',')), |i| Self::parse(i, s)),
180 || (),
181 |_, target| {
182 targets.push(target);
183 },
184 ),
185 opt(ws(char(','))),
186 ws(cut(char(')'))),
187 )))(i)?;
188 return Ok((i, Self::Tuple(Vec::new(), targets)));
189 }
190
191 let path = |i| {
192 map_res(path_or_identifier, |v| match v {
193 PathOrIdentifier::Path(v) => Ok(v),
194 PathOrIdentifier::Identifier(v) => Err(v),
195 })(i)
196 };
197
198 // match structs
199 let (i, path) = opt(path)(i)?;
200 if let Some(path) = path {
201 let i_before_matching_with = i;
202 let (i, _) = opt(ws(keyword("with")))(i)?;
203
204 let (i, is_unnamed_struct) = opt_opening_paren(i)?;
205 if is_unnamed_struct {
206 let (i, targets) = alt((
207 map(char(')'), |_| Vec::new()),
208 terminated(
209 cut(separated_list1(ws(char(',')), |i| Self::parse(i, s))),
210 pair(opt(ws(char(','))), ws(cut(char(')')))),
211 ),
212 ))(i)?;
213 return Ok((i, Self::Tuple(path, targets)));
214 }
215
216 let (i, is_named_struct) = opt_opening_brace(i)?;
217 if is_named_struct {
218 let (i, targets) = alt((
219 map(char('}'), |_| Vec::new()),
220 terminated(
221 cut(separated_list1(ws(char(',')), |i| Self::named(i, s))),
222 pair(opt(ws(char(','))), ws(cut(char('}')))),
223 ),
224 ))(i)?;
225 return Ok((i, Self::Struct(path, targets)));
226 }
227
228 return Ok((i_before_matching_with, Self::Path(path)));
229 }
230
231 // neither literal nor struct nor path
232 let (new_i, name) = identifier(i)?;
233 Ok((new_i, Self::verify_name(i, name)?))
234 }
235
236 fn lit(i: &'a str) -> ParseResult<'a, Self> {
237 alt((
238 map(str_lit, Self::StrLit),
239 map(char_lit, Self::CharLit),
240 map(num_lit, Self::NumLit),
241 map(bool_lit, Self::BoolLit),
242 ))(i)
243 }
244
245 fn named(init_i: &'a str, s: &State<'_>) -> ParseResult<'a, (&'a str, Self)> {
246 let (i, (src, target)) = pair(
247 identifier,
248 opt(preceded(ws(char(':')), |i| Self::parse(i, s))),
249 )(init_i)?;
250
251 let target = match target {
252 Some(target) => target,
253 None => Self::verify_name(init_i, src)?,
254 };
255
256 Ok((i, (src, target)))
257 }
258
259 fn verify_name(input: &'a str, name: &'a str) -> Result<Self, nom::Err<ErrorContext<'a>>> {
260 match name {
261 "self" | "writer" => Err(nom::Err::Failure(ErrorContext {
262 input,
263 message: Some(Cow::Owned(format!("Cannot use `{name}` as a name"))),
264 })),
265 _ => Ok(Self::Name(name)),
266 }
267 }
268}
269
270#[derive(Debug, PartialEq)]
271pub struct When<'a> {
272 pub ws: Ws,
273 pub target: Target<'a>,
274 pub nodes: Vec<Node<'a>>,
275}
276
277impl<'a> When<'a> {
278 fn r#match(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
279 let mut p = tuple((
280 |i| s.tag_block_start(i),
281 opt(Whitespace::parse),
282 ws(keyword("else")),
283 cut(tuple((
284 opt(Whitespace::parse),
285 |i| s.tag_block_end(i),
286 cut(|i| Node::many(i, s)),
287 ))),
288 ));
289 let (i, (_, pws, _, (nws, _, nodes))) = p(i)?;
290 Ok((
291 i,
292 Self {
293 ws: Ws(pws, nws),
294 target: Target::Name("_"),
295 nodes,
296 },
297 ))
298 }
299
300 #[allow(clippy::self_named_constructors)]
301 fn when(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
302 let mut p = tuple((
303 |i| s.tag_block_start(i),
304 opt(Whitespace::parse),
305 ws(keyword("when")),
306 cut(tuple((
307 ws(|i| Target::parse(i, s)),
308 opt(Whitespace::parse),
309 |i| s.tag_block_end(i),
310 cut(|i| Node::many(i, s)),
311 ))),
312 ));
313 let (i, (_, pws, _, (target, nws, _, nodes))) = p(i)?;
314 Ok((
315 i,
316 Self {
317 ws: Ws(pws, nws),
318 target,
319 nodes,
320 },
321 ))
322 }
323}
324
325#[derive(Debug, PartialEq)]
326pub struct Cond<'a> {
327 pub ws: Ws,
328 pub cond: Option<CondTest<'a>>,
329 pub nodes: Vec<Node<'a>>,
330}
331
332impl<'a> Cond<'a> {
333 fn parse(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
334 let mut p = tuple((
335 |i| s.tag_block_start(i),
336 opt(Whitespace::parse),
337 ws(alt((keyword("else"), |i| {
338 let _ = keyword("elif")(i)?;
339 Err(nom::Err::Failure(ErrorContext {
340 input: i,
341 message: Some(Cow::Borrowed(
342 "unknown `elif` keyword; did you mean `else if`?",
343 )),
344 }))
345 }))),
346 cut(tuple((
347 opt(|i| CondTest::parse(i, s)),
348 opt(Whitespace::parse),
349 |i| s.tag_block_end(i),
350 cut(|i| Node::many(i, s)),
351 ))),
352 ));
353 let (i, (_, pws, _, (cond, nws, _, nodes))) = p(i)?;
354 Ok((
355 i,
356 Self {
357 ws: Ws(pws, nws),
358 cond,
359 nodes,
360 },
361 ))
362 }
363}
364
365#[derive(Debug, PartialEq)]
366pub struct CondTest<'a> {
367 pub target: Option<Target<'a>>,
368 pub expr: Expr<'a>,
369}
370
371impl<'a> CondTest<'a> {
372 fn parse(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
373 let mut p: impl FnMut(&str) -> Result<…, …> = preceded(
374 first:ws(keyword("if")),
375 second:cut(parser:tuple((
376 opt(delimited(
377 first:ws(alt((keyword("let"), keyword("set")))),
378 second:ws(|i| Target::parse(i, s)),
379 third:ws(inner:char('=')),
380 )),
381 ws(|i: &str| Expr::parse(i, level:s.level.get())),
382 ))),
383 );
384 let (i: &str, (target: Option>, expr: Expr<'_>)) = p(i)?;
385 Ok((i, Self { target, expr }))
386 }
387}
388
389#[derive(Clone, Copy, Debug, PartialEq)]
390pub enum Whitespace {
391 Preserve,
392 Suppress,
393 Minimize,
394}
395
396impl Whitespace {
397 fn parse(i: &str) -> ParseResult<'_, Self> {
398 alt((
399 value(Self::Preserve, parser:char('+')),
400 value(Self::Suppress, parser:char('-')),
401 value(Self::Minimize, parser:char('~')),
402 ))(i)
403 }
404}
405
406#[derive(Debug, PartialEq)]
407pub struct Loop<'a> {
408 pub ws1: Ws,
409 pub var: Target<'a>,
410 pub iter: Expr<'a>,
411 pub cond: Option<Expr<'a>>,
412 pub body: Vec<Node<'a>>,
413 pub ws2: Ws,
414 pub else_nodes: Vec<Node<'a>>,
415 pub ws3: Ws,
416}
417
418impl<'a> Loop<'a> {
419 fn parse(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
420 fn content<'a>(i: &'a str, s: &State<'_>) -> ParseResult<'a, Vec<Node<'a>>> {
421 s.enter_loop();
422 let result = Node::many(i, s);
423 s.leave_loop();
424 result
425 }
426
427 let if_cond = preceded(
428 ws(keyword("if")),
429 cut(ws(|i| Expr::parse(i, s.level.get()))),
430 );
431
432 let else_block = |i| {
433 let mut p = preceded(
434 ws(keyword("else")),
435 cut(tuple((
436 opt(Whitespace::parse),
437 delimited(
438 |i| s.tag_block_end(i),
439 |i| Node::many(i, s),
440 |i| s.tag_block_start(i),
441 ),
442 opt(Whitespace::parse),
443 ))),
444 );
445 let (i, (pws, nodes, nws)) = p(i)?;
446 Ok((i, (pws, nodes, nws)))
447 };
448
449 let mut p = tuple((
450 opt(Whitespace::parse),
451 ws(keyword("for")),
452 cut(tuple((
453 ws(|i| Target::parse(i, s)),
454 ws(keyword("in")),
455 cut(tuple((
456 ws(|i| Expr::parse(i, s.level.get())),
457 opt(if_cond),
458 opt(Whitespace::parse),
459 |i| s.tag_block_end(i),
460 cut(tuple((
461 |i| content(i, s),
462 cut(tuple((
463 |i| s.tag_block_start(i),
464 opt(Whitespace::parse),
465 opt(else_block),
466 ws(keyword("endfor")),
467 opt(Whitespace::parse),
468 ))),
469 ))),
470 ))),
471 ))),
472 ));
473 let (i, (pws1, _, (var, _, (iter, cond, nws1, _, (body, (_, pws2, else_block, _, nws2)))))) =
474 p(i)?;
475 let (nws3, else_block, pws3) = else_block.unwrap_or_default();
476 Ok((
477 i,
478 Self {
479 ws1: Ws(pws1, nws1),
480 var,
481 iter,
482 cond,
483 body,
484 ws2: Ws(pws2, nws3),
485 else_nodes: else_block,
486 ws3: Ws(pws3, nws2),
487 },
488 ))
489 }
490}
491
492#[derive(Debug, PartialEq)]
493pub struct Macro<'a> {
494 pub ws1: Ws,
495 pub name: &'a str,
496 pub args: Vec<&'a str>,
497 pub nodes: Vec<Node<'a>>,
498 pub ws2: Ws,
499}
500
501impl<'a> Macro<'a> {
502 fn parse(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
503 fn parameters(i: &str) -> ParseResult<'_, Vec<&str>> {
504 delimited(
505 ws(char('(')),
506 separated_list0(char(','), ws(identifier)),
507 tuple((opt(ws(char(','))), char(')'))),
508 )(i)
509 }
510
511 let mut start = tuple((
512 opt(Whitespace::parse),
513 ws(keyword("macro")),
514 cut(tuple((
515 ws(identifier),
516 opt(ws(parameters)),
517 opt(Whitespace::parse),
518 |i| s.tag_block_end(i),
519 ))),
520 ));
521 let (i, (pws1, _, (name, params, nws1, _))) = start(i)?;
522
523 let mut end = cut(tuple((
524 |i| Node::many(i, s),
525 cut(tuple((
526 |i| s.tag_block_start(i),
527 opt(Whitespace::parse),
528 ws(keyword("endmacro")),
529 cut(preceded(
530 opt(|before| {
531 let (after, end_name) = ws(identifier)(before)?;
532 check_end_name(before, after, name, end_name, "macro")
533 }),
534 opt(Whitespace::parse),
535 )),
536 ))),
537 )));
538 let (i, (contents, (_, pws2, _, nws2))) = end(i)?;
539
540 if name == "super" {
541 // TODO: yield a a better error message here
542 return Err(ErrorContext::from_err(nom::Err::Failure(Error::new(
543 i,
544 ErrorKind::Fail,
545 ))));
546 }
547
548 Ok((
549 i,
550 Self {
551 ws1: Ws(pws1, nws1),
552 name,
553 args: params.unwrap_or_default(),
554 nodes: contents,
555 ws2: Ws(pws2, nws2),
556 },
557 ))
558 }
559}
560
561#[derive(Debug, PartialEq)]
562pub struct Import<'a> {
563 pub ws: Ws,
564 pub path: &'a str,
565 pub scope: &'a str,
566}
567
568impl<'a> Import<'a> {
569 fn parse(i: &'a str) -> ParseResult<'a, Self> {
570 let mut p: impl FnMut(&str) -> Result<…, …> = tuple((
571 opt(Whitespace::parse),
572 ws(inner:keyword("import")),
573 cut(parser:tuple((
574 ws(inner:str_lit),
575 ws(inner:keyword("as")),
576 cut(parser:pair(first:ws(identifier), second:opt(Whitespace::parse))),
577 ))),
578 ));
579 let (i: &str, (pws: Option, _, (path: &str, _, (scope: &str, nws: Option)))) = p(i)?;
580 Ok((
581 i,
582 Self {
583 ws: Ws(pws, nws),
584 path,
585 scope,
586 },
587 ))
588 }
589}
590
591#[derive(Debug, PartialEq)]
592pub struct Call<'a> {
593 pub ws: Ws,
594 pub scope: Option<&'a str>,
595 pub name: &'a str,
596 pub args: Vec<Expr<'a>>,
597}
598
599impl<'a> Call<'a> {
600 fn parse(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
601 let mut p = tuple((
602 opt(Whitespace::parse),
603 ws(keyword("call")),
604 cut(tuple((
605 opt(tuple((ws(identifier), ws(tag("::"))))),
606 ws(identifier),
607 opt(ws(|nested| Expr::arguments(nested, s.level.get(), true))),
608 opt(Whitespace::parse),
609 ))),
610 ));
611 let (i, (pws, _, (scope, name, args, nws))) = p(i)?;
612 let scope = scope.map(|(scope, _)| scope);
613 let args = args.unwrap_or_default();
614 Ok((
615 i,
616 Self {
617 ws: Ws(pws, nws),
618 scope,
619 name,
620 args,
621 },
622 ))
623 }
624}
625
626#[derive(Debug, PartialEq)]
627pub struct Match<'a> {
628 pub ws1: Ws,
629 pub expr: Expr<'a>,
630 pub arms: Vec<When<'a>>,
631 pub ws2: Ws,
632}
633
634impl<'a> Match<'a> {
635 fn parse(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
636 let mut p = tuple((
637 opt(Whitespace::parse),
638 ws(keyword("match")),
639 cut(tuple((
640 ws(|i| Expr::parse(i, s.level.get())),
641 opt(Whitespace::parse),
642 |i| s.tag_block_end(i),
643 cut(tuple((
644 ws(many0(ws(value((), |i| Comment::parse(i, s))))),
645 many1(|i| When::when(i, s)),
646 cut(tuple((
647 opt(|i| When::r#match(i, s)),
648 cut(tuple((
649 ws(|i| s.tag_block_start(i)),
650 opt(Whitespace::parse),
651 ws(keyword("endmatch")),
652 opt(Whitespace::parse),
653 ))),
654 ))),
655 ))),
656 ))),
657 ));
658 let (i, (pws1, _, (expr, nws1, _, (_, arms, (else_arm, (_, pws2, _, nws2)))))) = p(i)?;
659
660 let mut arms = arms;
661 if let Some(arm) = else_arm {
662 arms.push(arm);
663 }
664
665 Ok((
666 i,
667 Self {
668 ws1: Ws(pws1, nws1),
669 expr,
670 arms,
671 ws2: Ws(pws2, nws2),
672 },
673 ))
674 }
675}
676
677#[derive(Debug, PartialEq)]
678pub struct BlockDef<'a> {
679 pub ws1: Ws,
680 pub name: &'a str,
681 pub nodes: Vec<Node<'a>>,
682 pub ws2: Ws,
683}
684
685impl<'a> BlockDef<'a> {
686 fn parse(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
687 let mut start = tuple((
688 opt(Whitespace::parse),
689 ws(keyword("block")),
690 cut(tuple((ws(identifier), opt(Whitespace::parse), |i| {
691 s.tag_block_end(i)
692 }))),
693 ));
694 let (i, (pws1, _, (name, nws1, _))) = start(i)?;
695
696 let mut end = cut(tuple((
697 |i| Node::many(i, s),
698 cut(tuple((
699 |i| s.tag_block_start(i),
700 opt(Whitespace::parse),
701 ws(keyword("endblock")),
702 cut(tuple((
703 opt(|before| {
704 let (after, end_name) = ws(identifier)(before)?;
705 check_end_name(before, after, name, end_name, "block")
706 }),
707 opt(Whitespace::parse),
708 ))),
709 ))),
710 )));
711 let (i, (nodes, (_, pws2, _, (_, nws2)))) = end(i)?;
712
713 Ok((
714 i,
715 BlockDef {
716 ws1: Ws(pws1, nws1),
717 name,
718 nodes,
719 ws2: Ws(pws2, nws2),
720 },
721 ))
722 }
723}
724
725fn check_end_name<'a>(
726 before: &'a str,
727 after: &'a str,
728 name: &'a str,
729 end_name: &'a str,
730 kind: &str,
731) -> ParseResult<'a> {
732 if name == end_name {
733 return Ok((after, end_name));
734 }
735 let message: String = if name.is_empty() && !end_name.is_empty() {
736 format!("unexpected name `{end_name}` in `end{kind}` tag for unnamed `{kind}`")
737 } else {
738 format!("expected name `{name}` in `end{kind}` tag, found `{end_name}`")
739 };
740 Err(nom::Err::Failure(ErrorContext {
741 input: before,
742 message: Some(Cow::Owned(message)),
743 }))
744}
745
746#[derive(Debug, PartialEq)]
747pub struct Lit<'a> {
748 pub lws: &'a str,
749 pub val: &'a str,
750 pub rws: &'a str,
751}
752
753impl<'a> Lit<'a> {
754 fn parse(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
755 let p_start = alt((
756 tag(s.syntax.block_start),
757 tag(s.syntax.comment_start),
758 tag(s.syntax.expr_start),
759 ));
760
761 let (i, _) = not(eof)(i)?;
762 let (i, content) = opt(recognize(skip_till(p_start)))(i)?;
763 let (i, content) = match content {
764 Some("") => {
765 // {block,comment,expr}_start follows immediately.
766 return Err(nom::Err::Error(error_position!(i, ErrorKind::TakeUntil)));
767 }
768 Some(content) => (i, content),
769 None => ("", i), // there is no {block,comment,expr}_start: take everything
770 };
771 Ok((i, Self::split_ws_parts(content)))
772 }
773
774 pub(crate) fn split_ws_parts(s: &'a str) -> Self {
775 let trimmed_start = s.trim_start_matches(is_ws);
776 let len_start = s.len() - trimmed_start.len();
777 let trimmed = trimmed_start.trim_end_matches(is_ws);
778 Self {
779 lws: &s[..len_start],
780 val: trimmed,
781 rws: &trimmed_start[trimmed.len()..],
782 }
783 }
784}
785
786#[derive(Debug, PartialEq)]
787pub struct Raw<'a> {
788 pub ws1: Ws,
789 pub lit: Lit<'a>,
790 pub ws2: Ws,
791}
792
793impl<'a> Raw<'a> {
794 fn parse(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
795 let endraw = tuple((
796 |i| s.tag_block_start(i),
797 opt(Whitespace::parse),
798 ws(keyword("endraw")),
799 opt(Whitespace::parse),
800 peek(|i| s.tag_block_end(i)),
801 ));
802
803 let mut p = tuple((
804 opt(Whitespace::parse),
805 ws(keyword("raw")),
806 cut(tuple((
807 opt(Whitespace::parse),
808 |i| s.tag_block_end(i),
809 consumed(skip_till(endraw)),
810 ))),
811 ));
812
813 let (_, (pws1, _, (nws1, _, (contents, (i, (_, pws2, _, nws2, _)))))) = p(i)?;
814 let lit = Lit::split_ws_parts(contents);
815 let ws1 = Ws(pws1, nws1);
816 let ws2 = Ws(pws2, nws2);
817 Ok((i, Self { ws1, lit, ws2 }))
818 }
819}
820
821#[derive(Debug, PartialEq)]
822pub struct Let<'a> {
823 pub ws: Ws,
824 pub var: Target<'a>,
825 pub val: Option<Expr<'a>>,
826}
827
828impl<'a> Let<'a> {
829 fn parse(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
830 let mut p = tuple((
831 opt(Whitespace::parse),
832 ws(alt((keyword("let"), keyword("set")))),
833 cut(tuple((
834 ws(|i| Target::parse(i, s)),
835 opt(preceded(
836 ws(char('=')),
837 ws(|i| Expr::parse(i, s.level.get())),
838 )),
839 opt(Whitespace::parse),
840 ))),
841 ));
842 let (i, (pws, _, (var, val, nws))) = p(i)?;
843
844 Ok((
845 i,
846 Let {
847 ws: Ws(pws, nws),
848 var,
849 val,
850 },
851 ))
852 }
853}
854
855#[derive(Debug, PartialEq)]
856pub struct If<'a> {
857 pub ws: Ws,
858 pub branches: Vec<Cond<'a>>,
859}
860
861impl<'a> If<'a> {
862 fn parse(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
863 let mut p = tuple((
864 opt(Whitespace::parse),
865 |i| CondTest::parse(i, s),
866 cut(tuple((
867 opt(Whitespace::parse),
868 |i| s.tag_block_end(i),
869 cut(tuple((
870 |i| Node::many(i, s),
871 many0(|i| Cond::parse(i, s)),
872 cut(tuple((
873 |i| s.tag_block_start(i),
874 opt(Whitespace::parse),
875 ws(keyword("endif")),
876 opt(Whitespace::parse),
877 ))),
878 ))),
879 ))),
880 ));
881
882 let (i, (pws1, cond, (nws1, _, (nodes, elifs, (_, pws2, _, nws2))))) = p(i)?;
883 let mut branches = vec![Cond {
884 ws: Ws(pws1, nws1),
885 cond: Some(cond),
886 nodes,
887 }];
888 branches.extend(elifs);
889
890 Ok((
891 i,
892 Self {
893 ws: Ws(pws2, nws2),
894 branches,
895 },
896 ))
897 }
898}
899
900#[derive(Debug, PartialEq)]
901pub struct Include<'a> {
902 pub ws: Ws,
903 pub path: &'a str,
904}
905
906impl<'a> Include<'a> {
907 fn parse(i: &'a str) -> ParseResult<'a, Self> {
908 let mut p: impl FnMut(&str) -> Result<…, …> = tuple((
909 opt(Whitespace::parse),
910 ws(inner:keyword("include")),
911 cut(parser:pair(first:ws(str_lit), second:opt(Whitespace::parse))),
912 ));
913 let (i: &str, (pws: Option, _, (path: &str, nws: Option))) = p(i)?;
914 Ok((
915 i,
916 Self {
917 ws: Ws(pws, nws),
918 path,
919 },
920 ))
921 }
922}
923
924#[derive(Debug, PartialEq)]
925pub struct Extends<'a> {
926 pub path: &'a str,
927}
928
929impl<'a> Extends<'a> {
930 fn parse(i: &'a str) -> ParseResult<'a, Self> {
931 let (i: &str, path: &str) = preceded(first:ws(keyword("extends")), second:cut(parser:ws(inner:str_lit)))(i)?;
932 Ok((i, Self { path }))
933 }
934}
935
936#[derive(Debug, PartialEq)]
937pub struct Comment<'a> {
938 pub ws: Ws,
939 pub content: &'a str,
940}
941
942impl<'a> Comment<'a> {
943 fn parse(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
944 fn body<'a>(mut i: &'a str, s: &State<'_>) -> ParseResult<'a> {
945 let mut level = 0;
946 loop {
947 let (end, tail) = take_until(s.syntax.comment_end)(i)?;
948 match take_until::<_, _, ErrorContext<'_>>(s.syntax.comment_start)(i) {
949 Ok((start, _)) if start.as_ptr() < end.as_ptr() => {
950 level += 1;
951 i = &start[2..];
952 }
953 _ if level > 0 => {
954 level -= 1;
955 i = &end[2..];
956 }
957 _ => return Ok((end, tail)),
958 }
959 }
960 }
961
962 let mut p = tuple((
963 |i| s.tag_comment_start(i),
964 cut(tuple((
965 opt(Whitespace::parse),
966 |i| body(i, s),
967 |i| s.tag_comment_end(i),
968 ))),
969 ));
970 let (i, (content, (pws, tail, _))) = p(i)?;
971 let nws = if tail.ends_with('-') {
972 Some(Whitespace::Suppress)
973 } else if tail.ends_with('+') {
974 Some(Whitespace::Preserve)
975 } else if tail.ends_with('~') {
976 Some(Whitespace::Minimize)
977 } else {
978 None
979 };
980 Ok((
981 i,
982 Self {
983 ws: Ws(pws, nws),
984 content,
985 },
986 ))
987 }
988}
989
990/// First field is "minus/plus sign was used on the left part of the item".
991///
992/// Second field is "minus/plus sign was used on the right part of the item".
993#[derive(Clone, Copy, Debug, PartialEq)]
994pub struct Ws(pub Option<Whitespace>, pub Option<Whitespace>);
995