Skip to main content

lisette_syntax/program/
definition.rs

1use rustc_hash::FxHashMap as HashMap;
2
3use ecow::EcoString;
4
5use crate::ast::{
6    Annotation, EnumVariant, Generic, Span, StructFieldDefinition, StructKind, ValueEnumVariant,
7};
8use crate::types::Type;
9
10#[derive(Debug, Clone)]
11pub struct Definition {
12    pub visibility: Visibility,
13    pub ty: Type,
14    pub name: Option<EcoString>,
15    pub name_span: Option<Span>,
16    pub doc: Option<String>,
17    pub body: DefinitionBody,
18}
19
20#[derive(Debug, Clone)]
21pub enum DefinitionBody {
22    TypeAlias {
23        generics: Vec<Generic>,
24        annotation: Annotation,
25        methods: MethodSignatures,
26    },
27    Enum {
28        generics: Vec<Generic>,
29        variants: Vec<EnumVariant>,
30        methods: MethodSignatures,
31        displayable: bool,
32    },
33    ValueEnum {
34        variants: Vec<ValueEnumVariant>,
35        underlying_ty: Option<Type>,
36        methods: MethodSignatures,
37    },
38    Struct {
39        generics: Vec<Generic>,
40        fields: Vec<StructFieldDefinition>,
41        kind: StructKind,
42        methods: MethodSignatures,
43        constructor: Option<Type>,
44        displayable: bool,
45    },
46    Interface {
47        definition: Interface,
48    },
49    Value {
50        allowed_lints: Vec<String>,
51        go_hints: Vec<String>,
52        go_name: Option<String>,
53    },
54}
55
56impl Definition {
57    pub fn ty(&self) -> &Type {
58        &self.ty
59    }
60
61    pub fn visibility(&self) -> &Visibility {
62        &self.visibility
63    }
64
65    pub fn name_span(&self) -> Option<Span> {
66        self.name_span
67    }
68
69    pub fn doc(&self) -> Option<&String> {
70        self.doc.as_ref()
71    }
72
73    /// A newtype is a single-field, non-generic tuple struct. Relevant
74    /// because Go compiles newtypes to named scalar types, so `.0` is a cast
75    /// rather than a field access — it cannot be assigned to, and taking
76    /// its address is invalid.
77    pub fn is_newtype(&self) -> bool {
78        matches!(
79            &self.body,
80            DefinitionBody::Struct {
81                kind: StructKind::Tuple,
82                fields,
83                generics,
84                ..
85            } if fields.len() == 1 && generics.is_empty()
86        )
87    }
88
89    pub fn is_pointer_backed_newtype<F>(&self, is_alias: F) -> bool
90    where
91        F: Fn(&str) -> bool,
92    {
93        self.is_newtype()
94            && matches!(
95                &self.body,
96                DefinitionBody::Struct { fields, .. }
97                    if crate::types::peel_alias(&fields[0].ty, is_alias).is_ref()
98            )
99    }
100
101    pub fn allowed_lints(&self) -> &[String] {
102        match &self.body {
103            DefinitionBody::Value { allowed_lints, .. } => allowed_lints,
104            _ => &[],
105        }
106    }
107
108    pub fn go_hints(&self) -> &[String] {
109        match &self.body {
110            DefinitionBody::Value { go_hints, .. } => go_hints,
111            _ => &[],
112        }
113    }
114
115    pub fn go_name(&self) -> Option<&str> {
116        match &self.body {
117            DefinitionBody::Value { go_name, .. } => go_name.as_deref(),
118            _ => None,
119        }
120    }
121
122    pub fn methods_mut(&mut self) -> Option<&mut MethodSignatures> {
123        match &mut self.body {
124            DefinitionBody::Struct { methods, .. } => Some(methods),
125            DefinitionBody::TypeAlias { methods, .. } => Some(methods),
126            DefinitionBody::Enum { methods, .. } => Some(methods),
127            DefinitionBody::ValueEnum { methods, .. } => Some(methods),
128            _ => None,
129        }
130    }
131
132    pub fn is_displayable(&self) -> bool {
133        matches!(
134            &self.body,
135            DefinitionBody::Struct {
136                displayable: true,
137                ..
138            } | DefinitionBody::Enum {
139                displayable: true,
140                ..
141            }
142        )
143    }
144
145    pub fn is_type_definition(&self) -> bool {
146        matches!(
147            self.body,
148            DefinitionBody::Struct { .. }
149                | DefinitionBody::Enum { .. }
150                | DefinitionBody::ValueEnum { .. }
151                | DefinitionBody::TypeAlias { .. }
152        )
153    }
154
155    pub fn is_type_alias(&self) -> bool {
156        matches!(self.body, DefinitionBody::TypeAlias { .. })
157    }
158}
159
160pub type MethodSignatures = HashMap<EcoString, Type>;
161
162#[derive(Debug, Clone, PartialEq)]
163pub enum Visibility {
164    Public,
165    Private,
166    Local,
167}
168
169impl Visibility {
170    pub fn is_public(&self) -> bool {
171        matches!(self, Visibility::Public)
172    }
173}
174
175#[derive(Debug, Clone, PartialEq)]
176pub struct Interface {
177    pub name: EcoString,
178    pub generics: Vec<Generic>,
179    pub parents: Vec<Type>,
180    pub methods: HashMap<EcoString, Type>,
181}