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

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::{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}