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