upon 0.6.0

A lightweight and powerful template engine
Documentation
//! AST representing a template.

use crate::types::span::Span;

#[cfg_attr(internal_debug, derive(Debug))]
pub struct Template {
    pub scope: Scope,
}

#[cfg_attr(internal_debug, derive(Debug))]
pub struct Scope {
    pub stmts: Vec<Stmt>,
}

#[cfg_attr(internal_debug, derive(Debug))]
pub enum Stmt {
    Raw(Span),
    InlineExpr(InlineExpr),
    Include(Include),
    IfElse(IfElse),
    ForLoop(ForLoop),
    With(With),
}

#[cfg_attr(internal_debug, derive(Debug))]
pub struct InlineExpr {
    pub expr: Expr,
    pub span: Span,
}

#[cfg_attr(internal_debug, derive(Debug))]
pub struct Include {
    pub name: String,
    pub globals: Option<Expr>,
}

#[cfg_attr(internal_debug, derive(Debug))]
pub struct String {
    pub name: std::string::String,
    pub span: Span,
}

#[cfg_attr(internal_debug, derive(Debug))]
pub struct IfElse {
    pub not: bool,
    pub cond: Expr,
    pub then_branch: Scope,
    pub else_branch: Option<Scope>,
}

#[cfg_attr(internal_debug, derive(Debug))]
pub struct ForLoop {
    pub vars: LoopVars,
    pub iterable: Expr,
    pub body: Scope,
}

#[cfg_attr(internal_debug, derive(Debug))]
pub enum LoopVars {
    Item(Ident),
    KeyValue(KeyValue),
}

#[cfg_attr(internal_debug, derive(Debug))]
pub struct KeyValue {
    pub key: Ident,
    pub value: Ident,
    pub span: Span,
}

#[cfg_attr(internal_debug, derive(Debug))]
pub struct With {
    pub expr: Expr,
    pub name: Ident,
    pub body: Scope,
}

#[cfg_attr(internal_debug, derive(Debug))]
pub enum Expr {
    Base(BaseExpr),
    Call(Call),
}

#[cfg_attr(internal_debug, derive(Debug))]
pub struct Call {
    pub name: Ident,
    pub args: Option<Args>,
    pub receiver: Box<Expr>,
    pub span: Span,
}

#[cfg_attr(internal_debug, derive(Debug))]
pub struct Args {
    pub values: Vec<BaseExpr>,
    pub span: Span,
}

#[cfg_attr(internal_debug, derive(Debug))]
pub enum BaseExpr {
    Var(Var),
    Literal(Literal),
}

#[cfg_attr(internal_debug, derive(Debug))]
pub struct Var {
    pub path: Vec<Key>,
}

#[derive(Clone, Copy)]
#[cfg_attr(internal_debug, derive(Debug))]
pub enum Key {
    Ident(Ident),
    Index(Index),
}

#[derive(Clone, Copy)]
#[cfg_attr(internal_debug, derive(Debug))]
pub struct Ident {
    pub span: Span,
}

#[derive(Clone, Copy)]
#[cfg_attr(internal_debug, derive(Debug))]
pub struct Index {
    pub value: usize,
    pub span: Span,
}

#[cfg_attr(internal_debug, derive(Debug))]
pub struct Literal {
    pub value: crate::Value,
    pub span: Span,
}

impl Scope {
    pub const fn new() -> Self {
        Self { stmts: Vec::new() }
    }
}

impl Expr {
    pub fn span(&self) -> Span {
        match self {
            Self::Base(base) => base.span(),
            Self::Call(call) => call.span,
        }
    }
}

impl BaseExpr {
    pub fn span(&self) -> Span {
        match self {
            BaseExpr::Var(var) => var.span(),
            BaseExpr::Literal(lit) => lit.span,
        }
    }
}

impl Var {
    pub fn span(&self) -> Span {
        self.first().span().combine(self.last().span())
    }

    pub fn first(&self) -> &Key {
        self.path.first().unwrap()
    }

    pub fn last(&self) -> &Key {
        self.path.last().unwrap()
    }

    pub fn rest(&self) -> &[Key] {
        &self.path[1..]
    }
}

impl Key {
    pub const fn span(&self) -> Span {
        match self {
            Key::Ident(ident) => ident.span,
            Key::Index(index) => index.span,
        }
    }
}