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