Fork of daniellemaywood.uk/gleam — Wasm codegen work
1

Configure Feed

Select the types of activity you want to include in your feed.

1use std::{collections::HashMap, ops::Deref}; 2 3use ecow::{EcoString, eco_format}; 4use num_bigint::BigInt; 5use vec1::Vec1; 6 7use crate::{ 8 cranelift::mir::{ast::*, visit::Visit}, 9 exhaustiveness, parse, type_, 10}; 11 12pub mod ast; 13pub mod lower; 14pub mod visit; 15 16struct FlattenBlockPass; 17 18impl<'mir, T> Visit<'mir, T> for FlattenBlockPass { 19 fn visit_expression(&mut self, expression: &'mir mut Expression<T>) { 20 visit::visit_expression(self, expression); 21 22 if let Expression::Block(inner) = expression 23 && inner.len() == 1 24 { 25 *expression = inner.pop().expect("block should've been poppable"); 26 } 27 } 28 29 fn visit_expression_block(&mut self, expressions: &'mir mut Vec<Expression<T>>) { 30 visit::visit_expression_block(self, expressions); 31 32 *expressions = std::mem::take(expressions) 33 .into_iter() 34 .flat_map(|expr| match expr { 35 Expression::Block(inner) => inner, 36 _ => vec![expr], 37 }) 38 .collect(); 39 } 40} 41 42struct RemoveUnusedPass; 43 44impl<'mir, T> Visit<'mir, T> for RemoveUnusedPass { 45 fn visit_expression_block(&mut self, expressions: &'mir mut Vec<Expression<T>>) { 46 visit::visit_expression_block(self, expressions); 47 48 let last_index = expressions.len() - 1; 49 50 *expressions = std::mem::take(expressions) 51 .into_iter() 52 .enumerate() 53 .filter_map(|(index, expr)| match expr { 54 Expression::Var { .. } 55 | Expression::FunctionRef { .. } 56 | Expression::Int { .. } 57 | Expression::Float { .. } 58 | Expression::Bool { .. } 59 | Expression::String { .. } 60 if index != last_index => 61 { 62 None 63 } 64 65 _ => Some(expr), 66 }) 67 .collect(); 68 } 69} 70 71#[derive(Default)] 72struct RemoveUselessSetPass { 73 replacements: HashMap<EcoString, EcoString>, 74} 75 76impl<'mir, T> Visit<'mir, T> for RemoveUselessSetPass { 77 fn visit_expression(&mut self, expression: &'mir mut Expression<T>) { 78 visit::visit_expression(self, expression); 79 80 if let Expression::Set { name, value } = expression { 81 if let Expression::Var(var) = value.as_ref() { 82 _ = self 83 .replacements 84 .insert(name.name.clone(), var.name.clone()); 85 86 _ = var; 87 _ = name; 88 } 89 } 90 } 91 92 fn visit_expression_block(&mut self, expressions: &'mir mut Vec<Expression<T>>) { 93 visit::visit_expression_block(self, expressions); 94 95 *expressions = std::mem::take(expressions) 96 .into_iter() 97 .filter_map(|expr| match expr { 98 Expression::Set { name, value: _ } 99 if self.replacements.contains_key(&name.name) => 100 { 101 None 102 } 103 _ => Some(expr), 104 }) 105 .collect(); 106 } 107 108 fn visit_expression_var(&mut self, var: &'mir mut Var<T>) { 109 if let Some(replacement) = self.replacements.get(&var.name) { 110 var.name = replacement.clone(); 111 } 112 } 113} 114 115#[derive(Debug)] 116pub struct Translator<'ast> { 117 module: &'ast crate::ast::TypedModule, 118} 119 120impl<'ast> Translator<'ast> { 121 pub fn new(module: &'ast crate::ast::TypedModule) -> Self { 122 Self { module } 123 } 124 125 pub fn translate(self) -> Module<IncompleteType> { 126 let mut module = Module { 127 name: self.module.name.clone(), 128 functions: vec![], 129 }; 130 131 for definition in &self.module.definitions { 132 match definition { 133 crate::ast::Definition::Function(function) => { 134 module.functions.push(self.translate_function(function)); 135 } 136 crate::ast::Definition::TypeAlias(_type_alias) => todo!(), 137 crate::ast::Definition::CustomType(custom_type) => { 138 module 139 .functions 140 .append(&mut self.translate_custom_type(custom_type)); 141 } 142 crate::ast::Definition::Import(_import) => todo!(), 143 crate::ast::Definition::ModuleConstant(_module_constant) => todo!(), 144 } 145 } 146 147 FlattenBlockPass.visit_module(&mut module); 148 RemoveUnusedPass.visit_module(&mut module); 149 RemoveUselessSetPass::default().visit_module(&mut module); 150 151 module 152 } 153 154 fn translate_custom_type( 155 &self, 156 custom_type: &crate::ast::TypedCustomType, 157 ) -> Vec<Function<IncompleteType>> { 158 let mut functions = vec![]; 159 160 for (index, constructor) in custom_type.constructors.iter().enumerate() { 161 let parameters = constructor 162 .arguments 163 .iter() 164 .enumerate() 165 .map(|(index, argument)| FunctionParameter { 166 name: Some(eco_format!("_{index}")), 167 type_: Self::translate_type(&argument.type_), 168 }) 169 .collect(); 170 171 functions.push(Function::<IncompleteType> { 172 name: constructor.name.clone(), 173 return_type: IncompleteType::Struct { elements: vec![] }, 174 parameters, 175 body: Expression::Block(vec![Expression::<IncompleteType>::Struct { 176 tag: Some(index as u32), 177 items: constructor 178 .arguments 179 .iter() 180 .enumerate() 181 .map(|(index, argument)| { 182 Expression::Var(Var { 183 name: eco_format!("_{index}"), 184 type_: Self::translate_type(&argument.type_), 185 }) 186 }) 187 .collect(), 188 type_: IncompleteType::Struct { elements: vec![] }, 189 }]), 190 }); 191 } 192 193 functions 194 } 195 196 fn translate_function(&self, function: &crate::ast::TypedFunction) -> Function<IncompleteType> { 197 let (_, name) = function.name.clone().expect("function should have a name"); 198 199 let return_type = Self::translate_type(&function.return_type); 200 201 let mut translator = BodyTranslator::default(); 202 let arguments: Vec<_> = Iterator::collect(function.arguments.iter().map(|argument| { 203 argument.get_variable_name().map(|name| { 204 translator.make_var(name.clone(), Self::translate_type(&argument.type_)) 205 }) 206 })); 207 208 let parameters = Iterator::collect(function.arguments.iter().zip(arguments.iter()).map( 209 |(argument, name)| { 210 let type_ = Self::translate_type(&argument.type_); 211 212 FunctionParameter { 213 name: name.clone().map(|name| name.name), 214 type_, 215 } 216 }, 217 )); 218 219 let body = translator.translate(&function.body); 220 221 Function { 222 name, 223 body, 224 return_type, 225 parameters, 226 } 227 } 228 229 fn translate_type(type_: &type_::Type) -> IncompleteType { 230 match type_ { 231 type_::Type::Named { 232 publicity: _, 233 package: _, 234 module, 235 name, 236 arguments, 237 inferred_variant: _, 238 } => match (module.as_str(), name.as_str()) { 239 ("gleam", "Int") => IncompleteType::Int, 240 ("gleam", "Float") => IncompleteType::Float, 241 ("gleam", "Bool") => IncompleteType::Bool, 242 ("gleam", "String") => IncompleteType::String, 243 ("gleam", "List") => { 244 let list_type = Self::translate_type(&arguments[0]); 245 246 IncompleteType::List(Box::new(list_type)) 247 } 248 (_, _) => IncompleteType::Struct { 249 elements: arguments 250 .iter() 251 .map(|type_| Self::translate_type(type_)) 252 .collect(), 253 }, 254 }, 255 type_::Type::Fn { arguments, return_ } => IncompleteType::Func { 256 arguments: arguments 257 .iter() 258 .map(|arg| Self::translate_type(arg)) 259 .collect(), 260 returns: Box::new(Self::translate_type(return_)), 261 }, 262 type_::Type::Var { type_ } => match type_.borrow().deref() { 263 type_::TypeVar::Link { type_ } => Self::translate_type(type_), 264 type_::TypeVar::Unbound { id } | type_::TypeVar::Generic { id } => { 265 IncompleteType::Generic { id: *id } 266 } 267 }, 268 type_::Type::Tuple { elements } => IncompleteType::Struct { 269 elements: elements 270 .iter() 271 .map(|elem| Self::translate_type(elem)) 272 .collect(), 273 }, 274 } 275 } 276} 277 278#[derive(Debug, Default)] 279pub struct BodyTranslator { 280 variables: HashMap<EcoString, Var<IncompleteType>>, 281 variable_count: usize, 282 283 decision_map: HashMap<usize, Var<IncompleteType>>, 284} 285 286#[derive(Debug, Clone, Copy, PartialEq, Eq)] 287enum DecisionKind { 288 Case, 289 Let, 290} 291 292impl BodyTranslator { 293 fn make_tmp_var(&mut self, type_: IncompleteType) -> Var<IncompleteType> { 294 self.make_var("_tmp".into(), type_) 295 } 296 297 fn make_var(&mut self, name: EcoString, type_: IncompleteType) -> Var<IncompleteType> { 298 self.variable_count += 1; 299 300 let entry = eco_format!("{}${}", name.clone(), self.variable_count); 301 let var = Var { 302 name: entry, 303 type_: type_, 304 }; 305 306 _ = self.variables.insert(name.clone(), var.clone()); 307 308 var 309 } 310 311 fn get_var(&mut self, name: &EcoString) -> Var<IncompleteType> { 312 self.variables 313 .get(name) 314 .cloned() 315 .unwrap_or_else(|| panic!("variable '{name}' not found")) 316 } 317 318 fn in_var_scope<T>(&mut self, func: impl Fn(&mut Self) -> T) -> T { 319 let snapshot = self.variables.clone(); 320 let result = func(self); 321 self.variables = snapshot; 322 result 323 } 324 325 fn in_decision_scope<T>(&mut self, func: impl Fn(&mut Self) -> T) -> T { 326 let snapshot = self.decision_map.clone(); 327 let result = func(self); 328 self.decision_map = snapshot; 329 result 330 } 331 332 fn translate(mut self, body: &Vec1<crate::ast::TypedStatement>) -> Expression<IncompleteType> { 333 self.translate_statements(body) 334 } 335 336 fn translate_statements( 337 &mut self, 338 statements: &[crate::ast::TypedStatement], 339 ) -> Expression<IncompleteType> { 340 Expression::Block(Iterator::collect( 341 statements.iter().map(|stmt| self.translate_statement(stmt)), 342 )) 343 } 344 345 fn translate_statement( 346 &mut self, 347 statement: &crate::ast::TypedStatement, 348 ) -> Expression<IncompleteType> { 349 match statement { 350 crate::ast::Statement::Expression(expression) => self.translate_expression(expression), 351 crate::ast::Statement::Assignment(assignment) => self.translate_assignment(assignment), 352 crate::ast::Statement::Use(_) => todo!(), 353 crate::ast::Statement::Assert(_) => todo!(), 354 } 355 } 356 357 fn translate_expression( 358 &mut self, 359 expression: &crate::ast::TypedExpr, 360 ) -> Expression<IncompleteType> { 361 match expression { 362 crate::ast::TypedExpr::Int { 363 location: _, 364 type_: _, 365 value: _, 366 int_value, 367 } => Expression::Int { 368 value: int_value.clone(), 369 }, 370 crate::ast::TypedExpr::Float { 371 location: _, 372 type_: _, 373 value, 374 } => Expression::Float { 375 value: value.clone(), 376 }, 377 crate::ast::TypedExpr::String { 378 location: _, 379 type_: _, 380 value, 381 } => Expression::String { 382 value: value.clone(), 383 }, 384 crate::ast::TypedExpr::Block { 385 location: _, 386 statements, 387 } => self.in_var_scope(|this| this.translate_statements(statements)), 388 crate::ast::TypedExpr::Pipeline { 389 location: _, 390 first_value, 391 assignments, 392 finally, 393 finally_kind: _, 394 } => { 395 let mut block = vec![]; 396 397 let value = self.translate_expression(&first_value.value); 398 block.push(Expression::Set { 399 name: self.make_var( 400 first_value.name.clone(), 401 Translator::translate_type(&first_value.type_()), 402 ), 403 value: Box::new(value), 404 }); 405 406 for (assignment, _) in assignments { 407 let value = self.translate_expression(&assignment.value); 408 block.push(Expression::Set { 409 name: self.make_var( 410 assignment.name.clone(), 411 Translator::translate_type(&assignment.value.type_()), 412 ), 413 value: Box::new(value), 414 }); 415 } 416 417 block.push(self.translate_expression(finally)); 418 419 Expression::Block(block) 420 } 421 crate::ast::TypedExpr::Var { 422 location: _, 423 constructor, 424 name, 425 } => match &constructor.variant { 426 type_::ValueConstructorVariant::LocalVariable { 427 location: _, 428 origin: _, 429 } => Expression::Var(self.get_var(name)), 430 type_::ValueConstructorVariant::ModuleConstant { 431 documentation: _, 432 location: _, 433 module: _, 434 name: _, 435 literal: _, 436 implementations: _, 437 } => todo!(), 438 type_::ValueConstructorVariant::LocalConstant { literal: _ } => todo!(), 439 type_::ValueConstructorVariant::ModuleFn { 440 name, 441 field_map: _, 442 module, 443 arity, 444 location: _, 445 documentation: _, 446 implementations: _, 447 external_erlang: _, 448 external_javascript: _, 449 external_cranelift: _, 450 purity: _, 451 } => Expression::FunctionRef { 452 module: module.clone(), 453 name: name.clone(), 454 arity: *arity, 455 type_: Translator::translate_type(&constructor.type_), 456 }, 457 type_::ValueConstructorVariant::Record { 458 name, 459 arity, 460 field_map: _, 461 location: _, 462 module, 463 variants_count: _, 464 variant_index: _, 465 documentation: _, 466 } => match (module.as_str(), name.as_str()) { 467 ("gleam", "True") => Expression::Bool { value: true }, 468 ("gleam", "False") => Expression::Bool { value: false }, 469 (_, _) => Expression::FunctionRef { 470 module: module.clone(), 471 name: name.clone(), 472 arity: usize::from(*arity), 473 type_: Translator::translate_type(&constructor.type_), 474 }, 475 }, 476 }, 477 crate::ast::TypedExpr::Fn { 478 location: _, 479 type_: _, 480 kind: _, 481 arguments: _, 482 body: _, 483 return_annotation: _, 484 purity: _, 485 } => todo!(), 486 crate::ast::TypedExpr::List { 487 location: _, 488 type_, 489 elements, 490 tail, 491 } => { 492 let items = elements 493 .iter() 494 .map(|element| self.translate_expression(element)) 495 .collect(); 496 497 let tail = tail 498 .as_ref() 499 .map(|tail| Box::new(self.translate_expression(tail))); 500 501 Expression::List { 502 items, 503 tail, 504 type_: Translator::translate_type(type_), 505 } 506 } 507 crate::ast::TypedExpr::Call { 508 location: _, 509 type_, 510 fun, 511 arguments, 512 } => { 513 let target = self.translate_expression(fun); 514 let args = arguments 515 .iter() 516 .map(|arg| self.translate_expression(&arg.value)) 517 .collect(); 518 519 Expression::Call { 520 target: Box::new(target), 521 args, 522 type_: Translator::translate_type(type_), 523 } 524 } 525 crate::ast::TypedExpr::BinOp { 526 location: _, 527 type_: _, 528 name, 529 name_location: _, 530 left, 531 right, 532 } => { 533 let lhs = Box::new(self.translate_expression(left)); 534 let rhs = Box::new(self.translate_expression(right)); 535 536 match name { 537 crate::ast::BinOp::And => Expression::If { 538 cond: lhs, 539 then: rhs, 540 else_: Box::new(Expression::Bool { value: false }), 541 }, 542 crate::ast::BinOp::Or => Expression::If { 543 cond: lhs, 544 then: Box::new(Expression::Bool { value: true }), 545 else_: rhs, 546 }, 547 crate::ast::BinOp::Eq => Expression::Equals { lhs, rhs }, 548 crate::ast::BinOp::NotEq => Expression::NotEquals { lhs, rhs }, 549 crate::ast::BinOp::LtInt => Expression::IntLt { lhs, rhs }, 550 crate::ast::BinOp::LtEqInt => Expression::IntLtEq { lhs, rhs }, 551 crate::ast::BinOp::LtFloat => Expression::FloatLt { lhs, rhs }, 552 crate::ast::BinOp::LtEqFloat => Expression::FloatLtEq { lhs, rhs }, 553 crate::ast::BinOp::GtEqInt => Expression::IntGtEq { lhs, rhs }, 554 crate::ast::BinOp::GtInt => Expression::IntGt { lhs, rhs }, 555 crate::ast::BinOp::GtEqFloat => Expression::FloatGtEq { lhs, rhs }, 556 crate::ast::BinOp::GtFloat => Expression::FloatGt { lhs, rhs }, 557 crate::ast::BinOp::AddInt => Expression::IntAdd { lhs, rhs }, 558 crate::ast::BinOp::AddFloat => Expression::FloatAdd { lhs, rhs }, 559 crate::ast::BinOp::SubInt => Expression::IntSub { lhs, rhs }, 560 crate::ast::BinOp::SubFloat => Expression::FloatSub { lhs, rhs }, 561 crate::ast::BinOp::MultInt => Expression::IntMul { lhs, rhs }, 562 crate::ast::BinOp::MultFloat => Expression::FloatMul { lhs, rhs }, 563 crate::ast::BinOp::DivInt => Expression::IntDiv { lhs, rhs }, 564 crate::ast::BinOp::DivFloat => Expression::FloatDiv { lhs, rhs }, 565 crate::ast::BinOp::RemainderInt => Expression::IntRem { lhs, rhs }, 566 crate::ast::BinOp::Concatenate => Expression::StringConcat { lhs, rhs }, 567 } 568 } 569 crate::ast::TypedExpr::Case { 570 location: _, 571 type_: _, 572 subjects, 573 clauses, 574 compiled_case, 575 } => self.in_decision_scope(move |this| { 576 let mut block = vec![]; 577 578 for (index, subject) in subjects.iter().enumerate() { 579 let name = this.make_tmp_var(Translator::translate_type(&subject.type_())); 580 let value = this.translate_expression(subject); 581 582 _ = this.decision_map.insert(index, name.clone()); 583 584 block.push(Expression::Set { 585 name: name.clone(), 586 value: Box::new(value), 587 }); 588 } 589 590 block.push(this.translate_decision( 591 DecisionKind::Case, 592 clauses, 593 &compiled_case.tree, 594 )); 595 596 Expression::Block(block) 597 }), 598 crate::ast::TypedExpr::RecordAccess { 599 location: _, 600 field_start: _, 601 type_, 602 label: _, 603 index, 604 record, 605 } => Expression::StructAccess { 606 value: Box::new(self.translate_expression(record)), 607 index: *index, 608 type_: Translator::translate_type(type_), 609 }, 610 crate::ast::TypedExpr::ModuleSelect { 611 location: _, 612 field_start: _, 613 type_: _, 614 label: _, 615 module_name: _, 616 module_alias: _, 617 constructor: _, 618 } => todo!(), 619 crate::ast::TypedExpr::Tuple { 620 location: _, 621 type_, 622 elements, 623 } => Expression::Struct { 624 tag: None, 625 items: elements 626 .iter() 627 .map(|element| self.translate_expression(element)) 628 .collect(), 629 type_: Translator::translate_type(type_), 630 }, 631 crate::ast::TypedExpr::TupleIndex { 632 location: _, 633 type_, 634 index, 635 tuple, 636 } => Expression::StructAccess { 637 value: Box::new(self.translate_expression(tuple)), 638 index: *index, 639 type_: Translator::translate_type(type_), 640 }, 641 crate::ast::TypedExpr::Todo { 642 location: _, 643 message: _, 644 kind: _, 645 type_: _, 646 } => todo!(), 647 crate::ast::TypedExpr::Panic { 648 location: _, 649 message: _, 650 type_: _, 651 } => todo!(), 652 crate::ast::TypedExpr::Echo { 653 location: _, 654 type_: _, 655 expression: _, 656 message: _, 657 } => todo!(), 658 crate::ast::TypedExpr::BitArray { 659 location: _, 660 type_: _, 661 segments: _, 662 } => todo!(), 663 crate::ast::TypedExpr::RecordUpdate { 664 location: _, 665 type_, 666 record_assignment, 667 constructor, 668 arguments, 669 } => { 670 let mut block = vec![]; 671 672 if let Some(assignment) = record_assignment { 673 block.push(self.translate_assignment(assignment)); 674 } 675 676 let constructor = self.translate_expression(constructor); 677 let arguments = arguments 678 .iter() 679 .map(|argument| self.translate_expression(&argument.value)) 680 .collect(); 681 682 block.push(Expression::Call { 683 target: Box::new(constructor), 684 args: arguments, 685 type_: Translator::translate_type(type_), 686 }); 687 688 Expression::Block(block) 689 } 690 crate::ast::TypedExpr::NegateBool { location: _, value } => Expression::Equals { 691 lhs: Box::new(self.translate_expression(value)), 692 rhs: Box::new(Expression::Bool { value: false }), 693 }, 694 crate::ast::TypedExpr::NegateInt { location: _, value } => Expression::IntSub { 695 lhs: Box::new(Expression::Int { 696 value: BigInt::from(0), 697 }), 698 rhs: Box::new(self.translate_expression(value)), 699 }, 700 crate::ast::TypedExpr::Invalid { 701 location: _, 702 type_: _, 703 } => todo!(), 704 } 705 } 706 707 fn translate_assignment( 708 &mut self, 709 assignment: &crate::ast::TypedAssignment, 710 ) -> Expression<IncompleteType> { 711 self.in_decision_scope(|this| { 712 let mut block = vec![]; 713 714 let value_var = 715 this.make_tmp_var(Translator::translate_type(&assignment.value.type_())); 716 let value = this.translate_expression(&assignment.value); 717 718 block.push(Expression::Set { 719 name: value_var.clone(), 720 value: Box::new(value), 721 }); 722 723 _ = this.decision_map.insert(0, value_var.clone()); 724 725 block.push(this.translate_decision( 726 DecisionKind::Let, 727 &[], 728 &assignment.compiled_case.tree, 729 )); 730 731 block.push(Expression::Var(value_var)); 732 733 Expression::Block(block) 734 }) 735 } 736 737 fn translate_bound_value_type(&mut self, value: &exhaustiveness::BoundValue) -> IncompleteType { 738 match value { 739 exhaustiveness::BoundValue::Variable(variable) => { 740 Translator::translate_type(&variable.type_) 741 } 742 exhaustiveness::BoundValue::LiteralString(_) => IncompleteType::String, 743 exhaustiveness::BoundValue::LiteralInt(_) => IncompleteType::Int, 744 exhaustiveness::BoundValue::LiteralFloat(_) => IncompleteType::Float, 745 exhaustiveness::BoundValue::BitArraySlice { 746 bit_array: _, 747 read_action: _, 748 } => todo!(), 749 } 750 } 751 752 fn translate_decision( 753 &mut self, 754 kind: DecisionKind, 755 clauses: &[crate::ast::TypedClause], 756 decision: &exhaustiveness::Decision, 757 ) -> Expression<IncompleteType> { 758 match decision { 759 exhaustiveness::Decision::Run { body } => { 760 let mut block = vec![]; 761 762 for (binding, value) in &body.bindings { 763 let binding_type = self.translate_bound_value_type(value); 764 let binding = self.make_var(binding.clone(), binding_type); 765 766 block.push(self.translate_binding(binding.clone(), value)); 767 } 768 769 if kind == DecisionKind::Case { 770 block.push(self.translate_expression(&clauses[body.clause_index].then)); 771 } 772 773 Expression::Block(block) 774 } 775 exhaustiveness::Decision::Guard { 776 guard, 777 if_true, 778 if_false, 779 } => { 780 let mut block = vec![]; 781 782 let guard = clauses[*guard] 783 .guard 784 .as_ref() 785 .expect("expected clause to have a guard"); 786 787 let referenced_in_guard = guard.referenced_variables(); 788 789 let (guard_bindings, if_true_bindings): (Vec<_>, Vec<_>) = if_true 790 .bindings 791 .iter() 792 .partition(|(binding, _)| referenced_in_guard.contains(binding)); 793 794 for (binding, value) in guard_bindings { 795 let binding_type = self.translate_bound_value_type(value); 796 let binding = self.make_var(binding.clone(), binding_type); 797 798 block.push(self.translate_binding(binding, value)); 799 } 800 801 let cond = self.translate_guard(guard); 802 803 let if_true = { 804 let mut block = vec![]; 805 806 for (binding, value) in if_true_bindings { 807 let binding_type = self.translate_bound_value_type(value); 808 let binding = self.make_var(binding.clone(), binding_type); 809 810 block.push(self.translate_binding(binding.clone(), value)); 811 } 812 813 block.push(self.translate_expression(&clauses[if_true.clause_index].then)); 814 block 815 }; 816 817 let if_false = self.translate_decision(kind, clauses, if_false); 818 819 block.push(Expression::If { 820 cond: Box::new(cond), 821 then: Box::new(Expression::Block(if_true)), 822 else_: Box::new(if_false), 823 }); 824 825 Expression::Block(block) 826 } 827 exhaustiveness::Decision::Switch { 828 var, 829 choices, 830 fallback, 831 fallback_check, 832 } => { 833 let fallback = 834 self.translate_fallback(kind, var, clauses, fallback, fallback_check); 835 836 DoubleEndedIterator::rfold(choices.iter(), fallback, |fallback, (check, then)| { 837 Expression::If { 838 cond: Box::new( 839 self.translate_runtime_check( 840 check, 841 Expression::Var( 842 self.decision_map 843 .get(&var.id) 844 .cloned() 845 .expect("expected variable to be defined"), 846 ), 847 ), 848 ), 849 then: Box::new(self.translate_decision(kind, clauses, then)), 850 else_: Box::new(fallback), 851 } 852 }) 853 } 854 exhaustiveness::Decision::Fail => todo!(), 855 } 856 } 857 858 fn translate_fallback( 859 &mut self, 860 kind: DecisionKind, 861 var: &exhaustiveness::Variable, 862 clauses: &[crate::ast::TypedClause], 863 decision: &exhaustiveness::Decision, 864 check: &exhaustiveness::FallbackCheck, 865 ) -> Expression<IncompleteType> { 866 match check { 867 exhaustiveness::FallbackCheck::InfiniteCatchAll 868 | exhaustiveness::FallbackCheck::CatchAll { .. } => { 869 self.translate_decision(kind, clauses, decision) 870 } 871 exhaustiveness::FallbackCheck::RuntimeCheck { check } => { 872 let cond = self.translate_runtime_check( 873 check, 874 Expression::Var( 875 self.decision_map 876 .get(&var.id) 877 .cloned() 878 .expect("expected variable to be defined"), 879 ), 880 ); 881 882 let then = self.translate_decision(kind, clauses, decision); 883 884 Expression::If { 885 cond: Box::new(cond), 886 then: Box::new(then.clone()), 887 else_: Box::new(Expression::Panic { 888 type_: then.type_().clone(), 889 }), 890 } 891 } 892 } 893 } 894 895 fn translate_guard( 896 &mut self, 897 guard: &crate::ast::TypedClauseGuard, 898 ) -> Expression<IncompleteType> { 899 match guard { 900 crate::ast::ClauseGuard::Block { location: _, value } => self.translate_guard(value), 901 crate::ast::ClauseGuard::Equals { 902 location: _, 903 left, 904 right, 905 } => { 906 let lhs = self.translate_guard(left); 907 let rhs = self.translate_guard(right); 908 909 Expression::Equals { 910 lhs: Box::new(lhs), 911 rhs: Box::new(rhs), 912 } 913 } 914 crate::ast::ClauseGuard::NotEquals { 915 location: _, 916 left, 917 right, 918 } => Expression::NotEquals { 919 lhs: Box::new(self.translate_guard(left)), 920 rhs: Box::new(self.translate_guard(right)), 921 }, 922 crate::ast::ClauseGuard::GtInt { 923 location: _, 924 left, 925 right, 926 } => Expression::IntGt { 927 lhs: Box::new(self.translate_guard(left)), 928 rhs: Box::new(self.translate_guard(right)), 929 }, 930 crate::ast::ClauseGuard::GtEqInt { 931 location: _, 932 left, 933 right, 934 } => Expression::IntGtEq { 935 lhs: Box::new(self.translate_guard(left)), 936 rhs: Box::new(self.translate_guard(right)), 937 }, 938 crate::ast::ClauseGuard::LtInt { 939 location: _, 940 left, 941 right, 942 } => Expression::IntLt { 943 lhs: Box::new(self.translate_guard(left)), 944 rhs: Box::new(self.translate_guard(right)), 945 }, 946 crate::ast::ClauseGuard::LtEqInt { 947 location: _, 948 left, 949 right, 950 } => Expression::IntLtEq { 951 lhs: Box::new(self.translate_guard(left)), 952 rhs: Box::new(self.translate_guard(right)), 953 }, 954 crate::ast::ClauseGuard::GtFloat { 955 location: _, 956 left, 957 right, 958 } => Expression::FloatGt { 959 lhs: Box::new(self.translate_guard(left)), 960 rhs: Box::new(self.translate_guard(right)), 961 }, 962 crate::ast::ClauseGuard::GtEqFloat { 963 location: _, 964 left, 965 right, 966 } => Expression::FloatGtEq { 967 lhs: Box::new(self.translate_guard(left)), 968 rhs: Box::new(self.translate_guard(right)), 969 }, 970 crate::ast::ClauseGuard::LtFloat { 971 location: _, 972 left, 973 right, 974 } => Expression::FloatLt { 975 lhs: Box::new(self.translate_guard(left)), 976 rhs: Box::new(self.translate_guard(right)), 977 }, 978 crate::ast::ClauseGuard::LtEqFloat { 979 location: _, 980 left, 981 right, 982 } => Expression::FloatLtEq { 983 lhs: Box::new(self.translate_guard(left)), 984 rhs: Box::new(self.translate_guard(right)), 985 }, 986 crate::ast::ClauseGuard::AddInt { 987 location: _, 988 left, 989 right, 990 } => Expression::IntAdd { 991 lhs: Box::new(self.translate_guard(left)), 992 rhs: Box::new(self.translate_guard(right)), 993 }, 994 crate::ast::ClauseGuard::AddFloat { 995 location: _, 996 left, 997 right, 998 } => Expression::FloatAdd { 999 lhs: Box::new(self.translate_guard(left)), 1000 rhs: Box::new(self.translate_guard(right)), 1001 }, 1002 crate::ast::ClauseGuard::SubInt { 1003 location: _, 1004 left, 1005 right, 1006 } => Expression::IntSub { 1007 lhs: Box::new(self.translate_guard(left)), 1008 rhs: Box::new(self.translate_guard(right)), 1009 }, 1010 crate::ast::ClauseGuard::SubFloat { 1011 location: _, 1012 left, 1013 right, 1014 } => Expression::FloatSub { 1015 lhs: Box::new(self.translate_guard(left)), 1016 rhs: Box::new(self.translate_guard(right)), 1017 }, 1018 crate::ast::ClauseGuard::MultInt { 1019 location: _, 1020 left, 1021 right, 1022 } => Expression::IntMul { 1023 lhs: Box::new(self.translate_guard(left)), 1024 rhs: Box::new(self.translate_guard(right)), 1025 }, 1026 crate::ast::ClauseGuard::MultFloat { 1027 location: _, 1028 left, 1029 right, 1030 } => Expression::FloatMul { 1031 lhs: Box::new(self.translate_guard(left)), 1032 rhs: Box::new(self.translate_guard(right)), 1033 }, 1034 crate::ast::ClauseGuard::DivInt { 1035 location: _, 1036 left, 1037 right, 1038 } => Expression::IntDiv { 1039 lhs: Box::new(self.translate_guard(left)), 1040 rhs: Box::new(self.translate_guard(right)), 1041 }, 1042 crate::ast::ClauseGuard::DivFloat { 1043 location: _, 1044 left, 1045 right, 1046 } => Expression::FloatDiv { 1047 lhs: Box::new(self.translate_guard(left)), 1048 rhs: Box::new(self.translate_guard(right)), 1049 }, 1050 crate::ast::ClauseGuard::RemainderInt { 1051 location: _, 1052 left, 1053 right, 1054 } => Expression::IntRem { 1055 lhs: Box::new(self.translate_guard(left)), 1056 rhs: Box::new(self.translate_guard(right)), 1057 }, 1058 crate::ast::ClauseGuard::Or { 1059 location: _, 1060 left, 1061 right, 1062 } => Expression::If { 1063 cond: Box::new(self.translate_guard(left)), 1064 then: Box::new(Expression::Bool { value: true }), 1065 else_: Box::new(self.translate_guard(right)), 1066 }, 1067 crate::ast::ClauseGuard::And { 1068 location: _, 1069 left, 1070 right, 1071 } => Expression::If { 1072 cond: Box::new(self.translate_guard(left)), 1073 then: Box::new(self.translate_guard(right)), 1074 else_: Box::new(Expression::Bool { value: false }), 1075 }, 1076 crate::ast::ClauseGuard::Not { 1077 location: _, 1078 expression, 1079 } => Expression::Equals { 1080 lhs: Box::new(self.translate_guard(expression)), 1081 rhs: Box::new(Expression::Bool { value: false }), 1082 }, 1083 crate::ast::ClauseGuard::Var { 1084 location: _, 1085 type_: _, 1086 name, 1087 definition_location: _, 1088 } => Expression::Var(self.get_var(name)), 1089 crate::ast::ClauseGuard::TupleIndex { 1090 location: _, 1091 index, 1092 type_, 1093 tuple, 1094 } => Expression::StructAccess { 1095 value: Box::new(self.translate_guard(tuple)), 1096 index: *index, 1097 type_: Translator::translate_type(type_), 1098 }, 1099 crate::ast::ClauseGuard::FieldAccess { 1100 label_location: _, 1101 index, 1102 label: _, 1103 type_, 1104 container, 1105 } => Expression::StructAccess { 1106 value: Box::new(self.translate_guard(container)), 1107 index: index.expect("field access expected an index"), 1108 type_: Translator::translate_type(type_), 1109 }, 1110 crate::ast::ClauseGuard::ModuleSelect { 1111 location: _, 1112 type_: _, 1113 label: _, 1114 module_name: _, 1115 module_alias: _, 1116 literal: _, 1117 } => todo!(), 1118 crate::ast::ClauseGuard::Constant(constant) => self.translate_constant(constant), 1119 } 1120 } 1121 1122 fn translate_constant( 1123 &mut self, 1124 constant: &crate::ast::TypedConstant, 1125 ) -> Expression<IncompleteType> { 1126 match constant { 1127 crate::ast::Constant::Int { 1128 location: _, 1129 value: _, 1130 int_value, 1131 } => Expression::Int { 1132 value: int_value.clone(), 1133 }, 1134 crate::ast::Constant::Float { location: _, value } => Expression::Float { 1135 value: value.clone(), 1136 }, 1137 crate::ast::Constant::String { location: _, value } => Expression::String { 1138 value: value.clone(), 1139 }, 1140 crate::ast::Constant::Tuple { 1141 location: _, 1142 elements, 1143 } => Expression::Struct { 1144 tag: None, 1145 items: elements 1146 .iter() 1147 .map(|element| self.translate_constant(element)) 1148 .collect(), 1149 type_: Translator::translate_type(&constant.type_()), 1150 }, 1151 crate::ast::Constant::List { 1152 location: _, 1153 elements, 1154 type_, 1155 } => Expression::List { 1156 items: elements 1157 .iter() 1158 .map(|element| self.translate_constant(element)) 1159 .collect(), 1160 tail: None, 1161 type_: Translator::translate_type(type_), 1162 }, 1163 crate::ast::Constant::Record { 1164 location: _, 1165 module: _, 1166 name: _, 1167 arguments: _, 1168 tag: _, 1169 type_: _, 1170 field_map: _, 1171 record_constructor: _, 1172 } => todo!(), 1173 crate::ast::Constant::BitArray { 1174 location: _, 1175 segments: _, 1176 } => todo!(), 1177 crate::ast::Constant::Var { 1178 location: _, 1179 module: _, 1180 name: _, 1181 constructor: _, 1182 type_: _, 1183 } => todo!(), 1184 crate::ast::Constant::StringConcatenation { 1185 location: _, 1186 left, 1187 right, 1188 } => Expression::StringConcat { 1189 lhs: Box::new(self.translate_constant(left)), 1190 rhs: Box::new(self.translate_constant(right)), 1191 }, 1192 crate::ast::Constant::Invalid { 1193 location: _, 1194 type_: _, 1195 } => todo!(), 1196 } 1197 } 1198 1199 fn translate_binding( 1200 &mut self, 1201 binding: Var<IncompleteType>, 1202 value: &exhaustiveness::BoundValue, 1203 ) -> Expression<IncompleteType> { 1204 let value = match value { 1205 exhaustiveness::BoundValue::Variable(variable) => Expression::Var( 1206 self.decision_map 1207 .get(&variable.id) 1208 .cloned() 1209 .expect("expected variable to be defined"), 1210 ), 1211 exhaustiveness::BoundValue::LiteralString(_eco_string) => todo!(), 1212 exhaustiveness::BoundValue::LiteralInt(big_int) => Expression::Int { 1213 value: big_int.clone(), 1214 }, 1215 exhaustiveness::BoundValue::LiteralFloat(_eco_string) => todo!(), 1216 exhaustiveness::BoundValue::BitArraySlice { 1217 bit_array: _, 1218 read_action: _, 1219 } => todo!(), 1220 }; 1221 1222 Expression::Set { 1223 name: binding, 1224 value: Box::new(value), 1225 } 1226 } 1227 1228 fn translate_runtime_check( 1229 &mut self, 1230 check: &exhaustiveness::RuntimeCheck, 1231 against: Expression<IncompleteType>, 1232 ) -> Expression<IncompleteType> { 1233 match check { 1234 exhaustiveness::RuntimeCheck::Int { value } => { 1235 let value = parse::parse_int_value(&value).expect("unable to parse integer value"); 1236 1237 Expression::Equals { 1238 lhs: Box::new(against), 1239 rhs: Box::new(Expression::Int { value }), 1240 } 1241 } 1242 exhaustiveness::RuntimeCheck::Float { value } => Expression::Equals { 1243 lhs: Box::new(against), 1244 rhs: Box::new(Expression::Float { 1245 value: value.clone(), 1246 }), 1247 }, 1248 exhaustiveness::RuntimeCheck::String { value } => Expression::Equals { 1249 lhs: Box::new(against), 1250 rhs: Box::new(Expression::String { 1251 value: value.clone(), 1252 }), 1253 }, 1254 exhaustiveness::RuntimeCheck::StringPrefix { prefix: _, rest: _ } => todo!(), 1255 exhaustiveness::RuntimeCheck::Tuple { 1256 size: _, 1257 elements: _, 1258 } => todo!(), 1259 exhaustiveness::RuntimeCheck::BitArray { test: _ } => todo!(), 1260 exhaustiveness::RuntimeCheck::Variant { 1261 match_: _, 1262 index, 1263 labels: _, 1264 fields, 1265 } => { 1266 let mut block = vec![]; 1267 1268 for (index, field) in fields.iter().enumerate() { 1269 let var_type = Translator::translate_type(&field.type_); 1270 let var = self.make_tmp_var(var_type.clone()); 1271 1272 _ = self.decision_map.insert(field.id, var.clone()); 1273 1274 block.push(Expression::Set { 1275 name: var, 1276 value: Box::new(Expression::StructAccess { 1277 value: Box::new(against.clone()), 1278 index: index as u64, 1279 type_: var_type, 1280 }), 1281 }); 1282 } 1283 1284 block.push(Expression::Equals { 1285 lhs: Box::new(Expression::Int { 1286 value: BigInt::from(*index), 1287 }), 1288 rhs: Box::new(Expression::StructTag { 1289 value: Box::new(against), 1290 }), 1291 }); 1292 1293 Expression::Block(block) 1294 } 1295 exhaustiveness::RuntimeCheck::NonEmptyList { first: _, rest: _ } => todo!(), 1296 exhaustiveness::RuntimeCheck::EmptyList => todo!(), 1297 } 1298 } 1299} 1300 1301#[cfg(test)] 1302mod tests { 1303 use std::collections::{HashMap, HashSet}; 1304 1305 use super::*; 1306 use crate::analyse::TargetSupport; 1307 use crate::build::{Origin, Target}; 1308 use crate::config::PackageConfig; 1309 use crate::line_numbers::LineNumbers; 1310 use crate::parse::parse_module; 1311 use crate::type_::PRELUDE_MODULE_NAME; 1312 use crate::uid::UniqueIdGenerator; 1313 use crate::warning::{TypeWarningEmitter, WarningEmitter}; 1314 use camino::Utf8PathBuf; 1315 1316 fn compile_module(src: &str) -> crate::ast::TypedModule { 1317 use crate::type_::build_prelude; 1318 let parsed = parse_module(Utf8PathBuf::from("test/path"), src, &WarningEmitter::null()) 1319 .expect("syntax error"); 1320 let ast = parsed.module; 1321 let ids = UniqueIdGenerator::new(); 1322 let mut config = PackageConfig::default(); 1323 config.name = "thepackage".into(); 1324 let mut modules = im::HashMap::new(); 1325 let _ = modules.insert(PRELUDE_MODULE_NAME.into(), build_prelude(&ids)); 1326 let line_numbers = LineNumbers::new(src); 1327 1328 crate::analyse::ModuleAnalyzerConstructor::<()> { 1329 target: Target::Erlang, 1330 ids: &ids, 1331 origin: Origin::Src, 1332 importable_modules: &modules, 1333 warnings: &TypeWarningEmitter::null(), 1334 direct_dependencies: &HashMap::new(), 1335 dev_dependencies: &HashSet::new(), 1336 target_support: TargetSupport::Enforced, 1337 package_config: &config, 1338 } 1339 .infer_module(ast, line_numbers, "".into()) 1340 .expect("should successfully infer") 1341 } 1342 1343 fn translate(src: &str) -> Module<IncompleteType> { 1344 let typed_module = compile_module(src); 1345 1346 Translator::new(&typed_module).translate() 1347 } 1348 1349 #[test] 1350 fn translates_samples() { 1351 insta::assert_debug_snapshot!(translate( 1352 r#"pub fn add(lhs: Int, rhs: Int) -> Int { 1353 lhs + rhs 1354 }"# 1355 )); 1356 1357 insta::assert_debug_snapshot!(translate( 1358 r#"pub fn some_case(n: Int) -> Int { 1359 case n { 1360 0 -> 2 1361 1 -> 4 1362 _ -> 6 1363 } 1364 }"# 1365 )); 1366 1367 insta::assert_debug_snapshot!(translate( 1368 r#"pub fn some_case(n: Int) -> Int { 1369 case n { 1370 y if y == 0 -> 2 1371 1 -> 4 1372 _ -> 6 1373 } 1374 }"# 1375 )); 1376 1377 insta::assert_debug_snapshot!(translate( 1378 r#"pub fn fib(n: Int) -> Int { 1379 case n { 1380 0 -> 0 1381 1 -> 1 1382 _ -> fib(n - 1) + fib(n - 2) 1383 } 1384 }"# 1385 )); 1386 1387 insta::assert_debug_snapshot!(translate( 1388 r#"pub fn maths() { 1389 let _ = 1 + 0 1390 let _ = 2 - 1 1391 let _ = 3 * 2 1392 let _ = 4 / 3 1393 let _ = 5 % 4 1394 1395 let _ = 1.0 +. 0.0 1396 let _ = 2.0 -. 1.0 1397 let _ = 3.0 *. 2.0 1398 let _ = 4.0 /. 3.0 1399 1400 let _ = 1 == 2 && 2 == 4 1401 let _ = 1 == 2 || 2 == 4 1402 }"# 1403 )); 1404 1405 insta::assert_debug_snapshot!(translate( 1406 r#"pub fn booleans() { 1407 let _ = True 1408 let _ = False 1409 1410 let _ = True == False 1411 let _ = False != True 1412 1413 let _ = 1 > 2 1414 let _ = 1 >= 2 1415 let _ = 1 < 2 1416 let _ = 1 <= 2 1417 1418 let _ = 1.0 >. 2.0 1419 let _ = 1.0 >=. 2.0 1420 let _ = 1.0 <. 2.0 1421 let _ = 1.0 <=. 2.0 1422 }"# 1423 )); 1424 1425 insta::assert_debug_snapshot!(translate( 1426 r#"pub fn guard_operations(n: Int, f: Float) -> Int { 1427 case n, f { 1428 x, y if x == 0 -> 1 1429 x, y if x != 1 -> 2 1430 x, y if x > 2 -> 3 1431 x, y if x >= 3 -> 4 1432 x, y if x < 4 -> 5 1433 x, y if x <= 5 -> 6 1434 x, y if y >. 1.0 -> 7 1435 x, y if y >=. 2.0 -> 8 1436 x, y if y <. 3.0 -> 9 1437 x, y if y <=. 4.0 -> 10 1438 x, y if x > 0 && x < 10 -> 11 1439 x, y if x < 0 || x > 100 -> 12 1440 x, y if !{ x == 0 } -> 13 1441 x, y if x + 1 > 5 -> 14 1442 x, y if x - 1 < 0 -> 15 1443 x, y if x * 2 == 10 -> 16 1444 x, y if x / 2 == 1 -> 17 1445 x, y if y +. 1.0 >. 5.0 -> 18 1446 x, y if y -. 1.0 <. 0.0 -> 19 1447 x, y if y *. 2.0 == 4.0 -> 20 1448 x, y if y /. 2.0 >=. 1.0 -> 21 1449 x, y if x % 2 == 0 -> 22 1450 _, _ -> 0 1451 } 1452 }"# 1453 )); 1454 1455 insta::assert_debug_snapshot!(translate( 1456 r#"pub fn strings() { 1457 let _ = "hello" 1458 let _ = "hello, " <> "world!" 1459 }"# 1460 )); 1461 1462 insta::assert_debug_snapshot!(translate( 1463 r#"pub fn tuples() { 1464 let a = #(1, 2, 3) 1465 let _ = a.1 1466 }"# 1467 )); 1468 1469 insta::assert_debug_snapshot!(translate( 1470 r#"pub type Wibble { 1471 Wibble(a: Int, b: Int) 1472 } 1473 1474 pub fn types(w: Wibble) { 1475 let x = Wibble(a: 10, b: 20) 1476 1477 w.a + x.b 1478 }"# 1479 )); 1480 1481 insta::assert_debug_snapshot!(translate( 1482 r#"pub fn add(lhs: Int, rhs: Int) -> Int { 1483 lhs + rhs 1484 } 1485 1486 pub fn pipe() { 1487 10 |> add(20) |> add(30) 1488 }"# 1489 )); 1490 1491 insta::assert_debug_snapshot!(translate( 1492 r#"pub fn pipe() { 1493 [1, 2, 3, ..[4, 5, 6]] 1494 }"# 1495 )); 1496 1497 insta::assert_debug_snapshot!(translate( 1498 r#"pub type Wibble { 1499 Wibble 1500 Wobble 1501 } 1502 1503 pub fn check(wibble: Wibble) { 1504 case wibble { 1505 Wibble -> 0 1506 Wobble -> 1 1507 } 1508 }"# 1509 )); 1510 1511 insta::assert_debug_snapshot!(translate( 1512 r#"pub type Wibble { 1513 Wibble(x: Int, y: Int, z: Int) 1514 } 1515 1516 pub fn record_update(wibble: Wibble) { 1517 Wibble(..wibble, y: 20) 1518 }"# 1519 )); 1520 } 1521}