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

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