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,1016 @@
1
+ use super::*;
2
+ use num_bigint::BigInt;
3
+
4
+ impl Runtime {
5
+ pub(super) fn run_root(&mut self) -> MustardResult<ExecutionStep> {
6
+ self.check_cancellation()?;
7
+ self.collect_garbage()?;
8
+ self.check_call_depth()?;
9
+ let root_env = self.new_env(Some(self.globals))?;
10
+ self.push_frame(
11
+ self.program.root,
12
+ root_env,
13
+ &[],
14
+ Value::Object(
15
+ self.global_object_key()
16
+ .ok_or_else(|| MustardError::runtime("missing global object"))?,
17
+ ),
18
+ None,
19
+ )?;
20
+ self.run()
21
+ }
22
+
23
+ pub(super) fn step_active_frame(&mut self) -> MustardResult<StepAction> {
24
+ let frame_index = self
25
+ .frames
26
+ .len()
27
+ .checked_sub(1)
28
+ .ok_or_else(|| MustardError::runtime("vm lost all frames"))?;
29
+ let function_id = self.frames[frame_index].function_id;
30
+ let ip = self.frames[frame_index].ip;
31
+ let instruction = self
32
+ .program
33
+ .functions
34
+ .get(function_id)
35
+ .and_then(|function| function.code.get(ip))
36
+ .cloned()
37
+ .ok_or_else(|| MustardError::runtime("instruction pointer out of range"))?;
38
+ self.frames[frame_index].ip += 1;
39
+ self.bump_instruction_budget()?;
40
+ self.collect_garbage_before_instruction(&instruction)?;
41
+ match instruction {
42
+ Instruction::PushUndefined => {
43
+ self.frames[frame_index].stack.push(Value::Undefined);
44
+ }
45
+ Instruction::PushNull => self.frames[frame_index].stack.push(Value::Null),
46
+ Instruction::PushBool(value) => self.frames[frame_index].stack.push(Value::Bool(value)),
47
+ Instruction::PushNumber(value) => {
48
+ self.frames[frame_index].stack.push(Value::Number(value))
49
+ }
50
+ Instruction::PushBigInt(value) => {
51
+ let value = BigInt::parse_bytes(value.as_bytes(), 10)
52
+ .ok_or_else(|| MustardError::runtime("invalid BigInt literal in bytecode"))?;
53
+ self.frames[frame_index].stack.push(Value::BigInt(value));
54
+ }
55
+ Instruction::PushString(value) => {
56
+ self.frames[frame_index].stack.push(Value::String(value))
57
+ }
58
+ Instruction::PushRegExp { pattern, flags } => {
59
+ let value = self.make_regexp_value(pattern, flags)?;
60
+ self.frames[frame_index].stack.push(value);
61
+ }
62
+ Instruction::LoadName(name) => {
63
+ let env = self.frames[frame_index].env;
64
+ let value = self.lookup_name(env, &name)?;
65
+ self.frames[frame_index].stack.push(value);
66
+ }
67
+ Instruction::LoadGlobalObject => {
68
+ let value = Value::Object(
69
+ self.global_object_key()
70
+ .ok_or_else(|| MustardError::runtime("missing global object"))?,
71
+ );
72
+ self.frames[frame_index].stack.push(value);
73
+ }
74
+ Instruction::StoreName(name) => {
75
+ let value = self.frames[frame_index]
76
+ .stack
77
+ .pop()
78
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
79
+ let env = self.frames[frame_index].env;
80
+ self.assign_name(env, &name, value.clone())?;
81
+ self.frames[frame_index].stack.push(value);
82
+ }
83
+ Instruction::InitializePattern(pattern) => {
84
+ let value = self.frames[frame_index]
85
+ .stack
86
+ .pop()
87
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
88
+ let env = self.frames[frame_index].env;
89
+ self.initialize_pattern(env, &pattern, value)?;
90
+ }
91
+ Instruction::PushEnv => {
92
+ let current_env = self.frames[frame_index].env;
93
+ let env = self.new_env(Some(current_env))?;
94
+ self.frames[frame_index].scope_stack.push(current_env);
95
+ self.frames[frame_index].env = env;
96
+ }
97
+ Instruction::PopEnv => {
98
+ let restored = self.frames[frame_index]
99
+ .scope_stack
100
+ .pop()
101
+ .ok_or_else(|| MustardError::runtime("scope stack underflow"))?;
102
+ self.frames[frame_index].env = restored;
103
+ }
104
+ Instruction::DeclareName { name, mutable } => {
105
+ let env = self.frames[frame_index].env;
106
+ self.declare_name(env, name, mutable)?;
107
+ }
108
+ Instruction::MakeClosure { function_id } => {
109
+ let env = self.frames[frame_index].env;
110
+ let this_value = self.lookup_name(env, "this").unwrap_or(Value::Undefined);
111
+ let closure = self.insert_closure(function_id, env, this_value)?;
112
+ self.frames[frame_index].stack.push(Value::Closure(closure));
113
+ }
114
+ Instruction::MakeArray { count } => {
115
+ let values = pop_many(&mut self.frames[frame_index].stack, count)?;
116
+ let array = self.insert_array(values, IndexMap::new())?;
117
+ self.frames[frame_index].stack.push(Value::Array(array));
118
+ }
119
+ Instruction::ArrayPush => {
120
+ let value = self.frames[frame_index]
121
+ .stack
122
+ .pop()
123
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
124
+ let target = self.frames[frame_index]
125
+ .stack
126
+ .pop()
127
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
128
+ let Value::Array(array) = target else {
129
+ return Err(MustardError::runtime(
130
+ "array builder target is not an array",
131
+ ));
132
+ };
133
+ self.arrays
134
+ .get_mut(array)
135
+ .ok_or_else(|| MustardError::runtime("array missing"))?
136
+ .elements
137
+ .push(Some(value));
138
+ self.refresh_array_accounting(array)?;
139
+ self.frames[frame_index].stack.push(Value::Array(array));
140
+ }
141
+ Instruction::ArrayPushHole => {
142
+ let target = self.frames[frame_index]
143
+ .stack
144
+ .pop()
145
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
146
+ let Value::Array(array) = target else {
147
+ return Err(MustardError::runtime(
148
+ "array builder target is not an array",
149
+ ));
150
+ };
151
+ self.arrays
152
+ .get_mut(array)
153
+ .ok_or_else(|| MustardError::runtime("array missing"))?
154
+ .elements
155
+ .push(None);
156
+ self.refresh_array_accounting(array)?;
157
+ self.frames[frame_index].stack.push(Value::Array(array));
158
+ }
159
+ Instruction::ArrayExtend => {
160
+ let iterable = self.frames[frame_index]
161
+ .stack
162
+ .pop()
163
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
164
+ let target = self.frames[frame_index]
165
+ .stack
166
+ .pop()
167
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
168
+ let target = self.expand_iterable_into_array(target, iterable)?;
169
+ self.frames[frame_index].stack.push(target);
170
+ }
171
+ Instruction::MakeObject { keys } => {
172
+ let values = pop_many(&mut self.frames[frame_index].stack, keys.len())?;
173
+ let mut properties = IndexMap::new();
174
+ for (key, value) in keys.into_iter().zip(values.into_iter()) {
175
+ properties.insert(property_name_to_key(&key), value);
176
+ }
177
+ let object = self.insert_object(properties, ObjectKind::Plain)?;
178
+ self.frames[frame_index].stack.push(Value::Object(object));
179
+ }
180
+ Instruction::CopyDataProperties => {
181
+ let source = self.frames[frame_index]
182
+ .stack
183
+ .pop()
184
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
185
+ let target = self.frames[frame_index]
186
+ .stack
187
+ .pop()
188
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
189
+ self.copy_data_properties(target.clone(), source)?;
190
+ self.frames[frame_index].stack.push(target);
191
+ }
192
+ Instruction::CreateIterator => {
193
+ let iterable = self.frames[frame_index]
194
+ .stack
195
+ .pop()
196
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
197
+ let iterator = self.create_iterator(iterable)?;
198
+ self.frames[frame_index].stack.push(iterator);
199
+ }
200
+ Instruction::IteratorNext => {
201
+ let iterator = self.frames[frame_index]
202
+ .stack
203
+ .pop()
204
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
205
+ let (value, done) = self.iterator_next(iterator)?;
206
+ self.frames[frame_index].stack.push(value);
207
+ self.frames[frame_index].stack.push(Value::Bool(done));
208
+ }
209
+ Instruction::GetPropStatic { name, optional } => {
210
+ let object = self.frames[frame_index]
211
+ .stack
212
+ .pop()
213
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
214
+ let value = self.get_property(object, Value::String(name), optional)?;
215
+ self.frames[frame_index].stack.push(value);
216
+ }
217
+ Instruction::GetPropComputed { optional } => {
218
+ let property = self.frames[frame_index]
219
+ .stack
220
+ .pop()
221
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
222
+ let object = self.frames[frame_index]
223
+ .stack
224
+ .pop()
225
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
226
+ let value = self.get_property(object, property, optional)?;
227
+ self.frames[frame_index].stack.push(value);
228
+ }
229
+ Instruction::SetPropStatic { name } => {
230
+ let value = self.frames[frame_index]
231
+ .stack
232
+ .pop()
233
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
234
+ let object = self.frames[frame_index]
235
+ .stack
236
+ .pop()
237
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
238
+ self.set_property(object, Value::String(name), value.clone())?;
239
+ self.frames[frame_index].stack.push(value);
240
+ }
241
+ Instruction::SetPropComputed => {
242
+ let value = self.frames[frame_index]
243
+ .stack
244
+ .pop()
245
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
246
+ let property = self.frames[frame_index]
247
+ .stack
248
+ .pop()
249
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
250
+ let object = self.frames[frame_index]
251
+ .stack
252
+ .pop()
253
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
254
+ self.set_property(object, property, value.clone())?;
255
+ self.frames[frame_index].stack.push(value);
256
+ }
257
+ Instruction::Unary(operator) => {
258
+ let value = self.frames[frame_index]
259
+ .stack
260
+ .pop()
261
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
262
+ let result = self.apply_unary(operator, value)?;
263
+ self.frames[frame_index].stack.push(result);
264
+ }
265
+ Instruction::Binary(operator) => {
266
+ let right = self.frames[frame_index]
267
+ .stack
268
+ .pop()
269
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
270
+ let left = self.frames[frame_index]
271
+ .stack
272
+ .pop()
273
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
274
+ let result = self.apply_binary(operator, left, right)?;
275
+ self.frames[frame_index].stack.push(result);
276
+ }
277
+ Instruction::Update(operator) => {
278
+ let value = self.frames[frame_index]
279
+ .stack
280
+ .pop()
281
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
282
+ let result = self.apply_update(operator, value)?;
283
+ self.frames[frame_index].stack.push(result);
284
+ }
285
+ Instruction::PatternArrayIndex(index) => {
286
+ let value = self.frames[frame_index]
287
+ .stack
288
+ .pop()
289
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
290
+ let result = self.pattern_array_index(value, index)?;
291
+ self.frames[frame_index].stack.push(result);
292
+ }
293
+ Instruction::PatternArrayRest(start) => {
294
+ let value = self.frames[frame_index]
295
+ .stack
296
+ .pop()
297
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
298
+ let result = self.pattern_array_rest(value, start)?;
299
+ self.frames[frame_index].stack.push(result);
300
+ }
301
+ Instruction::PatternObjectRest(excluded) => {
302
+ let value = self.frames[frame_index]
303
+ .stack
304
+ .pop()
305
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
306
+ let result = self.pattern_object_rest(value, &excluded)?;
307
+ self.frames[frame_index].stack.push(result);
308
+ }
309
+ Instruction::Pop => {
310
+ self.frames[frame_index].stack.pop();
311
+ }
312
+ Instruction::Dup => {
313
+ let value = self.frames[frame_index]
314
+ .stack
315
+ .last()
316
+ .cloned()
317
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
318
+ self.frames[frame_index].stack.push(value);
319
+ }
320
+ Instruction::Dup2 => {
321
+ let len = self.frames[frame_index].stack.len();
322
+ if len < 2 {
323
+ return Err(MustardError::runtime("stack underflow"));
324
+ }
325
+ let a = self.frames[frame_index].stack[len - 2].clone();
326
+ let b = self.frames[frame_index].stack[len - 1].clone();
327
+ self.frames[frame_index].stack.push(a);
328
+ self.frames[frame_index].stack.push(b);
329
+ }
330
+ Instruction::PushHandler { catch, finally } => {
331
+ let frame = &mut self.frames[frame_index];
332
+ frame.handlers.push(ExceptionHandler {
333
+ catch,
334
+ finally,
335
+ env: frame.env,
336
+ scope_stack_len: frame.scope_stack.len(),
337
+ stack_len: frame.stack.len(),
338
+ });
339
+ }
340
+ Instruction::PopHandler => {
341
+ self.frames[frame_index]
342
+ .handlers
343
+ .pop()
344
+ .ok_or_else(|| MustardError::runtime("handler stack underflow"))?;
345
+ }
346
+ Instruction::EnterFinally { exit } => {
347
+ let completion_index = self.frames[frame_index]
348
+ .pending_completions
349
+ .len()
350
+ .checked_sub(1)
351
+ .ok_or_else(|| MustardError::runtime("missing pending completion"))?;
352
+ self.frames[frame_index]
353
+ .active_finally
354
+ .push(ActiveFinallyState {
355
+ completion_index,
356
+ exit,
357
+ });
358
+ }
359
+ Instruction::BeginCatch => {
360
+ let value = self.frames[frame_index]
361
+ .pending_exception
362
+ .take()
363
+ .ok_or_else(|| MustardError::runtime("missing pending exception"))?;
364
+ self.frames[frame_index].stack.push(value);
365
+ }
366
+ Instruction::Throw { span } => {
367
+ let value = self.frames[frame_index]
368
+ .stack
369
+ .pop()
370
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
371
+ return self.raise_exception(value, Some(span));
372
+ }
373
+ Instruction::PushPendingJump {
374
+ target,
375
+ target_handler_depth,
376
+ target_scope_depth,
377
+ } => {
378
+ self.store_completion(
379
+ frame_index,
380
+ CompletionRecord::Jump {
381
+ target,
382
+ target_handler_depth,
383
+ target_scope_depth,
384
+ },
385
+ )?;
386
+ }
387
+ Instruction::PushPendingReturn => {
388
+ let value = self.frames[frame_index]
389
+ .stack
390
+ .pop()
391
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
392
+ self.store_completion(frame_index, CompletionRecord::Return(value))?;
393
+ }
394
+ Instruction::PushPendingThrow => {
395
+ let value = self.frames[frame_index]
396
+ .stack
397
+ .pop()
398
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
399
+ self.store_completion(frame_index, CompletionRecord::Throw(value))?;
400
+ }
401
+ Instruction::ContinuePending => {
402
+ let marker = self.frames[frame_index]
403
+ .active_finally
404
+ .pop()
405
+ .ok_or_else(|| MustardError::runtime("missing active finally state"))?;
406
+ if marker.completion_index >= self.frames[frame_index].pending_completions.len() {
407
+ return Err(MustardError::runtime(
408
+ "active finally references missing completion",
409
+ ));
410
+ }
411
+ let completion = self.frames[frame_index]
412
+ .pending_completions
413
+ .remove(marker.completion_index);
414
+ return self.resume_completion(completion);
415
+ }
416
+ Instruction::Jump(target) => self.frames[frame_index].ip = target,
417
+ Instruction::JumpIfFalse(target) => {
418
+ let value = self.frames[frame_index]
419
+ .stack
420
+ .last()
421
+ .cloned()
422
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
423
+ if !is_truthy(&value) {
424
+ self.frames[frame_index].ip = target;
425
+ }
426
+ }
427
+ Instruction::JumpIfTrue(target) => {
428
+ let value = self.frames[frame_index]
429
+ .stack
430
+ .last()
431
+ .cloned()
432
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
433
+ if is_truthy(&value) {
434
+ self.frames[frame_index].ip = target;
435
+ }
436
+ }
437
+ Instruction::JumpIfNullish(target) => {
438
+ let value = self.frames[frame_index]
439
+ .stack
440
+ .last()
441
+ .cloned()
442
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
443
+ if matches!(value, Value::Null | Value::Undefined) {
444
+ self.frames[frame_index].ip = target;
445
+ }
446
+ }
447
+ Instruction::Call {
448
+ argc,
449
+ with_this,
450
+ optional,
451
+ } => {
452
+ let args = pop_many(&mut self.frames[frame_index].stack, argc)?;
453
+ let callee = self.frames[frame_index]
454
+ .stack
455
+ .pop()
456
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
457
+ let this_value = if with_this {
458
+ self.frames[frame_index]
459
+ .stack
460
+ .pop()
461
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?
462
+ } else {
463
+ Value::Undefined
464
+ };
465
+ if optional && matches!(callee, Value::Undefined | Value::Null) {
466
+ self.frames[frame_index].stack.push(Value::Undefined);
467
+ return Ok(StepAction::Continue);
468
+ }
469
+ match self.call_callable(callee, this_value, &args)? {
470
+ RunState::Completed(value) => {
471
+ self.frames[frame_index].stack.push(value);
472
+ }
473
+ RunState::PushedFrame => {}
474
+ RunState::StartedAsync(value) => {
475
+ self.frames[frame_index].stack.push(value);
476
+ }
477
+ RunState::Suspended {
478
+ capability,
479
+ args,
480
+ resume_behavior,
481
+ } => {
482
+ self.pending_resume_behavior = resume_behavior;
483
+ self.suspended_host_call = Some(PendingHostCall {
484
+ capability: capability.clone(),
485
+ args: args.clone(),
486
+ promise: None,
487
+ resume_behavior,
488
+ traceback: self.traceback_snapshots(),
489
+ });
490
+ self.snapshot_nonce = next_snapshot_nonce();
491
+ return Ok(StepAction::Return(ExecutionStep::Suspended(Box::new(
492
+ Suspension {
493
+ capability,
494
+ args,
495
+ snapshot: ExecutionSnapshot {
496
+ runtime: self.clone(),
497
+ },
498
+ },
499
+ ))));
500
+ }
501
+ }
502
+ }
503
+ Instruction::Await => {
504
+ let value = self.frames[frame_index]
505
+ .stack
506
+ .pop()
507
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
508
+ self.suspend_async_await(value)?;
509
+ }
510
+ Instruction::CallWithArray {
511
+ with_this,
512
+ optional,
513
+ } => {
514
+ let args = self.pop_argument_array(frame_index)?;
515
+ let callee = self.frames[frame_index]
516
+ .stack
517
+ .pop()
518
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
519
+ let this_value = if with_this {
520
+ self.frames[frame_index]
521
+ .stack
522
+ .pop()
523
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?
524
+ } else {
525
+ Value::Undefined
526
+ };
527
+ if optional && matches!(callee, Value::Undefined | Value::Null) {
528
+ self.frames[frame_index].stack.push(Value::Undefined);
529
+ return Ok(StepAction::Continue);
530
+ }
531
+ match self.call_callable(callee, this_value, &args)? {
532
+ RunState::Completed(value) => {
533
+ self.frames[frame_index].stack.push(value);
534
+ }
535
+ RunState::PushedFrame => {}
536
+ RunState::StartedAsync(value) => {
537
+ self.frames[frame_index].stack.push(value);
538
+ }
539
+ RunState::Suspended {
540
+ capability,
541
+ args,
542
+ resume_behavior,
543
+ } => {
544
+ self.pending_resume_behavior = resume_behavior;
545
+ self.suspended_host_call = Some(PendingHostCall {
546
+ capability: capability.clone(),
547
+ args: args.clone(),
548
+ promise: None,
549
+ resume_behavior,
550
+ traceback: self.traceback_snapshots(),
551
+ });
552
+ self.snapshot_nonce = next_snapshot_nonce();
553
+ return Ok(StepAction::Return(ExecutionStep::Suspended(Box::new(
554
+ Suspension {
555
+ capability,
556
+ args,
557
+ snapshot: ExecutionSnapshot {
558
+ runtime: self.clone(),
559
+ },
560
+ },
561
+ ))));
562
+ }
563
+ }
564
+ }
565
+ Instruction::Construct { argc } => {
566
+ let args = pop_many(&mut self.frames[frame_index].stack, argc)?;
567
+ let callee = self.frames[frame_index]
568
+ .stack
569
+ .pop()
570
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
571
+ let value = self.construct(callee, &args)?;
572
+ self.frames[frame_index].stack.push(value);
573
+ }
574
+ Instruction::ConstructWithArray => {
575
+ let args = self.pop_argument_array(frame_index)?;
576
+ let callee = self.frames[frame_index]
577
+ .stack
578
+ .pop()
579
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
580
+ let value = self.construct(callee, &args)?;
581
+ self.frames[frame_index].stack.push(value);
582
+ }
583
+ Instruction::Return => {
584
+ let value = self.frames[frame_index]
585
+ .stack
586
+ .pop()
587
+ .unwrap_or(Value::Undefined);
588
+ return self.complete_return(value);
589
+ }
590
+ }
591
+ Ok(StepAction::Continue)
592
+ }
593
+
594
+ pub(super) fn run(&mut self) -> MustardResult<ExecutionStep> {
595
+ loop {
596
+ self.check_cancellation()
597
+ .map_err(|error| self.annotate_runtime_error(error))?;
598
+ if self.frames.is_empty() {
599
+ match self.process_idle_state() {
600
+ Ok(Some(step)) => return Ok(step),
601
+ Ok(None) => continue,
602
+ Err(error) => return Err(self.annotate_runtime_error(error)),
603
+ }
604
+ }
605
+ let action = match self.step_active_frame() {
606
+ Ok(action) => action,
607
+ Err(error) => match self.handle_runtime_fault(error) {
608
+ Ok(action) => action,
609
+ Err(error) => return Err(self.annotate_runtime_error(error)),
610
+ },
611
+ };
612
+
613
+ match action {
614
+ StepAction::Continue => {}
615
+ StepAction::Return(step) => return Ok(step),
616
+ }
617
+ }
618
+ }
619
+
620
+ pub(super) fn run_until_frame_depth(
621
+ &mut self,
622
+ target_depth: usize,
623
+ host_suspension_message: &str,
624
+ ) -> MustardResult<()> {
625
+ while self.frames.len() > target_depth {
626
+ self.check_cancellation()?;
627
+ let action = match self.step_active_frame() {
628
+ Ok(action) => action,
629
+ Err(error) => self.handle_runtime_fault(error)?,
630
+ };
631
+ match action {
632
+ StepAction::Continue => {}
633
+ StepAction::Return(ExecutionStep::Suspended(_)) => {
634
+ return Err(MustardError::runtime(host_suspension_message));
635
+ }
636
+ StepAction::Return(ExecutionStep::Completed(_)) => {
637
+ return Err(MustardError::runtime(
638
+ "nested callback execution unexpectedly completed the program",
639
+ ));
640
+ }
641
+ }
642
+ }
643
+ Ok(())
644
+ }
645
+
646
+ pub(super) fn check_call_depth(&self) -> MustardResult<()> {
647
+ if self.frames.len() >= self.limits.call_depth_limit {
648
+ return Err(limit_error("call depth limit exceeded"));
649
+ }
650
+ Ok(())
651
+ }
652
+
653
+ pub(super) fn push_frame(
654
+ &mut self,
655
+ function_id: usize,
656
+ env: EnvKey,
657
+ args: &[Value],
658
+ this_value: Value,
659
+ async_promise: Option<PromiseKey>,
660
+ ) -> MustardResult<()> {
661
+ self.check_call_depth()?;
662
+ let (params, rest) = self
663
+ .program
664
+ .functions
665
+ .get(function_id)
666
+ .map(|function| (function.params.clone(), function.rest.clone()))
667
+ .ok_or_else(|| MustardError::runtime("function not found"))?;
668
+ let this_cell = self.insert_cell(this_value, true, true)?;
669
+ self.envs
670
+ .get_mut(env)
671
+ .ok_or_else(|| MustardError::runtime("environment missing"))?
672
+ .bindings
673
+ .insert("this".to_string(), this_cell);
674
+ self.refresh_env_accounting(env)?;
675
+ for pattern in &params {
676
+ for (name, _) in pattern_bindings(pattern) {
677
+ self.declare_name(env, name, true)?;
678
+ }
679
+ }
680
+ for (index, pattern) in params.iter().enumerate() {
681
+ let arg = args.get(index).cloned().unwrap_or(Value::Undefined);
682
+ self.initialize_pattern(env, pattern, arg)?;
683
+ }
684
+ if let Some(rest) = &rest {
685
+ for (name, _) in pattern_bindings(rest) {
686
+ self.declare_name(env, name, true)?;
687
+ }
688
+ let rest_array = self.insert_array(
689
+ args.iter().skip(params.len()).cloned().collect(),
690
+ IndexMap::new(),
691
+ )?;
692
+ self.initialize_pattern(env, rest, Value::Array(rest_array))?;
693
+ }
694
+ self.frames.push(Frame {
695
+ function_id,
696
+ ip: 0,
697
+ env,
698
+ scope_stack: Vec::new(),
699
+ stack: Vec::new(),
700
+ handlers: Vec::new(),
701
+ pending_exception: None,
702
+ pending_completions: Vec::new(),
703
+ active_finally: Vec::new(),
704
+ async_promise,
705
+ });
706
+ Ok(())
707
+ }
708
+
709
+ pub(super) fn call_callable(
710
+ &mut self,
711
+ callee: Value,
712
+ this_value: Value,
713
+ args: &[Value],
714
+ ) -> MustardResult<RunState> {
715
+ match callee {
716
+ Value::Closure(closure) => {
717
+ let closure = self
718
+ .closures
719
+ .get(closure)
720
+ .cloned()
721
+ .ok_or_else(|| MustardError::runtime("closure not found"))?;
722
+ let env = self.new_env(Some(closure.env))?;
723
+ let (is_async, is_arrow) = self
724
+ .program
725
+ .functions
726
+ .get(closure.function_id)
727
+ .map(|function| (function.is_async, function.is_arrow))
728
+ .ok_or_else(|| MustardError::runtime("function not found"))?;
729
+ let frame_this = if is_arrow {
730
+ closure.this_value.clone()
731
+ } else {
732
+ this_value
733
+ };
734
+ if is_async {
735
+ let promise = self.insert_promise(PromiseState::Pending)?;
736
+ self.push_frame(closure.function_id, env, args, frame_this, Some(promise))?;
737
+ Ok(RunState::StartedAsync(Value::Promise(promise)))
738
+ } else {
739
+ self.push_frame(closure.function_id, env, args, frame_this, None)?;
740
+ Ok(RunState::PushedFrame)
741
+ }
742
+ }
743
+ Value::BuiltinFunction(function) => match function {
744
+ BuiltinFunction::FunctionCall => self.call_function_call(this_value, args),
745
+ BuiltinFunction::FunctionApply => self.call_function_apply(this_value, args),
746
+ BuiltinFunction::FunctionBind => Ok(RunState::Completed(
747
+ self.call_function_bind(this_value, args)?,
748
+ )),
749
+ _ => Ok(RunState::Completed(
750
+ self.call_builtin(function, this_value, args)?,
751
+ )),
752
+ },
753
+ Value::Object(object)
754
+ if self
755
+ .objects
756
+ .get(object)
757
+ .is_some_and(|object| matches!(object.kind, ObjectKind::BoundFunction(_))) =>
758
+ {
759
+ let bound = match &self
760
+ .objects
761
+ .get(object)
762
+ .ok_or_else(|| MustardError::runtime("object missing"))?
763
+ .kind
764
+ {
765
+ ObjectKind::BoundFunction(bound) => bound.clone(),
766
+ _ => unreachable!(),
767
+ };
768
+ let mut combined = bound.args;
769
+ combined.extend(args.iter().cloned());
770
+ self.call_callable(bound.target, bound.this_value, &combined)
771
+ }
772
+ Value::HostFunction(capability) => {
773
+ let resume_behavior = resume_behavior_for_capability(&capability);
774
+ let args = args
775
+ .iter()
776
+ .cloned()
777
+ .map(|value| self.value_to_structured(value))
778
+ .collect::<MustardResult<Vec<_>>>()?;
779
+ if self.current_async_boundary_index().is_some() {
780
+ let outstanding = self.pending_host_calls.len()
781
+ + usize::from(self.suspended_host_call.is_some());
782
+ if outstanding >= self.limits.max_outstanding_host_calls {
783
+ return Err(limit_error("outstanding host-call limit exhausted"));
784
+ }
785
+ let promise = self.insert_promise(PromiseState::Pending)?;
786
+ self.pending_host_calls.push_back(PendingHostCall {
787
+ capability,
788
+ args,
789
+ promise: Some(promise),
790
+ resume_behavior,
791
+ traceback: self.traceback_snapshots(),
792
+ });
793
+ Ok(RunState::Completed(Value::Promise(promise)))
794
+ } else {
795
+ Ok(RunState::Suspended {
796
+ resume_behavior,
797
+ capability,
798
+ args,
799
+ })
800
+ }
801
+ }
802
+ _ => Err(MustardError::runtime("value is not callable")),
803
+ }
804
+ }
805
+
806
+ fn call_function_call(&mut self, target: Value, args: &[Value]) -> MustardResult<RunState> {
807
+ if !self.is_callable_value(&target)? {
808
+ return Err(MustardError::runtime(
809
+ "TypeError: Function.prototype.call called on incompatible receiver",
810
+ ));
811
+ }
812
+ let this_arg = args.first().cloned().unwrap_or(Value::Undefined);
813
+ self.call_callable(target, this_arg, &args[1..])
814
+ }
815
+
816
+ fn call_function_apply(&mut self, target: Value, args: &[Value]) -> MustardResult<RunState> {
817
+ if !self.is_callable_value(&target)? {
818
+ return Err(MustardError::runtime(
819
+ "TypeError: Function.prototype.apply called on incompatible receiver",
820
+ ));
821
+ }
822
+ let this_arg = args.first().cloned().unwrap_or(Value::Undefined);
823
+ let arg_list = match args.get(1).cloned().unwrap_or(Value::Undefined) {
824
+ Value::Undefined | Value::Null => Vec::new(),
825
+ Value::Array(array) => self.array_argument_values(Value::Array(array))?,
826
+ _ => {
827
+ return Err(MustardError::runtime(
828
+ "TypeError: Function.prototype.apply expects an array or undefined argument list in the supported surface",
829
+ ));
830
+ }
831
+ };
832
+ self.call_callable(target, this_arg, &arg_list)
833
+ }
834
+
835
+ fn call_function_bind(&mut self, target: Value, args: &[Value]) -> MustardResult<Value> {
836
+ if !self.is_callable_value(&target)? {
837
+ return Err(MustardError::runtime(
838
+ "TypeError: Function.prototype.bind called on incompatible receiver",
839
+ ));
840
+ }
841
+ let bound_this = args.first().cloned().unwrap_or(Value::Undefined);
842
+ let bound_args = args.iter().skip(1).cloned().collect();
843
+ Ok(Value::Object(self.insert_object(
844
+ IndexMap::new(),
845
+ ObjectKind::BoundFunction(BoundFunctionData {
846
+ target,
847
+ this_value: bound_this,
848
+ args: bound_args,
849
+ }),
850
+ )?))
851
+ }
852
+
853
+ fn is_callable_value(&self, value: &Value) -> MustardResult<bool> {
854
+ Ok(match value {
855
+ Value::Closure(_) | Value::BuiltinFunction(_) | Value::HostFunction(_) => true,
856
+ Value::Object(object) => matches!(
857
+ self.objects
858
+ .get(*object)
859
+ .ok_or_else(|| MustardError::runtime("object missing"))?
860
+ .kind,
861
+ ObjectKind::BoundFunction(_)
862
+ ),
863
+ _ => false,
864
+ })
865
+ }
866
+
867
+ pub(super) fn construct(&mut self, callee: Value, args: &[Value]) -> MustardResult<Value> {
868
+ match callee {
869
+ Value::BuiltinFunction(
870
+ BuiltinFunction::FunctionCtor
871
+ | BuiltinFunction::ArrayCtor
872
+ | BuiltinFunction::DateCtor
873
+ | BuiltinFunction::ObjectCtor
874
+ | BuiltinFunction::MapCtor
875
+ | BuiltinFunction::SetCtor
876
+ | BuiltinFunction::PromiseCtor
877
+ | BuiltinFunction::RegExpCtor
878
+ | BuiltinFunction::ErrorCtor
879
+ | BuiltinFunction::TypeErrorCtor
880
+ | BuiltinFunction::ReferenceErrorCtor
881
+ | BuiltinFunction::RangeErrorCtor
882
+ | BuiltinFunction::SyntaxErrorCtor
883
+ | BuiltinFunction::NumberCtor
884
+ | BuiltinFunction::StringCtor
885
+ | BuiltinFunction::BooleanCtor
886
+ | BuiltinFunction::IntlDateTimeFormatCtor
887
+ | BuiltinFunction::IntlNumberFormatCtor,
888
+ ) => match callee {
889
+ Value::BuiltinFunction(BuiltinFunction::FunctionCtor) => {
890
+ Err(MustardError::runtime(
891
+ "TypeError: Function constructor is unavailable in the supported surface",
892
+ ))
893
+ }
894
+ Value::BuiltinFunction(BuiltinFunction::MapCtor) => self.construct_map(args),
895
+ Value::BuiltinFunction(BuiltinFunction::SetCtor) => self.construct_set(args),
896
+ Value::BuiltinFunction(BuiltinFunction::DateCtor) => self.construct_date(args),
897
+ Value::BuiltinFunction(BuiltinFunction::PromiseCtor) => {
898
+ self.construct_promise(args)
899
+ }
900
+ Value::BuiltinFunction(BuiltinFunction::RegExpCtor) => self.construct_regexp(args),
901
+ Value::BuiltinFunction(BuiltinFunction::NumberCtor) => self.construct_number(args),
902
+ Value::BuiltinFunction(BuiltinFunction::StringCtor) => self.construct_string(args),
903
+ Value::BuiltinFunction(BuiltinFunction::BooleanCtor) => {
904
+ self.construct_boolean(args)
905
+ }
906
+ Value::BuiltinFunction(BuiltinFunction::IntlDateTimeFormatCtor) => {
907
+ self.construct_intl_date_time_format(args)
908
+ }
909
+ Value::BuiltinFunction(BuiltinFunction::IntlNumberFormatCtor) => {
910
+ self.construct_intl_number_format(args)
911
+ }
912
+ Value::BuiltinFunction(kind) => self.call_builtin(kind, Value::Undefined, args),
913
+ _ => unreachable!(),
914
+ },
915
+ _ => Err(MustardError::runtime(
916
+ "only conservative built-in constructors are supported in v1",
917
+ )),
918
+ }
919
+ }
920
+
921
+ fn pop_argument_array(&mut self, frame_index: usize) -> MustardResult<Vec<Value>> {
922
+ let args = self.frames[frame_index]
923
+ .stack
924
+ .pop()
925
+ .ok_or_else(|| MustardError::runtime("stack underflow"))?;
926
+ self.array_argument_values(args)
927
+ }
928
+
929
+ fn array_argument_values(&self, value: Value) -> MustardResult<Vec<Value>> {
930
+ let Value::Array(array) = value else {
931
+ return Err(MustardError::runtime(
932
+ "argument builder target is not an array",
933
+ ));
934
+ };
935
+ let elements = &self
936
+ .arrays
937
+ .get(array)
938
+ .ok_or_else(|| MustardError::runtime("array missing"))?
939
+ .elements;
940
+ Ok(elements
941
+ .iter()
942
+ .map(|value| value.clone().unwrap_or(Value::Undefined))
943
+ .collect())
944
+ }
945
+
946
+ fn expand_iterable_into_array(
947
+ &mut self,
948
+ target: Value,
949
+ iterable: Value,
950
+ ) -> MustardResult<Value> {
951
+ let Value::Array(array) = target else {
952
+ return Err(MustardError::runtime(
953
+ "array builder target is not an array",
954
+ ));
955
+ };
956
+ self.with_temporary_roots(&[Value::Array(array), iterable.clone()], |runtime| {
957
+ let iterator = runtime.create_iterator(iterable.clone())?;
958
+ runtime.with_temporary_roots(
959
+ &[Value::Array(array), iterable, iterator.clone()],
960
+ |runtime| {
961
+ loop {
962
+ runtime.charge_native_helper_work(1)?;
963
+ let (value, done) = runtime.iterator_next(iterator.clone())?;
964
+ if done {
965
+ break;
966
+ }
967
+ runtime
968
+ .arrays
969
+ .get_mut(array)
970
+ .ok_or_else(|| MustardError::runtime("array missing"))?
971
+ .elements
972
+ .push(Some(value));
973
+ runtime.refresh_array_accounting(array)?;
974
+ }
975
+ Ok(Value::Array(array))
976
+ },
977
+ )
978
+ })
979
+ }
980
+
981
+ fn pattern_array_index(&self, value: Value, index: usize) -> MustardResult<Value> {
982
+ let items = self.to_array_items(value)?;
983
+ Ok(items.get(index).cloned().unwrap_or(Value::Undefined))
984
+ }
985
+
986
+ fn pattern_array_rest(&mut self, value: Value, start: usize) -> MustardResult<Value> {
987
+ let items = self.to_array_items(value)?;
988
+ let array = self.insert_array(items.into_iter().skip(start).collect(), IndexMap::new())?;
989
+ Ok(Value::Array(array))
990
+ }
991
+
992
+ fn pattern_object_rest(&mut self, value: Value, excluded: &[String]) -> MustardResult<Value> {
993
+ let excluded: std::collections::HashSet<_> = excluded.iter().cloned().collect();
994
+ let mut rest_object = IndexMap::new();
995
+ match value {
996
+ Value::Object(object) => {
997
+ if let Some(object) = self.objects.get(object) {
998
+ for (key, value) in &object.properties {
999
+ if !excluded.contains(key) {
1000
+ rest_object.insert(key.clone(), value.clone());
1001
+ }
1002
+ }
1003
+ }
1004
+ }
1005
+ Value::Null | Value::Undefined => {
1006
+ return Err(MustardError::runtime(
1007
+ "cannot destructure object pattern from nullish value",
1008
+ ));
1009
+ }
1010
+ _ => {}
1011
+ }
1012
+ Ok(Value::Object(
1013
+ self.insert_object(rest_object, ObjectKind::Plain)?,
1014
+ ))
1015
+ }
1016
+ }