c_subset/
c_subset.rs

1use notugly::*;
2
3pub mod ast {
4    pub(crate) struct Ident(pub(crate) String);
5
6    pub(crate) struct CStruct {
7        pub(crate) name: Ident,
8        pub(crate) fields: Vec<(CType, Ident)>,
9    }
10    pub(crate) struct CEnum {
11        pub(crate) name: Ident,
12        pub(crate) variants: Vec<Ident>,
13    }
14
15    pub(crate) enum CType {
16        Struct(Ident),
17        Enum(Ident),
18        Int,
19        Char,
20        Ptr(Box<CType>),
21    }
22
23    pub(crate) struct CFunction {
24        pub(crate) name: Ident,
25        pub(crate) ret: CType,
26        pub(crate) params: Vec<(CType, Ident)>,
27        pub(crate) body: Vec<Stmt>,
28    }
29
30    pub(crate) enum Stmt {
31        Decl(CDecl),
32        Assignment(Ident, CExpr),
33        Expr(CExpr),
34        Return(CExpr),
35    }
36
37    pub(crate) enum CExpr {
38        IntLit(i32),
39        StrLit(String),
40        IdentLit(Ident),
41        Call(Ident, Vec<CExpr>),
42    }
43
44    pub(crate) enum CDecl {
45        StructDecl(CStruct),
46        EnumDecl(CEnum),
47        VarDecl(CType, Ident),
48        FunctionDecl(CFunction),
49    }
50}
51
52pub mod fmt {
53    use notugly::*;
54
55    use crate::ast::*;
56
57    fn sep(xs: &[impl Format], sep: &str) -> Document {
58        fold(xs, |lhs, rhs| lhs & text(sep) + rhs)
59    }
60
61    fn paren(x: Document) -> Document {
62        group_with("", group(text("(") & x / text(")")))
63    }
64
65    impl Format for Ident {
66        fn format(&self) -> Document {
67            text(&self.0)
68        }
69    }
70
71    impl Format for CStruct {
72        fn format(&self) -> Document {
73            let fields = self
74                .fields
75                .iter()
76                .map(|(ty, id)| ty.format() + id.format() & text(";"))
77                .collect::<Vec<_>>();
78            group(text("struct") + self.name.format() + bracket(4, "{", stack(&fields), "}"))
79        }
80    }
81
82    impl Format for CEnum {
83        fn format(&self) -> Document {
84            group(
85                text("enum") + self.name.format() + bracket(4, "{", sep(&self.variants, ","), "}"),
86            )
87        }
88    }
89
90    impl Format for CType {
91        fn format(&self) -> Document {
92            match self {
93                CType::Struct(id) => text("struct") + id.format(),
94                CType::Enum(id) => text("enum") + id.format(),
95                CType::Int => text("int"),
96                CType::Char => text("char"),
97                CType::Ptr(ty) => ty.format() & text("*"),
98            }
99        }
100    }
101
102    impl Format for CFunction {
103        fn format(&self) -> Document {
104            let params = self
105                .params
106                .iter()
107                .map(|(ty, id)| ty.format() + id.format() & text(","))
108                .collect::<Vec<_>>();
109
110            self.ret.format() + self.name.format()
111                & paren(sep(&params, ",")) + bracket(4, "{", stack(&self.body), "}")
112        }
113    }
114
115    impl Format for Stmt {
116        fn format(&self) -> Document {
117            match self {
118                Stmt::Decl(d) => d.format(),
119                Stmt::Assignment(id, e) => id.format() + text("=") + e.format() & text(";"),
120                Stmt::Expr(e) => e.format() & text(";"),
121                Stmt::Return(r) => text("return") + r.format() & text(";"),
122            }
123        }
124    }
125
126    impl Format for CExpr {
127        fn format(&self) -> Document {
128            match self {
129                CExpr::IntLit(i) => text(format!("{i}")),
130                CExpr::StrLit(s) => text(format!("\"{s}\"")),
131                CExpr::IdentLit(i) => i.format(),
132                CExpr::Call(f, args) => f.format() & paren(sep(args, ",")),
133            }
134        }
135    }
136
137    impl Format for CDecl {
138        fn format(&self) -> Document {
139            match self {
140                CDecl::StructDecl(s) => s.format() & text(";"),
141                CDecl::EnumDecl(e) => e.format() & text(";"),
142                CDecl::VarDecl(ty, id) => ty.format() + id.format() & text(";"),
143                CDecl::FunctionDecl(f) => f.format(),
144            }
145        }
146    }
147}
148
149fn main() {
150    use ast::*;
151
152    // Not necessarily correct program but you get it
153    let c_prog = &[
154        CDecl::StructDecl(CStruct {
155            name: Ident("point".into()),
156            fields: vec![
157                (CType::Int, Ident("x".into())),
158                (CType::Int, Ident("y".into())),
159            ],
160        }),
161        CDecl::EnumDecl(CEnum {
162            name: Ident("state".into()),
163            variants: vec![
164                Ident("left".into()),
165                Ident("right".into()),
166                Ident("up".into()),
167                Ident("down".into()),
168                Ident("forward".into()),
169                Ident("backward".into()),
170                Ident("random".into()),
171            ],
172        }),
173        CDecl::FunctionDecl(CFunction {
174            name: Ident("main".into()),
175            ret: CType::Int,
176            params: vec![],
177            body: vec![
178                Stmt::Decl(CDecl::VarDecl(CType::Int, Ident("n".into()))),
179                Stmt::Decl(CDecl::VarDecl(
180                    CType::Ptr(Box::new(CType::Char)),
181                    Ident("fmt".into()),
182                )),
183                Stmt::Assignment(Ident("n".into()), CExpr::IntLit(32)),
184                Stmt::Assignment(
185                    Ident("fmt".into()),
186                    CExpr::StrLit("Hello world n°%d!".into()),
187                ),
188                Stmt::Expr(CExpr::Call(
189                    Ident("printf".into()),
190                    vec![
191                        CExpr::IdentLit(Ident("fmt".into())),
192                        CExpr::IdentLit(Ident("n".into())),
193                    ],
194                )),
195                Stmt::Decl(CDecl::VarDecl(
196                    CType::Struct(Ident("point".into())),
197                    Ident("p".into()),
198                )),
199                Stmt::Decl(CDecl::VarDecl(
200                    CType::Enum(Ident("state".into())),
201                    Ident("s".into()),
202                )),
203                Stmt::Return(CExpr::IntLit(0)),
204            ],
205        }),
206    ];
207
208    println!("{}", stack(c_prog).pretty(60));
209}