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