spade_hir/
lib.rs

1pub mod expression;
2pub mod param_util;
3pub mod symbol_table;
4pub mod testutil;
5
6use std::collections::{BTreeMap, HashMap};
7use std::fmt::Formatter;
8
9pub use expression::{Argument, ArgumentKind, ArgumentList, ExprKind, Expression};
10use itertools::Itertools;
11use num::BigInt;
12use serde::{Deserialize, Serialize};
13use spade_common::id_tracker::{ExprID, ImplID};
14use spade_common::{
15    location_info::{Loc, WithLocation},
16    name::{Identifier, NameID, Path},
17    num_ext::InfallibleToBigInt,
18};
19use spade_diagnostics::Diagnostic;
20use spade_types::{meta_types::MetaType, PrimitiveType};
21
22/**
23  Representation of the language with most language constructs still present, with
24  more correctness guaranatees than the AST, such as types actually existing.
25*/
26
27#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
28pub struct Block {
29    pub statements: Vec<Loc<Statement>>,
30    pub result: Option<Loc<Expression>>,
31}
32impl WithLocation for Block {}
33
34#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
35pub struct PatternArgument {
36    pub target: Loc<Identifier>,
37    pub value: Loc<Pattern>,
38    pub kind: ArgumentKind,
39}
40impl WithLocation for PatternArgument {}
41
42#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
43pub enum PatternKind {
44    Integer(BigInt),
45    Bool(bool),
46    Name {
47        name: Loc<NameID>,
48        pre_declared: bool,
49    },
50    Tuple(Vec<Loc<Pattern>>),
51    Array(Vec<Loc<Pattern>>),
52    /// Instantiation of an entity. While the argument contains information about
53    /// argument names, for codegen purposes, the arguments must be ordered in
54    /// the target order. I.e. they should all act as positioanl arguments
55    Type(Loc<NameID>, Vec<PatternArgument>),
56}
57impl PatternKind {
58    pub fn name(name: Loc<NameID>) -> Self {
59        PatternKind::Name {
60            name,
61            pre_declared: false,
62        }
63    }
64
65    pub fn integer(val: i32) -> Self {
66        Self::Integer(val.to_bigint())
67    }
68}
69impl PatternKind {
70    pub fn with_id(self, id: ExprID) -> Pattern {
71        Pattern { id, kind: self }
72    }
73
74    pub fn idless(self) -> Pattern {
75        Pattern {
76            id: ExprID(0),
77            kind: self,
78        }
79    }
80}
81impl std::fmt::Display for PatternKind {
82    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83        match self {
84            PatternKind::Integer(val) => write!(f, "{val}"),
85            PatternKind::Bool(val) => write!(f, "{val}"),
86            PatternKind::Name { name, .. } => write!(f, "{name}"),
87            PatternKind::Tuple(members) => {
88                write!(
89                    f,
90                    "({})",
91                    members.iter().map(|m| format!("{}", m.kind)).join(", ")
92                )
93            }
94            PatternKind::Array(members) => {
95                write!(
96                    f,
97                    "[{}]",
98                    members.iter().map(|m| format!("{}", m.kind)).join(", ")
99                )
100            }
101            PatternKind::Type(name, _) => write!(f, "{name}(..)"),
102        }
103    }
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct Pattern {
108    // Unique ID of the pattern for use in type inference. Shared with expressions
109    // meaning there are no expression/pattern id collisions
110    pub id: ExprID,
111    pub kind: PatternKind,
112}
113impl WithLocation for Pattern {}
114
115impl Pattern {
116    pub fn get_names(&self) -> Vec<Loc<NameID>> {
117        match &self.kind {
118            PatternKind::Integer(_) => vec![],
119            PatternKind::Bool(_) => vec![],
120            PatternKind::Name {
121                name,
122                pre_declared: _,
123            } => vec![name.clone()],
124            PatternKind::Tuple(inner) => inner.iter().flat_map(|i| i.get_names()).collect(),
125            PatternKind::Type(_, args) => {
126                args.iter().flat_map(|arg| arg.value.get_names()).collect()
127            }
128            PatternKind::Array(inner) => inner.iter().flat_map(|i| i.get_names()).collect(),
129        }
130    }
131}
132
133impl PartialEq for Pattern {
134    fn eq(&self, other: &Self) -> bool {
135        self.kind == other.kind
136    }
137}
138
139#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
140pub struct WalTrace {
141    pub clk: Option<Loc<Expression>>,
142    pub rst: Option<Loc<Expression>>,
143}
144impl WithLocation for WalTrace {}
145
146#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
147pub struct Binding {
148    pub pattern: Loc<Pattern>,
149    pub ty: Option<Loc<TypeSpec>>,
150    pub value: Loc<Expression>,
151    // Specifies if a wal_trace mir node should be emitted for this struct. If this
152    // is present, the type is traceable
153    pub wal_trace: Option<Loc<WalTrace>>,
154}
155
156#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
157pub enum PipelineRegMarkerExtra {
158    Condition(Loc<Expression>),
159    Count {
160        count: Loc<TypeExpression>,
161        count_typeexpr_id: ExprID,
162    },
163}
164
165#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
166pub enum Statement {
167    Binding(Binding),
168    Expression(Loc<Expression>),
169    Register(Register),
170    Declaration(Vec<Loc<NameID>>),
171    PipelineRegMarker(Option<PipelineRegMarkerExtra>),
172    Label(Loc<NameID>),
173    Assert(Loc<Expression>),
174    Set {
175        target: Loc<Expression>,
176        value: Loc<Expression>,
177    },
178    WalSuffixed {
179        suffix: Identifier,
180        target: Loc<NameID>,
181    },
182}
183impl WithLocation for Statement {}
184
185impl Statement {
186    /// NOTE: For use in tests
187    pub fn named_let(pattern_id: ExprID, name_id: Loc<NameID>, val: Expression) -> Self {
188        Self::Binding(Binding {
189            pattern: PatternKind::name(name_id).with_id(pattern_id).nowhere(),
190            ty: None,
191            value: val.nowhere(),
192            wal_trace: None,
193        })
194    }
195
196    pub fn binding(
197        pattern: Loc<Pattern>,
198        ty: Option<Loc<TypeSpec>>,
199        value: Loc<Expression>,
200    ) -> Statement {
201        Statement::Binding(Binding {
202            pattern,
203            ty,
204            value,
205            wal_trace: None,
206        })
207    }
208}
209
210#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
211pub struct Register {
212    pub pattern: Loc<Pattern>,
213    pub clock: Loc<Expression>,
214    pub reset: Option<(Loc<Expression>, Loc<Expression>)>,
215    pub initial: Option<Loc<Expression>>,
216    pub value: Loc<Expression>,
217    pub value_type: Option<Loc<TypeSpec>>,
218    pub attributes: AttributeList,
219}
220impl WithLocation for Register {}
221
222#[derive(PartialEq, Debug, Clone, PartialOrd, Eq, Ord, Serialize, Deserialize)]
223pub struct Module {
224    pub name: Loc<NameID>,
225    pub documentation: String,
226}
227
228/// Type params have both an identifier and a NameID since they go through the
229/// ast lowering process in a few separate steps, and the identifier needs to be
230/// re-added to the symtab multiple times
231#[derive(PartialEq, Debug, Clone, Hash, Eq, Serialize, Deserialize)]
232pub struct TypeParam {
233    pub ident: Loc<Identifier>,
234    pub name_id: NameID,
235    pub trait_bounds: Vec<Loc<TraitSpec>>,
236    pub meta: MetaType,
237}
238impl WithLocation for TypeParam {}
239impl TypeParam {
240    pub fn name_id(&self) -> NameID {
241        self.name_id.clone()
242    }
243}
244
245#[derive(PartialEq, Debug, Clone, Serialize, Deserialize, Hash, Eq)]
246pub enum TypeExpression {
247    /// An integer value
248    Integer(BigInt),
249    /// Another type
250    TypeSpec(TypeSpec),
251    ConstGeneric(Loc<ConstGeneric>),
252}
253impl WithLocation for TypeExpression {}
254
255impl std::fmt::Display for TypeExpression {
256    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
257        match self {
258            TypeExpression::Integer(val) => write!(f, "{val}"),
259            TypeExpression::TypeSpec(val) => write!(f, "{val}"),
260            TypeExpression::ConstGeneric(val) => write!(f, "{val}"),
261        }
262    }
263}
264
265/// A specification of a type to be used. For example, the types of input/output arguments the type
266/// of fields in a struct etc.
267#[derive(PartialEq, Debug, Clone, Serialize, Deserialize, Hash, Eq)]
268pub enum TypeSpec {
269    /// The type is a declared type (struct, enum, typedef etc.) with n arguments
270    Declared(Loc<NameID>, Vec<Loc<TypeExpression>>),
271    /// The type is a generic argument visible in the current scope
272    Generic(Loc<NameID>),
273    /// The type is a tuple of other variables
274    Tuple(Vec<Loc<TypeSpec>>),
275    Array {
276        inner: Box<Loc<TypeSpec>>,
277        size: Box<Loc<TypeExpression>>,
278    },
279    Inverted(Box<Loc<TypeSpec>>),
280    Wire(Box<Loc<TypeSpec>>),
281    /// The type of the `self` parameter in a trait method spec. Should not
282    /// occur in non-traits. The Loc is only used for diag_bails, so an approximate
283    /// reference is fine.
284    TraitSelf(Loc<()>),
285    /// A wildcard, cannot occur everywhere, but ast lowering enusres that wildcards are valid,
286    /// i.e. it is safe to emit a Diagnostic::bug if this is encountered where it is invalid
287    Wildcard(Loc<()>),
288}
289impl WithLocation for TypeSpec {}
290
291// Quick functions for creating types without typing so much
292impl TypeSpec {
293    pub fn unit() -> Self {
294        TypeSpec::Tuple(Vec::new())
295    }
296}
297
298impl std::fmt::Display for TypeSpec {
299    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
300        let str = match self {
301            TypeSpec::Declared(name, params) => {
302                let type_params = if params.is_empty() {
303                    String::from("")
304                } else {
305                    format!(
306                        "<{}>",
307                        params
308                            .iter()
309                            .map(|g| format!("{g}"))
310                            .collect::<Vec<_>>()
311                            .join(", ")
312                    )
313                };
314                format!("{name}{type_params}")
315            }
316            TypeSpec::Generic(name) => format!("{name}"),
317            TypeSpec::Tuple(members) => {
318                format!(
319                    "({})",
320                    members
321                        .iter()
322                        .map(|m| format!("{m}"))
323                        .collect::<Vec<_>>()
324                        .join(", ")
325                )
326            }
327            TypeSpec::Array { inner, size } => format!("[{inner}; {size}]"),
328            TypeSpec::Inverted(inner) => format!("~{inner}"),
329            TypeSpec::Wire(inner) => format!("&{inner}"),
330            TypeSpec::TraitSelf(_) => "Self".into(),
331            TypeSpec::Wildcard(_) => "_".into(),
332        };
333        write!(f, "{str}")
334    }
335}
336
337/// A specification of a trait with type parameters
338#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Hash, Eq)]
339pub struct TraitSpec {
340    pub name: TraitName,
341    pub type_params: Option<Loc<Vec<Loc<TypeExpression>>>>,
342}
343impl WithLocation for TraitSpec {}
344
345/// Declaration of an enum
346#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
347pub struct Enum {
348    pub options: Vec<(Loc<NameID>, Loc<ParameterList>)>,
349    pub documentation: String,
350}
351impl WithLocation for Enum {}
352
353#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
354pub struct WalTraceable {
355    pub suffix: Path,
356    pub uses_clk: bool,
357    pub uses_rst: bool,
358}
359impl WithLocation for WalTraceable {}
360
361#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
362pub struct Struct {
363    pub members: Loc<ParameterList>,
364    pub is_port: bool,
365    pub attributes: AttributeList,
366    pub wal_traceable: Option<Loc<WalTraceable>>,
367    pub documentation: String,
368}
369impl WithLocation for Struct {}
370
371#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
372pub enum TypeDeclKind {
373    Enum(Loc<Enum>),
374    Primitive(PrimitiveType),
375    Struct(Loc<Struct>),
376}
377impl TypeDeclKind {
378    pub fn name(&self) -> &str {
379        match self {
380            TypeDeclKind::Enum(_) => "enum",
381            TypeDeclKind::Primitive(_) => "primitive",
382            TypeDeclKind::Struct(_) => "struct",
383        }
384    }
385}
386
387/// A declaration of a new type
388#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
389pub struct TypeDeclaration {
390    pub name: Loc<NameID>,
391    pub kind: TypeDeclKind,
392    pub generic_args: Vec<Loc<TypeParam>>,
393}
394impl WithLocation for TypeDeclaration {}
395
396#[derive(PartialEq, Debug, Clone, Serialize, Deserialize, Hash, Eq)]
397pub enum ConstGeneric {
398    Name(Loc<NameID>),
399    Const(BigInt),
400    Add(Box<Loc<ConstGeneric>>, Box<Loc<ConstGeneric>>),
401    Sub(Box<Loc<ConstGeneric>>, Box<Loc<ConstGeneric>>),
402    Mul(Box<Loc<ConstGeneric>>, Box<Loc<ConstGeneric>>),
403    Div(Box<Loc<ConstGeneric>>, Box<Loc<ConstGeneric>>),
404    Mod(Box<Loc<ConstGeneric>>, Box<Loc<ConstGeneric>>),
405    UintBitsToFit(Box<Loc<ConstGeneric>>),
406    Eq(Box<Loc<ConstGeneric>>, Box<Loc<ConstGeneric>>),
407    NotEq(Box<Loc<ConstGeneric>>, Box<Loc<ConstGeneric>>),
408}
409impl WithLocation for ConstGeneric {}
410
411impl ConstGeneric {
412    pub fn with_id(self, id: ExprID) -> ConstGenericWithId {
413        ConstGenericWithId { id, inner: self }
414    }
415}
416
417#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
418pub struct ConstGenericWithId {
419    pub id: ExprID,
420    pub inner: ConstGeneric,
421}
422impl WithLocation for ConstGenericWithId {}
423
424impl std::fmt::Display for ConstGeneric {
425    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
426        match self {
427            ConstGeneric::Name(n) => write!(f, "{n}"),
428            ConstGeneric::Const(val) => write!(f, "{val}"),
429            ConstGeneric::Add(l, r) => write!(f, "({l} + {r})"),
430            ConstGeneric::Sub(l, r) => write!(f, "({l} - {r})"),
431            ConstGeneric::Mul(l, r) => write!(f, "({l} * {r})"),
432            ConstGeneric::Div(l, r) => write!(f, "({l} / {r})"),
433            ConstGeneric::Mod(l, r) => write!(f, "({l} % {r})"),
434            ConstGeneric::Eq(l, r) => write!(f, "({l} == {r})"),
435            ConstGeneric::NotEq(l, r) => write!(f, "({l} != {r})"),
436            ConstGeneric::UintBitsToFit(a) => write!(f, "uint_bits_to_fit({a})"),
437        }
438    }
439}
440
441#[derive(PartialEq, Debug, Clone, Serialize, Deserialize, Hash, Eq)]
442pub enum WhereClause {
443    Int {
444        target: Loc<NameID>,
445        constraint: Loc<ConstGeneric>,
446    },
447    Type {
448        target: Loc<NameID>,
449        traits: Vec<Loc<TraitSpec>>,
450    },
451}
452impl WithLocation for WhereClause {}
453
454impl std::fmt::Display for WhereClause {
455    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
456        let str = match self {
457            WhereClause::Int { target, constraint } => {
458                format!("{target}: {{ {constraint} }}")
459            }
460            WhereClause::Type { target, traits } => {
461                format!(
462                    "{target}: {}",
463                    traits.iter().map(|trait_spec| &trait_spec.name).join(" + ")
464                )
465            }
466        };
467        write!(f, "{}", str)
468    }
469}
470
471#[derive(PartialEq, Debug, Clone, Serialize, Deserialize, Hash, Eq)]
472pub enum UnitName {
473    /// The name will be mangled down to contain the NameID in order to ensure
474    /// uniqueness. Emitted by generic functions
475    WithID(Loc<NameID>),
476    /// The name will contain the full path to the name but the ID section of the
477    /// nameID will not be included. Used by non-generic functions
478    FullPath(Loc<NameID>),
479    /// The name will not be mangled. In the output code it will appear as String
480    /// but the compiler will still refer to it by the NameID
481    Unmangled(String, Loc<NameID>),
482}
483
484impl UnitName {
485    pub fn name_id(&self) -> &Loc<NameID> {
486        match self {
487            UnitName::WithID(name) => name,
488            UnitName::FullPath(name) => name,
489            UnitName::Unmangled(_, name) => name,
490        }
491    }
492}
493
494impl std::fmt::Display for UnitName {
495    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
496        match self {
497            UnitName::WithID(name) | UnitName::FullPath(name) | UnitName::Unmangled(_, name) => {
498                write!(f, "{name}")
499            }
500        }
501    }
502}
503
504#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
505pub struct Unit {
506    pub name: UnitName,
507    pub head: UnitHead,
508    pub attributes: AttributeList,
509    // This is needed here because the head does not have NameIDs
510    pub inputs: Vec<(Loc<NameID>, Loc<TypeSpec>)>,
511    pub body: Loc<Expression>,
512}
513impl WithLocation for Unit {}
514
515#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
516pub struct Parameter {
517    /// If the #[no_mangle] attribute is present, this field is set
518    /// with the Loc pointing to the attribute
519    pub no_mangle: Option<Loc<()>>,
520    pub name: Loc<Identifier>,
521    pub ty: Loc<TypeSpec>,
522}
523
524#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
525pub struct ParameterList(pub Vec<Parameter>);
526impl WithLocation for ParameterList {}
527
528impl ParameterList {
529    pub fn argument_num(&self) -> usize {
530        self.0.len()
531    }
532
533    /// Look up the type of an argument. Panics if no such argument exists
534    pub fn arg_type(&self, name: &Identifier) -> &TypeSpec {
535        if let Some(result) = self.try_get_arg_type(name) {
536            result
537        } else {
538            panic!(
539                "Tried to get type of an argument which is not part of the parameter list. {}",
540                name
541            )
542        }
543    }
544
545    /// Look up the type of an argument, returning None if no such argument exists
546    pub fn try_get_arg_type(&self, name: &Identifier) -> Option<&Loc<TypeSpec>> {
547        for Parameter {
548            name: arg,
549            ty,
550            no_mangle: _,
551        } in &self.0
552        {
553            if &arg.inner == name {
554                return Some(ty);
555            }
556        }
557        None
558    }
559
560    pub fn arg_index(&self, target: &Identifier) -> Option<usize> {
561        let indices = self
562            .0
563            .iter()
564            .enumerate()
565            .filter_map(
566                |(
567                    i,
568                    Parameter {
569                        name,
570                        ty: _,
571                        no_mangle: _,
572                    },
573                )| {
574                    if &name.inner == target {
575                        Some(i)
576                    } else {
577                        None
578                    }
579                },
580            )
581            .collect::<Vec<_>>();
582
583        if indices.len() > 1 {
584            panic!("Duplicate arguments with the same name")
585        } else {
586            indices.first().cloned()
587        }
588    }
589}
590
591#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
592pub enum FunctionKind {
593    Fn,
594    Struct,
595    Enum,
596}
597
598#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
599pub enum UnitKind {
600    Function(FunctionKind),
601    Entity,
602    Pipeline {
603        depth: Loc<TypeExpression>,
604        depth_typeexpr_id: ExprID,
605    },
606}
607impl WithLocation for UnitKind {}
608
609impl UnitKind {
610    pub fn name(&self) -> &'static str {
611        match self {
612            UnitKind::Function(FunctionKind::Fn) => "function",
613            UnitKind::Function(FunctionKind::Struct) => "struct",
614            UnitKind::Function(FunctionKind::Enum) => "enum variant",
615            UnitKind::Entity => "entity",
616            UnitKind::Pipeline { .. } => "pipeline",
617        }
618    }
619
620    pub fn is_pipeline(&self) -> bool {
621        matches!(self, UnitKind::Pipeline { .. })
622    }
623}
624
625#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
626pub struct UnitHead {
627    pub name: Loc<Identifier>,
628    pub inputs: Loc<ParameterList>,
629    /// (-> token, type)
630    pub output_type: Option<Loc<TypeSpec>>,
631    pub unit_type_params: Vec<Loc<TypeParam>>,
632    pub scope_type_params: Vec<Loc<TypeParam>>,
633    pub unit_kind: Loc<UnitKind>,
634    pub where_clauses: Vec<Loc<WhereClause>>,
635    pub documentation: String,
636}
637impl WithLocation for UnitHead {}
638
639impl UnitHead {
640    pub fn output_type(&self) -> Loc<TypeSpec> {
641        match &self.output_type {
642            Some(t) => t.clone(),
643            None => {
644                // FIXME: We should point to the end of the argument list here
645                TypeSpec::unit().at_loc(&self.name.loc())
646            }
647        }
648    }
649    pub fn get_type_params(&self) -> Vec<Loc<TypeParam>> {
650        self.unit_type_params
651            .iter()
652            .chain(self.scope_type_params.iter())
653            .cloned()
654            .collect_vec()
655    }
656}
657
658#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
659pub enum Item {
660    Unit(Loc<Unit>),
661    ExternUnit(UnitName, Loc<UnitHead>),
662}
663
664impl Item {
665    pub fn assume_unit(&self) -> &Unit {
666        match self {
667            Item::Unit(u) => &u.inner,
668            Item::ExternUnit(_, _) => panic!("Expected unit, got extern unit"),
669        }
670    }
671}
672
673/// Items which have associated code that can be executed. This is different from
674/// type declarations which are items, but which do not have code on their own
675#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
676pub enum ExecutableItem {
677    EnumInstance { base_enum: NameID, variant: usize },
678    StructInstance,
679    Unit(Loc<Unit>),
680    ExternUnit(UnitName, Loc<UnitHead>),
681}
682impl WithLocation for ExecutableItem {}
683
684pub type TypeList = HashMap<NameID, Loc<TypeDeclaration>>;
685
686#[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Debug, Clone, PartialOrd, Ord)]
687pub enum TraitName {
688    Named(Loc<NameID>),
689    Anonymous(ImplID),
690}
691
692impl TraitName {
693    pub fn is_anonymous(&self) -> bool {
694        matches!(self, Self::Anonymous(_))
695    }
696
697    /// Returns the loc of the name of this trait, if it exists. None otherwise
698    pub fn name_loc(&self) -> Option<Loc<NameID>> {
699        match self {
700            TraitName::Named(n) => Some(n.clone()),
701            TraitName::Anonymous(_) => None,
702        }
703    }
704}
705
706impl std::fmt::Display for TraitName {
707    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
708        match self {
709            TraitName::Named(n) => write!(f, "{n}"),
710            TraitName::Anonymous(id) => write!(f, "Anonymous({})", id.0),
711        }
712    }
713}
714
715/// Attributes that are still present as attributes in the HIR. Not all AST
716/// attributes are in this list, as some are consumed and inlined into the corresponding
717/// ast node
718#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
719pub enum Attribute {
720    Optimize { passes: Vec<Loc<String>> },
721    Fsm { state: NameID },
722    WalTraceable { suffix: Identifier },
723}
724impl Attribute {
725    pub fn name(&self) -> &str {
726        match self {
727            Attribute::Optimize { passes: _ } => "optimize",
728            Attribute::Fsm { state: _ } => "fsm",
729            Attribute::WalTraceable { suffix: _ } => "suffix",
730        }
731    }
732}
733impl WithLocation for Attribute {}
734
735#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
736pub struct AttributeList(pub Vec<Loc<Attribute>>);
737
738impl AttributeList {
739    pub fn empty() -> Self {
740        Self(vec![])
741    }
742}
743
744#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
745pub struct ImplBlock {
746    /// Mapping of identifiers to the NameID of the entity which is the implementation
747    /// for the specified function
748    pub fns: HashMap<Identifier, (NameID, Loc<()>)>,
749    pub type_params: Vec<Loc<TypeParam>>,
750    pub target: Loc<TypeSpec>,
751    pub id: ImplID,
752}
753impl WithLocation for ImplBlock {}
754
755#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
756pub struct TraitDef {
757    pub type_params: Option<Loc<Vec<Loc<TypeParam>>>>,
758    pub fns: HashMap<Identifier, Loc<UnitHead>>,
759}
760impl WithLocation for TraitDef {}
761
762#[derive(PartialEq, Hash, Eq, Debug, Clone, Serialize, Deserialize)]
763pub enum ImplTarget {
764    Array,
765    Inverted,
766    Wire,
767    Named(NameID),
768}
769
770impl ImplTarget {
771    pub fn display(&self, args: &[TypeExpression]) -> String {
772        match self {
773            ImplTarget::Array => {
774                format!(
775                    "[{}; {}]",
776                    args.get(0)
777                        .map(|a| format!("{}", a))
778                        .unwrap_or_else(|| "<(bug) Missing param 0>".to_string()),
779                    args.get(1)
780                        .map(|a| format!("{}", a))
781                        .unwrap_or_else(|| "<(bug) Missing param 1>".to_string())
782                )
783            }
784            ImplTarget::Wire => {
785                format!(
786                    "&{}",
787                    args.get(0)
788                        .map(|a| format!("{}", a))
789                        .unwrap_or_else(|| "<(bug) Missing param 0>".to_string()),
790                )
791            }
792            ImplTarget::Inverted => {
793                format!(
794                    "inv {}",
795                    args.get(0)
796                        .map(|a| format!("{}", a))
797                        .unwrap_or_else(|| "<(bug) Missing param 0>".to_string()),
798                )
799            }
800            ImplTarget::Named(name) => {
801                format!(
802                    "{}{}",
803                    name,
804                    if args.is_empty() {
805                        format!("")
806                    } else {
807                        format!("<{}>", args.iter().map(|arg| format!("{}", arg)).join(", "))
808                    }
809                )
810            }
811        }
812    }
813}
814
815/// A list of all the items present in the whole AST, flattened to remove module
816/// hierarchies.
817///
818/// That is, `mod a { mod b{ entity X {} } } will result in members containing `a::b::X`, but the
819/// module hierarchy no longer has to be traversed.
820///
821/// The modules themselves however still exist in the `modules` set.
822#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
823pub struct ItemList {
824    pub executables: BTreeMap<NameID, ExecutableItem>,
825    pub types: TypeList,
826    /// All modules, including empty ones.
827    pub modules: BTreeMap<NameID, Module>,
828    // FIXME: Support entities and pipelines as trait members.
829    /// All traits in the compilation unit. Traits consist of a list of functions
830    /// by name. Anonymous impl blocks are also members here, but their name is never
831    /// visible to the user.
832    pub traits: HashMap<TraitName, TraitDef>,
833    pub impls: HashMap<ImplTarget, HashMap<(TraitName, Vec<TypeExpression>), Loc<ImplBlock>>>,
834}
835
836impl Default for ItemList {
837    fn default() -> Self {
838        Self::new()
839    }
840}
841
842impl ItemList {
843    pub fn new() -> Self {
844        Self {
845            executables: BTreeMap::new(),
846            types: TypeList::new(),
847            modules: BTreeMap::new(),
848            traits: HashMap::new(),
849            impls: HashMap::new(),
850        }
851    }
852
853    pub fn add_executable(
854        &mut self,
855        name: Loc<NameID>,
856        item: ExecutableItem,
857    ) -> Result<(), Diagnostic> {
858        if let Some(_) = self.executables.get_key_value(&name) {
859            Err(
860                Diagnostic::error(&name, format!("Multiple definitions of thing {name}"))
861                    .primary_label("New definition"),
862            )
863        } else {
864            self.executables.insert(name.inner, item);
865            Ok(())
866        }
867    }
868
869    pub fn add_trait(
870        &mut self,
871        name: TraitName,
872        type_params: Option<Loc<Vec<Loc<TypeParam>>>>,
873        members: Vec<(Identifier, Loc<UnitHead>)>,
874    ) -> Result<(), Diagnostic> {
875        if let Some((prev, _)) = self.traits.get_key_value(&name) {
876            Err(
877                // NOTE: unwrap here is safe *unless* we have got duplicate trait IDs which
878                // means we have bigger problems
879                Diagnostic::error(
880                    name.name_loc().unwrap(),
881                    format!("Multiple definitions of trait {name}"),
882                )
883                .primary_label("New definition")
884                .secondary_label(prev.name_loc().unwrap(), "Previous definition"),
885            )
886        } else {
887            self.traits.insert(
888                name,
889                TraitDef {
890                    type_params,
891                    fns: members.into_iter().collect(),
892                },
893            );
894            Ok(())
895        }
896    }
897
898    pub fn get_trait(&self, name: &TraitName) -> Option<&TraitDef> {
899        self.traits.get(name)
900    }
901
902    pub fn traits(&self) -> &HashMap<TraitName, TraitDef> {
903        &self.traits
904    }
905}