Skip to main content

mist_codegen/
lib.rs

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