1use super::{Ast, AstAlloc, TermPos};
3pub use crate::typ::{EnumRowF, EnumRowsF, RecordRowF, RecordRowsF, TypeF};
4use crate::{identifier::Ident, impl_display_from_bytecode_pretty, traverse::*};
5use iter::*;
6
7pub type TypeUnr<'ast> = TypeF<&'ast Type<'ast>, RecordRows<'ast>, EnumRows<'ast>, &'ast Ast<'ast>>;
10
11pub type EnumRowsUnr<'ast> = EnumRowsF<&'ast Type<'ast>, &'ast EnumRows<'ast>>;
13
14pub type RecordRowsUnr<'ast> = RecordRowsF<&'ast Type<'ast>, &'ast RecordRows<'ast>>;
16
17pub type EnumRow<'ast> = EnumRowF<&'ast Type<'ast>>;
19#[derive(Clone, PartialEq, Eq, Debug)]
21pub struct EnumRows<'ast>(pub EnumRowsUnr<'ast>);
22pub type RecordRow<'ast> = RecordRowF<&'ast Type<'ast>>;
24#[derive(Clone, PartialEq, Eq, Debug)]
25pub struct RecordRows<'ast>(pub RecordRowsUnr<'ast>);
27
28#[derive(Clone, PartialEq, Eq, Debug)]
30pub struct Type<'ast> {
31 pub typ: TypeUnr<'ast>,
32 pub pos: TermPos,
33}
34
35impl<'ast> From<TypeUnr<'ast>> for Type<'ast> {
36 fn from(typ: TypeUnr<'ast>) -> Self {
37 Type {
38 typ,
39 pos: TermPos::None,
40 }
41 }
42}
43
44impl<'ast> Type<'ast> {
45 pub fn with_pos(self, pos: TermPos) -> Type<'ast> {
47 Type { pos, ..self }
48 }
49
50 pub fn find_contract(&'ast self) -> Option<&'ast Ast<'ast>> {
52 self.find_map(|ty: &'ast Type| match &ty.typ {
53 TypeF::Contract(f) => Some(*f),
54 _ => None,
55 })
56 }
57}
58
59impl<'ast> TypeUnr<'ast> {
60 pub fn spanned(self, pos: TermPos) -> Type<'ast> {
61 Type { typ: self, pos }
62 }
63}
64
65impl<'ast> TraverseAlloc<'ast, Type<'ast>> for Type<'ast> {
66 fn traverse<F, E>(
67 self,
68 alloc: &'ast AstAlloc,
69 f: &mut F,
70 order: TraverseOrder,
71 ) -> Result<Self, E>
72 where
73 F: FnMut(Type<'ast>) -> Result<Type<'ast>, E>,
74 {
75 let pre_map = match order {
76 TraverseOrder::TopDown => f(self)?,
77 TraverseOrder::BottomUp => self,
78 };
79
80 let typ = pre_map.typ.try_map_state(
84 |ty, f| Ok(alloc.alloc(ty.clone().traverse(alloc, f, order)?)),
85 |rrows, f| rrows.traverse(alloc, f, order),
86 |erows, _| Ok(erows),
87 |ctr, _| Ok(ctr),
88 f,
89 )?;
90
91 let post_map = Type { typ, ..pre_map };
92
93 match order {
94 TraverseOrder::TopDown => Ok(post_map),
95 TraverseOrder::BottomUp => f(post_map),
96 }
97 }
98
99 fn traverse_ref<S, U>(
100 &'ast self,
101 f: &mut dyn FnMut(&'ast Type<'ast>, &S) -> TraverseControl<S, U>,
102 state: &S,
103 ) -> Option<U> {
104 let child_state = match f(self, state) {
105 TraverseControl::Continue => None,
106 TraverseControl::ContinueWithScope(s) => Some(s),
107 TraverseControl::SkipBranch => {
108 return None;
109 }
110 TraverseControl::Return(ret) => {
111 return Some(ret);
112 }
113 };
114 let state = child_state.as_ref().unwrap_or(state);
115
116 match &self.typ {
117 TypeF::Dyn
118 | TypeF::Number
119 | TypeF::Bool
120 | TypeF::String
121 | TypeF::ForeignId
122 | TypeF::Symbol
123 | TypeF::Var(_)
124 | TypeF::Enum(_)
125 | TypeF::Wildcard(_) => None,
126 TypeF::Contract(ast) => ast.traverse_ref(f, state),
127 TypeF::Arrow(t1, t2) => t1
128 .traverse_ref(f, state)
129 .or_else(|| t2.traverse_ref(f, state)),
130 TypeF::Forall { body: t, .. }
131 | TypeF::Dict { type_fields: t, .. }
132 | TypeF::Array(t) => t.traverse_ref(f, state),
133 TypeF::Record(rrows) => rrows.traverse_ref(f, state),
134 }
135 }
136}
137
138impl<'ast> TraverseAlloc<'ast, Ast<'ast>> for Type<'ast> {
139 fn traverse<F, E>(
140 self,
141 alloc: &'ast AstAlloc,
142 f: &mut F,
143 order: TraverseOrder,
144 ) -> Result<Self, E>
145 where
146 F: FnMut(Ast<'ast>) -> Result<Ast<'ast>, E>,
147 {
148 self.traverse(
149 alloc,
150 &mut |ty: Type| match ty.typ {
151 TypeF::Contract(t) => t
152 .clone()
153 .traverse(alloc, f, order)
154 .map(|t| Type::from(TypeF::Contract(alloc.alloc(t))).with_pos(ty.pos)),
155 _ => Ok(ty),
156 },
157 order,
158 )
159 }
160
161 fn traverse_ref<S, U>(
162 &'ast self,
163 f: &mut dyn FnMut(&'ast Ast<'ast>, &S) -> TraverseControl<S, U>,
164 state: &S,
165 ) -> Option<U> {
166 self.traverse_ref(
167 &mut |ty: &'ast Type, s: &S| match &ty.typ {
168 TypeF::Contract(t) => {
169 if let Some(ret) = t.traverse_ref(f, s) {
170 TraverseControl::Return(ret)
171 } else {
172 TraverseControl::SkipBranch
173 }
174 }
175 _ => TraverseControl::Continue,
176 },
177 state,
178 )
179 }
180}
181
182impl<'ast> TraverseAlloc<'ast, Type<'ast>> for RecordRows<'ast> {
183 fn traverse<F, E>(
184 self,
185 alloc: &'ast AstAlloc,
186 f: &mut F,
187 order: TraverseOrder,
188 ) -> Result<RecordRows<'ast>, E>
189 where
190 F: FnMut(Type<'ast>) -> Result<Type<'ast>, E>,
191 {
192 let rows = self.0.try_map_state(
196 |ty, f| Ok(alloc.alloc(ty.clone().traverse(alloc, f, order)?)),
197 |rrows, f| Ok(alloc.alloc(rrows.clone().traverse(alloc, f, order)?)),
198 f,
199 )?;
200
201 Ok(RecordRows(rows))
202 }
203
204 fn traverse_ref<S, U>(
205 &'ast self,
206 f: &mut dyn FnMut(&'ast Type<'ast>, &S) -> TraverseControl<S, U>,
207 state: &S,
208 ) -> Option<U> {
209 match &self.0 {
210 RecordRowsF::Extend { row, tail } => row
211 .typ
212 .traverse_ref(f, state)
213 .or_else(|| tail.traverse_ref(f, state)),
214 _ => None,
215 }
216 }
217}
218
219impl<'ast> RecordRows<'ast> {
220 pub fn find_path<'a>(&'a self, path: &[Ident]) -> Option<&'a RecordRow<'ast>> {
229 let mut curr_rrows = self;
230
231 for (idx, id) in path.iter().enumerate() {
232 let next_rrows = curr_rrows.iter().find_map(|item| match item {
233 RecordRowsItem::Row(row) if row.id.ident() == *id => Some(row),
234 _ => None,
235 });
236
237 if idx == path.len() - 1 {
238 return next_rrows;
239 }
240
241 match next_rrows.map(|row| &row.typ.typ) {
242 Some(TypeF::Record(rrows)) => curr_rrows = rrows,
243 _ => return None,
244 }
245 }
246
247 None
248 }
249
250 pub fn find_row(&self, id: Ident) -> Option<&RecordRow<'ast>> {
255 self.find_path(&[id])
256 }
257
258 pub fn iter(&self) -> RecordRowsIter<'_, Type<'ast>, RecordRows<'ast>> {
259 RecordRowsIter {
260 rrows: Some(self),
261 ty: std::marker::PhantomData,
262 }
263 }
264}
265
266impl<'ast> EnumRows<'ast> {
267 pub fn find_row<'a>(&'a self, id: Ident) -> Option<&'a EnumRow<'ast>> {
270 self.iter().find_map(|row_item| match row_item {
271 EnumRowsItem::Row(row) if row.id.ident() == id => Some(row),
272 _ => None,
273 })
274 }
275
276 pub fn iter(&self) -> EnumRowsIter<'_, Type<'ast>, EnumRows<'ast>> {
277 EnumRowsIter {
278 erows: Some(self),
279 ty: std::marker::PhantomData,
280 }
281 }
282}
283
284impl_display_from_bytecode_pretty!(Type<'_>);
285impl_display_from_bytecode_pretty!(EnumRow<'_>);
286impl_display_from_bytecode_pretty!(EnumRows<'_>);
287impl_display_from_bytecode_pretty!(RecordRow<'_>);
288impl_display_from_bytecode_pretty!(RecordRows<'_>);
289
290pub mod iter {
291 use super::*;
292 use crate::identifier::LocIdent;
293
294 pub struct RecordRowsIter<'a, Ty, RRows> {
296 pub(crate) rrows: Option<&'a RRows>,
297 pub(crate) ty: std::marker::PhantomData<Ty>,
298 }
299
300 pub enum RecordRowsItem<'a, Ty> {
302 TailDyn,
303 TailVar(&'a LocIdent),
304 Row(&'a RecordRowF<Ty>),
305 }
306
307 impl<'a, 'ast> Iterator for RecordRowsIter<'a, Type<'ast>, RecordRows<'ast>> {
308 type Item = RecordRowsItem<'a, &'ast Type<'ast>>;
309
310 fn next(&mut self) -> Option<Self::Item> {
311 self.rrows.and_then(|next| match next.0 {
312 RecordRowsF::Empty => {
313 self.rrows = None;
314 None
315 }
316 RecordRowsF::TailDyn => {
317 self.rrows = None;
318 Some(RecordRowsItem::TailDyn)
319 }
320 RecordRowsF::TailVar(ref id) => {
321 self.rrows = None;
322 Some(RecordRowsItem::TailVar(id))
323 }
324 RecordRowsF::Extend { ref row, tail } => {
325 self.rrows = Some(tail);
326 Some(RecordRowsItem::Row(row))
327 }
328 })
329 }
330 }
331
332 pub struct EnumRowsIter<'a, Ty, ERows> {
333 pub(crate) erows: Option<&'a ERows>,
334 pub(crate) ty: std::marker::PhantomData<Ty>,
335 }
336
337 pub enum EnumRowsItem<'a, Ty> {
338 TailVar(&'a LocIdent),
339 Row(&'a EnumRowF<Ty>),
340 }
341
342 impl<'a, 'ast> Iterator for EnumRowsIter<'a, Type<'ast>, EnumRows<'ast>> {
343 type Item = EnumRowsItem<'a, &'ast Type<'ast>>;
344
345 fn next(&mut self) -> Option<Self::Item> {
346 self.erows.and_then(|next| match next.0 {
347 EnumRowsF::Empty => {
348 self.erows = None;
349 None
350 }
351 EnumRowsF::TailVar(ref id) => {
352 self.erows = None;
353 Some(EnumRowsItem::TailVar(id))
354 }
355 EnumRowsF::Extend { ref row, tail } => {
356 self.erows = Some(tail);
357 Some(EnumRowsItem::Row(row))
358 }
359 })
360 }
361 }
362}