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