qbe_parser/ast/types/
parse.rs

1#![allow(clippy::unused_unit, reason = "part of macros")]
2use crate::ast::types::*;
3use crate::lexer::{Token, TokenParser, keyword, operator};
4use crate::parse::{Parse, impl_fromstr_via_parse, maybe_newline, spanned};
5
6use chumsky::prelude::*;
7
8impl Parse for AlignSpec {
9    const DESC: &'static str = "alignment spec";
10    fn parser<'a>() -> impl TokenParser<'a, AlignSpec> {
11        keyword!(align)
12            .parser()
13            .then_ignore(maybe_newline())
14            .ignore_then(Token::number())
15            .map_with(|value, extra| AlignSpec {
16                value,
17                span: extra.span(),
18            })
19            .labelled(Self::DESC)
20    }
21}
22
23impl Parse for TypeDef {
24    const DESC: &'static str = "type definition";
25
26    fn parser<'a>() -> impl TokenParser<'a, TypeDef> {
27        keyword!(type)
28            .parser()
29            .ignore_then(TypeName::parser())
30            .then_ignore(operator!(=).parser().padded_by(maybe_newline()))
31            .then(AlignSpec::parser().padded_by(maybe_newline()).or_not())
32            .then(TypeDefBody::parser().padded_by(maybe_newline()))
33            .map_with(|((name, align), body), extra| TypeDef {
34                span: extra.span(),
35                body,
36                align,
37                name,
38            })
39            .validate(|td, extra, emitter| {
40                if let Err(errors) = td.validate() {
41                    for e in errors {
42                        emitter.emit(Rich::custom(extra.span(), e));
43                    }
44                }
45                td
46            })
47            .labelled(Self::DESC)
48    }
49}
50impl_fromstr_via_parse!(TypeDef);
51
52impl Parse for TypeDefBody {
53    const DESC: &'static str = "type body";
54
55    fn parser<'a>() -> impl TokenParser<'a, TypeDefBody> {
56        choice((
57            OpaqueBody::parser().map(TypeDefBody::Opaque),
58            StructBody::parser().map(TypeDefBody::Struct),
59            UnionBody::parser().map(TypeDefBody::Union),
60        ))
61        .labelled("typedef body")
62    }
63}
64impl Parse for OpaqueBody {
65    const DESC: &'static str = "opaque type body";
66    fn parser<'a>() -> impl TokenParser<'a, Self> {
67        Token::number()
68            .padded_by(maybe_newline())
69            .delimited_by(just(Token::OpenBrace), just(Token::CloseBrace))
70            .map_with(spanned)
71            .map(|Spanned { value: size, span }| OpaqueBody { span, size })
72            .labelled(Self::DESC)
73    }
74}
75impl Parse for StructBody {
76    const DESC: &'static str = "struct body";
77    fn parser<'a>() -> impl TokenParser<'a, Self> {
78        FieldDef::parser()
79            .padded_by(maybe_newline())
80            .separated_by(operator!(,).parser())
81            .allow_trailing()
82            .collect::<Vec<_>>()
83            .delimited_by(just(Token::OpenBrace), just(Token::CloseBrace))
84            .map_with(|fields, extra| StructBody {
85                span: extra.span(),
86                fields,
87            })
88            .labelled(Self::DESC)
89    }
90}
91impl Parse for UnionBody {
92    const DESC: &'static str = "union body";
93    fn parser<'a>() -> impl TokenParser<'a, Self> {
94        StructBody::parser()
95            .padded_by(maybe_newline())
96            .repeated()
97            .at_least(1)
98            .collect::<Vec<_>>()
99            .delimited_by(just(Token::OpenBrace), just(Token::CloseBrace))
100            .map_with(|variants, extra| UnionBody {
101                span: extra.span(),
102                variants,
103            })
104            .labelled("struct body")
105    }
106}
107impl Parse for FieldDef {
108    const DESC: &'static str = "field definition";
109    fn parser<'a>() -> impl TokenParser<'a, Self> {
110        FieldType::parser()
111            .padded_by(maybe_newline())
112            .then(Token::number().or_not())
113            .map_with(|(ty, repeated), extra| FieldDef {
114                span: extra.span(),
115                ty,
116                repeated,
117            })
118            .labelled(Self::DESC)
119    }
120}
121macro_rules! parse_maybe_named_type {
122    (impl Parse for $target:ident {
123        const DESC = $desc:literal;
124        variants {
125            Named(TypeName),
126            $($variant:ident($inner:ty, Span)),+ $(,)?
127        }
128    }) => {
129        impl Parse for $target {
130            const DESC: &'static str = $desc;
131            fn parser<'a>() -> impl TokenParser<'a, Self> {
132                fn _check_variants(t: $target) {
133                    match t {
134                        $target::Named(tp) => {
135                            let _: TypeName = tp;
136                        },
137                        $($target::$variant(inner, s) => {
138                            let _: $inner = inner;
139                            let _: Span = s;
140                        },)*
141                    }
142                }
143                let simple = choice((
144                    $(<$inner>::parser().map_with(|tp, extra| {
145                        $target::$variant(tp, extra.span().into())
146                    }),)*
147                ));
148                TypeName::parser()
149                    .map($target::Named)
150                    .or(simple)
151                    .labelled(Self::DESC)
152            }
153        }
154        impl_fromstr_via_parse!($target);
155    };
156}
157parse_maybe_named_type! {
158    impl Parse for FieldType {
159        const DESC = "field type";
160        variants {
161            Named(TypeName),
162            Extended(ExtendedType, Span),
163        }
164    }
165}
166parse_maybe_named_type! {
167    impl Parse for AbiType {
168        const DESC = "abi type";
169        variants {
170            Named(TypeName),
171            Base(BaseType, Span),
172            SubWord(SubWordType, Span),
173        }
174    }
175}
176
177macro_rules! simple_type_parser {
178    ($($target:ident { DESC = $desc:literal }),+ $(,)?) => {
179        $(impl Parse for $target {
180            const DESC: &'static str = $desc;
181            fn parser<'a>() -> impl TokenParser<'a, Self> {
182                select!(Token::ShortTypeSpec(spec) => spec)
183                    .try_map(|spec, span| spec.try_into().map_err(|reason| {
184                        Rich::custom(span, reason)
185                    }))
186                    .labelled(Self::DESC)
187            }
188        })*
189    };
190}
191simple_type_parser!(
192    BaseType { DESC = "base type" },
193    ExtendedType { DESC = "extended type" },
194    SubWordType { DESC = "sub-word type" },
195);
196
197#[cfg(test)]
198mod test {}