Fork of daniellemaywood.uk/gleam — Wasm codegen work
9.6 kB
626 lines
1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2021 The Gleam contributors
3
4use crate::{assert_js, assert_ts_def};
5
6#[test]
7fn exported_functions() {
8 assert_js!(
9 r#"
10pub fn add(x, y) {
11 x + y
12}"#,
13 );
14}
15
16#[test]
17fn calling_functions() {
18 assert_js!(
19 r#"
20pub fn twice(f: fn(t) -> t, x: t) -> t {
21 f(f(x))
22}
23pub fn add_one(x: Int) -> Int {
24 x + 1
25}
26pub fn add_two(x: Int) -> Int {
27 twice(add_one, x)
28}
29
30pub fn take_two(x: Int) -> Int {
31 twice(fn(y) {y - 1}, x)
32}
33"#,
34 );
35}
36
37#[test]
38fn function_formatting() {
39 assert_js!(
40 r#"
41pub fn add(the_first_variable_that_should_be_added, the_second_variable_that_should_be_added) {
42 the_first_variable_that_should_be_added + the_second_variable_that_should_be_added
43}"#,
44 );
45}
46
47#[test]
48fn function_formatting1() {
49 assert_js!(
50 r#"
51pub fn this_function_really_does_have_a_ludicrously_unfeasibly_long_name_for_a_function(x, y) {
52x + y
53}"#,
54 );
55}
56
57#[test]
58fn function_formatting2() {
59 assert_js!(
60 r#"
61pub fn add(x, y) {
62x + y
63}
64
65pub fn long() {
66 add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, add(1, 1)))))))))))))))
67}"#,
68 );
69}
70
71#[test]
72fn function_formatting3() {
73 assert_js!(
74 r#"
75pub fn math(x, y) {
76 fn() {
77 x + y
78 x - y
79 2 * x
80 }
81}"#,
82 );
83}
84
85#[test]
86fn function_formatting_typescript() {
87 assert_ts_def!(
88 r#"
89pub fn add(the_first_variable_that_should_be_added, the_second_variable_that_should_be_added) {
90 the_first_variable_that_should_be_added + the_second_variable_that_should_be_added
91}"#,
92 );
93}
94
95#[test]
96fn function_formatting_typescript1() {
97 assert_ts_def!(
98 r#"
99pub fn this_function_really_does_have_a_ludicrously_unfeasibly_long_name_for_a_function(x, y) {
100x + y
101}"#,
102 );
103}
104
105#[test]
106fn tail_call() {
107 assert_js!(
108 r#"
109pub fn count(xs, n) {
110 case xs {
111 [] -> n
112 [_, ..xs] -> count(xs, n + 1)
113 }
114}
115"#,
116 );
117}
118
119#[test]
120fn tail_call_doesnt_clobber_tail_position_tracking() {
121 assert_js!(
122 r#"
123pub fn loop(indentation) {
124 case indentation > 0 {
125 True -> loop(indentation - 1)
126 False -> Nil
127 }
128}
129"#,
130 );
131}
132
133#[test]
134fn pipe_last() {
135 assert_js!(
136 r#"fn id(x) { x }
137pub fn main() {
138 1
139 |> id
140}
141"#,
142 );
143}
144
145#[test]
146fn calling_fn_literal() {
147 assert_js!(
148 r#"pub fn main() {
149 fn(x) { x }(1)
150}
151"#,
152 );
153}
154
155// Don't mistake calling a function with the same name as the current function
156// as tail recursion
157#[test]
158fn shadowing_current() {
159 assert_js!(
160 r#"pub fn main() {
161 let main = fn() { 0 }
162 main()
163}
164"#,
165 );
166}
167
168#[test]
169fn recursion_with_discards() {
170 assert_js!(
171 r#"pub fn main(f, _) {
172 f()
173 main(f, 1)
174}
175"#,
176 );
177}
178
179#[test]
180fn no_recur_in_anon_fn() {
181 assert_js!(
182 r#"pub fn main() {
183 fn() { main() }
184 1
185}
186"#,
187 );
188}
189
190#[test]
191fn case_in_call() {
192 assert_js!(
193 r#"pub fn main(f, x) {
194 f(case x {
195 1 -> 2
196 _ -> 0
197 })
198}
199"#,
200 );
201}
202
203#[test]
204fn reserved_word_fn() {
205 assert_js!(
206 r#"pub fn class() {
207 Nil
208}
209"#,
210 );
211}
212
213#[test]
214fn reserved_word_imported() {
215 assert_js!(
216 ("for", "pub fn class() { 1 }"),
217 r#"import for.{class}
218
219pub fn export() {
220 class()
221}
222"#,
223 );
224}
225
226#[test]
227fn reserved_word_imported_alias() {
228 assert_js!(
229 ("for", "pub fn class() { 1 }"),
230 r#"import for.{class as while} as function
231
232pub fn export() {
233 let delete = function.class
234 while()
235}
236"#,
237 );
238}
239
240#[test]
241fn reserved_word_const() {
242 assert_js!(
243 r#"const in = 1
244
245pub fn export() {
246 in
247}
248"#,
249 );
250}
251
252// https://github.com/gleam-lang/gleam/issues/1208
253#[test]
254fn reserved_word_argument() {
255 assert_js!(
256 r#"pub fn main(with) {
257 with
258}
259"#,
260 );
261}
262
263// https://github.com/gleam-lang/gleam/issues/1186
264#[test]
265fn multiple_discard() {
266 assert_js!(
267 r#"pub fn main(_, _, _) {
268 1
269}
270"#,
271 );
272}
273
274#[test]
275fn keyword_in_recursive_function() {
276 assert_js!(
277 r#"pub fn main(with: Int) -> Nil {
278 main(with - 1)
279}
280"#,
281 );
282}
283
284#[test]
285fn reserved_word_in_function_arguments() {
286 assert_js!(
287 r#"pub fn main(arguments, eval) {
288 #(arguments, eval)
289}
290"#,
291 );
292}
293
294#[test]
295fn let_last() {
296 assert_js!(
297 r#"pub fn main() {
298 let x = 1
299}
300"#,
301 );
302}
303
304#[test]
305fn assert_last() {
306 assert_js!(
307 r#"pub fn main() {
308 let assert x = 1
309}
310"#,
311 );
312}
313
314#[test]
315fn fn_return_fn_typescript() {
316 assert_ts_def!(
317 r#"pub fn main(f: fn(Int) -> Int) {
318 let func = fn(x, y) { f(x) + f(y) }
319 func
320}
321"#,
322 );
323}
324
325// https://github.com/gleam-lang/gleam/issues/1637
326#[test]
327fn variable_rewriting_in_anon_fn_with_matching_parameter() {
328 assert_js!(
329 r#"pub fn bad() {
330 fn(state) {
331 let state = state
332 state
333 }
334}
335"#,
336 );
337}
338
339// https://github.com/gleam-lang/gleam/issues/1637
340#[test]
341fn variable_rewriting_in_anon_fn_with_matching_parameter_in_case() {
342 assert_js!(
343 r#"pub fn bad() {
344 fn(state) {
345 let state = case Nil {
346 _ -> state
347 }
348 state
349 }
350}
351"#,
352 );
353}
354
355// https://github.com/gleam-lang/gleam/issues/1508
356#[test]
357fn pipe_variable_rebinding() {
358 assert_js!(
359 "
360pub fn main() {
361 let version = 1 |> version()
362 version
363}
364
365pub fn version(n) {
366 Ok(1)
367}"
368 )
369}
370
371#[test]
372fn pipe_shadow_import() {
373 assert_js!(
374 ("wibble", "pub fn println(x: String) { }"),
375 r#"
376 import wibble.{println}
377 pub fn main() {
378 let println =
379 "oh dear"
380 |> println
381 println
382 }"#
383 );
384}
385
386#[test]
387fn module_const_fn() {
388 assert_js!(
389 r#"
390pub fn int_identity(i: Int) -> Int { i }
391pub const int_identity_alias: fn(Int) -> Int = int_identity
392pub fn use_int_identity_alias() { int_identity_alias(42) }
393
394pub const compound: #(fn(Int) -> Int, fn(Int) -> Int) = #(int_identity, int_identity_alias)
395pub fn use_compound() { compound.0(compound.1(42)) }"#
396 );
397}
398
399#[test]
400fn module_const_fn1() {
401 assert_ts_def!(
402 r#"
403pub fn int_identity(i: Int) -> Int { i }
404pub const int_identity_alias: fn(Int) -> Int = int_identity
405pub const compound: #(fn(Int) -> Int, fn(Int) -> Int) =
406 #(int_identity, int_identity_alias)"#
407 )
408}
409
410// https://github.com/gleam-lang/gleam/issues/2399
411#[test]
412fn bad_comma() {
413 assert_js!(
414 r#"
415fn function_with_a_long_name_that_is_intended_to_sit_right_on_the_limit() {
416 Nil
417}
418
419fn identity(x) {
420 x
421}
422
423pub fn main() {
424 function_with_a_long_name_that_is_intended_to_sit_right_on_the_limit()
425 |> identity
426}
427"#
428 )
429}
430
431// https://github.com/gleam-lang/gleam/issues/2518
432#[test]
433fn function_literals_get_properly_wrapped_1() {
434 assert_js!(
435 r#"pub fn main() {
436 fn(n) { n + 1 }(10)
437}
438"#
439 );
440}
441
442// https://github.com/gleam-lang/gleam/issues/2518
443#[test]
444fn function_literals_get_properly_wrapped_2() {
445 assert_js!(
446 r#"pub fn main() {
447 { fn(n) { n + 1 } }(10)
448}
449"#
450 );
451}
452
453// https://github.com/gleam-lang/gleam/issues/2518
454#[test]
455fn function_literals_get_properly_wrapped_3() {
456 assert_js!(
457 r#"pub fn main() {
458 { let a = fn(n) { n + 1 } }(10)
459}
460"#
461 );
462}
463
464#[test]
465fn labelled_argument_ordering() {
466 // https://github.com/gleam-lang/gleam/issues/3671
467 assert_js!(
468 "
469type A { A }
470type B { B }
471type C { C }
472type D { D }
473
474fn wibble(a a: A, b b: B, c c: C, d d: D) {
475 Nil
476}
477
478pub fn main() {
479 wibble(A, C, D, b: B)
480 wibble(A, C, D, b: B)
481 wibble(B, C, D, a: A)
482 wibble(B, C, a: A, d: D)
483 wibble(B, C, d: D, a: A)
484 wibble(B, D, a: A, c: C)
485 wibble(B, D, c: C, a: A)
486 wibble(C, D, b: B, a: A)
487}
488"
489 );
490}
491
492// During the implementation of https://github.com/gleam-lang/gleam/pull/4337,
493// a bug was found where this code would compile incorrectly.
494#[test]
495fn two_pipes_in_a_row() {
496 assert_js!(
497 "
498pub type Function(a) {
499 Function(fn() -> a)
500}
501
502pub fn main() {
503 [fn() { 1 } |> Function, fn() { 2 } |> Function]
504}
505"
506 );
507}
508
509// https://github.com/gleam-lang/gleam/issues/4472
510#[test]
511fn pipe_into_block() {
512 assert_js!(
513 "
514fn side_effects(x) { x }
515
516pub fn main() {
517 1
518 |> side_effects
519 |> {
520 side_effects(2)
521 side_effects
522 }
523}
524"
525 );
526}
527
528// https://github.com/gleam-lang/gleam/issues/4472
529#[test]
530fn pipe_with_block_in_the_middle() {
531 assert_js!(
532 "
533fn side_effects(x) { x }
534
535pub fn main() {
536 1
537 |> side_effects
538 |> {
539 side_effects(2)
540 side_effects
541 }
542 |> side_effects
543}
544"
545 );
546}
547
548// https://github.com/gleam-lang/gleam/issues/4533
549#[test]
550fn immediately_invoked_function_expressions_include_statement_level() {
551 assert_js!(
552 "
553fn identity(x) { x }
554
555pub type Wibble {
556 Wibble(a: Int, b: Int)
557}
558
559pub fn main() {
560 let w = Wibble(1, 2)
561 identity(Wibble(..w |> identity, b: 4)) |> identity
562}
563"
564 );
565}
566
567#[test]
568fn public_function_gets_jsdoc() {
569 assert_js!(
570 "
571/// Hello! This is the documentation of the `main`
572/// function.
573///
574pub fn main() { 1 }
575"
576 );
577}
578
579#[test]
580fn internal_function_gets_ignored_jsdoc() {
581 assert_js!(
582 "
583/// Hello! This is the documentation of the `main`
584/// function, which is internal!
585///
586@internal
587pub fn main() { 1 }
588"
589 );
590}
591
592#[test]
593fn star_slash_in_jsdoc() {
594 assert_js!(
595 "
596/// */
597///
598pub fn main() { 1 }
599"
600 );
601}
602
603// https://github.com/gleam-lang/gleam/issues/5488
604#[test]
605fn pipeline_has_correct_semicolons() {
606 assert_js!(
607 "
608pub fn main() {
609 1 |> echo |> fn(x) { { x + 1 } * 2 }
610 { 1 + 2 } * 3
611}
612"
613 );
614}
615
616#[test]
617fn pipeline_with_final_has_correct_semicolon() {
618 assert_js!(
619 "
620pub fn main() {
621 1 |> echo
622 { 1 + 2 } * 3
623}
624"
625 );
626}