bracket/parser/
ast.rs

1//! Abstract syntax tree node types.
2use std::collections::HashMap;
3use std::fmt;
4use std::ops::Range;
5
6use serde_json::Value;
7
8use crate::{parser::iter::BranchIter, trim::TrimHint};
9
10const WHITESPACE: &str = "~";
11const ROOT: &str = "@root";
12//pub const LEVEL: &str = "@level";
13
14/// Trait for nodes that reference a slice of the
15/// source template.
16pub trait Slice<'source>: fmt::Display + fmt::Debug {
17    /// String slice of the full span for this node.
18    fn as_str(&self) -> &'source str;
19
20    /// The underlying template source.
21    fn source(&self) -> &'source str;
22}
23
24/// Trait for nodes that track line numbers.
25///
26/// Line numbers begin at index zero.
27pub trait Lines {
28    /// Reference to the line range for the node.
29    fn lines(&self) -> &Range<usize>;
30
31    /// Mutable reference to the line range for the node.
32    fn lines_mut(&mut self) -> &mut Range<usize>;
33
34    /// Set the end of the lines range.
35    fn lines_end(&mut self, line: &usize) {
36        self.lines_mut().end = line.clone() + 1;
37    }
38}
39
40/// Trait for elements that expect to be closed.
41pub trait Element<'source> {
42    /// Get the string for the open tag.
43    fn open(&self) -> &'source str;
44
45    /// Get the string for the close tag.
46    ///
47    /// If no close span has been set which can happen if the
48    /// element has no end tag this should return the empty string.
49    fn close(&self) -> &'source str;
50
51    /// Get the span for the open tag.
52    fn open_span(&self) -> &Range<usize>;
53
54    /// Get the span for the close tag.
55    fn close_span(&self) -> &Option<Range<usize>>;
56
57    /// Determine if this element has been closed.
58    fn is_closed(&self) -> bool;
59
60    /// Mark this element as correctly terminated.
61    fn exit(&mut self, close: Range<usize>);
62
63    /// The full byte range for this element; if the element is not closed
64    /// only the open span is returned.
65    fn span(&self) -> Range<usize> {
66        if let Some(ref close) = self.close_span() {
67            self.open_span().start..close.end
68        } else {
69            self.open_span().clone()
70        }
71    }
72}
73
74/// Nodes form the abstract syntax tree.
75///
76/// Every node provides access to a [TrimHint](crate::trim::TrimHint) used
77/// by the renderer to determine how whitespace should be handled.
78#[derive(Eq, PartialEq)]
79pub enum Node<'source> {
80    /// Document nodes encapsulate a collection of children.
81    Document(Document<'source>),
82    /// Text nodes are a byte range.
83    Text(Text<'source>),
84    /// Statement is a variable interpolation, partial render or helper call.
85    Statement(Call<'source>),
86    /// Blocks encapsulate an inner template.
87    ///
88    /// Blocks have a `raw` flag which indicates that the content
89    /// should not be interpreted. When the `raw` flag is set a block
90    /// must only have a single `Text` child node.
91    Block(Block<'source>),
92    /// Raw statement is a statement preceeded by a backslash
93    /// that should not be interpreted.
94    RawStatement(TextBlock<'source>),
95    /// Raw comments may contain nested templates (`{{!-- comment --}}`).
96    RawComment(TextBlock<'source>),
97    /// Comments may **not** contain nested templates (`{{! comment }}`).
98    Comment(TextBlock<'source>),
99    /// Link nodes are parsed from wiki-style links.
100    Link(Link<'source>),
101}
102
103impl Default for Node<'_> {
104    fn default() -> Self {
105        Node::Document(Document("", vec![]))
106    }
107}
108
109impl<'source> Node<'source> {
110    /// Get the trim hint for this node.
111    pub fn trim(&self) -> TrimHint {
112        TrimHint {
113            before: self.trim_before(),
114            after: self.trim_after(),
115        }
116    }
117
118    fn trim_before(&self) -> bool {
119        match *self {
120            Self::Document(_)
121            | Self::Text(_)
122            | Self::RawStatement(_)
123            | Self::RawComment(_)
124            | Self::Comment(_)
125            | Self::Link(_) => false,
126            Self::Statement(ref n) => n.trim_before(),
127            Self::Block(ref n) => n.trim_before(),
128        }
129    }
130
131    fn trim_after(&self) -> bool {
132        match *self {
133            Self::Document(_)
134            | Self::Text(_)
135            | Self::RawStatement(_)
136            | Self::RawComment(_)
137            | Self::Comment(_)
138            | Self::Link(_) => false,
139            Self::Statement(ref n) => n.trim_after(),
140            Self::Block(ref n) => n.trim_after(),
141        }
142    }
143
144    /// Iterate descendants of documents and blocks.
145    pub fn into_iter<'a>(&'a self) -> BranchIter<'a> {
146        BranchIter::new(self)
147    }
148}
149
150impl<'source> Slice<'source> for Node<'source> {
151    fn as_str(&self) -> &'source str {
152        match *self {
153            Self::Document(ref n) => n.as_str(),
154            Self::Text(ref n) => n.as_str(),
155            Self::Statement(ref n) => n.as_str(),
156            Self::Block(ref n) => n.as_str(),
157            Self::Link(ref n) => n.as_str(),
158            Self::RawStatement(ref n)
159            | Self::RawComment(ref n)
160            | Self::Comment(ref n) => n.as_str(),
161        }
162    }
163
164    fn source(&self) -> &'source str {
165        match *self {
166            Self::Document(ref n) => n.source(),
167            Self::Text(ref n) => n.source(),
168            Self::RawStatement(ref n) => n.source(),
169            Self::RawComment(ref n) => n.source(),
170            Self::Comment(ref n) => n.source(),
171            Self::Statement(ref n) => n.source(),
172            Self::Block(ref n) => n.source(),
173            Self::Link(ref n) => n.source(),
174        }
175    }
176}
177
178impl fmt::Display for Node<'_> {
179    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180        match *self {
181            Self::Document(ref n) => n.fmt(f),
182            Self::Text(ref n) => n.fmt(f),
183            Self::Statement(ref n) => n.fmt(f),
184            Self::Block(ref n) => n.fmt(f),
185            Self::Link(ref n) => n.fmt(f),
186            Self::RawStatement(ref n)
187            | Self::RawComment(ref n)
188            | Self::Comment(ref n) => n.fmt(f),
189        }
190    }
191}
192
193impl fmt::Debug for Node<'_> {
194    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195        match *self {
196            Self::Document(ref n) => fmt::Debug::fmt(n, f),
197            Self::Text(ref n) => fmt::Debug::fmt(n, f),
198            Self::Statement(ref n) => fmt::Debug::fmt(n, f),
199            Self::Block(ref n) => fmt::Debug::fmt(n, f),
200            Self::Link(ref n) => fmt::Debug::fmt(n, f),
201            Self::RawStatement(ref n)
202            | Self::RawComment(ref n)
203            | Self::Comment(ref n) => fmt::Debug::fmt(n, f),
204        }
205    }
206}
207
208/// Text nodes refer to a consecutive range of bytes.
209#[derive(Eq, PartialEq)]
210pub struct Text<'source> {
211    source: &'source str,
212    span: Range<usize>,
213    line: Range<usize>,
214}
215
216impl<'source> Text<'source> {
217    /// Create a new text node.
218    pub fn new(
219        source: &'source str,
220        span: Range<usize>,
221        line: Range<usize>,
222    ) -> Self {
223        Self { source, span, line }
224    }
225}
226
227impl<'source> Lines for Text<'source> {
228    fn lines(&self) -> &Range<usize> {
229        &self.line
230    }
231
232    fn lines_mut(&mut self) -> &mut Range<usize> {
233        &mut self.line
234    }
235}
236
237impl<'source> Slice<'source> for Text<'source> {
238    fn as_str(&self) -> &'source str {
239        &self.source[self.span.start..self.span.end]
240    }
241
242    fn source(&self) -> &'source str {
243        self.source
244    }
245}
246
247impl fmt::Display for Text<'_> {
248    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
249        write!(f, "{}", self.as_str())
250    }
251}
252
253impl fmt::Debug for Text<'_> {
254    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255        f.debug_struct("Text")
256            .field("source", &self.as_str())
257            .field("span", &self.span)
258            .field("line", &self.line)
259            .finish()
260    }
261}
262
263/// Text blocks encapsulate a text node with start and end
264/// ranges; used primarily for comments.
265#[derive(Eq, PartialEq)]
266pub struct TextBlock<'source> {
267    source: &'source str,
268    text: Text<'source>,
269    open: Range<usize>,
270    close: Range<usize>,
271}
272
273impl<'source> TextBlock<'source> {
274    /// Create a new text block.
275    pub fn new(
276        source: &'source str,
277        text: Text<'source>,
278        open: Range<usize>,
279        close: Range<usize>,
280    ) -> Self {
281        Self {
282            source,
283            text,
284            open,
285            close,
286        }
287    }
288}
289
290impl<'source> Slice<'source> for TextBlock<'source> {
291    fn as_str(&self) -> &'source str {
292        &self.source[self.open.start..self.close.end]
293    }
294
295    fn source(&self) -> &'source str {
296        self.source
297    }
298}
299
300impl<'source> Lines for TextBlock<'source> {
301    fn lines(&self) -> &Range<usize> {
302        self.text.lines()
303    }
304
305    fn lines_mut(&mut self) -> &mut Range<usize> {
306        self.text.lines_mut()
307    }
308}
309
310impl<'source> Into<Text<'source>> for TextBlock<'source> {
311    fn into(self) -> Text<'source> {
312        self.text
313    }
314}
315
316impl fmt::Display for TextBlock<'_> {
317    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
318        write!(f, "{}", self.as_str())
319    }
320}
321
322impl fmt::Debug for TextBlock<'_> {
323    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
324        f.debug_struct("TextBlock")
325            .field("source", &self.as_str())
326            .field("open", &self.open)
327            .field("close", &self.close)
328            .field("line", self.lines())
329            .finish()
330    }
331}
332
333/// Indicates the kind of escaping using for raw
334/// identifiers.
335#[derive(Debug, Eq, PartialEq)]
336pub enum RawIdType {
337    /// Raw identifier in single quotes.
338    Single,
339    /// Raw identifier in double quotes.
340    Double,
341    /// Raw identifier in square brackets.
342    Array,
343}
344
345/// Indicates the kind of path component.
346#[derive(Debug, Eq, PartialEq)]
347pub enum ComponentType {
348    /// Parent reference type.
349    Parent,
350    /// Explicit this keyword type.
351    ThisKeyword,
352    /// Explicit this using dot slash notation.
353    ThisDotSlash,
354    /// Identifier path component.
355    Identifier,
356    /// Local identifier path component.
357    LocalIdentifier,
358    /// Raw identifier path component.
359    RawIdentifier(RawIdType),
360    /// Path delimiter.
361    Delimiter,
362}
363
364/// Components form part of a path.
365#[derive(Eq, PartialEq)]
366pub struct Component<'source> {
367    source: &'source str,
368    kind: ComponentType,
369    span: Range<usize>,
370    value: Option<String>,
371}
372
373impl<'source> Component<'source> {
374    /// Create a new component path.
375    ///
376    /// If a component path contains escape sequences an
377    /// owned value should be given otherwise the component
378    /// path will use the supplied span.
379    pub fn new(
380        source: &'source str,
381        kind: ComponentType,
382        span: Range<usize>,
383        value: Option<String>,
384    ) -> Self {
385        Self {
386            source,
387            kind,
388            span,
389            value,
390        }
391    }
392
393    /// Determine if this is the special `@root` component.
394    pub fn is_root(&self) -> bool {
395        self.as_str() == ROOT
396    }
397
398    /// Get the kind of this component.
399    pub fn kind(&self) -> &ComponentType {
400        &self.kind
401    }
402
403    /// The span for this component.
404    pub fn span(&self) -> &Range<usize> {
405        &self.span
406    }
407
408    /// Determine if this component is a local identifier; begins
409    /// with an `@` symbol.
410    pub fn is_local(&self) -> bool {
411        &ComponentType::LocalIdentifier == self.kind()
412    }
413
414    /// Determine if this component is an identifier.
415    pub fn is_identifier(&self) -> bool {
416        &ComponentType::Identifier == self.kind()
417    }
418
419    /// Determine if this component uses an explicit this reference;
420    /// the reference may be the keyword `this` or `./`.
421    pub fn is_explicit(&self) -> bool {
422        &ComponentType::ThisKeyword == self.kind()
423            || self.is_explicit_dot_slash()
424    }
425
426    /// Determine if this component uses and explicit dot slash (`./`)
427    /// reference.
428    ///
429    /// This is used by the path parser to determine if the next expected
430    /// token should be a path delimiter or identifier.
431    pub fn is_explicit_dot_slash(&self) -> bool {
432        &ComponentType::ThisDotSlash == self.kind()
433    }
434
435    /// Get the underlying value for the path component.
436    ///
437    /// If an owned value has been given to this path component
438    /// (which is necessary when the path component includes escape sequences)
439    /// then a reference to the owned value is returned otherwise
440    /// a string slice into the original template for the span
441    /// assigned to this component path is returned.
442    ///
443    /// When performing lookup of values using a path a caller must use
444    /// this function and **not** `as_str()` otherwise literal strings
445    /// with escape sequences will not be respected.
446    pub fn as_value(&self) -> &str {
447        if let Some(ref value) = self.value {
448            return value;
449        }
450        self.as_str()
451    }
452}
453
454impl<'source> Slice<'source> for Component<'source> {
455    fn as_str(&self) -> &'source str {
456        &self.source[self.span().start..self.span().end]
457    }
458
459    fn source(&self) -> &'source str {
460        self.source
461    }
462}
463
464impl fmt::Display for Component<'_> {
465    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
466        write!(f, "{}", self.as_str())
467    }
468}
469
470impl fmt::Debug for Component<'_> {
471    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
472        f.debug_struct("Component")
473            .field("source", &self.as_str())
474            .field("kind", &self.kind)
475            .field("span", &self.span)
476            .finish()
477    }
478}
479
480/// Path to a variable.
481#[derive(Eq, PartialEq)]
482pub struct Path<'source> {
483    source: &'source str,
484    components: Vec<Component<'source>>,
485    parents: u8,
486    explicit: bool,
487    root: bool,
488    span: Range<usize>,
489    line: Range<usize>,
490    absolute: bool,
491}
492
493impl<'source> Path<'source> {
494    /// Create a new path.
495    pub fn new(
496        source: &'source str,
497        span: Range<usize>,
498        line: Range<usize>,
499    ) -> Self {
500        Self {
501            source,
502            components: Vec::new(),
503            parents: 0,
504            explicit: false,
505            root: false,
506            span,
507            line,
508            absolute: false,
509        }
510    }
511
512    /// Determine if this path is absolute.
513    ///
514    /// A path is absolute when it begins with a slash (/); 
515    /// paths that start with a period (.) delimiter are illegal.
516    pub fn absolute(&self) -> bool {
517        self.absolute 
518    }
519
520    /// Set the absolute flag for this path.
521    pub fn set_absolute(&mut self, value: bool) {
522        self.absolute = value;
523    }
524
525    /// Get the span for the path.
526    pub fn span(&self) -> &Range<usize> {
527        &self.span
528    }
529
530    /// Mutable span for the path.
531    pub fn span_mut(&mut self) -> &mut Range<usize> {
532        &mut self.span
533    }
534
535    /// Add a component to this path.
536    pub fn add_component(&mut self, part: Component<'source>) {
537        self.components.push(part);
538    }
539
540    /// Get the path components.
541    pub fn components(&self) -> &Vec<Component<'source>> {
542        &self.components
543    }
544
545    /// Get the number of parent references.
546    pub fn parents(&self) -> u8 {
547        self.parents
548    }
549
550    /// Set the number of parent references.
551    pub fn set_parents(&mut self, parents: u8) {
552        self.parents = parents;
553    }
554
555    /// Flag this path as resolved relative to the root value.
556    pub fn is_root(&self) -> bool {
557        self.root
558    }
559
560    /// Set whether to resolve relative to a root value.
561    pub fn set_root(&mut self, root: bool) {
562        self.root = root;
563    }
564
565    /// Flag this path as an explicit scope reference (eg: `this` or `./`).
566    pub fn is_explicit(&self) -> bool {
567        self.explicit
568    }
569
570    /// Set whether this path is an explicit reference.
571    pub fn set_explicit(&mut self, explicit: bool) {
572        self.explicit = explicit;
573    }
574
575    /// Determine if the path components are empty.
576    pub fn is_empty(&self) -> bool {
577        self.components.is_empty()
578    }
579
580    /// Determine if the first component is a local identifier.
581    pub fn is_local(&self) -> bool {
582        return !self.components.is_empty()
583            && self.components.first().unwrap().is_local();
584    }
585
586    /// Determine if this path is a simple identifier.
587    pub fn is_simple(&self) -> bool {
588        return self.components.len() == 1
589            && self.components.first().unwrap().kind
590                == ComponentType::Identifier;
591    }
592}
593
594impl<'source> Slice<'source> for Path<'source> {
595    fn as_str(&self) -> &'source str {
596        &self.source[self.span.start..self.span.end]
597    }
598
599    fn source(&self) -> &'source str {
600        self.source
601    }
602}
603
604impl<'source> Lines for Path<'source> {
605    fn lines(&self) -> &Range<usize> {
606        &self.line
607    }
608
609    fn lines_mut(&mut self) -> &mut Range<usize> {
610        &mut self.line
611    }
612}
613
614impl fmt::Display for Path<'_> {
615    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
616        write!(f, "{}", self.as_str())
617    }
618}
619
620impl fmt::Debug for Path<'_> {
621    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
622        f.debug_struct("Path")
623            .field("source", &self.as_str())
624            .field("components", &self.components)
625            .field("parents", &self.parents)
626            .field("explicit", &self.explicit)
627            .field("root", &self.root)
628            .field("line", &self.line)
629            .finish()
630    }
631}
632
633/// Parameter values can be used as arguments or hash values.
634#[derive(Debug, Eq, PartialEq)]
635pub enum ParameterValue<'source> {
636    /// A parameter that should resolve to a runtime variable.
637    Path(Path<'source>),
638    /// A literal JSON value.
639    Json {
640        /// The underlying template source.
641        source: &'source str,
642        /// The literal JSON value.
643        value: Value,
644        /// The byte span for the value.
645        span: Range<usize>,
646        /// The line range for the value.
647        line: Range<usize>,
648    },
649    /// A sub-expression to be invoked at runtime to determine the value.
650    SubExpr(Call<'source>),
651}
652
653impl<'source> From<(&'source str, Value, Range<usize>, Range<usize>)>
654    for ParameterValue<'source>
655{
656    fn from(value: (&'source str, Value, Range<usize>, Range<usize>)) -> Self {
657        ParameterValue::Json {
658            source: value.0,
659            value: value.1,
660            span: value.2,
661            line: value.3,
662        }
663    }
664}
665
666impl<'source> Slice<'source> for ParameterValue<'source> {
667    fn as_str(&self) -> &'source str {
668        match *self {
669            Self::Path(ref path) => path.as_str(),
670            Self::Json {
671                source, ref span, ..
672            } => &source[span.start..span.end],
673            Self::SubExpr(ref call) => call.as_str(),
674        }
675    }
676
677    fn source(&self) -> &'source str {
678        match *self {
679            Self::Path(ref path) => path.source(),
680            Self::Json { source, .. } => source,
681            Self::SubExpr(ref call) => call.source(),
682        }
683    }
684}
685
686impl<'source> Lines for ParameterValue<'source> {
687    fn lines(&self) -> &Range<usize> {
688        match *self {
689            ParameterValue::Path(ref path) => path.lines(),
690            ParameterValue::Json { ref line, .. } => line,
691            ParameterValue::SubExpr(ref call) => call.lines(),
692        }
693    }
694
695    fn lines_mut(&mut self) -> &mut Range<usize> {
696        match *self {
697            ParameterValue::Path(ref mut path) => path.lines_mut(),
698            ParameterValue::Json { ref mut line, .. } => line,
699            ParameterValue::SubExpr(ref mut call) => call.lines_mut(),
700        }
701    }
702}
703
704impl fmt::Display for ParameterValue<'_> {
705    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
706        write!(f, "{}", self.as_str())
707    }
708}
709
710/// Call targets represent either a helper call, partial render or variable path.
711///
712/// To support dynamic partials call targets may also be sub-expressions.
713#[derive(Debug, Eq, PartialEq)]
714pub enum CallTarget<'source> {
715    /// Path call target.
716    Path(Path<'source>),
717    /// Sub expression call target.
718    SubExpr(Box<Call<'source>>),
719}
720
721impl<'source> CallTarget<'source> {
722    /// Determine if this call target is empty.
723    pub fn is_empty(&self) -> bool {
724        match *self {
725            Self::Path(ref path) => path.is_empty(),
726            Self::SubExpr(ref call) => call.is_empty(),
727        }
728    }
729
730    /// Get the span for the call target.
731    ///
732    /// For paths this is the entire span for sub expressions
733    /// it is the open span.
734    pub fn span(&self) -> &Range<usize> {
735        match *self {
736            Self::Path(ref path) => path.span(),
737            Self::SubExpr(ref call) => call.open_span(),
738        }
739    }
740}
741
742impl<'source> Slice<'source> for CallTarget<'source> {
743    fn as_str(&self) -> &'source str {
744        match *self {
745            Self::Path(ref path) => path.as_str(),
746            Self::SubExpr(ref call) => call.as_str(),
747        }
748    }
749
750    fn source(&self) -> &'source str {
751        match *self {
752            Self::Path(ref path) => path.source(),
753            Self::SubExpr(ref call) => call.source(),
754        }
755    }
756}
757
758impl<'source> Lines for CallTarget<'source> {
759    fn lines(&self) -> &Range<usize> {
760        match *self {
761            Self::Path(ref path) => path.lines(),
762            Self::SubExpr(ref call) => call.lines(),
763        }
764    }
765
766    fn lines_mut(&mut self) -> &mut Range<usize> {
767        match *self {
768            Self::Path(ref mut path) => path.lines_mut(),
769            Self::SubExpr(ref mut call) => call.lines_mut(),
770        }
771    }
772}
773
774impl fmt::Display for CallTarget<'_> {
775    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
776        write!(f, "{}", self.as_str())
777    }
778}
779
780impl Default for CallTarget<'_> {
781    fn default() -> Self {
782        CallTarget::Path(Path::new("", 0..0, 0..0))
783    }
784}
785
786/// Call is a variable interpolation, helper invocation or partial
787/// render.
788///
789/// A call has zero or more arguments and optional hash parameters.
790///
791/// The partial flag is used to indicate that this call should be
792/// rendered as a partial.
793#[derive(Default, Eq, PartialEq)]
794pub struct Call<'source> {
795    // Raw source input.
796    source: &'source str,
797    partial: bool,
798    conditional: bool,
799    open: Range<usize>,
800    close: Option<Range<usize>>,
801    target: CallTarget<'source>,
802    arguments: Vec<ParameterValue<'source>>,
803    parameters: HashMap<&'source str, ParameterValue<'source>>,
804    line: Range<usize>,
805}
806
807impl<'source> Call<'source> {
808    /// Create an open call.
809    ///
810    /// If it is correctly terminated the parser will call `exit()` to terminate
811    /// the call statement.
812    pub fn new(
813        source: &'source str,
814        open: Range<usize>,
815        line: Range<usize>,
816    ) -> Self {
817        Self {
818            source,
819            partial: false,
820            conditional: false,
821            open,
822            close: None,
823            target: CallTarget::Path(Path::new(source, 0..0, 0..0)),
824            arguments: Vec::new(),
825            parameters: HashMap::new(),
826            line,
827        }
828    }
829
830    /// Determine if the target for this call is empty.
831    pub fn is_empty(&self) -> bool {
832        self.target.is_empty()
833    }
834
835    /// Get the call target.
836    pub fn target(&self) -> &CallTarget<'source> {
837        &self.target
838    }
839
840    /// Determine if a call target is available.
841    pub fn has_target(&self) -> bool {
842        self.target.as_str() != ""
843    }
844
845    /// Set the call target.
846    pub fn set_target(&mut self, target: CallTarget<'source>) {
847        self.target = target;
848    }
849
850    /// Add an argument to this call.
851    pub fn add_argument(&mut self, arg: ParameterValue<'source>) {
852        self.arguments.push(arg);
853    }
854
855    /// Get the list of arguments.
856    pub fn arguments(&self) -> &Vec<ParameterValue<'source>> {
857        &self.arguments
858    }
859
860    /// Add a hash parameter to this call.
861    pub fn add_parameter(
862        &mut self,
863        key: &'source str,
864        val: ParameterValue<'source>,
865    ) {
866        self.parameters.insert(key, val);
867    }
868
869    /// Get the map of hash parameters.
870    pub fn parameters(
871        &self,
872    ) -> &HashMap<&'source str, ParameterValue<'source>> {
873        &self.parameters
874    }
875
876    /// Determine if this call has the partial flag.
877    pub fn is_partial(&self) -> bool {
878        self.partial
879    }
880
881    /// Set the partial flag.
882    pub fn set_partial(&mut self, partial: bool) {
883        self.partial = partial;
884    }
885
886    /// Determine if this call has a conditional flag (the `else` keyword).
887    pub fn is_conditional(&self) -> bool {
888        self.conditional
889    }
890
891    /// Set the conditional flag.
892    pub fn set_conditional(&mut self, conditional: bool) {
893        self.conditional = conditional;
894    }
895
896    /// Determine if the content of this call should be escaped.
897    pub fn is_escaped(&self) -> bool {
898        // FIXME: ensure this is not `true` for raw blocks!
899        !self.open().starts_with("{{{")
900    }
901
902    fn trim_before(&self) -> bool {
903        self.open().ends_with(WHITESPACE)
904    }
905
906    fn trim_after(&self) -> bool {
907        self.close().starts_with(WHITESPACE)
908    }
909}
910
911impl<'source> Slice<'source> for Call<'source> {
912    fn as_str(&self) -> &'source str {
913        if let Some(ref close) = self.close {
914            return &self.source[self.open.start..close.end];
915        }
916        &self.source[self.open.start..self.open.end]
917    }
918
919    fn source(&self) -> &'source str {
920        self.source
921    }
922}
923
924impl<'source> Lines for Call<'source> {
925    fn lines(&self) -> &Range<usize> {
926        &self.line
927    }
928
929    fn lines_mut(&mut self) -> &mut Range<usize> {
930        &mut self.line
931    }
932}
933
934impl<'source> Element<'source> for Call<'source> {
935    fn open(&self) -> &'source str {
936        &self.source[self.open.start..self.open.end]
937    }
938
939    fn close(&self) -> &'source str {
940        if let Some(ref close) = self.close {
941            return &self.source[close.start..close.end];
942        }
943        ""
944    }
945
946    fn open_span(&self) -> &Range<usize> {
947        &self.open
948    }
949
950    fn close_span(&self) -> &Option<Range<usize>> {
951        &self.close
952    }
953
954    fn is_closed(&self) -> bool {
955        self.close.is_some()
956    }
957
958    fn exit(&mut self, close: Range<usize>) {
959        self.close = Some(close);
960    }
961}
962
963impl fmt::Display for Call<'_> {
964    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
965        write!(f, "{}", self.as_str())
966    }
967}
968
969impl fmt::Debug for Call<'_> {
970    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
971        f.debug_struct("Call")
972            .field("source", &self.as_str())
973            .field("partial", &self.partial)
974            .field("open", &self.open)
975            .field("close", &self.close)
976            .field("target", &self.target)
977            .field("arguments", &self.arguments)
978            .field("parameters", &self.parameters)
979            .finish()
980    }
981}
982
983/// Documents are abstract nodes that encapsulate a collection
984/// of child nodes.
985///
986/// They are used as the root node of a compiled template.
987#[derive(Eq, PartialEq)]
988pub struct Document<'source>(pub &'source str, pub Vec<Node<'source>>);
989
990impl<'source> Document<'source> {
991    /// List of child nodes.
992    pub fn nodes(&self) -> &Vec<Node<'source>> {
993        &self.1
994    }
995
996    /// Mutable list of child nodes.
997    pub fn nodes_mut(&mut self) -> &mut Vec<Node<'source>> {
998        &mut self.1
999    }
1000}
1001
1002impl<'source> Slice<'source> for Document<'source> {
1003    fn as_str(&self) -> &'source str {
1004        self.0
1005    }
1006    fn source(&self) -> &'source str {
1007        self.0
1008    }
1009}
1010
1011impl fmt::Display for Document<'_> {
1012    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1013        write!(f, "{}", self.as_str())
1014    }
1015}
1016
1017impl fmt::Debug for Document<'_> {
1018    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1019        f.debug_struct("Document").field("nodes", &self.1).finish()
1020    }
1021}
1022
1023/// Block encapsulates an inner template.
1024///
1025/// These nodes are rendered indirectly via registered helpers
1026/// that should call back in to the renderer.
1027///
1028/// When a block has the raw flag set it should only contain a
1029/// single `Text` child node.
1030#[derive(Eq, PartialEq)]
1031pub struct Block<'source> {
1032    source: &'source str,
1033    nodes: Vec<Node<'source>>,
1034    raw: bool,
1035    open: Range<usize>,
1036    close: Option<Range<usize>>,
1037    call: Call<'source>,
1038    conditionals: Vec<Node<'source>>,
1039    line: Range<usize>,
1040}
1041
1042impl<'source> Block<'source> {
1043    /// Create a new block.
1044    pub fn new(
1045        source: &'source str,
1046        open: Range<usize>,
1047        raw: bool,
1048        line: Range<usize>,
1049    ) -> Self {
1050        Self {
1051            source,
1052            nodes: Vec::new(),
1053            raw,
1054            open,
1055            close: None,
1056            call: Default::default(),
1057            conditionals: Vec::new(),
1058            line,
1059        }
1060    }
1061
1062    /// Get the call for the block.
1063    pub fn call(&self) -> &Call<'source> {
1064        &self.call
1065    }
1066
1067    /// Set the call for the block.
1068    pub fn set_call(&mut self, call: Call<'source>) {
1069        self.call = call;
1070    }
1071
1072    /// The name of this block extracted from the call target.
1073    ///
1074    /// This will only be available if the call target is a path
1075    /// and the path is a simple identifier.
1076    pub fn name(&self) -> Option<&'source str> {
1077        match self.call.target() {
1078            CallTarget::Path(ref path) => {
1079                if path.is_simple() {
1080                    let id = path.components().first().unwrap();
1081                    Some(id.as_str())
1082                } else {
1083                    None
1084                }
1085            }
1086            CallTarget::SubExpr(_) => None,
1087        }
1088    }
1089
1090    /// Determine if this block has the raw flag.
1091    pub fn is_raw(&self) -> bool {
1092        self.raw
1093    }
1094
1095    /// Add a condition to this block.
1096    pub fn add_condition(&mut self, condition: Block<'source>) {
1097        self.close_condition(condition.call.open.clone());
1098        self.conditionals.push(Node::Block(condition));
1099    }
1100
1101    /// Get the list of conditional blocks.
1102    pub fn conditions(&self) -> &Vec<Node<'source>> {
1103        &self.conditionals
1104    }
1105
1106    /// Add a node to this block; if this block has
1107    /// conditionals then the node is added to the last conditional.
1108    pub fn push(&mut self, node: Node<'source>) {
1109        if !self.conditionals.is_empty() {
1110            let mut last = self.conditionals.last_mut().unwrap();
1111            match &mut last {
1112                Node::Block(ref mut condition) => {
1113                    condition.nodes.push(node);
1114                }
1115                _ => {}
1116            }
1117        } else {
1118            self.nodes.push(node);
1119        }
1120    }
1121
1122    /// The collection of nodes for this block.
1123    ///
1124    /// For raw blocks this should always be a single `Text` node.
1125    pub fn nodes(&self) -> &'source Vec<Node> {
1126        &self.nodes
1127    }
1128
1129    /// The trim hint for the close tag.
1130    pub fn trim_close(&self) -> TrimHint {
1131        TrimHint {
1132            before: self.trim_before_close(),
1133            after: self.trim_after_close(),
1134        }
1135    }
1136
1137    fn close_condition(&mut self, span: Range<usize>) {
1138        if !self.conditionals.is_empty() {
1139            if span.start > 0 {
1140                let close = span.start - 1..span.start;
1141                let mut last = self.conditionals.last_mut().unwrap();
1142                match &mut last {
1143                    Node::Block(ref mut condition) => {
1144                        condition.close = Some(close);
1145                    }
1146                    _ => {}
1147                }
1148            }
1149        }
1150    }
1151
1152    fn trim_before(&self) -> bool {
1153        let open = self.open();
1154        if self.is_raw() {
1155            open.len() > 4 && WHITESPACE == &open[4..5]
1156        } else {
1157            open.len() > 2 && WHITESPACE == &open[2..3]
1158        }
1159    }
1160
1161    fn trim_after(&self) -> bool {
1162        self.call.trim_after()
1163    }
1164
1165    fn trim_before_close(&self) -> bool {
1166        let close = self.close();
1167        if self.is_raw() {
1168            close.len() > 4 && WHITESPACE == &close[4..5]
1169        } else {
1170            close.len() > 2 && WHITESPACE == &close[2..3]
1171        }
1172    }
1173
1174    fn trim_after_close(&self) -> bool {
1175        let close = self.close();
1176
1177        if self.is_raw() {
1178            if close.len() > 5 {
1179                let index = close.len() - 5;
1180                close.len() > 4 && WHITESPACE == &close[index..index + 1]
1181            } else {
1182                false
1183            }
1184        } else {
1185            if close.len() > 3 {
1186                let index = close.len() - 3;
1187                close.len() > 2 && WHITESPACE == &close[index..index + 1]
1188            } else {
1189                false
1190            }
1191        }
1192    }
1193}
1194
1195impl<'source> Slice<'source> for Block<'source> {
1196    fn as_str(&self) -> &'source str {
1197        let close = self.close.clone().unwrap_or(0..self.source.len());
1198        &self.source[self.open.start..close.end]
1199    }
1200
1201    fn source(&self) -> &'source str {
1202        self.source
1203    }
1204}
1205
1206impl<'source> Lines for Block<'source> {
1207    fn lines(&self) -> &Range<usize> {
1208        &self.line
1209    }
1210
1211    fn lines_mut(&mut self) -> &mut Range<usize> {
1212        &mut self.line
1213    }
1214}
1215
1216impl<'source> Element<'source> for Block<'source> {
1217    fn open(&self) -> &'source str {
1218        &self.source[self.open.start..self.open.end]
1219    }
1220
1221    fn close(&self) -> &'source str {
1222        if let Some(ref close) = self.close {
1223            &self.source[close.start..close.end]
1224        } else {
1225            ""
1226        }
1227    }
1228
1229    fn open_span(&self) -> &Range<usize> {
1230        &self.open
1231    }
1232
1233    fn close_span(&self) -> &Option<Range<usize>> {
1234        &self.close
1235    }
1236
1237    fn is_closed(&self) -> bool {
1238        self.close.is_some()
1239    }
1240
1241    fn exit(&mut self, span: Range<usize>) {
1242        // NOTE: close_condition() sets the span up until the next
1243        // NOTE: block but when we exit a block node the last conditional
1244        // NOTE: needs a close matching the end tag so that whitespace
1245        // NOTE: trim logic is correct.
1246        if !self.conditionals.is_empty() {
1247            let mut last = self.conditionals.last_mut().unwrap();
1248            match &mut last {
1249                Node::Block(ref mut condition) => {
1250                    condition.close = Some(span.clone());
1251                }
1252                _ => {}
1253            }
1254        }
1255
1256        self.close = Some(span);
1257    }
1258}
1259
1260impl fmt::Display for Block<'_> {
1261    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1262        for t in self.nodes() {
1263            t.fmt(f)?;
1264        }
1265        Ok(())
1266    }
1267}
1268
1269impl fmt::Debug for Block<'_> {
1270    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1271        f.debug_struct("Block")
1272            .field("line", &self.line)
1273            .field("open", &self.open)
1274            .field("close", &self.close)
1275            .field("call", &self.call)
1276            .field("nodes", &self.nodes)
1277            .finish()
1278    }
1279}
1280
1281/// Link node for wiki-style links.
1282#[derive(Eq, PartialEq)]
1283pub struct Link<'source> {
1284    source: &'source str,
1285    open: Range<usize>,
1286    close: Option<Range<usize>>,
1287    line: Range<usize>,
1288    href_span: Range<usize>,
1289    label_span: Range<usize>,
1290    title_span: Range<usize>,
1291
1292    // Owned value when escape sequences are detected
1293    href: Option<String>,
1294    label: Option<String>,
1295    title: Option<String>,
1296}
1297
1298impl<'source> Link<'source> {
1299    /// Create a new link.
1300    pub fn new(
1301        source: &'source str,
1302        open: Range<usize>,
1303        line: Range<usize>,
1304    ) -> Self {
1305        Self {
1306            source,
1307            href_span: open.end..open.end,
1308            label_span: open.end..open.end,
1309            title_span: open.end..open.end,
1310            open,
1311            line,
1312            close: None,
1313            href: None,
1314            label: None,
1315            title: None,
1316        }
1317    }
1318
1319    /// Get the link href.
1320    ///
1321    /// If an owned value has been set it is preferred.
1322    pub fn href(&self) -> &str {
1323        if let Some(ref href) = self.href {
1324            return href;
1325        }
1326        &self.source[self.href_span.start..self.href_span.end]
1327    }
1328
1329    /// Get the link label.
1330    ///
1331    /// If an owned value has been set it is preferred.
1332    pub fn label(&self) -> &str {
1333        let lbl = if let Some(ref label) = self.label {
1334            return label;
1335        } else {
1336            &self.source[self.label_span.start..self.label_span.end]
1337        };
1338
1339        lbl
1340    }
1341
1342    /// Get the link title.
1343    ///
1344    /// If an owned value has been set it is preferred.
1345    pub fn title(&self) -> &str {
1346        let title = if let Some(ref title) = self.title {
1347            return title;
1348        } else {
1349            &self.source[self.title_span.start..self.title_span.end]
1350        };
1351
1352        title
1353    }
1354
1355    /// Get the span for the href.
1356    pub fn href_span(&self) -> &Range<usize> {
1357        &self.href_span
1358    }
1359
1360    /// Get the span for the label.
1361    pub fn label_span(&self) -> &Range<usize> {
1362        &self.label_span
1363    }
1364
1365    /// Get the span for the title.
1366    pub fn title_span(&self) -> &Range<usize> {
1367        &self.title_span
1368    }
1369
1370    /// Update the end of the href span.
1371    pub fn href_end(&mut self, end: usize) {
1372        self.href_span.end = end;
1373    }
1374
1375    /// Update the start of the label span.
1376    pub fn label_start(&mut self, start: usize) {
1377        self.label_span.start = start;
1378    }
1379
1380    /// Update the end of the label span.
1381    pub fn label_end(&mut self, end: usize) {
1382        self.label_span.end = end;
1383    }
1384
1385    /// Update the start of the title span.
1386    pub fn title_start(&mut self, start: usize) {
1387        self.title_span.start = start;
1388    }
1389
1390    /// Update the end of the title span.
1391    pub fn title_end(&mut self, end: usize) {
1392        self.title_span.end = end;
1393    }
1394
1395    /// Set an owned value for the href.
1396    ///
1397    /// Only available when the parser detects escape sequences
1398    /// in the input.
1399    pub fn set_href(&mut self, value: String) {
1400        self.href = Some(value);
1401    }
1402
1403    /// Set an owned value for the label.
1404    ///
1405    /// Only available when the parser detects escape sequences
1406    /// in the input.
1407    pub fn set_label(&mut self, value: String) {
1408        self.label = Some(value);
1409    }
1410
1411    /// Set an owned value for the title.
1412    ///
1413    /// Only available when the parser detects escape sequences
1414    /// in the input.
1415    pub fn set_title(&mut self, value: String) {
1416        self.title = Some(value);
1417    }
1418
1419    /// Determine if this link has been escaped using a leading backslash.
1420    pub fn is_escaped(&self) -> bool {
1421        self.open().starts_with("\\")
1422    }
1423
1424    /// The value after a backslash escape.
1425    pub(crate) fn after_escape(&self) -> &'source str {
1426        let close = self.close.clone().unwrap_or(0..self.open.len());
1427        &self.source[self.open.start + 1..close.end]
1428    }
1429}
1430
1431impl<'source> Slice<'source> for Link<'source> {
1432    fn as_str(&self) -> &'source str {
1433        let close = self.close.clone().unwrap_or(0..self.open.len());
1434        &self.source[self.open.start..close.end]
1435    }
1436
1437    fn source(&self) -> &'source str {
1438        self.source
1439    }
1440}
1441
1442impl<'source> Lines for Link<'source> {
1443    fn lines(&self) -> &Range<usize> {
1444        &self.line
1445    }
1446
1447    fn lines_mut(&mut self) -> &mut Range<usize> {
1448        &mut self.line
1449    }
1450}
1451
1452impl<'source> Element<'source> for Link<'source> {
1453    fn open(&self) -> &'source str {
1454        &self.source[self.open.start..self.open.end]
1455    }
1456
1457    fn close(&self) -> &'source str {
1458        if let Some(ref close) = self.close {
1459            &self.source[close.start..close.end]
1460        } else {
1461            ""
1462        }
1463    }
1464
1465    fn open_span(&self) -> &Range<usize> {
1466        &self.open
1467    }
1468
1469    fn close_span(&self) -> &Option<Range<usize>> {
1470        &self.close
1471    }
1472
1473    fn is_closed(&self) -> bool {
1474        self.close.is_some()
1475    }
1476
1477    fn exit(&mut self, span: Range<usize>) {
1478        self.close = Some(span);
1479    }
1480}
1481
1482impl fmt::Display for Link<'_> {
1483    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1484        write!(f, "{}", self.as_str())
1485    }
1486}
1487
1488impl fmt::Debug for Link<'_> {
1489    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1490        f.debug_struct("Link")
1491            .field("open", &self.open)
1492            .field("close", &self.close)
1493            .field("href", &self.href)
1494            .field("label", &self.label)
1495            .finish()
1496    }
1497}