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}