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
99impl GenRust for Attribute {
100    fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
101        match self {
102            Self::Path(path) => cg.add(&path.get_rust()),
103            Self::NameValue { path, value } => {
104                cg.add(&format!("{} =", path.get_rust()));
105                value.gen_rust(ctx, cg);
106            }
107            Self::List { path, items } => {
108                cg.add(&path.get_rust());
109                for (i, item) in items.iter().enumerate() {
110                    if i > 0 {
111                        cg.add(", ");
112                    }
113
114                    item.gen_rust(ctx, cg);
115                }
116            }
117        }
118    }
119}
120
121impl<T: GetRust> GetRust for Spanned<T> {
122    fn get_rust(&self) -> String {
123        format!(
124            "/* {}:{} */ {}",
125            self.line,
126            self.column,
127            self.item.get_rust()
128        )
129    }
130}
131
132impl<T: GenRust> GenRust for Spanned<T> {
133    fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
134        cg.add_indentedln(&format!("/* {}:{} */", self.line, self.column));
135        cg.add_indented("");
136        self.item.gen_rust(ctx, cg);
137    }
138}
139
140impl GetRust for Path {
141    fn get_rust(&self) -> String {
142        self.0
143            .iter()
144            .map(Identifier::get_rust)
145            .collect::<Vec<String>>()
146            .join("::")
147    }
148}
149
150impl GetRust for TypePostfix {
151    fn get_rust(&self) -> String {
152        match self {
153            TypePostfix::Ref => format!("&"),
154            TypePostfix::RefMut => format!("&mut "),
155            TypePostfix::RefLifetime(lifetime) => format!("&'{} ", lifetime.get_rust()),
156            TypePostfix::RefMutLifetime(lifetime) => format!("&'{} mut ", lifetime.get_rust()),
157            TypePostfix::Dyn => format!("dyn "),
158        }
159    }
160}
161
162impl GetRust for Visibility {
163    fn get_rust(&self) -> String {
164        match self {
165            Visibility::Public => "pub ".to_string(),
166            Visibility::PublicTarget(path) => format!("pub({}) ", path.get_rust()),
167            Visibility::Private => "".to_string(),
168        }
169    }
170}
171
172impl GetRust for Identifier {
173    fn get_rust(&self) -> String {
174        self.0.clone()
175    }
176}
177
178impl GetRust for TypeExpr {
179    fn get_rust(&self) -> String {
180        self.1
181            .iter()
182            .map(TypePostfix::get_rust)
183            .rev()
184            .collect::<String>()
185            + &self.0.get_rust()
186    }
187}
188
189pub fn get_static_type_path(path: &Path) -> String {
190    let rust_path = path.get_rust();
191
192    if rust_path == "void" {
193        format!("()")
194    } else {
195        rust_path
196    }
197}
198
199impl GetRust for TypeExprKind {
200    fn get_rust(&self) -> String {
201        match self {
202            TypeExprKind::Path(path) => get_static_type_path(path),
203            TypeExprKind::Lifetime(name) => format!("'{}", name.get_rust()),
204            TypeExprKind::PathParams(path, params) => {
205                format!(
206                    "{}<{}>",
207                    get_static_type_path(path),
208                    params
209                        .into_iter()
210                        .map(|t| t.get_rust())
211                        .collect::<Vec<_>>()
212                        .join(", ")
213                )
214            }
215            TypeExprKind::Tuple(types) => format!(
216                "({})",
217                types
218                    .into_iter()
219                    .map(|t| t.get_rust())
220                    .collect::<Vec<_>>()
221                    .join(", ")
222            ),
223        }
224    }
225}
226
227impl GenRust for Pattern {
228    fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
229        match self {
230            Self::Id(id) => cg.add(&id.get_rust()),
231            Self::Path(path) => cg.add(&path.get_rust()),
232            Self::Literal(lit) => lit.gen_rust(ctx, cg),
233
234            Self::Struct(path, ids) => {
235                cg.add(&path.get_rust());
236                cg.add(" {");
237                for id in ids {
238                    cg.add(&id.get_rust());
239                    cg.add(",");
240                }
241                cg.add("}");
242            }
243
244            Self::NamedTuple(path, ids) => {
245                cg.add(&path.get_rust());
246                cg.add(" (");
247                for id in ids {
248                    cg.add(&id.get_rust());
249                    cg.add(",");
250                }
251                cg.add(")");
252            }
253
254            Self::Tuple(ids) => {
255                cg.add("(");
256                for id in ids {
257                    cg.add(&id.get_rust());
258                    cg.add(",");
259                }
260                cg.add(")");
261            }
262        }
263    }
264}