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