calyx_frontend/
ast.rs

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