engawa-lisp 0.1.3

Tatara-lisp authoring layer for engawa render graphs. Operators write (defmaterial …) / (defgraph …) / (defeffect …) in a .tlisp file; this crate parses + lowers to engawa::RenderGraph. Pairs with shikumi's notify watcher for hot-reload.
Documentation
//! Typed s-expression tree — the parser's output, the lowering
//! step's input. Pure data; no parser state, no lifetimes.

use crate::parse::Span;

/// A single s-expression node carrying its source span for
/// error reporting.
#[derive(Debug, Clone, PartialEq)]
pub struct Sexpr {
    pub kind: SexprKind,
    pub span: Span,
}

#[derive(Debug, Clone, PartialEq)]
pub enum SexprKind {
    /// `(form arg arg …)`
    List(Vec<Sexpr>),
    /// `symbol-name`
    Symbol(String),
    /// `"quoted string"`
    String(String),
    /// `42` or `1.5` — operator-typed numbers; the lowering step
    /// reparses into the target Rust type (u32, f32, etc.).
    Number(String),
}

impl Sexpr {
    /// Convenience: if this sexpr is a list, return its
    /// elements. Otherwise None.
    #[must_use]
    pub fn as_list(&self) -> Option<&[Sexpr]> {
        if let SexprKind::List(items) = &self.kind {
            Some(items)
        } else {
            None
        }
    }

    /// Convenience: if this sexpr is a symbol, return its text.
    #[must_use]
    pub fn as_symbol(&self) -> Option<&str> {
        if let SexprKind::Symbol(s) = &self.kind {
            Some(s.as_str())
        } else {
            None
        }
    }

    /// Convenience: if this sexpr is a string literal, return its text.
    #[must_use]
    pub fn as_string(&self) -> Option<&str> {
        if let SexprKind::String(s) = &self.kind {
            Some(s.as_str())
        } else {
            None
        }
    }

    /// Convenience: if this sexpr is a number, return its text.
    #[must_use]
    pub fn as_number(&self) -> Option<&str> {
        if let SexprKind::Number(s) = &self.kind {
            Some(s.as_str())
        } else {
            None
        }
    }
}