Skip to main content

rustlavel_view/
ast.rs

1//! The parsed shape of a template.
2
3use crate::expr::Expr;
4use rustlavel_core::Error;
5use std::collections::BTreeMap;
6
7/// One renderable piece of a template.
8#[derive(Debug, Clone, PartialEq)]
9pub enum Node {
10    /// Literal markup.
11    Text(String),
12    /// `{{ expr }}` when escaped, `{!! expr !!}` when not.
13    Echo { expr: Expr, escaped: bool },
14    /// `@if` / `@elseif` / `@else`: the first branch whose condition is truthy
15    /// wins, otherwise `otherwise` runs if there is one.
16    If { branches: Vec<Branch>, otherwise: Option<Vec<Node>> },
17    /// `@foreach(subject as binding)`.
18    Foreach { subject: Expr, binding: String, body: Vec<Node> },
19    /// `@yield("name")`, with the optional fallback from `@yield("name", expr)`.
20    Yield { section: String, default: Option<Expr> },
21    /// `@include("partial")`.
22    Include(TemplateRef),
23}
24
25/// One arm of an `@if` chain.
26#[derive(Debug, Clone, PartialEq)]
27pub struct Branch {
28    pub condition: Expr,
29    pub body: Vec<Node>,
30}
31
32/// A reference from one template to another.
33///
34/// It keeps the position it was written at, so "that layout does not exist" can
35/// be reported with the same precision as a syntax error instead of surfacing
36/// as a bare file-not-found from somewhere deep in the renderer.
37#[derive(Debug, Clone, PartialEq)]
38pub struct TemplateRef {
39    /// The referenced view name, as written.
40    pub name: String,
41    /// The view the reference was written in.
42    pub file: String,
43    pub line: usize,
44    pub column: usize,
45}
46
47impl TemplateRef {
48    /// Blame this reference for a failure.
49    pub fn error(&self, message: impl Into<String>) -> Error {
50        Error::Template {
51            file: self.file.clone(),
52            line: self.line,
53            column: self.column,
54            message: message.into(),
55        }
56    }
57}
58
59/// A parsed template: what it renders, plus the layout wiring around it.
60#[derive(Debug, Clone, PartialEq)]
61pub struct Template {
62    /// The view name it was loaded under, e.g. `pages.home`.
63    pub name: String,
64    /// Everything outside a `@section`.
65    pub nodes: Vec<Node>,
66    /// The layout named by `@extends`, if any.
67    pub extends: Option<TemplateRef>,
68    /// Section bodies, keyed by name and hoisted out of `nodes`.
69    ///
70    /// Sections are captured rather than rendered in place: they exist to be
71    /// pulled into a layout by `@yield`, so a template that defines one and is
72    /// rendered on its own simply does not emit it.
73    pub sections: BTreeMap<String, Vec<Node>>,
74}