spade_ast/
lib.rs

1use itertools::Itertools;
2use num::{BigInt, BigUint, Signed, Zero};
3use spade_common::{
4    location_info::{Loc, WithLocation},
5    name::{Identifier, Path},
6    num_ext::InfallibleToBigInt,
7};
8use std::fmt::Display;
9pub mod testutil;
10
11#[derive(PartialEq, Debug, Clone)]
12pub enum TypeExpression {
13    TypeSpec(Box<Loc<TypeSpec>>),
14    Integer(BigInt),
15    ConstGeneric(Box<Loc<Expression>>),
16}
17impl WithLocation for TypeExpression {}
18
19impl std::fmt::Display for TypeExpression {
20    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21        match self {
22            TypeExpression::TypeSpec(inner) => write!(f, "{inner}"),
23            TypeExpression::Integer(inner) => write!(f, "{inner}"),
24            TypeExpression::ConstGeneric(_) => write!(f, "{{...}}"),
25        }
26    }
27}
28
29#[derive(PartialEq, Debug, Clone)]
30pub enum NamedTurbofish {
31    Short(Loc<Identifier>),
32    Full(Loc<Identifier>, Loc<TypeExpression>),
33}
34impl WithLocation for NamedTurbofish {}
35
36#[derive(PartialEq, Debug, Clone)]
37pub enum TurbofishInner {
38    Named(Vec<Loc<NamedTurbofish>>),
39    Positional(Vec<Loc<TypeExpression>>),
40}
41impl WithLocation for TurbofishInner {}
42
43/// A specification of a type to be used. For example, the types of input/output arguments the type
44/// of fields in a struct etc.
45#[derive(PartialEq, Debug, Clone)]
46pub enum TypeSpec {
47    Tuple(Vec<Loc<TypeExpression>>),
48    Array {
49        inner: Box<Loc<TypeExpression>>,
50        size: Box<Loc<TypeExpression>>,
51    },
52    Named(Loc<Path>, Option<Loc<Vec<Loc<TypeExpression>>>>),
53    /// An inverted signal (`~`), its "direction" is the inverse of normal. A `~&T` taken as an
54    /// argument is an output, and a returned `~&T` is an input. This used to be expressed as `&mut
55    /// T` Inversions cancel each other, i.e. `~~&T` is effectively `&T` Inverted signals are
56    /// ports.
57    /// If applied to a struct port, all fields are inverted.
58    Inverted(Box<Loc<TypeExpression>>),
59    Wire(Box<Loc<TypeExpression>>),
60    Wildcard,
61}
62impl WithLocation for TypeSpec {}
63
64impl std::fmt::Display for TypeSpec {
65    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66        match self {
67            TypeSpec::Tuple(inner) => {
68                write!(f, "({})", inner.iter().map(|i| format!("{i}")).join(", "))
69            }
70            TypeSpec::Array { inner, size } => write!(f, "[{inner}; {size}]"),
71            TypeSpec::Named(name, args) => {
72                let args = match args {
73                    Some(a) => a.iter().map(|a| format!("{a}")).join(", "),
74                    None => String::new(),
75                };
76                write!(f, "{name}{args}")
77            }
78            TypeSpec::Inverted(inner) => write!(f, "inv {inner}"),
79            TypeSpec::Wire(inner) => write!(f, "&{inner}"),
80            TypeSpec::Wildcard => write!(f, "_"),
81        }
82    }
83}
84
85#[derive(PartialEq, Debug, Clone)]
86pub enum ArgumentPattern {
87    Named(Vec<(Loc<Identifier>, Option<Loc<Pattern>>)>),
88    Positional(Vec<Loc<Pattern>>),
89}
90impl WithLocation for ArgumentPattern {}
91
92#[derive(PartialEq, Debug, Clone)]
93pub enum Pattern {
94    Integer(IntLiteral),
95    Bool(bool),
96    Path(Loc<Path>),
97    Tuple(Vec<Loc<Pattern>>),
98    Array(Vec<Loc<Pattern>>),
99    Type(Loc<Path>, Loc<ArgumentPattern>),
100}
101impl WithLocation for Pattern {}
102
103// Helper constructors for writing neater tests
104impl Pattern {
105    pub fn integer(val: i32) -> Self {
106        Pattern::Integer(IntLiteral::Unsized(val.to_bigint()))
107    }
108    pub fn name(name: &str) -> Loc<Self> {
109        Pattern::Path(Path(vec![Identifier(name.to_string()).nowhere()]).nowhere()).nowhere()
110    }
111}
112
113#[derive(PartialEq, Debug, Clone)]
114pub enum NamedArgument {
115    Full(Loc<Identifier>, Loc<Expression>),
116    /// Binds a local variable to an argument with the same name
117    Short(Loc<Identifier>),
118}
119impl WithLocation for NamedArgument {}
120
121#[derive(PartialEq, Debug, Clone)]
122pub enum ArgumentList {
123    Positional(Vec<Loc<Expression>>),
124    Named(Vec<NamedArgument>),
125}
126impl WithLocation for ArgumentList {}
127
128#[derive(PartialEq, Debug, Clone)]
129pub enum WhereClause {
130    GenericInt {
131        target: Loc<Path>,
132        expression: Loc<Expression>,
133    },
134    TraitBounds {
135        target: Loc<Path>,
136        traits: Vec<Loc<TraitSpec>>,
137    },
138}
139impl WhereClause {
140    pub fn target(&self) -> &Loc<Path> {
141        match self {
142            WhereClause::GenericInt {
143                target,
144                expression: _,
145            } => target,
146            WhereClause::TraitBounds { target, traits: _ } => target,
147        }
148    }
149}
150impl WithLocation for WhereClause {}
151
152#[derive(PartialEq, Debug, Clone)]
153pub enum BinaryOperator {
154    Add,
155    Sub,
156    Mul,
157    Div,
158    Mod,
159    Equals,
160    NotEquals,
161    Lt,
162    Gt,
163    Le,
164    Ge,
165    LogicalAnd,
166    LogicalOr,
167    LogicalXor,
168    LeftShift,
169    RightShift,
170    ArithmeticRightShift,
171    BitwiseAnd,
172    BitwiseOr,
173    BitwiseXor,
174}
175impl WithLocation for BinaryOperator {}
176
177impl std::fmt::Display for BinaryOperator {
178    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
179        match self {
180            BinaryOperator::Add => write!(f, "+"),
181            BinaryOperator::Sub => write!(f, "-"),
182            BinaryOperator::Mul => write!(f, "*"),
183            BinaryOperator::Div => write!(f, "/"),
184            BinaryOperator::Mod => write!(f, "%"),
185            BinaryOperator::Equals => write!(f, "=="),
186            BinaryOperator::NotEquals => write!(f, "!="),
187            BinaryOperator::Lt => write!(f, "<"),
188            BinaryOperator::Gt => write!(f, ">"),
189            BinaryOperator::Le => write!(f, "<="),
190            BinaryOperator::Ge => write!(f, ">="),
191            BinaryOperator::LogicalAnd => write!(f, "&"),
192            BinaryOperator::LogicalOr => write!(f, "|"),
193            BinaryOperator::LogicalXor => write!(f, "^"),
194            BinaryOperator::LeftShift => write!(f, "<<"),
195            BinaryOperator::RightShift => write!(f, ">>"),
196            BinaryOperator::ArithmeticRightShift => write!(f, ">>>"),
197            BinaryOperator::BitwiseAnd => write!(f, "&&"),
198            BinaryOperator::BitwiseOr => write!(f, "||"),
199            BinaryOperator::BitwiseXor => write!(f, "^^"),
200        }
201    }
202}
203
204#[derive(PartialEq, Debug, Clone)]
205pub enum UnaryOperator {
206    Sub,
207    Not,
208    BitwiseNot,
209    Dereference,
210    Reference,
211}
212impl WithLocation for UnaryOperator {}
213
214impl std::fmt::Display for UnaryOperator {
215    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
216        match self {
217            UnaryOperator::Sub => write!(f, "-"),
218            UnaryOperator::Not => write!(f, "!"),
219            UnaryOperator::BitwiseNot => write!(f, "~"),
220            UnaryOperator::Dereference => write!(f, "*"),
221            UnaryOperator::Reference => write!(f, "&"),
222        }
223    }
224}
225
226#[derive(PartialEq, Debug, Clone)]
227pub enum PipelineStageReference {
228    Relative(Loc<TypeExpression>),
229    Absolute(Loc<Identifier>),
230}
231
232#[derive(PartialEq, Debug, Clone)]
233pub enum CallKind {
234    Function,
235    Entity(Loc<()>),
236    Pipeline(Loc<()>, Loc<TypeExpression>),
237}
238impl WithLocation for CallKind {}
239
240#[derive(PartialEq, Debug, Clone)]
241pub enum BitLiteral {
242    Low,
243    High,
244    HighImp,
245}
246impl WithLocation for BitLiteral {}
247
248#[derive(PartialEq, Debug, Clone)]
249pub enum Expression {
250    Identifier(Loc<Path>),
251    IntLiteral(IntLiteral),
252    BoolLiteral(bool),
253    BitLiteral(BitLiteral),
254    /// `[1, 2, 3]`
255    ArrayLiteral(Vec<Loc<Expression>>),
256    /// `[<expr>; <amount>]`
257    /// amount is a const generic
258    ArrayShorthandLiteral(Box<Loc<Expression>>, Box<Loc<Expression>>),
259    Index(Box<Loc<Expression>>, Box<Loc<Expression>>),
260    RangeIndex {
261        target: Box<Loc<Expression>>,
262        // NOTE: These are const generics
263        start: Box<Loc<Expression>>,
264        end: Box<Loc<Expression>>,
265    },
266    TupleLiteral(Vec<Loc<Expression>>),
267    TupleIndex(Box<Loc<Expression>>, Loc<u128>),
268    FieldAccess(Box<Loc<Expression>>, Loc<Identifier>),
269    CreatePorts,
270    Call {
271        kind: CallKind,
272        callee: Loc<Path>,
273        args: Loc<ArgumentList>,
274        turbofish: Option<Loc<TurbofishInner>>,
275    },
276    MethodCall {
277        target: Box<Loc<Expression>>,
278        name: Loc<Identifier>,
279        args: Loc<ArgumentList>,
280        kind: CallKind,
281        turbofish: Option<Loc<TurbofishInner>>,
282    },
283    If(
284        Box<Loc<Expression>>,
285        Box<Loc<Expression>>,
286        Box<Loc<Expression>>,
287    ),
288    TypeLevelIf(
289        Box<Loc<Expression>>,
290        Box<Loc<Expression>>,
291        Box<Loc<Expression>>,
292    ),
293    Match(
294        Box<Loc<Expression>>,
295        Loc<Vec<(Loc<Pattern>, Loc<Expression>)>>,
296    ),
297    UnaryOperator(Loc<UnaryOperator>, Box<Loc<Expression>>),
298    BinaryOperator(
299        Box<Loc<Expression>>,
300        Loc<BinaryOperator>,
301        Box<Loc<Expression>>,
302    ),
303    Block(Box<Block>),
304    /// E.g. `stage(-5).x`, `stage('b).y`
305    PipelineReference {
306        /// ```text
307        /// stage(-5).xyz
308        /// ^^^^^^^^^
309        /// ```
310        stage_kw_and_reference_loc: Loc<()>,
311        /// ```text
312        /// stage(-5).xyz
313        ///       ^^
314        /// ```
315        stage: PipelineStageReference,
316        /// ```text
317        /// stage(-5).xyz
318        ///           ^^^
319        /// ```
320        name: Loc<Identifier>,
321    },
322    StageValid,
323    StageReady,
324}
325impl WithLocation for Expression {}
326
327impl Expression {
328    pub fn int_literal_signed(val: i32) -> Self {
329        Self::IntLiteral(IntLiteral::unsized_(val))
330    }
331
332    pub fn as_int_literal(self) -> Option<IntLiteral> {
333        match self {
334            Expression::IntLiteral(lit) => Some(lit),
335            _ => None,
336        }
337    }
338
339    pub fn assume_block(&self) -> &Block {
340        if let Expression::Block(inner) = self {
341            inner
342        } else {
343            panic!("Expected block")
344        }
345    }
346
347    pub fn variant_str(&self) -> &'static str {
348        match self {
349            Expression::Identifier(_) => "identifier",
350            Expression::IntLiteral(_) => "int literal",
351            Expression::BoolLiteral(_) => "bool literal",
352            Expression::BitLiteral(_) => "bit literal",
353            Expression::ArrayLiteral(_) => "array literal",
354            Expression::ArrayShorthandLiteral(_, _) => "array shorthand literal",
355            Expression::CreatePorts => "port",
356            Expression::Index(_, _) => "index",
357            Expression::RangeIndex { .. } => "range index",
358            Expression::TupleLiteral(_) => "tuple literal",
359            Expression::TupleIndex(_, _) => "tuple index",
360            Expression::FieldAccess(_, _) => "field access",
361            Expression::If(_, _, _) => "if",
362            Expression::TypeLevelIf(_, _, _) => "type level if",
363            Expression::Match(_, _) => "match",
364            Expression::Call { .. } => "call",
365            Expression::MethodCall { .. } => "method call",
366            Expression::UnaryOperator(_, _) => "unary operator",
367            Expression::BinaryOperator(_, _, _) => "binary operator",
368            Expression::Block(_) => "block",
369            Expression::PipelineReference { .. } => "pipeline reference",
370            Expression::StageValid => "stage.valid",
371            Expression::StageReady => "stage.ready",
372        }
373    }
374}
375
376/// An integer literal, which may or may not have been suffixed with `U` to indicate
377/// it being an unsigned literal.
378#[derive(PartialEq, Debug, Clone)]
379pub enum IntLiteral {
380    Unsized(BigInt),
381    Signed { val: BigInt, size: BigUint },
382    Unsigned { val: BigUint, size: BigUint },
383}
384impl WithLocation for IntLiteral {}
385
386impl IntLiteral {
387    pub fn unsized_(val: i32) -> IntLiteral {
388        IntLiteral::Unsized(val.to_bigint())
389    }
390
391    /// Returns this number as a signed number. Unsigned numbers are losslessly converted to
392    /// signed
393    pub fn as_signed(self) -> BigInt {
394        match self {
395            IntLiteral::Signed { val, size: _ } => val,
396            IntLiteral::Unsigned { val, size: _ } => val.to_bigint(),
397            IntLiteral::Unsized(val) => val,
398        }
399    }
400
401    // Returns the signed, or unsigned number as a BigUint if it is positive, otherwise,
402    // None
403    pub fn as_unsigned(self) -> Option<BigUint> {
404        match self {
405            IntLiteral::Signed { val, size: _ } | IntLiteral::Unsized(val) => {
406                if val >= BigInt::zero() {
407                    Some(val.to_biguint().unwrap())
408                } else {
409                    None
410                }
411            }
412            IntLiteral::Unsigned { val, size: _ } => Some(val),
413        }
414    }
415
416    pub fn is_negative(&self) -> bool {
417        match self {
418            IntLiteral::Unsized(val) | IntLiteral::Signed { val, size: _ } => val.is_negative(),
419            IntLiteral::Unsigned { .. } => false,
420        }
421    }
422}
423
424impl Display for IntLiteral {
425    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
426        match self {
427            // this is not dry
428            IntLiteral::Unsized(val) | IntLiteral::Signed { val, .. } => write!(f, "{}", val),
429            IntLiteral::Unsigned { val, .. } => write!(f, "{}", val),
430        }
431    }
432}
433
434#[derive(PartialEq, Debug, Clone)]
435pub struct Block {
436    pub statements: Vec<Loc<Statement>>,
437    pub result: Option<Loc<Expression>>,
438}
439impl WithLocation for Block {}
440
441#[derive(PartialEq, Debug, Clone)]
442pub struct Binding {
443    pub pattern: Loc<Pattern>,
444    pub ty: Option<Loc<TypeSpec>>,
445    pub value: Loc<Expression>,
446    pub attrs: AttributeList,
447}
448
449#[derive(PartialEq, Debug, Clone)]
450pub enum Statement {
451    Label(Loc<Identifier>),
452    Declaration(Vec<Loc<Identifier>>),
453    Binding(Binding),
454    Expression(Loc<Expression>),
455    PipelineRegMarker(Option<Loc<TypeExpression>>, Option<Loc<Expression>>),
456    Register(Loc<Register>),
457    /// Sets the value of the target expression, which must be a Backward port to
458    /// the value of `value`
459    Set {
460        target: Loc<Expression>,
461        value: Loc<Expression>,
462    },
463    Assert(Loc<Expression>),
464}
465impl WithLocation for Statement {}
466
467impl Statement {
468    // Creates a binding from name, type and values without any attributes.
469    pub fn binding(
470        pattern: Loc<Pattern>,
471        ty: Option<Loc<TypeSpec>>,
472        value: Loc<Expression>,
473    ) -> Self {
474        Self::Binding(Binding {
475            pattern,
476            ty,
477            value,
478            attrs: AttributeList::empty(),
479        })
480    }
481}
482
483/// A generic type parameter
484#[derive(PartialEq, Debug, Clone)]
485pub enum TypeParam {
486    TypeName {
487        name: Loc<Identifier>,
488        traits: Vec<Loc<TraitSpec>>,
489    },
490    TypeWithMeta {
491        meta: Loc<Identifier>,
492        name: Loc<Identifier>,
493    },
494}
495impl WithLocation for TypeParam {}
496impl TypeParam {
497    pub fn name(&self) -> &Loc<Identifier> {
498        match self {
499            TypeParam::TypeName { name, traits: _ } => name,
500            TypeParam::TypeWithMeta { meta: _, name } => name,
501        }
502    }
503}
504
505#[derive(PartialEq, Debug, Clone)]
506pub enum GenericBound {
507    IntegerConstraint(Loc<Path>, Loc<Expression>),
508    TypeConstraint(Loc<Path>, Vec<Loc<Identifier>>),
509}
510
511impl WithLocation for GenericBound {}
512
513impl GenericBound {
514    pub fn path(&self) -> &Loc<Path> {
515        match self {
516            GenericBound::IntegerConstraint(path, _) => path,
517            GenericBound::TypeConstraint(path, _) => path,
518        }
519    }
520}
521
522#[derive(PartialEq, Debug, Clone)]
523pub enum Attribute {
524    Optimize {
525        passes: Vec<Loc<String>>,
526    },
527    NoMangle {
528        all: bool,
529    },
530    Fsm {
531        state: Option<Loc<Identifier>>,
532    },
533    WalTraceable {
534        suffix: Option<Loc<Identifier>>,
535        uses_clk: bool,
536        uses_rst: bool,
537    },
538    WalTrace {
539        clk: Option<Loc<Expression>>,
540        rst: Option<Loc<Expression>>,
541    },
542    /// Create a copy of the marked signal with the specified suffix applied
543    WalSuffix {
544        suffix: Loc<Identifier>,
545    },
546    Documentation {
547        content: String,
548    },
549}
550
551impl Attribute {
552    pub fn name(&self) -> &str {
553        match self {
554            Attribute::Optimize { passes: _ } => "optimize",
555            Attribute::NoMangle { .. } => "no_mangle",
556            Attribute::Fsm { state: _ } => "fsm",
557            Attribute::WalTraceable { .. } => "wal_traceable",
558            Attribute::WalTrace { .. } => "wal_trace",
559            Attribute::WalSuffix { .. } => "wal_suffix",
560            Attribute::Documentation { .. } => "doc",
561        }
562    }
563}
564
565impl WithLocation for Attribute {}
566
567#[derive(PartialEq, Debug, Clone)]
568pub struct AttributeList(pub Vec<Loc<Attribute>>);
569impl AttributeList {
570    pub fn empty() -> Self {
571        Self(vec![])
572    }
573
574    pub fn from_vec(attrs: Vec<Loc<Attribute>>) -> Self {
575        Self(attrs)
576    }
577}
578
579#[derive(PartialEq, Debug, Clone)]
580pub struct ParameterList {
581    pub self_: Option<Loc<()>>,
582    pub args: Vec<(AttributeList, Loc<Identifier>, Loc<TypeSpec>)>,
583}
584impl WithLocation for ParameterList {}
585
586impl ParameterList {
587    pub fn without_self(args: Vec<(Loc<Identifier>, Loc<TypeSpec>)>) -> Self {
588        Self {
589            self_: None,
590            args: args
591                .into_iter()
592                .map(|(n, t)| (AttributeList::empty(), n, t))
593                .collect(),
594        }
595    }
596
597    pub fn with_self(self_: Loc<()>, args: Vec<(Loc<Identifier>, Loc<TypeSpec>)>) -> Self {
598        Self {
599            self_: Some(self_),
600            args: args
601                .into_iter()
602                .map(|(n, t)| (AttributeList::empty(), n, t))
603                .collect(),
604        }
605    }
606}
607
608#[derive(PartialEq, Debug, Clone)]
609pub enum UnitKind {
610    Function,
611    Entity,
612    Pipeline(Loc<TypeExpression>),
613}
614impl WithLocation for UnitKind {}
615
616impl UnitKind {
617    pub fn is_pipeline(&self) -> bool {
618        match self {
619            UnitKind::Function => false,
620            UnitKind::Entity => false,
621            UnitKind::Pipeline(_) => true,
622        }
623    }
624}
625
626impl std::fmt::Display for UnitKind {
627    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
628        match self {
629            UnitKind::Function => write!(f, "fn"),
630            UnitKind::Entity => write!(f, "entity"),
631            UnitKind::Pipeline(_) => write!(f, "pipeline"),
632        }
633    }
634}
635
636#[derive(PartialEq, Debug, Clone)]
637pub struct UnitHead {
638    pub extern_token: Option<Loc<()>>,
639    pub attributes: AttributeList,
640    pub unit_kind: Loc<UnitKind>,
641    pub name: Loc<Identifier>,
642    pub inputs: Loc<ParameterList>,
643    pub output_type: Option<(Loc<()>, Loc<TypeSpec>)>,
644    pub type_params: Option<Loc<Vec<Loc<TypeParam>>>>,
645    pub where_clauses: Vec<WhereClause>,
646}
647impl WithLocation for UnitHead {}
648
649#[derive(PartialEq, Debug, Clone)]
650pub struct Unit {
651    pub head: UnitHead,
652    /// The body is an expression for ID assignment purposes, but semantic analysis
653    /// ensures that it is always a block. If body is `None`, the entity is `extern`.
654    pub body: Option<Loc<Expression>>,
655}
656impl WithLocation for Unit {}
657
658#[derive(PartialEq, Debug, Clone)]
659pub struct Register {
660    pub pattern: Loc<Pattern>,
661    pub clock: Loc<Expression>,
662    pub reset: Option<(Loc<Expression>, Loc<Expression>)>,
663    pub initial: Option<Loc<Expression>>,
664    pub value: Loc<Expression>,
665    pub value_type: Option<Loc<TypeSpec>>,
666    pub attributes: AttributeList,
667}
668impl WithLocation for Register {}
669
670/// A definition of a trait
671#[derive(PartialEq, Debug, Clone)]
672pub struct TraitDef {
673    pub name: Loc<Identifier>,
674    pub type_params: Option<Loc<Vec<Loc<TypeParam>>>>,
675    pub where_clauses: Vec<WhereClause>,
676    pub methods: Vec<Loc<UnitHead>>,
677}
678impl WithLocation for TraitDef {}
679
680/// A specification of a trait with type parameters
681#[derive(PartialEq, Debug, Clone)]
682pub struct TraitSpec {
683    pub path: Loc<Path>,
684    pub type_params: Option<Loc<Vec<Loc<TypeExpression>>>>,
685}
686impl WithLocation for TraitSpec {}
687
688#[derive(PartialEq, Debug, Clone)]
689pub struct ImplBlock {
690    pub r#trait: Option<Loc<TraitSpec>>,
691    pub type_params: Option<Loc<Vec<Loc<TypeParam>>>>,
692    pub where_clauses: Vec<WhereClause>,
693    pub target: Loc<TypeSpec>,
694    pub units: Vec<Loc<Unit>>,
695}
696impl WithLocation for ImplBlock {}
697
698/// Declaration of an enum
699#[derive(PartialEq, Debug, Clone)]
700pub struct Enum {
701    pub attributes: AttributeList,
702    pub name: Loc<Identifier>,
703    pub variants: Vec<EnumVariant>,
704}
705impl WithLocation for Enum {}
706
707#[derive(PartialEq, Debug, Clone)]
708pub struct EnumVariant {
709    pub attributes: AttributeList,
710    pub name: Loc<Identifier>,
711    pub args: Option<Loc<ParameterList>>,
712}
713
714#[derive(PartialEq, Debug, Clone)]
715pub struct Struct {
716    pub attributes: AttributeList,
717    pub name: Loc<Identifier>,
718    pub members: Loc<ParameterList>,
719    pub port_keyword: Option<Loc<()>>,
720}
721impl WithLocation for Struct {}
722
723impl Struct {
724    pub fn is_port(&self) -> bool {
725        self.port_keyword.is_some()
726    }
727}
728
729#[derive(PartialEq, Debug, Clone)]
730pub enum TypeDeclKind {
731    Enum(Loc<Enum>),
732    Struct(Loc<Struct>),
733}
734
735/// A declaration of a new type
736#[derive(PartialEq, Debug, Clone)]
737pub struct TypeDeclaration {
738    pub name: Loc<Identifier>,
739    pub kind: TypeDeclKind,
740    pub generic_args: Option<Loc<Vec<Loc<TypeParam>>>>,
741}
742impl WithLocation for TypeDeclaration {}
743
744#[derive(PartialEq, Debug, Clone)]
745pub struct UseStatement {
746    pub path: Loc<Path>,
747    pub alias: Option<Loc<Identifier>>,
748}
749impl WithLocation for UseStatement {}
750
751/// Items are things typically present at the top level of a module such as
752/// entities, pipelines, submodules etc.
753#[derive(PartialEq, Debug, Clone)]
754pub enum Item {
755    Unit(Loc<Unit>),
756    TraitDef(Loc<TraitDef>),
757    Type(Loc<TypeDeclaration>),
758    ExternalMod(Loc<Identifier>),
759    Module(Loc<Module>),
760    Use(Loc<UseStatement>),
761    ImplBlock(Loc<ImplBlock>),
762}
763impl WithLocation for Item {}
764
765impl Item {
766    pub fn name(&self) -> Option<&Identifier> {
767        match self {
768            Item::Unit(u) => Some(&u.head.name.inner),
769            Item::TraitDef(t) => Some(&t.name.inner),
770            Item::Type(t) => Some(&t.name.inner),
771            Item::Module(m) => Some(&m.name.inner),
772            Item::ExternalMod(name) => Some(name),
773            Item::Use(u) => u.alias.as_ref().map(|name| &name.inner),
774            Item::ImplBlock(_) => None,
775        }
776    }
777
778    pub fn variant_str(&self) -> &'static str {
779        match self {
780            Item::Unit(_) => "unit",
781            Item::TraitDef(_) => "trait definition",
782            Item::Type(_) => "type",
783            Item::Module(_) => "module",
784            Item::ExternalMod(_) => "module",
785            Item::Use(_) => "use",
786            Item::ImplBlock(_) => "impl",
787        }
788    }
789}
790
791#[derive(PartialEq, Debug, Clone)]
792pub struct Module {
793    pub name: Loc<Identifier>,
794    pub body: Loc<ModuleBody>,
795}
796impl WithLocation for Module {}
797
798#[derive(PartialEq, Debug, Clone)]
799pub struct ModuleBody {
800    pub members: Vec<Item>,
801    pub documentation: Vec<String>,
802}
803impl WithLocation for ModuleBody {}