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