mustardscript 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/Cargo.lock +1579 -0
  2. package/Cargo.toml +40 -0
  3. package/LICENSE +201 -0
  4. package/README.md +828 -0
  5. package/SECURITY.md +34 -0
  6. package/crates/mustard/Cargo.toml +31 -0
  7. package/crates/mustard/src/cancellation.rs +28 -0
  8. package/crates/mustard/src/diagnostic.rs +145 -0
  9. package/crates/mustard/src/ir.rs +435 -0
  10. package/crates/mustard/src/lib.rs +21 -0
  11. package/crates/mustard/src/limits.rs +22 -0
  12. package/crates/mustard/src/parser/expressions.rs +723 -0
  13. package/crates/mustard/src/parser/mod.rs +115 -0
  14. package/crates/mustard/src/parser/operators.rs +105 -0
  15. package/crates/mustard/src/parser/patterns.rs +123 -0
  16. package/crates/mustard/src/parser/scope.rs +107 -0
  17. package/crates/mustard/src/parser/statements.rs +298 -0
  18. package/crates/mustard/src/parser/tests/acceptance.rs +339 -0
  19. package/crates/mustard/src/parser/tests/mod.rs +2 -0
  20. package/crates/mustard/src/parser/tests/rejections.rs +107 -0
  21. package/crates/mustard/src/runtime/accounting.rs +613 -0
  22. package/crates/mustard/src/runtime/api.rs +192 -0
  23. package/crates/mustard/src/runtime/async_runtime/mod.rs +5 -0
  24. package/crates/mustard/src/runtime/async_runtime/promises.rs +246 -0
  25. package/crates/mustard/src/runtime/async_runtime/reactions.rs +400 -0
  26. package/crates/mustard/src/runtime/async_runtime/scheduler.rs +224 -0
  27. package/crates/mustard/src/runtime/builtins/arrays.rs +1205 -0
  28. package/crates/mustard/src/runtime/builtins/collections.rs +573 -0
  29. package/crates/mustard/src/runtime/builtins/install.rs +501 -0
  30. package/crates/mustard/src/runtime/builtins/intl.rs +553 -0
  31. package/crates/mustard/src/runtime/builtins/mod.rs +25 -0
  32. package/crates/mustard/src/runtime/builtins/objects.rs +405 -0
  33. package/crates/mustard/src/runtime/builtins/primitives.rs +859 -0
  34. package/crates/mustard/src/runtime/builtins/promises.rs +335 -0
  35. package/crates/mustard/src/runtime/builtins/regexp.rs +356 -0
  36. package/crates/mustard/src/runtime/builtins/strings.rs +803 -0
  37. package/crates/mustard/src/runtime/builtins/support.rs +561 -0
  38. package/crates/mustard/src/runtime/bytecode.rs +123 -0
  39. package/crates/mustard/src/runtime/compiler/assignments.rs +690 -0
  40. package/crates/mustard/src/runtime/compiler/bindings.rs +92 -0
  41. package/crates/mustard/src/runtime/compiler/context.rs +46 -0
  42. package/crates/mustard/src/runtime/compiler/control.rs +342 -0
  43. package/crates/mustard/src/runtime/compiler/expressions.rs +372 -0
  44. package/crates/mustard/src/runtime/compiler/mod.rs +173 -0
  45. package/crates/mustard/src/runtime/compiler/statements.rs +459 -0
  46. package/crates/mustard/src/runtime/conversions/boundary.rs +293 -0
  47. package/crates/mustard/src/runtime/conversions/coercions.rs +217 -0
  48. package/crates/mustard/src/runtime/conversions/errors.rs +118 -0
  49. package/crates/mustard/src/runtime/conversions/mod.rs +14 -0
  50. package/crates/mustard/src/runtime/conversions/operators.rs +334 -0
  51. package/crates/mustard/src/runtime/env.rs +355 -0
  52. package/crates/mustard/src/runtime/exceptions.rs +377 -0
  53. package/crates/mustard/src/runtime/gc.rs +595 -0
  54. package/crates/mustard/src/runtime/mod.rs +318 -0
  55. package/crates/mustard/src/runtime/properties.rs +1762 -0
  56. package/crates/mustard/src/runtime/serialization.rs +127 -0
  57. package/crates/mustard/src/runtime/shared.rs +108 -0
  58. package/crates/mustard/src/runtime/snapshot_validation_tests.rs +93 -0
  59. package/crates/mustard/src/runtime/state.rs +652 -0
  60. package/crates/mustard/src/runtime/tests/async_host.rs +104 -0
  61. package/crates/mustard/src/runtime/tests/collections.rs +50 -0
  62. package/crates/mustard/src/runtime/tests/diagnostics.rs +36 -0
  63. package/crates/mustard/src/runtime/tests/exceptions.rs +122 -0
  64. package/crates/mustard/src/runtime/tests/execution.rs +553 -0
  65. package/crates/mustard/src/runtime/tests/gc.rs +533 -0
  66. package/crates/mustard/src/runtime/tests/mod.rs +56 -0
  67. package/crates/mustard/src/runtime/tests/serialization.rs +170 -0
  68. package/crates/mustard/src/runtime/validation/bytecode.rs +484 -0
  69. package/crates/mustard/src/runtime/validation/mod.rs +14 -0
  70. package/crates/mustard/src/runtime/validation/policy.rs +94 -0
  71. package/crates/mustard/src/runtime/validation/snapshot.rs +406 -0
  72. package/crates/mustard/src/runtime/validation/walk.rs +206 -0
  73. package/crates/mustard/src/runtime/vm.rs +1016 -0
  74. package/crates/mustard/src/span.rs +22 -0
  75. package/crates/mustard/src/structured.rs +107 -0
  76. package/crates/mustard-bridge/Cargo.toml +17 -0
  77. package/crates/mustard-bridge/src/codec.rs +46 -0
  78. package/crates/mustard-bridge/src/dto.rs +99 -0
  79. package/crates/mustard-bridge/src/lib.rs +12 -0
  80. package/crates/mustard-bridge/src/operations.rs +142 -0
  81. package/crates/mustard-node/Cargo.toml +24 -0
  82. package/crates/mustard-node/build.rs +3 -0
  83. package/crates/mustard-node/src/lib.rs +236 -0
  84. package/crates/mustard-sidecar/Cargo.toml +21 -0
  85. package/crates/mustard-sidecar/src/lib.rs +134 -0
  86. package/crates/mustard-sidecar/src/main.rs +36 -0
  87. package/dist/index.js +20 -0
  88. package/dist/install.js +117 -0
  89. package/dist/lib/cancellation.js +124 -0
  90. package/dist/lib/errors.js +46 -0
  91. package/dist/lib/executor.js +555 -0
  92. package/dist/lib/policy.js +292 -0
  93. package/dist/lib/progress.js +356 -0
  94. package/dist/lib/runtime.js +109 -0
  95. package/dist/lib/structured.js +286 -0
  96. package/dist/native-loader.js +227 -0
  97. package/index.d.ts +23 -0
  98. package/mustard.d.ts +220 -0
  99. package/package.json +97 -0
