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    Lambda {
271        unit_kind: Loc<UnitKind>,
272        args: Loc<Vec<Loc<Pattern>>>,
273        body: Box<Loc<Block>>,
274    },
275    Call {
276        kind: CallKind,
277        callee: Loc<Path>,
278        args: Loc<ArgumentList>,
279        turbofish: Option<Loc<TurbofishInner>>,
280    },
281    MethodCall {
282        target: Box<Loc<Expression>>,
283        name: Loc<Identifier>,
284        args: Loc<ArgumentList>,
285        kind: CallKind,
286        turbofish: Option<Loc<TurbofishInner>>,
287    },
288    If(
289        Box<Loc<Expression>>,
290        Box<Loc<Expression>>,
291        Box<Loc<Expression>>,
292    ),
293    TypeLevelIf(
294        Box<Loc<Expression>>,
295        Box<Loc<Expression>>,
296        Box<Loc<Expression>>,
297    ),
298    Match(
299        Box<Loc<Expression>>,
300        Loc<Vec<(Loc<Pattern>, Loc<Expression>)>>,
301    ),
302    UnaryOperator(Loc<UnaryOperator>, Box<Loc<Expression>>),
303    BinaryOperator(
304        Box<Loc<Expression>>,
305        Loc<BinaryOperator>,
306        Box<Loc<Expression>>,
307    ),
308    Block(Box<Block>),
309    /// E.g. `stage(-5).x`, `stage('b).y`
310    PipelineReference {
311        /// ```text
312        /// stage(-5).xyz
313        /// ^^^^^^^^^
314        /// ```
315        stage_kw_and_reference_loc: Loc<()>,
316        /// ```text
317        /// stage(-5).xyz
318        ///       ^^
319        /// ```
320        stage: PipelineStageReference,
321        /// ```text
322        /// stage(-5).xyz
323        ///           ^^^
324        /// ```
325        name: Loc<Identifier>,
326    },
327    StageValid,
328    StageReady,
329    StaticUnreachable(Loc<String>),
330}
331impl WithLocation for Expression {}
332
333impl Expression {
334    pub fn int_literal_signed(val: i32) -> Self {
335        Self::IntLiteral(IntLiteral::unsized_(val))
336    }
337
338    pub fn as_int_literal(self) -> Option<IntLiteral> {
339        match self {
340            Expression::IntLiteral(lit) => Some(lit),
341            _ => None,
342        }
343    }
344
345    pub fn assume_block(&self) -> &Block {
346        if let Expression::Block(inner) = self {
347            inner
348        } else {
349            panic!("Expected block")
350        }
351    }
352
353    pub fn variant_str(&self) -> &'static str {
354        match self {
355            Expression::Identifier(_) => "identifier",
356            Expression::IntLiteral(_) => "int literal",
357            Expression::BoolLiteral(_) => "bool literal",
358            Expression::BitLiteral(_) => "bit literal",
359            Expression::ArrayLiteral(_) => "array literal",
360            Expression::ArrayShorthandLiteral(_, _) => "array shorthand literal",
361            Expression::CreatePorts => "port",
362            Expression::Index(_, _) => "index",
363            Expression::RangeIndex { .. } => "range index",
364            Expression::TupleLiteral(_) => "tuple literal",
365            Expression::TupleIndex(_, _) => "tuple index",
366            Expression::FieldAccess(_, _) => "field access",
367            Expression::If(_, _, _) => "if",
368            Expression::TypeLevelIf(_, _, _) => "type level if",
369            Expression::Match(_, _) => "match",
370            Expression::Lambda { .. } => "lambda",
371            Expression::Call { .. } => "call",
372            Expression::MethodCall { .. } => "method call",
373            Expression::UnaryOperator(_, _) => "unary operator",
374            Expression::BinaryOperator(_, _, _) => "binary operator",
375            Expression::Block(_) => "block",
376            Expression::PipelineReference { .. } => "pipeline reference",
377            Expression::StageValid => "stage.valid",
378            Expression::StageReady => "stage.ready",
379            Expression::StaticUnreachable(_) => "static_unreachable",
380        }
381    }
382}
383
384/// An integer literal, which may or may not have been suffixed with `U` to indicate
385/// it being an unsigned literal.
386#[derive(PartialEq, Debug, Clone)]
387pub enum IntLiteral {
388    Unsized(BigInt),
389    Signed { val: BigInt, size: BigUint },
390    Unsigned { val: BigUint, size: BigUint },
391}
392impl WithLocation for IntLiteral {}
393
394impl IntLiteral {
395    pub fn unsized_(val: i32) -> IntLiteral {
396        IntLiteral::Unsized(val.to_bigint())
397    }
398
399    /// Returns this number as a signed number. Unsigned numbers are losslessly converted to
400    /// signed
401    pub fn as_signed(self) -> BigInt {
402        match self {
403            IntLiteral::Signed { val, size: _ } => val,
404            IntLiteral::Unsigned { val, size: _ } => val.to_bigint(),
405            IntLiteral::Unsized(val) => val,
406        }
407    }
408
409    // Returns the signed, or unsigned number as a BigUint if it is positive, otherwise,
410    // None
411    pub fn as_unsigned(self) -> Option<BigUint> {
412        match self {
413            IntLiteral::Signed { val, size: _ } | IntLiteral::Unsized(val) => {
414                if val >= BigInt::zero() {
415                    Some(val.to_biguint().unwrap())
416                } else {
417                    None
418                }
419            }
420            IntLiteral::Unsigned { val, size: _ } => Some(val),
421        }
422    }
423
424    pub fn is_negative(&self) -> bool {
425        match self {
426            IntLiteral::Unsized(val) | IntLiteral::Signed { val, size: _ } => val.is_negative(),
427            IntLiteral::Unsigned { .. } => false,
428        }
429    }
430}
431
432impl Display for IntLiteral {
433    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
434        match self {
435            // this is not dry
436            IntLiteral::Unsized(val) | IntLiteral::Signed { val, .. } => write!(f, "{}", val),
437            IntLiteral::Unsigned { val, .. } => write!(f, "{}", val),
438        }
439    }
440}
441
442#[derive(PartialEq, Debug, Clone)]
443pub struct Block {
444    pub statements: Vec<Loc<Statement>>,
445    pub result: Option<Loc<Expression>>,
446}
447impl WithLocation for Block {}
448
449#[derive(PartialEq, Debug, Clone)]
450pub struct Binding {
451    pub pattern: Loc<Pattern>,
452    pub ty: Option<Loc<TypeSpec>>,
453    pub value: Loc<Expression>,
454    pub attrs: AttributeList,
455}
456
457#[derive(PartialEq, Debug, Clone)]
458pub enum Statement {
459    Label(Loc<Identifier>),
460    Declaration(Vec<Loc<Identifier>>),
461    Binding(Binding),
462    Expression(Loc<Expression>),
463    PipelineRegMarker(Option<Loc<TypeExpression>>, Option<Loc<Expression>>),
464    Register(Loc<Register>),
465    /// Sets the value of the target expression, which must be a Backward port to
466    /// the value of `value`
467    Set {
468        target: Loc<Expression>,
469        value: Loc<Expression>,
470    },
471    Assert(Loc<Expression>),
472}
473impl WithLocation for Statement {}
474
475impl Statement {
476    // Creates a binding from name, type and values without any attributes.
477    pub fn binding(
478        pattern: Loc<Pattern>,
479        ty: Option<Loc<TypeSpec>>,
480        value: Loc<Expression>,
481    ) -> Self {
482        Self::Binding(Binding {
483            pattern,
484            ty,
485            value,
486            attrs: AttributeList::empty(),
487        })
488    }
489}
490
491/// A generic type parameter
492#[derive(PartialEq, Debug, Clone)]
493pub enum TypeParam {
494    TypeName {
495        name: Loc<Identifier>,
496        traits: Vec<Loc<TraitSpec>>,
497    },
498    TypeWithMeta {
499        meta: Loc<Identifier>,
500        name: Loc<Identifier>,
501    },
502}
503impl WithLocation for TypeParam {}
504impl TypeParam {
505    pub fn name(&self) -> &Loc<Identifier> {
506        match self {
507            TypeParam::TypeName { name, traits: _ } => name,
508            TypeParam::TypeWithMeta { meta: _, name } => name,
509        }
510    }
511}
512
513#[derive(PartialEq, Debug, Clone)]
514pub enum GenericBound {
515    IntegerConstraint(Loc<Path>, Loc<Expression>),
516    TypeConstraint(Loc<Path>, Vec<Loc<Identifier>>),
517}
518
519impl WithLocation for GenericBound {}
520
521impl GenericBound {
522    pub fn path(&self) -> &Loc<Path> {
523        match self {
524            GenericBound::IntegerConstraint(path, _) => path,
525            GenericBound::TypeConstraint(path, _) => path,
526        }
527    }
528}
529
530#[derive(PartialEq, Debug, Clone)]
531pub enum Attribute {
532    Optimize {
533        passes: Vec<Loc<String>>,
534    },
535    NoMangle {
536        all: bool,
537    },
538    Fsm {
539        state: Option<Loc<Identifier>>,
540    },
541    WalTraceable {
542        suffix: Option<Loc<Identifier>>,
543        uses_clk: bool,
544        uses_rst: bool,
545    },
546    WalTrace {
547        clk: Option<Loc<Expression>>,
548        rst: Option<Loc<Expression>>,
549    },
550    /// Create a copy of the marked signal with the specified suffix applied
551    WalSuffix {
552        suffix: Loc<Identifier>,
553    },
554    Documentation {
555        content: String,
556    },
557    SurferTranslator(String),
558}
559
560impl Attribute {
561    pub fn name(&self) -> &str {
562        match self {
563            Attribute::Optimize { passes: _ } => "optimize",
564            Attribute::NoMangle { .. } => "no_mangle",
565            Attribute::Fsm { state: _ } => "fsm",
566            Attribute::WalTraceable { .. } => "wal_traceable",
567            Attribute::WalTrace { .. } => "wal_trace",
568            Attribute::WalSuffix { .. } => "wal_suffix",
569            Attribute::Documentation { .. } => "doc",
570            Attribute::SurferTranslator(_) => "surfer_translator",
571        }
572    }
573}
574
575impl WithLocation for Attribute {}
576
577#[derive(PartialEq, Debug, Clone)]
578pub struct AttributeList(pub Vec<Loc<Attribute>>);
579impl AttributeList {
580    pub fn empty() -> Self {
581        Self(vec![])
582    }
583
584    pub fn from_vec(attrs: Vec<Loc<Attribute>>) -> Self {
585        Self(attrs)
586    }
587}
588
589#[derive(PartialEq, Debug, Clone)]
590pub struct ParameterList {
591    pub self_: Option<Loc<()>>,
592    pub args: Vec<(AttributeList, Loc<Identifier>, Loc<TypeSpec>)>,
593}
594impl WithLocation for ParameterList {}
595
596impl ParameterList {
597    pub fn without_self(args: Vec<(AttributeList, Loc<Identifier>, Loc<TypeSpec>)>) -> Self {
598        Self { self_: None, args }
599    }
600
601    pub fn with_self(self_: Loc<()>, args: Vec<(Loc<Identifier>, Loc<TypeSpec>)>) -> Self {
602        Self {
603            self_: Some(self_),
604            args: args
605                .into_iter()
606                .map(|(n, t)| (AttributeList::empty(), n, t))
607                .collect(),
608        }
609    }
610}
611
612#[derive(PartialEq, Debug, Clone)]
613pub enum UnitKind {
614    Function,
615    Entity,
616    Pipeline(Loc<TypeExpression>),
617}
618impl WithLocation for UnitKind {}
619
620impl UnitKind {
621    pub fn is_pipeline(&self) -> bool {
622        match self {
623            UnitKind::Function => false,
624            UnitKind::Entity => false,
625            UnitKind::Pipeline(_) => true,
626        }
627    }
628}
629
630impl std::fmt::Display for UnitKind {
631    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
632        match self {
633            UnitKind::Function => write!(f, "fn"),
634            UnitKind::Entity => write!(f, "entity"),
635            UnitKind::Pipeline(_) => write!(f, "pipeline"),
636        }
637    }
638}
639
640#[derive(PartialEq, Debug, Clone)]
641pub struct UnitHead {
642    pub extern_token: Option<Loc<()>>,
643    pub attributes: AttributeList,
644    pub unit_kind: Loc<UnitKind>,
645    pub name: Loc<Identifier>,
646    pub inputs: Loc<ParameterList>,
647    pub output_type: Option<(Loc<()>, Loc<TypeSpec>)>,
648    pub type_params: Option<Loc<Vec<Loc<TypeParam>>>>,
649    pub where_clauses: Vec<WhereClause>,
650}
651impl WithLocation for UnitHead {}
652
653#[derive(PartialEq, Debug, Clone)]
654pub struct Unit {
655    pub head: UnitHead,
656    /// The body is an expression for ID assignment purposes, but semantic analysis
657    /// ensures that it is always a block. If body is `None`, the entity is `extern`.
658    pub body: Option<Loc<Expression>>,
659}
660impl WithLocation for Unit {}
661
662#[derive(PartialEq, Debug, Clone)]
663pub struct Register {
664    pub pattern: Loc<Pattern>,
665    pub clock: Loc<Expression>,
666    pub reset: Option<(Loc<Expression>, Loc<Expression>)>,
667    pub initial: Option<Loc<Expression>>,
668    pub value: Loc<Expression>,
669    pub value_type: Option<Loc<TypeSpec>>,
670    pub attributes: AttributeList,
671}
672impl WithLocation for Register {}
673
674/// A definition of a trait
675#[derive(PartialEq, Debug, Clone)]
676pub struct TraitDef {
677    pub name: Loc<Identifier>,
678    pub type_params: Option<Loc<Vec<Loc<TypeParam>>>>,
679    pub where_clauses: Vec<WhereClause>,
680    pub methods: Vec<Loc<UnitHead>>,
681}
682impl WithLocation for TraitDef {}
683
684/// A specification of a trait with type parameters
685#[derive(PartialEq, Debug, Clone)]
686pub struct TraitSpec {
687    pub path: Loc<Path>,
688    pub type_params: Option<Loc<Vec<Loc<TypeExpression>>>>,
689}
690impl WithLocation for TraitSpec {}
691
692#[derive(PartialEq, Debug, Clone)]
693pub struct ImplBlock {
694    pub r#trait: Option<Loc<TraitSpec>>,
695    pub type_params: Option<Loc<Vec<Loc<TypeParam>>>>,
696    pub where_clauses: Vec<WhereClause>,
697    pub target: Loc<TypeSpec>,
698    pub units: Vec<Loc<Unit>>,
699}
700impl WithLocation for ImplBlock {}
701
702/// Declaration of an enum
703#[derive(PartialEq, Debug, Clone)]
704pub struct Enum {
705    pub attributes: AttributeList,
706    pub name: Loc<Identifier>,
707    pub variants: Vec<EnumVariant>,
708}
709impl WithLocation for Enum {}
710
711#[derive(PartialEq, Debug, Clone)]
712pub struct EnumVariant {
713    pub attributes: AttributeList,
714    pub name: Loc<Identifier>,
715    pub args: Option<Loc<ParameterList>>,
716}
717
718#[derive(PartialEq, Debug, Clone)]
719pub struct Struct {
720    pub attributes: AttributeList,
721    pub name: Loc<Identifier>,
722    pub members: Loc<ParameterList>,
723    pub port_keyword: Option<Loc<()>>,
724}
725impl WithLocation for Struct {}
726
727impl Struct {
728    pub fn is_port(&self) -> bool {
729        self.port_keyword.is_some()
730    }
731}
732
733#[derive(PartialEq, Debug, Clone)]
734pub enum TypeDeclKind {
735    Enum(Loc<Enum>),
736    Struct(Loc<Struct>),
737}
738
739/// A declaration of a new type
740#[derive(PartialEq, Debug, Clone)]
741pub struct TypeDeclaration {
742    pub name: Loc<Identifier>,
743    pub kind: TypeDeclKind,
744    pub generic_args: Option<Loc<Vec<Loc<TypeParam>>>>,
745}
746impl WithLocation for TypeDeclaration {}
747
748#[derive(PartialEq, Debug, Clone)]
749pub struct UseStatement {
750    pub path: Loc<Path>,
751    pub alias: Option<Loc<Identifier>>,
752}
753impl WithLocation for UseStatement {}
754
755/// Items are things typically present at the top level of a module such as
756/// entities, pipelines, submodules etc.
757#[derive(PartialEq, Debug, Clone)]
758pub enum Item {
759    Unit(Loc<Unit>),
760    TraitDef(Loc<TraitDef>),
761    Type(Loc<TypeDeclaration>),
762    ExternalMod(Loc<Identifier>),
763    Module(Loc<Module>),
764    Use(Loc<UseStatement>),
765    ImplBlock(Loc<ImplBlock>),
766}
767impl WithLocation for Item {}
768
769impl Item {
770    pub fn name(&self) -> Option<&Identifier> {
771        match self {
772            Item::Unit(u) => Some(&u.head.name.inner),
773            Item::TraitDef(t) => Some(&t.name.inner),
774            Item::Type(t) => Some(&t.name.inner),
775            Item::Module(m) => Some(&m.name.inner),
776            Item::ExternalMod(name) => Some(name),
777            Item::Use(u) => u.alias.as_ref().map(|name| &name.inner),
778            Item::ImplBlock(_) => None,
779        }
780    }
781
782    pub fn variant_str(&self) -> &'static str {
783        match self {
784            Item::Unit(_) => "unit",
785            Item::TraitDef(_) => "trait definition",
786            Item::Type(_) => "type",
787            Item::Module(_) => "module",
788            Item::ExternalMod(_) => "module",
789            Item::Use(_) => "use",
790            Item::ImplBlock(_) => "impl",
791        }
792    }
793}
794
795#[derive(PartialEq, Debug, Clone)]
796pub struct Module {
797    pub name: Loc<Identifier>,
798    pub body: Loc<ModuleBody>,
799}
800impl WithLocation for Module {}
801
802#[derive(PartialEq, Debug, Clone)]
803pub struct ModuleBody {
804    pub members: Vec<Item>,
805    pub documentation: Vec<String>,
806}
807impl WithLocation for ModuleBody {}