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

Configure Feed

Select the types of activity you want to include in your feed.

gleam / compiler-core / src / ast / tests.rs
33 kB 1214 lines
1// SPDX-License-Identifier: Apache-2.0 2// SPDX-FileCopyrightText: 2022 The Gleam contributors 3 4use std::sync::Arc; 5 6use camino::Utf8PathBuf; 7use ecow::EcoString; 8 9use crate::analyse::TargetSupport; 10use crate::build::{ExpressionPosition, Origin, Target}; 11use crate::config::PackageConfig; 12use crate::line_numbers::LineNumbers; 13use crate::type_::error::{VariableDeclaration, VariableOrigin, VariableSyntax}; 14use crate::type_::expression::{FunctionDefinition, Purity}; 15use crate::type_::{Deprecation, PRELUDE_MODULE_NAME, Problems}; 16use crate::warning::WarningEmitter; 17use crate::{ 18 ast::{BinOp, SrcSpan, TypedExpr}, 19 build::Located, 20 type_::{ 21 self, AccessorsMap, EnvironmentArguments, ExprTyper, FieldMap, ModuleValueConstructor, 22 RecordAccessor, Type, ValueConstructor, ValueConstructorVariant, 23 }, 24 uid::UniqueIdGenerator, 25 warning::TypeWarningEmitter, 26}; 27 28use super::{Publicity, Statement, TypedModule, TypedStatement}; 29 30fn compile_module(src: &str) -> TypedModule { 31 use crate::type_::build_prelude; 32 let parsed = 33 crate::parse::parse_module(Utf8PathBuf::from("test/path"), src, &WarningEmitter::null()) 34 .expect("syntax error"); 35 let ast = parsed.module; 36 let ids = UniqueIdGenerator::new(); 37 let mut config = PackageConfig::default(); 38 config.name = "thepackage".into(); 39 let mut modules = im::HashMap::new(); 40 // DUPE: preludeinsertion 41 // TODO: Currently we do this here and also in the tests. It would be better 42 // to have one place where we create all this required state for use in each 43 // place. 44 let _ = modules.insert(PRELUDE_MODULE_NAME.into(), build_prelude(&ids)); 45 let line_numbers = LineNumbers::new(src); 46 let mut config = PackageConfig::default(); 47 config.name = "thepackage".into(); 48 49 crate::analyse::ModuleAnalyzerConstructor::<()> { 50 target: Target::Erlang, 51 ids: &ids, 52 origin: Origin::Src, 53 importable_modules: &modules, 54 warnings: &TypeWarningEmitter::null(), 55 direct_dependencies: &std::collections::HashMap::new(), 56 dev_dependencies: &std::collections::HashSet::new(), 57 target_support: TargetSupport::Enforced, 58 package_config: &config, 59 } 60 .infer_module(ast, line_numbers, "".into()) 61 .expect("should successfully infer") 62} 63 64fn get_bare_expression(statement: &TypedStatement) -> &TypedExpr { 65 match statement { 66 Statement::Expression(expression) => expression, 67 Statement::Use(_) | Statement::Assignment(_) | Statement::Assert(_) => { 68 panic!("Expected expression, got {statement:?}") 69 } 70 } 71} 72 73fn cat_type() -> Arc<Type> { 74 Arc::new(Type::Named { 75 publicity: Publicity::Public, 76 package: "mypackage".into(), 77 module: "mymod".into(), 78 name: "Cat".into(), 79 arguments: vec![], 80 inferred_variant: None, 81 }) 82} 83 84fn compile_expression(src: &str) -> TypedStatement { 85 let ast = crate::parse::parse_statement_sequence(src).expect("syntax error"); 86 87 let mut modules = im::HashMap::new(); 88 let ids = UniqueIdGenerator::new(); 89 // DUPE: preludeinsertion 90 // TODO: Currently we do this here and also in the tests. It would be better 91 // to have one place where we create all this required state for use in each 92 // place. 93 let _ = modules.insert(PRELUDE_MODULE_NAME.into(), type_::build_prelude(&ids)); 94 let dev_dependencies = std::collections::HashSet::new(); 95 96 let mut environment = EnvironmentArguments { 97 ids, 98 current_package: "thepackage".into(), 99 gleam_version: None, 100 current_module: "mymod".into(), 101 target: Target::Erlang, 102 importable_modules: &modules, 103 target_support: TargetSupport::Enforced, 104 current_origin: Origin::Src, 105 dev_dependencies: &dev_dependencies, 106 } 107 .build(); 108 109 // Insert a cat record to use in the tests 110 let cat_type = cat_type(); 111 let variant = ValueConstructorVariant::Record { 112 documentation: Some("wibble".into()), 113 variants_count: 1, 114 name: "Cat".into(), 115 arity: 2, 116 location: SrcSpan { start: 12, end: 15 }, 117 field_map: Some(FieldMap { 118 arity: 2, 119 fields: [("name".into(), 0), ("age".into(), 1)].into(), 120 }), 121 module: "mymod".into(), 122 variant_index: 0, 123 }; 124 environment.insert_variable( 125 "Cat".into(), 126 variant, 127 type_::fn_(vec![type_::string(), type_::int()], cat_type.clone()), 128 Publicity::Public, 129 Deprecation::NotDeprecated, 130 ); 131 132 let accessors = [ 133 ( 134 "name".into(), 135 RecordAccessor { 136 index: 0, 137 label: "name".into(), 138 type_: type_::string(), 139 documentation: None, 140 }, 141 ), 142 ( 143 "age".into(), 144 RecordAccessor { 145 index: 1, 146 label: "age".into(), 147 type_: type_::int(), 148 documentation: None, 149 }, 150 ), 151 ]; 152 153 environment.insert_accessors( 154 "Cat".into(), 155 AccessorsMap { 156 publicity: Publicity::Public, 157 type_: cat_type, 158 shared_accessors: accessors.clone().into(), 159 variant_specific_accessors: vec![accessors.into()], 160 variant_positional_accessors: vec![vec![]], 161 }, 162 ); 163 let mut problems = Problems::new(); 164 ExprTyper::new( 165 &mut environment, 166 FunctionDefinition { 167 has_body: true, 168 has_erlang_external: false, 169 has_javascript_external: false, 170 has_wasm_external: false, 171 }, 172 &mut problems, 173 ) 174 .infer_statements(ast) 175 .first() 176 .clone() 177} 178 179#[test] 180fn find_node_todo() { 181 let statement = compile_expression(r#" todo "#); 182 let expr = get_bare_expression(&statement); 183 assert_eq!(expr.find_node(0), None); 184 assert_eq!( 185 expr.find_node(1), 186 Some(Located::Expression { 187 expression: expr, 188 position: ExpressionPosition::Expression 189 }) 190 ); 191 assert_eq!( 192 expr.find_node(4), 193 Some(Located::Expression { 194 expression: expr, 195 position: ExpressionPosition::Expression 196 }) 197 ); 198 assert_eq!( 199 expr.find_node(5), 200 Some(Located::Expression { 201 expression: expr, 202 position: ExpressionPosition::Expression 203 }) 204 ); 205 assert_eq!(expr.find_node(6), None); 206} 207 208#[test] 209fn find_node_todo_with_string() { 210 let statement = compile_expression(r#" todo as "ok" "#); 211 let expr = get_bare_expression(&statement); 212 let message = TypedExpr::String { 213 location: SrcSpan { start: 9, end: 13 }, 214 type_: type_::string(), 215 value: "ok".into(), 216 }; 217 218 assert_eq!(expr.find_node(0), None); 219 assert_eq!( 220 expr.find_node(1), 221 Some(Located::Expression { 222 expression: expr, 223 position: ExpressionPosition::Expression 224 }) 225 ); 226 assert_eq!( 227 expr.find_node(12), 228 Some(Located::Expression { 229 expression: &message, 230 position: ExpressionPosition::Expression 231 }) 232 ); 233 assert_eq!( 234 expr.find_node(13), 235 Some(Located::Expression { 236 expression: &message, 237 position: ExpressionPosition::Expression 238 }) 239 ); 240 assert_eq!(expr.find_node(14), None); 241} 242 243#[test] 244fn find_node_string() { 245 let statement = compile_expression(r#" "ok" "#); 246 let expr = get_bare_expression(&statement); 247 assert_eq!(expr.find_node(0), None); 248 assert_eq!( 249 expr.find_node(1), 250 Some(Located::Expression { 251 expression: expr, 252 position: ExpressionPosition::Expression 253 }) 254 ); 255 assert_eq!( 256 expr.find_node(4), 257 Some(Located::Expression { 258 expression: expr, 259 position: ExpressionPosition::Expression 260 }) 261 ); 262 assert_eq!( 263 expr.find_node(5), 264 Some(Located::Expression { 265 expression: expr, 266 position: ExpressionPosition::Expression 267 }) 268 ); 269 assert_eq!(expr.find_node(6), None); 270} 271 272#[test] 273fn find_node_float() { 274 let statement = compile_expression(r#" 1.02 "#); 275 let expr = get_bare_expression(&statement); 276 assert_eq!(expr.find_node(0), None); 277 assert_eq!( 278 expr.find_node(1), 279 Some(Located::Expression { 280 expression: expr, 281 position: ExpressionPosition::Expression 282 }) 283 ); 284 assert_eq!( 285 expr.find_node(4), 286 Some(Located::Expression { 287 expression: expr, 288 position: ExpressionPosition::Expression 289 }) 290 ); 291 assert_eq!( 292 expr.find_node(5), 293 Some(Located::Expression { 294 expression: expr, 295 position: ExpressionPosition::Expression 296 }) 297 ); 298 assert_eq!(expr.find_node(6), None); 299} 300 301#[test] 302fn find_node_int() { 303 let statement = compile_expression(r#" 1302 "#); 304 let expr = get_bare_expression(&statement); 305 assert_eq!(expr.find_node(0), None); 306 assert_eq!( 307 expr.find_node(1), 308 Some(Located::Expression { 309 expression: expr, 310 position: ExpressionPosition::Expression 311 }) 312 ); 313 assert_eq!( 314 expr.find_node(4), 315 Some(Located::Expression { 316 expression: expr, 317 position: ExpressionPosition::Expression 318 }) 319 ); 320 assert_eq!( 321 expr.find_node(5), 322 Some(Located::Expression { 323 expression: expr, 324 position: ExpressionPosition::Expression 325 }) 326 ); 327 assert_eq!(expr.find_node(6), None); 328} 329 330#[test] 331fn find_node_var() { 332 let statement = compile_expression( 333 r#"{let wibble = 1 334wibble}"#, 335 ); 336 let expr = get_bare_expression(&statement); 337 338 let int1 = TypedExpr::Int { 339 location: SrcSpan { start: 14, end: 15 }, 340 value: "1".into(), 341 int_value: 1.into(), 342 type_: type_::int(), 343 }; 344 345 let var = TypedExpr::Var { 346 location: SrcSpan { start: 16, end: 22 }, 347 constructor: ValueConstructor { 348 deprecation: Deprecation::NotDeprecated, 349 publicity: Publicity::Private, 350 variant: ValueConstructorVariant::LocalVariable { 351 location: SrcSpan { start: 5, end: 11 }, 352 origin: VariableOrigin { 353 syntax: VariableSyntax::Variable("wibble".into()), 354 declaration: VariableDeclaration::LetPattern, 355 }, 356 }, 357 type_: type_::int(), 358 }, 359 name: "wibble".into(), 360 }; 361 362 assert_eq!( 363 expr.find_node(15), 364 Some(Located::Expression { 365 expression: &int1, 366 position: ExpressionPosition::Expression 367 }) 368 ); 369 assert_eq!( 370 expr.find_node(16), 371 Some(Located::Expression { 372 expression: &var, 373 position: ExpressionPosition::Expression 374 }) 375 ); 376 assert_eq!( 377 expr.find_node(21), 378 Some(Located::Expression { 379 expression: &var, 380 position: ExpressionPosition::Expression 381 }) 382 ); 383 assert_eq!( 384 expr.find_node(22), 385 Some(Located::Expression { 386 expression: &var, 387 position: ExpressionPosition::Expression 388 }) 389 ); 390} 391 392#[test] 393fn find_node_sequence() { 394 let block = compile_expression(r#"{ 1 2 3 }"#); 395 assert!(block.find_node(0).is_none()); 396 assert!(block.find_node(1).is_none()); 397 assert!(block.find_node(2).is_some()); 398 assert!(block.find_node(3).is_some()); 399 assert!(block.find_node(4).is_some()); 400 assert!(block.find_node(5).is_some()); 401 assert!(block.find_node(6).is_some()); 402 assert!(block.find_node(7).is_some()); 403} 404 405#[test] 406fn find_node_list() { 407 let statement = compile_expression(r#"[1, 2, 3]"#); 408 let list = get_bare_expression(&statement); 409 410 let int1 = TypedExpr::Int { 411 location: SrcSpan { start: 1, end: 2 }, 412 type_: type_::int(), 413 value: "1".into(), 414 int_value: 1.into(), 415 }; 416 let int2 = TypedExpr::Int { 417 location: SrcSpan { start: 4, end: 5 }, 418 type_: type_::int(), 419 value: "2".into(), 420 int_value: 2.into(), 421 }; 422 let int3 = TypedExpr::Int { 423 location: SrcSpan { start: 7, end: 8 }, 424 type_: type_::int(), 425 value: "3".into(), 426 int_value: 3.into(), 427 }; 428 429 assert_eq!( 430 list.find_node(0), 431 Some(Located::Expression { 432 expression: list, 433 position: ExpressionPosition::Expression 434 }) 435 ); 436 assert_eq!( 437 list.find_node(1), 438 Some(Located::Expression { 439 expression: &int1, 440 position: ExpressionPosition::Expression 441 }) 442 ); 443 assert_eq!( 444 list.find_node(2), 445 Some(Located::Expression { 446 expression: &int1, 447 position: ExpressionPosition::Expression 448 }) 449 ); 450 assert_eq!( 451 list.find_node(3), 452 Some(Located::Expression { 453 expression: list, 454 position: ExpressionPosition::Expression 455 }) 456 ); 457 assert_eq!( 458 list.find_node(4), 459 Some(Located::Expression { 460 expression: &int2, 461 position: ExpressionPosition::Expression 462 }) 463 ); 464 assert_eq!( 465 list.find_node(5), 466 Some(Located::Expression { 467 expression: &int2, 468 position: ExpressionPosition::Expression 469 }) 470 ); 471 assert_eq!( 472 list.find_node(6), 473 Some(Located::Expression { 474 expression: list, 475 position: ExpressionPosition::Expression 476 }) 477 ); 478 assert_eq!( 479 list.find_node(7), 480 Some(Located::Expression { 481 expression: &int3, 482 position: ExpressionPosition::Expression 483 }) 484 ); 485 assert_eq!( 486 list.find_node(8), 487 Some(Located::Expression { 488 expression: &int3, 489 position: ExpressionPosition::Expression 490 }) 491 ); 492 assert_eq!( 493 list.find_node(9), 494 Some(Located::Expression { 495 expression: list, 496 position: ExpressionPosition::Expression 497 }) 498 ); 499} 500 501#[test] 502fn find_node_tuple() { 503 let statement = compile_expression(r#"#(1, 2, 3)"#); 504 let tuple = get_bare_expression(&statement); 505 506 let int1 = TypedExpr::Int { 507 location: SrcSpan { start: 2, end: 3 }, 508 type_: type_::int(), 509 value: "1".into(), 510 int_value: 1.into(), 511 }; 512 let int2 = TypedExpr::Int { 513 location: SrcSpan { start: 5, end: 6 }, 514 type_: type_::int(), 515 value: "2".into(), 516 int_value: 2.into(), 517 }; 518 let int3 = TypedExpr::Int { 519 location: SrcSpan { start: 8, end: 9 }, 520 type_: type_::int(), 521 value: "3".into(), 522 int_value: 3.into(), 523 }; 524 525 assert_eq!( 526 tuple.find_node(0), 527 Some(Located::Expression { 528 expression: tuple, 529 position: ExpressionPosition::Expression 530 }) 531 ); 532 assert_eq!( 533 tuple.find_node(1), 534 Some(Located::Expression { 535 expression: tuple, 536 position: ExpressionPosition::Expression 537 }) 538 ); 539 assert_eq!( 540 tuple.find_node(2), 541 Some(Located::Expression { 542 expression: &int1, 543 position: ExpressionPosition::Expression 544 }) 545 ); 546 assert_eq!( 547 tuple.find_node(3), 548 Some(Located::Expression { 549 expression: &int1, 550 position: ExpressionPosition::Expression 551 }) 552 ); 553 assert_eq!( 554 tuple.find_node(4), 555 Some(Located::Expression { 556 expression: tuple, 557 position: ExpressionPosition::Expression 558 }) 559 ); 560 assert_eq!( 561 tuple.find_node(5), 562 Some(Located::Expression { 563 expression: &int2, 564 position: ExpressionPosition::Expression 565 }) 566 ); 567 assert_eq!( 568 tuple.find_node(6), 569 Some(Located::Expression { 570 expression: &int2, 571 position: ExpressionPosition::Expression 572 }) 573 ); 574 assert_eq!( 575 tuple.find_node(7), 576 Some(Located::Expression { 577 expression: tuple, 578 position: ExpressionPosition::Expression 579 }) 580 ); 581 assert_eq!( 582 tuple.find_node(8), 583 Some(Located::Expression { 584 expression: &int3, 585 position: ExpressionPosition::Expression 586 }) 587 ); 588 assert_eq!( 589 tuple.find_node(9), 590 Some(Located::Expression { 591 expression: &int3, 592 position: ExpressionPosition::Expression 593 }) 594 ); 595 assert_eq!( 596 tuple.find_node(10), 597 Some(Located::Expression { 598 expression: tuple, 599 position: ExpressionPosition::Expression 600 }) 601 ); 602} 603 604#[test] 605fn find_node_binop() { 606 let statement = compile_expression(r#"1 + 2"#); 607 let expr = get_bare_expression(&statement); 608 assert!(expr.find_node(0).is_some()); 609 assert!(expr.find_node(1).is_some()); 610 assert!(expr.find_node(2).is_none()); 611 assert!(expr.find_node(3).is_none()); 612 assert!(expr.find_node(4).is_some()); 613 assert!(expr.find_node(5).is_some()); 614} 615 616#[test] 617fn subtraction_is_left_associative_in_ast() { 618 // `1 - 2 - 3` must parse as `(1 - 2) - 3`, not `1 - (2 - 3)`. 619 let statement = compile_expression("1 - 2 - 3"); 620 let expr = get_bare_expression(&statement); 621 622 let TypedExpr::BinOp { 623 operator: BinOp::SubInt, 624 left, 625 right, 626 .. 627 } = expr 628 else { 629 panic!("expected outer SubInt, got {expr:?}"); 630 }; 631 632 let TypedExpr::Int { 633 value: right_val, .. 634 } = right.as_ref() 635 else { 636 panic!("expected int on right, got {right:?}"); 637 }; 638 assert_eq!(right_val, "3"); 639 640 let TypedExpr::BinOp { 641 operator: BinOp::SubInt, 642 left: ll, 643 right: lr, 644 .. 645 } = left.as_ref() 646 else { 647 panic!("expected inner SubInt on left, got {left:?}"); 648 }; 649 650 let TypedExpr::Int { value: ll_val, .. } = ll.as_ref() else { 651 panic!("expected int as left-left, got {ll:?}") 652 }; 653 let TypedExpr::Int { value: lr_val, .. } = lr.as_ref() else { 654 panic!("expected int as left-right, got {lr:?}") 655 }; 656 assert_eq!(ll_val, "1"); 657 assert_eq!(lr_val, "2"); 658} 659 660#[test] 661fn find_node_tuple_index() { 662 let statement = compile_expression(r#"#(1).0"#); 663 let expr = get_bare_expression(&statement); 664 665 let int = TypedExpr::Int { 666 location: SrcSpan { start: 2, end: 3 }, 667 value: "1".into(), 668 int_value: 1.into(), 669 type_: type_::int(), 670 }; 671 672 assert_eq!( 673 expr.find_node(2), 674 Some(Located::Expression { 675 expression: &int, 676 position: ExpressionPosition::Expression 677 }) 678 ); 679 assert_eq!( 680 expr.find_node(5), 681 Some(Located::Expression { 682 expression: expr, 683 position: ExpressionPosition::Expression 684 }) 685 ); 686 assert_eq!( 687 expr.find_node(6), 688 Some(Located::Expression { 689 expression: expr, 690 position: ExpressionPosition::Expression 691 }) 692 ); 693} 694 695#[test] 696fn find_node_module_select() { 697 let expr = TypedExpr::ModuleSelect { 698 location: SrcSpan { start: 1, end: 4 }, 699 field_start: 2, 700 type_: type_::int(), 701 label: "label".into(), 702 module_name: "name".into(), 703 module_alias: "alias".into(), 704 constructor: ModuleValueConstructor::Fn { 705 module: "module".into(), 706 name: "function".into(), 707 external_erlang: None, 708 external_javascript: None, 709 location: SrcSpan { start: 1, end: 55 }, 710 documentation: None, 711 field_map: None, 712 purity: Purity::Pure, 713 }, 714 }; 715 716 assert_eq!(expr.find_node(0), None); 717 assert_eq!( 718 expr.find_node(1), 719 Some(Located::ModuleName { 720 location: SrcSpan::new(1, 6), 721 module_name: "name".into(), 722 module_alias: "alias".into(), 723 layer: super::Layer::Value 724 }) 725 ); 726 assert_eq!( 727 expr.find_node(2), 728 Some(Located::Expression { 729 expression: &expr, 730 position: ExpressionPosition::Expression 731 }) 732 ); 733 assert_eq!( 734 expr.find_node(3), 735 Some(Located::Expression { 736 expression: &expr, 737 position: ExpressionPosition::Expression 738 }) 739 ); 740} 741 742#[test] 743fn find_node_fn() { 744 let statement = compile_expression("fn() { 1 }"); 745 let expr = get_bare_expression(&statement); 746 747 let int = TypedExpr::Int { 748 location: SrcSpan { start: 7, end: 8 }, 749 value: "1".into(), 750 int_value: 1.into(), 751 type_: type_::int(), 752 }; 753 754 assert_eq!( 755 expr.find_node(0), 756 Some(Located::Expression { 757 expression: expr, 758 position: ExpressionPosition::Expression 759 }) 760 ); 761 assert_eq!( 762 expr.find_node(6), 763 Some(Located::Expression { 764 expression: expr, 765 position: ExpressionPosition::Expression 766 }) 767 ); 768 assert_eq!( 769 expr.find_node(7), 770 Some(Located::Expression { 771 expression: &int, 772 position: ExpressionPosition::Expression 773 }) 774 ); 775 assert_eq!( 776 expr.find_node(8), 777 Some(Located::Expression { 778 expression: &int, 779 position: ExpressionPosition::Expression 780 }) 781 ); 782 assert_eq!( 783 expr.find_node(9), 784 Some(Located::Expression { 785 expression: expr, 786 position: ExpressionPosition::Expression 787 }) 788 ); 789 assert_eq!( 790 expr.find_node(10), 791 Some(Located::Expression { 792 expression: expr, 793 position: ExpressionPosition::Expression 794 }) 795 ); 796} 797 798#[test] 799fn find_node_call() { 800 let statement = compile_expression("fn(_, _) { 1 }(1, 2)"); 801 let expr = get_bare_expression(&statement); 802 803 let return_ = TypedExpr::Int { 804 location: SrcSpan { start: 11, end: 12 }, 805 value: "1".into(), 806 int_value: 1.into(), 807 type_: type_::int(), 808 }; 809 810 let arg1 = TypedExpr::Int { 811 location: SrcSpan { start: 15, end: 16 }, 812 value: "1".into(), 813 int_value: 1.into(), 814 type_: type_::int(), 815 }; 816 817 let arg2 = TypedExpr::Int { 818 location: SrcSpan { start: 18, end: 19 }, 819 value: "2".into(), 820 int_value: 2.into(), 821 type_: type_::int(), 822 }; 823 824 let TypedExpr::Call { 825 fun: called_function, 826 arguments: function_arguments, 827 .. 828 } = expr 829 else { 830 panic!("Expression was not a function call"); 831 }; 832 833 assert_eq!( 834 expr.find_node(11), 835 Some(Located::Expression { 836 expression: &return_, 837 position: ExpressionPosition::Expression 838 }) 839 ); 840 assert_eq!( 841 expr.find_node(15), 842 Some(Located::Expression { 843 expression: &arg1, 844 position: ExpressionPosition::Expression 845 }) 846 ); 847 assert_eq!( 848 expr.find_node(16), 849 Some(Located::Expression { 850 expression: &arg1, 851 position: ExpressionPosition::ArgumentOrLabel { 852 called_function, 853 function_arguments 854 } 855 }) 856 ); 857 assert_eq!( 858 expr.find_node(17), 859 Some(Located::Expression { 860 expression: expr, 861 position: ExpressionPosition::Expression 862 }) 863 ); 864 assert_eq!( 865 expr.find_node(18), 866 Some(Located::Expression { 867 expression: &arg2, 868 position: ExpressionPosition::Expression 869 }) 870 ); 871 assert_eq!( 872 expr.find_node(19), 873 Some(Located::Expression { 874 expression: &arg2, 875 position: ExpressionPosition::ArgumentOrLabel { 876 called_function, 877 function_arguments 878 } 879 }) 880 ); 881 assert_eq!( 882 expr.find_node(20), 883 Some(Located::Expression { 884 expression: expr, 885 position: ExpressionPosition::Expression 886 }) 887 ); 888} 889 890#[test] 891fn find_node_record_access() { 892 let statement = compile_expression(r#"Cat("Nubi", 3).name"#); 893 let access = get_bare_expression(&statement); 894 895 let string = TypedExpr::String { 896 location: SrcSpan { start: 4, end: 10 }, 897 value: "Nubi".into(), 898 type_: type_::string(), 899 }; 900 901 let int = TypedExpr::Int { 902 location: SrcSpan { start: 12, end: 13 }, 903 value: "3".into(), 904 int_value: 3.into(), 905 type_: type_::int(), 906 }; 907 908 assert_eq!( 909 access.find_node(4), 910 Some(Located::Expression { 911 expression: &string, 912 position: ExpressionPosition::Expression 913 }) 914 ); 915 assert_eq!( 916 access.find_node(9), 917 Some(Located::Expression { 918 expression: &string, 919 position: ExpressionPosition::Expression 920 }) 921 ); 922 assert_eq!( 923 access.find_node(12), 924 Some(Located::Expression { 925 expression: &int, 926 position: ExpressionPosition::Expression 927 }) 928 ); 929 let label = Located::RecordAccessLabel { 930 location: SrcSpan { start: 15, end: 19 }, 931 field_type: type_::string(), 932 label: "name".into(), 933 record_type: cat_type(), 934 documentation: None, 935 }; 936 assert_eq!(access.find_node(15), Some(label.clone())); 937 assert_eq!(access.find_node(18), Some(label.clone())); 938 assert_eq!(access.find_node(19), Some(label)); 939} 940 941#[test] 942fn find_node_record_update() { 943 let statement = compile_expression(r#"Cat(..Cat("Nubi", 3), age: 4)"#); 944 let update = get_bare_expression(&statement); 945 946 let cat = TypedExpr::Var { 947 location: SrcSpan { start: 0, end: 3 }, 948 constructor: ValueConstructor { 949 publicity: Publicity::Public, 950 deprecation: Deprecation::NotDeprecated, 951 variant: ValueConstructorVariant::Record { 952 name: "Cat".into(), 953 arity: 2, 954 field_map: Some(FieldMap { 955 arity: 2, 956 fields: [(EcoString::from("age"), 1), (EcoString::from("name"), 0)].into(), 957 }), 958 location: SrcSpan { start: 12, end: 15 }, 959 module: "mymod".into(), 960 variants_count: 1, 961 variant_index: 0, 962 documentation: Some("wibble".into()), 963 }, 964 type_: type_::fn_( 965 vec![type_::string(), type_::int()], 966 type_::named("mypackage", "mymod", "Cat", Publicity::Public, vec![]), 967 ), 968 }, 969 name: "Cat".into(), 970 }; 971 972 let int = TypedExpr::Int { 973 location: SrcSpan { start: 27, end: 28 }, 974 value: "4".into(), 975 int_value: 4.into(), 976 type_: type_::int(), 977 }; 978 979 assert_eq!( 980 update.find_node(0), 981 Some(Located::Expression { 982 expression: &cat, 983 position: ExpressionPosition::Expression 984 }) 985 ); 986 assert_eq!( 987 update.find_node(3), 988 Some(Located::Expression { 989 expression: &cat, 990 position: ExpressionPosition::Expression 991 }) 992 ); 993 assert_eq!( 994 update.find_node(27), 995 Some(Located::Expression { 996 expression: &int, 997 position: ExpressionPosition::Expression 998 }) 999 ); 1000 assert_eq!( 1001 update.find_node(28), 1002 Some(Located::Expression { 1003 expression: &int, 1004 position: ExpressionPosition::Expression 1005 }) 1006 ); 1007 assert_eq!( 1008 update.find_node(29), 1009 Some(Located::Expression { 1010 expression: update, 1011 position: ExpressionPosition::Expression 1012 }) 1013 ); 1014} 1015 1016#[test] 1017fn find_node_case() { 1018 let statement = compile_expression( 1019 r#" 1020case 1, 2 { 1021 _, _ -> 3 1022} 1023"#, 1024 ); 1025 let case = get_bare_expression(&statement); 1026 1027 let int1 = TypedExpr::Int { 1028 location: SrcSpan { start: 6, end: 7 }, 1029 value: "1".into(), 1030 int_value: 1.into(), 1031 type_: type_::int(), 1032 }; 1033 1034 let int2 = TypedExpr::Int { 1035 location: SrcSpan { start: 9, end: 10 }, 1036 value: "2".into(), 1037 int_value: 2.into(), 1038 type_: type_::int(), 1039 }; 1040 1041 let int3 = TypedExpr::Int { 1042 location: SrcSpan { start: 23, end: 24 }, 1043 value: "3".into(), 1044 int_value: 3.into(), 1045 type_: type_::int(), 1046 }; 1047 1048 assert_eq!( 1049 case.find_node(1), 1050 Some(Located::Expression { 1051 expression: case, 1052 position: ExpressionPosition::Expression 1053 }) 1054 ); 1055 assert_eq!( 1056 case.find_node(6), 1057 Some(Located::Expression { 1058 expression: &int1, 1059 position: ExpressionPosition::Expression 1060 }) 1061 ); 1062 assert_eq!( 1063 case.find_node(9), 1064 Some(Located::Expression { 1065 expression: &int2, 1066 position: ExpressionPosition::Expression 1067 }) 1068 ); 1069 assert_eq!( 1070 case.find_node(23), 1071 Some(Located::Expression { 1072 expression: &int3, 1073 position: ExpressionPosition::Expression 1074 }) 1075 ); 1076 assert_eq!( 1077 case.find_node(25), 1078 Some(Located::Expression { 1079 expression: case, 1080 position: ExpressionPosition::Expression 1081 }) 1082 ); 1083 assert_eq!( 1084 case.find_node(26), 1085 Some(Located::Expression { 1086 expression: case, 1087 position: ExpressionPosition::Expression 1088 }) 1089 ); 1090 assert_eq!(case.find_node(27), None); 1091} 1092 1093#[test] 1094fn find_node_bool() { 1095 let statement = compile_expression(r#"!True"#); 1096 let negate = get_bare_expression(&statement); 1097 1098 let bool = TypedExpr::Var { 1099 location: SrcSpan { start: 1, end: 5 }, 1100 constructor: ValueConstructor { 1101 deprecation: Deprecation::NotDeprecated, 1102 publicity: Publicity::Public, 1103 variant: ValueConstructorVariant::Record { 1104 documentation: None, 1105 variants_count: 2, 1106 name: "True".into(), 1107 arity: 0, 1108 field_map: None, 1109 location: SrcSpan { start: 0, end: 0 }, 1110 module: PRELUDE_MODULE_NAME.into(), 1111 variant_index: 0, 1112 }, 1113 type_: type_::bool_with_variant(Some(true)), 1114 }, 1115 name: "True".into(), 1116 }; 1117 1118 assert_eq!( 1119 negate.find_node(0), 1120 Some(Located::Expression { 1121 expression: negate, 1122 position: ExpressionPosition::Expression 1123 }) 1124 ); 1125 assert_eq!( 1126 negate.find_node(1), 1127 Some(Located::Expression { 1128 expression: &bool, 1129 position: ExpressionPosition::Expression 1130 }) 1131 ); 1132 assert_eq!( 1133 negate.find_node(2), 1134 Some(Located::Expression { 1135 expression: &bool, 1136 position: ExpressionPosition::Expression 1137 }) 1138 ); 1139 assert_eq!( 1140 negate.find_node(3), 1141 Some(Located::Expression { 1142 expression: &bool, 1143 position: ExpressionPosition::Expression 1144 }) 1145 ); 1146 assert_eq!( 1147 negate.find_node(4), 1148 Some(Located::Expression { 1149 expression: &bool, 1150 position: ExpressionPosition::Expression 1151 }) 1152 ); 1153 assert_eq!( 1154 negate.find_node(5), 1155 Some(Located::Expression { 1156 expression: &bool, 1157 position: ExpressionPosition::Expression 1158 }) 1159 ); 1160} 1161 1162#[test] 1163fn find_node_statement_fn() { 1164 let module = compile_module( 1165 r#" 1166 1167pub fn main() { 1168 Nil 1169} 1170 1171"#, 1172 ); 1173 1174 assert!(module.find_node(0).is_none()); 1175 assert!(module.find_node(1).is_none()); 1176 1177 // The fn 1178 assert!(module.find_node(2).is_some()); 1179 assert!(module.find_node(24).is_some()); 1180 assert!(module.find_node(25).is_some()); 1181 assert!(module.find_node(26).is_none()); 1182} 1183 1184#[test] 1185fn find_node_statement_import() { 1186 let module = compile_module( 1187 r#" 1188import gleam 1189"#, 1190 ); 1191 1192 assert!(module.find_node(0).is_none()); 1193 1194 // The import 1195 assert!(module.find_node(1).is_some()); 1196 assert!(module.find_node(12).is_some()); 1197 assert!(module.find_node(13).is_some()); 1198 assert!(module.find_node(14).is_none()); 1199} 1200 1201#[test] 1202fn find_node_use() { 1203 let use_ = compile_expression( 1204 r#" 1205use x <- fn(f) { f(1) } 1206124 1207"#, 1208 ); 1209 1210 assert!(use_.find_node(0).is_none()); 1211 assert!(use_.find_node(1).is_some()); // The use 1212 assert!(use_.find_node(23).is_some()); 1213 assert!(use_.find_node(26).is_some()); // The int 1214}