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