heron_rebuild_syntax/
ast.rs

1/// type alias just to make type signatures look more consistent.
2pub type Ident<'a> = &'a str;
3/// type alias to make branch-related type signatures more readable.
4pub type Branch<'a> = Vec<(&'a str, &'a str)>;
5
6/// The right-hand side of any value expression.
7/// Ducttape originally had another rhs type:
8/// Sequential branchpoint expressions, written (Branchpoint: 0..10..1).
9#[derive(Debug, PartialEq, Eq)]
10pub enum Rhs<'a> {
11    /// no rhs (e.g. in output specs)
12    Unbound,
13    /// "some quoted value" or unquoted_value_without_spaces
14    Literal { val: &'a str },
15    /// $var
16    Variable { name: &'a str },
17    /// @
18    ShorthandVariable,
19    /// $var[Branchpoint: val]
20    GraftedVariable { name: Ident<'a>, branch: Branch<'a> },
21    /// $var@task
22    TaskOutput { task: &'a str, output: &'a str },
23    /// @task
24    ShorthandTaskOutput { task: &'a str },
25    /// $var@task[Branchpoint: val]
26    GraftedTaskOutput {
27        task: &'a str,
28        output: &'a str,
29        branch: Vec<(&'a str, &'a str)>,
30    },
31    /// @task[Branchpoint: val]
32    ShorthandGraftedTaskOutput {
33        task: &'a str,
34        branch: Vec<(&'a str, &'a str)>,
35    },
36    /// (Branchpoint: val1=$rhs1 val2=$rhs2)
37    Branchpoint {
38        branchpoint: &'a str,
39        vals: Vec<(&'a str, Self)>,
40    },
41    /// "foo-$bla-blee" or just 'foo'
42    Interp { text: &'a str, vars: Vec<&'a str> },
43}
44
45// These methods are just to assist with writing more legible tests.
46#[cfg(test)]
47impl<'a> Rhs<'a> {
48    pub fn literal(val: &'a str) -> Self {
49        Self::Literal { val }
50    }
51    pub fn variable(name: &'a str) -> Self {
52        Self::Variable { name }
53    }
54    // pub fn shorthand_variable() -> Self {
55    //     Self::ShorthandVariable
56    // }
57    pub fn grafted_variable(name: &'a str, branch: Branch<'a>) -> Self {
58        Self::GraftedVariable { name, branch }
59    }
60    pub fn task_output(output: Ident<'a>, task: Ident<'a>) -> Self {
61        Self::TaskOutput { output, task }
62    }
63    pub fn shorthand_task_output(task: Ident<'a>) -> Self {
64        Self::ShorthandTaskOutput { task }
65    }
66    pub fn grafted_task_output(output: Ident<'a>, task: Ident<'a>, branch: Branch<'a>) -> Self {
67        Self::GraftedTaskOutput {
68            output,
69            task,
70            branch,
71        }
72    }
73    pub fn shorthand_grafted_task_output(task: Ident<'a>, branch: Branch<'a>) -> Self {
74        Self::ShorthandGraftedTaskOutput { task, branch }
75    }
76    pub fn branchpoint(branchpoint: Ident<'a>, vals: Vec<(Ident<'a>, Self)>) -> Self {
77        Self::Branchpoint { branchpoint, vals }
78    }
79}
80
81/// One part of the header of a [`TasklikeBlock`].
82/// Ducttape had an additional spec type: package (syntax: ': package_name').
83#[derive(Debug, PartialEq, Eq)]
84pub enum BlockSpec<'a> {
85    Output {
86        lhs: &'a str,
87        rhs: Rhs<'a>,
88    },
89    Input {
90        lhs: &'a str,
91        rhs: Rhs<'a>,
92    },
93    Param {
94        lhs: &'a str,
95        rhs: Rhs<'a>,
96        dot: bool,
97    },
98    Module {
99        name: Ident<'a>,
100    },
101}
102
103#[cfg(test)]
104impl<'a> BlockSpec<'a> {
105    pub fn output(lhs: Ident<'a>, rhs: Rhs<'a>) -> Self {
106        Self::Output { lhs, rhs }
107    }
108    pub fn input(lhs: Ident<'a>, rhs: Rhs<'a>) -> Self {
109        Self::Input { lhs, rhs }
110    }
111    pub fn param(lhs: Ident<'a>, rhs: Rhs<'a>) -> Self {
112        Self::Param {
113            lhs,
114            rhs,
115            dot: false,
116        }
117    }
118    pub fn dot_param(lhs: Ident<'a>, rhs: Rhs<'a>) -> Self {
119        Self::Param {
120            lhs,
121            rhs,
122            dot: true,
123        }
124    }
125}
126
127/// Specific type of a [`TasklikeBlock`].
128/// Ducttape had the following additional types:
129/// package, action, versioner, submitter, function.
130/// We would like to at least add an equivalent to submitter in the future.
131#[derive(Debug, Clone, Copy, PartialEq, Eq)]
132pub enum BlockType {
133    Task,
134}
135
136/// A block which uses the task structure.
137#[derive(Debug, PartialEq, Eq)]
138pub struct TasklikeBlock<'a> {
139    /// Block name
140    pub name: &'a str,
141    /// Specific type of block
142    pub subtype: BlockType,
143    /// Header components
144    pub specs: Vec<BlockSpec<'a>>,
145    /// Bash code contained within braces
146    pub code: BashCode<'a>,
147}
148
149/// A block which consists of multiple nested [`TasklikeBlock`]s.
150#[derive(Debug, PartialEq, Eq)]
151pub struct GrouplikeBlock<'a> {
152    /// Block name
153    pub name: &'a str,
154    /// Specific type of block
155    pub subtype: BlockType,
156    /// Header components
157    pub specs: Vec<BlockSpec<'a>>,
158    /// Sub-blocks
159    pub blocks: Vec<TasklikeBlock<'a>>,
160}
161
162/// A block of bash code.
163#[derive(Debug, PartialEq, Eq)]
164pub struct BashCode<'a> {
165    /// The literal text of the code.
166    pub text: &'a str,
167    /// Set of variable names referenced in the code.
168    pub vars: crate::HashSet<Ident<'a>>,
169}
170
171/// Specification of branches for a single branchpoint.
172#[derive(Debug, PartialEq, Eq)]
173pub enum Branches<'a> {
174    /// Specifies all branches (`*`).
175    Glob,
176    /// A specific set of branches (e.g. `branch1 branch2 branch3` etc.)
177    Specified(Vec<&'a str>),
178}
179
180/// One part of a [`Plan`], consisting of a list of goal tasks and a list of branches.
181#[derive(Debug, PartialEq, Eq)]
182pub struct CrossProduct<'a> {
183    /// Task names for the traversal to reach.
184    pub goals: Vec<Ident<'a>>,
185    /// List of (branchpoint name, branches) pairs used to form traversal.
186    pub branches: Vec<(Ident<'a>, Branches<'a>)>,
187}
188
189/// A block of one or more [`CrossProduct`]s that specify a traversal through the workflow.
190#[derive(Debug, PartialEq, Eq)]
191pub struct Plan<'a> {
192    /// Plan name
193    pub name: &'a str,
194    /// List of contained [`CrossProduct`]s
195    pub cross_products: Vec<CrossProduct<'a>>,
196}
197
198/// One high-level item in the workflow.
199#[derive(Debug, PartialEq, Eq)]
200pub enum Item<'a> {
201    // Versioner(GrouplikeBlock<'a>),
202    /// A task definition.
203    Task(TasklikeBlock<'a>),
204    /// An import statement.
205    Import(&'a str),
206    // Package(TasklikeBlock<'a>),
207    /// A block of config variables.
208    GlobalConfig(Vec<(&'a str, Rhs<'a>)>),
209    /// A [`Plan`].
210    Plan(Plan<'a>),
211    /// A module definition.
212    Module(Ident<'a>, Rhs<'a>),
213}