spade_hir/
lib.rs

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