c2e/
ast.rs

1/*
2 * This program is free software: you can redistribute it and/or modify it under the terms of
3 * the GNU General Public License as published by the Free Software Foundation, either version
4 * 3 of the License, or (at your option) any later version.
5 *
6 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
7 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8 * See the GNU General Public License for more details.
9 *
10 * You should have received a copy of the GNU General Public License along with this program. If
11 * not, see <https://www.gnu.org/licenses/>.
12 */
13
14//! Abstract syntax tree (AST) types
15
16use core::{
17    fmt::Display,
18    ops::{Deref, DerefMut},
19};
20
21use alloc::{boxed::Box, vec::Vec};
22use enumflags2::BitFlags;
23
24#[derive(Debug, Clone, PartialEq, Eq)]
25pub struct Declaration<'src> {
26    pub base_type: QualifiedType<'src>,
27    pub declarator: Declarator<'src>,
28}
29
30// Convert from a tuple `(Type, Declarator)` to a `Declaration`
31impl<'src> From<(QualifiedType<'src>, Declarator<'src>)> for Declaration<'src> {
32    fn from((base_type, declarator): (QualifiedType<'src>, Declarator<'src>)) -> Self {
33        Declaration {
34            base_type,
35            declarator,
36        }
37    }
38}
39
40#[derive(Debug, Copy, Clone, PartialEq, Eq, parse_display::Display)]
41pub enum Type<'src> {
42    #[display("{0}")]
43    Primitive(PrimitiveType),
44    #[display("{0} {1}")]
45    Record(RecordKind, &'src str),
46    // TODO: user-defined (typedef) types
47}
48
49#[derive(Debug, Copy, Clone, PartialEq, Eq, parse_display::Display)]
50#[display("{0}{1}")]
51pub struct QualifiedType<'src>(pub TypeQualifiers, pub Type<'src>);
52
53impl<'src> From<(TypeQualifiers, Type<'src>)> for QualifiedType<'src> {
54    fn from((qualifiers, ty): (TypeQualifiers, Type<'src>)) -> Self {
55        QualifiedType(qualifiers, ty)
56    }
57}
58
59impl<'src> From<Type<'src>> for QualifiedType<'src> {
60    fn from(ty: Type<'src>) -> Self {
61        QualifiedType(TypeQualifiers::default(), ty)
62    }
63}
64
65/// Qualifier for a type
66#[derive(Debug, Copy, Clone, PartialEq, Eq, parse_display::Display)]
67#[display(style = "title case")]
68#[enumflags2::bitflags]
69#[repr(u8)]
70pub enum TypeQualifier {
71    /// `const`
72    Const,
73    /// `volatile`
74    Volatile,
75    /// `restrict`
76    Restrict,
77}
78
79/// Bit set of [type qualifiers][TypeQualifier]
80#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
81pub struct TypeQualifiers(pub BitFlags<TypeQualifier>);
82
83impl Deref for TypeQualifiers {
84    type Target = BitFlags<TypeQualifier>;
85
86    fn deref(&self) -> &Self::Target {
87        &self.0
88    }
89}
90
91impl DerefMut for TypeQualifiers {
92    fn deref_mut(&mut self) -> &mut Self::Target {
93        &mut self.0
94    }
95}
96
97/// Format the type qualifiers as a space-separated list.
98///
99/// # Examples
100///
101/// ```
102/// # use c2e::ast::TypeQualifiers;
103/// let empty = TypeQualifiers::default();
104/// assert_eq!(&empty.to_string(), "");
105/// ```
106///
107/// ```
108/// # use c2e::ast::{TypeQualifiers, TypeQualifier};
109/// let mut qualifiers = TypeQualifiers([
110///     TypeQualifier::Const,
111///     TypeQualifier::Volatile
112/// ].into_iter().collect());
113/// assert_eq!(&qualifiers.to_string(), "const volatile");
114/// ```
115impl Display for TypeQualifiers {
116    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
117        self.0.iter().enumerate().try_for_each(|(i, qualifier)| {
118            if i == 0 {
119                write!(f, "{qualifier}")
120            } else {
121                write!(f, " {qualifier}")
122            }
123        })
124    }
125}
126
127impl chumsky::container::Container<TypeQualifier> for TypeQualifiers {
128    fn push(&mut self, item: TypeQualifier) {
129        self.insert(item);
130    }
131}
132
133#[derive(Debug, Copy, Clone, PartialEq, Eq, parse_display::Display, parse_display::FromStr)]
134#[display(style = "title case")]
135pub enum RecordKind {
136    Union,
137    Struct,
138    Enum,
139}
140
141#[derive(Debug, Copy, Clone, PartialEq, Eq, parse_display::Display)]
142pub struct PrimitiveType(pub(crate) &'static str);
143
144impl AsRef<str> for PrimitiveType {
145    fn as_ref(&self) -> &str {
146        self.0
147    }
148}
149
150#[derive(Debug, Clone, PartialEq, Eq)]
151pub enum Declarator<'src> {
152    /// Represents the base of an anonymous (unnamed) declaration, such as a function parameter.
153    /// I.e., this is where [`Declarator::Ident`] would be used if the declaration had a name.
154    Anonymous,
155    Ident(&'src str),
156    Ptr(Box<Declarator<'src>>, TypeQualifiers),
157    Array(Box<Declarator<'src>>, Option<usize>),
158    Function {
159        func: Box<Declarator<'src>>,
160        params: Vec<Declaration<'src>>,
161    },
162}
163
164#[cfg(test)]
165mod tests {
166    use alloc::string::ToString;
167
168    use super::*;
169
170    #[test]
171    fn test_primitive_type_as_ref() {
172        let int_type = PrimitiveType("int");
173        assert_eq!(AsRef::<str>::as_ref(&int_type), "int");
174    }
175
176    #[test]
177    fn type_qualifiers_display() {
178        let mut qualifiers = TypeQualifiers::default();
179        assert_eq!(qualifiers.to_string(), "");
180
181        qualifiers.insert(TypeQualifier::Const);
182        assert_eq!(qualifiers.to_string(), "const");
183
184        qualifiers.insert(TypeQualifier::Volatile);
185        assert_eq!(qualifiers.to_string(), "const volatile");
186    }
187}