qbe_parser/ast/types/
parse.rs1#![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 {}