Fork of daniellemaywood.uk/gleam — Wasm codegen work
15 kB
485 lines
1use std::ops::Deref;
2
3use ecow::{EcoString, eco_format};
4use im::HashSet;
5use num_bigint::BigInt;
6use vec1::Vec1;
7
8use crate::{ast, exhaustiveness, parse, type_};
9
10#[derive(Debug, Default)]
11pub struct Module {
12 functions: Vec<Function>,
13}
14
15#[derive(Debug)]
16pub struct Function {
17 pub name: EcoString,
18 pub return_type: Type,
19 pub parameters: Vec<FunctionParameter>,
20 pub body: Expression,
21}
22
23#[derive(Debug)]
24pub struct FunctionParameter {
25 pub type_: Type,
26 pub name: Option<EcoString>,
27}
28
29#[derive(Debug, Default)]
30pub struct Translator {
31 module: Module,
32}
33
34#[derive(Debug, Clone, Copy)]
35pub enum Type {
36 Int,
37 Float,
38 Bool,
39 Generic,
40}
41
42#[derive(Debug)]
43pub enum Expression {
44 Block(Vec<Expression>),
45
46 Var {
47 name: EcoString,
48 },
49
50 Int {
51 value: BigInt,
52 },
53
54 Equals {
55 lhs: Box<Expression>,
56 rhs: Box<Expression>,
57 },
58
59 IntAdd {
60 lhs: Box<Expression>,
61 rhs: Box<Expression>,
62 },
63
64 Set {
65 name: EcoString,
66 value: Box<Expression>,
67 },
68
69 If {
70 cond: Box<Expression>,
71 then: Box<Expression>,
72 else_: Box<Expression>,
73 },
74}
75
76impl Translator {
77 pub fn translate(mut self, module: &ast::TypedModule) -> Module {
78 for definition in &module.definitions {
79 match definition {
80 ast::Definition::Function(function) => {
81 self.module
82 .functions
83 .push(Self::translate_function(function));
84 }
85 ast::Definition::TypeAlias(_type_alias) => todo!(),
86 ast::Definition::CustomType(_custom_type) => todo!(),
87 ast::Definition::Import(_import) => todo!(),
88 ast::Definition::ModuleConstant(_module_constant) => todo!(),
89 }
90 }
91
92 self.module
93 }
94
95 fn translate_function(function: &ast::TypedFunction) -> Function {
96 let (_, name) = function.name.clone().expect("function should have a name");
97
98 let return_type = Self::translate_type(&function.return_type);
99
100 let parameters = Iterator::collect(function.arguments.iter().map(|argument| {
101 let name = argument.get_variable_name().cloned();
102 let type_ = Self::translate_type(&argument.type_);
103
104 FunctionParameter { name, type_ }
105 }));
106
107 let body = BodyTranslator::default().translate(&function.body);
108
109 Function {
110 name,
111 body,
112 return_type,
113 parameters,
114 }
115 }
116
117 fn translate_type(type_: &type_::Type) -> Type {
118 match type_ {
119 type_::Type::Named {
120 publicity: _,
121 package: _,
122 module,
123 name,
124 arguments: _,
125 inferred_variant: _,
126 } => match (module.as_str(), name.as_str()) {
127 ("gleam", "Int") => Type::Int,
128 ("gleam", "Float") => Type::Float,
129 ("gleam", "Bool") => Type::Bool,
130 (_, _) => todo!(),
131 },
132 type_::Type::Fn {
133 arguments: _,
134 return_: _,
135 } => todo!(),
136 type_::Type::Var { type_ } => match type_.borrow().deref() {
137 type_::TypeVar::Link { type_ } => Self::translate_type(type_),
138 type_::TypeVar::Unbound { id: _ } | type_::TypeVar::Generic { id: _ } => {
139 Type::Generic
140 }
141 },
142 type_::Type::Tuple { elements: _ } => todo!(),
143 }
144 }
145}
146
147#[derive(Debug, Default)]
148pub struct BodyTranslator {
149 variables: HashSet<EcoString>,
150 variable_count: usize,
151}
152
153impl BodyTranslator {
154 fn translate(mut self, body: &Vec1<ast::TypedStatement>) -> Expression {
155 Expression::Block(Iterator::collect(
156 body.iter().map(|stmt| self.translate_statement(stmt)),
157 ))
158 }
159
160 fn translate_statement(&mut self, statement: &ast::TypedStatement) -> Expression {
161 match statement {
162 ast::Statement::Expression(expression) => self.translate_expression(expression),
163 ast::Statement::Assignment(assignment) => self.translate_assignment(assignment),
164 ast::Statement::Use(_) => todo!(),
165 ast::Statement::Assert(_) => todo!(),
166 }
167 }
168
169 fn translate_expression(&mut self, expression: &ast::TypedExpr) -> Expression {
170 match expression {
171 ast::TypedExpr::Int {
172 location: _,
173 type_: _,
174 value: _,
175 int_value,
176 } => Expression::Int {
177 value: int_value.clone(),
178 },
179 ast::TypedExpr::Float {
180 location: _,
181 type_: _,
182 value: _,
183 } => todo!(),
184 ast::TypedExpr::String {
185 location: _,
186 type_: _,
187 value: _,
188 } => todo!(),
189 ast::TypedExpr::Block {
190 location: _,
191 statements: _,
192 } => todo!(),
193 ast::TypedExpr::Pipeline {
194 location: _,
195 first_value: _,
196 assignments: _,
197 finally: _,
198 finally_kind: _,
199 } => todo!(),
200 ast::TypedExpr::Var {
201 location: _,
202 constructor: _,
203 name,
204 } => Expression::Var { name: name.clone() },
205 ast::TypedExpr::Fn {
206 location: _,
207 type_: _,
208 kind: _,
209 arguments: _,
210 body: _,
211 return_annotation: _,
212 purity: _,
213 } => todo!(),
214 ast::TypedExpr::List {
215 location: _,
216 type_: _,
217 elements: _,
218 tail: _,
219 } => todo!(),
220 ast::TypedExpr::Call {
221 location: _,
222 type_: _,
223 fun: _,
224 arguments: _,
225 } => todo!(),
226 ast::TypedExpr::BinOp {
227 location: _,
228 type_: _,
229 name,
230 name_location: _,
231 left,
232 right,
233 } => {
234 let lhs = Box::new(self.translate_expression(left));
235 let rhs = Box::new(self.translate_expression(right));
236
237 match name {
238 ast::BinOp::And => todo!(),
239 ast::BinOp::Or => todo!(),
240 ast::BinOp::Eq => Expression::Equals { lhs, rhs },
241 ast::BinOp::NotEq => todo!(),
242 ast::BinOp::LtInt => todo!(),
243 ast::BinOp::LtEqInt => todo!(),
244 ast::BinOp::LtFloat => todo!(),
245 ast::BinOp::LtEqFloat => todo!(),
246 ast::BinOp::GtEqInt => todo!(),
247 ast::BinOp::GtInt => todo!(),
248 ast::BinOp::GtEqFloat => todo!(),
249 ast::BinOp::GtFloat => todo!(),
250 ast::BinOp::AddInt => Expression::IntAdd { lhs, rhs },
251 ast::BinOp::AddFloat => todo!(),
252 ast::BinOp::SubInt => todo!(),
253 ast::BinOp::SubFloat => todo!(),
254 ast::BinOp::MultInt => todo!(),
255 ast::BinOp::MultFloat => todo!(),
256 ast::BinOp::DivInt => todo!(),
257 ast::BinOp::DivFloat => todo!(),
258 ast::BinOp::RemainderInt => todo!(),
259 ast::BinOp::Concatenate => todo!(),
260 }
261 }
262 ast::TypedExpr::Case {
263 location: _,
264 type_: _,
265 subjects,
266 clauses,
267 compiled_case,
268 } => {
269 let mut block = vec![];
270
271 let subject_vars: Vec<_> = Iterator::collect(subjects.iter().map(|subject| {
272 let name = self.make_tmp_var();
273 let value = self.translate_expression(subject);
274
275 block.push(Expression::Set {
276 name: name.clone(),
277 value: Box::new(value),
278 });
279
280 return name;
281 }));
282
283 block.push(self.translate_decision(&subject_vars, clauses, &compiled_case.tree));
284
285 Expression::Block(block)
286 }
287 ast::TypedExpr::RecordAccess {
288 location: _,
289 field_start: _,
290 type_: _,
291 label: _,
292 index: _,
293 record: _,
294 } => todo!(),
295 ast::TypedExpr::ModuleSelect {
296 location: _,
297 field_start: _,
298 type_: _,
299 label: _,
300 module_name: _,
301 module_alias: _,
302 constructor: _,
303 } => todo!(),
304 ast::TypedExpr::Tuple {
305 location: _,
306 type_: _,
307 elements: _,
308 } => todo!(),
309 ast::TypedExpr::TupleIndex {
310 location: _,
311 type_: _,
312 index: _,
313 tuple: _,
314 } => todo!(),
315 ast::TypedExpr::Todo {
316 location: _,
317 message: _,
318 kind: _,
319 type_: _,
320 } => todo!(),
321 ast::TypedExpr::Panic {
322 location: _,
323 message: _,
324 type_: _,
325 } => todo!(),
326 ast::TypedExpr::Echo {
327 location: _,
328 type_: _,
329 expression: _,
330 message: _,
331 } => todo!(),
332 ast::TypedExpr::BitArray {
333 location: _,
334 type_: _,
335 segments: _,
336 } => todo!(),
337 ast::TypedExpr::RecordUpdate {
338 location: _,
339 type_: _,
340 record_assignment: _,
341 constructor: _,
342 arguments: _,
343 } => todo!(),
344 ast::TypedExpr::NegateBool {
345 location: _,
346 value: _,
347 } => todo!(),
348 ast::TypedExpr::NegateInt {
349 location: _,
350 value: _,
351 } => todo!(),
352 ast::TypedExpr::Invalid {
353 location: _,
354 type_: _,
355 } => todo!(),
356 }
357 }
358
359 fn translate_assignment(&mut self, assignment: &ast::TypedAssignment) -> Expression {
360 dbg!(&assignment.compiled_case);
361
362 todo!()
363 }
364
365 fn make_tmp_var(&mut self) -> EcoString {
366 let variable_count = self.variable_count;
367 self.make_var(eco_format!("_tmp{variable_count}"))
368 }
369
370 fn make_var(&mut self, name: EcoString) -> EcoString {
371 self.variable_count += 1;
372 _ = self.variables.insert(name.clone());
373 name
374 }
375
376 fn translate_decision(
377 &mut self,
378 subjects: &[EcoString],
379 clauses: &[ast::TypedClause],
380 decision: &exhaustiveness::Decision,
381 ) -> Expression {
382 match decision {
383 exhaustiveness::Decision::Run { body } => {
384 let mut block = vec![];
385
386 for (binding, value) in &body.bindings {
387 block.push(self.translate_binding(subjects, binding.clone(), value));
388 }
389
390 block.push(self.translate_expression(&clauses[body.clause_index].then));
391
392 Expression::Block(block)
393 }
394 exhaustiveness::Decision::Guard {
395 guard: _,
396 if_true: _,
397 if_false: _,
398 } => {
399 todo!()
400 }
401 exhaustiveness::Decision::Switch {
402 var,
403 choices,
404 fallback,
405 fallback_check: _,
406 } => {
407 let fallback = self.translate_decision(subjects, clauses, fallback);
408
409 choices
410 .iter()
411 .rfold(fallback, |fallback, (check, then)| Expression::If {
412 cond: Box::new(self.translate_runtime_check(
413 check,
414 Expression::Var {
415 name: subjects[var.id].clone(),
416 },
417 )),
418 then: Box::new(self.translate_decision(subjects, clauses, then)),
419 else_: Box::new(fallback),
420 })
421 }
422 exhaustiveness::Decision::Fail => todo!(),
423 }
424 }
425
426 fn translate_binding(
427 &mut self,
428 subjects: &[EcoString],
429 binding: EcoString,
430 value: &exhaustiveness::BoundValue,
431 ) -> Expression {
432 let value = match value {
433 exhaustiveness::BoundValue::Variable(variable) => Expression::Var {
434 name: subjects[variable.id].clone(),
435 },
436 exhaustiveness::BoundValue::LiteralString(_eco_string) => todo!(),
437 exhaustiveness::BoundValue::LiteralInt(big_int) => Expression::Int {
438 value: big_int.clone(),
439 },
440 exhaustiveness::BoundValue::LiteralFloat(_eco_string) => todo!(),
441 exhaustiveness::BoundValue::BitArraySlice {
442 bit_array: _,
443 read_action: _,
444 } => todo!(),
445 };
446
447 Expression::Set {
448 name: binding,
449 value: Box::new(value),
450 }
451 }
452
453 fn translate_runtime_check(
454 &mut self,
455 check: &exhaustiveness::RuntimeCheck,
456 against: Expression,
457 ) -> Expression {
458 match check {
459 exhaustiveness::RuntimeCheck::Int { value } => {
460 let value = parse::parse_int_value(&value).expect("unable to parse integer value");
461
462 Expression::Equals {
463 lhs: Box::new(against),
464 rhs: Box::new(Expression::Int { value }),
465 }
466 }
467 exhaustiveness::RuntimeCheck::Float { value: _ } => todo!(),
468 exhaustiveness::RuntimeCheck::String { value: _ } => todo!(),
469 exhaustiveness::RuntimeCheck::StringPrefix { prefix: _, rest: _ } => todo!(),
470 exhaustiveness::RuntimeCheck::Tuple {
471 size: _,
472 elements: _,
473 } => todo!(),
474 exhaustiveness::RuntimeCheck::BitArray { test: _ } => todo!(),
475 exhaustiveness::RuntimeCheck::Variant {
476 match_: _,
477 index: _,
478 labels: _,
479 fields: _,
480 } => todo!(),
481 exhaustiveness::RuntimeCheck::NonEmptyList { first: _, rest: _ } => todo!(),
482 exhaustiveness::RuntimeCheck::EmptyList => todo!(),
483 }
484 }
485}