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, Literal, Span, StructFieldDefinition, StructKind,
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, Copy, PartialEq, Eq, Hash)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22pub enum TypeAttribute {
23    Display,
24    ClosedDomain,
25    AnonStruct,
26}
27
28pub type Attributes = HashMap<TypeAttribute, ()>;
29
30#[derive(Debug, Clone)]
31pub enum DefinitionBody {
32    TypeAlias {
33        generics: Vec<Generic>,
34        annotation: Annotation,
35        methods: MethodSignatures,
36    },
37    Enum {
38        generics: Vec<Generic>,
39        variants: Vec<EnumVariant>,
40        methods: MethodSignatures,
41        attributes: Attributes,
42    },
43    Struct {
44        generics: Vec<Generic>,
45        fields: Vec<StructFieldDefinition>,
46        kind: StructKind,
47        methods: MethodSignatures,
48        constructor: Option<Type>,
49        attributes: Attributes,
50    },
51    Interface {
52        definition: Interface,
53    },
54    Value {
55        allowed_lints: Vec<String>,
56        go_hints: Vec<String>,
57        go_name: Option<String>,
58        /// The known literal value when this definition is a case-eligible
59        /// constant (usable as a Go `case` and as a const-pattern target).
60        /// `None` for variables, functions, and non-literal constants.
61        const_value: Option<Literal>,
62    },
63}
64
65impl Definition {
66    pub fn ty(&self) -> &Type {
67        &self.ty
68    }
69
70    pub fn visibility(&self) -> &Visibility {
71        &self.visibility
72    }
73
74    pub fn name_span(&self) -> Option<Span> {
75        self.name_span
76    }
77
78    pub fn doc(&self) -> Option<&String> {
79        self.doc.as_ref()
80    }
81
82    /// A newtype is a single-field, non-generic tuple struct. Relevant
83    /// because Go compiles newtypes to named scalar types, so `.0` is a cast
84    /// rather than a field access — it cannot be assigned to, and taking
85    /// its address is invalid.
86    pub fn is_newtype(&self) -> bool {
87        matches!(
88            &self.body,
89            DefinitionBody::Struct {
90                kind: StructKind::Tuple,
91                fields,
92                generics,
93                ..
94            } if fields.len() == 1 && generics.is_empty()
95        )
96    }
97
98    pub fn is_pointer_backed_newtype<F>(&self, is_alias: F) -> bool
99    where
100        F: Fn(&str) -> bool,
101    {
102        self.is_newtype()
103            && matches!(
104                &self.body,
105                DefinitionBody::Struct { fields, .. }
106                    if crate::types::peel_alias(&fields[0].ty, is_alias).is_ref()
107            )
108    }
109
110    pub fn allowed_lints(&self) -> &[String] {
111        match &self.body {
112            DefinitionBody::Value { allowed_lints, .. } => allowed_lints,
113            _ => &[],
114        }
115    }
116
117    pub fn go_hints(&self) -> &[String] {
118        match &self.body {
119            DefinitionBody::Value { go_hints, .. } => go_hints,
120            _ => &[],
121        }
122    }
123
124    pub fn go_name(&self) -> Option<&str> {
125        match &self.body {
126            DefinitionBody::Value { go_name, .. } => go_name.as_deref(),
127            _ => None,
128        }
129    }
130
131    pub fn const_value(&self) -> Option<&Literal> {
132        match &self.body {
133            DefinitionBody::Value { const_value, .. } => const_value.as_ref(),
134            _ => None,
135        }
136    }
137
138    pub fn methods_mut(&mut self) -> Option<&mut MethodSignatures> {
139        match &mut self.body {
140            DefinitionBody::Struct { methods, .. } => Some(methods),
141            DefinitionBody::TypeAlias { methods, .. } => Some(methods),
142            DefinitionBody::Enum { methods, .. } => Some(methods),
143            _ => None,
144        }
145    }
146
147    pub fn attributes(&self) -> Option<&Attributes> {
148        match &self.body {
149            DefinitionBody::Struct { attributes, .. } | DefinitionBody::Enum { attributes, .. } => {
150                Some(attributes)
151            }
152            _ => None,
153        }
154    }
155
156    pub fn is_display(&self) -> bool {
157        self.attributes()
158            .is_some_and(|a| a.contains_key(&TypeAttribute::Display))
159    }
160
161    pub fn is_closed_domain(&self) -> bool {
162        self.attributes()
163            .is_some_and(|a| a.contains_key(&TypeAttribute::ClosedDomain))
164    }
165
166    pub fn is_anon_struct(&self) -> bool {
167        self.attributes()
168            .is_some_and(|a| a.contains_key(&TypeAttribute::AnonStruct))
169    }
170
171    pub fn is_type_definition(&self) -> bool {
172        matches!(
173            self.body,
174            DefinitionBody::Struct { .. }
175                | DefinitionBody::Enum { .. }
176                | DefinitionBody::TypeAlias { .. }
177        )
178    }
179
180    pub fn is_type_alias(&self) -> bool {
181        matches!(self.body, DefinitionBody::TypeAlias { .. })
182    }
183
184    pub fn is_value(&self, qualified_name: &str) -> bool {
185        matches!(self.body, DefinitionBody::Value { .. })
186            && self.ty.unwrap_forall().get_qualified_id() != Some(qualified_name)
187    }
188}
189
190pub type MethodSignatures = HashMap<EcoString, Type>;
191
192#[derive(Debug, Clone, PartialEq)]
193pub enum Visibility {
194    Public,
195    Private,
196    Local,
197}
198
199impl Visibility {
200    pub fn is_public(&self) -> bool {
201        matches!(self, Visibility::Public)
202    }
203}
204
205#[derive(Debug, Clone, PartialEq)]
206pub struct Interface {
207    pub name: EcoString,
208    pub generics: Vec<Generic>,
209    pub parents: Vec<Type>,
210    pub methods: HashMap<EcoString, Type>,
211}