Skip to main content

rib/parser/
type_name.rs

1use crate::parser::errors::RibParseError;
2use crate::rib_source_span::GetSourcePosition;
3use crate::wit_type::{TypeResult, WitType};
4use crate::{InferredNumber, InferredType, TypeInternal};
5use combine::parser::char;
6use combine::parser::char::{char, spaces, string};
7use combine::{attempt, between, choice, optional, sep_by, Parser};
8use combine::{parser, ParseError};
9use std::fmt::Display;
10use std::ops::Deref;
11
12// Rib grammar uses it's own `TypeName` instead of relying from any other crates to annotate types (Example: 1: u32, let x: u32 = 1;),
13// and sticks on to the  Display instance that aligns with what we see in WIT.
14// Usage of TypeName, InferredType and WitType:
15// The Rib compiler uses `InferredType` - the output of type inference. The `TypeName` used in type annotations may help with this type inference.
16// The Rib-IR which is close to running Rib code uses `WitType`, that there won't be either `TypeName` or `InferredType` in the Rib-IR.
17// Any compilation or interpreter error messages will also be using `TypeName` to show the type of the expression
18// for which we convert WitType or InferredType back to TypeName. If `InferredType` cannot be converted to `TypeName`, we explain the error displaying
19// the original expression, and there is no point displaying `InferredType` to the user.
20#[derive(Debug, Hash, Clone, Eq, PartialEq, Ord, PartialOrd)]
21pub enum TypeName {
22    Bool,
23    S8,
24    U8,
25    S16,
26    U16,
27    S32,
28    U32,
29    S64,
30    U64,
31    F32,
32    F64,
33    Chr,
34    Str,
35    List(Box<TypeName>),
36    Tuple(Vec<TypeName>),
37    Option(Box<TypeName>),
38    Result {
39        ok: Option<Box<TypeName>>,
40        error: Option<Box<TypeName>>,
41    },
42    Record(Vec<(String, Box<TypeName>)>),
43    Flags(Vec<String>),
44    Enum(Vec<String>),
45    Variant {
46        cases: Vec<(String, Option<Box<TypeName>>)>,
47    },
48}
49
50impl Display for TypeName {
51    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52        match self {
53            TypeName::Bool => write!(f, "bool"),
54            TypeName::S8 => write!(f, "s8"),
55            TypeName::U8 => write!(f, "u8"),
56            TypeName::S16 => write!(f, "s16"),
57            TypeName::U16 => write!(f, "u16"),
58            TypeName::S32 => write!(f, "s32"),
59            TypeName::U32 => write!(f, "u32"),
60            TypeName::S64 => write!(f, "s64"),
61            TypeName::U64 => write!(f, "u64"),
62            TypeName::F32 => write!(f, "f32"),
63            TypeName::F64 => write!(f, "f64"),
64            TypeName::Chr => write!(f, "char"),
65            TypeName::Str => write!(f, "string"),
66            TypeName::List(inner_type) => write!(f, "list<{inner_type}>"),
67            TypeName::Tuple(inner_types) => {
68                write!(f, "tuple<")?;
69                for (i, inner_type) in inner_types.iter().enumerate() {
70                    if i > 0 {
71                        write!(f, ", ")?;
72                    }
73                    write!(f, "{inner_type}")?;
74                }
75                write!(f, ">")
76            }
77            TypeName::Option(inner_type) => write!(f, "option<{inner_type}>"),
78            // https://component-model.bytecodealliance.org/design/wit.html#results
79            TypeName::Result { ok, error } => match (ok, error) {
80                (Some(ok), Some(error)) => {
81                    write!(f, "result<{ok}, {error}>")
82                }
83                (Some(ok), None) => {
84                    write!(f, "result<{ok}>")
85                }
86                (None, Some(error)) => {
87                    write!(f, "result<_, {error}>")
88                }
89                (None, None) => {
90                    write!(f, "result")
91                }
92            },
93            TypeName::Record(fields) => {
94                write!(f, "record {{ ")?;
95                for (i, (field, typ)) in fields.iter().enumerate() {
96                    if i > 0 {
97                        write!(f, ", ")?;
98                    }
99                    write!(f, "{field}: {typ}")?;
100                }
101                write!(f, " }}")
102            }
103            TypeName::Flags(flags) => {
104                write!(f, "flags<")?;
105                for (i, flag) in flags.iter().enumerate() {
106                    if i > 0 {
107                        write!(f, ", ")?;
108                    }
109                    write!(f, "{flag}")?;
110                }
111                write!(f, ">")
112            }
113            TypeName::Enum(cases) => {
114                write!(f, "enum {{ ")?;
115                for (i, case) in cases.iter().enumerate() {
116                    if i > 0 {
117                        write!(f, ", ")?;
118                    }
119                    write!(f, "{case}")?;
120                }
121                write!(f, " }}")
122            }
123            TypeName::Variant { cases } => {
124                write!(f, "variant {{")?;
125                for (i, (case, typ)) in cases.iter().enumerate() {
126                    if i > 0 {
127                        write!(f, ", ")?;
128                    }
129                    write!(f, "{case}")?;
130                    if let Some(typ) = typ {
131                        write!(f, "({typ})")?;
132                    }
133                }
134                write!(f, " }}")
135            }
136        }
137    }
138}
139
140impl From<&InferredNumber> for TypeName {
141    fn from(value: &InferredNumber) -> Self {
142        match value {
143            InferredNumber::S8 => TypeName::S8,
144            InferredNumber::U8 => TypeName::U8,
145            InferredNumber::S16 => TypeName::S16,
146            InferredNumber::U16 => TypeName::U16,
147            InferredNumber::S32 => TypeName::S32,
148            InferredNumber::U32 => TypeName::U32,
149            InferredNumber::S64 => TypeName::S64,
150            InferredNumber::U64 => TypeName::U64,
151            InferredNumber::F32 => TypeName::F32,
152            InferredNumber::F64 => TypeName::F64,
153        }
154    }
155}
156
157impl TryFrom<WitType> for TypeName {
158    type Error = String;
159    fn try_from(analysed_type: WitType) -> Result<Self, Self::Error> {
160        match analysed_type {
161            WitType::Bool(_) => Ok(TypeName::Bool),
162            WitType::S8(_) => Ok(TypeName::S8),
163            WitType::U8(_) => Ok(TypeName::U8),
164            WitType::S16(_) => Ok(TypeName::S16),
165            WitType::U16(_) => Ok(TypeName::U16),
166            WitType::S32(_) => Ok(TypeName::S32),
167            WitType::U32(_) => Ok(TypeName::U32),
168            WitType::S64(_) => Ok(TypeName::S64),
169            WitType::U64(_) => Ok(TypeName::U64),
170            WitType::F32(_) => Ok(TypeName::F32),
171            WitType::F64(_) => Ok(TypeName::F64),
172            WitType::Chr(_) => Ok(TypeName::Chr),
173            WitType::Str(_) => Ok(TypeName::Str),
174            WitType::List(inner_type) => Ok(TypeName::List(Box::new(
175                inner_type.inner.deref().clone().try_into()?,
176            ))),
177            WitType::Tuple(inner_type) => Ok(TypeName::Tuple(
178                inner_type
179                    .items
180                    .into_iter()
181                    .map(|x| x.try_into())
182                    .collect::<Result<_, _>>()?,
183            )),
184            WitType::Option(type_option) => Ok(TypeName::Option(Box::new(
185                type_option.inner.deref().clone().try_into()?,
186            ))),
187            WitType::Result(TypeResult { ok, err, .. }) => match (ok, err) {
188                (Some(ok), Some(err)) => Ok(TypeName::Result {
189                    ok: Some(Box::new(ok.deref().clone().try_into()?)),
190                    error: Some(Box::new(err.deref().clone().try_into()?)),
191                }),
192                (Some(ok), None) => Ok(TypeName::Result {
193                    ok: Some(Box::new(ok.deref().clone().try_into()?)),
194                    error: None,
195                }),
196                (None, Some(err)) => Ok(TypeName::Result {
197                    ok: None,
198                    error: Some(Box::new(err.deref().clone().try_into()?)),
199                }),
200                (None, None) => Ok(TypeName::Result {
201                    ok: None,
202                    error: None,
203                }),
204            },
205            WitType::Record(type_record) => {
206                let mut fields = vec![];
207                for field in type_record.fields {
208                    let name = field.name.clone();
209                    let typ = field.typ.clone();
210                    let type_name = typ.try_into()?;
211                    fields.push((name, Box::new(type_name)));
212                }
213
214                Ok(TypeName::Record(fields))
215            }
216            WitType::Flags(flags) => Ok(TypeName::Flags(flags.names)),
217            WitType::Enum(cases) => Ok(TypeName::Enum(cases.cases)),
218            WitType::Variant(cases) => {
219                let mut variant_cases = vec![];
220                for case in cases.cases {
221                    let name = case.name.clone();
222                    let typ = case.typ.clone();
223                    match typ {
224                        Some(typ) => {
225                            let type_name = typ.try_into()?;
226                            variant_cases.push((name, Some(Box::new(type_name))));
227                        }
228                        None => {
229                            variant_cases.push((name, None));
230                        }
231                    }
232                }
233                Ok(TypeName::Variant {
234                    cases: variant_cases,
235                })
236            }
237            WitType::Handle(type_handle) => {
238                Err(format!("Handle type not supported: {type_handle:?}"))
239            }
240        }
241    }
242}
243
244impl From<&TypeName> for InferredType {
245    fn from(type_name: &TypeName) -> Self {
246        match type_name {
247            TypeName::Bool => InferredType::bool(),
248            TypeName::S8 => InferredType::s8(),
249            TypeName::U8 => InferredType::u8(),
250            TypeName::S16 => InferredType::s16(),
251            TypeName::U16 => InferredType::u16(),
252            TypeName::S32 => InferredType::s32(),
253            TypeName::U32 => InferredType::u32(),
254            TypeName::S64 => InferredType::s64(),
255            TypeName::U64 => InferredType::u64(),
256            TypeName::F32 => InferredType::f32(),
257            TypeName::F64 => InferredType::f64(),
258            TypeName::Chr => InferredType::char(),
259            TypeName::Str => InferredType::string(),
260            TypeName::List(inner_type) => InferredType::list(inner_type.deref().into()),
261            TypeName::Tuple(inner_types) => {
262                InferredType::tuple(inner_types.iter().map(|t| t.into()).collect())
263            }
264            TypeName::Option(type_name) => InferredType::option(type_name.deref().into()),
265            TypeName::Result { ok, error } => InferredType::result(
266                ok.as_deref().map(|x| x.into()),
267                error.as_deref().map(|x| x.into()),
268            ),
269            TypeName::Record(fields) => InferredType::record(
270                fields
271                    .iter()
272                    .map(|(field, typ)| (field.clone(), typ.deref().into()))
273                    .collect(),
274            ),
275            TypeName::Flags(flags) => InferredType::flags(flags.clone()),
276            TypeName::Enum(cases) => InferredType::enum_(cases.clone()),
277            TypeName::Variant { cases } => InferredType::from_variant_cases(
278                cases
279                    .iter()
280                    .map(|(case_name, typ)| (case_name.clone(), typ.as_deref().map(|x| x.into())))
281                    .collect(),
282            ),
283        }
284    }
285}
286
287impl TryFrom<InferredType> for TypeName {
288    type Error = String;
289
290    fn try_from(value: InferredType) -> Result<Self, Self::Error> {
291        match value.inner.deref() {
292            TypeInternal::Bool => Ok(TypeName::Bool),
293            TypeInternal::S8 => Ok(TypeName::S8),
294            TypeInternal::U8 => Ok(TypeName::U8),
295            TypeInternal::S16 => Ok(TypeName::S16),
296            TypeInternal::U16 => Ok(TypeName::U16),
297            TypeInternal::S32 => Ok(TypeName::S32),
298            TypeInternal::U32 => Ok(TypeName::U32),
299            TypeInternal::S64 => Ok(TypeName::S64),
300            TypeInternal::U64 => Ok(TypeName::U64),
301            TypeInternal::F32 => Ok(TypeName::F32),
302            TypeInternal::F64 => Ok(TypeName::F64),
303            TypeInternal::Chr => Ok(TypeName::Chr),
304            TypeInternal::Str => Ok(TypeName::Str),
305            TypeInternal::List(inferred_type) => {
306                let verified = inferred_type.clone().try_into()?;
307                Ok(TypeName::List(Box::new(verified)))
308            }
309            TypeInternal::Tuple(inferred_types) => {
310                let mut verified_types = vec![];
311                for typ in inferred_types {
312                    let verified = typ.clone().try_into()?;
313                    verified_types.push(verified);
314                }
315                Ok(TypeName::Tuple(verified_types))
316            }
317            TypeInternal::Record(name_and_types) => {
318                let mut fields = vec![];
319                for (field, typ) in name_and_types {
320                    fields.push((field.clone(), Box::new(typ.clone().try_into()?)));
321                }
322                Ok(TypeName::Record(fields))
323            }
324            TypeInternal::Flags(flags) => Ok(TypeName::Flags(flags.clone())),
325            TypeInternal::Enum(enums) => Ok(TypeName::Enum(enums.clone())),
326            TypeInternal::Option(inferred_type) => {
327                let result = inferred_type.clone().try_into()?;
328                Ok(TypeName::Option(Box::new(result)))
329            }
330            TypeInternal::Result { ok, error } => {
331                let ok_unified = ok.as_ref().map(|ok| ok.clone().try_into()).transpose()?;
332                let err_unified = error
333                    .as_ref()
334                    .map(|err| err.clone().try_into())
335                    .transpose()?;
336                Ok(TypeName::Result {
337                    ok: ok_unified.map(Box::new),
338                    error: err_unified.map(Box::new),
339                })
340            }
341            TypeInternal::Variant(variant) => {
342                let mut cases = vec![];
343                for (case, typ) in variant {
344                    let verified = typ.clone().map(TypeName::try_from).transpose()?;
345                    cases.push((case.clone(), verified.map(Box::new)));
346                }
347                Ok(TypeName::Variant { cases })
348            }
349            TypeInternal::Resource { .. } => {
350                Err("Cannot convert a resource type to a type name".to_string())
351            }
352            TypeInternal::AllOf(_) => {
353                Err("Cannot convert a all of type to a type name".to_string())
354            }
355            TypeInternal::Unknown => {
356                Err("Cannot convert an unknown type to a type name".to_string())
357            }
358            TypeInternal::Sequence(_) => {
359                Err("Cannot convert a sequence type to a type name".to_string())
360            }
361            TypeInternal::Instance { .. } => {
362                Err("Cannot convert an instance type to a type name".to_string())
363            }
364            TypeInternal::Range { .. } => {
365                Err("Cannot convert a range type to a type name".to_string())
366            }
367        }
368    }
369}
370
371pub fn parse_basic_type<Input>() -> impl Parser<Input, Output = TypeName>
372where
373    Input: combine::Stream<Token = char>,
374    RibParseError: Into<
375        <Input::Error as ParseError<Input::Token, Input::Range, Input::Position>>::StreamError,
376    >,
377    Input::Position: GetSourcePosition,
378{
379    choice((
380        attempt(string("bool").map(|_| TypeName::Bool)),
381        attempt(string("s8").map(|_| TypeName::S8)),
382        attempt(string("u8").map(|_| TypeName::U8)),
383        attempt(string("s16").map(|_| TypeName::S16)),
384        attempt(string("u16").map(|_| TypeName::U16)),
385        attempt(string("s32").map(|_| TypeName::S32)),
386        attempt(string("u32").map(|_| TypeName::U32)),
387        attempt(string("s64").map(|_| TypeName::S64)),
388        attempt(string("u64").map(|_| TypeName::U64)),
389        attempt(string("f32").map(|_| TypeName::F32)),
390        attempt(string("f64").map(|_| TypeName::F64)),
391        attempt(string("char").map(|_| TypeName::Chr)),
392        attempt(string("string").map(|_| TypeName::Str)),
393    ))
394    .skip(spaces().silent())
395}
396
397pub fn parse_list_type<Input>() -> impl Parser<Input, Output = TypeName>
398where
399    Input: combine::Stream<Token = char>,
400    RibParseError: Into<
401        <Input::Error as ParseError<Input::Token, Input::Range, Input::Position>>::StreamError,
402    >,
403    Input::Position: GetSourcePosition,
404{
405    string("list")
406        .skip(spaces().silent())
407        .with(between(
408            char('<').skip(spaces().silent().silent()),
409            char('>').skip(spaces().silent().silent()),
410            type_name(),
411        ))
412        .map(|inner_type| TypeName::List(Box::new(inner_type)))
413}
414
415pub fn parse_option_type<Input>() -> impl Parser<Input, Output = TypeName>
416where
417    Input: combine::Stream<Token = char>,
418    RibParseError: Into<
419        <Input::Error as ParseError<Input::Token, Input::Range, Input::Position>>::StreamError,
420    >,
421    Input::Position: GetSourcePosition,
422{
423    string("option")
424        .skip(spaces().silent())
425        .with(between(
426            char('<').skip(spaces().silent().silent()),
427            char('>').skip(spaces().silent().silent()),
428            type_name(),
429        ))
430        .map(|inner_type| TypeName::Option(Box::new(inner_type)))
431}
432
433enum ResultSuccess {
434    NoType,
435    WithType(TypeName),
436}
437
438// https://component-model.bytecodealliance.org/design/wit.html#results
439pub fn parse_result_type<Input>() -> impl Parser<Input, Output = TypeName>
440where
441    Input: combine::Stream<Token = char>,
442    RibParseError: Into<
443        <Input::Error as ParseError<Input::Token, Input::Range, Input::Position>>::StreamError,
444    >,
445    Input::Position: GetSourcePosition,
446{
447    string("result")
448        .skip(spaces().silent())
449        .with(optional(between(
450            char('<').skip(spaces().silent()),
451            char('>').skip(spaces().silent()),
452            (
453                choice!(
454                    string("_")
455                        .skip(spaces().silent())
456                        .map(|_| ResultSuccess::NoType),
457                    type_name()
458                        .skip(spaces().silent())
459                        .map(ResultSuccess::WithType)
460                ),
461                optional(
462                    char(',')
463                        .skip(spaces().silent())
464                        .with(type_name().skip(spaces().silent())),
465                ),
466            ),
467        )))
468        .map(|result| match result {
469            None => TypeName::Result {
470                ok: None,
471                error: None,
472            },
473            Some((ResultSuccess::NoType, None)) => TypeName::Result {
474                ok: None,
475                error: None,
476            },
477            Some((ResultSuccess::NoType, Some(error))) => TypeName::Result {
478                ok: None,
479                error: Some(Box::new(error)),
480            },
481            Some((ResultSuccess::WithType(ok), None)) => TypeName::Result {
482                ok: Some(Box::new(ok)),
483                error: None,
484            },
485            Some((ResultSuccess::WithType(ok), Some(error))) => TypeName::Result {
486                ok: Some(Box::new(ok)),
487                error: Some(Box::new(error)),
488            },
489        })
490}
491
492pub fn parse_tuple_type<Input>() -> impl Parser<Input, Output = TypeName>
493where
494    Input: combine::Stream<Token = char>,
495    RibParseError: Into<
496        <Input::Error as ParseError<Input::Token, Input::Range, Input::Position>>::StreamError,
497    >,
498    Input::Position: GetSourcePosition,
499{
500    string("tuple")
501        .skip(spaces().silent())
502        .with(between(
503            char('<').skip(spaces().silent()),
504            char('>').skip(spaces().silent()),
505            sep_by(type_name(), char(',').skip(spaces().silent())),
506        ))
507        .map(TypeName::Tuple)
508}
509
510pub fn type_name_<Input>() -> impl Parser<Input, Output = TypeName>
511where
512    Input: combine::Stream<Token = char>,
513    RibParseError: Into<
514        <Input::Error as ParseError<Input::Token, Input::Range, Input::Position>>::StreamError,
515    >,
516    Input::Position: GetSourcePosition,
517{
518    spaces().silent().with(choice((
519        attempt(parse_basic_type()),
520        attempt(parse_list_type()),
521        attempt(parse_tuple_type()),
522        attempt(parse_option_type()),
523        attempt(parse_result_type()),
524    )))
525}
526
527parser! {
528    pub fn type_name[Input]()(Input) -> TypeName
529     where [Input: combine::Stream<Token = char>, RibParseError: Into<<Input::Error as ParseError<Input::Token, Input::Range, Input::Position>>::StreamError>, Input::Position: GetSourcePosition]
530    {
531       type_name_()
532    }
533}
534
535#[cfg(test)]
536mod type_name_tests {
537    use combine::stream::position;
538    use combine::EasyParser;
539    use test_r::test;
540
541    use super::*;
542
543    fn parse_and_compare(input: &str, expected: TypeName) {
544        let written = format!("{expected}");
545        let result1 = type_name()
546            .easy_parse(position::Stream::new(input))
547            .map(|x| x.0);
548        let result2 = type_name()
549            .easy_parse(position::Stream::new(written.as_str()))
550            .map(|x| x.0);
551        assert_eq!(result1, Ok(expected.clone()));
552        assert_eq!(result2, Ok(expected));
553    }
554
555    #[test]
556    fn test_basic_types() {
557        parse_and_compare("bool", TypeName::Bool);
558        parse_and_compare("s8", TypeName::S8);
559        parse_and_compare("u8", TypeName::U8);
560        parse_and_compare("s16", TypeName::S16);
561        parse_and_compare("u16", TypeName::U16);
562        parse_and_compare("s32", TypeName::S32);
563        parse_and_compare("u32", TypeName::U32);
564        parse_and_compare("s64", TypeName::S64);
565        parse_and_compare("u64", TypeName::U64);
566        parse_and_compare("f32", TypeName::F32);
567        parse_and_compare("f64", TypeName::F64);
568        parse_and_compare("char", TypeName::Chr);
569        parse_and_compare("string", TypeName::Str);
570    }
571
572    #[test]
573    fn test_list_type_name() {
574        parse_and_compare("list<u8>", TypeName::List(Box::new(TypeName::U8)));
575        parse_and_compare(
576            "list<list<f32>>",
577            TypeName::List(Box::new(TypeName::List(Box::new(TypeName::F32)))),
578        );
579    }
580
581    #[test]
582    fn test_tuple_type_name() {
583        parse_and_compare(
584            "tuple<u8, u16>",
585            TypeName::Tuple(vec![TypeName::U8, TypeName::U16]),
586        );
587        parse_and_compare(
588            "tuple<s32, list<u8>>",
589            TypeName::Tuple(vec![TypeName::S32, TypeName::List(Box::new(TypeName::U8))]),
590        );
591        parse_and_compare(
592            "tuple<tuple<s8, s16>, u32>",
593            TypeName::Tuple(vec![
594                TypeName::Tuple(vec![TypeName::S8, TypeName::S16]),
595                TypeName::U32,
596            ]),
597        );
598    }
599
600    #[test]
601    fn test_option_type_name() {
602        parse_and_compare("option<u8>", TypeName::Option(Box::new(TypeName::U8)));
603        parse_and_compare(
604            "option<list<f32>>",
605            TypeName::Option(Box::new(TypeName::List(Box::new(TypeName::F32)))),
606        );
607    }
608
609    #[test]
610    fn test_nested_types() {
611        parse_and_compare(
612            "list<tuple<u8, s8>>",
613            TypeName::List(Box::new(TypeName::Tuple(vec![TypeName::U8, TypeName::S8]))),
614        );
615        parse_and_compare(
616            "tuple<list<u16>, list<f64>>",
617            TypeName::Tuple(vec![
618                TypeName::List(Box::new(TypeName::U16)),
619                TypeName::List(Box::new(TypeName::F64)),
620            ]),
621        );
622    }
623
624    #[test]
625    fn test_spaces_around_types() {
626        parse_and_compare("  u8  ", TypeName::U8);
627        parse_and_compare("list< u8 >", TypeName::List(Box::new(TypeName::U8)));
628        parse_and_compare(
629            "tuple< s32 , list< u8 > >",
630            TypeName::Tuple(vec![TypeName::S32, TypeName::List(Box::new(TypeName::U8))]),
631        );
632    }
633}