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(¶ms, ",")) + 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 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}