Skip to main content

alba_syntax/
ast.rs

1//! Typed AST for the Beamfile DSL, produced by [`crate::parser::parse`].
2//!
3//! Every piece of source-derived data is wrapped in [`Spanned<T>`] so
4//! diagnostics can point a caret at the exact offending text rather than at
5//! an enclosing construct.
6//!
7//! String-shaped beam fields (`description`, `inputs`, `outputs`, `run`,
8//! `env` values, `cwd`, and the string/list variants of an executor option
9//! value) are [`StringTemplate`]s: every string in the AST supports
10//! `{expr}` interpolation. Identifiers that name things rather than hold
11//! interpolatable text (`import` paths, the `as` alias, `version`,
12//! `default`, beam names, parameter names) stay plain `Spanned<String>`.
13
14use crate::expr::Expr;
15use crate::template::StringTemplate;
16use crate::token::Span;
17
18/// A value together with the span of source text it was parsed from.
19#[derive(Debug, Clone, PartialEq)]
20pub struct Spanned<T> {
21    pub value: T,
22    pub span: Span,
23}
24
25impl<T> Spanned<T> {
26    pub fn new(value: T, span: Span) -> Self {
27        Self { value, span }
28    }
29}
30
31/// A fully parsed Beamfile.
32#[derive(Debug, Clone, PartialEq)]
33pub struct File {
34    pub version: Option<Spanned<String>>,
35    pub imports: Vec<Import>,
36    pub lets: Vec<LetBinding>,
37    pub default: Option<Spanned<String>>,
38    pub beams: Vec<BeamDecl>,
39    pub hooks: Vec<HookDecl>,
40}
41
42/// `import "path" as alias`.
43#[derive(Debug, Clone, PartialEq)]
44pub struct Import {
45    pub path: Spanned<String>,
46    pub alias: Spanned<String>,
47}
48
49/// `let name = value`.
50#[derive(Debug, Clone, PartialEq)]
51pub struct LetBinding {
52    pub name: Spanned<String>,
53    pub value: Expr,
54}
55
56/// A reference to a beam in a `needs [...]` list, optionally namespaced by
57/// the import aliases it is reached through (`api:build`, `api:db:migrate`,
58/// or plain `codegen`).
59#[derive(Debug, Clone, PartialEq, Eq)]
60pub struct BeamRef {
61    /// The alias segments preceding the name, outermost first: empty for a
62    /// local beam, `["api"]` for `api:build`, `["api", "db"]` for a beam
63    /// reached through two levels of importing. A chain of aliases is what
64    /// produces a multi-segment beam id, so `needs` has to be able to
65    /// spell one.
66    pub namespace: Vec<String>,
67    pub name: String,
68}
69
70/// A `NAME = value` entry in an `env { ... }` block: a name paired with its
71/// templated string value. Named to keep clippy's `type_complexity` lint
72/// quiet.
73pub type NamedString = (Spanned<String>, StringTemplate);
74
75/// The value half of an `executor { ... }` block's `option value` entry:
76/// a string (`image "x"`), a boolean (`remote true`), or a list of strings
77/// (`volumes ["a:/b", "c:/d"]`). Unlike `env`'s values, an executor option
78/// is never a bare identifier — see `parser.rs`'s `parse_executor_decl`.
79#[derive(Debug, Clone, PartialEq)]
80pub enum ExecutorOptionValue {
81    Str(StringTemplate),
82    Bool(bool),
83    List(Vec<StringTemplate>),
84}
85
86/// `executor <name> { option value, ... }`.
87#[derive(Debug, Clone, PartialEq)]
88pub struct ExecutorDecl {
89    pub name: Spanned<String>,
90    pub options: Vec<(Spanned<String>, ExecutorOptionValue)>,
91}
92
93/// `beam name(params) { ... }`.
94#[derive(Debug, Clone, PartialEq)]
95pub struct BeamDecl {
96    pub name: Spanned<String>,
97    pub params: Vec<Spanned<String>>,
98    pub description: Option<StringTemplate>,
99    pub needs: Vec<Spanned<BeamRef>>,
100    pub inputs: Vec<StringTemplate>,
101    pub outputs: Vec<StringTemplate>,
102    /// One entry for the single-string form of `run`, N entries for the
103    /// list form.
104    pub run: Vec<StringTemplate>,
105    pub env: Vec<NamedString>,
106    pub cwd: Option<StringTemplate>,
107    pub executor: Option<ExecutorDecl>,
108    pub allow_failure: bool,
109    pub span: Span,
110}
111
112/// `hook <name> { beam <ref> }`: a git hook bound to the beam it runs.
113#[derive(Debug, Clone, PartialEq)]
114pub struct HookDecl {
115    /// The git hook name as written (`pre-commit`); whether git knows it
116    /// is `alba-core`'s check.
117    pub name: Spanned<String>,
118    pub beam: Spanned<BeamRef>,
119    pub span: Span,
120}