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 TypePostfix {
160    fn get_rust(&self) -> String {
161        match self {
162            TypePostfix::Ref => format!("&"),
163            TypePostfix::RefMut => format!("&mut "),
164            TypePostfix::RefLifetime(lifetime) => format!("&'{} ", lifetime.get_rust()),
165            TypePostfix::RefMutLifetime(lifetime) => format!("&'{} mut ", lifetime.get_rust()),
166            TypePostfix::Dyn => format!("dyn "),
167        }
168    }
169}
170
171impl GetRust for Visibility {
172    fn get_rust(&self) -> String {
173        match self {
174            Visibility::Public => "pub ".to_string(),
175            Visibility::PublicTarget(path) => format!("pub({}) ", path.get_rust()),
176            Visibility::Private => "".to_string(),
177        }
178    }
179}
180
181impl GetRust for Identifier {
182    fn get_rust(&self) -> String {
183        self.0.clone()
184    }
185}
186
187impl GetRust for TypeExpr {
188    fn get_rust(&self) -> String {
189        self.1
190            .iter()
191            .map(TypePostfix::get_rust)
192            .rev()
193            .collect::<String>()
194            + &self.0.get_rust()
195    }
196}
197
198pub fn get_static_type_path(path: &Path) -> String {
199    let rust_path = path.get_rust();
200
201    if rust_path == "void" {
202        format!("()")
203    } else {
204        rust_path
205    }
206}
207
208impl GetRust for TypeExprKind {
209    fn get_rust(&self) -> String {
210        match self {
211            TypeExprKind::Path(path, generics) => {
212                if let Some(generics) = generics {
213                    format!("{}{}", get_static_type_path(path), generics.get_rust())
214                } else {
215                    get_static_type_path(path)
216                }
217            }
218            TypeExprKind::Lifetime(name) => format!("'{}", name.get_rust()),
219            TypeExprKind::Tuple(types) => format!(
220                "({})",
221                types
222                    .into_iter()
223                    .map(|t| t.get_rust())
224                    .collect::<Vec<_>>()
225                    .join(", ")
226            ),
227        }
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}