@@ -0,0 +1,690 @@
1
+ use super::super::{bytecode::Instruction, format_number_key};
2
+ use super::{Compiler, context::CompileContext};
3
+ use crate::{
4
+ diagnostic::MustardResult,
5
+ ir::{AssignOp, AssignTarget, Expr, MemberProperty, Pattern, PropertyName, UpdateOp},
6
+ span::SourceSpan,
7
+ };
8
+
9
+ use super::bindings::assign_op_to_binary;
10
+
11
+ impl Compiler {
12
+ fn declare_internal_binding(&mut self, context: &mut CompileContext, prefix: &str) -> String {
13
+ let name = self.fresh_internal_name(context, prefix);
14
+ context.code.push(Instruction::DeclareName {
15
+ name: name.clone(),
16
+ mutable: true,
17
+ });
18
+ name
19
+ }
20
+
21
+ fn store_internal_binding(
22
+ &mut self,
23
+ context: &mut CompileContext,
24
+ name: &str,
25
+ span: SourceSpan,
26
+ ) {
27
+ context
28
+ .code
29
+ .push(Instruction::InitializePattern(Pattern::Identifier {
30
+ span,
31
+ name: name.to_string(),
32
+ }));
33
+ }
34
+
35
+ pub(super) fn compile_pattern_binding(
36
+ &mut self,
37
+ context: &mut CompileContext,
38
+ pattern: &Pattern,
39
+ ) -> MustardResult<()> {
40
+ match pattern {
41
+ Pattern::Identifier { .. } => {
42
+ context
43
+ .code
44
+ .push(Instruction::InitializePattern(pattern.clone()));
45
+ }
46
+ Pattern::Array {
47
+ span,
48
+ elements,
49
+ rest,
50
+ } => {
51
+ let source = self.declare_internal_binding(context, "pattern_array");
52
+ self.store_internal_binding(context, &source, *span);
53
+ for (index, element) in elements.iter().enumerate() {
54
+ if let Some(element) = element {
55
+ context.code.push(Instruction::LoadName(source.clone()));
56
+ context.code.push(Instruction::PatternArrayIndex(index));
57
+ self.compile_pattern_binding(context, element)?;
58
+ }
59
+ }
60
+ if let Some(rest) = rest {
61
+ context.code.push(Instruction::LoadName(source));
62
+ context
63
+ .code
64
+ .push(Instruction::PatternArrayRest(elements.len()));
65
+ self.compile_pattern_binding(context, rest)?;
66
+ }
67
+ }
68
+ Pattern::Object {
69
+ span,
70
+ properties,
71
+ rest,
72
+ } => {
73
+ let source = self.declare_internal_binding(context, "pattern_object");
74
+ self.store_internal_binding(context, &source, *span);
75
+ for property in properties {
76
+ context.code.push(Instruction::LoadName(source.clone()));
77
+ match &property.key {
78
+ PropertyName::Identifier(name) | PropertyName::String(name) => {
79
+ context.code.push(Instruction::GetPropStatic {
80
+ name: name.clone(),
81
+ optional: false,
82
+ });
83
+ }
84
+ PropertyName::Number(number) => {
85
+ context.code.push(Instruction::GetPropStatic {
86
+ name: format_number_key(*number),
87
+ optional: false,
88
+ });
89
+ }
90
+ }
91
+ self.compile_pattern_binding(context, &property.value)?;
92
+ }
93
+ if let Some(rest) = rest {
94
+ let excluded = properties
95
+ .iter()
96
+ .map(|property| match &property.key {
97
+ PropertyName::Identifier(name) | PropertyName::String(name) => {
98
+ name.clone()
99
+ }
100
+ PropertyName::Number(number) => format_number_key(*number),
101
+ })
102
+ .collect();
103
+ context.code.push(Instruction::LoadName(source));
104
+ context.code.push(Instruction::PatternObjectRest(excluded));
105
+ self.compile_pattern_binding(context, rest)?;
106
+ }
107
+ }
108
+ Pattern::Default {
109
+ span,
110
+ target,
111
+ default_value,
112
+ } => {
113
+ let source = self.declare_internal_binding(context, "pattern_default");
114
+ self.store_internal_binding(context, &source, *span);
115
+ context.code.push(Instruction::LoadName(source.clone()));
116
+ context.code.push(Instruction::PushUndefined);
117
+ context
118
+ .code
119
+ .push(Instruction::Binary(crate::ir::BinaryOp::StrictEq));
120
+ let use_source = self.emit_jump(context, Instruction::JumpIfFalse(usize::MAX));
121
+ context.code.push(Instruction::Pop);
122
+ self.compile_expr(context, default_value)?;
123
+ let end = self.emit_jump(context, Instruction::Jump(usize::MAX));
124
+ let use_source_ip = context.code.len();
125
+ self.patch_jump(context, use_source, use_source_ip);
126
+ context.code.push(Instruction::Pop);
127
+ context.code.push(Instruction::LoadName(source));
128
+ let end_ip = context.code.len();
129
+ self.patch_jump(context, end, end_ip);
130
+ self.compile_pattern_binding(context, target)?;
131
+ }
132
+ }
133
+ Ok(())
134
+ }
135
+
136
+ fn compile_assign_target_pattern(
137
+ &mut self,
138
+ context: &mut CompileContext,
139
+ target: &AssignTarget,
140
+ ) -> MustardResult<()> {
141
+ match target {
142
+ AssignTarget::Identifier { .. } | AssignTarget::Member { .. } => {
143
+ let source = self.declare_internal_binding(context, "assign_value");
144
+ self.store_internal_binding(context, &source, SourceSpan::new(0, 0));
145
+ self.compile_assignment(
146
+ context,
147
+ target,
148
+ AssignOp::Assign,
149
+ &Expr::Identifier {
150
+ span: SourceSpan::new(0, 0),
151
+ name: source,
152
+ },
153
+ )?;
154
+ context.code.push(Instruction::Pop);
155
+ }
156
+ AssignTarget::Default {
157
+ span,
158
+ target,
159
+ default_value,
160
+ } => {
161
+ let source = self.declare_internal_binding(context, "assign_default");
162
+ self.store_internal_binding(context, &source, *span);
163
+ context.code.push(Instruction::LoadName(source.clone()));
164
+ context.code.push(Instruction::PushUndefined);
165
+ context
166
+ .code
167
+ .push(Instruction::Binary(crate::ir::BinaryOp::StrictEq));
168
+ let use_source = self.emit_jump(context, Instruction::JumpIfFalse(usize::MAX));
169
+ context.code.push(Instruction::Pop);
170
+ self.compile_expr(context, default_value)?;
171
+ let end = self.emit_jump(context, Instruction::Jump(usize::MAX));
172
+ let use_source_ip = context.code.len();
173
+ self.patch_jump(context, use_source, use_source_ip);
174
+ context.code.push(Instruction::Pop);
175
+ context.code.push(Instruction::LoadName(source));
176
+ let end_ip = context.code.len();
177
+ self.patch_jump(context, end, end_ip);
178
+ self.compile_assign_target_pattern(context, target)?;
179
+ }
180
+ AssignTarget::Array {
181
+ span,
182
+ elements,
183
+ rest,
184
+ } => {
185
+ let source = self.declare_internal_binding(context, "assign_array");
186
+ self.store_internal_binding(context, &source, *span);
187
+ for (index, element) in elements.iter().enumerate() {
188
+ if let Some(element) = element {
189
+ context.code.push(Instruction::LoadName(source.clone()));
190
+ context.code.push(Instruction::PatternArrayIndex(index));
191
+ self.compile_assign_target_pattern(context, element)?;
192
+ }
193
+ }
194
+ if let Some(rest) = rest {
195
+ context.code.push(Instruction::LoadName(source));
196
+ context
197
+ .code
198
+ .push(Instruction::PatternArrayRest(elements.len()));
199
+ self.compile_assign_target_pattern(context, rest)?;
200
+ }
201
+ }
202
+ AssignTarget::Object {
203
+ span,
204
+ properties,
205
+ rest,
206
+ } => {
207
+ let source = self.declare_internal_binding(context, "assign_object");
208
+ self.store_internal_binding(context, &source, *span);
209
+ for property in properties {
210
+ context.code.push(Instruction::LoadName(source.clone()));
211
+ match &property.key {
212
+ PropertyName::Identifier(name) | PropertyName::String(name) => {
213
+ context.code.push(Instruction::GetPropStatic {
214
+ name: name.clone(),
215
+ optional: false,
216
+ });
217
+ }
218
+ PropertyName::Number(number) => {
219
+ context.code.push(Instruction::GetPropStatic {
220
+ name: format_number_key(*number),
221
+ optional: false,
222
+ });
223
+ }
224
+ }
225
+ self.compile_assign_target_pattern(context, &property.value)?;
226
+ }
227
+ if let Some(rest) = rest {
228
+ let excluded = properties
229
+ .iter()
230
+ .map(|property| match &property.key {
231
+ PropertyName::Identifier(name) | PropertyName::String(name) => {
232
+ name.clone()
233
+ }
234
+ PropertyName::Number(number) => format_number_key(*number),
235
+ })
236
+ .collect();
237
+ context.code.push(Instruction::LoadName(source));
238
+ context.code.push(Instruction::PatternObjectRest(excluded));
239
+ self.compile_assign_target_pattern(context, rest)?;
240
+ }
241
+ }
242
+ }
243
+ Ok(())
244
+ }
245
+
246
+ fn compile_short_circuit_assignment_identifier(
247
+ &mut self,
248
+ context: &mut CompileContext,
249
+ name: &str,
250
+ value: &Expr,
251
+ jump_if_eval: Instruction,
252
+ ) -> MustardResult<()> {
253
+ context.code.push(Instruction::LoadName(name.to_string()));
254
+ context.code.push(Instruction::Dup);
255
+ let rhs_jump = self.emit_jump(context, jump_if_eval);
256
+ context.code.push(Instruction::Pop);
257
+ let end_jump = self.emit_jump(context, Instruction::Jump(usize::MAX));
258
+ let rhs_ip = context.code.len();
259
+ self.patch_jump(context, rhs_jump, rhs_ip);
260
+ context.code.push(Instruction::Pop);
261
+ context.code.push(Instruction::Pop);
262
+ self.compile_expr(context, value)?;
263
+ context.code.push(Instruction::StoreName(name.to_string()));
264
+ let end_ip = context.code.len();
265
+ self.patch_jump(context, end_jump, end_ip);
266
+ Ok(())
267
+ }
268
+
269
+ fn compile_short_circuit_assignment_static(
270
+ &mut self,
271
+ context: &mut CompileContext,
272
+ object: &Expr,
273
+ name: String,
274
+ optional: bool,
275
+ value: &Expr,
276
+ jump_if_eval: Instruction,
277
+ ) -> MustardResult<()> {
278
+ let object_binding = self.fresh_internal_name(context, "assign_obj");
279
+ context.code.push(Instruction::DeclareName {
280
+ name: object_binding.clone(),
281
+ mutable: false,
282
+ });
283
+ self.compile_expr(context, object)?;
284
+ context
285
+ .code
286
+ .push(Instruction::InitializePattern(Pattern::Identifier {
287
+ span: SourceSpan::new(0, 0),
288
+ name: object_binding.clone(),
289
+ }));
290
+ context
291
+ .code
292
+ .push(Instruction::LoadName(object_binding.clone()));
293
+ context.code.push(Instruction::GetPropStatic {
294
+ name: name.clone(),
295
+ optional,
296
+ });
297
+ context.code.push(Instruction::Dup);
298
+ let rhs_jump = self.emit_jump(context, jump_if_eval);
299
+ context.code.push(Instruction::Pop);
300
+ let end_jump = self.emit_jump(context, Instruction::Jump(usize::MAX));
301
+ let rhs_ip = context.code.len();
302
+ self.patch_jump(context, rhs_jump, rhs_ip);
303
+ context.code.push(Instruction::Pop);
304
+ context.code.push(Instruction::Pop);
305
+ context.code.push(Instruction::LoadName(object_binding));
306
+ self.compile_expr(context, value)?;
307
+ context.code.push(Instruction::SetPropStatic { name });
308
+ let end_ip = context.code.len();
309
+ self.patch_jump(context, end_jump, end_ip);
310
+ Ok(())
311
+ }
312
+
313
+ fn compile_short_circuit_assignment_computed(
314
+ &mut self,
315
+ context: &mut CompileContext,
316
+ object: &Expr,
317
+ property: &Expr,
318
+ optional: bool,
319
+ value: &Expr,
320
+ jump_if_eval: Instruction,
321
+ ) -> MustardResult<()> {
322
+ let object_binding = self.fresh_internal_name(context, "assign_obj");
323
+ let key_binding = self.fresh_internal_name(context, "assign_key");
324
+ for name in [&object_binding, &key_binding] {
325
+ context.code.push(Instruction::DeclareName {
326
+ name: name.clone(),
327
+ mutable: false,
328
+ });
329
+ }
330
+ self.compile_expr(context, object)?;
331
+ context
332
+ .code
333
+ .push(Instruction::InitializePattern(Pattern::Identifier {
334
+ span: SourceSpan::new(0, 0),
335
+ name: object_binding.clone(),
336
+ }));
337
+ self.compile_expr(context, property)?;
338
+ context
339
+ .code
340
+ .push(Instruction::InitializePattern(Pattern::Identifier {
341
+ span: SourceSpan::new(0, 0),
342
+ name: key_binding.clone(),
343
+ }));
344
+ context
345
+ .code
346
+ .push(Instruction::LoadName(object_binding.clone()));
347
+ context
348
+ .code
349
+ .push(Instruction::LoadName(key_binding.clone()));
350
+ context.code.push(Instruction::GetPropComputed { optional });
351
+ context.code.push(Instruction::Dup);
352
+ let rhs_jump = self.emit_jump(context, jump_if_eval);
353
+ context.code.push(Instruction::Pop);
354
+ let end_jump = self.emit_jump(context, Instruction::Jump(usize::MAX));
355
+ let rhs_ip = context.code.len();
356
+ self.patch_jump(context, rhs_jump, rhs_ip);
357
+ context.code.push(Instruction::Pop);
358
+ context.code.push(Instruction::Pop);
359
+ context.code.push(Instruction::LoadName(object_binding));
360
+ context.code.push(Instruction::LoadName(key_binding));
361
+ self.compile_expr(context, value)?;
362
+ context.code.push(Instruction::SetPropComputed);
363
+ let end_ip = context.code.len();
364
+ self.patch_jump(context, end_jump, end_ip);
365
+ Ok(())
366
+ }
367
+
368
+ pub(super) fn compile_assignment(
369
+ &mut self,
370
+ context: &mut CompileContext,
371
+ target: &AssignTarget,
372
+ operator: AssignOp,
373
+ value: &Expr,
374
+ ) -> MustardResult<()> {
375
+ if matches!(
376
+ target,
377
+ AssignTarget::Array { .. } | AssignTarget::Object { .. } | AssignTarget::Default { .. }
378
+ ) {
379
+ self.compile_expr(context, value)?;
380
+ let result = self.declare_internal_binding(context, "assign_result");
381
+ self.store_internal_binding(context, &result, SourceSpan::new(0, 0));
382
+ context.code.push(Instruction::LoadName(result.clone()));
383
+ self.compile_assign_target_pattern(
384
+ context,
385
+ match target {
386
+ AssignTarget::Array { .. }
387
+ | AssignTarget::Object { .. }
388
+ | AssignTarget::Default { .. } => target,
389
+ _ => unreachable!(),
390
+ },
391
+ )?;
392
+ context.code.push(Instruction::LoadName(result));
393
+ return Ok(());
394
+ }
395
+ match target {
396
+ AssignTarget::Identifier { name, .. } => {
397
+ if operator == AssignOp::Assign {
398
+ self.compile_expr(context, value)?;
399
+ context.code.push(Instruction::StoreName(name.clone()));
400
+ } else if operator == AssignOp::OrAssign {
401
+ self.compile_short_circuit_assignment_identifier(
402
+ context,
403
+ name,
404
+ value,
405
+ Instruction::JumpIfFalse(usize::MAX),
406
+ )?;
407
+ } else if operator == AssignOp::AndAssign {
408
+ self.compile_short_circuit_assignment_identifier(
409
+ context,
410
+ name,
411
+ value,
412
+ Instruction::JumpIfTrue(usize::MAX),
413
+ )?;
414
+ } else if operator == AssignOp::NullishAssign {
415
+ self.compile_short_circuit_assignment_identifier(
416
+ context,
417
+ name,
418
+ value,
419
+ Instruction::JumpIfNullish(usize::MAX),
420
+ )?;
421
+ } else {
422
+ context.code.push(Instruction::LoadName(name.clone()));
423
+ self.compile_expr(context, value)?;
424
+ context
425
+ .code
426
+ .push(Instruction::Binary(assign_op_to_binary(operator)?));
427
+ context.code.push(Instruction::StoreName(name.clone()));
428
+ }
429
+ }
430
+ AssignTarget::Member {
431
+ object,
432
+ property,
433
+ optional,
434
+ ..
435
+ } => match property {
436
+ MemberProperty::Static(PropertyName::Identifier(name))
437
+ | MemberProperty::Static(PropertyName::String(name)) => {
438
+ if operator == AssignOp::Assign {
439
+ self.compile_expr(context, object)?;
440
+ self.compile_expr(context, value)?;
441
+ context
442
+ .code
443
+ .push(Instruction::SetPropStatic { name: name.clone() });
444
+ } else if operator == AssignOp::OrAssign {
445
+ self.compile_short_circuit_assignment_static(
446
+ context,
447
+ object,
448
+ name.clone(),
449
+ *optional,
450
+ value,
451
+ Instruction::JumpIfFalse(usize::MAX),
452
+ )?;
453
+ } else if operator == AssignOp::AndAssign {
454
+ self.compile_short_circuit_assignment_static(
455
+ context,
456
+ object,
457
+ name.clone(),
458
+ *optional,
459
+ value,
460
+ Instruction::JumpIfTrue(usize::MAX),
461
+ )?;
462
+ } else if operator == AssignOp::NullishAssign {
463
+ self.compile_short_circuit_assignment_static(
464
+ context,
465
+ object,
466
+ name.clone(),
467
+ *optional,
468
+ value,
469
+ Instruction::JumpIfNullish(usize::MAX),
470
+ )?;
471
+ } else {
472
+ self.compile_expr(context, object)?;
473
+ context.code.push(Instruction::Dup);
474
+ context.code.push(Instruction::GetPropStatic {
475
+ name: name.clone(),
476
+ optional: *optional,
477
+ });
478
+ self.compile_expr(context, value)?;
479
+ context
480
+ .code
481
+ .push(Instruction::Binary(assign_op_to_binary(operator)?));
482
+ context
483
+ .code
484
+ .push(Instruction::SetPropStatic { name: name.clone() });
485
+ }
486
+ }
487
+ MemberProperty::Static(PropertyName::Number(number)) => {
488
+ let name = format_number_key(*number);
489
+ if operator == AssignOp::Assign {
490
+ self.compile_expr(context, object)?;
491
+ self.compile_expr(context, value)?;
492
+ context.code.push(Instruction::SetPropStatic { name });
493
+ } else if operator == AssignOp::OrAssign {
494
+ self.compile_short_circuit_assignment_static(
495
+ context,
496
+ object,
497
+ name,
498
+ *optional,
499
+ value,
500
+ Instruction::JumpIfFalse(usize::MAX),
501
+ )?;
502
+ } else if operator == AssignOp::AndAssign {
503
+ self.compile_short_circuit_assignment_static(
504
+ context,
505
+ object,
506
+ name,
507
+ *optional,
508
+ value,
509
+ Instruction::JumpIfTrue(usize::MAX),
510
+ )?;
511
+ } else if operator == AssignOp::NullishAssign {
512
+ self.compile_short_circuit_assignment_static(
513
+ context,
514
+ object,
515
+ name,
516
+ *optional,
517
+ value,
518
+ Instruction::JumpIfNullish(usize::MAX),
519
+ )?;
520
+ } else {
521
+ self.compile_expr(context, object)?;
522
+ context.code.push(Instruction::Dup);
523
+ context.code.push(Instruction::GetPropStatic {
524
+ name: name.clone(),
525
+ optional: *optional,
526
+ });
527
+ self.compile_expr(context, value)?;
528
+ context
529
+ .code
530
+ .push(Instruction::Binary(assign_op_to_binary(operator)?));
531
+ context.code.push(Instruction::SetPropStatic { name });
532
+ }
533
+ }
534
+ MemberProperty::Computed(expr) => {
535
+ if operator == AssignOp::Assign {
536
+ self.compile_expr(context, object)?;
537
+ self.compile_expr(context, expr)?;
538
+ self.compile_expr(context, value)?;
539
+ context.code.push(Instruction::SetPropComputed);
540
+ } else if operator == AssignOp::OrAssign {
541
+ self.compile_short_circuit_assignment_computed(
542
+ context,
543
+ object,
544
+ expr,
545
+ *optional,
546
+ value,
547
+ Instruction::JumpIfFalse(usize::MAX),
548
+ )?;
549
+ } else if operator == AssignOp::AndAssign {
550
+ self.compile_short_circuit_assignment_computed(
551
+ context,
552
+ object,
553
+ expr,
554
+ *optional,
555
+ value,
556
+ Instruction::JumpIfTrue(usize::MAX),
557
+ )?;
558
+ } else if operator == AssignOp::NullishAssign {
559
+ self.compile_short_circuit_assignment_computed(
560
+ context,
561
+ object,
562
+ expr,
563
+ *optional,
564
+ value,
565
+ Instruction::JumpIfNullish(usize::MAX),
566
+ )?;
567
+ } else {
568
+ self.compile_expr(context, object)?;
569
+ self.compile_expr(context, expr)?;
570
+ context.code.push(Instruction::Dup2);
571
+ context.code.push(Instruction::GetPropComputed {
572
+ optional: *optional,
573
+ });
574
+ self.compile_expr(context, value)?;
575
+ context
576
+ .code
577
+ .push(Instruction::Binary(assign_op_to_binary(operator)?));
578
+ context.code.push(Instruction::SetPropComputed);
579
+ }
580
+ }
581
+ },
582
+ AssignTarget::Array { .. }
583
+ | AssignTarget::Object { .. }
584
+ | AssignTarget::Default { .. } => unreachable!(),
585
+ }
586
+ Ok(())
587
+ }
588
+
589
+ pub(super) fn compile_update(
590
+ &mut self,
591
+ context: &mut CompileContext,
592
+ target: &AssignTarget,
593
+ operator: UpdateOp,
594
+ prefix: bool,
595
+ ) -> MustardResult<()> {
596
+ match target {
597
+ AssignTarget::Identifier { name, .. } => {
598
+ context.code.push(Instruction::LoadName(name.clone()));
599
+ if !prefix {
600
+ context.code.push(Instruction::Dup);
601
+ }
602
+ context.code.push(Instruction::Update(operator));
603
+ context.code.push(Instruction::StoreName(name.clone()));
604
+ if !prefix {
605
+ context.code.push(Instruction::Pop);
606
+ }
607
+ }
608
+ AssignTarget::Member {
609
+ object,
610
+ property,
611
+ optional,
612
+ ..
613
+ } => {
614
+ let object_binding = self.declare_internal_binding(context, "update_obj");
615
+ self.compile_expr(context, object)?;
616
+ self.store_internal_binding(context, &object_binding, SourceSpan::new(0, 0));
617
+ let key_binding = if let MemberProperty::Computed(property) = property {
618
+ let key_binding = self.declare_internal_binding(context, "update_key");
619
+ self.compile_expr(context, property)?;
620
+ self.store_internal_binding(context, &key_binding, SourceSpan::new(0, 0));
621
+ Some(key_binding)
622
+ } else {
623
+ None
624
+ };
625
+ context
626
+ .code
627
+ .push(Instruction::LoadName(object_binding.clone()));
628
+ match property {
629
+ MemberProperty::Static(PropertyName::Identifier(name))
630
+ | MemberProperty::Static(PropertyName::String(name)) => {
631
+ context.code.push(Instruction::GetPropStatic {
632
+ name: name.clone(),
633
+ optional: *optional,
634
+ });
635
+ }
636
+ MemberProperty::Static(PropertyName::Number(number)) => {
637
+ context.code.push(Instruction::GetPropStatic {
638
+ name: format_number_key(*number),
639
+ optional: *optional,
640
+ });
641
+ }
642
+ MemberProperty::Computed(_) => {
643
+ context.code.push(Instruction::LoadName(
644
+ key_binding.clone().expect("computed update key missing"),
645
+ ));
646
+ context.code.push(Instruction::GetPropComputed {
647
+ optional: *optional,
648
+ });
649
+ }
650
+ }
651
+ if !prefix {
652
+ context.code.push(Instruction::Dup);
653
+ }
654
+ context.code.push(Instruction::Update(operator));
655
+ let value_binding = self.declare_internal_binding(context, "update_value");
656
+ self.store_internal_binding(context, &value_binding, SourceSpan::new(0, 0));
657
+ context.code.push(Instruction::LoadName(object_binding));
658
+ match property {
659
+ MemberProperty::Static(PropertyName::Identifier(name))
660
+ | MemberProperty::Static(PropertyName::String(name)) => {
661
+ context.code.push(Instruction::LoadName(value_binding));
662
+ context
663
+ .code
664
+ .push(Instruction::SetPropStatic { name: name.clone() });
665
+ }
666
+ MemberProperty::Static(PropertyName::Number(number)) => {
667
+ context.code.push(Instruction::LoadName(value_binding));
668
+ context.code.push(Instruction::SetPropStatic {
669
+ name: format_number_key(*number),
670
+ });
671
+ }
672
+ MemberProperty::Computed(_) => {
673
+ context.code.push(Instruction::LoadName(
674
+ key_binding.expect("computed update key missing"),
675
+ ));
676
+ context.code.push(Instruction::LoadName(value_binding));
677
+ context.code.push(Instruction::SetPropComputed);
678
+ }
679
+ }
680
+ if !prefix {
681
+ context.code.push(Instruction::Pop);
682
+ }
683
+ }
684
+ AssignTarget::Array { .. }
685
+ | AssignTarget::Object { .. }
686
+ | AssignTarget::Default { .. } => unreachable!(),
687
+ }
688
+ Ok(())
689
+ }
690
+ }