Skip to main content

spade_ast/
lib.rs

1use itertools::Itertools;
2use num::{BigInt, BigUint, Signed, Zero};
3use serde::{Deserialize, Serialize};
4use spade_common::{
5    location_info::{Loc, WithLocation},
6    name::{Identifier, Path, Visibility},
7    namespace::ModuleNamespace,
8    num_ext::InfallibleToBigInt,
9};
10use spade_diagnostics::Diagnostic;
11use std::{fmt::Display, path::PathBuf, rc::Rc};
12
13pub use crate::token::TokenKind;
14
15pub mod testutil;
16pub mod token;
17
18#[derive(PartialEq, Debug, Clone)]
19pub struct ParseCtx {
20    pub file_id: usize,
21    pub working_dir: Option<PathBuf>,
22}
23
24#[derive(PartialEq, Debug, Clone)]
25pub enum TypeExpression {
26    TypeSpec(Box<Loc<TypeSpec>>),
27    Bool(bool),
28    Integer(BigInt),
29    String(String),
30    ConstGeneric(Box<Loc<Expression>>),
31}
32
33impl std::fmt::Display for TypeExpression {
34    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35        match self {
36            TypeExpression::TypeSpec(inner) => write!(f, "{inner}"),
37            TypeExpression::Bool(inner) => write!(f, "{inner}"),
38            TypeExpression::Integer(inner) => write!(f, "{inner}"),
39            TypeExpression::String(inner) => write!(f, "{inner:?}"),
40            TypeExpression::ConstGeneric(_) => write!(f, "{{...}}"),
41        }
42    }
43}
44
45#[derive(PartialEq, Debug, Clone)]
46pub enum NamedTurbofish {
47    Short(Loc<Identifier>),
48    Full(Loc<Identifier>, Loc<TypeExpression>),
49}
50
51#[derive(PartialEq, Debug, Clone)]
52pub enum TurbofishInner {
53    Named(Vec<Loc<NamedTurbofish>>),
54    Positional(Vec<Loc<TypeExpression>>),
55}
56
57/// A specification of a type to be used. For example, the types of input/output arguments the type
58/// of fields in a struct etc.
59#[derive(PartialEq, Debug, Clone)]
60pub enum TypeSpec {
61    Tuple(Vec<Loc<TypeExpression>>),
62    Array {
63        inner: Box<Loc<TypeExpression>>,
64        size: Box<Loc<TypeExpression>>,
65    },
66    Named(Loc<Path>, Option<Loc<Vec<Loc<TypeExpression>>>>),
67    /// An inverted signal (`~`), its "direction" is the inverse of normal. A `~&T` taken as an
68    /// argument is an output, and a returned `~&T` is an input. This used to be expressed as `&mut
69    /// T` Inversions cancel each other, i.e. `~~&T` is effectively `&T` Inverted signals are
70    /// ports.
71    /// If applied to a struct port, all fields are inverted.
72    Inverted(Box<Loc<TypeExpression>>),
73    CopyView(Box<Loc<TypeExpression>>),
74    Impl(Vec<Loc<TraitSpec>>),
75    Wildcard,
76}
77
78impl TypeSpec {
79    pub fn is_tuple(&self) -> bool {
80        match self {
81            TypeSpec::Tuple(_) => true,
82            TypeSpec::Array { .. }
83            | TypeSpec::Named(_, _)
84            | TypeSpec::Inverted(_)
85            | TypeSpec::CopyView(_)
86            | TypeSpec::Impl(_)
87            | TypeSpec::Wildcard => false,
88        }
89    }
90
91    pub fn is_empty_tuple(&self) -> bool {
92        match self {
93            TypeSpec::Tuple(ts) => ts.is_empty(),
94            TypeSpec::Array { .. }
95            | TypeSpec::Named(_, _)
96            | TypeSpec::Inverted(_)
97            | TypeSpec::CopyView(_)
98            | TypeSpec::Impl(_)
99            | TypeSpec::Wildcard => false,
100        }
101    }
102}
103
104impl std::fmt::Display for TypeSpec {
105    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106        match self {
107            TypeSpec::Tuple(inner) => {
108                write!(f, "({})", inner.iter().map(|i| format!("{i}")).join(", "))
109            }
110            TypeSpec::Array { inner, size } => write!(f, "[{inner}; {size}]"),
111            TypeSpec::Named(name, args) => {
112                let args = match args {
113                    Some(a) => format!("<{}>", a.iter().map(|a| format!("{a}")).join(", ")),
114                    None => String::new(),
115                };
116                write!(f, "{name}{args}")
117            }
118            TypeSpec::Inverted(inner) => write!(f, "inv {inner}"),
119            TypeSpec::CopyView(inner) => write!(f, "&{inner}"),
120            TypeSpec::Impl(trait_specs) => write!(
121                f,
122                "impl {}",
123                trait_specs.iter().map(|s| format!("{s}")).join(" + ")
124            ),
125            TypeSpec::Wildcard => write!(f, "_"),
126        }
127    }
128}
129
130#[derive(PartialEq, Debug, Clone)]
131pub enum ArgumentPattern {
132    Named(Vec<(Loc<Identifier>, Option<Loc<Pattern>>)>),
133    Positional(Vec<Loc<Pattern>>),
134}
135
136#[derive(PartialEq, Debug, Clone)]
137pub enum Pattern {
138    Integer(IntLiteral),
139    Bool(bool),
140    Bound(Loc<Identifier>, Box<Loc<Pattern>>),
141    Path {
142        wire: Option<Loc<()>>,
143        path: Loc<Path>,
144    },
145    Tuple(Vec<Loc<Pattern>>),
146    Array(Vec<Loc<Pattern>>),
147    Type(Loc<Path>, Loc<ArgumentPattern>),
148}
149
150// Helper constructors for writing neater tests
151impl Pattern {
152    pub fn integer(val: i32) -> Self {
153        Pattern::Integer(IntLiteral::Unsized(val.to_bigint()))
154    }
155    pub fn name(name: &str) -> Loc<Self> {
156        Pattern::Path {
157            wire: None,
158            path: Path::from_strs(&[name]).nowhere(),
159        }
160        .nowhere()
161    }
162}
163
164#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
165pub enum MacroFragment {
166    Block,
167    Expr,
168    Ident,
169    Item,
170    Literal,
171    Pattern,
172    Path,
173    Statement,
174    Tokens,
175    Type,
176    Visibility,
177}
178
179#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
180pub enum MacroRepetitions {
181    Optional,
182    Many0,
183    Many1,
184}
185
186#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
187pub enum MacroPattern {
188    Token(Loc<TokenKind>),
189    RepeatedSubpattern {
190        parts: Vec<Loc<MacroPattern>>,
191        delim: Option<Loc<TokenKind>>,
192        reps: Loc<MacroRepetitions>,
193    },
194    EnclosedSubpattern {
195        parts: Vec<Loc<MacroPattern>>,
196        open_delim: Loc<TokenKind>,
197        close_delim: Loc<TokenKind>,
198    },
199    Fragment {
200        name: Loc<Identifier>,
201        kind: Loc<Identifier>,
202    },
203}
204
205#[derive(PartialEq, Debug, Clone)]
206pub enum NamedArgument {
207    Full(Loc<Identifier>, Loc<Expression>),
208    /// Binds a local variable to an argument with the same name
209    Short(Loc<Identifier>),
210}
211
212#[derive(PartialEq, Debug, Clone)]
213pub enum ArgumentList {
214    Positional(Vec<Loc<Expression>>),
215    Named(Vec<NamedArgument>),
216}
217
218#[derive(PartialEq, Debug, Clone)]
219pub enum Inequality {
220    Eq,
221    Neq,
222    Lt,
223    Leq,
224    Gt,
225    Geq,
226}
227
228#[derive(PartialEq, Debug, Clone)]
229pub enum WhereClause {
230    GenericInt {
231        target: Loc<Path>,
232        kind: Inequality,
233        expression: Loc<Expression>,
234        if_unsatisfied: Option<String>,
235    },
236    TraitBounds {
237        target: Loc<Path>,
238        traits: Vec<Loc<TraitSpec>>,
239    },
240}
241impl WhereClause {
242    pub fn target(&self) -> &Loc<Path> {
243        match self {
244            WhereClause::GenericInt {
245                target,
246                kind: _,
247                expression: _,
248                if_unsatisfied: _,
249            } => target,
250            WhereClause::TraitBounds { target, traits: _ } => target,
251        }
252    }
253}
254
255#[derive(PartialEq, Debug, Clone)]
256pub struct AssocType {
257    pub name: Loc<Identifier>,
258    pub type_params: Option<Loc<Vec<Loc<TypeParam>>>>,
259}
260
261#[derive(PartialEq, Debug, Clone)]
262pub enum BinaryOperator {
263    Add,
264    Sub,
265    Mul,
266    Div,
267    Mod,
268    Eq,
269    Neq,
270    Lt,
271    Gt,
272    Le,
273    Ge,
274    LogicalAnd,
275    LogicalOr,
276    LogicalXor,
277    LeftShift,
278    RightShift,
279    ArithmeticRightShift,
280    BitwiseAnd,
281    BitwiseOr,
282    BitwiseXor,
283    WrappingAdd,
284    WrappingSub,
285    WrappingMul,
286    WrappingLeftShift,
287    WrappingRightShift,
288}
289
290impl std::fmt::Display for BinaryOperator {
291    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
292        match self {
293            BinaryOperator::Add => write!(f, "+"),
294            BinaryOperator::Sub => write!(f, "-"),
295            BinaryOperator::Mul => write!(f, "*"),
296            BinaryOperator::Div => write!(f, "/"),
297            BinaryOperator::Mod => write!(f, "%"),
298            BinaryOperator::Eq => write!(f, "=="),
299            BinaryOperator::Neq => write!(f, "!="),
300            BinaryOperator::Lt => write!(f, "<"),
301            BinaryOperator::Gt => write!(f, ">"),
302            BinaryOperator::Le => write!(f, "<="),
303            BinaryOperator::Ge => write!(f, ">="),
304            BinaryOperator::LogicalAnd => write!(f, "&"),
305            BinaryOperator::LogicalOr => write!(f, "|"),
306            BinaryOperator::LogicalXor => write!(f, "^"),
307            BinaryOperator::LeftShift => write!(f, "<<"),
308            BinaryOperator::RightShift => write!(f, ">>"),
309            BinaryOperator::ArithmeticRightShift => write!(f, ">>>"),
310            BinaryOperator::BitwiseAnd => write!(f, "&&"),
311            BinaryOperator::BitwiseOr => write!(f, "||"),
312            BinaryOperator::BitwiseXor => write!(f, "^^"),
313            BinaryOperator::WrappingAdd => write!(f, "+."),
314            BinaryOperator::WrappingSub => write!(f, "-."),
315            BinaryOperator::WrappingMul => write!(f, "*."),
316            BinaryOperator::WrappingLeftShift => write!(f, "<<."),
317            BinaryOperator::WrappingRightShift => write!(f, ">>."),
318        }
319    }
320}
321
322#[derive(PartialEq, Debug, Clone)]
323pub enum UnaryOperator {
324    Sub,
325    Not,
326    BitwiseNot,
327    WrappingSub,
328    Dereference,
329    Reference,
330}
331
332impl std::fmt::Display for UnaryOperator {
333    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
334        match self {
335            UnaryOperator::Sub => write!(f, "-"),
336            UnaryOperator::Not => write!(f, "!"),
337            UnaryOperator::BitwiseNot => write!(f, "~"),
338            UnaryOperator::WrappingSub => write!(f, "-."),
339            UnaryOperator::Dereference => write!(f, "*"),
340            UnaryOperator::Reference => write!(f, "&"),
341        }
342    }
343}
344
345#[derive(PartialEq, Debug, Clone)]
346pub enum PipelineStageReference {
347    Relative(Loc<TypeExpression>),
348    Absolute(Loc<Identifier>),
349}
350
351#[derive(PartialEq, Debug, Clone)]
352pub enum CallKind {
353    Function,
354    Entity(Loc<()>),
355    Pipeline(Loc<()>, Loc<TypeExpression>),
356}
357
358#[derive(PartialEq, Debug, Clone)]
359pub enum BitLiteral {
360    Low,
361    High,
362    HighImp,
363}
364
365#[derive(PartialEq, Debug, Clone)]
366pub enum IncompleteExpression {
367    IncompleteDot {
368        base: Box<Loc<Expression>>,
369        has_inst: bool,
370        has_depth: bool,
371    },
372}
373
374#[derive(PartialEq, Debug, Clone)]
375pub enum Expression {
376    Identifier(Loc<Path>),
377    IntLiteral(Loc<IntLiteral>),
378    BoolLiteral(Loc<bool>),
379    StrLiteral(Loc<String>),
380    TriLiteral(Loc<BitLiteral>),
381    /// `[1, 2, 3]`. The Option contains a label, if present
382    ArrayLiteral(Vec<(Option<Loc<Identifier>>, Loc<Expression>)>),
383    /// `[<expr>; <amount>]`
384    /// amount is a const generic
385    ArrayShorthandLiteral(Box<Loc<Expression>>, Box<Loc<Expression>>),
386    Index(Box<Loc<Expression>>, Box<Loc<Expression>>),
387    RangeIndex {
388        target: Box<Loc<Expression>>,
389        // NOTE: These are const generics
390        start: Option<Box<Loc<Expression>>>,
391        end: Option<Box<Loc<Expression>>>,
392    },
393    Parenthesized(Box<Loc<Expression>>),
394    TupleLiteral(Vec<Loc<Expression>>),
395    TupleIndex {
396        target: Box<Loc<Expression>>,
397        index: Loc<u128>,
398        deprecated_syntax: bool,
399    },
400    FieldAccess(Box<Loc<Expression>>, Loc<Identifier>),
401    TypeCast(Box<Loc<Expression>>, Loc<TypeExpression>),
402    Lambda {
403        unit_kind: Loc<UnitKind>,
404        args: Loc<Vec<Loc<Pattern>>>,
405        body: Box<Loc<Block>>,
406    },
407    /// A call to a standalone or associated function, will be differentiated in ast lowering.
408    Call {
409        kind: CallKind,
410        callee: Loc<Path>,
411        args: Loc<ArgumentList>,
412        turbofish: Option<Loc<TurbofishInner>>,
413    },
414    MethodCall {
415        target: Box<Loc<Expression>>,
416        name: Loc<Identifier>,
417        args: Loc<ArgumentList>,
418        kind: CallKind,
419        turbofish: Option<Loc<TurbofishInner>>,
420    },
421    MacroCall {
422        callee: Loc<Path>,
423        tokens: Vec<Loc<TokenKind>>,
424        parse_ctx: Rc<ParseCtx>,
425    },
426    If {
427        cond: Box<Loc<Expression>>,
428        on_true: Box<Loc<Expression>>,
429        on_false: Box<Loc<Expression>>,
430    },
431    TypeLevelIf {
432        cond: Box<Loc<Expression>>,
433        on_true: Box<Loc<Expression>>,
434        on_false: Box<Loc<Expression>>,
435    },
436    Match {
437        expression: Box<Loc<Expression>>,
438        branches: Loc<Vec<(Loc<Pattern>, Option<Loc<Expression>>, Loc<Expression>)>>,
439        if_let: bool,
440    },
441    UnaryOperator(Loc<UnaryOperator>, Box<Loc<Expression>>),
442    BinaryOperator(
443        Box<Loc<Expression>>,
444        Loc<BinaryOperator>,
445        Box<Loc<Expression>>,
446    ),
447    Block(Box<Block>),
448    Unsafe(Box<Loc<Block>>),
449    /// E.g. `stage(-5).x`, `stage('b).y`
450    PipelineReference {
451        /// ```text
452        /// stage(-5).xyz
453        /// ^^^^^^^^^
454        /// ```
455        stage_kw_and_reference_loc: Loc<()>,
456        /// ```text
457        /// stage(-5).xyz
458        ///       ^^
459        /// ```
460        stage: PipelineStageReference,
461        /// ```text
462        /// stage(-5).xyz
463        ///           ^^^
464        /// ```
465        name: Loc<Identifier>,
466    },
467    LabelAccess {
468        label: Loc<Path>,
469        field: Loc<Identifier>,
470    },
471    StageValid,
472    StageReady,
473    StaticUnreachable(Loc<String>),
474    /// An expression which is incomplete, but which downstream passes can still
475    /// use. The `Diagnostic` is the parse error that would have been emitted
476    /// by the parser, and it is the responsibility of some downstream pass
477    /// to emit this diagnostic.
478    Incomplete(Diagnostic, IncompleteExpression),
479}
480
481impl Expression {
482    pub fn int_literal_signed(val: i32) -> Self {
483        Self::IntLiteral(IntLiteral::unsized_(val).nowhere())
484    }
485
486    pub fn bool_literal(val: bool) -> Self {
487        Self::BoolLiteral(val.nowhere())
488    }
489
490    pub fn as_int_literal(self) -> Option<IntLiteral> {
491        match self {
492            Expression::IntLiteral(lit) => Some(lit.inner),
493            _ => None,
494        }
495    }
496
497    pub fn assume_block(&self) -> &Block {
498        if let Expression::Block(inner) = self {
499            inner
500        } else {
501            panic!("Expected block")
502        }
503    }
504
505    pub fn variant_str(&self) -> &'static str {
506        match self {
507            Expression::Identifier(_) => "identifier",
508            Expression::IntLiteral(_) => "int literal",
509            Expression::BoolLiteral(_) => "bool literal",
510            Expression::StrLiteral(_) => "str literal",
511            Expression::TriLiteral(_) => "tri-state literal",
512            Expression::ArrayLiteral(_) => "array literal",
513            Expression::ArrayShorthandLiteral(_, _) => "array shorthand literal",
514            Expression::Index(_, _) => "index",
515            Expression::RangeIndex { .. } => "range index",
516            Expression::Parenthesized(_) => "parenthesized",
517            Expression::TupleLiteral(_) => "tuple literal",
518            Expression::TupleIndex { .. } => "tuple index",
519            Expression::FieldAccess(_, _) => "field access",
520            Expression::Incomplete { .. } => "incomplete",
521            Expression::TypeCast(_, _) => "type cast",
522            Expression::If { .. } => "if",
523            Expression::TypeLevelIf { .. } => "type level if",
524            Expression::Match { if_let: false, .. } => "match",
525            Expression::Match { if_let: true, .. } => "if let",
526            Expression::Lambda { .. } => "lambda",
527            Expression::Call { .. } => "call",
528            Expression::MethodCall { .. } => "method call",
529            Expression::MacroCall { .. } => "macro call",
530            Expression::UnaryOperator(_, _) => "unary operator",
531            Expression::BinaryOperator(_, _, _) => "binary operator",
532            Expression::Block(_) => "block",
533            Expression::Unsafe(_) => "unsafe",
534            Expression::PipelineReference { .. } => "pipeline reference",
535            Expression::LabelAccess { .. } => "label access",
536            Expression::StageValid => "stage.valid",
537            Expression::StageReady => "stage.ready",
538            Expression::StaticUnreachable(_) => "static_unreachable",
539        }
540    }
541}
542
543/// An integer literal, which may or may not have been suffixed with `U` to indicate
544/// it being an unsigned literal.
545#[derive(PartialEq, Debug, Clone)]
546pub enum IntLiteral {
547    Unsized(BigInt),
548    Signed { val: BigInt, size: Option<BigUint> },
549    Unsigned { val: BigUint, size: Option<BigUint> },
550}
551
552impl IntLiteral {
553    pub fn unsized_(val: i32) -> IntLiteral {
554        IntLiteral::Unsized(val.to_bigint())
555    }
556
557    /// Returns this number as a signed number. Unsigned numbers are losslessly converted to
558    /// signed
559    pub fn as_signed(self) -> BigInt {
560        match self {
561            IntLiteral::Signed { val, size: _ } => val,
562            IntLiteral::Unsigned { val, size: _ } => val.to_bigint(),
563            IntLiteral::Unsized(val) => val,
564        }
565    }
566
567    // Returns the signed, or unsigned number as a BigUint if it is positive, otherwise,
568    // None
569    pub fn as_unsigned(self) -> Option<BigUint> {
570        match self {
571            IntLiteral::Signed { val, size: _ } | IntLiteral::Unsized(val) => {
572                if val >= BigInt::zero() {
573                    Some(val.to_biguint().unwrap())
574                } else {
575                    None
576                }
577            }
578            IntLiteral::Unsigned { val, size: _ } => Some(val),
579        }
580    }
581
582    pub fn is_negative(&self) -> bool {
583        match self {
584            IntLiteral::Unsized(val) | IntLiteral::Signed { val, size: _ } => val.is_negative(),
585            IntLiteral::Unsigned { .. } => false,
586        }
587    }
588}
589
590impl Display for IntLiteral {
591    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
592        match self {
593            // this is not dry
594            IntLiteral::Unsized(val) | IntLiteral::Signed { val, .. } => write!(f, "{}", val),
595            IntLiteral::Unsigned { val, .. } => write!(f, "{}", val),
596        }
597    }
598}
599
600#[derive(PartialEq, Debug, Clone, Default)]
601pub struct Block {
602    pub statements: Vec<Loc<Statement>>,
603    pub result: Option<Loc<Expression>>,
604}
605
606#[derive(PartialEq, Debug, Clone)]
607pub struct Binding {
608    pub pattern: Loc<Pattern>,
609    pub ty: Option<Loc<TypeSpec>>,
610    pub value: Loc<Expression>,
611    pub attrs: AttributeList,
612}
613
614#[derive(PartialEq, Debug, Clone)]
615pub enum Statement {
616    Label(Loc<Identifier>),
617    Declaration(Vec<Loc<Identifier>>),
618    Binding(Binding),
619    Expression(Loc<Expression>, AttributeList),
620    PipelineRegMarker(Option<Loc<TypeExpression>>, Option<Loc<Expression>>),
621    Register(Loc<Register>),
622    /// Sets the value of the target expression, which must be a Backward port to
623    /// the value of `value`
624    Set {
625        target: Loc<Expression>,
626        value: Loc<Expression>,
627    },
628    Assert(Loc<Expression>),
629    Type(Loc<TypeDeclaration>),
630}
631
632impl Statement {
633    // Creates a binding from name, type and values without any attributes.
634    pub fn binding(
635        pattern: Loc<Pattern>,
636        ty: Option<Loc<TypeSpec>>,
637        value: Loc<Expression>,
638    ) -> Self {
639        Self::Binding(Binding {
640            pattern,
641            ty,
642            value,
643            attrs: AttributeList::empty(),
644        })
645    }
646}
647
648/// A generic type parameter
649#[derive(PartialEq, Debug, Clone)]
650pub enum TypeParam {
651    TypeName {
652        name: Loc<Identifier>,
653        traits: Vec<Loc<TraitSpec>>,
654        default: Option<Loc<TypeExpression>>,
655    },
656    TypeWithMeta {
657        meta: Loc<Identifier>,
658        name: Loc<Identifier>,
659        default: Option<Loc<TypeExpression>>,
660    },
661}
662impl TypeParam {
663    pub fn name(&self) -> &Loc<Identifier> {
664        match self {
665            TypeParam::TypeName {
666                name,
667                traits: _,
668                default: _,
669            } => name,
670            TypeParam::TypeWithMeta {
671                meta: _,
672                name,
673                default: _,
674            } => name,
675        }
676    }
677
678    pub fn default(&self) -> &Option<Loc<TypeExpression>> {
679        match self {
680            TypeParam::TypeName {
681                name: _,
682                traits: _,
683                default,
684            } => default,
685            TypeParam::TypeWithMeta {
686                meta: _,
687                name: _,
688                default,
689            } => default,
690        }
691    }
692}
693
694#[derive(PartialEq, Debug, Clone)]
695pub enum GenericBound {
696    IntegerConstraint(Loc<Path>, Loc<Expression>),
697    TypeConstraint(Loc<Path>, Vec<Loc<Identifier>>),
698}
699
700impl GenericBound {
701    pub fn path(&self) -> &Loc<Path> {
702        match self {
703            GenericBound::IntegerConstraint(path, _) => path,
704            GenericBound::TypeConstraint(path, _) => path,
705        }
706    }
707}
708
709#[derive(PartialEq, Debug, Clone)]
710pub enum Attribute {
711    SpadecParenSugar,
712    VerilogAttrs {
713        entries: Vec<(Loc<Identifier>, Option<Loc<String>>)>,
714    },
715    Optimize {
716        passes: Vec<Loc<String>>,
717    },
718    Deprecated {
719        since: Option<Loc<String>>,
720        note: Option<Loc<String>>,
721    },
722    NoMangle {
723        all: bool,
724    },
725    Fsm {
726        state: Option<Loc<Identifier>>,
727    },
728    Documentation {
729        content: String,
730    },
731    SurferTranslator(String),
732    Inline,
733}
734
735impl Attribute {
736    pub fn name(&self) -> &str {
737        match self {
738            Attribute::SpadecParenSugar => "spadec_paren_sugar",
739            Attribute::VerilogAttrs { .. } => "verilog_attrs",
740            Attribute::Optimize { passes: _ } => "optimize",
741            Attribute::Deprecated { .. } => "deprecated",
742            Attribute::NoMangle { .. } => "no_mangle",
743            Attribute::Fsm { .. } => "fsm",
744            Attribute::Documentation { .. } => "doc",
745            Attribute::SurferTranslator(_) => "surfer_translator",
746            Attribute::Inline => "inline",
747        }
748    }
749}
750
751#[derive(PartialEq, Debug, Clone)]
752pub struct AttributeList(pub Vec<Loc<Attribute>>);
753impl AttributeList {
754    pub fn empty() -> Self {
755        Self(vec![])
756    }
757
758    pub fn is_empty(&self) -> bool {
759        self.0.is_empty()
760    }
761
762    pub fn from_vec(attrs: Vec<Loc<Attribute>>) -> Self {
763        Self(attrs)
764    }
765
766    pub fn merge_docs(&self) -> String {
767        self.0
768            .iter()
769            .filter_map(|attr| {
770                if let Attribute::Documentation { content } = &attr.inner {
771                    Some(content)
772                } else {
773                    None
774                }
775            })
776            .join("\n")
777    }
778}
779
780#[derive(PartialEq, Debug, Clone, Copy)]
781pub struct WireMarker {}
782
783#[derive(PartialEq, Debug, Clone)]
784pub struct ParameterList {
785    pub self_: Option<(Loc<AttributeList>, Option<Loc<WireMarker>>, Option<Loc<()>>)>,
786    pub args: Vec<(
787        AttributeList,
788        Option<Loc<WireMarker>>,
789        Loc<Identifier>,
790        Loc<TypeSpec>,
791    )>,
792}
793
794impl ParameterList {
795    pub fn without_self(
796        args: Vec<(
797            AttributeList,
798            Option<Loc<WireMarker>>,
799            Loc<Identifier>,
800            Loc<TypeSpec>,
801        )>,
802    ) -> Self {
803        Self { self_: None, args }
804    }
805}
806
807#[derive(PartialEq, Debug, Clone)]
808pub enum UnitKind {
809    Function,
810    Entity,
811    Pipeline(Loc<TypeExpression>),
812}
813
814impl UnitKind {
815    pub fn is_pipeline(&self) -> bool {
816        match self {
817            UnitKind::Function => false,
818            UnitKind::Entity => false,
819            UnitKind::Pipeline(_) => true,
820        }
821    }
822}
823
824impl std::fmt::Display for UnitKind {
825    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
826        match self {
827            UnitKind::Function => write!(f, "fn"),
828            UnitKind::Entity => write!(f, "entity"),
829            UnitKind::Pipeline(_) => write!(f, "pipeline"),
830        }
831    }
832}
833
834#[derive(PartialEq, Debug, Clone)]
835pub struct UnitHead {
836    pub visibility: Loc<Visibility>,
837    pub unsafe_token: Option<Loc<()>>,
838    pub extern_token: Option<Loc<()>>,
839    pub attributes: AttributeList,
840    pub unit_kind: Loc<UnitKind>,
841    pub name: Loc<Identifier>,
842    pub inputs: Loc<ParameterList>,
843    pub output_type: Option<(Loc<()>, Loc<TypeSpec>)>,
844    pub type_params: Option<Loc<Vec<Loc<TypeParam>>>>,
845    pub where_clauses: Vec<WhereClause>,
846}
847
848#[derive(PartialEq, Debug, Clone)]
849pub struct Unit {
850    pub head: UnitHead,
851    /// The body is an expression for ID assignment purposes, but semantic analysis
852    /// ensures that it is always a block. If body is `None`, the entity is `extern`.
853    pub body: Option<Loc<Expression>>,
854}
855
856#[derive(PartialEq, Debug, Clone)]
857pub struct Register {
858    pub keyword: Loc<()>,
859    pub pattern: Loc<Pattern>,
860    pub clock: Loc<Expression>,
861    pub reset: Option<(Loc<Expression>, Loc<Expression>)>,
862    pub initial: Option<Loc<Expression>>,
863    pub value: Loc<Expression>,
864    pub value_type: Option<Loc<TypeSpec>>,
865    pub attributes: AttributeList,
866}
867
868pub type MacroRules = Vec<(Loc<MacroPattern>, Vec<Loc<TokenKind>>)>;
869
870/// A definition of a macro
871#[derive(PartialEq, Debug, Clone)]
872pub struct MacroDef {
873    pub visibility: Loc<Visibility>,
874    pub name: Loc<Identifier>,
875    pub rules: MacroRules,
876    pub attributes: AttributeList,
877}
878
879/// A definition of a trait
880#[derive(PartialEq, Debug, Clone)]
881pub struct TraitDef {
882    pub visibility: Loc<Visibility>,
883    pub name: Loc<Identifier>,
884    pub type_params: Option<Loc<Vec<Loc<TypeParam>>>>,
885    pub subtraits: Vec<Loc<TraitSpec>>,
886    pub where_clauses: Vec<WhereClause>,
887    pub attributes: AttributeList,
888    pub assoc_types: Vec<Loc<AssocType>>,
889    pub methods: Vec<Loc<UnitHead>>,
890}
891
892/// A specification of a trait with type parameters
893#[derive(PartialEq, Debug, Clone)]
894pub struct TraitSpec {
895    pub path: Loc<Path>,
896    pub type_params: Option<Loc<Vec<Loc<TypeExpression>>>>,
897    pub paren_syntax: bool,
898}
899
900impl std::fmt::Display for TraitSpec {
901    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
902        let Self {
903            path,
904            type_params,
905            paren_syntax,
906        } = self;
907
908        if *paren_syntax {
909            let mut type_params = type_params.clone().unwrap();
910            let return_type = type_params.pop().unwrap();
911            let param_tuple = type_params.pop().unwrap();
912
913            let type_params_string = match type_params.as_slice() {
914                [] => String::new(),
915                params => format!("<{}>", params.iter().map(|p| format!("{p}")).join(", ")),
916            };
917
918            let return_type_string = match return_type.inner {
919                TypeExpression::TypeSpec(ts) if ts.is_empty_tuple() => String::new(),
920                ty => format!(" -> {ty}"),
921            };
922
923            write!(
924                f,
925                "{path}{type_params_string}{param_tuple}{return_type_string}",
926            )
927        } else {
928            write!(
929                f,
930                "{path}{}",
931                type_params
932                    .as_ref()
933                    .map(|tp| { format!("<{}>", tp.iter().map(|e| format!("{e}")).join(", ")) })
934                    .unwrap_or(String::new())
935            )
936        }
937    }
938}
939
940#[derive(PartialEq, Debug, Clone)]
941pub struct ImplBlock {
942    pub r#trait: Option<Loc<TraitSpec>>,
943    pub type_params: Option<Loc<Vec<Loc<TypeParam>>>>,
944    pub where_clauses: Vec<WhereClause>,
945    pub target: Loc<TypeSpec>,
946    pub assoc_types: Vec<Loc<TypeDeclaration>>,
947    pub units: Vec<Loc<Unit>>,
948}
949
950/// Declaration of an enum
951#[derive(PartialEq, Debug, Clone)]
952pub struct Enum {
953    pub attributes: AttributeList,
954    pub name: Loc<Identifier>,
955    pub variants: Vec<EnumVariant>,
956}
957
958#[derive(PartialEq, Debug, Clone)]
959pub struct EnumVariant {
960    pub attributes: AttributeList,
961    pub name: Loc<Identifier>,
962    pub args: Option<Loc<ParameterList>>,
963}
964
965#[derive(PartialEq, Debug, Clone)]
966pub struct Struct {
967    pub attributes: AttributeList,
968    pub name: Loc<Identifier>,
969    pub members: Loc<ParameterList>,
970}
971
972#[derive(PartialEq, Debug, Clone)]
973pub struct TypeAlias {
974    pub attributes: AttributeList,
975    pub name: Loc<Identifier>,
976    pub type_spec: Loc<TypeSpec>,
977}
978
979#[derive(PartialEq, Debug, Clone)]
980pub enum TypeDeclKind {
981    Enum(Loc<Enum>),
982    Struct(Loc<Struct>),
983    Alias(Loc<TypeAlias>),
984}
985
986/// A declaration of a new type
987#[derive(PartialEq, Debug, Clone)]
988pub struct TypeDeclaration {
989    pub visibility: Loc<Visibility>,
990    pub name: Loc<Identifier>,
991    pub kind: TypeDeclKind,
992    pub generic_args: Option<Loc<Vec<Loc<TypeParam>>>>,
993}
994
995#[derive(PartialEq, Debug, Clone)]
996pub struct UseStatement {
997    pub visibility: Loc<Visibility>,
998    pub path: Loc<Path>,
999    pub alias: Option<Loc<Identifier>>,
1000}
1001
1002/// Items are things typically present at the top level of a module such as
1003/// entities, pipelines, submodules etc.
1004#[derive(PartialEq, Debug, Clone)]
1005pub enum Item {
1006    Unit(Loc<Unit>),
1007    MacroDef(Loc<MacroDef>),
1008    TraitDef(Loc<TraitDef>),
1009    Type(Loc<TypeDeclaration>),
1010    ExternalMod(Loc<ExternalMod>),
1011    Module(Loc<Module>),
1012    Use(AttributeList, Loc<Vec<UseStatement>>),
1013    ImplBlock(Loc<ImplBlock>),
1014}
1015
1016impl Item {
1017    pub fn name(&self) -> Option<&Identifier> {
1018        match self {
1019            Item::Unit(u) => Some(&u.head.name.inner),
1020            Item::MacroDef(m) => Some(&m.name.inner),
1021            Item::TraitDef(t) => Some(&t.name.inner),
1022            Item::Type(t) => Some(&t.name.inner),
1023            Item::Module(m) => Some(&m.name.inner),
1024            Item::ExternalMod(m) => Some(&m.name.inner),
1025            Item::Use(_, _) => None,
1026            Item::ImplBlock(_) => None,
1027        }
1028    }
1029
1030    pub fn variant_str(&self) -> &'static str {
1031        match self {
1032            Item::Unit(_) => "unit",
1033            Item::MacroDef(_) => "macro definition",
1034            Item::TraitDef(_) => "trait definition",
1035            Item::Type(_) => "type",
1036            Item::Module(_) => "module",
1037            Item::ExternalMod(_) => "module",
1038            Item::Use(_, _) => "use",
1039            Item::ImplBlock(_) => "impl",
1040        }
1041    }
1042}
1043
1044#[derive(PartialEq, Debug, Clone)]
1045pub struct ExternalMod {
1046    pub visibility: Loc<Visibility>,
1047    pub name: Loc<Identifier>,
1048    pub attributes: AttributeList,
1049}
1050
1051#[derive(PartialEq, Debug, Clone)]
1052pub struct Module {
1053    pub visibility: Loc<Visibility>,
1054    pub name: Loc<Identifier>,
1055    pub body: Loc<ModuleBody>,
1056    pub attributes: AttributeList,
1057}
1058
1059#[derive(PartialEq, Debug, Clone)]
1060pub struct ModuleBody {
1061    pub members: Vec<Item>,
1062    pub documentation: Vec<String>,
1063}
1064
1065/// Contains AST nodes that were found during parsing even if they did not end
1066/// up being part of a complete ast node.
1067///
1068/// For example,
1069/// ```
1070/// match something {
1071///     path::
1072/// }
1073/// ```
1074///
1075/// would result in `path::` being added to `paths` even though the match expression
1076/// is missing a branch which makes the parser bail
1077///
1078/// This is primarily used by completion
1079#[derive(Clone, Default, Serialize, Deserialize)]
1080pub struct FloatingNodes {
1081    pub paths: Vec<Loc<Path>>,
1082    /// Locs that track where namespaces are created
1083    /// The paths here are _not_ absolute, they are relative to to any more broad module locs
1084    ///
1085    /// For example
1086    ///
1087    /// ```spade
1088    /// src/submod/subfile.spade:
1089    /// mod a {}
1090    /// ```
1091    ///
1092    /// results in two modules:
1093    /// `proj::submod::subfile` and `a`, Loc'd appropriately
1094    ///
1095    /// To infer the actual path, the modules have to be walked in expanding order
1096    pub namespaces: Vec<Loc<ModuleNamespace>>,
1097}
1098
1099impl FloatingNodes {
1100    pub fn add_path(&mut self, path: Loc<Path>) {
1101        self.paths.push(path)
1102    }
1103
1104    pub fn merge(&mut self, other: FloatingNodes) {
1105        let FloatingNodes { paths, namespaces } = other;
1106        self.paths.extend(paths);
1107        self.namespaces.extend(namespaces);
1108    }
1109}