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