Fork of daniellemaywood.uk/gleam — Wasm codegen work
41 kB
1218 lines
1use std::{collections::HashMap, ops::Deref};
2
3use ecow::{EcoString, eco_format};
4use num_bigint::BigInt;
5use vec1::Vec1;
6
7use crate::{ast, exhaustiveness, parse, type_};
8
9#[derive(Debug, PartialEq, Eq, Default)]
10pub struct Module {
11 pub functions: Vec<Function>,
12}
13
14#[derive(Debug, PartialEq, Eq)]
15pub struct Function {
16 pub name: EcoString,
17 pub return_type: Type,
18 pub parameters: Vec<FunctionParameter>,
19 pub body: Expression,
20}
21
22#[derive(Debug, PartialEq, Eq)]
23pub struct FunctionParameter {
24 pub type_: Type,
25 pub name: Option<EcoString>,
26}
27
28#[derive(Debug, Default, PartialEq, Eq)]
29pub struct Translator {
30 module: Module,
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum Type {
35 Int,
36 Float,
37 Bool,
38 Generic,
39}
40
41#[derive(Debug, PartialEq, Eq, Clone)]
42pub struct Var {
43 pub name: EcoString,
44}
45
46#[derive(Debug, PartialEq, Eq, Clone)]
47pub enum Expression {
48 Block(Vec<Expression>),
49
50 FunctionRef {
51 module: EcoString,
52 name: EcoString,
53 },
54
55 Var(Var),
56
57 Int {
58 value: BigInt,
59 },
60
61 Float {
62 value: EcoString,
63 },
64
65 Equals {
66 lhs: Box<Expression>,
67 rhs: Box<Expression>,
68 },
69
70 IntAdd {
71 lhs: Box<Expression>,
72 rhs: Box<Expression>,
73 },
74
75 IntSub {
76 lhs: Box<Expression>,
77 rhs: Box<Expression>,
78 },
79
80 IntMul {
81 lhs: Box<Expression>,
82 rhs: Box<Expression>,
83 },
84
85 IntDiv {
86 lhs: Box<Expression>,
87 rhs: Box<Expression>,
88 },
89
90 FloatAdd {
91 lhs: Box<Expression>,
92 rhs: Box<Expression>,
93 },
94
95 FloatSub {
96 lhs: Box<Expression>,
97 rhs: Box<Expression>,
98 },
99
100 FloatMul {
101 lhs: Box<Expression>,
102 rhs: Box<Expression>,
103 },
104
105 FloatDiv {
106 lhs: Box<Expression>,
107 rhs: Box<Expression>,
108 },
109
110 Set {
111 name: Var,
112 value: Box<Expression>,
113 },
114
115 If {
116 cond: Box<Expression>,
117 then: Box<Expression>,
118 else_: Box<Expression>,
119 },
120
121 Call {
122 target: Box<Expression>,
123 args: Vec<Expression>,
124 },
125}
126
127impl Translator {
128 pub fn translate(mut self, module: &ast::TypedModule) -> Module {
129 for definition in &module.definitions {
130 match definition {
131 ast::Definition::Function(function) => {
132 self.module
133 .functions
134 .push(Self::translate_function(function));
135 }
136 ast::Definition::TypeAlias(_type_alias) => todo!(),
137 ast::Definition::CustomType(_custom_type) => todo!(),
138 ast::Definition::Import(_import) => todo!(),
139 ast::Definition::ModuleConstant(_module_constant) => todo!(),
140 }
141 }
142
143 self.module
144 }
145
146 fn translate_function(function: &ast::TypedFunction) -> Function {
147 let (_, name) = function.name.clone().expect("function should have a name");
148
149 let return_type = Self::translate_type(&function.return_type);
150
151 let parameters = Iterator::collect(function.arguments.iter().map(|argument| {
152 let name = argument.get_variable_name().cloned();
153 let type_ = Self::translate_type(&argument.type_);
154
155 FunctionParameter { name, type_ }
156 }));
157
158 let mut translator = BodyTranslator::default();
159 for argument in &function.arguments {
160 if let Some(name) = argument.get_variable_name() {
161 _ = translator.make_var(name.clone());
162 }
163 }
164
165 let body = translator.translate(&function.body);
166 let body = Self::flatten_expression(body);
167 let body = Self::remove_unused_code(body);
168
169 Function {
170 name,
171 body,
172 return_type,
173 parameters,
174 }
175 }
176
177 fn translate_type(type_: &type_::Type) -> Type {
178 match type_ {
179 type_::Type::Named {
180 publicity: _,
181 package: _,
182 module,
183 name,
184 arguments: _,
185 inferred_variant: _,
186 } => match (module.as_str(), name.as_str()) {
187 ("gleam", "Int") => Type::Int,
188 ("gleam", "Float") => Type::Float,
189 ("gleam", "Bool") => Type::Bool,
190 (_, _) => todo!(),
191 },
192 type_::Type::Fn {
193 arguments: _,
194 return_: _,
195 } => todo!(),
196 type_::Type::Var { type_ } => match type_.borrow().deref() {
197 type_::TypeVar::Link { type_ } => Self::translate_type(type_),
198 type_::TypeVar::Unbound { id: _ } | type_::TypeVar::Generic { id: _ } => {
199 Type::Generic
200 }
201 },
202 type_::Type::Tuple { elements: _ } => todo!(),
203 }
204 }
205
206 fn flatten_expression(expression: Expression) -> Expression {
207 match expression {
208 Expression::Block(expressions) => {
209 let mut block = vec![];
210
211 for expression in expressions {
212 let expression = Self::flatten_expression(expression);
213
214 match expression {
215 Expression::Block(mut expressions) => block.append(&mut expressions),
216 Expression::Var { .. }
217 | Expression::FunctionRef { .. }
218 | Expression::Int { .. }
219 | Expression::Float { .. }
220 | Expression::Equals { .. }
221 | Expression::IntAdd { .. }
222 | Expression::IntSub { .. }
223 | Expression::IntMul { .. }
224 | Expression::IntDiv { .. }
225 | Expression::FloatAdd { .. }
226 | Expression::FloatSub { .. }
227 | Expression::FloatMul { .. }
228 | Expression::FloatDiv { .. }
229 | Expression::Set { .. }
230 | Expression::If { .. }
231 | Expression::Call { .. } => block.push(expression),
232 };
233 }
234
235 match block.as_slice() {
236 [single] => single.clone(),
237 _ => Expression::Block(block),
238 }
239 }
240 Expression::FunctionRef { module, name } => Expression::FunctionRef { module, name },
241 Expression::Var(var) => Expression::Var(var),
242 Expression::Int { value } => Expression::Int { value },
243 Expression::Float { value } => Expression::Float { value },
244 Expression::Equals { lhs, rhs } => Expression::Equals {
245 lhs: Box::new(Self::flatten_expression(*lhs)),
246 rhs: Box::new(Self::flatten_expression(*rhs)),
247 },
248 Expression::IntAdd { lhs, rhs } => Expression::IntAdd {
249 lhs: Box::new(Self::flatten_expression(*lhs)),
250 rhs: Box::new(Self::flatten_expression(*rhs)),
251 },
252 Expression::IntSub { lhs, rhs } => Expression::IntSub {
253 lhs: Box::new(Self::flatten_expression(*lhs)),
254 rhs: Box::new(Self::flatten_expression(*rhs)),
255 },
256 Expression::IntMul { lhs, rhs } => Expression::IntMul {
257 lhs: Box::new(Self::flatten_expression(*lhs)),
258 rhs: Box::new(Self::flatten_expression(*rhs)),
259 },
260 Expression::IntDiv { lhs, rhs } => Expression::IntDiv {
261 lhs: Box::new(Self::flatten_expression(*lhs)),
262 rhs: Box::new(Self::flatten_expression(*rhs)),
263 },
264 Expression::FloatAdd { lhs, rhs } => Expression::FloatAdd {
265 lhs: Box::new(Self::flatten_expression(*lhs)),
266 rhs: Box::new(Self::flatten_expression(*rhs)),
267 },
268 Expression::FloatSub { lhs, rhs } => Expression::FloatSub {
269 lhs: Box::new(Self::flatten_expression(*lhs)),
270 rhs: Box::new(Self::flatten_expression(*rhs)),
271 },
272 Expression::FloatMul { lhs, rhs } => Expression::FloatMul {
273 lhs: Box::new(Self::flatten_expression(*lhs)),
274 rhs: Box::new(Self::flatten_expression(*rhs)),
275 },
276 Expression::FloatDiv { lhs, rhs } => Expression::FloatDiv {
277 lhs: Box::new(Self::flatten_expression(*lhs)),
278 rhs: Box::new(Self::flatten_expression(*rhs)),
279 },
280 Expression::Set { name, value } => Expression::Set {
281 name,
282 value: Box::new(Self::flatten_expression(*value)),
283 },
284 Expression::If { cond, then, else_ } => Expression::If {
285 cond: Box::new(Self::flatten_expression(*cond)),
286 then: Box::new(Self::flatten_expression(*then)),
287 else_: Box::new(Self::flatten_expression(*else_)),
288 },
289 Expression::Call { target, args } => Expression::Call {
290 target: Box::new(Self::flatten_expression(*target)),
291 args: args.into_iter().map(Self::flatten_expression).collect(),
292 },
293 }
294 }
295
296 fn remove_unused_code(expression: Expression) -> Expression {
297 match expression {
298 Expression::Block(expressions) => {
299 let mut block = vec![];
300
301 let last_expression_index = expressions.len() - 1;
302
303 for (index, expression) in expressions.into_iter().enumerate() {
304 let expression = Self::remove_unused_code(expression);
305
306 match expression {
307 Expression::Var { .. } | Expression::FunctionRef { .. }
308 if index != last_expression_index => {}
309
310 Expression::Block(_)
311 | Expression::FunctionRef { .. }
312 | Expression::Var { .. }
313 | Expression::Int { .. }
314 | Expression::Float { .. }
315 | Expression::Equals { .. }
316 | Expression::IntAdd { .. }
317 | Expression::IntSub { .. }
318 | Expression::IntMul { .. }
319 | Expression::IntDiv { .. }
320 | Expression::FloatAdd { .. }
321 | Expression::FloatSub { .. }
322 | Expression::FloatMul { .. }
323 | Expression::FloatDiv { .. }
324 | Expression::Set { .. }
325 | Expression::If { .. }
326 | Expression::Call { .. } => block.push(expression),
327 }
328 }
329
330 match block.as_slice() {
331 [single] => single.clone(),
332 _ => Expression::Block(block),
333 }
334 }
335 Expression::FunctionRef { module, name } => Expression::FunctionRef { module, name },
336 Expression::Var(var) => Expression::Var(var),
337 Expression::Int { value } => Expression::Int { value },
338 Expression::Float { value } => Expression::Float { value },
339 Expression::Equals { lhs, rhs } => Expression::Equals {
340 lhs: Box::new(Self::remove_unused_code(*lhs)),
341 rhs: Box::new(Self::remove_unused_code(*rhs)),
342 },
343 Expression::IntAdd { lhs, rhs } => Expression::IntAdd {
344 lhs: Box::new(Self::remove_unused_code(*lhs)),
345 rhs: Box::new(Self::remove_unused_code(*rhs)),
346 },
347 Expression::IntSub { lhs, rhs } => Expression::IntSub {
348 lhs: Box::new(Self::remove_unused_code(*lhs)),
349 rhs: Box::new(Self::remove_unused_code(*rhs)),
350 },
351 Expression::IntMul { lhs, rhs } => Expression::IntMul {
352 lhs: Box::new(Self::remove_unused_code(*lhs)),
353 rhs: Box::new(Self::remove_unused_code(*rhs)),
354 },
355 Expression::IntDiv { lhs, rhs } => Expression::IntDiv {
356 lhs: Box::new(Self::remove_unused_code(*lhs)),
357 rhs: Box::new(Self::remove_unused_code(*rhs)),
358 },
359 Expression::FloatAdd { lhs, rhs } => Expression::FloatAdd {
360 lhs: Box::new(Self::remove_unused_code(*lhs)),
361 rhs: Box::new(Self::remove_unused_code(*rhs)),
362 },
363 Expression::FloatSub { lhs, rhs } => Expression::FloatSub {
364 lhs: Box::new(Self::remove_unused_code(*lhs)),
365 rhs: Box::new(Self::remove_unused_code(*rhs)),
366 },
367 Expression::FloatMul { lhs, rhs } => Expression::FloatMul {
368 lhs: Box::new(Self::remove_unused_code(*lhs)),
369 rhs: Box::new(Self::remove_unused_code(*rhs)),
370 },
371 Expression::FloatDiv { lhs, rhs } => Expression::FloatDiv {
372 lhs: Box::new(Self::remove_unused_code(*lhs)),
373 rhs: Box::new(Self::remove_unused_code(*rhs)),
374 },
375 Expression::Set { name, value } => Expression::Set {
376 name,
377 value: Box::new(Self::remove_unused_code(*value)),
378 },
379 Expression::If { cond, then, else_ } => Expression::If {
380 cond: Box::new(Self::remove_unused_code(*cond)),
381 then: Box::new(Self::remove_unused_code(*then)),
382 else_: Box::new(Self::remove_unused_code(*else_)),
383 },
384 Expression::Call { target, args } => Expression::Call {
385 target: Box::new(Self::remove_unused_code(*target)),
386 args: args.into_iter().map(Self::remove_unused_code).collect(),
387 },
388 }
389 }
390}
391
392#[derive(Debug, Default)]
393pub struct BodyTranslator {
394 variables: HashMap<EcoString, EcoString>,
395 variable_count: usize,
396}
397
398#[derive(Debug, Clone, Copy, PartialEq, Eq)]
399enum DecisionKind {
400 Case,
401 Let,
402}
403
404impl BodyTranslator {
405 fn make_tmp_var(&mut self) -> Var {
406 self.make_var("_tmp".into())
407 }
408
409 fn make_var(&mut self, name: EcoString) -> Var {
410 self.variable_count += 1;
411
412 let entry = eco_format!("{}${}", name.clone(), self.variable_count);
413 _ = self.variables.insert(name.clone(), entry.clone());
414
415 Var { name: entry }
416 }
417
418 fn get_var(&mut self, name: &EcoString) -> Var {
419 let variable = self
420 .variables
421 .get(name)
422 .cloned()
423 .unwrap_or_else(|| panic!("variable '{name}' not found"));
424
425 Var { name: variable }
426 }
427
428 fn in_var_scope<T>(&mut self, func: impl Fn(&mut Self) -> T) -> T {
429 let snapshot = self.variables.clone();
430 let result = func(self);
431 self.variables = snapshot;
432 result
433 }
434
435 fn translate(mut self, body: &Vec1<ast::TypedStatement>) -> Expression {
436 self.translate_statements(body)
437 }
438
439 fn translate_statements(&mut self, statements: &[ast::TypedStatement]) -> Expression {
440 Expression::Block(Iterator::collect(
441 statements.iter().map(|stmt| self.translate_statement(stmt)),
442 ))
443 }
444
445 fn translate_statement(&mut self, statement: &ast::TypedStatement) -> Expression {
446 match statement {
447 ast::Statement::Expression(expression) => self.translate_expression(expression),
448 ast::Statement::Assignment(assignment) => self.translate_assignment(assignment),
449 ast::Statement::Use(_) => todo!(),
450 ast::Statement::Assert(_) => todo!(),
451 }
452 }
453
454 fn translate_expression(&mut self, expression: &ast::TypedExpr) -> Expression {
455 match expression {
456 ast::TypedExpr::Int {
457 location: _,
458 type_: _,
459 value: _,
460 int_value,
461 } => Expression::Int {
462 value: int_value.clone(),
463 },
464 ast::TypedExpr::Float {
465 location: _,
466 type_: _,
467 value,
468 } => Expression::Float {
469 value: value.clone(),
470 },
471 ast::TypedExpr::String {
472 location: _,
473 type_: _,
474 value: _,
475 } => todo!(),
476 ast::TypedExpr::Block {
477 location: _,
478 statements,
479 } => self.in_var_scope(|this| this.translate_statements(statements)),
480 ast::TypedExpr::Pipeline {
481 location: _,
482 first_value: _,
483 assignments: _,
484 finally: _,
485 finally_kind: _,
486 } => todo!(),
487 ast::TypedExpr::Var {
488 location: _,
489 constructor,
490 name,
491 } => match &constructor.variant {
492 type_::ValueConstructorVariant::LocalVariable {
493 location: _,
494 origin: _,
495 } => Expression::Var(self.get_var(name)),
496 type_::ValueConstructorVariant::ModuleConstant {
497 documentation: _,
498 location: _,
499 module: _,
500 name: _,
501 literal: _,
502 implementations: _,
503 } => todo!(),
504 type_::ValueConstructorVariant::LocalConstant { literal: _ } => todo!(),
505 type_::ValueConstructorVariant::ModuleFn {
506 name,
507 field_map: _,
508 module,
509 arity: _,
510 location: _,
511 documentation: _,
512 implementations: _,
513 external_erlang: _,
514 external_javascript: _,
515 external_cranelift: _,
516 purity: _,
517 } => Expression::FunctionRef {
518 module: module.clone(),
519 name: name.clone(),
520 },
521 type_::ValueConstructorVariant::Record {
522 name: _,
523 arity: _,
524 field_map: _,
525 location: _,
526 module: _,
527 variants_count: _,
528 variant_index: _,
529 documentation: _,
530 } => todo!(),
531 },
532 ast::TypedExpr::Fn {
533 location: _,
534 type_: _,
535 kind: _,
536 arguments: _,
537 body: _,
538 return_annotation: _,
539 purity: _,
540 } => todo!(),
541 ast::TypedExpr::List {
542 location: _,
543 type_: _,
544 elements: _,
545 tail: _,
546 } => todo!(),
547 ast::TypedExpr::Call {
548 location: _,
549 type_: _,
550 fun,
551 arguments,
552 } => {
553 let target = self.translate_expression(fun);
554 let args = arguments
555 .iter()
556 .map(|arg| self.translate_expression(&arg.value))
557 .collect();
558
559 Expression::Call {
560 target: Box::new(target),
561 args,
562 }
563 }
564 ast::TypedExpr::BinOp {
565 location: _,
566 type_: _,
567 name,
568 name_location: _,
569 left,
570 right,
571 } => {
572 let lhs = Box::new(self.translate_expression(left));
573 let rhs = Box::new(self.translate_expression(right));
574
575 match name {
576 ast::BinOp::And => todo!(),
577 ast::BinOp::Or => todo!(),
578 ast::BinOp::Eq => Expression::Equals { lhs, rhs },
579 ast::BinOp::NotEq => todo!(),
580 ast::BinOp::LtInt => todo!(),
581 ast::BinOp::LtEqInt => todo!(),
582 ast::BinOp::LtFloat => todo!(),
583 ast::BinOp::LtEqFloat => todo!(),
584 ast::BinOp::GtEqInt => todo!(),
585 ast::BinOp::GtInt => todo!(),
586 ast::BinOp::GtEqFloat => todo!(),
587 ast::BinOp::GtFloat => todo!(),
588 ast::BinOp::AddInt => Expression::IntAdd { lhs, rhs },
589 ast::BinOp::AddFloat => Expression::FloatAdd { lhs, rhs },
590 ast::BinOp::SubInt => Expression::IntSub { lhs, rhs },
591 ast::BinOp::SubFloat => Expression::FloatSub { lhs, rhs },
592 ast::BinOp::MultInt => Expression::IntMul { lhs, rhs },
593 ast::BinOp::MultFloat => Expression::FloatMul { lhs, rhs },
594 ast::BinOp::DivInt => Expression::IntDiv { lhs, rhs },
595 ast::BinOp::DivFloat => Expression::FloatDiv { lhs, rhs },
596 ast::BinOp::RemainderInt => todo!(),
597 ast::BinOp::Concatenate => todo!(),
598 }
599 }
600 ast::TypedExpr::Case {
601 location: _,
602 type_: _,
603 subjects,
604 clauses,
605 compiled_case,
606 } => {
607 let mut block = vec![];
608
609 let subject_vars: Vec<_> = Iterator::collect(subjects.iter().map(|subject| {
610 let name = self.make_tmp_var();
611 let value = self.translate_expression(subject);
612
613 block.push(Expression::Set {
614 name: name.clone(),
615 value: Box::new(value),
616 });
617
618 return name;
619 }));
620
621 block.push(self.translate_decision(
622 DecisionKind::Case,
623 &subject_vars,
624 clauses,
625 &compiled_case.tree,
626 ));
627
628 Expression::Block(block)
629 }
630 ast::TypedExpr::RecordAccess {
631 location: _,
632 field_start: _,
633 type_: _,
634 label: _,
635 index: _,
636 record: _,
637 } => todo!(),
638 ast::TypedExpr::ModuleSelect {
639 location: _,
640 field_start: _,
641 type_: _,
642 label: _,
643 module_name: _,
644 module_alias: _,
645 constructor: _,
646 } => todo!(),
647 ast::TypedExpr::Tuple {
648 location: _,
649 type_: _,
650 elements: _,
651 } => todo!(),
652 ast::TypedExpr::TupleIndex {
653 location: _,
654 type_: _,
655 index: _,
656 tuple: _,
657 } => todo!(),
658 ast::TypedExpr::Todo {
659 location: _,
660 message: _,
661 kind: _,
662 type_: _,
663 } => todo!(),
664 ast::TypedExpr::Panic {
665 location: _,
666 message: _,
667 type_: _,
668 } => todo!(),
669 ast::TypedExpr::Echo {
670 location: _,
671 type_: _,
672 expression: _,
673 message: _,
674 } => todo!(),
675 ast::TypedExpr::BitArray {
676 location: _,
677 type_: _,
678 segments: _,
679 } => todo!(),
680 ast::TypedExpr::RecordUpdate {
681 location: _,
682 type_: _,
683 record_assignment: _,
684 constructor: _,
685 arguments: _,
686 } => todo!(),
687 ast::TypedExpr::NegateBool {
688 location: _,
689 value: _,
690 } => todo!(),
691 ast::TypedExpr::NegateInt {
692 location: _,
693 value: _,
694 } => todo!(),
695 ast::TypedExpr::Invalid {
696 location: _,
697 type_: _,
698 } => todo!(),
699 }
700 }
701
702 fn translate_assignment(&mut self, assignment: &ast::TypedAssignment) -> Expression {
703 let mut block = vec![];
704
705 let value_var = self.make_tmp_var();
706 let value = self.translate_expression(&assignment.value);
707
708 block.push(Expression::Set {
709 name: value_var.clone(),
710 value: Box::new(value),
711 });
712
713 block.push(self.translate_decision(
714 DecisionKind::Let,
715 &[value_var.clone()],
716 &[],
717 &assignment.compiled_case.tree,
718 ));
719
720 block.push(Expression::Var(value_var));
721
722 Expression::Block(block)
723 }
724
725 fn translate_decision(
726 &mut self,
727 kind: DecisionKind,
728 subjects: &[Var],
729 clauses: &[ast::TypedClause],
730 decision: &exhaustiveness::Decision,
731 ) -> Expression {
732 match decision {
733 exhaustiveness::Decision::Run { body } => {
734 let mut block = vec![];
735
736 for (binding, value) in &body.bindings {
737 let binding = self.make_var(binding.clone());
738
739 block.push(self.translate_binding(subjects, binding.clone(), value));
740 }
741
742 if kind == DecisionKind::Case {
743 block.push(self.translate_expression(&clauses[body.clause_index].then));
744 }
745
746 Expression::Block(block)
747 }
748 exhaustiveness::Decision::Guard {
749 guard,
750 if_true,
751 if_false,
752 } => {
753 let mut block = vec![];
754
755 let guard = clauses[*guard]
756 .guard
757 .as_ref()
758 .expect("expected clause to have a guard");
759
760 let referenced_in_guard = guard.referenced_variables();
761
762 let (guard_bindings, if_true_bindings): (Vec<_>, Vec<_>) = if_true
763 .bindings
764 .iter()
765 .partition(|(binding, _)| referenced_in_guard.contains(binding));
766
767 for (binding, value) in guard_bindings {
768 let binding = self.make_var(binding.clone());
769
770 block.push(self.translate_binding(subjects, binding, value));
771 }
772
773 let cond = self.translate_guard(guard);
774
775 let if_true = {
776 let mut block = vec![];
777
778 for (binding, value) in if_true_bindings {
779 let binding = self.make_var(binding.clone());
780
781 block.push(self.translate_binding(subjects, binding.clone(), value));
782 }
783
784 block.push(self.translate_expression(&clauses[if_true.clause_index].then));
785 block
786 };
787
788 let if_false = self.translate_decision(kind, subjects, clauses, if_false);
789
790 block.push(Expression::If {
791 cond: Box::new(cond),
792 then: Box::new(Expression::Block(if_true)),
793 else_: Box::new(if_false),
794 });
795
796 Expression::Block(block)
797 }
798 exhaustiveness::Decision::Switch {
799 var,
800 choices,
801 fallback,
802 fallback_check: _,
803 } => {
804 let fallback = self.translate_decision(kind, subjects, clauses, fallback);
805
806 DoubleEndedIterator::rfold(choices.iter(), fallback, |fallback, (check, then)| {
807 Expression::If {
808 cond: Box::new(self.translate_runtime_check(
809 check,
810 Expression::Var(subjects[var.id].clone()),
811 )),
812 then: Box::new(self.translate_decision(kind, subjects, clauses, then)),
813 else_: Box::new(fallback),
814 }
815 })
816 }
817 exhaustiveness::Decision::Fail => todo!(),
818 }
819 }
820
821 fn translate_guard(&mut self, guard: &ast::TypedClauseGuard) -> Expression {
822 match guard {
823 ast::ClauseGuard::Block {
824 location: _,
825 value: _,
826 } => todo!(),
827 ast::ClauseGuard::Equals {
828 location: _,
829 left,
830 right,
831 } => {
832 let lhs = self.translate_guard(left);
833 let rhs = self.translate_guard(right);
834
835 Expression::Equals {
836 lhs: Box::new(lhs),
837 rhs: Box::new(rhs),
838 }
839 }
840 ast::ClauseGuard::NotEquals {
841 location: _,
842 left: _,
843 right: _,
844 } => todo!(),
845 ast::ClauseGuard::GtInt {
846 location: _,
847 left: _,
848 right: _,
849 } => todo!(),
850 ast::ClauseGuard::GtEqInt {
851 location: _,
852 left: _,
853 right: _,
854 } => todo!(),
855 ast::ClauseGuard::LtInt {
856 location: _,
857 left: _,
858 right: _,
859 } => todo!(),
860 ast::ClauseGuard::LtEqInt {
861 location: _,
862 left: _,
863 right: _,
864 } => todo!(),
865 ast::ClauseGuard::GtFloat {
866 location: _,
867 left: _,
868 right: _,
869 } => todo!(),
870 ast::ClauseGuard::GtEqFloat {
871 location: _,
872 left: _,
873 right: _,
874 } => todo!(),
875 ast::ClauseGuard::LtFloat {
876 location: _,
877 left: _,
878 right: _,
879 } => todo!(),
880 ast::ClauseGuard::LtEqFloat {
881 location: _,
882 left: _,
883 right: _,
884 } => todo!(),
885 ast::ClauseGuard::AddInt {
886 location: _,
887 left,
888 right,
889 } => Expression::IntAdd {
890 lhs: Box::new(self.translate_guard(left)),
891 rhs: Box::new(self.translate_guard(right)),
892 },
893 ast::ClauseGuard::AddFloat {
894 location: _,
895 left,
896 right,
897 } => Expression::FloatAdd {
898 lhs: Box::new(self.translate_guard(left)),
899 rhs: Box::new(self.translate_guard(right)),
900 },
901 ast::ClauseGuard::SubInt {
902 location: _,
903 left,
904 right,
905 } => Expression::IntSub {
906 lhs: Box::new(self.translate_guard(left)),
907 rhs: Box::new(self.translate_guard(right)),
908 },
909 ast::ClauseGuard::SubFloat {
910 location: _,
911 left,
912 right,
913 } => Expression::FloatSub {
914 lhs: Box::new(self.translate_guard(left)),
915 rhs: Box::new(self.translate_guard(right)),
916 },
917 ast::ClauseGuard::MultInt {
918 location: _,
919 left,
920 right,
921 } => Expression::IntMul {
922 lhs: Box::new(self.translate_guard(left)),
923 rhs: Box::new(self.translate_guard(right)),
924 },
925 ast::ClauseGuard::MultFloat {
926 location: _,
927 left,
928 right,
929 } => Expression::FloatMul {
930 lhs: Box::new(self.translate_guard(left)),
931 rhs: Box::new(self.translate_guard(right)),
932 },
933 ast::ClauseGuard::DivInt {
934 location: _,
935 left,
936 right,
937 } => Expression::IntDiv {
938 lhs: Box::new(self.translate_guard(left)),
939 rhs: Box::new(self.translate_guard(right)),
940 },
941 ast::ClauseGuard::DivFloat {
942 location: _,
943 left,
944 right,
945 } => Expression::FloatDiv {
946 lhs: Box::new(self.translate_guard(left)),
947 rhs: Box::new(self.translate_guard(right)),
948 },
949 ast::ClauseGuard::RemainderInt {
950 location: _,
951 left: _,
952 right: _,
953 } => todo!(),
954 ast::ClauseGuard::Or {
955 location: _,
956 left: _,
957 right: _,
958 } => todo!(),
959 ast::ClauseGuard::And {
960 location: _,
961 left: _,
962 right: _,
963 } => todo!(),
964 ast::ClauseGuard::Not {
965 location: _,
966 expression: _,
967 } => todo!(),
968 ast::ClauseGuard::Var {
969 location: _,
970 type_: _,
971 name,
972 definition_location: _,
973 } => Expression::Var(self.get_var(name)),
974 ast::ClauseGuard::TupleIndex {
975 location: _,
976 index: _,
977 type_: _,
978 tuple: _,
979 } => todo!(),
980 ast::ClauseGuard::FieldAccess {
981 label_location: _,
982 index: _,
983 label: _,
984 type_: _,
985 container: _,
986 } => todo!(),
987 ast::ClauseGuard::ModuleSelect {
988 location: _,
989 type_: _,
990 label: _,
991 module_name: _,
992 module_alias: _,
993 literal: _,
994 } => todo!(),
995 ast::ClauseGuard::Constant(constant) => self.translate_constant(constant),
996 }
997 }
998
999 fn translate_constant(&mut self, constant: &ast::TypedConstant) -> Expression {
1000 match constant {
1001 ast::Constant::Int {
1002 location: _,
1003 value: _,
1004 int_value,
1005 } => Expression::Int {
1006 value: int_value.clone(),
1007 },
1008 ast::Constant::Float { location: _, value } => Expression::Float {
1009 value: value.clone(),
1010 },
1011 ast::Constant::String {
1012 location: _,
1013 value: _,
1014 } => todo!(),
1015 ast::Constant::Tuple {
1016 location: _,
1017 elements: _,
1018 } => todo!(),
1019 ast::Constant::List {
1020 location: _,
1021 elements: _,
1022 type_: _,
1023 } => todo!(),
1024 ast::Constant::Record {
1025 location: _,
1026 module: _,
1027 name: _,
1028 arguments: _,
1029 tag: _,
1030 type_: _,
1031 field_map: _,
1032 record_constructor: _,
1033 } => todo!(),
1034 ast::Constant::BitArray {
1035 location: _,
1036 segments: _,
1037 } => todo!(),
1038 ast::Constant::Var {
1039 location: _,
1040 module: _,
1041 name: _,
1042 constructor: _,
1043 type_: _,
1044 } => todo!(),
1045 ast::Constant::StringConcatenation {
1046 location: _,
1047 left: _,
1048 right: _,
1049 } => todo!(),
1050 ast::Constant::Invalid {
1051 location: _,
1052 type_: _,
1053 } => todo!(),
1054 }
1055 }
1056
1057 fn translate_binding(
1058 &mut self,
1059 subjects: &[Var],
1060 binding: Var,
1061 value: &exhaustiveness::BoundValue,
1062 ) -> Expression {
1063 let value = match value {
1064 exhaustiveness::BoundValue::Variable(variable) => {
1065 Expression::Var(subjects[variable.id].clone())
1066 }
1067 exhaustiveness::BoundValue::LiteralString(_eco_string) => todo!(),
1068 exhaustiveness::BoundValue::LiteralInt(big_int) => Expression::Int {
1069 value: big_int.clone(),
1070 },
1071 exhaustiveness::BoundValue::LiteralFloat(_eco_string) => todo!(),
1072 exhaustiveness::BoundValue::BitArraySlice {
1073 bit_array: _,
1074 read_action: _,
1075 } => todo!(),
1076 };
1077
1078 Expression::Set {
1079 name: binding,
1080 value: Box::new(value),
1081 }
1082 }
1083
1084 fn translate_runtime_check(
1085 &mut self,
1086 check: &exhaustiveness::RuntimeCheck,
1087 against: Expression,
1088 ) -> Expression {
1089 match check {
1090 exhaustiveness::RuntimeCheck::Int { value } => {
1091 let value = parse::parse_int_value(&value).expect("unable to parse integer value");
1092
1093 Expression::Equals {
1094 lhs: Box::new(against),
1095 rhs: Box::new(Expression::Int { value }),
1096 }
1097 }
1098 exhaustiveness::RuntimeCheck::Float { value: _ } => todo!(),
1099 exhaustiveness::RuntimeCheck::String { value: _ } => todo!(),
1100 exhaustiveness::RuntimeCheck::StringPrefix { prefix: _, rest: _ } => todo!(),
1101 exhaustiveness::RuntimeCheck::Tuple {
1102 size: _,
1103 elements: _,
1104 } => todo!(),
1105 exhaustiveness::RuntimeCheck::BitArray { test: _ } => todo!(),
1106 exhaustiveness::RuntimeCheck::Variant {
1107 match_: _,
1108 index: _,
1109 labels: _,
1110 fields: _,
1111 } => todo!(),
1112 exhaustiveness::RuntimeCheck::NonEmptyList { first: _, rest: _ } => todo!(),
1113 exhaustiveness::RuntimeCheck::EmptyList => todo!(),
1114 }
1115 }
1116}
1117
1118#[cfg(test)]
1119mod tests {
1120 use std::collections::{HashMap, HashSet};
1121
1122 use super::*;
1123 use crate::analyse::TargetSupport;
1124 use crate::build::{Origin, Target};
1125 use crate::config::PackageConfig;
1126 use crate::line_numbers::LineNumbers;
1127 use crate::parse::parse_module;
1128 use crate::type_::PRELUDE_MODULE_NAME;
1129 use crate::uid::UniqueIdGenerator;
1130 use crate::warning::{TypeWarningEmitter, WarningEmitter};
1131 use camino::Utf8PathBuf;
1132
1133 fn compile_module(src: &str) -> ast::TypedModule {
1134 use crate::type_::build_prelude;
1135 let parsed = parse_module(Utf8PathBuf::from("test/path"), src, &WarningEmitter::null())
1136 .expect("syntax error");
1137 let ast = parsed.module;
1138 let ids = UniqueIdGenerator::new();
1139 let mut config = PackageConfig::default();
1140 config.name = "thepackage".into();
1141 let mut modules = im::HashMap::new();
1142 let _ = modules.insert(PRELUDE_MODULE_NAME.into(), build_prelude(&ids));
1143 let line_numbers = LineNumbers::new(src);
1144
1145 crate::analyse::ModuleAnalyzerConstructor::<()> {
1146 target: Target::Erlang,
1147 ids: &ids,
1148 origin: Origin::Src,
1149 importable_modules: &modules,
1150 warnings: &TypeWarningEmitter::null(),
1151 direct_dependencies: &HashMap::new(),
1152 dev_dependencies: &HashSet::new(),
1153 target_support: TargetSupport::Enforced,
1154 package_config: &config,
1155 }
1156 .infer_module(ast, line_numbers, "".into())
1157 .expect("should successfully infer")
1158 }
1159
1160 fn translate(src: &str) -> Module {
1161 let typed_module = compile_module(src);
1162
1163 Translator::default().translate(&typed_module)
1164 }
1165
1166 #[test]
1167 fn translates_samples() {
1168 insta::assert_debug_snapshot!(translate(
1169 r#"pub fn add(lhs: Int, rhs: Int) -> Int {
1170 lhs + rhs
1171 }"#
1172 ));
1173
1174 insta::assert_debug_snapshot!(translate(
1175 r#"pub fn some_case(n: Int) -> Int {
1176 case n {
1177 0 -> 2
1178 1 -> 4
1179 _ -> 6
1180 }
1181 }"#
1182 ));
1183
1184 insta::assert_debug_snapshot!(translate(
1185 r#"pub fn some_case(n: Int) -> Int {
1186 case n {
1187 y if y == 0 -> 2
1188 1 -> 4
1189 _ -> 6
1190 }
1191 }"#
1192 ));
1193
1194 insta::assert_debug_snapshot!(translate(
1195 r#"pub fn fib(n: Int) -> Int {
1196 case n {
1197 0 -> 0
1198 1 -> 1
1199 _ -> fib(n - 1) + fib(n - 2)
1200 }
1201 }"#
1202 ));
1203
1204 insta::assert_debug_snapshot!(translate(
1205 r#"pub fn maths() {
1206 let _ = 1 + 0
1207 let _ = 2 - 1
1208 let _ = 3 * 2
1209 let _ = 4 / 3
1210
1211 let _ = 1.0 +. 0.0
1212 let _ = 2.0 -. 1.0
1213 let _ = 3.0 *. 2.0
1214 let _ = 4.0 /. 3.0
1215 }"#
1216 ));
1217 }
1218}