calyx_frontend/
ast.rs

1//! Abstract Syntax Tree for Calyx
2use super::parser;
3use crate::{Attributes, PortDef, Primitive, source_info::SourceInfoTable};
4use atty::Stream;
5use calyx_utils::{CalyxResult, Error, GPosIdx, Id, PosString};
6use std::{num::NonZeroU64, path::PathBuf};
7
8/// Corresponds to an individual Calyx file.
9#[derive(Debug)]
10pub struct NamespaceDef {
11    /// Path to extern files.
12    pub imports: Vec<PosString>,
13    /// List of component definitions.
14    pub components: Vec<ComponentDef>,
15    /// Extern statements and any primitive declarations in them.
16    pub externs: Vec<(Option<PosString>, Vec<Primitive>)>,
17    /// Optional opaque metadata.
18    pub metadata: Option<String>,
19    /// Optional Source Info table
20    pub source_info_table: Option<SourceInfoTable>,
21}
22
23impl NamespaceDef {
24    /// Construct a namespace from a file or the input stream.
25    /// If no file is provided, the input stream must be a TTY.
26    pub fn construct(file: &Option<PathBuf>) -> CalyxResult<Self> {
27        match file {
28            Some(file) => parser::CalyxParser::parse_file(file),
29            None => {
30                if atty::isnt(Stream::Stdin) {
31                    parser::CalyxParser::parse(std::io::stdin())
32                } else {
33                    Err(Error::invalid_file(
34                        "No file provided and terminal not a TTY".to_string(),
35                    ))
36                }
37            }
38        }
39    }
40
41    /// Construct a namespace from a definition using a string.
42    pub fn construct_from_str(inp: &str) -> CalyxResult<Self> {
43        parser::CalyxParser::parse(inp.as_bytes())
44    }
45}
46
47/// AST statement for defining components.
48#[derive(Debug)]
49pub struct ComponentDef {
50    /// Name of the component.
51    pub name: Id,
52    /// Defines input and output ports along with their attributes.
53    pub signature: Vec<PortDef<u64>>,
54    /// List of instantiated sub-components
55    pub cells: Vec<Cell>,
56    /// List of groups
57    pub groups: Vec<Group>,
58    /// List of StaticGroups
59    pub static_groups: Vec<StaticGroup>,
60    /// List of fsms
61    pub fsms: Vec<Fsm>,
62    /// List of continuous assignments
63    pub continuous_assignments: Vec<Wire>,
64    /// Single control statement for this component.
65    pub control: Control,
66    /// Attributes attached to this component
67    pub attributes: Attributes,
68    /// True iff this is a combinational component
69    pub is_comb: bool,
70    /// (Optional) latency of component, if it is static
71    pub latency: Option<NonZeroU64>,
72}
73
74impl ComponentDef {
75    pub fn new<S>(
76        name: S,
77        is_comb: bool,
78        latency: Option<NonZeroU64>,
79        signature: Vec<PortDef<u64>>,
80    ) -> Self
81    where
82        S: Into<Id>,
83    {
84        Self {
85            name: name.into(),
86            signature,
87            cells: Vec::new(),
88            groups: Vec::new(),
89            static_groups: Vec::new(),
90            fsms: Vec::new(),
91            continuous_assignments: Vec::new(),
92            control: Control::empty(),
93            attributes: Attributes::default(),
94            is_comb,
95            latency,
96        }
97    }
98}
99
100/// Statement that refers to a port on a subcomponent.
101/// This is distinct from a `Portdef` which defines a port.
102#[derive(Debug)]
103pub enum Port {
104    /// Refers to the port named `port` on the subcomponent
105    /// `component`.
106    Comp { component: Id, port: Id },
107
108    /// Refers to the port named `port` on the component
109    /// currently being defined.
110    This { port: Id },
111
112    /// `struct_elem[name]` parses into `Hole { struct_elem, name }`
113    /// and is a hole named `name` on `struct_elem`, which is the
114    /// name of either a group or an FSM
115    Hole { struct_elem: Id, name: Id },
116}
117
118// ===================================
119// AST for wire guard expressions
120// ===================================
121
122#[derive(Debug)]
123pub enum NumType {
124    Decimal,
125    Binary,
126    Octal,
127    Hex,
128}
129
130/// Custom bitwidth numbers
131#[derive(Debug)]
132pub struct BitNum {
133    pub width: u64,
134    pub num_type: NumType,
135    pub val: u64,
136    pub span: GPosIdx,
137}
138
139/// Atomic operations used in guard conditions and RHS of the
140/// guarded assignments.
141#[derive(Debug)]
142pub enum Atom {
143    /// Accessing a particular port on a component.
144    Port(Port),
145    /// A constant.
146    Num(BitNum),
147}
148
149/// The AST for GuardExprs
150#[derive(Debug)]
151pub enum GuardExpr {
152    // Logical operations
153    And(Box<GuardExpr>, Box<GuardExpr>),
154    Or(Box<GuardExpr>, Box<GuardExpr>),
155    Not(Box<GuardExpr>),
156    CompOp(CompGuard),
157    Atom(Atom),
158}
159
160/// Guard Comparison Type
161pub type CompGuard = (GuardComp, Atom, Atom);
162
163/// The AST for StaticGuardExprs
164#[derive(Debug)]
165pub enum StaticGuardExpr {
166    And(Box<StaticGuardExpr>, Box<StaticGuardExpr>),
167    Or(Box<StaticGuardExpr>, Box<StaticGuardExpr>),
168    Not(Box<StaticGuardExpr>),
169    CompOp(CompGuard),
170    Atom(Atom),
171    StaticInfo((u64, u64)),
172}
173
174/// Possible comparison operators for guards.
175#[derive(Debug)]
176pub enum GuardComp {
177    Eq,
178    Neq,
179    Gt,
180    Lt,
181    Geq,
182    Leq,
183}
184
185/// Guards `expr` using the optional guard condition `guard`.
186#[derive(Debug)]
187pub struct Guard {
188    pub guard: Option<GuardExpr>,
189    pub expr: Atom,
190}
191
192/// Guards `expr` using the optional guard condition `guard`.
193#[derive(Debug)]
194pub struct StaticGuard {
195    pub guard: Option<StaticGuardExpr>,
196    pub expr: Atom,
197}
198
199// ===================================
200// Data definitions for Structure
201// ===================================
202
203/// Prototype of the cell definition
204#[derive(Debug)]
205pub struct Proto {
206    /// Name of the primitive.
207    pub name: Id,
208    /// Parameter binding for primitives
209    pub params: Vec<u64>,
210}
211
212/// The Cell AST nodes.
213#[derive(Debug)]
214pub struct Cell {
215    /// Name of the cell.
216    pub name: Id,
217    /// Name of the prototype this cell was built from.
218    pub prototype: Proto,
219    /// Attributes attached to this cell definition
220    pub attributes: Attributes,
221    /// Whether this cell is external
222    pub reference: bool,
223}
224
225/// Methods for constructing the structure AST nodes.
226impl Cell {
227    /// Constructs a primitive cell instantiation.
228    pub fn from(
229        name: Id,
230        proto: Id,
231        params: Vec<u64>,
232        attributes: Attributes,
233        reference: bool,
234    ) -> Cell {
235        Cell {
236            name,
237            prototype: Proto {
238                name: proto,
239                params,
240            },
241            attributes,
242            reference,
243        }
244    }
245}
246
247#[derive(Debug)]
248pub struct Group {
249    pub name: Id,
250    pub wires: Vec<Wire>,
251    pub attributes: Attributes,
252    pub is_comb: bool,
253}
254
255#[derive(Debug)]
256pub struct StaticGroup {
257    pub name: Id,
258    pub wires: Vec<StaticWire>,
259    pub attributes: Attributes,
260    pub latency: NonZeroU64,
261}
262
263#[derive(Debug)]
264/// The next state transition for an FSM.
265///
266/// Transitions are either `Unconditional` (always transition to one specific state) or
267/// `Conditional` (with a set of guards mapping to next states). For the `Conditional` case, we
268/// have a list of guards and their corresponding states; the last entry in this list is the
269/// default transition.
270pub enum Transition {
271    Unconditional(u64),
272    Conditional(Vec<(Option<GuardExpr>, u64)>),
273}
274
275#[derive(Debug)]
276/// A single state in an FSM.
277///
278/// A `FSMRule` consists of the set of assignments that are active in a given state and the
279/// transitions from this state to other states. The assignments are a list of wires, like a
280/// `group` definition.
281pub struct FSMState {
282    pub assignments: Vec<Wire>,
283    pub transition: Transition,
284}
285
286#[derive(Debug)]
287/// A fsm block has a name, attributes, and `FSMRule`s
288/// that correspond to all the states within the fsm.
289pub struct Fsm {
290    // Name of the fsm construct
291    pub name: Id,
292    // Attributes attached to this fsm
293    pub attributes: Attributes,
294    // A list of rules, indexed by state.
295    pub fsm_states: Vec<FSMState>,
296}
297
298/// Data for the `->` structure statement.
299#[derive(Debug)]
300pub struct Wire {
301    /// Source of the wire.
302    pub src: Guard,
303
304    /// Guarded destinations of the wire.
305    pub dest: Port,
306
307    /// Attributes for this assignment
308    pub attributes: Attributes,
309}
310
311/// Data for the `->` structure statement.
312#[derive(Debug)]
313pub struct StaticWire {
314    /// Source of the wire.
315    pub src: StaticGuard,
316
317    /// Guarded destinations of the wire.
318    pub dest: Port,
319
320    /// Attributes for this assignment
321    pub attributes: Attributes,
322}
323
324/// Control AST nodes.
325/// Since enables and static enables are indistinguishable to the AST, there
326/// is single Control Enum for both Static and Dynamic Control
327#[derive(Debug)]
328#[allow(clippy::large_enum_variant)]
329pub enum Control {
330    /// Represents sequential composition of control statements.
331    Seq {
332        /// List of `Control` statements to run in sequence.
333        stmts: Vec<Control>,
334        /// Attributes
335        attributes: Attributes,
336    },
337    /// Represents parallel composition of control statements.
338    Par {
339        /// List of `Control` statements to run in sequence.
340        stmts: Vec<Control>,
341        /// Attributes
342        attributes: Attributes,
343    },
344    /// Standard imperative if statement
345    If {
346        /// Port that connects the conditional check.
347        port: Port,
348
349        /// Modules that need to be enabled to send signal on `port`.
350        cond: Option<Id>,
351
352        /// Control for the true branch.
353        tbranch: Box<Control>,
354
355        /// Control for the true branch.
356        fbranch: Box<Control>,
357
358        /// Attributes
359        attributes: Attributes,
360    },
361    /// Standard imperative while statement
362    While {
363        /// Port that connects the conditional check.
364        port: Port,
365
366        /// Modules that need to be enabled to send signal on `port`.
367        cond: Option<Id>,
368
369        /// Control for the loop body.
370        body: Box<Control>,
371
372        /// Attributes
373        attributes: Attributes,
374    },
375    /// Static Repeat (essentially a bounded while loop w/o a condition)
376    Repeat {
377        /// Control for the true branch.
378        num_repeats: u64,
379
380        /// Control for the true branch.
381        body: Box<Control>,
382
383        /// Attributes
384        attributes: Attributes,
385    },
386    /// Runs the control for a list of subcomponents.
387    Enable {
388        /// Group to be enabled
389        comp: Id,
390        /// Attributes
391        attributes: Attributes,
392    },
393    /// Invoke component with input/output assignments.
394    Invoke {
395        /// Name of the component to be invoked.
396        comp: Id,
397        /// Input assignments
398        inputs: Vec<(Id, Atom)>,
399        /// Output assignments
400        outputs: Vec<(Id, Atom)>,
401        /// Attributes
402        attributes: Attributes,
403        /// Combinational group that may execute with this invoke.
404        comb_group: Option<Id>,
405        /// External cells that may execute with this invoke.
406        ref_cells: Vec<(Id, Id)>,
407    },
408    /// Invoke component with input/output assignments.
409    StaticInvoke {
410        /// Name of the component to be invoked.
411        comp: Id,
412        /// Input assignments
413        inputs: Vec<(Id, Atom)>,
414        /// Output assignments
415        outputs: Vec<(Id, Atom)>,
416        /// Attributes
417        attributes: Attributes,
418        /// External cells that may execute with this invoke.
419        ref_cells: Vec<(Id, Id)>,
420        /// Combinational group that may execute with this invoke.
421        comb_group: Option<Id>,
422        /// (optional) latency. Latency can be inferred if not given.
423        latency: Option<NonZeroU64>,
424    },
425    /// Control statement that does nothing.
426    Empty {
427        /// Attributes
428        attributes: Attributes,
429    },
430    /// Represents sequential composition of static control statements.
431    StaticSeq {
432        /// List of `Control` statements to run in sequence.
433        /// If not all of these stmts are static, we should error out
434        stmts: Vec<Control>,
435        /// Attributes
436        attributes: Attributes,
437        /// Optional latency for the seq
438        latency: Option<NonZeroU64>,
439    },
440    /// Represents parallel composition of static control statements.
441    StaticPar {
442        /// List of `Control` statements to run in sequence.
443        /// If not all of these stmts are static, we should error out
444        stmts: Vec<Control>,
445        /// Attributes
446        attributes: Attributes,
447        /// Optional latency for the par
448        latency: Option<NonZeroU64>,
449    },
450    /// Static if statement.
451    StaticIf {
452        /// Port that connects the conditional check.
453        port: Port,
454
455        /// Control for the true branch.
456        tbranch: Box<Control>,
457
458        /// Control for the true branch.
459        fbranch: Box<Control>,
460
461        /// Attributes
462        attributes: Attributes,
463
464        /// Optional latency; should be the longer of the two branches
465        latency: Option<NonZeroU64>,
466    },
467    /// Static Repeat (essentially a bounded while loop w/o a condition)
468    StaticRepeat {
469        /// Control for the true branch.
470        num_repeats: u64,
471
472        /// Control for the true branch.
473        body: Box<Control>,
474
475        /// Attributes
476        attributes: Attributes,
477    },
478}
479
480impl Control {
481    pub fn empty() -> Control {
482        Control::Empty {
483            attributes: Attributes::default(),
484        }
485    }
486
487    pub fn get_attributes(&self) -> &Attributes {
488        match self {
489            Control::Seq { attributes, .. } => attributes,
490            Control::Par { attributes, .. } => attributes,
491            Control::If { attributes, .. } => attributes,
492            Control::While { attributes, .. } => attributes,
493            Control::Repeat { attributes, .. } => attributes,
494            Control::Enable { attributes, .. } => attributes,
495            Control::Invoke { attributes, .. } => attributes,
496            Control::Empty { attributes, .. } => attributes,
497            Control::StaticSeq { attributes, .. } => attributes,
498            Control::StaticPar { attributes, .. } => attributes,
499            Control::StaticIf { attributes, .. } => attributes,
500            Control::StaticRepeat { attributes, .. } => attributes,
501            Control::StaticInvoke { attributes, .. } => attributes,
502        }
503    }
504}