doot/crates/doot-lang/src/ast.rs
2026-02-05 20:49:22 -06:00

323 lines
6.7 KiB
Rust

//! Abstract syntax tree definitions for the doot language.
use crate::lexer::Span;
use std::collections::HashMap;
/// Identifier type alias.
pub type Ident = String;
/// A parsed doot program.
#[derive(Clone, Debug, PartialEq)]
pub struct Program {
pub statements: Vec<Spanned<Statement>>,
}
/// Wraps a node with source location information.
#[derive(Clone, Debug, PartialEq)]
pub struct Spanned<T> {
pub node: T,
pub span: Span,
}
impl<T> Spanned<T> {
/// Creates a new spanned node.
pub fn new(node: T, span: Span) -> Self {
Self { node, span }
}
}
/// Top-level statement types.
#[derive(Clone, Debug, PartialEq)]
pub enum Statement {
VarDecl(VarDecl),
FnDecl(FnDecl),
StructDecl(StructDecl),
EnumDecl(EnumDecl),
TypeAlias(TypeAlias),
Import(Import),
Dotfile(Dotfile),
Package(Package),
Secret(Secret),
Hook(Hook),
MacroDecl(MacroDecl),
MacroCall(MacroCall),
ForLoop(ForLoop),
If(IfStatement),
Match(MatchStatement),
Expr(Expr),
Return(Option<Expr>),
}
/// Variable declaration.
#[derive(Clone, Debug, PartialEq)]
pub struct VarDecl {
pub name: Ident,
pub ty: Option<TypeAnnotation>,
pub value: Expr,
}
/// Function declaration.
#[derive(Clone, Debug, PartialEq)]
pub struct FnDecl {
pub name: Ident,
pub is_async: bool,
pub params: Vec<FnParam>,
pub return_type: Option<TypeAnnotation>,
pub body: Vec<Spanned<Statement>>,
}
/// Function parameter.
#[derive(Clone, Debug, PartialEq)]
pub struct FnParam {
pub name: Ident,
pub ty: TypeAnnotation,
pub default: Option<Expr>,
}
/// Struct type declaration.
#[derive(Clone, Debug, PartialEq)]
pub struct StructDecl {
pub name: Ident,
pub fields: Vec<StructField>,
pub methods: Vec<FnDecl>,
}
/// Struct field definition.
#[derive(Clone, Debug, PartialEq)]
pub struct StructField {
pub name: Ident,
pub ty: TypeAnnotation,
pub default: Option<Expr>,
}
/// Enum type declaration.
#[derive(Clone, Debug, PartialEq)]
pub struct EnumDecl {
pub name: Ident,
pub variants: Vec<EnumVariant>,
}
/// Enum variant definition.
#[derive(Clone, Debug, PartialEq)]
pub struct EnumVariant {
pub name: Ident,
pub fields: Option<Vec<TypeAnnotation>>,
}
/// Type alias declaration.
#[derive(Clone, Debug, PartialEq)]
pub struct TypeAlias {
pub name: Ident,
pub ty: TypeAnnotation,
}
/// Module import statement.
#[derive(Clone, Debug, PartialEq)]
pub struct Import {
pub path: String,
pub alias: Option<Ident>,
}
/// Deploy mode for dotfiles.
#[derive(Clone, Copy, Debug, PartialEq, Default)]
pub enum DeployMode {
#[default]
Copy,
Link,
}
/// Permission rule - either a single mode or pattern-based.
#[derive(Clone, Debug, PartialEq)]
pub enum PermissionRule {
Single(u32),
Pattern { pattern: String, mode: u32 },
}
/// Dotfile deployment declaration.
#[derive(Clone, Debug, PartialEq)]
pub struct Dotfile {
pub source: Expr,
pub target: Expr,
pub when: Option<Expr>,
pub template: Option<bool>,
pub permissions: Vec<PermissionRule>,
pub owner: Option<String>,
pub deploy: DeployMode,
pub link_patterns: Vec<String>,
pub copy_patterns: Vec<String>,
}
/// Package installation declaration.
#[derive(Clone, Debug, PartialEq)]
pub struct Package {
pub default: Option<Expr>,
pub brew: Option<PackageSpec>,
pub apt: Option<PackageSpec>,
pub pacman: Option<PackageSpec>,
pub yay: Option<PackageSpec>,
pub when: Option<Expr>,
}
/// Package manager-specific specification.
#[derive(Clone, Debug, PartialEq)]
pub struct PackageSpec {
pub name: Expr,
pub cask: Option<bool>,
pub tap: Option<String>,
}
/// Encrypted secret file declaration.
#[derive(Clone, Debug, PartialEq)]
pub struct Secret {
pub source: Expr,
pub target: Expr,
pub mode: Option<u32>,
}
/// Lifecycle hook declaration.
#[derive(Clone, Debug, PartialEq)]
pub struct Hook {
pub stage: HookStage,
pub run: Expr,
pub when: Option<Expr>,
}
/// Hook execution stage.
#[derive(Clone, Debug, PartialEq)]
pub enum HookStage {
BeforeDeploy,
AfterDeploy,
BeforePackage,
AfterPackage,
}
/// Macro definition.
#[derive(Clone, Debug, PartialEq)]
pub struct MacroDecl {
pub name: Ident,
pub params: Vec<Ident>,
pub body: Vec<Spanned<Statement>>,
}
/// Macro invocation.
#[derive(Clone, Debug, PartialEq)]
pub struct MacroCall {
pub name: Ident,
pub args: Vec<Expr>,
}
/// For loop statement.
#[derive(Clone, Debug, PartialEq)]
pub struct ForLoop {
pub var: Ident,
pub iter: Expr,
pub body: Vec<Spanned<Statement>>,
}
/// Conditional statement.
#[derive(Clone, Debug, PartialEq)]
pub struct IfStatement {
pub condition: Expr,
pub then_body: Vec<Spanned<Statement>>,
pub else_body: Option<Vec<Spanned<Statement>>>,
}
/// Pattern matching statement.
#[derive(Clone, Debug, PartialEq)]
pub struct MatchStatement {
pub expr: Expr,
pub arms: Vec<MatchArm>,
}
/// Single arm in a match statement.
#[derive(Clone, Debug, PartialEq)]
pub struct MatchArm {
pub pattern: Pattern,
pub body: Expr,
}
/// Match pattern types.
#[derive(Clone, Debug, PartialEq)]
pub enum Pattern {
Literal(Literal),
Ident(Ident),
EnumVariant { ty: Ident, variant: Ident },
Wildcard,
}
/// Expression types.
#[derive(Clone, Debug, PartialEq)]
pub enum Expr {
Literal(Literal),
Ident(Ident),
Path(Box<Expr>, Box<Expr>),
Binary(Box<Expr>, BinOp, Box<Expr>),
Unary(UnaryOp, Box<Expr>),
Call(Box<Expr>, Vec<Expr>),
MethodCall(Box<Expr>, Ident, Vec<Expr>),
Index(Box<Expr>, Box<Expr>),
Field(Box<Expr>, Ident),
EnumVariant(Ident, Ident),
StructInit(Ident, HashMap<Ident, Expr>),
List(Vec<Expr>),
If(Box<Expr>, Box<Expr>, Option<Box<Expr>>),
Lambda(Vec<FnParam>, Box<Expr>),
Await(Box<Expr>),
Interpolated(Vec<InterpolatedPart>),
HomePath(Box<Expr>),
}
/// Part of an interpolated string.
#[derive(Clone, Debug, PartialEq)]
pub enum InterpolatedPart {
Literal(String),
Expr(Expr),
}
/// Literal value types.
#[derive(Clone, Debug, PartialEq)]
pub enum Literal {
Int(i64),
Float(f64),
Str(String),
Bool(bool),
None,
}
/// Binary operators.
#[derive(Clone, Debug, PartialEq)]
pub enum BinOp {
Add,
Sub,
Mul,
Div,
Mod,
Eq,
NotEq,
Lt,
Gt,
LtEq,
GtEq,
And,
Or,
PathJoin,
NullCoalesce,
}
/// Unary operators.
#[derive(Clone, Debug, PartialEq)]
pub enum UnaryOp {
Neg,
Not,
}
/// Type annotation in source code.
#[derive(Clone, Debug, PartialEq)]
pub enum TypeAnnotation {
Simple(Ident),
List(Box<TypeAnnotation>),
Optional(Box<TypeAnnotation>),
Function(Vec<TypeAnnotation>, Box<TypeAnnotation>),
Union(Vec<TypeAnnotation>),
Literal(Literal),
}