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}