Skip to main content

mist_codegen/
lib.rs

1pub mod class_decl;
2pub mod expr;
3pub mod statement;
4pub mod top_level;
5
6use mist_parser::ast::*;
7
8pub struct Context {
9    pub expr_ensure_semicolon: bool,
10    pub expr_super: Option<ExprPath>,
11}
12
13pub trait GenRust {
14    fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen);
15}
16
17pub trait GetRust {
18    fn get_rust(&self) -> String;
19    fn get_rust_ctx(&self, cx: &mut Context) -> String {
20        let _ = cx;
21        self.get_rust()
22    }
23}
24
25#[derive(Default)]
26pub struct RustCodegen {
27    output: String,
28    indent: usize,
29}
30
31impl RustCodegen {
32    pub fn new() -> Self {
33        Self {
34            output: String::new(),
35            indent: 0,
36        }
37    }
38
39    fn indent_str(&self) -> String {
40        "    ".repeat(self.indent)
41    }
42
43    fn add(&mut self, s: &str) {
44        self.output.push_str(s);
45    }
46
47    fn addln(&mut self, s: &str) {
48        self.add(s);
49        self.add("\n");
50    }
51
52    fn add_indented(&mut self, s: &str) {
53        let line = format!("{}{}", self.indent_str(), s);
54        self.add(&line);
55    }
56
57    fn add_indentedln(&mut self, s: &str) {
58        let line = format!("{}{}\n", self.indent_str(), s);
59        self.add(&line);
60    }
61
62    pub fn generate(&mut self, toplevels: Vec<TopLevel>) -> String {
63        let mut ctx = Context {
64            expr_ensure_semicolon: true,
65            expr_super: None,
66        };
67
68        for tl in toplevels {
69            tl.gen_rust(&mut ctx, self);
70        }
71
72        self.output.clone()
73    }
74
75    pub fn ensure_brackets(&mut self, ctx: &mut Context, stmt: &Box<Statement>) {
76        match &**stmt {
77            Statement::Block(_) => stmt.gen_rust(ctx, self),
78            _ => {
79                self.add("{");
80                self.indent += 1;
81                stmt.gen_rust(ctx, self);
82                self.indent -= 1;
83                self.add("}");
84            }
85        }
86    }
87
88    pub fn ensure_brackets_expr(&mut self, ctx: &mut Context, expr: &Expression) {
89        match expr {
90            Expression::Statement(stmt) => self.ensure_brackets(ctx, stmt),
91            _ => {
92                self.add("{");
93                self.indent += 1;
94                expr.gen_rust(ctx, self);
95                self.indent -= 1;
96                self.add("}");
97            }
98        }
99    }
100
101    pub fn ensure_brackets_body(&mut self, ctx: &mut Context, body: &StatementBody) {
102        match body {
103            StatementBody::Expression(expr) => self.ensure_brackets_expr(ctx, expr),
104
105            StatementBody::Statement(expr) => {
106                ctx.expr_ensure_semicolon = true;
107                self.ensure_brackets_expr(ctx, expr);
108            }
109        }
110    }
111}
112
113impl GenRust for Attribute {
114    fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
115        match self {
116            Self::Path(path) => cg.add(&path.get_rust()),
117            Self::NameValue { path, value } => {
118                cg.add(&format!("{} = ", path.get_rust()));
119                value.gen_rust(ctx, cg);
120            }
121            Self::List { path, items } => {
122                cg.add(&path.get_rust());
123                cg.add("(");
124                for (i, item) in items.iter().enumerate() {
125                    if i > 0 {
126                        cg.add(", ");
127                    }
128
129                    item.gen_rust(ctx, cg);
130                }
131                cg.add(")");
132            }
133        }
134    }
135}
136
137impl<T: GetRust> GetRust for Spanned<T> {
138    fn get_rust(&self) -> String {
139        format!(
140            "/* {}:{} */ {}",
141            self.line,
142            self.column,
143            self.item.get_rust()
144        )
145    }
146}
147
148impl<T: GenRust> GenRust for Spanned<T> {
149    fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
150        cg.add_indentedln(&format!("/* {}:{} */", self.line, self.column));
151        cg.add_indented("");
152        self.item.gen_rust(ctx, cg);
153    }
154}
155
156impl GetRust for Path {
157    fn get_rust(&self) -> String {
158        self.0
159            .iter()
160            .map(Identifier::get_rust)
161            .collect::<Vec<String>>()
162            .join("::")
163    }
164}
165
166impl GetRust for Visibility {
167    fn get_rust(&self) -> String {
168        match self {
169            Visibility::Public => "pub ".to_string(),
170            Visibility::PublicTarget(path) => format!("pub({}) ", path.get_rust()),
171            Visibility::Private => "".to_string(),
172        }
173    }
174}
175
176impl GetRust for Identifier {
177    fn get_rust(&self) -> String {
178        self.0.clone()
179    }
180}
181
182impl GetRust for TypeExpr {
183    fn get_rust(&self) -> String {
184        match self {
185            Self::Path(path, generics) => {
186                if let Some(generics) = generics {
187                    format!("{}{}", path.get_rust(), generics.get_rust())
188                } else {
189                    path.get_rust()
190                }
191            }
192            Self::Lifetime(name) => format!("'{}", name.get_rust()),
193            Self::Tuple(types) => format!(
194                "({})",
195                types
196                    .into_iter()
197                    .map(|t| t.get_rust())
198                    .collect::<Vec<_>>()
199                    .join(", ")
200            ),
201            Self::StaticFn(types, return_type) => {
202                if let Some(return_type) = return_type {
203                    format!(
204                        "fn({}) -> {}",
205                        types
206                            .into_iter()
207                            .map(|t| t.get_rust())
208                            .collect::<Vec<_>>()
209                            .join(", "),
210                        return_type.get_rust()
211                    )
212                } else {
213                    format!(
214                        "fn({})",
215                        types
216                            .into_iter()
217                            .map(|t| t.get_rust())
218                            .collect::<Vec<_>>()
219                            .join(", "),
220                    )
221                }
222            }
223
224            Self::UnsafePtr { mutable, ty } => {
225                let mutable = if *mutable { "mut " } else { "const " };
226                format!("*{mutable}{}", ty.get_rust())
227            }
228
229            Self::Ref {
230                lifetime,
231                mutable,
232                ty,
233            } => {
234                let mutable = if *mutable { "mut " } else { "" };
235
236                if let Some(lifetime) = lifetime {
237                    format!("&'{} {mutable}{}", lifetime.get_rust(), ty.get_rust())
238                } else {
239                    format!("&{mutable}{}", ty.get_rust())
240                }
241            }
242
243            Self::Dyn(ty) => {
244                format!("dyn {}", ty.get_rust())
245            }
246        }
247    }
248}
249
250impl GenRust for Pattern {
251    fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
252        match self {
253            Self::Etc => cg.add(".."),
254            Self::Literal(lit) => lit.gen_rust(ctx, cg),
255            Self::Path(mutable, path) => {
256                if *mutable {
257                    cg.add("mut ");
258                };
259
260                cg.add(&path.get_rust())
261            }
262            Self::Struct(path, inner) => {
263                cg.add(&path.get_rust());
264                cg.add(" {");
265
266                for (idx, i) in inner.iter().enumerate() {
267                    if idx > 0 {
268                        cg.add(", ");
269                    }
270
271                    if let Some((name, pat)) = i {
272                        cg.add(&name.get_rust());
273                        if let Some(pat) = pat {
274                            cg.add(": ");
275                            pat.gen_rust(ctx, cg);
276                        }
277                    } else {
278                        cg.add("..");
279                    }
280                }
281
282                cg.add("}");
283            }
284
285            Self::NamedTuple(path, inner) => {
286                cg.add(&path.get_rust());
287                cg.add(" (");
288                for pat in inner {
289                    pat.gen_rust(ctx, cg);
290                    cg.add(",");
291                }
292                cg.add(")");
293            }
294
295            Self::Tuple(inner) => {
296                cg.add("(");
297                for pat in inner {
298                    pat.gen_rust(ctx, cg);
299                    cg.add(",");
300                }
301                cg.add(")");
302            }
303        }
304    }
305}