alpha
Login
or
Join now
nandi.uk
/
gleam
Star
2
Fork
0
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
Fork of daniellemaywood.uk/gleam — Wasm codegen work
Star
2
Fork
0
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
Overview
Issues
Pulls
Pipelines
Be more strict with block lifting
author
GearsDatapacks
committer
Louis Pilfold
date
1 year ago
(Mar 16, 2025, 2:01 PM UTC)
commit
f50ef0f9
f50ef0f916ec393ac072cea2dab937a4d9acc2b5
parent
be6815a1
be6815a1725218c9b410249111a8598307a17fdd
+377
-260
26 changed files
Expand all
Collapse all
Unified
Split
compiler-core
src
javascript
expression.rs
tests
snapshots
gleam_core__javascript__tests__blocks__concat_blocks.snap
gleam_core__javascript__tests__blocks__left_operator_sequence.snap
gleam_core__javascript__tests__blocks__right_operator_sequence.snap
gleam_core__javascript__tests__bools__binop_panic_left.snap
gleam_core__javascript__tests__bools__binop_panic_right.snap
gleam_core__javascript__tests__bools__binop_todo_left.snap
gleam_core__javascript__tests__bools__binop_todo_right.snap
gleam_core__javascript__tests__bools__negate_panic.snap
gleam_core__javascript__tests__bools__negate_todo.snap
gleam_core__javascript__tests__bools__negation_block.snap
gleam_core__javascript__tests__case__called_case.snap
gleam_core__javascript__tests__case__pipe.snap
gleam_core__javascript__tests__echo__echo_with_a_block.snap
gleam_core__javascript__tests__echo__echo_with_a_case_expression.snap
gleam_core__javascript__tests__echo__echo_with_a_panic.snap
gleam_core__javascript__tests__functions__case_in_call.snap
gleam_core__javascript__tests__functions__two_pipes_in_a_row.snap
gleam_core__javascript__tests__lists__multi_line_list_literals.snap
gleam_core__javascript__tests__numbers__float_divide_complex_expr.snap
gleam_core__javascript__tests__numbers__int_divide_complex_expr.snap
gleam_core__javascript__tests__numbers__int_mod_complex_expr.snap
gleam_core__javascript__tests__panic__as_expression.snap
gleam_core__javascript__tests__panic__pipe.snap
gleam_core__javascript__tests__todo__as_expression.snap
gleam_core__javascript__tests__tuples__tuple_with_block_element.snap
+171
-73
compiler-core/src/javascript/expression.rs
View file
Reviewed
···
19
19
#[derive(Debug, Clone)]
20
20
pub enum Position {
21
21
Tail,
22
22
-
NotTail,
22
22
+
NotTail(Ordering),
23
23
/// We are compiling an expression inside a block, meaning we must assign
24
24
/// to the `_block` variable at the end of the scope, because blocks are not
25
25
/// expressions in JS.
···
37
37
pub fn is_tail(&self) -> bool {
38
38
matches!(self, Self::Tail)
39
39
}
40
40
+
}
41
41
+
42
42
+
#[derive(Debug, Clone, Copy)]
43
43
+
pub enum Ordering {
44
44
+
Strict,
45
45
+
Loose,
40
46
}
41
47
42
48
#[derive(Debug)]
···
168
174
TypedExpr::Float { value, .. } => Ok(float(value)),
169
175
170
176
TypedExpr::List { elements, tail, .. } => {
171
171
-
self.not_in_tail_position(|r#gen| match tail {
177
177
+
self.not_in_tail_position(Ordering::Strict, |r#gen| match tail {
172
178
Some(tail) => {
173
179
r#gen.tracker.prepend_used = true;
174
180
let tail = r#gen.wrap_expression(tail)?;
···
245
251
let expression = expression
246
252
.as_ref()
247
253
.expect("echo with no expression outside of pipe");
248
248
-
let expresion_doc =
249
249
-
self.not_in_tail_position(|this| this.wrap_expression(expression))?;
254
254
+
let expresion_doc = self.not_in_tail_position(Ordering::Strict, |this| {
255
255
+
this.wrap_expression(expression)
256
256
+
})?;
250
257
self.echo(expresion_doc, location)
251
258
}
252
259
···
262
269
}
263
270
264
271
fn negate_with(&mut self, with: &'static str, value: &'a TypedExpr) -> Output<'a> {
265
265
-
self.not_in_tail_position(|r#gen| Ok(docvec![with, r#gen.wrap_expression(value)?]))
272
272
+
self.not_in_tail_position(Ordering::Strict, |r#gen| {
273
273
+
Ok(docvec![with, r#gen.wrap_expression(value)?])
274
274
+
})
266
275
}
267
276
268
277
fn bit_array(&mut self, segments: &'a [TypedExprBitArraySegment]) -> Output<'a> {
···
272
281
273
282
// Collect all the values used in segments.
274
283
let segments_array = array(segments.iter().map(|segment| {
275
275
-
let value = self.not_in_tail_position(|r#gen| r#gen.wrap_expression(&segment.value))?;
284
284
+
let value = self.not_in_tail_position(Ordering::Strict, |r#gen| {
285
285
+
r#gen.wrap_expression(&segment.value)
286
286
+
})?;
276
287
277
288
if segment.type_ == crate::type_::int() || segment.type_ == crate::type_::float() {
278
289
let details = self.sized_bit_array_segment_details(segment)?;
···
421
432
(Some(size_value), size)
422
433
}
423
434
_ => {
424
424
-
let mut size =
425
425
-
self.not_in_tail_position(|r#gen| r#gen.wrap_expression(size))?;
435
435
+
let mut size = self.not_in_tail_position(Ordering::Strict, |r#gen| {
436
436
+
r#gen.wrap_expression(size)
437
437
+
})?;
426
438
427
439
if unit != 1 {
428
440
size = size.group().append(" * ".to_doc().append(unit.to_doc()));
···
452
464
pub fn wrap_return(&mut self, document: Document<'a>) -> Document<'a> {
453
465
match &self.scope_position {
454
466
Position::Tail => docvec!["return ", document, ";"],
455
455
-
Position::NotTail => document,
467
467
+
Position::NotTail(_) => document,
456
468
Position::Assign(name) => docvec![name.clone(), " = ", document, ";"],
457
469
}
458
470
}
459
471
460
460
-
pub fn not_in_tail_position<CompileFn>(&mut self, compile: CompileFn) -> Output<'a>
472
472
+
pub fn not_in_tail_position<CompileFn>(
473
473
+
&mut self,
474
474
+
ordering: Ordering,
475
475
+
compile: CompileFn,
476
476
+
) -> Output<'a>
461
477
where
462
478
CompileFn: Fn(&mut Self) -> Output<'a>,
463
479
{
464
464
-
let function_position = std::mem::replace(&mut self.function_position, Position::NotTail);
465
465
-
let scope_position = std::mem::replace(&mut self.scope_position, Position::NotTail);
480
480
+
let function_position =
481
481
+
std::mem::replace(&mut self.function_position, Position::NotTail(ordering));
482
482
+
let scope_position =
483
483
+
std::mem::replace(&mut self.scope_position, Position::NotTail(ordering));
466
484
467
485
let result = compile(self);
468
486
···
471
489
result
472
490
}
473
491
474
474
-
fn wrap_block<CompileFn>(&mut self, compile: CompileFn) -> Output<'a>
475
475
-
where
476
476
-
CompileFn: Fn(&mut Self) -> Output<'a>,
477
477
-
{
478
478
-
let block_variable = self.next_local_var(&BLOCK_VARIABLE.into());
479
479
-
480
480
-
// Save initial state
481
481
-
let scope_position = std::mem::replace(
482
482
-
&mut self.scope_position,
483
483
-
Position::Assign(block_variable.clone()),
484
484
-
);
485
485
-
let function_position = std::mem::replace(&mut self.function_position, Position::NotTail);
486
486
-
487
487
-
// Generate the expression
488
488
-
let statement_doc = compile(self)?;
489
489
-
self.statement_level
490
490
-
.push(docvec!["let ", block_variable.clone(), ";"]);
491
491
-
self.statement_level.push(statement_doc);
492
492
-
493
493
-
// Reset
494
494
-
self.scope_position = scope_position;
495
495
-
self.function_position = function_position;
496
496
-
497
497
-
Ok(self.wrap_return(block_variable.to_doc()))
498
498
-
}
499
499
-
500
492
/// Use the `_block` variable if the expression is JS statement.
501
493
pub fn wrap_expression(&mut self, expression: &'a TypedExpr) -> Output<'a> {
502
502
-
match expression {
503
503
-
TypedExpr::Panic { .. }
504
504
-
| TypedExpr::Todo { .. }
505
505
-
| TypedExpr::Case { .. }
506
506
-
| TypedExpr::Pipeline { .. }
507
507
-
| TypedExpr::RecordUpdate { .. } => self.wrap_block(|this| this.expression(expression)),
494
494
+
match (expression, &self.scope_position) {
495
495
+
(_, Position::Tail | Position::Assign(_)) => self.expression(expression),
496
496
+
(
497
497
+
TypedExpr::Panic { .. }
498
498
+
| TypedExpr::Todo { .. }
499
499
+
| TypedExpr::Case { .. }
500
500
+
| TypedExpr::Pipeline { .. }
501
501
+
| TypedExpr::RecordUpdate { .. },
502
502
+
Position::NotTail(Ordering::Loose),
503
503
+
) => self.wrap_block(|this| this.expression(expression)),
504
504
+
(
505
505
+
TypedExpr::Panic { .. }
506
506
+
| TypedExpr::Todo { .. }
507
507
+
| TypedExpr::Case { .. }
508
508
+
| TypedExpr::Pipeline { .. }
509
509
+
| TypedExpr::RecordUpdate { .. },
510
510
+
Position::NotTail(Ordering::Strict),
511
511
+
) => self.immediately_invoked_function_expression(expression, |r#gen, expr| {
512
512
+
r#gen.expression(expr)
513
513
+
}),
508
514
_ => self.expression(expression),
509
515
}
510
516
}
···
525
531
// Here the document is a return statement: `return <expr>;`
526
532
// or an assignment: `_block = <expr>;`
527
533
Position::Tail | Position::Assign(_) => document,
528
528
-
Position::NotTail => docvec!["(", document, ")"],
534
534
+
Position::NotTail(_) => docvec!["(", document, ")"],
529
535
})
530
536
}
531
537
538
538
+
/// Wrap an expression in an immediately invoked function expression
539
539
+
fn immediately_invoked_function_expression<T, ToDoc>(
540
540
+
&mut self,
541
541
+
statements: &'a T,
542
542
+
to_doc: ToDoc,
543
543
+
) -> Output<'a>
544
544
+
where
545
545
+
ToDoc: FnOnce(&mut Self, &'a T) -> Output<'a>,
546
546
+
{
547
547
+
// Save initial state
548
548
+
let scope_position = std::mem::replace(&mut self.scope_position, Position::Tail);
549
549
+
550
550
+
// Set state for in this iife
551
551
+
let current_scope_vars = self.current_scope_vars.clone();
552
552
+
553
553
+
// Generate the expression
554
554
+
let result = to_doc(self, statements);
555
555
+
556
556
+
// Reset
557
557
+
self.current_scope_vars = current_scope_vars;
558
558
+
self.scope_position = scope_position;
559
559
+
560
560
+
// Wrap in iife document
561
561
+
let doc = immediately_invoked_function_expression_document(result?);
562
562
+
Ok(self.wrap_return(doc))
563
563
+
}
564
564
+
565
565
+
fn wrap_block<CompileFn>(&mut self, compile: CompileFn) -> Output<'a>
566
566
+
where
567
567
+
CompileFn: Fn(&mut Self) -> Output<'a>,
568
568
+
{
569
569
+
let block_variable = self.next_local_var(&BLOCK_VARIABLE.into());
570
570
+
571
571
+
// Save initial state
572
572
+
let scope_position = std::mem::replace(
573
573
+
&mut self.scope_position,
574
574
+
Position::Assign(block_variable.clone()),
575
575
+
);
576
576
+
let function_position = std::mem::replace(
577
577
+
&mut self.function_position,
578
578
+
Position::NotTail(Ordering::Strict),
579
579
+
);
580
580
+
581
581
+
// Generate the expression
582
582
+
let statement_doc = compile(self);
583
583
+
584
584
+
// Reset
585
585
+
self.scope_position = scope_position;
586
586
+
self.function_position = function_position;
587
587
+
588
588
+
self.statement_level
589
589
+
.push(docvec!["let ", block_variable.clone(), ";"]);
590
590
+
self.statement_level.push(statement_doc?);
591
591
+
592
592
+
Ok(self.wrap_return(block_variable.to_doc()))
593
593
+
}
594
594
+
532
595
fn variable(&mut self, name: &'a EcoString, constructor: &'a ValueConstructor) -> Output<'a> {
533
596
match &constructor.variant {
534
597
ValueConstructorVariant::LocalConstant { literal } => {
···
566
629
expression: None,
567
630
location,
568
631
..
569
569
-
} => documents.push(self.not_in_tail_position(|this| {
632
632
+
} => documents.push(self.not_in_tail_position(Ordering::Strict, |this| {
570
633
let var = latest_local_var
571
634
.as_ref()
572
635
.expect("echo with no previous step in a pipe");
···
575
638
576
639
// Otherwise we assign the intermediate pipe value to a variable.
577
640
_ => {
578
578
-
documents.push(self.not_in_tail_position(|this| {
641
641
+
documents.push(self.not_in_tail_position(Ordering::Strict, |this| {
579
642
this.simple_variable_assignment(&assignment.name, &assignment.value)
580
643
})?);
581
644
latest_local_var = Some(self.local_var(&assignment.name));
···
621
684
} else {
622
685
match &self.scope_position {
623
686
Position::Tail | Position::Assign(_) => self.block_document(statements),
624
624
-
Position::NotTail => self.wrap_block(|this| {
687
687
+
Position::NotTail(Ordering::Strict) => self
688
688
+
.immediately_invoked_function_expression(statements, |r#gen, statements| {
689
689
+
r#gen.statements(statements)
690
690
+
}),
691
691
+
Position::NotTail(Ordering::Loose) => self.wrap_block(|this| {
625
692
// Save previous scope
626
693
let current_scope_vars = this.current_scope_vars.clone();
627
694
···
654
721
let mut documents = Vec::with_capacity(count * 3);
655
722
for (i, statement) in statements.iter().enumerate() {
656
723
if i + 1 < count {
657
657
-
documents.push(self.not_in_tail_position(|r#gen| r#gen.statement(statement))?);
724
724
+
documents.push(
725
725
+
self.not_in_tail_position(Ordering::Loose, |r#gen| r#gen.statement(statement))?,
726
726
+
);
658
727
if requires_semicolon(statement) {
659
728
documents.push(";".to_doc());
660
729
}
···
677
746
value: &'a TypedExpr,
678
747
) -> Output<'a> {
679
748
// Subject must be rendered before the variable for variable numbering
680
680
-
let subject = self.not_in_tail_position(|r#gen| r#gen.wrap_expression(value))?;
749
749
+
let subject =
750
750
+
self.not_in_tail_position(Ordering::Loose, |r#gen| r#gen.wrap_expression(value))?;
681
751
let js_name = self.next_local_var(name);
682
752
let assignment = docvec!["let ", js_name.clone(), " = ", subject, ";"];
683
753
let assignment = if self.scope_position.is_tail() {
···
707
777
// Otherwise we need to compile the patterns
708
778
let (subject, subject_assignment) = pattern::assign_subject(self, value);
709
779
// Value needs to be rendered before traversing pattern to have correctly incremented variables.
710
710
-
let value = self.not_in_tail_position(|r#gen| r#gen.wrap_expression(value))?;
780
780
+
let value =
781
781
+
self.not_in_tail_position(Ordering::Loose, |r#gen| r#gen.wrap_expression(value))?;
711
782
let mut pattern_generator = pattern::Generator::new(self);
712
783
pattern_generator.traverse_pattern(&subject, pattern)?;
713
784
let compiled = pattern_generator.take_compiled();
···
831
902
.zip(subject_values)
832
903
.flat_map(|(assignment_name, value)| assignment_name.map(|name| (name, value)))
833
904
.map(|(name, value)| {
834
834
-
let value = self.not_in_tail_position(|r#gen| r#gen.wrap_expression(value))?;
905
905
+
let value = self
906
906
+
.not_in_tail_position(Ordering::Strict, |r#gen| r#gen.wrap_expression(value))?;
835
907
Ok(docvec!["let ", name, " = ", value, ";", line()])
836
908
})
837
909
.try_collect()?;
···
846
918
message: Option<&'a TypedExpr>,
847
919
) -> Output<'a> {
848
920
let message = match message {
849
849
-
Some(m) => self.not_in_tail_position(|r#gen| r#gen.expression(m))?,
921
921
+
Some(m) => self.not_in_tail_position(Ordering::Strict, |r#gen| r#gen.expression(m))?,
850
922
None => string("Pattern match failed, no pattern matched the value."),
851
923
};
852
924
···
854
926
}
855
927
856
928
fn tuple(&mut self, elements: &'a [TypedExpr]) -> Output<'a> {
857
857
-
self.not_in_tail_position(|r#gen| {
929
929
+
self.not_in_tail_position(Ordering::Strict, |r#gen| {
858
930
array(
859
931
elements
860
932
.iter()
···
866
938
fn call(&mut self, fun: &'a TypedExpr, arguments: &'a [TypedCallArg]) -> Output<'a> {
867
939
let arguments = arguments
868
940
.iter()
869
869
-
.map(|element| self.not_in_tail_position(|r#gen| r#gen.wrap_expression(&element.value)))
941
941
+
.map(|element| {
942
942
+
self.not_in_tail_position(Ordering::Strict, |r#gen| {
943
943
+
r#gen.wrap_expression(&element.value)
944
944
+
})
945
945
+
})
870
946
.try_collect()?;
871
947
872
948
self.call_with_doc_args(fun, arguments)
···
943
1019
}
944
1020
945
1021
_ => {
946
946
-
let fun = self.not_in_tail_position(|r#gen| {
1022
1022
+
let fun = self.not_in_tail_position(Ordering::Strict, |r#gen| {
947
1023
let is_fn_literal = matches!(fun, TypedExpr::Fn { .. });
948
1024
let fun = r#gen.wrap_expression(fun)?;
949
1025
if is_fn_literal {
···
998
1074
}
999
1075
1000
1076
fn record_access(&mut self, record: &'a TypedExpr, label: &'a str) -> Output<'a> {
1001
1001
-
self.not_in_tail_position(|r#gen| {
1077
1077
+
self.not_in_tail_position(Ordering::Strict, |r#gen| {
1002
1078
let record = r#gen.wrap_expression(record)?;
1003
1079
Ok(docvec![record, ".", maybe_escape_property_doc(label)])
1004
1080
})
···
1011
1087
args: &'a [TypedCallArg],
1012
1088
) -> Output<'a> {
1013
1089
Ok(docvec![
1014
1014
-
self.not_in_tail_position(|r#gen| r#gen.assignment(record))?,
1090
1090
+
self.not_in_tail_position(Ordering::Strict, |r#gen| r#gen.assignment(record))?,
1015
1091
line(),
1016
1092
self.call(constructor, args)?,
1017
1093
])
1018
1094
}
1019
1095
1020
1096
fn tuple_index(&mut self, tuple: &'a TypedExpr, index: u64) -> Output<'a> {
1021
1021
-
self.not_in_tail_position(|r#gen| {
1097
1097
+
self.not_in_tail_position(Ordering::Strict, |r#gen| {
1022
1098
let tuple = r#gen.wrap_expression(tuple)?;
1023
1099
Ok(docvec![tuple, eco_format!("[{index}]")])
1024
1100
})
···
1046
1122
}
1047
1123
1048
1124
fn div_int(&mut self, left: &'a TypedExpr, right: &'a TypedExpr) -> Output<'a> {
1049
1049
-
let left = self.not_in_tail_position(|r#gen| r#gen.child_expression(left))?;
1050
1050
-
let right = self.not_in_tail_position(|r#gen| r#gen.child_expression(right))?;
1125
1125
+
let left =
1126
1126
+
self.not_in_tail_position(Ordering::Strict, |r#gen| r#gen.child_expression(left))?;
1127
1127
+
let right =
1128
1128
+
self.not_in_tail_position(Ordering::Strict, |r#gen| r#gen.child_expression(right))?;
1051
1129
self.tracker.int_division_used = true;
1052
1130
Ok(docvec!["divideInt", wrap_args([left, right])])
1053
1131
}
1054
1132
1055
1133
fn remainder_int(&mut self, left: &'a TypedExpr, right: &'a TypedExpr) -> Output<'a> {
1056
1056
-
let left = self.not_in_tail_position(|r#gen| r#gen.child_expression(left))?;
1057
1057
-
let right = self.not_in_tail_position(|r#gen| r#gen.child_expression(right))?;
1134
1134
+
let left =
1135
1135
+
self.not_in_tail_position(Ordering::Strict, |r#gen| r#gen.child_expression(left))?;
1136
1136
+
let right =
1137
1137
+
self.not_in_tail_position(Ordering::Strict, |r#gen| r#gen.child_expression(right))?;
1058
1138
self.tracker.int_remainder_used = true;
1059
1139
Ok(docvec!["remainderInt", wrap_args([left, right])])
1060
1140
}
1061
1141
1062
1142
fn div_float(&mut self, left: &'a TypedExpr, right: &'a TypedExpr) -> Output<'a> {
1063
1063
-
let left = self.not_in_tail_position(|r#gen| r#gen.child_expression(left))?;
1064
1064
-
let right = self.not_in_tail_position(|r#gen| r#gen.child_expression(right))?;
1143
1143
+
let left =
1144
1144
+
self.not_in_tail_position(Ordering::Strict, |r#gen| r#gen.child_expression(left))?;
1145
1145
+
let right =
1146
1146
+
self.not_in_tail_position(Ordering::Strict, |r#gen| r#gen.child_expression(right))?;
1065
1147
self.tracker.float_division_used = true;
1066
1148
Ok(docvec!["divideFloat", wrap_args([left, right])])
1067
1149
}
···
1074
1156
) -> Output<'a> {
1075
1157
// If it is a simple scalar type then we can use JS' reference identity
1076
1158
if is_js_scalar(left.type_()) {
1077
1077
-
let left_doc = self.not_in_tail_position(|r#gen| r#gen.child_expression(left))?;
1078
1078
-
let right_doc = self.not_in_tail_position(|r#gen| r#gen.child_expression(right))?;
1159
1159
+
let left_doc =
1160
1160
+
self.not_in_tail_position(Ordering::Strict, |r#gen| r#gen.child_expression(left))?;
1161
1161
+
let right_doc =
1162
1162
+
self.not_in_tail_position(Ordering::Strict, |r#gen| r#gen.child_expression(right))?;
1079
1163
let operator = if should_be_equal { " === " } else { " !== " };
1080
1164
return Ok(docvec![left_doc, operator, right_doc]);
1081
1165
}
1082
1166
1083
1167
// Other types must be compared using structural equality
1084
1084
-
let left = self.not_in_tail_position(|r#gen| r#gen.wrap_expression(left))?;
1085
1085
-
let right = self.not_in_tail_position(|r#gen| r#gen.wrap_expression(right))?;
1168
1168
+
let left =
1169
1169
+
self.not_in_tail_position(Ordering::Strict, |r#gen| r#gen.wrap_expression(left))?;
1170
1170
+
let right =
1171
1171
+
self.not_in_tail_position(Ordering::Strict, |r#gen| r#gen.wrap_expression(right))?;
1086
1172
Ok(self.prelude_equal_call(should_be_equal, left, right))
1087
1173
}
1088
1174
···
1110
1196
right: &'a TypedExpr,
1111
1197
op: &'a str,
1112
1198
) -> Output<'a> {
1113
1113
-
let left = self.not_in_tail_position(|r#gen| r#gen.child_expression(left))?;
1114
1114
-
let right = self.not_in_tail_position(|r#gen| r#gen.child_expression(right))?;
1199
1199
+
let left =
1200
1200
+
self.not_in_tail_position(Ordering::Strict, |r#gen| r#gen.child_expression(left))?;
1201
1201
+
let right =
1202
1202
+
self.not_in_tail_position(Ordering::Strict, |r#gen| r#gen.child_expression(right))?;
1115
1203
Ok(docvec![left, " ", op, " ", right])
1116
1204
}
1117
1205
1118
1206
fn todo(&mut self, message: Option<&'a TypedExpr>, location: &'a SrcSpan) -> Output<'a> {
1119
1207
let message = match message {
1120
1120
-
Some(m) => self.not_in_tail_position(|r#gen| r#gen.expression(m))?,
1208
1208
+
Some(m) => self.not_in_tail_position(Ordering::Strict, |r#gen| r#gen.expression(m))?,
1121
1209
None => string("`todo` expression evaluated. This code has not yet been implemented."),
1122
1210
};
1123
1211
let doc = self.throw_error("todo", &message, *location, vec![]);
···
1127
1215
1128
1216
fn panic(&mut self, location: &'a SrcSpan, message: Option<&'a TypedExpr>) -> Output<'a> {
1129
1217
let message = match message {
1130
1130
-
Some(m) => self.not_in_tail_position(|r#gen| r#gen.expression(m))?,
1218
1218
+
Some(m) => self.not_in_tail_position(Ordering::Strict, |r#gen| r#gen.expression(m))?,
1131
1219
None => string("`panic` expression evaluated."),
1132
1220
};
1133
1221
let doc = self.throw_error("panic", &message, *location, vec![]);
···
1954
2042
Statement::Assignment(_) => false,
1955
2043
Statement::Use(_) => false,
1956
2044
}
2045
2045
+
}
2046
2046
+
2047
2047
+
/// Wrap a document in an immediately invoked function expression
2048
2048
+
fn immediately_invoked_function_expression_document(document: Document<'_>) -> Document<'_> {
2049
2049
+
docvec![
2050
2050
+
docvec!["(() => {", break_("", " "), document].nest(INDENT),
2051
2051
+
break_("", " "),
2052
2052
+
"})()",
2053
2053
+
]
2054
2054
+
.group()
1957
2055
}
1958
2056
1959
2057
fn record_constructor<'a>(
+7
-7
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__concat_blocks.snap
View file
Reviewed
···
17
17
18
18
----- COMPILED JAVASCRIPT
19
19
function main(f, a, b) {
20
20
-
let _block;
21
21
-
let _pipe = a;
22
22
-
_block = f(_pipe);
23
23
-
let _block$1;
24
24
-
let _pipe$1 = b;
25
25
-
_block$1 = f(_pipe$1);
26
26
-
return _block + _block$1;
20
20
+
return (() => {
21
21
+
let _pipe = a;
22
22
+
return f(_pipe);
23
23
+
})() + (() => {
24
24
+
let _pipe = b;
25
25
+
return f(_pipe);
26
26
+
})();
27
27
}
+3
-5
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__left_operator_sequence.snap
View file
Reviewed
···
14
14
15
15
----- COMPILED JAVASCRIPT
16
16
function go() {
17
17
-
let _block;
18
18
-
{
17
17
+
return 1 === (() => {
19
18
1;
20
20
-
_block = 2;
21
21
-
}
22
22
-
return 1 === _block;
19
19
+
return 2;
20
20
+
})();
23
21
}
+3
-5
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__blocks__right_operator_sequence.snap
View file
Reviewed
···
14
14
15
15
----- COMPILED JAVASCRIPT
16
16
function go() {
17
17
-
let _block;
18
18
-
{
17
17
+
return (() => {
19
18
1;
20
20
-
_block = 2;
21
21
-
}
22
22
-
return _block === 1;
19
19
+
return 2;
20
20
+
})() === 1;
23
21
}
+10
-10
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__binop_panic_left.snap
View file
Reviewed
···
11
11
import { makeError } from "../gleam.mjs";
12
12
13
13
export function negate(x) {
14
14
-
let _block;
15
15
-
throw makeError(
16
16
-
"panic",
17
17
-
"my/mod",
18
18
-
2,
19
19
-
"negate",
20
20
-
"`panic` expression evaluated.",
21
21
-
{}
22
22
-
)
23
23
-
return _block && x;
14
14
+
return (() => {
15
15
+
throw makeError(
16
16
+
"panic",
17
17
+
"my/mod",
18
18
+
2,
19
19
+
"negate",
20
20
+
"`panic` expression evaluated.",
21
21
+
{}
22
22
+
)
23
23
+
})() && x;
24
24
}
+10
-10
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__binop_panic_right.snap
View file
Reviewed
···
11
11
import { makeError } from "../gleam.mjs";
12
12
13
13
export function negate(x) {
14
14
-
let _block;
15
15
-
throw makeError(
16
16
-
"panic",
17
17
-
"my/mod",
18
18
-
2,
19
19
-
"negate",
20
20
-
"`panic` expression evaluated.",
21
21
-
{}
22
22
-
)
23
23
-
return x && _block;
14
14
+
return x && (() => {
15
15
+
throw makeError(
16
16
+
"panic",
17
17
+
"my/mod",
18
18
+
2,
19
19
+
"negate",
20
20
+
"`panic` expression evaluated.",
21
21
+
{}
22
22
+
)
23
23
+
})();
24
24
}
+10
-10
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__binop_todo_left.snap
View file
Reviewed
···
11
11
import { makeError } from "../gleam.mjs";
12
12
13
13
export function negate(x) {
14
14
-
let _block;
15
15
-
throw makeError(
16
16
-
"todo",
17
17
-
"my/mod",
18
18
-
2,
19
19
-
"negate",
20
20
-
"`todo` expression evaluated. This code has not yet been implemented.",
21
21
-
{}
22
22
-
)
23
23
-
return _block && x;
14
14
+
return (() => {
15
15
+
throw makeError(
16
16
+
"todo",
17
17
+
"my/mod",
18
18
+
2,
19
19
+
"negate",
20
20
+
"`todo` expression evaluated. This code has not yet been implemented.",
21
21
+
{}
22
22
+
)
23
23
+
})() && x;
24
24
}
+10
-10
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__binop_todo_right.snap
View file
Reviewed
···
11
11
import { makeError } from "../gleam.mjs";
12
12
13
13
export function negate(x) {
14
14
-
let _block;
15
15
-
throw makeError(
16
16
-
"todo",
17
17
-
"my/mod",
18
18
-
2,
19
19
-
"negate",
20
20
-
"`todo` expression evaluated. This code has not yet been implemented.",
21
21
-
{}
22
22
-
)
23
23
-
return x && _block;
14
14
+
return x && (() => {
15
15
+
throw makeError(
16
16
+
"todo",
17
17
+
"my/mod",
18
18
+
2,
19
19
+
"negate",
20
20
+
"`todo` expression evaluated. This code has not yet been implemented.",
21
21
+
{}
22
22
+
)
23
23
+
})();
24
24
}
+10
-10
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__negate_panic.snap
View file
Reviewed
···
11
11
import { makeError } from "../gleam.mjs";
12
12
13
13
export function negate(x) {
14
14
-
let _block;
15
15
-
throw makeError(
16
16
-
"panic",
17
17
-
"my/mod",
18
18
-
2,
19
19
-
"negate",
20
20
-
"`panic` expression evaluated.",
21
21
-
{}
22
22
-
)
23
23
-
return !_block;
14
14
+
return !(() => {
15
15
+
throw makeError(
16
16
+
"panic",
17
17
+
"my/mod",
18
18
+
2,
19
19
+
"negate",
20
20
+
"`panic` expression evaluated.",
21
21
+
{}
22
22
+
)
23
23
+
})();
24
24
}
+10
-10
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__negate_todo.snap
View file
Reviewed
···
11
11
import { makeError } from "../gleam.mjs";
12
12
13
13
export function negate(x) {
14
14
-
let _block;
15
15
-
throw makeError(
16
16
-
"todo",
17
17
-
"my/mod",
18
18
-
2,
19
19
-
"negate",
20
20
-
"`todo` expression evaluated. This code has not yet been implemented.",
21
21
-
{}
22
22
-
)
23
23
-
return !_block;
14
14
+
return !(() => {
15
15
+
throw makeError(
16
16
+
"todo",
17
17
+
"my/mod",
18
18
+
2,
19
19
+
"negate",
20
20
+
"`todo` expression evaluated. This code has not yet been implemented.",
21
21
+
{}
22
22
+
)
23
23
+
})();
24
24
}
+3
-5
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bools__negation_block.snap
View file
Reviewed
···
12
12
13
13
----- COMPILED JAVASCRIPT
14
14
export function negate(x) {
15
15
-
let _block;
16
16
-
{
15
15
+
return !(() => {
17
16
123;
18
18
-
_block = x;
19
19
-
}
20
20
-
return !_block;
17
17
+
return x;
18
18
+
})();
21
19
}
+7
-7
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__called_case.snap
View file
Reviewed
···
14
14
15
15
----- COMPILED JAVASCRIPT
16
16
function go(x, y) {
17
17
-
let _block;
18
18
-
if (x === 0) {
19
19
-
_block = y;
20
20
-
} else {
21
21
-
_block = y;
22
22
-
}
23
23
-
return _block();
17
17
+
return (() => {
18
18
+
if (x === 0) {
19
19
+
return y;
20
20
+
} else {
21
21
+
return y;
22
22
+
}
23
23
+
})()();
24
24
}
+4
-4
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__pipe.snap
View file
Reviewed
···
14
14
15
15
----- COMPILED JAVASCRIPT
16
16
function go(x, f) {
17
17
-
let _block;
18
18
-
let _pipe = x;
19
19
-
_block = f(_pipe);
20
20
-
let $ = _block;
17
17
+
let $ = (() => {
18
18
+
let _pipe = x;
19
19
+
return f(_pipe);
20
20
+
})();
21
21
if ($ === 0) {
22
22
return 1;
23
23
} else {
+8
-6
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__echo__echo_with_a_block.snap
View file
Reviewed
···
24
24
} from "../gleam.mjs";
25
25
26
26
export function main() {
27
27
-
let _block;
28
28
-
{
29
29
-
undefined;
30
30
-
_block = 1;
31
31
-
}
32
32
-
return echo(_block, "src/module.gleam", 3);
27
27
+
return echo(
28
28
+
(() => {
29
29
+
undefined;
30
30
+
return 1;
31
31
+
})(),
32
32
+
"src/module.gleam",
33
33
+
3,
34
34
+
);
33
35
}
34
36
35
37
// ...omitted code from `templates/echo.mjs`...
+10
-6
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__echo__echo_with_a_case_expression.snap
View file
Reviewed
···
23
23
} from "../gleam.mjs";
24
24
25
25
export function main() {
26
26
-
let _block;
27
27
-
let $ = 1;
28
28
-
{
29
29
-
_block = 2;
30
30
-
}
31
31
-
return echo(_block, "src/module.gleam", 3);
26
26
+
return echo(
27
27
+
(() => {
28
28
+
let $ = 1;
29
29
+
{
30
30
+
return 2;
31
31
+
}
32
32
+
})(),
33
33
+
"src/module.gleam",
34
34
+
3,
35
35
+
);
32
36
}
33
37
34
38
// ...omitted code from `templates/echo.mjs`...
+13
-9
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__echo__echo_with_a_panic.snap
View file
Reviewed
···
22
22
} from "../gleam.mjs";
23
23
24
24
export function main() {
25
25
-
let _block;
26
26
-
throw makeError(
27
27
-
"panic",
28
28
-
"my/mod",
25
25
+
return echo(
26
26
+
(() => {
27
27
+
throw makeError(
28
28
+
"panic",
29
29
+
"my/mod",
30
30
+
3,
31
31
+
"main",
32
32
+
"`panic` expression evaluated.",
33
33
+
{}
34
34
+
)
35
35
+
})(),
36
36
+
"src/module.gleam",
29
37
3,
30
30
-
"main",
31
31
-
"`panic` expression evaluated.",
32
32
-
{}
33
33
-
)
34
34
-
return echo(_block, "src/module.gleam", 3);
38
38
+
);
35
39
}
36
40
37
41
// ...omitted code from `templates/echo.mjs`...
+9
-7
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__case_in_call.snap
View file
Reviewed
···
13
13
14
14
----- COMPILED JAVASCRIPT
15
15
export function main(f, x) {
16
16
-
let _block;
17
17
-
if (x === 1) {
18
18
-
_block = 2;
19
19
-
} else {
20
20
-
_block = 0;
21
21
-
}
22
22
-
return f(_block);
16
16
+
return f(
17
17
+
(() => {
18
18
+
if (x === 1) {
19
19
+
return 2;
20
20
+
} else {
21
21
+
return 0;
22
22
+
}
23
23
+
})(),
24
24
+
);
23
25
}
+10
-7
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__functions__two_pipes_in_a_row.snap
View file
Reviewed
···
24
24
}
25
25
26
26
export function main() {
27
27
-
let _block;
28
28
-
let _pipe = () => { return 1; };
29
29
-
_block = new Function(_pipe);
30
30
-
let _block$1;
31
31
-
let _pipe$1 = () => { return 2; };
32
32
-
_block$1 = new Function(_pipe$1);
33
33
-
return toList([_block, _block$1]);
27
27
+
return toList([
28
28
+
(() => {
29
29
+
let _pipe = () => { return 1; };
30
30
+
return new Function(_pipe);
31
31
+
})(),
32
32
+
(() => {
33
33
+
let _pipe = () => { return 2; };
34
34
+
return new Function(_pipe);
35
35
+
})(),
36
36
+
]);
34
37
}
+6
-6
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__lists__multi_line_list_literals.snap
View file
Reviewed
···
13
13
import { toList } from "../gleam.mjs";
14
14
15
15
function go(x) {
16
16
-
let _block;
17
17
-
{
18
18
-
true;
19
19
-
_block = 1;
20
20
-
}
21
21
-
return toList([_block]);
16
16
+
return toList([
17
17
+
(() => {
18
18
+
true;
19
19
+
return 1;
20
20
+
})(),
21
21
+
]);
22
22
}
+11
-8
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__float_divide_complex_expr.snap
View file
Reviewed
···
16
16
import { divideFloat } from "../gleam.mjs";
17
17
18
18
function go() {
19
19
-
let _block;
20
20
-
let $ = 1.0 >= 0.0;
21
21
-
if ($) {
22
22
-
_block = 2.0;
23
23
-
} else {
24
24
-
_block = 4.0;
25
25
-
}
26
26
-
return divideFloat(_block, 2.0);
19
19
+
return divideFloat(
20
20
+
(() => {
21
21
+
let $ = 1.0 >= 0.0;
22
22
+
if ($) {
23
23
+
return 2.0;
24
24
+
} else {
25
25
+
return 4.0;
26
26
+
}
27
27
+
})(),
28
28
+
2.0
29
29
+
);
27
30
}
+11
-8
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__int_divide_complex_expr.snap
View file
Reviewed
···
16
16
import { divideInt } from "../gleam.mjs";
17
17
18
18
function go() {
19
19
-
let _block;
20
20
-
let $ = 1 >= 0;
21
21
-
if ($) {
22
22
-
_block = 2;
23
23
-
} else {
24
24
-
_block = 4;
25
25
-
}
26
26
-
return divideInt(_block, 2);
19
19
+
return divideInt(
20
20
+
(() => {
21
21
+
let $ = 1 >= 0;
22
22
+
if ($) {
23
23
+
return 2;
24
24
+
} else {
25
25
+
return 4;
26
26
+
}
27
27
+
})(),
28
28
+
2
29
29
+
);
27
30
}
+11
-8
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__numbers__int_mod_complex_expr.snap
View file
Reviewed
···
16
16
import { remainderInt } from "../gleam.mjs";
17
17
18
18
function go() {
19
19
-
let _block;
20
20
-
let $ = 1 >= 0;
21
21
-
if ($) {
22
22
-
_block = 2;
23
23
-
} else {
24
24
-
_block = 4;
25
25
-
}
26
26
-
return remainderInt(_block, 2);
19
19
+
return remainderInt(
20
20
+
(() => {
21
21
+
let $ = 1 >= 0;
22
22
+
if ($) {
23
23
+
return 2;
24
24
+
} else {
25
25
+
return 4;
26
26
+
}
27
27
+
})(),
28
28
+
2
29
29
+
);
27
30
}
+12
-10
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__panic__as_expression.snap
View file
Reviewed
···
24
24
{}
25
25
)
26
26
let boop = _block;
27
27
-
let _block$1;
28
28
-
throw makeError(
29
29
-
"panic",
30
30
-
"my/mod",
31
31
-
4,
32
32
-
"go",
33
33
-
"`panic` expression evaluated.",
34
34
-
{}
35
35
-
)
36
36
-
return f(_block$1);
27
27
+
return f(
28
28
+
(() => {
29
29
+
throw makeError(
30
30
+
"panic",
31
31
+
"my/mod",
32
32
+
4,
33
33
+
"go",
34
34
+
"`panic` expression evaluated.",
35
35
+
{}
36
36
+
)
37
37
+
})(),
38
38
+
);
37
39
}
+10
-10
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__panic__pipe.snap
View file
Reviewed
···
13
13
import { makeError } from "../gleam.mjs";
14
14
15
15
function go(f) {
16
16
-
let _block;
17
17
-
throw makeError(
18
18
-
"panic",
19
19
-
"my/mod",
20
20
-
3,
21
21
-
"go",
22
22
-
"`panic` expression evaluated.",
23
23
-
{}
24
24
-
)
25
16
let _pipe = f;
26
26
-
return _block(_pipe);
17
17
+
return (() => {
18
18
+
throw makeError(
19
19
+
"panic",
20
20
+
"my/mod",
21
21
+
3,
22
22
+
"go",
23
23
+
"`panic` expression evaluated.",
24
24
+
{}
25
25
+
)
26
26
+
})()(_pipe);
27
27
}
+1
-3
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__todo__as_expression.snap
View file
Reviewed
···
17
17
let _block;
18
18
throw makeError("todo", "my/mod", 3, "go", "I should do this", {})
19
19
let boop = _block;
20
20
-
let _block$1;
21
21
-
throw makeError("todo", "my/mod", 4, "go", "Boom", {})
22
22
-
return f(_block$1);
20
20
+
return f((() => { throw makeError("todo", "my/mod", 4, "go", "Boom", {}) })());
23
21
}
+7
-6
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__tuples__tuple_with_block_element.snap
View file
Reviewed
···
17
17
18
18
----- COMPILED JAVASCRIPT
19
19
function go() {
20
20
-
let _block;
21
21
-
{
22
22
-
"2";
23
23
-
_block = "3";
24
24
-
}
25
25
-
return ["1", _block];
20
20
+
return [
21
21
+
"1",
22
22
+
(() => {
23
23
+
"2";
24
24
+
return "3";
25
25
+
})(),
26
26
+
];
26
27
}