1use itertools::Itertools;
2use num::{BigInt, BigUint, Signed, Zero};
3use spade_common::{
4 location_info::{Loc, WithLocation},
5 name::{Identifier, Path},
6 num_ext::InfallibleToBigInt,
7};
8use std::fmt::Display;
9pub mod testutil;
10
11#[derive(PartialEq, Debug, Clone)]
12pub enum TypeExpression {
13 TypeSpec(Box<Loc<TypeSpec>>),
14 Integer(BigInt),
15 String(String),
16 ConstGeneric(Box<Loc<Expression>>),
17}
18
19impl std::fmt::Display for TypeExpression {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 match self {
22 TypeExpression::TypeSpec(inner) => write!(f, "{inner}"),
23 TypeExpression::Integer(inner) => write!(f, "{inner}"),
24 TypeExpression::String(inner) => write!(f, "{inner:?}"),
25 TypeExpression::ConstGeneric(_) => write!(f, "{{...}}"),
26 }
27 }
28}
29
30#[derive(PartialEq, Debug, Clone)]
31pub enum NamedTurbofish {
32 Short(Loc<Identifier>),
33 Full(Loc<Identifier>, Loc<TypeExpression>),
34}
35
36#[derive(PartialEq, Debug, Clone)]
37pub enum TurbofishInner {
38 Named(Vec<Loc<NamedTurbofish>>),
39 Positional(Vec<Loc<TypeExpression>>),
40}
41
42#[derive(PartialEq, Debug, Clone)]
45pub enum TypeSpec {
46 Tuple(Vec<Loc<TypeExpression>>),
47 Array {
48 inner: Box<Loc<TypeExpression>>,
49 size: Box<Loc<TypeExpression>>,
50 },
51 Named(Loc<Path>, Option<Loc<Vec<Loc<TypeExpression>>>>),
52 Inverted(Box<Loc<TypeExpression>>),
58 Wire(Box<Loc<TypeExpression>>),
59 Wildcard,
60}
61
62impl std::fmt::Display for TypeSpec {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 match self {
65 TypeSpec::Tuple(inner) => {
66 write!(f, "({})", inner.iter().map(|i| format!("{i}")).join(", "))
67 }
68 TypeSpec::Array { inner, size } => write!(f, "[{inner}; {size}]"),
69 TypeSpec::Named(name, args) => {
70 let args = match args {
71 Some(a) => a.iter().map(|a| format!("{a}")).join(", "),
72 None => String::new(),
73 };
74 write!(f, "{name}{args}")
75 }
76 TypeSpec::Inverted(inner) => write!(f, "inv {inner}"),
77 TypeSpec::Wire(inner) => write!(f, "&{inner}"),
78 TypeSpec::Wildcard => write!(f, "_"),
79 }
80 }
81}
82
83#[derive(PartialEq, Debug, Clone)]
84pub enum ArgumentPattern {
85 Named(Vec<(Loc<Identifier>, Option<Loc<Pattern>>)>),
86 Positional(Vec<Loc<Pattern>>),
87}
88
89#[derive(PartialEq, Debug, Clone)]
90pub enum Pattern {
91 Integer(IntLiteral),
92 Bool(bool),
93 Path(Loc<Path>),
94 Tuple(Vec<Loc<Pattern>>),
95 Array(Vec<Loc<Pattern>>),
96 Type(Loc<Path>, Loc<ArgumentPattern>),
97}
98
99impl Pattern {
101 pub fn integer(val: i32) -> Self {
102 Pattern::Integer(IntLiteral::Unsized(val.to_bigint()))
103 }
104 pub fn name(name: &str) -> Loc<Self> {
105 Pattern::Path(Path(vec![Identifier(name.to_string()).nowhere()]).nowhere()).nowhere()
106 }
107}
108
109#[derive(PartialEq, Debug, Clone)]
110pub enum NamedArgument {
111 Full(Loc<Identifier>, Loc<Expression>),
112 Short(Loc<Identifier>),
114}
115
116#[derive(PartialEq, Debug, Clone)]
117pub enum ArgumentList {
118 Positional(Vec<Loc<Expression>>),
119 Named(Vec<NamedArgument>),
120}
121
122#[derive(PartialEq, Debug, Clone)]
123pub enum WhereClause {
124 GenericInt {
125 target: Loc<Path>,
126 expression: Loc<Expression>,
127 },
128 TraitBounds {
129 target: Loc<Path>,
130 traits: Vec<Loc<TraitSpec>>,
131 },
132}
133impl WhereClause {
134 pub fn target(&self) -> &Loc<Path> {
135 match self {
136 WhereClause::GenericInt {
137 target,
138 expression: _,
139 } => target,
140 WhereClause::TraitBounds { target, traits: _ } => target,
141 }
142 }
143}
144
145#[derive(PartialEq, Debug, Clone)]
146pub enum BinaryOperator {
147 Add,
148 Sub,
149 Mul,
150 Div,
151 Mod,
152 Equals,
153 NotEquals,
154 Lt,
155 Gt,
156 Le,
157 Ge,
158 LogicalAnd,
159 LogicalOr,
160 LogicalXor,
161 LeftShift,
162 RightShift,
163 ArithmeticRightShift,
164 BitwiseAnd,
165 BitwiseOr,
166 BitwiseXor,
167}
168
169impl std::fmt::Display for BinaryOperator {
170 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
171 match self {
172 BinaryOperator::Add => write!(f, "+"),
173 BinaryOperator::Sub => write!(f, "-"),
174 BinaryOperator::Mul => write!(f, "*"),
175 BinaryOperator::Div => write!(f, "/"),
176 BinaryOperator::Mod => write!(f, "%"),
177 BinaryOperator::Equals => write!(f, "=="),
178 BinaryOperator::NotEquals => write!(f, "!="),
179 BinaryOperator::Lt => write!(f, "<"),
180 BinaryOperator::Gt => write!(f, ">"),
181 BinaryOperator::Le => write!(f, "<="),
182 BinaryOperator::Ge => write!(f, ">="),
183 BinaryOperator::LogicalAnd => write!(f, "&"),
184 BinaryOperator::LogicalOr => write!(f, "|"),
185 BinaryOperator::LogicalXor => write!(f, "^"),
186 BinaryOperator::LeftShift => write!(f, "<<"),
187 BinaryOperator::RightShift => write!(f, ">>"),
188 BinaryOperator::ArithmeticRightShift => write!(f, ">>>"),
189 BinaryOperator::BitwiseAnd => write!(f, "&&"),
190 BinaryOperator::BitwiseOr => write!(f, "||"),
191 BinaryOperator::BitwiseXor => write!(f, "^^"),
192 }
193 }
194}
195
196#[derive(PartialEq, Debug, Clone)]
197pub enum UnaryOperator {
198 Sub,
199 Not,
200 BitwiseNot,
201 Dereference,
202 Reference,
203}
204
205impl std::fmt::Display for UnaryOperator {
206 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
207 match self {
208 UnaryOperator::Sub => write!(f, "-"),
209 UnaryOperator::Not => write!(f, "!"),
210 UnaryOperator::BitwiseNot => write!(f, "~"),
211 UnaryOperator::Dereference => write!(f, "*"),
212 UnaryOperator::Reference => write!(f, "&"),
213 }
214 }
215}
216
217#[derive(PartialEq, Debug, Clone)]
218pub enum PipelineStageReference {
219 Relative(Loc<TypeExpression>),
220 Absolute(Loc<Identifier>),
221}
222
223#[derive(PartialEq, Debug, Clone)]
224pub enum CallKind {
225 Function,
226 Entity(Loc<()>),
227 Pipeline(Loc<()>, Loc<TypeExpression>),
228}
229
230#[derive(PartialEq, Debug, Clone)]
231pub enum BitLiteral {
232 Low,
233 High,
234 HighImp,
235}
236
237#[derive(PartialEq, Debug, Clone)]
238pub enum Expression {
239 Identifier(Loc<Path>),
240 IntLiteral(Loc<IntLiteral>),
241 BoolLiteral(Loc<bool>),
242 StrLiteral(Loc<String>),
243 TriLiteral(Loc<BitLiteral>),
244 ArrayLiteral(Vec<Loc<Expression>>),
246 ArrayShorthandLiteral(Box<Loc<Expression>>, Box<Loc<Expression>>),
249 Index(Box<Loc<Expression>>, Box<Loc<Expression>>),
250 RangeIndex {
251 target: Box<Loc<Expression>>,
252 start: Box<Loc<Expression>>,
254 end: Box<Loc<Expression>>,
255 },
256 Parenthesized(Box<Loc<Expression>>),
257 TupleLiteral(Vec<Loc<Expression>>),
258 TupleIndex(Box<Loc<Expression>>, Loc<u128>),
259 FieldAccess(Box<Loc<Expression>>, Loc<Identifier>),
260 CreatePorts,
261 Lambda {
262 unit_kind: Loc<UnitKind>,
263 args: Loc<Vec<Loc<Pattern>>>,
264 body: Box<Loc<Block>>,
265 },
266 Call {
267 kind: CallKind,
268 callee: Loc<Path>,
269 args: Loc<ArgumentList>,
270 turbofish: Option<Loc<TurbofishInner>>,
271 },
272 MethodCall {
273 target: Box<Loc<Expression>>,
274 name: Loc<Identifier>,
275 args: Loc<ArgumentList>,
276 kind: CallKind,
277 turbofish: Option<Loc<TurbofishInner>>,
278 },
279 If(
280 Box<Loc<Expression>>,
281 Box<Loc<Expression>>,
282 Box<Loc<Expression>>,
283 ),
284 TypeLevelIf(
285 Box<Loc<Expression>>,
286 Box<Loc<Expression>>,
287 Box<Loc<Expression>>,
288 ),
289 Match(
290 Box<Loc<Expression>>,
291 Loc<Vec<(Loc<Pattern>, Loc<Expression>)>>,
292 ),
293 UnaryOperator(Loc<UnaryOperator>, Box<Loc<Expression>>),
294 BinaryOperator(
295 Box<Loc<Expression>>,
296 Loc<BinaryOperator>,
297 Box<Loc<Expression>>,
298 ),
299 Block(Box<Block>),
300 Unsafe(Box<Loc<Block>>),
301 PipelineReference {
303 stage_kw_and_reference_loc: Loc<()>,
308 stage: PipelineStageReference,
313 name: Loc<Identifier>,
318 },
319 StageValid,
320 StageReady,
321 StaticUnreachable(Loc<String>),
322}
323
324impl Expression {
325 pub fn int_literal_signed(val: i32) -> Self {
326 Self::IntLiteral(IntLiteral::unsized_(val).nowhere())
327 }
328
329 pub fn bool_literal(val: bool) -> Self {
330 Self::BoolLiteral(val.nowhere())
331 }
332
333 pub fn as_int_literal(self) -> Option<IntLiteral> {
334 match self {
335 Expression::IntLiteral(lit) => Some(lit.inner),
336 _ => None,
337 }
338 }
339
340 pub fn assume_block(&self) -> &Block {
341 if let Expression::Block(inner) = self {
342 inner
343 } else {
344 panic!("Expected block")
345 }
346 }
347
348 pub fn variant_str(&self) -> &'static str {
349 match self {
350 Expression::Identifier(_) => "identifier",
351 Expression::IntLiteral(_) => "int literal",
352 Expression::BoolLiteral(_) => "bool literal",
353 Expression::StrLiteral(_) => "str literal",
354 Expression::TriLiteral(_) => "tri-state literal",
355 Expression::ArrayLiteral(_) => "array literal",
356 Expression::ArrayShorthandLiteral(_, _) => "array shorthand literal",
357 Expression::CreatePorts => "port",
358 Expression::Index(_, _) => "index",
359 Expression::RangeIndex { .. } => "range index",
360 Expression::Parenthesized(_) => "parenthesized",
361 Expression::TupleLiteral(_) => "tuple literal",
362 Expression::TupleIndex(_, _) => "tuple index",
363 Expression::FieldAccess(_, _) => "field access",
364 Expression::If(_, _, _) => "if",
365 Expression::TypeLevelIf(_, _, _) => "type level if",
366 Expression::Match(_, _) => "match",
367 Expression::Lambda { .. } => "lambda",
368 Expression::Call { .. } => "call",
369 Expression::MethodCall { .. } => "method call",
370 Expression::UnaryOperator(_, _) => "unary operator",
371 Expression::BinaryOperator(_, _, _) => "binary operator",
372 Expression::Block(_) => "block",
373 Expression::Unsafe(_) => "unsafe",
374 Expression::PipelineReference { .. } => "pipeline reference",
375 Expression::StageValid => "stage.valid",
376 Expression::StageReady => "stage.ready",
377 Expression::StaticUnreachable(_) => "static_unreachable",
378 }
379 }
380}
381
382#[derive(PartialEq, Debug, Clone)]
385pub enum IntLiteral {
386 Unsized(BigInt),
387 Signed { val: BigInt, size: BigUint },
388 Unsigned { val: BigUint, size: BigUint },
389}
390
391impl IntLiteral {
392 pub fn unsized_(val: i32) -> IntLiteral {
393 IntLiteral::Unsized(val.to_bigint())
394 }
395
396 pub fn as_signed(self) -> BigInt {
399 match self {
400 IntLiteral::Signed { val, size: _ } => val,
401 IntLiteral::Unsigned { val, size: _ } => val.to_bigint(),
402 IntLiteral::Unsized(val) => val,
403 }
404 }
405
406 pub fn as_unsigned(self) -> Option<BigUint> {
409 match self {
410 IntLiteral::Signed { val, size: _ } | IntLiteral::Unsized(val) => {
411 if val >= BigInt::zero() {
412 Some(val.to_biguint().unwrap())
413 } else {
414 None
415 }
416 }
417 IntLiteral::Unsigned { val, size: _ } => Some(val),
418 }
419 }
420
421 pub fn is_negative(&self) -> bool {
422 match self {
423 IntLiteral::Unsized(val) | IntLiteral::Signed { val, size: _ } => val.is_negative(),
424 IntLiteral::Unsigned { .. } => false,
425 }
426 }
427}
428
429impl Display for IntLiteral {
430 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
431 match self {
432 IntLiteral::Unsized(val) | IntLiteral::Signed { val, .. } => write!(f, "{}", val),
434 IntLiteral::Unsigned { val, .. } => write!(f, "{}", val),
435 }
436 }
437}
438
439#[derive(PartialEq, Debug, Clone)]
440pub struct Block {
441 pub statements: Vec<Loc<Statement>>,
442 pub result: Option<Loc<Expression>>,
443}
444
445#[derive(PartialEq, Debug, Clone)]
446pub struct Binding {
447 pub pattern: Loc<Pattern>,
448 pub ty: Option<Loc<TypeSpec>>,
449 pub value: Loc<Expression>,
450 pub attrs: AttributeList,
451}
452
453#[derive(PartialEq, Debug, Clone)]
454pub enum Statement {
455 Label(Loc<Identifier>),
456 Declaration(Vec<Loc<Identifier>>),
457 Binding(Binding),
458 Expression(Loc<Expression>),
459 PipelineRegMarker(Option<Loc<TypeExpression>>, Option<Loc<Expression>>),
460 Register(Loc<Register>),
461 Set {
464 target: Loc<Expression>,
465 value: Loc<Expression>,
466 },
467 Assert(Loc<Expression>),
468}
469
470impl Statement {
471 pub fn binding(
473 pattern: Loc<Pattern>,
474 ty: Option<Loc<TypeSpec>>,
475 value: Loc<Expression>,
476 ) -> Self {
477 Self::Binding(Binding {
478 pattern,
479 ty,
480 value,
481 attrs: AttributeList::empty(),
482 })
483 }
484}
485
486#[derive(PartialEq, Debug, Clone)]
488pub enum TypeParam {
489 TypeName {
490 name: Loc<Identifier>,
491 traits: Vec<Loc<TraitSpec>>,
492 },
493 TypeWithMeta {
494 meta: Loc<Identifier>,
495 name: Loc<Identifier>,
496 },
497}
498impl TypeParam {
499 pub fn name(&self) -> &Loc<Identifier> {
500 match self {
501 TypeParam::TypeName { name, traits: _ } => name,
502 TypeParam::TypeWithMeta { meta: _, name } => name,
503 }
504 }
505}
506
507#[derive(PartialEq, Debug, Clone)]
508pub enum GenericBound {
509 IntegerConstraint(Loc<Path>, Loc<Expression>),
510 TypeConstraint(Loc<Path>, Vec<Loc<Identifier>>),
511}
512
513impl GenericBound {
514 pub fn path(&self) -> &Loc<Path> {
515 match self {
516 GenericBound::IntegerConstraint(path, _) => path,
517 GenericBound::TypeConstraint(path, _) => path,
518 }
519 }
520}
521
522#[derive(PartialEq, Debug, Clone)]
523pub enum Attribute {
524 Optimize {
525 passes: Vec<Loc<String>>,
526 },
527 NoMangle {
528 all: bool,
529 },
530 Fsm {
531 state: Option<Loc<Identifier>>,
532 },
533 WalTraceable {
534 suffix: Option<Loc<Identifier>>,
535 uses_clk: bool,
536 uses_rst: bool,
537 },
538 WalTrace {
539 clk: Option<Loc<Expression>>,
540 rst: Option<Loc<Expression>>,
541 },
542 WalSuffix {
544 suffix: Loc<Identifier>,
545 },
546 Documentation {
547 content: String,
548 },
549 SurferTranslator(String),
550}
551
552impl Attribute {
553 pub fn name(&self) -> &str {
554 match self {
555 Attribute::Optimize { passes: _ } => "optimize",
556 Attribute::NoMangle { .. } => "no_mangle",
557 Attribute::Fsm { state: _ } => "fsm",
558 Attribute::WalTraceable { .. } => "wal_traceable",
559 Attribute::WalTrace { .. } => "wal_trace",
560 Attribute::WalSuffix { .. } => "wal_suffix",
561 Attribute::Documentation { .. } => "doc",
562 Attribute::SurferTranslator(_) => "surfer_translator",
563 }
564 }
565}
566
567#[derive(PartialEq, Debug, Clone)]
568pub struct AttributeList(pub Vec<Loc<Attribute>>);
569impl AttributeList {
570 pub fn empty() -> Self {
571 Self(vec![])
572 }
573
574 pub fn from_vec(attrs: Vec<Loc<Attribute>>) -> Self {
575 Self(attrs)
576 }
577}
578
579#[derive(PartialEq, Debug, Clone)]
580pub struct ParameterList {
581 pub self_: Option<Loc<()>>,
582 pub args: Vec<(AttributeList, Loc<Identifier>, Loc<TypeSpec>)>,
583}
584
585impl ParameterList {
586 pub fn without_self(args: Vec<(AttributeList, Loc<Identifier>, Loc<TypeSpec>)>) -> Self {
587 Self { self_: None, args }
588 }
589
590 pub fn with_self(self_: Loc<()>, args: Vec<(Loc<Identifier>, Loc<TypeSpec>)>) -> Self {
591 Self {
592 self_: Some(self_),
593 args: args
594 .into_iter()
595 .map(|(n, t)| (AttributeList::empty(), n, t))
596 .collect(),
597 }
598 }
599}
600
601#[derive(PartialEq, Debug, Clone)]
602pub enum UnitKind {
603 Function,
604 Entity,
605 Pipeline(Loc<TypeExpression>),
606}
607
608impl UnitKind {
609 pub fn is_pipeline(&self) -> bool {
610 match self {
611 UnitKind::Function => false,
612 UnitKind::Entity => false,
613 UnitKind::Pipeline(_) => true,
614 }
615 }
616}
617
618impl std::fmt::Display for UnitKind {
619 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
620 match self {
621 UnitKind::Function => write!(f, "fn"),
622 UnitKind::Entity => write!(f, "entity"),
623 UnitKind::Pipeline(_) => write!(f, "pipeline"),
624 }
625 }
626}
627
628#[derive(PartialEq, Debug, Clone)]
629pub struct UnitHead {
630 pub unsafe_token: Option<Loc<()>>,
631 pub extern_token: Option<Loc<()>>,
632 pub attributes: AttributeList,
633 pub unit_kind: Loc<UnitKind>,
634 pub name: Loc<Identifier>,
635 pub inputs: Loc<ParameterList>,
636 pub output_type: Option<(Loc<()>, Loc<TypeSpec>)>,
637 pub type_params: Option<Loc<Vec<Loc<TypeParam>>>>,
638 pub where_clauses: Vec<WhereClause>,
639}
640
641#[derive(PartialEq, Debug, Clone)]
642pub struct Unit {
643 pub head: UnitHead,
644 pub body: Option<Loc<Expression>>,
647}
648
649#[derive(PartialEq, Debug, Clone)]
650pub struct Register {
651 pub pattern: Loc<Pattern>,
652 pub clock: Loc<Expression>,
653 pub reset: Option<(Loc<Expression>, Loc<Expression>)>,
654 pub initial: Option<Loc<Expression>>,
655 pub value: Loc<Expression>,
656 pub value_type: Option<Loc<TypeSpec>>,
657 pub attributes: AttributeList,
658}
659
660#[derive(PartialEq, Debug, Clone)]
662pub struct TraitDef {
663 pub name: Loc<Identifier>,
664 pub type_params: Option<Loc<Vec<Loc<TypeParam>>>>,
665 pub where_clauses: Vec<WhereClause>,
666 pub methods: Vec<Loc<UnitHead>>,
667}
668
669#[derive(PartialEq, Debug, Clone)]
671pub struct TraitSpec {
672 pub path: Loc<Path>,
673 pub type_params: Option<Loc<Vec<Loc<TypeExpression>>>>,
674}
675
676#[derive(PartialEq, Debug, Clone)]
677pub struct ImplBlock {
678 pub r#trait: Option<Loc<TraitSpec>>,
679 pub type_params: Option<Loc<Vec<Loc<TypeParam>>>>,
680 pub where_clauses: Vec<WhereClause>,
681 pub target: Loc<TypeSpec>,
682 pub units: Vec<Loc<Unit>>,
683}
684
685#[derive(PartialEq, Debug, Clone)]
687pub struct Enum {
688 pub attributes: AttributeList,
689 pub name: Loc<Identifier>,
690 pub variants: Vec<EnumVariant>,
691}
692
693#[derive(PartialEq, Debug, Clone)]
694pub struct EnumVariant {
695 pub attributes: AttributeList,
696 pub name: Loc<Identifier>,
697 pub args: Option<Loc<ParameterList>>,
698}
699
700#[derive(PartialEq, Debug, Clone)]
701pub struct Struct {
702 pub attributes: AttributeList,
703 pub name: Loc<Identifier>,
704 pub members: Loc<ParameterList>,
705 pub port_keyword: Option<Loc<()>>,
706}
707
708impl Struct {
709 pub fn is_port(&self) -> bool {
710 self.port_keyword.is_some()
711 }
712}
713
714#[derive(PartialEq, Debug, Clone)]
715pub enum TypeDeclKind {
716 Enum(Loc<Enum>),
717 Struct(Loc<Struct>),
718}
719
720#[derive(PartialEq, Debug, Clone)]
722pub struct TypeDeclaration {
723 pub name: Loc<Identifier>,
724 pub kind: TypeDeclKind,
725 pub generic_args: Option<Loc<Vec<Loc<TypeParam>>>>,
726}
727
728#[derive(PartialEq, Debug, Clone)]
729pub struct UseStatement {
730 pub path: Loc<Path>,
731 pub alias: Option<Loc<Identifier>>,
732}
733
734#[derive(PartialEq, Debug, Clone)]
737pub enum Item {
738 Unit(Loc<Unit>),
739 TraitDef(Loc<TraitDef>),
740 Type(Loc<TypeDeclaration>),
741 ExternalMod(Loc<Identifier>),
742 Module(Loc<Module>),
743 Use(Loc<UseStatement>),
744 ImplBlock(Loc<ImplBlock>),
745}
746
747impl Item {
748 pub fn name(&self) -> Option<&Identifier> {
749 match self {
750 Item::Unit(u) => Some(&u.head.name.inner),
751 Item::TraitDef(t) => Some(&t.name.inner),
752 Item::Type(t) => Some(&t.name.inner),
753 Item::Module(m) => Some(&m.name.inner),
754 Item::ExternalMod(name) => Some(name),
755 Item::Use(u) => u.alias.as_ref().map(|name| &name.inner),
756 Item::ImplBlock(_) => None,
757 }
758 }
759
760 pub fn variant_str(&self) -> &'static str {
761 match self {
762 Item::Unit(_) => "unit",
763 Item::TraitDef(_) => "trait definition",
764 Item::Type(_) => "type",
765 Item::Module(_) => "module",
766 Item::ExternalMod(_) => "module",
767 Item::Use(_) => "use",
768 Item::ImplBlock(_) => "impl",
769 }
770 }
771}
772
773#[derive(PartialEq, Debug, Clone)]
774pub struct Module {
775 pub name: Loc<Identifier>,
776 pub body: Loc<ModuleBody>,
777}
778
779#[derive(PartialEq, Debug, Clone)]
780pub struct ModuleBody {
781 pub members: Vec<Item>,
782 pub documentation: Vec<String>,
783}