use vize_l0::{Box, Vec};
use crate::markup::surface::Token;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PugRefusal {
Doctype,
Yield,
Interpolation,
Case,
When,
Default,
Extends,
Block,
MixinBlock,
Include,
Mixin,
Conditional,
Each,
While,
Filter,
BlockCode,
}
impl PugRefusal {
pub fn keyword(self) -> &'static str {
match self {
Self::Doctype => "doctype",
Self::Yield => "yield",
Self::Interpolation => "#{…} tag interpolation",
Self::Case => "case",
Self::When => "when",
Self::Default => "default",
Self::Extends => "extends",
Self::Block => "block",
Self::MixinBlock => "block (mixin block)",
Self::Include => "include",
Self::Mixin => "mixin",
Self::Conditional => "if/unless/else",
Self::Each => "each/for",
Self::While => "while",
Self::Filter => ":filter",
Self::BlockCode => "- block code",
}
}
}
#[derive(Debug)]
pub struct PugTree<'a> {
pub source: &'a str,
pub nodes: Vec<'a, PugNode<'a>>,
pub eof: Token<'a>,
}
#[derive(Debug)]
pub enum PugNode<'a> {
Tag(Box<'a, PugTag<'a>>),
Call(Box<'a, PugCall<'a>>),
Text(Box<'a, PugText<'a>>),
Html(Box<'a, PugHtml<'a>>),
TextBlock(Box<'a, PugDotBlock<'a>>),
Code(Box<'a, PugCode<'a>>),
Comment(Box<'a, PugComment<'a>>),
Refused(Box<'a, PugRefused<'a>>),
Unexpected(Box<'a, PugUnexpected<'a>>),
}
#[derive(Debug)]
pub struct PugTag<'a> {
pub name: Option<Token<'a>>,
pub parts: Vec<'a, PugTagPart<'a>>,
pub dot: Option<Token<'a>>,
pub inline: PugInline<'a>,
pub block: PugBlock<'a>,
}
impl<'a> PugTag<'a> {
pub fn tag_name(&self) -> &'a str {
self.name.map_or("div", |token| token.text)
}
}
#[derive(Debug)]
pub enum PugTagPart<'a> {
Class(Token<'a>),
Id(Token<'a>),
Attrs(Box<'a, PugAttrGroup<'a>>),
AndAttributes(Token<'a>),
}
#[derive(Debug)]
pub struct PugCall<'a> {
pub head: Token<'a>,
pub args: Option<Token<'a>>,
pub tag: PugTag<'a>,
}
impl<'a> PugCall<'a> {
pub fn arguments(&self) -> Option<&'a str> {
let text = self.args.as_ref()?.text;
text.strip_prefix('(')?.strip_suffix(')')
}
}
#[derive(Debug)]
pub struct PugAttrGroup<'a> {
pub open: Token<'a>,
pub items: Vec<'a, PugAttrItem<'a>>,
pub close: Token<'a>,
}
#[derive(Debug)]
pub enum PugAttrItem<'a> {
Attr(PugAttr<'a>),
Unexpected(Token<'a>),
}
#[derive(Debug)]
pub struct PugAttr<'a> {
pub name: Token<'a>,
pub op: Option<Token<'a>>,
pub value: Option<Token<'a>>,
pub comma: Option<Token<'a>>,
}
impl PugAttr<'_> {
pub fn key(&self) -> &str {
let text = self.name.text;
match text.chars().next() {
Some(quote @ ('"' | '\'')) => {
let inner = text.strip_prefix(quote).unwrap_or(text);
inner.strip_suffix(quote).unwrap_or(inner)
}
_ => text,
}
}
pub fn unescaped(&self) -> bool {
self.op.is_some_and(|op| op.text == "!=")
}
}
#[derive(Debug)]
pub enum PugInline<'a> {
None,
Text(PugText<'a>),
Code(Box<'a, PugCode<'a>>),
Expansion {
colon: Token<'a>,
node: Box<'a, PugNode<'a>>,
},
SelfClosing(Token<'a>),
}
#[derive(Debug)]
pub enum PugBlock<'a> {
Nodes(Vec<'a, PugNode<'a>>),
Text(PugText<'a>),
}
#[derive(Debug)]
pub struct PugText<'a> {
pub pieces: Vec<'a, PugTextPiece<'a>>,
}
#[derive(Debug)]
pub enum PugTextPiece<'a> {
Pipe(Token<'a>),
Raw(Token<'a>),
Escape(Token<'a>),
Newline(u32),
Interpolation(Box<'a, PugInterpolation<'a>>),
Code(Token<'a>),
Unexpected(Token<'a>),
}
#[derive(Debug)]
pub struct PugInterpolation<'a> {
pub open: Token<'a>,
pub nodes: Vec<'a, PugNode<'a>>,
pub close: Token<'a>,
}
#[derive(Debug)]
pub struct PugHtml<'a> {
pub items: Vec<'a, PugHtmlItem<'a>>,
}
#[derive(Debug)]
pub enum PugHtmlItem<'a> {
Line(PugText<'a>),
Block(Vec<'a, PugNode<'a>>),
Code(Box<'a, PugCode<'a>>),
}
#[derive(Debug)]
pub struct PugDotBlock<'a> {
pub dot: Token<'a>,
pub text: PugText<'a>,
}
#[derive(Debug)]
pub struct PugCode<'a> {
pub flag: Token<'a>,
pub code: Token<'a>,
pub block: Vec<'a, PugNode<'a>>,
}
impl PugCode<'_> {
pub fn buffered(&self) -> bool {
self.flag.text != "-"
}
pub fn escaped(&self) -> bool {
self.flag.text == "="
}
}
#[derive(Debug)]
pub struct PugComment<'a> {
pub marker: Token<'a>,
pub text: Token<'a>,
pub body: Option<PugText<'a>>,
}
impl PugComment<'_> {
pub fn buffered(&self) -> bool {
self.marker.text == "//"
}
}
#[derive(Debug)]
pub struct PugRefused<'a> {
pub refusal: PugRefusal,
pub head: Token<'a>,
pub body: Option<PugText<'a>>,
pub block: Vec<'a, PugNode<'a>>,
}
#[derive(Debug)]
pub struct PugUnexpected<'a> {
pub token: Token<'a>,
pub block: Vec<'a, PugNode<'a>>,
}