plum
git clone https://git.pyrossh.dev/plum
A statically typed, imperative programming language inspired by rust, python
b48d3a3
— Peter John
2026-08-09T18:35:29+05:30
test: migrate embedded plum fixtures to `fun` keyword syntax
- plum-checker/tests/checker_tests.rs +63 -63
- plum-core/tests/formatter_test.rs +3 -3
- plum-core/tests/loader_test.rs +17 -17
- plum-core/tests/parser_test.rs +6 -6
- plum-wasm-codegen/tests/codegen_tests.rs +145 -145
plum-checker/tests/checker_tests.rs
CHANGED
|
@@ -53,14 +53,14 @@ fn mono_scheme() {
|
|
|
53
53
|
|
|
54
54
|
#[test]
|
|
55
55
|
fn valid_add_fn_passes() {
|
|
56
|
-
let src = "add(a: Int, b: Int) -> Int =\n a + b\n";
|
|
56
|
+
let src = "fun add(a: Int, b: Int) -> Int =\n a + b\n";
|
|
57
57
|
let source = parse(src);
|
|
58
58
|
assert!(check_source(&source).is_ok(), "expected Ok");
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
#[test]
|
|
62
62
|
fn wrong_return_type_is_error() {
|
|
63
|
-
let src = "bad() -> Int =\n True\n";
|
|
63
|
+
let src = "fun bad() -> Int =\n True\n";
|
|
64
64
|
let source = parse(src);
|
|
65
65
|
let result = check_source(&source);
|
|
66
66
|
assert!(result.is_err());
|
|
@@ -70,7 +70,7 @@ fn wrong_return_type_is_error() {
|
|
|
70
70
|
|
|
71
71
|
#[test]
|
|
72
72
|
fn undeclared_var_is_error() {
|
|
73
|
-
let src = "bad() -> Int =\n x\n";
|
|
73
|
+
let src = "fun bad() -> Int =\n x\n";
|
|
74
74
|
let source = parse(src);
|
|
75
75
|
let result = check_source(&source);
|
|
76
76
|
assert!(result.is_err());
|
|
@@ -78,7 +78,7 @@ fn undeclared_var_is_error() {
|
|
|
78
78
|
|
|
79
79
|
#[test]
|
|
80
80
|
fn type_mismatch_in_binary_op_is_error() {
|
|
81
|
-
let src = "bad() -> Int =\n 1 + 2.0\n";
|
|
81
|
+
let src = "fun bad() -> Int =\n 1 + 2.0\n";
|
|
82
82
|
let source = parse(src);
|
|
83
83
|
let result = check_source(&source);
|
|
84
84
|
assert!(result.is_err());
|
|
@@ -86,14 +86,14 @@ fn type_mismatch_in_binary_op_is_error() {
|
|
|
86
86
|
|
|
87
87
|
#[test]
|
|
88
88
|
fn bool_literal_true_false_are_bool() {
|
|
89
|
-
let src = "isTrue() -> Bool =\n True\n";
|
|
89
|
+
let src = "fun isTrue() -> Bool =\n True\n";
|
|
90
90
|
let source = parse(src);
|
|
91
91
|
assert!(check_source(&source).is_ok(), "expected Ok, got {:?}", check_source(&source).err());
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
#[test]
|
|
95
95
|
fn bool_literal_wrong_return_type_is_error() {
|
|
96
|
-
let src = "bad() -> Int =\n False\n";
|
|
96
|
+
let src = "fun bad() -> Int =\n False\n";
|
|
97
97
|
let source = parse(src);
|
|
98
98
|
let result = check_source(&source);
|
|
99
99
|
assert!(result.is_err());
|
|
@@ -101,7 +101,7 @@ fn bool_literal_wrong_return_type_is_error() {
|
|
|
101
101
|
|
|
102
102
|
#[test]
|
|
103
103
|
fn method_self_field_access_passes() {
|
|
104
|
-
let src = "type Cat =\n name: Str\n age: Int\n\
|
|
104
|
+
let src = "type Cat =\n name: Str\n age: Int\n\nfun getName<Cat>() -> Str =\n self.name\n";
|
|
105
105
|
let source = parse(src);
|
|
106
106
|
let result = check_source(&source);
|
|
107
107
|
assert!(result.is_ok(), "expected Ok, got {:?}", result.err());
|
|
@@ -109,7 +109,7 @@ fn method_self_field_access_passes() {
|
|
|
109
109
|
|
|
110
110
|
#[test]
|
|
111
111
|
fn method_self_unknown_field_is_error() {
|
|
112
|
-
let src = "type Cat =\n name: Str\n\
|
|
112
|
+
let src = "type Cat =\n name: Str\n\nfun getAge<Cat>() -> Int =\n self.age\n";
|
|
113
113
|
let source = parse(src);
|
|
114
114
|
let result = check_source(&source);
|
|
115
115
|
assert!(result.is_err());
|
|
@@ -117,7 +117,7 @@ fn method_self_unknown_field_is_error() {
|
|
|
117
117
|
|
|
118
118
|
#[test]
|
|
119
119
|
fn self_outside_method_is_error() {
|
|
120
|
-
let src = "bad() -> Int =\n self\n";
|
|
120
|
+
let src = "fun bad() -> Int =\n self\n";
|
|
121
121
|
let source = parse(src);
|
|
122
122
|
let result = check_source(&source);
|
|
123
123
|
assert!(result.is_err());
|
|
@@ -125,7 +125,7 @@ fn self_outside_method_is_error() {
|
|
|
125
125
|
|
|
126
126
|
#[test]
|
|
127
127
|
fn class_call_checks_field_types() {
|
|
128
|
-
let src = "type Cat =\n name: Str\n age: Int\n\
|
|
128
|
+
let src = "type Cat =\n name: Str\n age: Int\n\nfun makeCat() -> Cat =\n Cat(name: \"x\", age: 1)\n";
|
|
129
129
|
let source = parse(src);
|
|
130
130
|
let result = check_source(&source);
|
|
131
131
|
assert!(result.is_ok(), "expected Ok, got {:?}", result.err());
|
|
@@ -133,7 +133,7 @@ fn class_call_checks_field_types() {
|
|
|
133
133
|
|
|
134
134
|
#[test]
|
|
135
135
|
fn class_call_wrong_field_type_is_error() {
|
|
136
|
-
let src = "type Cat =\n name: Str\n age: Int\n\
|
|
136
|
+
let src = "type Cat =\n name: Str\n age: Int\n\nfun makeCat() -> Cat =\n Cat(name: \"x\", age: \"y\")\n";
|
|
137
137
|
let source = parse(src);
|
|
138
138
|
let result = check_source(&source);
|
|
139
139
|
assert!(result.is_err());
|
|
@@ -141,7 +141,7 @@ fn class_call_wrong_field_type_is_error() {
|
|
|
141
141
|
|
|
142
142
|
#[test]
|
|
143
143
|
fn class_call_unknown_field_is_error() {
|
|
144
|
-
let src = "type Cat =\n name: Str\n\
|
|
144
|
+
let src = "type Cat =\n name: Str\n\nfun makeCat() -> Cat =\n Cat(name: \"x\", age: 1)\n";
|
|
145
145
|
let source = parse(src);
|
|
146
146
|
let result = check_source(&source);
|
|
147
147
|
assert!(result.is_err());
|
|
@@ -149,7 +149,7 @@ fn class_call_unknown_field_is_error() {
|
|
|
149
149
|
|
|
150
150
|
#[test]
|
|
151
151
|
fn method_call_via_attribute_type_checks_args() {
|
|
152
|
-
let src = "type Cat =\n name: Str\n\
|
|
152
|
+
let src = "type Cat =\n name: Str\n\nfun rename<Cat>(n: Str) -> Str =\n n\n\nfun use(c: Cat) -> Str =\n c.rename(\"x\")\n";
|
|
153
153
|
let source = parse(src);
|
|
154
154
|
let result = check_source(&source);
|
|
155
155
|
assert!(result.is_ok(), "expected Ok, got {:?}", result.err());
|
|
@@ -157,7 +157,7 @@ fn method_call_via_attribute_type_checks_args() {
|
|
|
157
157
|
|
|
158
158
|
#[test]
|
|
159
159
|
fn match_binds_name_pattern_to_subject_type() {
|
|
160
|
-
let src = "main(a: Int) -> Int =\n match a\n x =>\n x\n _ =>\n 0\n";
|
|
160
|
+
let src = "fun main(a: Int) -> Int =\n match a\n x =>\n x\n _ =>\n 0\n";
|
|
161
161
|
let source = parse(src);
|
|
162
162
|
let result = check_source(&source);
|
|
163
163
|
assert!(result.is_ok(), "expected Ok, got {:?}", result.err());
|
|
@@ -166,7 +166,7 @@ fn match_binds_name_pattern_to_subject_type() {
|
|
|
166
166
|
#[test]
|
|
167
167
|
fn match_inline_case_body_type_checks() {
|
|
168
168
|
// Case bodies can be a single inline expression, not just an indented block.
|
|
169
|
-
let src = "main(a: Int) -> Int =\n match a\n 1 => 10\n _ => 0\n";
|
|
169
|
+
let src = "fun main(a: Int) -> Int =\n match a\n 1 => 10\n _ => 0\n";
|
|
170
170
|
let source = parse(src);
|
|
171
171
|
let result = check_source(&source);
|
|
172
172
|
assert!(result.is_ok(), "expected Ok, got {:?}", result.err());
|
|
@@ -178,7 +178,7 @@ fn match_true_false_are_variant_patterns_not_bindings_without_enum_decl() {
|
|
|
178
178
|
// comparisons even when the source doesn't redeclare `enum Bool`, so a
|
|
179
179
|
// later `_` wildcard arm remains reachable (each pattern binds/compares,
|
|
180
180
|
// it doesn't just re-bind the subject under the name "True").
|
|
181
|
-
let src = "pick(a: Bool) -> Int =\n match a\n True =>\n 1\n False =>\n 0\n";
|
|
181
|
+
let src = "fun pick(a: Bool) -> Int =\n match a\n True =>\n 1\n False =>\n 0\n";
|
|
182
182
|
let source = parse(src);
|
|
183
183
|
let result = check_source(&source);
|
|
184
184
|
assert!(result.is_ok(), "expected Ok, got {:?}", result.err());
|
|
@@ -186,7 +186,7 @@ fn match_true_false_are_variant_patterns_not_bindings_without_enum_decl() {
|
|
|
186
186
|
|
|
187
187
|
#[test]
|
|
188
188
|
fn match_int_pattern_against_str_subject_is_error() {
|
|
189
|
-
let src = "main(a: Str) -> Int =\n match a\n 1 =>\n 1\n _ =>\n 0\n";
|
|
189
|
+
let src = "fun main(a: Str) -> Int =\n match a\n 1 =>\n 1\n _ =>\n 0\n";
|
|
190
190
|
let source = parse(src);
|
|
191
191
|
let result = check_source(&source);
|
|
192
192
|
assert!(result.is_err());
|
|
@@ -202,7 +202,7 @@ enum Option =
|
|
|
202
202
|
| Some(Int)
|
|
203
203
|
| None
|
|
204
204
|
|
|
205
|
-
isNone(o: Option) -> Bool = o == None
|
|
205
|
+
fun isNone(o: Option) -> Bool = o == None
|
|
206
206
|
";
|
|
207
207
|
let source = parse(src);
|
|
208
208
|
let result = check_source(&source);
|
|
@@ -216,7 +216,7 @@ enum Option =
|
|
|
216
216
|
| Some[Int]
|
|
217
217
|
| None
|
|
218
218
|
|
|
219
|
-
makeSome(v: Int) -> Option =
|
|
219
|
+
fun makeSome(v: Int) -> Option =
|
|
220
220
|
Some(v)
|
|
221
221
|
";
|
|
222
222
|
let source = parse(src);
|
|
@@ -231,7 +231,7 @@ enum Option =
|
|
|
231
231
|
| Some(Int)
|
|
232
232
|
| None
|
|
233
233
|
|
|
234
|
-
bad() -> Option =
|
|
234
|
+
fun bad() -> Option =
|
|
235
235
|
Some(\"x\")
|
|
236
236
|
";
|
|
237
237
|
let source = parse(src);
|
|
@@ -246,7 +246,7 @@ enum Shape =
|
|
|
246
246
|
| Rect[Float, Float]
|
|
247
247
|
| Circle[Float]
|
|
248
248
|
|
|
249
|
-
bad() -> Shape =
|
|
249
|
+
fun bad() -> Shape =
|
|
250
250
|
Rect(1.0)
|
|
251
251
|
";
|
|
252
252
|
let source = parse(src);
|
|
@@ -261,7 +261,7 @@ enum Shape =
|
|
|
261
261
|
| Rect[Float, Float]
|
|
262
262
|
| Circle[Float]
|
|
263
263
|
|
|
264
|
-
area(s: Shape) -> Float =
|
|
264
|
+
fun area(s: Shape) -> Float =
|
|
265
265
|
match s
|
|
266
266
|
Rect(w, h) =>
|
|
267
267
|
w * h
|
|
@@ -280,7 +280,7 @@ enum Shape =
|
|
|
280
280
|
| Rect[Float, Float]
|
|
281
281
|
| Circle[Float]
|
|
282
282
|
|
|
283
|
-
bad(s: Shape) -> Float =
|
|
283
|
+
fun bad(s: Shape) -> Float =
|
|
284
284
|
match s
|
|
285
285
|
Rect(w) =>
|
|
286
286
|
w
|
|
@@ -322,10 +322,10 @@ fn generic_class_instantiated_at_two_concrete_types_type_checks() {
|
|
|
322
322
|
type Box[T] =
|
|
323
323
|
value: T
|
|
324
324
|
|
|
325
|
-
makeIntBox() -> Box =
|
|
325
|
+
fun makeIntBox() -> Box =
|
|
326
326
|
Box(value: 5)
|
|
327
327
|
|
|
328
|
-
makeStrBox() -> Box =
|
|
328
|
+
fun makeStrBox() -> Box =
|
|
329
329
|
Box(value: \"x\")
|
|
330
330
|
";
|
|
331
331
|
let source = parse(src);
|
|
@@ -336,13 +336,13 @@ makeStrBox() -> Box =
|
|
|
336
336
|
#[test]
|
|
337
337
|
fn generic_function_called_with_different_concrete_types_per_site_type_checks() {
|
|
338
338
|
let src = "\
|
|
339
|
-
wrap(value: T) -> Bool =
|
|
339
|
+
fun wrap(value: T) -> Bool =
|
|
340
340
|
True
|
|
341
341
|
|
|
342
|
-
useInt() -> Bool =
|
|
342
|
+
fun useInt() -> Bool =
|
|
343
343
|
wrap(5)
|
|
344
344
|
|
|
345
|
-
useStr() -> Bool =
|
|
345
|
+
fun useStr() -> Bool =
|
|
346
346
|
wrap(\"x\")
|
|
347
347
|
";
|
|
348
348
|
let source = parse(src);
|
|
@@ -353,10 +353,10 @@ useStr() -> Bool =
|
|
|
353
353
|
#[test]
|
|
354
354
|
fn generic_function_with_two_independent_type_params_type_checks() {
|
|
355
355
|
let src = "\
|
|
356
|
-
pair(first: T, second: U) -> Bool =
|
|
356
|
+
fun pair(first: T, second: U) -> Bool =
|
|
357
357
|
True
|
|
358
358
|
|
|
359
|
-
use() -> Bool =
|
|
359
|
+
fun use() -> Bool =
|
|
360
360
|
pair(1, \"x\")
|
|
361
361
|
";
|
|
362
362
|
let source = parse(src);
|
|
@@ -372,10 +372,10 @@ fn generic_function_with_internally_inconsistent_body_is_rejected_after_speciali
|
|
|
372
372
|
// behavior — rewriting `wrong$Str`'s `-> Int` to `-> Str` — would make the
|
|
373
373
|
// whole program type-check, masking the real `expected Int, found Str` error.
|
|
374
374
|
let src = "\
|
|
375
|
-
wrong(x: T) -> Int =
|
|
375
|
+
fun wrong(x: T) -> Int =
|
|
376
376
|
\"hello\"
|
|
377
377
|
|
|
378
|
-
useIt() -> Str =
|
|
378
|
+
fun useIt() -> Str =
|
|
379
379
|
wrong(\"s\")
|
|
380
380
|
";
|
|
381
381
|
let source = parse(src);
|
|
@@ -395,7 +395,7 @@ enum Option =
|
|
|
395
395
|
| Some[T]
|
|
396
396
|
| None
|
|
397
397
|
|
|
398
|
-
get() -> Int =
|
|
398
|
+
fun get() -> Int =
|
|
399
399
|
o = Some(5)
|
|
400
400
|
match o
|
|
401
401
|
Some(v) =>
|
|
@@ -438,7 +438,7 @@ enum Option =
|
|
|
438
438
|
| Some[T]
|
|
439
439
|
| None
|
|
440
440
|
|
|
441
|
-
useInt() -> Int =
|
|
441
|
+
fun useInt() -> Int =
|
|
442
442
|
o = Some(5)
|
|
443
443
|
match o
|
|
444
444
|
Some(v) =>
|
|
@@ -446,7 +446,7 @@ useInt() -> Int =
|
|
|
446
446
|
None =>
|
|
447
447
|
0
|
|
448
448
|
|
|
449
|
-
useStr() -> Str =
|
|
449
|
+
fun useStr() -> Str =
|
|
450
450
|
o = Some(\"x\")
|
|
451
451
|
match o
|
|
452
452
|
Some(v) =>
|
|
@@ -476,10 +476,10 @@ fn generic_method_on_generic_class_type_checks() {
|
|
|
476
476
|
type Box[T] =
|
|
477
477
|
value: T
|
|
478
478
|
|
|
479
|
-
getValue<Box>() -> T =
|
|
479
|
+
fun getValue<Box>() -> T =
|
|
480
480
|
self.value
|
|
481
481
|
|
|
482
|
-
use() -> Int =
|
|
482
|
+
fun use() -> Int =
|
|
483
483
|
b = Box(value: 5)
|
|
484
484
|
b.getValue()
|
|
485
485
|
";
|
|
@@ -502,11 +502,11 @@ fn unbounded_recursive_generic_instantiation_is_a_clear_error() {
|
|
|
502
502
|
type Box[T] =
|
|
503
503
|
value: T
|
|
504
504
|
|
|
505
|
-
recurse(v: T) -> Int =
|
|
505
|
+
fun recurse(v: T) -> Int =
|
|
506
506
|
b = Box(value: v)
|
|
507
507
|
recurse(b)
|
|
508
508
|
|
|
509
|
-
use() -> Int =
|
|
509
|
+
fun use() -> Int =
|
|
510
510
|
recurse(5)
|
|
511
511
|
";
|
|
512
512
|
let source = parse(src);
|
|
@@ -528,14 +528,14 @@ enum Option =
|
|
|
528
528
|
| Some[T]
|
|
529
529
|
| None
|
|
530
530
|
|
|
531
|
-
unwrapOr(o: Option, default: Int) -> Int =
|
|
531
|
+
fun unwrapOr(o: Option, default: Int) -> Int =
|
|
532
532
|
match o
|
|
533
533
|
Some(v) =>
|
|
534
534
|
v
|
|
535
535
|
None =>
|
|
536
536
|
default
|
|
537
537
|
|
|
538
|
-
use() -> Int =
|
|
538
|
+
fun use() -> Int =
|
|
539
539
|
unwrapOr(Some(5), 0)
|
|
540
540
|
";
|
|
541
541
|
let source = parse(src);
|
|
@@ -559,13 +559,13 @@ fn ordinary_function_with_bare_generic_class_param_type_checks() {
|
|
|
559
559
|
type Box[T] =
|
|
560
560
|
value: T
|
|
561
561
|
|
|
562
|
-
getBoxValue<Box>() -> T =
|
|
562
|
+
fun getBoxValue<Box>() -> T =
|
|
563
563
|
self.value
|
|
564
564
|
|
|
565
|
-
sumBox(b: Box) -> Int =
|
|
565
|
+
fun sumBox(b: Box) -> Int =
|
|
566
566
|
b.getBoxValue()
|
|
567
567
|
|
|
568
|
-
use() -> Int =
|
|
568
|
+
fun use() -> Int =
|
|
569
569
|
sumBox(Box(value: 5))
|
|
570
570
|
";
|
|
571
571
|
let source = parse(src);
|
|
@@ -576,7 +576,7 @@ use() -> Int =
|
|
|
576
576
|
#[test]
|
|
577
577
|
fn closure_literal_infers_as_a_function_type() {
|
|
578
578
|
let src = "\
|
|
579
|
-
useClosure() -> Bool =
|
|
579
|
+
fun useClosure() -> Bool =
|
|
580
580
|
cb = |v|
|
|
581
581
|
True
|
|
582
582
|
cb(5)
|
|
@@ -589,7 +589,7 @@ useClosure() -> Bool =
|
|
|
589
589
|
#[test]
|
|
590
590
|
fn fn_value_typed_param_can_be_called() {
|
|
591
591
|
let src = "\
|
|
592
|
-
each(cb: fn(Int) -> Bool) -> Bool =
|
|
592
|
+
fun each(cb: fn(Int) -> Bool) -> Bool =
|
|
593
593
|
cb(5)
|
|
594
594
|
";
|
|
595
595
|
let source = parse(src);
|
|
@@ -604,7 +604,7 @@ type Cat =
|
|
|
604
604
|
name: Str
|
|
605
605
|
age: Int
|
|
606
606
|
|
|
607
|
-
haveBirthday<Cat>() =
|
|
607
|
+
fun haveBirthday<Cat>() =
|
|
608
608
|
self.age = self.age + 1
|
|
609
609
|
";
|
|
610
610
|
let source = parse(src);
|
|
@@ -618,7 +618,7 @@ type Cat =
|
|
|
618
618
|
name: Str
|
|
619
619
|
age: Int
|
|
620
620
|
|
|
621
|
-
breakCat<Cat>() =
|
|
621
|
+
fun breakCat<Cat>() =
|
|
622
622
|
self.age = \"oops\"
|
|
623
623
|
";
|
|
624
624
|
let source = parse(src);
|
|
@@ -633,7 +633,7 @@ type Cat =
|
|
|
633
633
|
name: Str
|
|
634
634
|
age: Int
|
|
635
635
|
|
|
636
|
-
breakCat<Cat>() =
|
|
636
|
+
fun breakCat<Cat>() =
|
|
637
637
|
self.nope = 1
|
|
638
638
|
";
|
|
639
639
|
let source = parse(src);
|
|
@@ -644,10 +644,10 @@ breakCat<Cat>() =
|
|
|
644
644
|
#[test]
|
|
645
645
|
fn closure_passed_to_fn_value_typed_param_type_checks() {
|
|
646
646
|
let src = "\
|
|
647
|
-
each(cb: fn(Int) -> Bool) -> Bool =
|
|
647
|
+
fun each(cb: fn(Int) -> Bool) -> Bool =
|
|
648
648
|
cb(5)
|
|
649
649
|
|
|
650
|
-
use() -> Bool =
|
|
650
|
+
fun use() -> Bool =
|
|
651
651
|
each(|v|
|
|
652
652
|
True)
|
|
653
653
|
";
|
|
@@ -659,10 +659,10 @@ use() -> Bool =
|
|
|
659
659
|
#[test]
|
|
660
660
|
fn variadic_call_with_zero_trailing_args_passes() {
|
|
661
661
|
let src = "\
|
|
662
|
-
sumAll(nums: ...Int) -> Int =
|
|
662
|
+
fun sumAll(nums: ...Int) -> Int =
|
|
663
663
|
0
|
|
664
664
|
|
|
665
|
-
useSumAll() -> Int =
|
|
665
|
+
fun useSumAll() -> Int =
|
|
666
666
|
sumAll()
|
|
667
667
|
";
|
|
668
668
|
let source = parse(src);
|
|
@@ -672,10 +672,10 @@ useSumAll() -> Int =
|
|
|
672
672
|
#[test]
|
|
673
673
|
fn variadic_call_with_several_trailing_args_passes() {
|
|
674
674
|
let src = "\
|
|
675
|
-
sumAll(nums: ...Int) -> Int =
|
|
675
|
+
fun sumAll(nums: ...Int) -> Int =
|
|
676
676
|
0
|
|
677
677
|
|
|
678
|
-
useSumAll() -> Int =
|
|
678
|
+
fun useSumAll() -> Int =
|
|
679
679
|
sumAll(1, 2, 3)
|
|
680
680
|
";
|
|
681
681
|
let source = parse(src);
|
|
@@ -685,10 +685,10 @@ useSumAll() -> Int =
|
|
|
685
685
|
#[test]
|
|
686
686
|
fn variadic_call_with_mismatched_trailing_arg_type_is_error() {
|
|
687
687
|
let src = "\
|
|
688
|
-
sumAll(nums: ...Int) -> Int =
|
|
688
|
+
fun sumAll(nums: ...Int) -> Int =
|
|
689
689
|
0
|
|
690
690
|
|
|
691
|
-
useSumAll() -> Int =
|
|
691
|
+
fun useSumAll() -> Int =
|
|
692
692
|
sumAll(1, \"two\")
|
|
693
693
|
";
|
|
694
694
|
let source = parse(src);
|
|
@@ -698,10 +698,10 @@ useSumAll() -> Int =
|
|
|
698
698
|
#[test]
|
|
699
699
|
fn variadic_call_with_fixed_prefix_passes() {
|
|
700
700
|
let src = "\
|
|
701
|
-
combine(prefix: Int, rest: ...Int) -> Int =
|
|
701
|
+
fun combine(prefix: Int, rest: ...Int) -> Int =
|
|
702
702
|
prefix
|
|
703
703
|
|
|
704
|
-
useCombine() -> Int =
|
|
704
|
+
fun useCombine() -> Int =
|
|
705
705
|
combine(1, 2, 3)
|
|
706
706
|
";
|
|
707
707
|
let source = parse(src);
|
|
@@ -711,7 +711,7 @@ useCombine() -> Int =
|
|
|
711
711
|
#[test]
|
|
712
712
|
fn two_variadic_params_is_error() {
|
|
713
713
|
let src = "\
|
|
714
|
-
bad(a: ...Int, b: ...Int) -> Int =
|
|
714
|
+
fun bad(a: ...Int, b: ...Int) -> Int =
|
|
715
715
|
0
|
|
716
716
|
";
|
|
717
717
|
let source = parse(src);
|
|
@@ -721,7 +721,7 @@ bad(a: ...Int, b: ...Int) -> Int =
|
|
|
721
721
|
#[test]
|
|
722
722
|
fn variadic_param_not_last_is_error() {
|
|
723
723
|
let src = "\
|
|
724
|
-
bad(a: ...Int, b: Int) -> Int =
|
|
724
|
+
fun bad(a: ...Int, b: Int) -> Int =
|
|
725
725
|
0
|
|
726
726
|
";
|
|
727
727
|
let source = parse(src);
|
|
@@ -731,7 +731,7 @@ bad(a: ...Int, b: Int) -> Int =
|
|
|
731
731
|
#[test]
|
|
732
732
|
fn for_loop_over_variadic_binds_element_type() {
|
|
733
733
|
let src = "\
|
|
734
|
-
sumAll(nums: ...Int) -> Int =
|
|
734
|
+
fun sumAll(nums: ...Int) -> Int =
|
|
735
735
|
total = 0
|
|
736
736
|
for v in nums
|
|
737
737
|
total = total + v
|
|
@@ -744,7 +744,7 @@ sumAll(nums: ...Int) -> Int =
|
|
|
744
744
|
#[test]
|
|
745
745
|
fn for_loop_over_variadic_with_two_vars_is_error() {
|
|
746
746
|
let src = "\
|
|
747
|
-
bad(nums: ...Int) -> Int =
|
|
747
|
+
fun bad(nums: ...Int) -> Int =
|
|
748
748
|
for v, i in nums
|
|
749
749
|
v
|
|
750
750
|
0
|
plum-core/tests/formatter_test.rs
CHANGED
|
@@ -2,7 +2,7 @@ use plum_core::format_source;
|
|
|
2
2
|
|
|
3
3
|
#[test]
|
|
4
4
|
fn formats_simple_function() {
|
|
5
|
-
let input = "main() =\n x = 1\n";
|
|
5
|
+
let input = "fun main() =\n x = 1\n";
|
|
6
6
|
let result = format_source(input).expect("format_source should succeed");
|
|
7
7
|
assert!(result.contains("main()"));
|
|
8
8
|
assert!(result.contains("x ="));
|
|
@@ -10,7 +10,7 @@ fn formats_simple_function() {
|
|
|
10
10
|
|
|
11
11
|
#[test]
|
|
12
12
|
fn formats_binary_operator_spacing() {
|
|
13
|
-
let input = "add<Int>(a: Int, b: Int) -> Int =\n a+b\n";
|
|
13
|
+
let input = "fun add<Int>(a: Int, b: Int) -> Int =\n a+b\n";
|
|
14
14
|
let result = format_source(input).expect("format_source should succeed");
|
|
15
15
|
assert!(result.contains("a + b"));
|
|
16
16
|
}
|
|
@@ -24,7 +24,7 @@ fn rejects_syntax_error() {
|
|
|
24
24
|
|
|
25
25
|
#[test]
|
|
26
26
|
fn idempotent_on_already_formatted() {
|
|
27
|
-
let input = "main() =\n x = 1 + 2\n";
|
|
27
|
+
let input = "fun main() =\n x = 1 + 2\n";
|
|
28
28
|
let first = format_source(input).expect("first pass");
|
|
29
29
|
let second = format_source(&first).expect("second pass");
|
|
30
30
|
assert_eq!(first, second, "formatting should be idempotent");
|
plum-core/tests/loader_test.rs
CHANGED
|
@@ -16,8 +16,8 @@ fn write_lib_file(lib_path: &std::path::Path, name: &str, contents: &str) -> std
|
|
|
16
16
|
fn import_sees_imported_declarations() {
|
|
17
17
|
let dir = TempDir::new().unwrap();
|
|
18
18
|
let lib_path = dir.path().join("libs");
|
|
19
|
-
write_lib_file(&lib_path, "helper", "module fixtures\n\
|
|
19
|
+
write_lib_file(&lib_path, "helper", "module fixtures\n\nfun helperFn() -> Int =\n 42\n");
|
|
20
|
-
let entry = write_lib_file(&lib_path, "main", "module fixtures\n\nimport helper\n\
|
|
20
|
+
let entry = write_lib_file(&lib_path, "main", "module fixtures\n\nimport helper\n\nfun main() -> Int =\n helperFn()\n");
|
|
21
21
|
|
|
22
22
|
let merged = load_and_merge(&entry, &lib_path).expect("load_and_merge failed");
|
|
23
23
|
let names: Vec<&str> = merged.items.iter().filter_map(|i| match i {
|
|
@@ -32,9 +32,9 @@ fn import_sees_imported_declarations() {
|
|
|
32
32
|
fn transitive_import_surfaces_grandchild_declarations() {
|
|
33
33
|
let dir = TempDir::new().unwrap();
|
|
34
34
|
let lib_path = dir.path().join("libs");
|
|
35
|
-
write_lib_file(&lib_path, "c", "module fixtures\n\
|
|
35
|
+
write_lib_file(&lib_path, "c", "module fixtures\n\nfun cFn() -> Int =\n 3\n");
|
|
36
|
-
write_lib_file(&lib_path, "b", "module fixtures\n\nimport c\n\
|
|
36
|
+
write_lib_file(&lib_path, "b", "module fixtures\n\nimport c\n\nfun bFn() -> Int =\n cFn()\n");
|
|
37
|
-
let entry = write_lib_file(&lib_path, "a", "module fixtures\n\nimport b\n\
|
|
37
|
+
let entry = write_lib_file(&lib_path, "a", "module fixtures\n\nimport b\n\nfun main() -> Int =\n bFn()\n");
|
|
38
38
|
|
|
39
39
|
let merged = load_and_merge(&entry, &lib_path).expect("load_and_merge failed");
|
|
40
40
|
let names: Vec<&str> = merged.items.iter().filter_map(|i| match i {
|
|
@@ -48,10 +48,10 @@ fn transitive_import_surfaces_grandchild_declarations() {
|
|
|
48
48
|
fn diamond_import_includes_shared_dependency_once() {
|
|
49
49
|
let dir = TempDir::new().unwrap();
|
|
50
50
|
let lib_path = dir.path().join("libs");
|
|
51
|
-
write_lib_file(&lib_path, "d", "module fixtures\n\
|
|
51
|
+
write_lib_file(&lib_path, "d", "module fixtures\n\nfun dFn() -> Int =\n 4\n");
|
|
52
|
-
write_lib_file(&lib_path, "b", "module fixtures\n\nimport d\n\
|
|
52
|
+
write_lib_file(&lib_path, "b", "module fixtures\n\nimport d\n\nfun bFn() -> Int =\n dFn()\n");
|
|
53
|
-
write_lib_file(&lib_path, "c", "module fixtures\n\nimport d\n\
|
|
53
|
+
write_lib_file(&lib_path, "c", "module fixtures\n\nimport d\n\nfun cFn() -> Int =\n dFn()\n");
|
|
54
|
-
let entry = write_lib_file(&lib_path, "a", "module fixtures\n\nimport b\nimport c\n\
|
|
54
|
+
let entry = write_lib_file(&lib_path, "a", "module fixtures\n\nimport b\nimport c\n\nfun main() -> Int =\n bFn() + cFn()\n");
|
|
55
55
|
|
|
56
56
|
let merged = load_and_merge(&entry, &lib_path).expect("load_and_merge failed");
|
|
57
57
|
let d_count = merged.items.iter().filter(|i| matches!(i, plum_core::ast::Item::Fn(f) if f.name == "dFn")).count();
|
|
@@ -62,8 +62,8 @@ fn diamond_import_includes_shared_dependency_once() {
|
|
|
62
62
|
fn import_cycle_resolves_without_hanging_or_erroring() {
|
|
63
63
|
let dir = TempDir::new().unwrap();
|
|
64
64
|
let lib_path = dir.path().join("libs");
|
|
65
|
-
write_lib_file(&lib_path, "b", "module fixtures\n\nimport a\n\
|
|
65
|
+
write_lib_file(&lib_path, "b", "module fixtures\n\nimport a\n\nfun bFn() -> Int =\n 1\n");
|
|
66
|
-
let entry = write_lib_file(&lib_path, "a", "module fixtures\n\nimport b\n\
|
|
66
|
+
let entry = write_lib_file(&lib_path, "a", "module fixtures\n\nimport b\n\nfun main() -> Int =\n bFn()\n");
|
|
67
67
|
|
|
68
68
|
let merged = load_and_merge(&entry, &lib_path).expect("import cycle should resolve, not error");
|
|
69
69
|
let names: Vec<&str> = merged.items.iter().filter_map(|i| match i {
|
|
@@ -78,7 +78,7 @@ fn import_cycle_resolves_without_hanging_or_erroring() {
|
|
|
78
78
|
fn unresolvable_import_is_a_clear_error() {
|
|
79
79
|
let dir = TempDir::new().unwrap();
|
|
80
80
|
let lib_path = dir.path().join("libs");
|
|
81
|
-
let entry = write_lib_file(&lib_path, "main", "module fixtures\n\nimport does_not_exist\n\
|
|
81
|
+
let entry = write_lib_file(&lib_path, "main", "module fixtures\n\nimport does_not_exist\n\nfun main() -> Int =\n 0\n");
|
|
82
82
|
|
|
83
83
|
let result = load_and_merge(&entry, &lib_path);
|
|
84
84
|
assert!(result.is_err());
|
|
@@ -90,8 +90,8 @@ fn unresolvable_import_is_a_clear_error() {
|
|
|
90
90
|
fn duplicate_top_level_name_across_files_is_a_clear_error() {
|
|
91
91
|
let dir = TempDir::new().unwrap();
|
|
92
92
|
let lib_path = dir.path().join("libs");
|
|
93
|
-
write_lib_file(&lib_path, "helper", "module fixtures\n\
|
|
93
|
+
write_lib_file(&lib_path, "helper", "module fixtures\n\nfun sharedFn() -> Int =\n 1\n");
|
|
94
|
-
let entry = write_lib_file(&lib_path, "main", "module fixtures\n\nimport helper\n\
|
|
94
|
+
let entry = write_lib_file(&lib_path, "main", "module fixtures\n\nimport helper\n\nfun sharedFn() -> Int =\n 2\n");
|
|
95
95
|
|
|
96
96
|
let result = load_and_merge(&entry, &lib_path);
|
|
97
97
|
assert!(result.is_err());
|
|
@@ -109,7 +109,7 @@ module fixtures
|
|
|
109
109
|
type Cat =
|
|
110
110
|
age: Int
|
|
111
111
|
|
|
112
|
-
length<Cat>(self) -> Int =
|
|
112
|
+
fun length<Cat>(self) -> Int =
|
|
113
113
|
self.age
|
|
114
114
|
");
|
|
115
115
|
let entry = write_lib_file(&lib_path, "main", "\
|
|
@@ -120,10 +120,10 @@ import cat
|
|
|
120
120
|
type Box =
|
|
121
121
|
items: Int
|
|
122
122
|
|
|
123
|
-
length<Box>(self) -> Int =
|
|
123
|
+
fun length<Box>(self) -> Int =
|
|
124
124
|
self.items
|
|
125
125
|
|
|
126
|
-
main() -> Int =
|
|
126
|
+
fun main() -> Int =
|
|
127
127
|
0
|
|
128
128
|
");
|
|
129
129
|
|
plum-core/tests/parser_test.rs
CHANGED
|
@@ -21,7 +21,7 @@ fn only_trait(source: &Source) -> &Trait {
|
|
|
21
21
|
#[test]
|
|
22
22
|
fn closure_literal_parses_with_params_and_body() {
|
|
23
23
|
let src = "\
|
|
24
|
-
useClosure() -> Bool =
|
|
24
|
+
fun useClosure() -> Bool =
|
|
25
25
|
cb = |v|
|
|
26
26
|
True
|
|
27
27
|
cb(5)
|
|
@@ -38,7 +38,7 @@ useClosure() -> Bool =
|
|
|
38
38
|
#[test]
|
|
39
39
|
fn closure_literal_parses_with_no_params() {
|
|
40
40
|
let src = "\
|
|
41
|
-
useClosure() -> Bool =
|
|
41
|
+
fun useClosure() -> Bool =
|
|
42
42
|
cb = ||
|
|
43
43
|
True
|
|
44
44
|
cb()
|
|
@@ -53,7 +53,7 @@ useClosure() -> Bool =
|
|
|
53
53
|
|
|
54
54
|
#[test]
|
|
55
55
|
fn fn_without_receiver_but_with_return_type_has_no_type_param() {
|
|
56
|
-
let src = "main() -> Int =\n 0\n";
|
|
56
|
+
let src = "fun main() -> Int =\n 0\n";
|
|
57
57
|
let source = parse(src);
|
|
58
58
|
let f = only_fn(&source);
|
|
59
59
|
assert_eq!(f.type_param, None, "return type must not be mistaken for a method receiver");
|
|
@@ -62,7 +62,7 @@ fn fn_without_receiver_but_with_return_type_has_no_type_param() {
|
|
|
62
62
|
|
|
63
63
|
#[test]
|
|
64
64
|
fn fn_with_receiver_and_return_type_has_correct_type_param() {
|
|
65
|
-
let src = "toStr<Cat>() -> Str =\n \"x\"\n";
|
|
65
|
+
let src = "fun toStr<Cat>() -> Str =\n \"x\"\n";
|
|
66
66
|
let source = parse(src);
|
|
67
67
|
let f = only_fn(&source);
|
|
68
68
|
assert_eq!(f.type_param, Some("Cat".to_string()));
|
|
@@ -71,7 +71,7 @@ fn fn_with_receiver_and_return_type_has_correct_type_param() {
|
|
|
71
71
|
|
|
72
72
|
#[test]
|
|
73
73
|
fn fn_value_type_param_parses_with_positional_types_and_return() {
|
|
74
|
-
let src = "each(cb: fn(Int) -> Bool) -> Bool =\n True\n";
|
|
74
|
+
let src = "fun each(cb: fn(Int) -> Bool) -> Bool =\n True\n";
|
|
75
75
|
let source = parse(src);
|
|
76
76
|
let f = only_fn(&source);
|
|
77
77
|
let ParamType::Fn(param_types, ret) = &f.params[0].ty else { panic!("expected ParamType::Fn, got {:?}", f.params[0].ty) };
|
|
@@ -96,7 +96,7 @@ fn trait_method_return_type_is_not_mangled_to_arrow_token() {
|
|
|
96
96
|
|
|
97
97
|
#[test]
|
|
98
98
|
fn fn_value_type_param_parses_with_no_return() {
|
|
99
|
-
let src = "each(cb: fn(Int)) -> Bool =\n True\n";
|
|
99
|
+
let src = "fun each(cb: fn(Int)) -> Bool =\n True\n";
|
|
100
100
|
let source = parse(src);
|
|
101
101
|
let f = only_fn(&source);
|
|
102
102
|
let ParamType::Fn(param_types, ret) = &f.params[0].ty else { panic!("expected ParamType::Fn") };
|
plum-wasm-codegen/tests/codegen_tests.rs
CHANGED
|
@@ -12,7 +12,7 @@ fn parse(src: &str) -> plum_core::ast::Source {
|
|
|
12
12
|
|
|
13
13
|
#[test]
|
|
14
14
|
fn compiles_to_valid_wasm() {
|
|
15
|
-
let src = "add(a: Int, b: Int) -> Int =\n a + b\n";
|
|
15
|
+
let src = "fun add(a: Int, b: Int) -> Int =\n a + b\n";
|
|
16
16
|
let source = parse(src);
|
|
17
17
|
let bytes = compile_source(&source).expect("compile failed");
|
|
18
18
|
// Valid WASM starts with the magic number
|
|
@@ -22,7 +22,7 @@ fn compiles_to_valid_wasm() {
|
|
|
22
22
|
|
|
23
23
|
#[test]
|
|
24
24
|
fn output_validates() {
|
|
25
|
-
let src = "add(a: Int, b: Int) -> Int =\n a + b\n";
|
|
25
|
+
let src = "fun add(a: Int, b: Int) -> Int =\n a + b\n";
|
|
26
26
|
let source = parse(src);
|
|
27
27
|
let bytes = compile_source(&source).expect("compile failed");
|
|
28
28
|
// wasmparser should accept the output
|
|
@@ -33,7 +33,7 @@ fn output_validates() {
|
|
|
33
33
|
#[test]
|
|
34
34
|
fn factorial_compiles() {
|
|
35
35
|
let src = "\
|
|
36
|
-
factorial(x: Int) -> Int =
|
|
36
|
+
fun factorial(x: Int) -> Int =
|
|
37
37
|
if x < 2
|
|
38
38
|
return 1
|
|
39
39
|
return x * factorial(x - 1)
|
|
@@ -47,7 +47,7 @@ factorial(x: Int) -> Int =
|
|
|
47
47
|
|
|
48
48
|
#[test]
|
|
49
49
|
fn give42_compiles_and_exports() {
|
|
50
|
-
let src = "give42() -> Int =\n 42\n";
|
|
50
|
+
let src = "fun give42() -> Int =\n 42\n";
|
|
51
51
|
let source = parse(src);
|
|
52
52
|
let bytes = compile_source(&source).expect("compile failed");
|
|
53
53
|
assert_eq!(&bytes[0..4], b"\0asm");
|
|
@@ -65,23 +65,23 @@ fn assert_valid(src: &str) -> Vec<u8> {
|
|
|
65
65
|
|
|
66
66
|
#[test]
|
|
67
67
|
fn bool_literals_compile() {
|
|
68
|
-
assert_valid("main() -> Bool =\n True\n");
|
|
68
|
+
assert_valid("fun main() -> Bool =\n True\n");
|
|
69
|
-
assert_valid("main() -> Bool =\n False\n");
|
|
69
|
+
assert_valid("fun main() -> Bool =\n False\n");
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
#[test]
|
|
73
73
|
fn string_literal_compiles() {
|
|
74
|
-
assert_valid("main() -> Str =\n \"hello\"\n");
|
|
74
|
+
assert_valid("fun main() -> Str =\n \"hello\"\n");
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
#[test]
|
|
78
78
|
fn empty_string_literal_compiles() {
|
|
79
|
-
assert_valid("main() -> Str =\n \"\"\n");
|
|
79
|
+
assert_valid("fun main() -> Str =\n \"\"\n");
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
#[test]
|
|
83
83
|
fn string_interpolation_of_an_int_runs_correctly() {
|
|
84
|
-
let src = "main() -> Str =\n x = 42\n \"{x}\"\n";
|
|
84
|
+
let src = "fun main() -> Str =\n x = 42\n \"{x}\"\n";
|
|
85
85
|
let source = parse(src);
|
|
86
86
|
let bytes = compile_source(&source).expect("compile failed");
|
|
87
87
|
assert_eq!(run_main_str(&bytes), "42");
|
|
@@ -89,7 +89,7 @@ fn string_interpolation_of_an_int_runs_correctly() {
|
|
|
89
89
|
|
|
90
90
|
#[test]
|
|
91
91
|
fn string_interpolation_of_a_negative_int_runs_correctly() {
|
|
92
|
-
let src = "main() -> Str =\n x = -7\n \"{x}\"\n";
|
|
92
|
+
let src = "fun main() -> Str =\n x = -7\n \"{x}\"\n";
|
|
93
93
|
let source = parse(src);
|
|
94
94
|
let bytes = compile_source(&source).expect("compile failed");
|
|
95
95
|
assert_eq!(run_main_str(&bytes), "-7");
|
|
@@ -97,7 +97,7 @@ fn string_interpolation_of_a_negative_int_runs_correctly() {
|
|
|
97
97
|
|
|
98
98
|
#[test]
|
|
99
99
|
fn string_interpolation_of_zero_runs_correctly() {
|
|
100
|
-
let src = "main() -> Str =\n x = 0\n \"{x}\"\n";
|
|
100
|
+
let src = "fun main() -> Str =\n x = 0\n \"{x}\"\n";
|
|
101
101
|
let source = parse(src);
|
|
102
102
|
let bytes = compile_source(&source).expect("compile failed");
|
|
103
103
|
assert_eq!(run_main_str(&bytes), "0");
|
|
@@ -105,7 +105,7 @@ fn string_interpolation_of_zero_runs_correctly() {
|
|
|
105
105
|
|
|
106
106
|
#[test]
|
|
107
107
|
fn string_interpolation_with_surrounding_text_and_multiple_interps_runs_correctly() {
|
|
108
|
-
let src = "main() -> Str =\n count = 3\n total = 10\n \"{count} of {total} complete\"\n";
|
|
108
|
+
let src = "fun main() -> Str =\n count = 3\n total = 10\n \"{count} of {total} complete\"\n";
|
|
109
109
|
let source = parse(src);
|
|
110
110
|
let bytes = compile_source(&source).expect("compile failed");
|
|
111
111
|
assert_eq!(run_main_str(&bytes), "3 of 10 complete");
|
|
@@ -113,7 +113,7 @@ fn string_interpolation_with_surrounding_text_and_multiple_interps_runs_correctl
|
|
|
113
113
|
|
|
114
114
|
#[test]
|
|
115
115
|
fn string_interpolation_of_a_str_runs_correctly() {
|
|
116
|
-
let src = "greet(name: Str) -> Str =\n \"Hello, {name}!\"\n\
|
|
116
|
+
let src = "fun greet(name: Str) -> Str =\n \"Hello, {name}!\"\n\nfun main() -> Str =\n greet(\"World\")\n";
|
|
117
117
|
let source = parse(src);
|
|
118
118
|
let bytes = compile_source(&source).expect("compile failed");
|
|
119
119
|
assert_eq!(run_main_str(&bytes), "Hello, World!");
|
|
@@ -121,7 +121,7 @@ fn string_interpolation_of_a_str_runs_correctly() {
|
|
|
121
121
|
|
|
122
122
|
#[test]
|
|
123
123
|
fn string_interpolation_of_a_bool_runs_correctly() {
|
|
124
|
-
let src = "main() -> Str =\n b = True\n \"is {b}\"\n";
|
|
124
|
+
let src = "fun main() -> Str =\n b = True\n \"is {b}\"\n";
|
|
125
125
|
let source = parse(src);
|
|
126
126
|
let bytes = compile_source(&source).expect("compile failed");
|
|
127
127
|
assert_eq!(run_main_str(&bytes), "is True");
|
|
@@ -132,7 +132,7 @@ fn string_interpolation_of_a_float_is_a_clear_error() {
|
|
|
132
132
|
// Float-to-decimal-string formatting is a substantial separate undertaking
|
|
133
133
|
// (correct rounding needs something like Grisu/Ryu); scoped out for now with
|
|
134
134
|
// an explicit error rather than emitting an incorrect conversion.
|
|
135
|
-
let src = "main() -> Str =\n x = 1.5\n \"{x}\"\n";
|
|
135
|
+
let src = "fun main() -> Str =\n x = 1.5\n \"{x}\"\n";
|
|
136
136
|
let source = parse(src);
|
|
137
137
|
let err = compile_source(&source).expect_err("float interpolation should not silently compile");
|
|
138
138
|
assert!(err.contains("Float"), "got: {}", err);
|
|
@@ -140,7 +140,7 @@ fn string_interpolation_of_a_float_is_a_clear_error() {
|
|
|
140
140
|
|
|
141
141
|
#[test]
|
|
142
142
|
fn float_arithmetic_and_negation_compile() {
|
|
143
|
-
assert_valid("main(x: Float) -> Float =\n y = -x\n y + 1.5\n");
|
|
143
|
+
assert_valid("fun main(x: Float) -> Float =\n y = -x\n y + 1.5\n");
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
#[test]
|
|
@@ -150,10 +150,10 @@ type Cat =
|
|
|
150
150
|
name: Str
|
|
151
151
|
age: Int
|
|
152
152
|
|
|
153
|
-
getAge<Cat>() -> Int =
|
|
153
|
+
fun getAge<Cat>() -> Int =
|
|
154
154
|
self.age
|
|
155
155
|
|
|
156
|
-
makeCat() -> Int =
|
|
156
|
+
fun makeCat() -> Int =
|
|
157
157
|
c = Cat(name: \"x\", age: 3)
|
|
158
158
|
c.getAge()
|
|
159
159
|
";
|
|
@@ -171,7 +171,7 @@ type Wrapper =
|
|
|
171
171
|
inner: Pair
|
|
172
172
|
tag: Int
|
|
173
173
|
|
|
174
|
-
make() -> Int =
|
|
174
|
+
fun make() -> Int =
|
|
175
175
|
w = Wrapper(inner: Pair(a: 1, b: 2), tag: 9)
|
|
176
176
|
w.tag
|
|
177
177
|
";
|
|
@@ -180,32 +180,32 @@ make() -> Int =
|
|
|
180
180
|
|
|
181
181
|
#[test]
|
|
182
182
|
fn match_with_int_and_wildcard_compiles() {
|
|
183
|
-
let src = "main(a: Int) -> Int =\n match a\n 1 =>\n return 10\n _ =>\n return 0\n";
|
|
183
|
+
let src = "fun main(a: Int) -> Int =\n match a\n 1 =>\n return 10\n _ =>\n return 0\n";
|
|
184
184
|
assert_valid(src);
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
#[test]
|
|
188
188
|
fn match_binding_pattern_compiles() {
|
|
189
|
-
let src = "main(a: Int) -> Int =\n match a\n x =>\n return x\n";
|
|
189
|
+
let src = "fun main(a: Int) -> Int =\n match a\n x =>\n return x\n";
|
|
190
190
|
assert_valid(src);
|
|
191
191
|
}
|
|
192
192
|
|
|
193
193
|
#[test]
|
|
194
194
|
fn match_inline_case_body_compiles() {
|
|
195
195
|
// Case bodies can be a single inline expression, not just an indented block.
|
|
196
|
-
let src = "main(a: Int) =\n match a\n 1 => 10\n _ => 0\n";
|
|
196
|
+
let src = "fun main(a: Int) =\n match a\n 1 => 10\n _ => 0\n";
|
|
197
197
|
assert_valid(src);
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
#[test]
|
|
201
201
|
fn match_bool_variant_pattern_compiles() {
|
|
202
|
-
let src = "main(a: Bool) -> Int =\n match a\n True =>\n return 1\n False =>\n return 0\n";
|
|
202
|
+
let src = "fun main(a: Bool) -> Int =\n match a\n True =>\n return 1\n False =>\n return 0\n";
|
|
203
203
|
assert_valid(src);
|
|
204
204
|
}
|
|
205
205
|
|
|
206
206
|
#[test]
|
|
207
207
|
fn match_string_pattern_is_a_clear_error() {
|
|
208
|
-
let src = "main(a: Str) -> Int =\n match a\n \"x\" =>\n 1\n _ =>\n 0\n";
|
|
208
|
+
let src = "fun main(a: Str) -> Int =\n match a\n \"x\" =>\n 1\n _ =>\n 0\n";
|
|
209
209
|
let source = parse(src);
|
|
210
210
|
let err = compile_source(&source).expect_err("string match patterns are not yet supported");
|
|
211
211
|
assert!(err.contains("string match"), "got: {}", err);
|
|
@@ -222,7 +222,7 @@ enum Nested =
|
|
|
222
222
|
| Wrap[Option]
|
|
223
223
|
| Empty
|
|
224
224
|
|
|
225
|
-
f(n: Nested) -> Int =
|
|
225
|
+
fun f(n: Nested) -> Int =
|
|
226
226
|
match n
|
|
227
227
|
Wrap(Some(v)) =>
|
|
228
228
|
return v
|
|
@@ -231,7 +231,7 @@ f(n: Nested) -> Int =
|
|
|
231
231
|
Empty =>
|
|
232
232
|
return 0
|
|
233
233
|
|
|
234
|
-
main() -> Int =
|
|
234
|
+
fun main() -> Int =
|
|
235
235
|
f(Wrap(Some(5)))
|
|
236
236
|
";
|
|
237
237
|
let source = parse(src);
|
|
@@ -252,7 +252,7 @@ enum Nested =
|
|
|
252
252
|
| Wrap[Option]
|
|
253
253
|
| Empty
|
|
254
254
|
|
|
255
|
-
f(n: Nested) -> Int =
|
|
255
|
+
fun f(n: Nested) -> Int =
|
|
256
256
|
match n
|
|
257
257
|
Wrap(Some(v)) =>
|
|
258
258
|
return v
|
|
@@ -261,7 +261,7 @@ f(n: Nested) -> Int =
|
|
|
261
261
|
Empty =>
|
|
262
262
|
return 0
|
|
263
263
|
|
|
264
|
-
main() -> Int =
|
|
264
|
+
fun main() -> Int =
|
|
265
265
|
f(Wrap(None))
|
|
266
266
|
";
|
|
267
267
|
let source = parse(src);
|
|
@@ -285,13 +285,13 @@ enum Box =
|
|
|
285
285
|
| Full[T]
|
|
286
286
|
| Empty
|
|
287
287
|
|
|
288
|
-
unwrap(b: Box) -> Int =
|
|
288
|
+
fun unwrap(b: Box) -> Int =
|
|
289
289
|
match b
|
|
290
290
|
Full(Some(v)) => v
|
|
291
291
|
Full(None) => -1
|
|
292
292
|
Empty => 0
|
|
293
293
|
|
|
294
|
-
main() -> Int =
|
|
294
|
+
fun main() -> Int =
|
|
295
295
|
unwrap(Full(Some(7)))
|
|
296
296
|
";
|
|
297
297
|
let source = parse(src);
|
|
@@ -308,14 +308,14 @@ enum Option =
|
|
|
308
308
|
| Some[Option]
|
|
309
309
|
| None
|
|
310
310
|
|
|
311
|
-
unwrapTwice(o: Option) -> Int =
|
|
311
|
+
fun unwrapTwice(o: Option) -> Int =
|
|
312
312
|
match o
|
|
313
313
|
Some(Some(None)) => 1
|
|
314
314
|
Some(None) => 2
|
|
315
315
|
None => 3
|
|
316
316
|
_ => 0
|
|
317
317
|
|
|
318
|
-
main() -> Int =
|
|
318
|
+
fun main() -> Int =
|
|
319
319
|
unwrapTwice(Some(Some(None)))
|
|
320
320
|
";
|
|
321
321
|
let source = parse(src);
|
|
@@ -371,12 +371,12 @@ fn run_main_str(bytes: &[u8]) -> String {
|
|
|
371
371
|
#[test]
|
|
372
372
|
fn factorial_runs_correctly() {
|
|
373
373
|
let src = "\
|
|
374
|
-
factorial(x: Int) -> Int =
|
|
374
|
+
fun factorial(x: Int) -> Int =
|
|
375
375
|
if x < 2
|
|
376
376
|
return 1
|
|
377
377
|
return x * factorial(x - 1)
|
|
378
378
|
|
|
379
|
-
main() -> Int =
|
|
379
|
+
fun main() -> Int =
|
|
380
380
|
factorial(5)
|
|
381
381
|
";
|
|
382
382
|
let source = parse(src);
|
|
@@ -391,10 +391,10 @@ type Cat =
|
|
|
391
391
|
name: Str
|
|
392
392
|
age: Int
|
|
393
393
|
|
|
394
|
-
getAge<Cat>() -> Int =
|
|
394
|
+
fun getAge<Cat>() -> Int =
|
|
395
395
|
self.age
|
|
396
396
|
|
|
397
|
-
main() -> Int =
|
|
397
|
+
fun main() -> Int =
|
|
398
398
|
c = Cat(name: \"x\", age: 7)
|
|
399
399
|
c.getAge()
|
|
400
400
|
";
|
|
@@ -414,7 +414,7 @@ type Wrapper =
|
|
|
414
414
|
inner: Pair
|
|
415
415
|
tag: Int
|
|
416
416
|
|
|
417
|
-
main() -> Int =
|
|
417
|
+
fun main() -> Int =
|
|
418
418
|
w = Wrapper(inner: Pair(a: 11, b: 22), tag: 99)
|
|
419
419
|
w.inner.b
|
|
420
420
|
";
|
|
@@ -433,14 +433,14 @@ fn repeated_class_call_in_a_loop_does_not_alias() {
|
|
|
433
433
|
type Box =
|
|
434
434
|
v: Int
|
|
435
435
|
|
|
436
|
-
sumBoxes() -> Int =
|
|
436
|
+
fun sumBoxes() -> Int =
|
|
437
437
|
total = 0
|
|
438
438
|
for i in 0..5
|
|
439
439
|
b = Box(v: i)
|
|
440
440
|
total = total + b.v
|
|
441
441
|
return total
|
|
442
442
|
|
|
443
|
-
main() -> Int =
|
|
443
|
+
fun main() -> Int =
|
|
444
444
|
sumBoxes()
|
|
445
445
|
";
|
|
446
446
|
let source = parse(src);
|
|
@@ -451,7 +451,7 @@ main() -> Int =
|
|
|
451
451
|
#[test]
|
|
452
452
|
fn match_int_and_wildcard_run_correctly() {
|
|
453
453
|
let src = "\
|
|
454
|
-
classify(a: Int) -> Int =
|
|
454
|
+
fun classify(a: Int) -> Int =
|
|
455
455
|
match a
|
|
456
456
|
1 =>
|
|
457
457
|
return 100
|
|
@@ -460,7 +460,7 @@ classify(a: Int) -> Int =
|
|
|
460
460
|
_ =>
|
|
461
461
|
return 0
|
|
462
462
|
|
|
463
|
-
main() -> Int =
|
|
463
|
+
fun main() -> Int =
|
|
464
464
|
classify(2)
|
|
465
465
|
";
|
|
466
466
|
let source = parse(src);
|
|
@@ -475,14 +475,14 @@ fn match_bool_variant_pattern_runs_correctly() {
|
|
|
475
475
|
// source file — otherwise the first arm always "matches" (as a rebinding) and
|
|
476
476
|
// `pick(False)` would wrongly return 1.
|
|
477
477
|
let src = "\
|
|
478
|
-
pick(a: Bool) -> Int =
|
|
478
|
+
fun pick(a: Bool) -> Int =
|
|
479
479
|
match a
|
|
480
480
|
True =>
|
|
481
481
|
return 1
|
|
482
482
|
False =>
|
|
483
483
|
return 0
|
|
484
484
|
|
|
485
|
-
main() -> Int =
|
|
485
|
+
fun main() -> Int =
|
|
486
486
|
pick(False)
|
|
487
487
|
";
|
|
488
488
|
let source = parse(src);
|
|
@@ -497,10 +497,10 @@ fn lowercase_single_word_function_call_runs_correctly() {
|
|
|
497
497
|
// matched its text and the grammar's lexer would nondeterministically commit to
|
|
498
498
|
// `var_identifier`, breaking every such call site.
|
|
499
499
|
let src = "\
|
|
500
|
-
double(n: Int) -> Int =
|
|
500
|
+
fun double(n: Int) -> Int =
|
|
501
501
|
n * 2
|
|
502
502
|
|
|
503
|
-
main() -> Int =
|
|
503
|
+
fun main() -> Int =
|
|
504
504
|
double(21)
|
|
505
505
|
";
|
|
506
506
|
let source = parse(src);
|
|
@@ -511,11 +511,11 @@ main() -> Int =
|
|
|
511
511
|
#[test]
|
|
512
512
|
fn assert_traps_on_false_and_passes_through_on_true() {
|
|
513
513
|
let src_ok = "\
|
|
514
|
-
check(n: Int) -> Int =
|
|
514
|
+
fun check(n: Int) -> Int =
|
|
515
515
|
assert n > 0
|
|
516
516
|
n
|
|
517
517
|
|
|
518
|
-
main() -> Int =
|
|
518
|
+
fun main() -> Int =
|
|
519
519
|
check(5)
|
|
520
520
|
";
|
|
521
521
|
let source = parse(src_ok);
|
|
@@ -523,11 +523,11 @@ main() -> Int =
|
|
|
523
523
|
assert_eq!(run_main(&bytes), 5);
|
|
524
524
|
|
|
525
525
|
let src_trap = "\
|
|
526
|
-
check(n: Int) -> Int =
|
|
526
|
+
fun check(n: Int) -> Int =
|
|
527
527
|
assert n > 0
|
|
528
528
|
n
|
|
529
529
|
|
|
530
|
-
main() -> Int =
|
|
530
|
+
fun main() -> Int =
|
|
531
531
|
check(-1)
|
|
532
532
|
";
|
|
533
533
|
let source = parse(src_trap);
|
|
@@ -545,10 +545,10 @@ main() -> Int =
|
|
|
545
545
|
fn todo_traps_at_runtime() {
|
|
546
546
|
// `todo` marks an unimplemented body — it must trap, not silently do nothing.
|
|
547
547
|
let src = "\
|
|
548
|
-
notDoneYet() -> Int =
|
|
548
|
+
fun notDoneYet() -> Int =
|
|
549
549
|
todo
|
|
550
550
|
|
|
551
|
-
main() -> Int =
|
|
551
|
+
fun main() -> Int =
|
|
552
552
|
notDoneYet()
|
|
553
553
|
";
|
|
554
554
|
let source = parse(src);
|
|
@@ -570,7 +570,7 @@ enum Color =
|
|
|
570
570
|
| Green
|
|
571
571
|
| Blue
|
|
572
572
|
|
|
573
|
-
main() -> Int =\n x = Green\n 0\n";
|
|
573
|
+
fun main() -> Int =\n x = Green\n 0\n";
|
|
574
574
|
assert_valid(src);
|
|
575
575
|
}
|
|
576
576
|
|
|
@@ -581,14 +581,14 @@ enum Option =
|
|
|
581
581
|
| Some[Int]
|
|
582
582
|
| None
|
|
583
583
|
|
|
584
|
-
unwrapOr(o: Option, default: Int) -> Int =
|
|
584
|
+
fun unwrapOr(o: Option, default: Int) -> Int =
|
|
585
585
|
match o
|
|
586
586
|
Some(v) =>
|
|
587
587
|
return v
|
|
588
588
|
None =>
|
|
589
589
|
return default
|
|
590
590
|
|
|
591
|
-
main() -> Int =
|
|
591
|
+
fun main() -> Int =
|
|
592
592
|
unwrapOr(Some(7), 0)
|
|
593
593
|
";
|
|
594
594
|
let source = parse(src);
|
|
@@ -603,14 +603,14 @@ enum Shape =
|
|
|
603
603
|
| Rect[Int, Int]
|
|
604
604
|
| Circle[Int]
|
|
605
605
|
|
|
606
|
-
area(s: Shape) -> Int =
|
|
606
|
+
fun area(s: Shape) -> Int =
|
|
607
607
|
match s
|
|
608
608
|
Rect(w, h) =>
|
|
609
609
|
return w * h
|
|
610
610
|
Circle(r) =>
|
|
611
611
|
return r * r
|
|
612
612
|
|
|
613
|
-
main() -> Int =
|
|
613
|
+
fun main() -> Int =
|
|
614
614
|
area(Rect(3, 4))
|
|
615
615
|
";
|
|
616
616
|
let source = parse(src);
|
|
@@ -626,7 +626,7 @@ enum Color =
|
|
|
626
626
|
| Green
|
|
627
627
|
| Blue
|
|
628
628
|
|
|
629
|
-
code(c: Color) -> Int =
|
|
629
|
+
fun code(c: Color) -> Int =
|
|
630
630
|
match c
|
|
631
631
|
Red =>
|
|
632
632
|
return 1
|
|
@@ -635,7 +635,7 @@ code(c: Color) -> Int =
|
|
|
635
635
|
Blue =>
|
|
636
636
|
return 3
|
|
637
637
|
|
|
638
|
-
main() -> Int =
|
|
638
|
+
fun main() -> Int =
|
|
639
639
|
code(Green)
|
|
640
640
|
";
|
|
641
641
|
let source = parse(src);
|
|
@@ -650,14 +650,14 @@ enum Option =
|
|
|
650
650
|
| Some[Int]
|
|
651
651
|
| None
|
|
652
652
|
|
|
653
|
-
isSome(o: Option) -> Int =
|
|
653
|
+
fun isSome(o: Option) -> Int =
|
|
654
654
|
match o
|
|
655
655
|
Some(_) =>
|
|
656
656
|
return 1
|
|
657
657
|
None =>
|
|
658
658
|
return 0
|
|
659
659
|
|
|
660
|
-
main() -> Int =
|
|
660
|
+
fun main() -> Int =
|
|
661
661
|
isSome(Some(99))
|
|
662
662
|
";
|
|
663
663
|
let source = parse(src);
|
|
@@ -675,14 +675,14 @@ enum Option =
|
|
|
675
675
|
| Some[Int]
|
|
676
676
|
| None
|
|
677
677
|
|
|
678
|
-
unwrapOr(o: Option, default: Int) -> Int =
|
|
678
|
+
fun unwrapOr(o: Option, default: Int) -> Int =
|
|
679
679
|
match o
|
|
680
680
|
Some(v) =>
|
|
681
681
|
return v
|
|
682
682
|
None =>
|
|
683
683
|
return default
|
|
684
684
|
|
|
685
|
-
main() -> Int =
|
|
685
|
+
fun main() -> Int =
|
|
686
686
|
unwrapOr(None, 5)
|
|
687
687
|
";
|
|
688
688
|
let source = parse(src);
|
|
@@ -702,14 +702,14 @@ enum Option =
|
|
|
702
702
|
type Box =
|
|
703
703
|
value: Option
|
|
704
704
|
|
|
705
|
-
unwrap<Box>(default: Int) -> Int =
|
|
705
|
+
fun unwrap<Box>(default: Int) -> Int =
|
|
706
706
|
match self.value
|
|
707
707
|
Some(v) =>
|
|
708
708
|
return v
|
|
709
709
|
None =>
|
|
710
710
|
return default
|
|
711
711
|
|
|
712
|
-
main() -> Int =
|
|
712
|
+
fun main() -> Int =
|
|
713
713
|
b = Box(value: Some(42))
|
|
714
714
|
b.unwrap(0)
|
|
715
715
|
";
|
|
@@ -721,12 +721,12 @@ main() -> Int =
|
|
|
721
721
|
#[test]
|
|
722
722
|
fn tail_match_without_return_runs_correctly() {
|
|
723
723
|
let src = "\
|
|
724
|
-
bindExample(n: Int) -> Int =
|
|
724
|
+
fun bindExample(n: Int) -> Int =
|
|
725
725
|
match n
|
|
726
726
|
x =>
|
|
727
727
|
x
|
|
728
728
|
|
|
729
|
-
main() -> Int =
|
|
729
|
+
fun main() -> Int =
|
|
730
730
|
bindExample(5)
|
|
731
731
|
";
|
|
732
732
|
let source = parse(src);
|
|
@@ -737,13 +737,13 @@ main() -> Int =
|
|
|
737
737
|
#[test]
|
|
738
738
|
fn tail_if_without_return_runs_correctly() {
|
|
739
739
|
let src = "\
|
|
740
|
-
abs(n: Int) -> Int =
|
|
740
|
+
fun abs(n: Int) -> Int =
|
|
741
741
|
if n < 0
|
|
742
742
|
-n
|
|
743
743
|
else
|
|
744
744
|
n
|
|
745
745
|
|
|
746
|
-
main() -> Int =
|
|
746
|
+
fun main() -> Int =
|
|
747
747
|
abs(-7)
|
|
748
748
|
";
|
|
749
749
|
let source = parse(src);
|
|
@@ -754,7 +754,7 @@ main() -> Int =
|
|
|
754
754
|
#[test]
|
|
755
755
|
fn tail_if_nested_inside_match_arm_without_return_runs_correctly() {
|
|
756
756
|
let src = "\
|
|
757
|
-
classify(n: Int) -> Int =
|
|
757
|
+
fun classify(n: Int) -> Int =
|
|
758
758
|
match n
|
|
759
759
|
0 =>
|
|
760
760
|
1
|
|
@@ -764,7 +764,7 @@ classify(n: Int) -> Int =
|
|
|
764
764
|
else
|
|
765
765
|
2
|
|
766
766
|
|
|
767
|
-
main() -> Int =
|
|
767
|
+
fun main() -> Int =
|
|
768
768
|
classify(-5)
|
|
769
769
|
";
|
|
770
770
|
let source = parse(src);
|
|
@@ -775,14 +775,14 @@ main() -> Int =
|
|
|
775
775
|
#[test]
|
|
776
776
|
fn tail_match_mixing_return_and_bare_expr_arms_runs_correctly() {
|
|
777
777
|
let src = "\
|
|
778
|
-
describe(n: Int) -> Int =
|
|
778
|
+
fun describe(n: Int) -> Int =
|
|
779
779
|
match n
|
|
780
780
|
0 =>
|
|
781
781
|
return 100
|
|
782
782
|
x =>
|
|
783
783
|
x * 2
|
|
784
784
|
|
|
785
|
-
main() -> Int =
|
|
785
|
+
fun main() -> Int =
|
|
786
786
|
describe(21)
|
|
787
787
|
";
|
|
788
788
|
let source = parse(src);
|
|
@@ -797,14 +797,14 @@ enum Option =
|
|
|
797
797
|
| Some[Int]
|
|
798
798
|
| None
|
|
799
799
|
|
|
800
|
-
unwrapOr(o: Option, default: Int) -> Int =
|
|
800
|
+
fun unwrapOr(o: Option, default: Int) -> Int =
|
|
801
801
|
match o
|
|
802
802
|
Some(v) =>
|
|
803
803
|
v
|
|
804
804
|
None =>
|
|
805
805
|
default
|
|
806
806
|
|
|
807
|
-
main() -> Int =
|
|
807
|
+
fun main() -> Int =
|
|
808
808
|
unwrapOr(Some(9), 0)
|
|
809
809
|
";
|
|
810
810
|
let source = parse(src);
|
|
@@ -815,7 +815,7 @@ main() -> Int =
|
|
|
815
815
|
#[test]
|
|
816
816
|
fn tail_if_without_else_is_a_clear_error() {
|
|
817
817
|
let src = "\
|
|
818
|
-
bad(n: Int) -> Int =
|
|
818
|
+
fun bad(n: Int) -> Int =
|
|
819
819
|
if n < 0
|
|
820
820
|
return 1
|
|
821
821
|
";
|
|
@@ -827,7 +827,7 @@ bad(n: Int) -> Int =
|
|
|
827
827
|
#[test]
|
|
828
828
|
fn tail_match_non_exhaustive_is_a_clear_error() {
|
|
829
829
|
let src = "\
|
|
830
|
-
bad(n: Int) -> Int =
|
|
830
|
+
fun bad(n: Int) -> Int =
|
|
831
831
|
match n
|
|
832
832
|
0 =>
|
|
833
833
|
1
|
|
@@ -840,7 +840,7 @@ bad(n: Int) -> Int =
|
|
|
840
840
|
#[test]
|
|
841
841
|
fn tail_match_arm_ending_in_non_value_statement_is_a_clear_error() {
|
|
842
842
|
let src = "\
|
|
843
|
-
bad(n: Int) -> Int =
|
|
843
|
+
fun bad(n: Int) -> Int =
|
|
844
844
|
match n
|
|
845
845
|
x =>
|
|
846
846
|
y = x
|
|
@@ -856,14 +856,14 @@ fn generic_class_specialized_at_two_types_does_not_alias() {
|
|
|
856
856
|
type Box[T] =
|
|
857
857
|
value: T
|
|
858
858
|
|
|
859
|
-
getIntValue<Box>() -> Int =
|
|
859
|
+
fun getIntValue<Box>() -> Int =
|
|
860
860
|
self.value
|
|
861
861
|
|
|
862
|
-
useInt() -> Int =
|
|
862
|
+
fun useInt() -> Int =
|
|
863
863
|
b = Box(value: 7)
|
|
864
864
|
b.getIntValue()
|
|
865
865
|
|
|
866
|
-
main() -> Int =
|
|
866
|
+
fun main() -> Int =
|
|
867
867
|
useInt()
|
|
868
868
|
";
|
|
869
869
|
let source = parse(src);
|
|
@@ -874,10 +874,10 @@ main() -> Int =
|
|
|
874
874
|
#[test]
|
|
875
875
|
fn generic_function_called_at_multiple_concrete_types_runs_correctly() {
|
|
876
876
|
let src = "\
|
|
877
|
-
identity(value: T) -> T =
|
|
877
|
+
fun identity(value: T) -> T =
|
|
878
878
|
value
|
|
879
879
|
|
|
880
|
-
main() -> Int =
|
|
880
|
+
fun main() -> Int =
|
|
881
881
|
identity(5) + identity(37)
|
|
882
882
|
";
|
|
883
883
|
let source = parse(src);
|
|
@@ -891,10 +891,10 @@ fn generic_method_on_generic_class_runs_correctly() {
|
|
|
891
891
|
type Box[T] =
|
|
892
892
|
value: T
|
|
893
893
|
|
|
894
|
-
getValue<Box>() -> Int =
|
|
894
|
+
fun getValue<Box>() -> Int =
|
|
895
895
|
self.value
|
|
896
896
|
|
|
897
|
-
main() -> Int =
|
|
897
|
+
fun main() -> Int =
|
|
898
898
|
b = Box(value: 9)
|
|
899
899
|
b.getValue()
|
|
900
900
|
";
|
|
@@ -906,13 +906,13 @@ main() -> Int =
|
|
|
906
906
|
#[test]
|
|
907
907
|
fn transitively_generic_call_chain_runs_correctly() {
|
|
908
908
|
let src = "\
|
|
909
|
-
identity(value: T) -> T =
|
|
909
|
+
fun identity(value: T) -> T =
|
|
910
910
|
value
|
|
911
911
|
|
|
912
|
-
doubled(value: T) -> Int =
|
|
912
|
+
fun doubled(value: T) -> Int =
|
|
913
913
|
identity(value) + identity(value)
|
|
914
914
|
|
|
915
|
-
main() -> Int =
|
|
915
|
+
fun main() -> Int =
|
|
916
916
|
doubled(21)
|
|
917
917
|
";
|
|
918
918
|
let source = parse(src);
|
|
@@ -927,14 +927,14 @@ enum Option =
|
|
|
927
927
|
| Some[T]
|
|
928
928
|
| None
|
|
929
929
|
|
|
930
|
-
unwrapOr(o: Option, default: Int) -> Int =
|
|
930
|
+
fun unwrapOr(o: Option, default: Int) -> Int =
|
|
931
931
|
match o
|
|
932
932
|
Some(v) =>
|
|
933
933
|
v
|
|
934
934
|
None =>
|
|
935
935
|
default
|
|
936
936
|
|
|
937
|
-
main() -> Int =
|
|
937
|
+
fun main() -> Int =
|
|
938
938
|
unwrapOr(Some(13), 0)
|
|
939
939
|
";
|
|
940
940
|
let source = parse(src);
|
|
@@ -956,21 +956,21 @@ enum Option =
|
|
|
956
956
|
| Some[T]
|
|
957
957
|
| None
|
|
958
958
|
|
|
959
|
-
unwrapIntOr(o: Option, default: Int) -> Int =
|
|
959
|
+
fun unwrapIntOr(o: Option, default: Int) -> Int =
|
|
960
960
|
match o
|
|
961
961
|
Some(v) =>
|
|
962
962
|
v
|
|
963
963
|
None =>
|
|
964
964
|
default
|
|
965
965
|
|
|
966
|
-
unwrapStrOr(o: Option, default: Int) -> Int =
|
|
966
|
+
fun unwrapStrOr(o: Option, default: Int) -> Int =
|
|
967
967
|
match o
|
|
968
968
|
Some(v) =>
|
|
969
969
|
4
|
|
970
970
|
None =>
|
|
971
971
|
default
|
|
972
972
|
|
|
973
|
-
main() -> Int =
|
|
973
|
+
fun main() -> Int =
|
|
974
974
|
unwrapIntOr(Some(13), 0) + unwrapStrOr(Some(\"abcd\"), 0)
|
|
975
975
|
";
|
|
976
976
|
let source = parse(src);
|
|
@@ -989,14 +989,14 @@ enum Option =
|
|
|
989
989
|
| Some[T]
|
|
990
990
|
| None
|
|
991
991
|
|
|
992
|
-
unwrapOr(o: Option, default: Int) -> Int =
|
|
992
|
+
fun unwrapOr(o: Option, default: Int) -> Int =
|
|
993
993
|
match o
|
|
994
994
|
Some(v) =>
|
|
995
995
|
v
|
|
996
996
|
None =>
|
|
997
997
|
default
|
|
998
998
|
|
|
999
|
-
main() -> Int =
|
|
999
|
+
fun main() -> Int =
|
|
1000
1000
|
unwrapOr(Some(5), 0) + unwrapOr(Some(37), 0)
|
|
1001
1001
|
";
|
|
1002
1002
|
let source = parse(src);
|
|
@@ -1010,13 +1010,13 @@ fn ordinary_function_with_bare_generic_class_param_runs_correctly() {
|
|
|
1010
1010
|
type Box[T] =
|
|
1011
1011
|
value: T
|
|
1012
1012
|
|
|
1013
|
-
getBoxValue<Box>() -> Int =
|
|
1013
|
+
fun getBoxValue<Box>() -> Int =
|
|
1014
1014
|
self.value
|
|
1015
1015
|
|
|
1016
|
-
sumBox(b: Box) -> Int =
|
|
1016
|
+
fun sumBox(b: Box) -> Int =
|
|
1017
1017
|
b.getBoxValue()
|
|
1018
1018
|
|
|
1019
|
-
main() -> Int =
|
|
1019
|
+
fun main() -> Int =
|
|
1020
1020
|
sumBox(Box(value: 11))
|
|
1021
1021
|
";
|
|
1022
1022
|
let source = parse(src);
|
|
@@ -1069,10 +1069,10 @@ fn wasm_module_with_a_table_element_validates_and_call_indirect_works() {
|
|
|
1069
1069
|
#[test]
|
|
1070
1070
|
fn non_capturing_closure_passed_and_called_runs_correctly() {
|
|
1071
1071
|
let src = "\
|
|
1072
|
-
each(cb: fn(Int) -> Int) -> Int =
|
|
1072
|
+
fun each(cb: fn(Int) -> Int) -> Int =
|
|
1073
1073
|
cb(5)
|
|
1074
1074
|
|
|
1075
|
-
main() -> Int =
|
|
1075
|
+
fun main() -> Int =
|
|
1076
1076
|
each(|v| v)
|
|
1077
1077
|
";
|
|
1078
1078
|
let source = parse(src);
|
|
@@ -1086,10 +1086,10 @@ fn multi_line_closure_call_argument_with_closing_paren_on_last_statement_line_ru
|
|
|
1086
1086
|
// multi-line closure body immediately followed by `)` on the same line as the
|
|
1087
1087
|
// body's last statement, so this shape didn't parse at all before.
|
|
1088
1088
|
let src = "\
|
|
1089
|
-
each(cb: fn(Int) -> Int) -> Int =
|
|
1089
|
+
fun each(cb: fn(Int) -> Int) -> Int =
|
|
1090
1090
|
cb(5)
|
|
1091
1091
|
|
|
1092
|
-
main() -> Int =
|
|
1092
|
+
fun main() -> Int =
|
|
1093
1093
|
each(|v|
|
|
1094
1094
|
x = v + 1
|
|
1095
1095
|
x * 2)
|
|
@@ -1102,17 +1102,17 @@ main() -> Int =
|
|
|
1102
1102
|
#[test]
|
|
1103
1103
|
fn capturing_closure_snapshots_value_at_creation_time_runs_correctly() {
|
|
1104
1104
|
let src = "\
|
|
1105
|
-
each(cb: fn(Int) -> Int) -> Int =
|
|
1105
|
+
fun each(cb: fn(Int) -> Int) -> Int =
|
|
1106
1106
|
cb(0)
|
|
1107
1107
|
|
|
1108
|
-
useClosure() -> Int =
|
|
1108
|
+
fun useClosure() -> Int =
|
|
1109
1109
|
x = 10
|
|
1110
1110
|
cb = |v|
|
|
1111
1111
|
x + v
|
|
1112
1112
|
x = 999
|
|
1113
1113
|
each(cb)
|
|
1114
1114
|
|
|
1115
|
-
main() -> Int =
|
|
1115
|
+
fun main() -> Int =
|
|
1116
1116
|
useClosure()
|
|
1117
1117
|
";
|
|
1118
1118
|
let source = parse(src);
|
|
@@ -1132,16 +1132,16 @@ fn closure_assigned_then_called_at_float_type_runs_correctly() {
|
|
|
1132
1132
|
// Float param silently defaulted to Int, producing a `call_indirect` signature
|
|
1133
1133
|
// mismatch between the compiled closure body and its call site.
|
|
1134
1134
|
let src = "\
|
|
1135
|
-
eachF(cb: fn(Float) -> Float) -> Float =
|
|
1135
|
+
fun eachF(cb: fn(Float) -> Float) -> Float =
|
|
1136
1136
|
cb(0.0)
|
|
1137
1137
|
|
|
1138
|
-
useClosure() -> Float =
|
|
1138
|
+
fun useClosure() -> Float =
|
|
1139
1139
|
offset = 2.5
|
|
1140
1140
|
cb = |v|
|
|
1141
1141
|
offset + v
|
|
1142
1142
|
eachF(cb)
|
|
1143
1143
|
|
|
1144
|
-
main() -> Float =
|
|
1144
|
+
fun main() -> Float =
|
|
1145
1145
|
useClosure()
|
|
1146
1146
|
";
|
|
1147
1147
|
let source = parse(src);
|
|
@@ -1155,15 +1155,15 @@ fn closure_assigned_then_called_at_class_type_runs_correctly() {
|
|
|
1155
1155
|
type Cat =
|
|
1156
1156
|
age: Int
|
|
1157
1157
|
|
|
1158
|
-
eachCat(cb: fn(Cat) -> Int) -> Int =
|
|
1158
|
+
fun eachCat(cb: fn(Cat) -> Int) -> Int =
|
|
1159
1159
|
cb(Cat(age: 7))
|
|
1160
1160
|
|
|
1161
|
-
useClosure() -> Int =
|
|
1161
|
+
fun useClosure() -> Int =
|
|
1162
1162
|
cb = |c|
|
|
1163
1163
|
c.age
|
|
1164
1164
|
eachCat(cb)
|
|
1165
1165
|
|
|
1166
|
-
main() -> Int =
|
|
1166
|
+
fun main() -> Int =
|
|
1167
1167
|
useClosure()
|
|
1168
1168
|
";
|
|
1169
1169
|
let source = parse(src);
|
|
@@ -1174,13 +1174,13 @@ main() -> Int =
|
|
|
1174
1174
|
#[test]
|
|
1175
1175
|
fn closure_passed_through_already_generic_higher_order_function_runs_correctly() {
|
|
1176
1176
|
let src = "\
|
|
1177
|
-
identity(value: T) -> T =
|
|
1177
|
+
fun identity(value: T) -> T =
|
|
1178
1178
|
value
|
|
1179
1179
|
|
|
1180
|
-
each(cb: fn(Int) -> Int) -> Int =
|
|
1180
|
+
fun each(cb: fn(Int) -> Int) -> Int =
|
|
1181
1181
|
cb(identity(7))
|
|
1182
1182
|
|
|
1183
|
-
main() -> Int =
|
|
1183
|
+
fun main() -> Int =
|
|
1184
1184
|
each(|v| v * 2)
|
|
1185
1185
|
";
|
|
1186
1186
|
let source = parse(src);
|
|
@@ -1198,10 +1198,10 @@ fn nested_closure_literal_runs_correctly() {
|
|
|
1198
1198
|
// exercises the multi-level capture chain: `outer` must itself capture `offset`
|
|
1199
1199
|
// purely because `inner` needs it, not because `outer` uses it.
|
|
1200
1200
|
let src = "\
|
|
1201
|
-
each(cb: fn(Int) -> Int) -> Int =
|
|
1201
|
+
fun each(cb: fn(Int) -> Int) -> Int =
|
|
1202
1202
|
cb(5)
|
|
1203
1203
|
|
|
1204
|
-
useNested() -> Int =
|
|
1204
|
+
fun useNested() -> Int =
|
|
1205
1205
|
offset = 100
|
|
1206
1206
|
outer = |v|
|
|
1207
1207
|
inner = |w|
|
|
@@ -1209,7 +1209,7 @@ useNested() -> Int =
|
|
|
1209
1209
|
inner(v)
|
|
1210
1210
|
each(outer)
|
|
1211
1211
|
|
|
1212
|
-
main() -> Int =
|
|
1212
|
+
fun main() -> Int =
|
|
1213
1213
|
useNested()
|
|
1214
1214
|
";
|
|
1215
1215
|
let source = parse(src);
|
|
@@ -1220,10 +1220,10 @@ main() -> Int =
|
|
|
1220
1220
|
#[test]
|
|
1221
1221
|
fn nested_closure_literal_passed_directly_as_call_argument_runs_correctly() {
|
|
1222
1222
|
let src = "\
|
|
1223
|
-
each(cb: fn(Int) -> Int) -> Int =
|
|
1223
|
+
fun each(cb: fn(Int) -> Int) -> Int =
|
|
1224
1224
|
cb(5)
|
|
1225
1225
|
|
|
1226
|
-
main() -> Int =
|
|
1226
|
+
fun main() -> Int =
|
|
1227
1227
|
each(|v|
|
|
1228
1228
|
each(|w| w + v))
|
|
1229
1229
|
";
|
|
@@ -1238,13 +1238,13 @@ fn named_function_used_as_a_closure_typed_value_runs_correctly() {
|
|
|
1238
1238
|
// wherever a `fn(...)`-typed value is expected — no closure literal involved at
|
|
1239
1239
|
// the call site at all.
|
|
1240
1240
|
let src = "\
|
|
1241
|
-
double(x: Int) -> Int =
|
|
1241
|
+
fun double(x: Int) -> Int =
|
|
1242
1242
|
x * 2
|
|
1243
1243
|
|
|
1244
|
-
each(cb: fn(Int) -> Int) -> Int =
|
|
1244
|
+
fun each(cb: fn(Int) -> Int) -> Int =
|
|
1245
1245
|
cb(21)
|
|
1246
1246
|
|
|
1247
|
-
main() -> Int =
|
|
1247
|
+
fun main() -> Int =
|
|
1248
1248
|
each(double)
|
|
1249
1249
|
";
|
|
1250
1250
|
let source = parse(src);
|
|
@@ -1255,10 +1255,10 @@ main() -> Int =
|
|
|
1255
1255
|
#[test]
|
|
1256
1256
|
fn named_function_used_as_a_value_assigned_then_called_runs_correctly() {
|
|
1257
1257
|
let src = "\
|
|
1258
|
-
double(x: Int) -> Int =
|
|
1258
|
+
fun double(x: Int) -> Int =
|
|
1259
1259
|
x * 2
|
|
1260
1260
|
|
|
1261
|
-
main() -> Int =
|
|
1261
|
+
fun main() -> Int =
|
|
1262
1262
|
f = double
|
|
1263
1263
|
f(21)
|
|
1264
1264
|
";
|
|
@@ -1273,13 +1273,13 @@ fn named_function_used_as_a_value_alongside_a_closure_at_the_same_call_type_runs
|
|
|
1273
1273
|
// closure of the same signature (both must resolve to the same wasm function
|
|
1274
1274
|
// type, since both flow through the exact same `cb(...)` call site).
|
|
1275
1275
|
let src = "\
|
|
1276
|
-
double(x: Int) -> Int =
|
|
1276
|
+
fun double(x: Int) -> Int =
|
|
1277
1277
|
x * 2
|
|
1278
1278
|
|
|
1279
|
-
each(cb: fn(Int) -> Int) -> Int =
|
|
1279
|
+
fun each(cb: fn(Int) -> Int) -> Int =
|
|
1280
1280
|
cb(10)
|
|
1281
1281
|
|
|
1282
|
-
main() -> Int =
|
|
1282
|
+
fun main() -> Int =
|
|
1283
1283
|
each(double) + each(|v| v + 1)
|
|
1284
1284
|
";
|
|
1285
1285
|
let source = parse(src);
|
|
@@ -1292,14 +1292,14 @@ fn multi_subject_match_with_enum_tags_runs_correctly() {
|
|
|
1292
1292
|
// Mirrors libs/std/bool.plum's `and`/`or`: `match self, o` against two Bool
|
|
1293
1293
|
// subjects, each case naming a tag pattern per position.
|
|
1294
1294
|
let src = "\
|
|
1295
|
-
and(a: Bool, b: Bool) -> Bool =
|
|
1295
|
+
fun and(a: Bool, b: Bool) -> Bool =
|
|
1296
1296
|
match a, b
|
|
1297
1297
|
True, True => True
|
|
1298
1298
|
True, False => False
|
|
1299
1299
|
False, True => False
|
|
1300
1300
|
False, False => False
|
|
1301
1301
|
|
|
1302
|
-
main() -> Int =
|
|
1302
|
+
fun main() -> Int =
|
|
1303
1303
|
x = and(True, True)
|
|
1304
1304
|
y = and(True, False)
|
|
1305
1305
|
match x, y
|
|
@@ -1317,13 +1317,13 @@ fn multi_subject_match_falls_through_to_next_case_when_only_first_position_match
|
|
|
1317
1317
|
// doesn't (b is 2) — codegen must fall through to the *next case* (trying its
|
|
1318
1318
|
// own position 0 again), not just "move on" within the first case.
|
|
1319
1319
|
let src = "\
|
|
1320
|
-
classify(a: Int, b: Int) -> Int =
|
|
1320
|
+
fun classify(a: Int, b: Int) -> Int =
|
|
1321
1321
|
match a, b
|
|
1322
1322
|
1, 1 => 100
|
|
1323
1323
|
1, 2 => 200
|
|
1324
1324
|
_, _ => 0
|
|
1325
1325
|
|
|
1326
|
-
main() -> Int =
|
|
1326
|
+
fun main() -> Int =
|
|
1327
1327
|
classify(1, 2)
|
|
1328
1328
|
";
|
|
1329
1329
|
let source = parse(src);
|
|
@@ -1334,13 +1334,13 @@ main() -> Int =
|
|
|
1334
1334
|
#[test]
|
|
1335
1335
|
fn multi_subject_match_with_binding_and_wildcard_runs_correctly() {
|
|
1336
1336
|
let src = "\
|
|
1337
|
-
combine(a: Int, b: Int) -> Int =
|
|
1337
|
+
fun combine(a: Int, b: Int) -> Int =
|
|
1338
1338
|
match a, b
|
|
1339
1339
|
0, y => y
|
|
1340
1340
|
x, 0 => x
|
|
1341
1341
|
x, y => x + y
|
|
1342
1342
|
|
|
1343
|
-
main() -> Int =
|
|
1343
|
+
fun main() -> Int =
|
|
1344
1344
|
combine(3, 4)
|
|
1345
1345
|
";
|
|
1346
1346
|
let source = parse(src);
|
|
@@ -1357,12 +1357,12 @@ enum Option =
|
|
|
1357
1357
|
| Some[T]
|
|
1358
1358
|
| None
|
|
1359
1359
|
|
|
1360
|
-
both(a: Option, b: Option) -> Int =
|
|
1360
|
+
fun both(a: Option, b: Option) -> Int =
|
|
1361
1361
|
match a, b
|
|
1362
1362
|
Some(x), Some(y) => x + y
|
|
1363
1363
|
_, _ => 0
|
|
1364
1364
|
|
|
1365
|
-
main() -> Int =
|
|
1365
|
+
fun main() -> Int =
|
|
1366
1366
|
both(Some(3), Some(4))
|
|
1367
1367
|
";
|
|
1368
1368
|
let source = parse(src);
|
|
@@ -1376,10 +1376,10 @@ fn field_assignment_target_runs_correctly() {
|
|
|
1376
1376
|
type Counter =
|
|
1377
1377
|
value: Int
|
|
1378
1378
|
|
|
1379
|
-
bump<Counter>() =
|
|
1379
|
+
fun bump<Counter>() =
|
|
1380
1380
|
self.value = self.value + 1
|
|
1381
1381
|
|
|
1382
|
-
main() -> Int =
|
|
1382
|
+
fun main() -> Int =
|
|
1383
1383
|
c = Counter(value: 41)
|
|
1384
1384
|
c.bump()
|
|
1385
1385
|
c.value
|
|
@@ -1398,10 +1398,10 @@ type Inner =
|
|
|
1398
1398
|
type Outer =
|
|
1399
1399
|
inner: Inner
|
|
1400
1400
|
|
|
1401
|
-
bump<Outer>() =
|
|
1401
|
+
fun bump<Outer>() =
|
|
1402
1402
|
self.inner.value = self.inner.value + 1
|
|
1403
1403
|
|
|
1404
|
-
main() -> Int =
|
|
1404
|
+
fun main() -> Int =
|
|
1405
1405
|
o = Outer(inner: Inner(value: 9))
|
|
1406
1406
|
o.bump()
|
|
1407
1407
|
o.inner.value
|
|
@@ -1417,7 +1417,7 @@ fn mixed_multi_assign_with_field_target_runs_correctly() {
|
|
|
1417
1417
|
type Counter =
|
|
1418
1418
|
value: Int
|
|
1419
1419
|
|
|
1420
|
-
main() -> Int =
|
|
1420
|
+
fun main() -> Int =
|
|
1421
1421
|
c = Counter(value: 5)
|
|
1422
1422
|
a, c.value = 100, 7
|
|
1423
1423
|
a + c.value
|
|
@@ -1430,10 +1430,10 @@ main() -> Int =
|
|
|
1430
1430
|
#[test]
|
|
1431
1431
|
fn variadic_call_with_varying_trailing_arg_counts_runs_correctly() {
|
|
1432
1432
|
let src = "\
|
|
1433
|
-
combine(prefix: Int, rest: ...Int) -> Int =
|
|
1433
|
+
fun combine(prefix: Int, rest: ...Int) -> Int =
|
|
1434
1434
|
prefix
|
|
1435
1435
|
|
|
1436
|
-
main() -> Int =
|
|
1436
|
+
fun main() -> Int =
|
|
1437
1437
|
a = combine(10)
|
|
1438
1438
|
b = combine(20, 1)
|
|
1439
1439
|
c = combine(30, 1, 2, 3)
|
|
@@ -1447,13 +1447,13 @@ main() -> Int =
|
|
|
1447
1447
|
#[test]
|
|
1448
1448
|
fn sum_all_variadic_int_runs_correctly() {
|
|
1449
1449
|
let src = "\
|
|
1450
|
-
sumAll(nums: ...Int) -> Int =
|
|
1450
|
+
fun sumAll(nums: ...Int) -> Int =
|
|
1451
1451
|
total = 0
|
|
1452
1452
|
for v in nums
|
|
1453
1453
|
total = total + v
|
|
1454
1454
|
total
|
|
1455
1455
|
|
|
1456
|
-
main() -> Int =
|
|
1456
|
+
fun main() -> Int =
|
|
1457
1457
|
sumAll(1, 2, 3, 4)
|
|
1458
1458
|
";
|
|
1459
1459
|
let source = parse(src);
|
|
@@ -1464,13 +1464,13 @@ main() -> Int =
|
|
|
1464
1464
|
#[test]
|
|
1465
1465
|
fn sum_all_variadic_int_with_zero_args_runs_correctly() {
|
|
1466
1466
|
let src = "\
|
|
1467
|
-
sumAll(nums: ...Int) -> Int =
|
|
1467
|
+
fun sumAll(nums: ...Int) -> Int =
|
|
1468
1468
|
total = 0
|
|
1469
1469
|
for v in nums
|
|
1470
1470
|
total = total + v
|
|
1471
1471
|
total
|
|
1472
1472
|
|
|
1473
|
-
main() -> Int =
|
|
1473
|
+
fun main() -> Int =
|
|
1474
1474
|
sumAll()
|
|
1475
1475
|
";
|
|
1476
1476
|
let source = parse(src);
|