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