lini 0.2.0

A small, human-readable language for plain-text diagrams that compiles to clean SVG
Documentation
//! The syntax tree: produced by [`super::parser`], consumed by `resolve`.
//!
//! A file is three ordered parts (SPEC §1/§3): the **stylesheet** (root
//! declarations, `--var` declarations, rules, and `name::base` defines), then
//! the **instances** (nodes), then the **wires**.

use crate::ast::{Side, WireOp};
use crate::span::Span;

#[derive(Debug, Clone)]
pub struct File {
    pub stylesheet: Vec<StyleItem>,
    pub instances: Vec<Child>,
    pub wires: Vec<Wire>,
}

/// A top-level stylesheet entry. Order among these is free; they all precede the
/// instances.
#[derive(Debug, Clone)]
pub enum StyleItem {
    /// `key: value;` at the file top — configures the root container.
    RootDecl(Decl),
    /// `--name: value;` — a themeable variable declaration. `Decl::name` holds
    /// the name without the `--` prefix.
    Var(Decl),
    /// `selector { decls }` — element / class / descendant rule.
    Rule(Rule),
    /// `name::base { body }` — a new type from a base, with its defaults.
    Define(Define),
}

#[derive(Debug, Clone)]
pub struct Rule {
    pub selector: Selector,
    pub decls: Vec<Decl>,
    pub span: Span,
}

/// One or more parts; more than one is a descendant combinator, matched against
/// a node's ancestor chain (ancestor → … → target), like CSS.
#[derive(Debug, Clone)]
pub struct Selector {
    pub parts: Vec<SelPart>,
}

#[derive(Debug, Clone)]
pub enum SelPart {
    /// A bare type name (`box`, a user type, …).
    Type(String),
    /// A `.class`.
    Class(String),
}

#[derive(Debug, Clone)]
pub struct Define {
    pub name: String,
    pub base: String,
    pub body: Block,
    pub span: Span,
}

/// A box — a drawn node (SPEC §3). At least one of id / type / block is present.
/// Its text is a `Child::Text` in the block, or its id (id-as-label) when the
/// block supplies none.
#[derive(Debug, Clone)]
pub struct Node {
    pub id: Option<String>,
    /// `|type|`; `None` means the default `box`, filled at resolve.
    pub ty: Option<String>,
    pub classes: Vec<String>,
    pub block: Option<Block>,
    pub span: Span,
}

/// A box or define body: declarations, then children (boxes and text, in source
/// order), then internal wires (SPEC §3 — the fixed in-block order).
#[derive(Debug, Clone, Default)]
pub struct Block {
    pub decls: Vec<Decl>,
    pub children: Vec<Child>,
    pub wires: Vec<Wire>,
}

/// A body child, in source order: a box or a bare text node (SPEC §3).
#[derive(Debug, Clone)]
pub enum Child {
    Box(Node),
    Text(TextNode),
}

/// Bare text content `"…"` (SPEC §3) — a label, a cell, a wire label. No id,
/// type, classes, or block; never a wrapped node.
#[derive(Debug, Clone)]
pub struct TextNode {
    pub text: String,
    pub span: Span,
}

#[derive(Debug, Clone)]
pub struct Wire {
    pub chain: Vec<EndpointGroup>,
    pub op: WireOp,
    pub classes: Vec<String>,
    pub block: Option<WireBlock>,
    pub span: Span,
}

/// A wire body (SPEC §9): declarations (including `along:`) and labels — bare
/// text, or a `|plain|` box for a styled / offset label.
#[derive(Debug, Clone, Default)]
pub struct WireBlock {
    pub decls: Vec<Decl>,
    pub labels: Vec<Child>,
}

#[derive(Debug, Clone)]
pub struct EndpointGroup {
    pub endpoints: Vec<Endpoint>,
}

#[derive(Debug, Clone)]
pub struct Endpoint {
    pub path: Vec<String>,
    pub side: Option<Side>,
    pub span: Span,
}

/// `key: v…, v…;` — a declaration. `groups` is the comma-separated value list;
/// each group is a space-separated value sequence. One group is the common case;
/// `points` is the multi-group case.
#[derive(Debug, Clone)]
pub struct Decl {
    pub name: String,
    pub groups: Vec<Vec<Value>>,
    pub span: Span,
}

#[derive(Debug, Clone)]
pub enum Value {
    Number(f64),
    String(String),
    Hex(String),
    Ident(String),
    /// `--name` reference (name stored without the `--`).
    Var(String),
    /// `rgb(…)`, `hsl(…)`, `repeat(…)`.
    Call(Call),
}

#[derive(Debug, Clone)]
pub struct Call {
    pub name: String,
    pub args: Vec<Value>,
}