1use std::fmt::{self, Debug, Display, Formatter, Write};
2use std::str::FromStr;
3
4use crate::ast::{NumericLiteral, Span, Spanned, TypeName};
5use crate::lexer::ShortTypeSpec;
6use crate::lexer::tokens::InvalidShortTypeSpecError;
7use crate::print::IndentedPrinter;
8
9mod parse;
10#[cfg(test)]
11mod test;
12
13#[derive(Debug, Eq, PartialEq, Hash, Clone)]
15pub struct AlignSpec {
16 pub span: Span,
17 pub value: NumericLiteral<u64>,
18}
19impl AlignSpec {
20 pub fn unspanned(value: u64) -> Self {
21 AlignSpec {
22 span: Span::MISSING,
23 value: NumericLiteral::unspanned(value),
24 }
25 }
26}
27impl Display for AlignSpec {
28 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
29 write!(f, "align {}", self.value)
30 }
31}
32
33macro_rules! simple_type {
34 (
35 $(#[$tp_attr:meta])*
36 $v:vis enum $target:ident {
37 $($variant:ident),+ $(,)?
38 }
39 ) => {
40 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
41 $(#[$tp_attr])*
42 $v enum $target {
43 $($variant),*
44 }
45 impl $target {
46 #[inline] pub fn to_short_spec(&self) -> ShortTypeSpec {
48 match self {
49 $(Self::$variant => ShortTypeSpec::$variant,)*
50 }
51 }
52 fn type_desc() -> &'static str {
53 let snake = paste3::paste!(stringify!([<$target:snake>]));
54 snake.strip_suffix("_type").expect(snake)
55 }
56 }
57 impl Display for $target {
58 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
59 Display::fmt(&self.to_short_spec(), f)
60 }
61 }
62 paste3::paste! {
63 #[derive(Debug, thiserror::Error, Copy, Clone)]
64 #[error("Expected a {} type, but got \"{spec}\"", $target::type_desc())]
65 pub struct [<Invalid $target Error>] {
66 spec: ShortTypeSpec
67 }
68 impl TryFrom<ShortTypeSpec> for $target {
69 type Error = [<Invalid $target:camel Error>];
70 #[inline] fn try_from(spec: ShortTypeSpec) -> Result<Self, Self::Error> {
72 match spec {
73 $(ShortTypeSpec::$variant => Ok(Self::$variant),)*
74 _ => return Err(Self::Error { spec })
75 }
76 }
77 }
78 #[derive(Debug, thiserror::Error, Clone)]
79 #[error("Expected a {} type, but got {text:?}", $target::type_desc())]
80 pub struct [<$target ParseError>] {
81 text: String,
82 }
83 impl From<[<Invalid $target Error>]> for [<$target ParseError>] {
84 #[cold]
85 fn from(cause: [<Invalid $target Error>]) -> Self {
86 Self { text: cause.spec.text().into() }
87 }
88 }
89 impl FromStr for $target {
90 type Err = [<$target ParseError>];
91 fn from_str(s: &str) -> Result<Self, Self::Err> {
92 Ok(ShortTypeSpec::from_str(s)
93 .map_err(#[cold] |InvalidShortTypeSpecError| Self::Err { text: s.into() })?
94 .try_into()?)
95 }
96 }
97 }
98 #[cfg(test)]
99 paste3::paste! {
100 mod [<test_ $target:snake>] {
101 #[test]
102 fn desc() {
103 super::$target::type_desc();
104 }
105 }
106 }
107 };
108}
109
110simple_type!(
111 pub enum BaseType {
112 Word,
113 Long,
114 Single,
115 Double,
116 }
117);
118impl BaseType {
119 pub fn to_extended_type(&self) -> ExtendedType {
120 ExtendedType::from(*self)
121 }
122}
123impl TryFrom<ExtendedType> for BaseType {
124 type Error = InvalidBaseTypeError;
125
126 #[inline] fn try_from(value: ExtendedType) -> Result<Self, Self::Error> {
128 value.to_short_spec().try_into()
129 }
130}
131simple_type!(
132 pub enum ExtendedType {
133 Word,
135 Long,
136 Single,
137 Double,
138 Half,
140 Byte,
141 }
142);
143impl From<BaseType> for ExtendedType {
144 #[inline] fn from(value: BaseType) -> Self {
146 value.to_short_spec().try_into().unwrap()
147 }
148}
149simple_type!(
150 pub enum SubWordType {
151 SignedByte,
152 UnsignedByte,
153 SignedHalf,
154 UnsignedHalf,
155 }
156);
157impl SubWordType {
158 #[inline]
160 pub fn erase_sign_info(&self) -> ExtendedType {
161 match self {
162 SubWordType::SignedByte | SubWordType::UnsignedByte => ExtendedType::Byte,
163 SubWordType::SignedHalf | SubWordType::UnsignedHalf => ExtendedType::Half,
164 }
165 }
166}
167
168macro_rules! maybe_named_type {
169 (
170 $(#[$ty_attr:meta])*
171 $v:vis enum $target:ident {
172 Named(TypeName),
173 $($simple_variant:ident($simple_type:ty, Span)),+ $(,)?
174 }
175 ) => {
176 $(#[$ty_attr])*
177 #[derive(Debug, Clone)]
178 $v enum $target {
179 Named(TypeName),
180 $($simple_variant($simple_type, Span)),*
181 }
182 impl $target {
183 pub fn span(&self) -> Span {
184 match *self {
185 $($target::$simple_variant(_, span) => span,)*
186 $target::Named(ref name) => name.span(),
187 }
188 }
189 }
190 impl Display for $target {
191 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
192 match self {
193 $target::Named(name) => Display::fmt(name, f),
194 $($target::$simple_variant(simple, _) => Display::fmt(simple, f),)*
195 }
196 }
197 }
198 $(impl From<$simple_type> for $target {
199 fn from(value: $simple_type) -> Self {
200 $target::$simple_variant(value, Span::MISSING)
201 }
202 }
203 impl From<Spanned<$simple_type>> for $target {
204 fn from(value: Spanned<$simple_type>) -> Self {
205 $target::$simple_variant(value.value, value.span)
206 }
207 })*
208 impl From<TypeName> for $target {
209 #[inline]
210 fn from(value: TypeName) -> Self {
211 $target::Named(value)
212 }
213 }
214 };
215}
216
217maybe_named_type! {
218 #[derive(PartialEq, Eq, Hash)]
220 pub enum AbiType {
221 Named(TypeName),
222 Base(BaseType, Span),
223 SubWord(SubWordType, Span),
224 }
225}
226maybe_named_type! {
227 #[derive(PartialEq, Eq, Hash)]
229 pub enum FieldType {
230 Named(TypeName),
231 Extended(ExtendedType, Span),
232 }
233}
234impl From<BaseType> for FieldType {
235 fn from(value: BaseType) -> Self {
236 value.to_extended_type().into()
237 }
238}
239impl From<Spanned<BaseType>> for FieldType {
240 fn from(value: Spanned<BaseType>) -> Self {
241 Spanned::map(value, ExtendedType::from).into()
242 }
243}
244#[derive(Debug, Eq, PartialEq, Hash, Clone)]
245pub struct TypeDef {
246 pub name: TypeName,
247 pub align: Option<AlignSpec>,
248 pub span: Span,
249 pub body: TypeDefBody,
250}
251impl TypeDef {
252 pub(super) fn span(&self) -> Span {
254 self.span
255 }
256 fn print(&self, out: &mut IndentedPrinter<'_>) -> fmt::Result {
257 write!(out, "type {} = ", self.name)?;
258 if let Some(ref align) = self.align {
259 write!(out, "{align} ")?;
260 }
261 self.body.print(out)
262 }
263 pub fn validate(&self) -> Result<(), Vec<InvalidTypeDefReason>> {
264 let mut errors = Vec::new();
265 match self.body {
266 TypeDefBody::Struct(_) => {}
267 TypeDefBody::Union(ref body) => {
268 if body.variants.is_empty() {
269 errors.push(InvalidTypeDefReason::UnionTypeEmpty);
270 }
271 }
272 TypeDefBody::Opaque(_) => {
273 if self.align.is_none() {
274 errors.push(InvalidTypeDefReason::OpaqueMissingAlignment);
275 }
276 }
277 }
278 if errors.is_empty() {
279 Ok(())
280 } else {
281 Err(errors)
282 }
283 }
284}
285impl Display for TypeDef {
286 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
287 self.print(&mut IndentedPrinter::new(f))
288 }
289}
290#[derive(Debug, thiserror::Error)]
292#[non_exhaustive]
293pub enum InvalidTypeDefReason {
294 #[error("Opaque type missing alignment")]
295 OpaqueMissingAlignment,
296 #[error("Union type has no variants")]
297 UnionTypeEmpty,
298}
299#[derive(Debug, Eq, PartialEq, Hash, Clone)]
300#[non_exhaustive]
301pub enum TypeDefBody {
302 Struct(StructBody),
303 Union(UnionBody),
304 Opaque(OpaqueBody),
305}
306impl TypeDefBody {
307 fn print(&self, out: &mut IndentedPrinter<'_>) -> fmt::Result {
308 match self {
309 TypeDefBody::Struct(body) => body.print(out),
310 TypeDefBody::Union(body) => body.print(out),
311 TypeDefBody::Opaque(body) => body.print(out),
312 }
313 }
314}
315impl Display for TypeDefBody {
316 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
317 self.print(&mut IndentedPrinter::new(f))
318 }
319}
320#[derive(Debug, Eq, PartialEq, Hash, Clone)]
321pub struct OpaqueBody {
322 pub span: Span,
323 pub size: NumericLiteral<u64>,
324}
325impl OpaqueBody {
326 fn print(&self, out: &mut IndentedPrinter<'_>) -> fmt::Result {
327 write!(out, "{self}")
329 }
330}
331impl Display for OpaqueBody {
332 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
333 write!(f, "{{ {} }}", self.size)
334 }
335}
336#[derive(Debug, Eq, PartialEq, Hash, Clone)]
337pub struct UnionBody {
338 pub span: Span,
339 pub variants: Vec<StructBody>,
340}
341impl UnionBody {
342 fn print(&self, out: &mut IndentedPrinter<'_>) -> fmt::Result {
343 writeln!(out, "{{")?;
344 out.indented(|out| {
345 for variant in &self.variants {
346 out.maybe_writeln()?;
347 variant.print(out)?;
348 }
349 out.maybe_writeln()
350 })?;
351 write!(out, "}}")
352 }
353}
354impl Display for UnionBody {
355 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
356 self.print(&mut IndentedPrinter::new(f))
357 }
358}
359#[derive(Debug, Eq, PartialEq, Hash, Clone)]
360pub struct StructBody {
361 pub span: Span,
362 pub fields: Vec<FieldDef>,
363}
364impl StructBody {
365 fn print(&self, out: &mut IndentedPrinter<'_>) -> fmt::Result {
366 writeln!(out, "{{")?;
367 out.indented(|out| {
368 out.print_separated_with(",", &self.fields, |field, out| {
369 out.maybe_writeln()?;
370 write!(out, "{field}")
371 })
372 })?;
373 write!(out, "\n}}")
374 }
375}
376#[derive(Debug, Eq, PartialEq, Hash, Clone)]
377pub struct FieldDef {
378 pub span: Span,
379 pub ty: FieldType,
380 pub repeated: Option<NumericLiteral<u64>>,
382}
383impl Display for FieldDef {
384 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
385 write!(f, "{}", self.ty)?;
386 if let Some(ref repeated) = self.repeated {
387 write!(f, " {repeated}")?;
388 }
389 Ok(())
390 }
391}