mustardscript 0.1.0 → 0.1.1

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 (96) hide show
  1. package/README.md +62 -20
  2. package/SECURITY.md +1 -1
  3. package/dist/index.js +2 -0
  4. package/dist/lib/executor.js +16 -1
  5. package/dist/lib/policy.js +301 -22
  6. package/dist/lib/progress.js +499 -113
  7. package/dist/lib/runtime.js +109 -40
  8. package/dist/lib/structured.js +327 -11
  9. package/dist/native-loader.js +11 -12
  10. package/index.d.ts +54 -6
  11. package/mustard.d.ts +23 -1
  12. package/package.json +34 -25
  13. package/Cargo.lock +0 -1579
  14. package/Cargo.toml +0 -40
  15. package/crates/mustard/Cargo.toml +0 -31
  16. package/crates/mustard/src/cancellation.rs +0 -28
  17. package/crates/mustard/src/diagnostic.rs +0 -145
  18. package/crates/mustard/src/ir.rs +0 -435
  19. package/crates/mustard/src/lib.rs +0 -21
  20. package/crates/mustard/src/limits.rs +0 -22
  21. package/crates/mustard/src/parser/expressions.rs +0 -723
  22. package/crates/mustard/src/parser/mod.rs +0 -115
  23. package/crates/mustard/src/parser/operators.rs +0 -105
  24. package/crates/mustard/src/parser/patterns.rs +0 -123
  25. package/crates/mustard/src/parser/scope.rs +0 -107
  26. package/crates/mustard/src/parser/statements.rs +0 -298
  27. package/crates/mustard/src/parser/tests/acceptance.rs +0 -339
  28. package/crates/mustard/src/parser/tests/mod.rs +0 -2
  29. package/crates/mustard/src/parser/tests/rejections.rs +0 -107
  30. package/crates/mustard/src/runtime/accounting.rs +0 -613
  31. package/crates/mustard/src/runtime/api.rs +0 -192
  32. package/crates/mustard/src/runtime/async_runtime/mod.rs +0 -5
  33. package/crates/mustard/src/runtime/async_runtime/promises.rs +0 -246
  34. package/crates/mustard/src/runtime/async_runtime/reactions.rs +0 -400
  35. package/crates/mustard/src/runtime/async_runtime/scheduler.rs +0 -224
  36. package/crates/mustard/src/runtime/builtins/arrays.rs +0 -1205
  37. package/crates/mustard/src/runtime/builtins/collections.rs +0 -573
  38. package/crates/mustard/src/runtime/builtins/install.rs +0 -501
  39. package/crates/mustard/src/runtime/builtins/intl.rs +0 -553
  40. package/crates/mustard/src/runtime/builtins/mod.rs +0 -25
  41. package/crates/mustard/src/runtime/builtins/objects.rs +0 -405
  42. package/crates/mustard/src/runtime/builtins/primitives.rs +0 -859
  43. package/crates/mustard/src/runtime/builtins/promises.rs +0 -335
  44. package/crates/mustard/src/runtime/builtins/regexp.rs +0 -356
  45. package/crates/mustard/src/runtime/builtins/strings.rs +0 -803
  46. package/crates/mustard/src/runtime/builtins/support.rs +0 -561
  47. package/crates/mustard/src/runtime/bytecode.rs +0 -123
  48. package/crates/mustard/src/runtime/compiler/assignments.rs +0 -690
  49. package/crates/mustard/src/runtime/compiler/bindings.rs +0 -92
  50. package/crates/mustard/src/runtime/compiler/context.rs +0 -46
  51. package/crates/mustard/src/runtime/compiler/control.rs +0 -342
  52. package/crates/mustard/src/runtime/compiler/expressions.rs +0 -372
  53. package/crates/mustard/src/runtime/compiler/mod.rs +0 -173
  54. package/crates/mustard/src/runtime/compiler/statements.rs +0 -459
  55. package/crates/mustard/src/runtime/conversions/boundary.rs +0 -293
  56. package/crates/mustard/src/runtime/conversions/coercions.rs +0 -217
  57. package/crates/mustard/src/runtime/conversions/errors.rs +0 -118
  58. package/crates/mustard/src/runtime/conversions/mod.rs +0 -14
  59. package/crates/mustard/src/runtime/conversions/operators.rs +0 -334
  60. package/crates/mustard/src/runtime/env.rs +0 -355
  61. package/crates/mustard/src/runtime/exceptions.rs +0 -377
  62. package/crates/mustard/src/runtime/gc.rs +0 -595
  63. package/crates/mustard/src/runtime/mod.rs +0 -318
  64. package/crates/mustard/src/runtime/properties.rs +0 -1762
  65. package/crates/mustard/src/runtime/serialization.rs +0 -127
  66. package/crates/mustard/src/runtime/shared.rs +0 -108
  67. package/crates/mustard/src/runtime/snapshot_validation_tests.rs +0 -93
  68. package/crates/mustard/src/runtime/state.rs +0 -652
  69. package/crates/mustard/src/runtime/tests/async_host.rs +0 -104
  70. package/crates/mustard/src/runtime/tests/collections.rs +0 -50
  71. package/crates/mustard/src/runtime/tests/diagnostics.rs +0 -36
  72. package/crates/mustard/src/runtime/tests/exceptions.rs +0 -122
  73. package/crates/mustard/src/runtime/tests/execution.rs +0 -553
  74. package/crates/mustard/src/runtime/tests/gc.rs +0 -533
  75. package/crates/mustard/src/runtime/tests/mod.rs +0 -56
  76. package/crates/mustard/src/runtime/tests/serialization.rs +0 -170
  77. package/crates/mustard/src/runtime/validation/bytecode.rs +0 -484
  78. package/crates/mustard/src/runtime/validation/mod.rs +0 -14
  79. package/crates/mustard/src/runtime/validation/policy.rs +0 -94
  80. package/crates/mustard/src/runtime/validation/snapshot.rs +0 -406
  81. package/crates/mustard/src/runtime/validation/walk.rs +0 -206
  82. package/crates/mustard/src/runtime/vm.rs +0 -1016
  83. package/crates/mustard/src/span.rs +0 -22
  84. package/crates/mustard/src/structured.rs +0 -107
  85. package/crates/mustard-bridge/Cargo.toml +0 -17
  86. package/crates/mustard-bridge/src/codec.rs +0 -46
  87. package/crates/mustard-bridge/src/dto.rs +0 -99
  88. package/crates/mustard-bridge/src/lib.rs +0 -12
  89. package/crates/mustard-bridge/src/operations.rs +0 -142
  90. package/crates/mustard-node/Cargo.toml +0 -24
  91. package/crates/mustard-node/build.rs +0 -3
  92. package/crates/mustard-node/src/lib.rs +0 -236
  93. package/crates/mustard-sidecar/Cargo.toml +0 -21
  94. package/crates/mustard-sidecar/src/lib.rs +0 -134
  95. package/crates/mustard-sidecar/src/main.rs +0 -36
  96. package/dist/install.js +0 -117
@@ -1,170 +0,0 @@
1
- use super::*;
2
-
3
- #[test]
4
- fn round_trips_program_and_snapshot() {
5
- let source = "const value = fetch_data(1); value + 2;";
6
- let program = compile(source).expect("compile should succeed");
7
- let bytecode = lower_to_bytecode(&program).expect("lowering should succeed");
8
- let program_bytes = dump_program(&bytecode).expect("program dump should succeed");
9
- let loaded_program = load_program(&program_bytes).expect("program load should succeed");
10
- assert_eq!(loaded_program.root, bytecode.root);
11
- assert_eq!(loaded_program.functions.len(), bytecode.functions.len());
12
-
13
- let suspension = suspend(source, &["fetch_data"]);
14
- let snapshot_bytes = dump_snapshot(&suspension.snapshot).expect("snapshot dump should succeed");
15
- let loaded_snapshot = load_snapshot(&snapshot_bytes).expect("snapshot load should succeed");
16
- let resumed = resume_with_options(
17
- loaded_snapshot,
18
- ResumePayload::Value(number(1.0)),
19
- ResumeOptions {
20
- cancellation_token: None,
21
- snapshot_policy: Some(SnapshotPolicy {
22
- capabilities: vec!["fetch_data".to_string()],
23
- limits: RuntimeLimits::default(),
24
- }),
25
- },
26
- )
27
- .expect("resume should succeed");
28
- match resumed {
29
- ExecutionStep::Completed(value) => {
30
- assert_eq!(value, number(3.0));
31
- }
32
- other => panic!("expected completion, got {other:?}"),
33
- }
34
- }
35
-
36
- #[test]
37
- fn rejects_invalid_jump_targets_before_execution() {
38
- let program = invalid_program(vec![Instruction::Jump(99), Instruction::Return]);
39
- let error = start_bytecode(&program, ExecutionOptions::default())
40
- .expect_err("invalid jump target should fail validation");
41
- assert!(error.to_string().contains("jumps to invalid target 99"));
42
- }
43
-
44
- #[test]
45
- fn rejects_inconsistent_stack_depth_in_serialized_programs() {
46
- let program = invalid_program(vec![
47
- Instruction::PushNumber(1.0),
48
- Instruction::JumpIfTrue(3),
49
- Instruction::Pop,
50
- Instruction::Return,
51
- ]);
52
- let bytes = dump_program(&program).expect("invalid program still serializes");
53
- let error =
54
- load_program(&bytes).expect_err("invalid serialized program should fail validation");
55
- assert!(
56
- error
57
- .to_string()
58
- .contains("has inconsistent validation state")
59
- );
60
- }
61
-
62
- #[test]
63
- fn rejects_cross_version_serialized_programs() {
64
- let program = lower_to_bytecode(&compile("1;").expect("compile should succeed"))
65
- .expect("lowering should succeed");
66
- let mut bytes = dump_program(&program).expect("program should serialize");
67
- bytes[0] = bytes[0].saturating_add(1);
68
- let error = load_program(&bytes).expect_err("cross-version program should be rejected");
69
- assert!(
70
- error
71
- .to_string()
72
- .contains("serialized program version mismatch")
73
- );
74
- }
75
-
76
- #[test]
77
- fn rejects_invalid_snapshot_frame_state() {
78
- let mut suspension = suspend("const value = fetch_data(1); value + 2;", &["fetch_data"]);
79
- suspension.snapshot.runtime.frames[0].ip = 999;
80
- let bytes = dump_snapshot(&suspension.snapshot).expect("snapshot should serialize");
81
- let error = load_snapshot(&bytes).expect_err("invalid snapshot should fail validation");
82
- assert!(
83
- error
84
- .to_string()
85
- .contains("frame instruction pointer 999 is out of range")
86
- );
87
- }
88
-
89
- #[test]
90
- fn direct_execution_snapshot_deserialize_reruns_validation() {
91
- let mut suspension = suspend("const value = fetch_data(1); value + 2;", &["fetch_data"]);
92
- suspension.snapshot.runtime.frames[0].ip = 999;
93
- let bytes =
94
- bincode::serialize(&suspension.snapshot).expect("snapshot should serialize directly");
95
- let error = bincode::deserialize::<ExecutionSnapshot>(&bytes)
96
- .expect_err("invalid snapshots should fail validation during direct deserialize");
97
- assert!(
98
- error
99
- .to_string()
100
- .contains("frame instruction pointer 999 is out of range")
101
- );
102
- }
103
-
104
- #[test]
105
- fn rejects_cross_version_snapshots() {
106
- let suspension = suspend("const value = fetch_data(1); value + 2;", &["fetch_data"]);
107
-
108
- let mut bytes = dump_snapshot(&suspension.snapshot).expect("snapshot should serialize");
109
- bytes[0] = bytes[0].saturating_add(1);
110
- let error = load_snapshot(&bytes).expect_err("cross-version snapshot should be rejected");
111
- assert!(
112
- error
113
- .to_string()
114
- .contains("serialized snapshot version mismatch")
115
- );
116
- }
117
-
118
- #[test]
119
- fn rejects_out_of_range_promise_combinator_snapshot_state() {
120
- let mut suspension = suspend(
121
- r#"
122
- async function main() {
123
- return Promise.all([fetch_data(1), fetch_data(2)]);
124
- }
125
- main();
126
- "#,
127
- &["fetch_data"],
128
- );
129
-
130
- let target = suspension
131
- .snapshot
132
- .runtime
133
- .promises
134
- .iter()
135
- .find_map(|(key, promise)| match promise.driver.as_ref() {
136
- Some(PromiseDriver::All { .. }) => Some(key),
137
- _ => None,
138
- })
139
- .expect("Promise.all target should exist");
140
-
141
- let mutated = suspension
142
- .snapshot
143
- .runtime
144
- .promises
145
- .values_mut()
146
- .find_map(|promise| {
147
- promise.reactions.iter_mut().find_map(|reaction| match reaction {
148
- PromiseReaction::Combinator {
149
- target: reaction_target,
150
- index,
151
- ..
152
- } if *reaction_target == target => {
153
- *index = 99;
154
- Some(())
155
- }
156
- _ => None,
157
- })
158
- });
159
- assert!(mutated.is_some(), "Promise.all combinator reaction should exist");
160
-
161
- let bytes = dump_snapshot(&suspension.snapshot).expect("snapshot should serialize");
162
- let error = load_snapshot(&bytes).expect_err("forged snapshot should fail validation");
163
- assert!(
164
- error
165
- .to_string()
166
- .contains("promise")
167
- && error.to_string().contains("combinator index"),
168
- "unexpected error: {error}"
169
- );
170
- }
@@ -1,484 +0,0 @@
1
- use super::*;
2
-
3
- #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4
- struct ValidationState {
5
- stack_depth: usize,
6
- scope_depth: usize,
7
- handler_depth: usize,
8
- pending_depth: usize,
9
- }
10
-
11
- pub(in crate::runtime) fn validate_bytecode_program(
12
- program: &BytecodeProgram,
13
- ) -> MustardResult<()> {
14
- if program.functions.is_empty() {
15
- return Err(MustardError::validation(
16
- "bytecode validation failed: program defines no functions",
17
- None,
18
- ));
19
- }
20
- if program.root >= program.functions.len() {
21
- return Err(MustardError::validation(
22
- format!(
23
- "bytecode validation failed: root function {} is out of range for {} functions",
24
- program.root,
25
- program.functions.len()
26
- ),
27
- None,
28
- ));
29
- }
30
- for (function_id, function) in program.functions.iter().enumerate() {
31
- validate_function(program, function_id, function)?;
32
- }
33
- Ok(())
34
- }
35
-
36
- fn validate_function(
37
- program: &BytecodeProgram,
38
- function_id: usize,
39
- function: &FunctionPrototype,
40
- ) -> MustardResult<()> {
41
- if function.code.is_empty() {
42
- return Err(MustardError::validation(
43
- format!("bytecode validation failed: function {function_id} has no instructions"),
44
- None,
45
- ));
46
- }
47
- if !matches!(function.code.last(), Some(Instruction::Return)) {
48
- return Err(MustardError::validation(
49
- format!("bytecode validation failed: function {function_id} does not end in Return"),
50
- None,
51
- ));
52
- }
53
-
54
- let code_len = function.code.len();
55
- for (ip, instruction) in function.code.iter().enumerate() {
56
- match instruction {
57
- Instruction::MakeClosure {
58
- function_id: target,
59
- } if *target >= program.functions.len() => {
60
- return Err(MustardError::validation(
61
- format!(
62
- "bytecode validation failed: function {function_id} instruction {ip} references missing closure target {target}"
63
- ),
64
- None,
65
- ));
66
- }
67
- Instruction::Jump(target)
68
- | Instruction::JumpIfFalse(target)
69
- | Instruction::JumpIfTrue(target)
70
- | Instruction::JumpIfNullish(target)
71
- | Instruction::EnterFinally { exit: target }
72
- | Instruction::PushPendingJump { target, .. }
73
- if *target >= code_len =>
74
- {
75
- return Err(MustardError::validation(
76
- format!(
77
- "bytecode validation failed: function {function_id} instruction {ip} jumps to invalid target {target}"
78
- ),
79
- None,
80
- ));
81
- }
82
- Instruction::PushHandler { catch, finally }
83
- if catch.is_some_and(|target| target >= code_len)
84
- || finally.is_some_and(|target| target >= code_len) =>
85
- {
86
- return Err(MustardError::validation(
87
- format!(
88
- "bytecode validation failed: function {function_id} instruction {ip} references an invalid exception target"
89
- ),
90
- None,
91
- ));
92
- }
93
- _ => {}
94
- }
95
- }
96
-
97
- let mut states = vec![None; code_len];
98
- let mut work = VecDeque::from([(
99
- 0usize,
100
- ValidationState {
101
- stack_depth: 0,
102
- scope_depth: 0,
103
- handler_depth: 0,
104
- pending_depth: 0,
105
- },
106
- )]);
107
- while let Some((ip, state)) = work.pop_front() {
108
- if let Some(existing) = states[ip] {
109
- if existing != state {
110
- return Err(MustardError::validation(
111
- format!(
112
- "bytecode validation failed: function {function_id} instruction {ip} has inconsistent validation state: existing={existing:?}, new={state:?}"
113
- ),
114
- None,
115
- ));
116
- }
117
- continue;
118
- }
119
- states[ip] = Some(state);
120
-
121
- let instruction = &function.code[ip];
122
- let next_state = apply_validation_effect(function_id, ip, instruction, state)?;
123
- for successor in validation_successors(ip, instruction, code_len) {
124
- work.push_back((successor, next_state));
125
- }
126
- match instruction {
127
- Instruction::PushHandler { catch, finally } => {
128
- if let Some(target) = catch {
129
- work.push_back((
130
- *target,
131
- ValidationState {
132
- handler_depth: state.handler_depth,
133
- ..state
134
- },
135
- ));
136
- } else if let Some(target) = finally {
137
- work.push_back((
138
- *target,
139
- ValidationState {
140
- handler_depth: state.handler_depth,
141
- pending_depth: state.pending_depth + 1,
142
- ..state
143
- },
144
- ));
145
- }
146
- }
147
- Instruction::PushPendingJump {
148
- target,
149
- target_handler_depth,
150
- target_scope_depth,
151
- } => {
152
- work.push_back((
153
- *target,
154
- ValidationState {
155
- scope_depth: *target_scope_depth,
156
- handler_depth: *target_handler_depth,
157
- ..state
158
- },
159
- ));
160
- }
161
- _ => {}
162
- }
163
- }
164
-
165
- Ok(())
166
- }
167
-
168
- fn apply_validation_effect(
169
- function_id: usize,
170
- ip: usize,
171
- instruction: &Instruction,
172
- state: ValidationState,
173
- ) -> MustardResult<ValidationState> {
174
- let require_stack = |count: usize| -> MustardResult<()> {
175
- if state.stack_depth < count {
176
- return Err(MustardError::validation(
177
- format!(
178
- "bytecode validation failed: function {function_id} instruction {ip} requires stack depth {count}, found {}",
179
- state.stack_depth
180
- ),
181
- None,
182
- ));
183
- }
184
- Ok(())
185
- };
186
-
187
- let next = match instruction {
188
- Instruction::PushUndefined
189
- | Instruction::PushNull
190
- | Instruction::PushBool(_)
191
- | Instruction::PushNumber(_)
192
- | Instruction::PushBigInt(_)
193
- | Instruction::PushString(_)
194
- | Instruction::PushRegExp { .. }
195
- | Instruction::LoadName(_)
196
- | Instruction::LoadGlobalObject
197
- | Instruction::MakeClosure { .. }
198
- | Instruction::BeginCatch => ValidationState {
199
- stack_depth: state.stack_depth + 1,
200
- ..state
201
- },
202
- Instruction::StoreName(_) => {
203
- require_stack(1)?;
204
- state
205
- }
206
- Instruction::InitializePattern(_) | Instruction::Pop => {
207
- require_stack(1)?;
208
- ValidationState {
209
- stack_depth: state.stack_depth - 1,
210
- ..state
211
- }
212
- }
213
- Instruction::PushEnv => ValidationState {
214
- scope_depth: state.scope_depth + 1,
215
- ..state
216
- },
217
- Instruction::PopEnv => {
218
- if state.scope_depth == 0 {
219
- return Err(MustardError::validation(
220
- format!(
221
- "bytecode validation failed: function {function_id} instruction {ip} pops an empty scope stack"
222
- ),
223
- None,
224
- ));
225
- }
226
- ValidationState {
227
- scope_depth: state.scope_depth - 1,
228
- ..state
229
- }
230
- }
231
- Instruction::DeclareName { .. } => state,
232
- Instruction::MakeArray { count } => {
233
- require_stack(*count)?;
234
- ValidationState {
235
- stack_depth: state.stack_depth - count + 1,
236
- ..state
237
- }
238
- }
239
- Instruction::ArrayPush => {
240
- require_stack(2)?;
241
- state
242
- }
243
- Instruction::ArrayPushHole => {
244
- require_stack(1)?;
245
- state
246
- }
247
- Instruction::ArrayExtend => {
248
- require_stack(2)?;
249
- ValidationState {
250
- stack_depth: state.stack_depth - 1,
251
- ..state
252
- }
253
- }
254
- Instruction::MakeObject { keys } => {
255
- require_stack(keys.len())?;
256
- ValidationState {
257
- stack_depth: state.stack_depth - keys.len() + 1,
258
- ..state
259
- }
260
- }
261
- Instruction::CopyDataProperties => {
262
- require_stack(2)?;
263
- ValidationState {
264
- stack_depth: state.stack_depth - 1,
265
- ..state
266
- }
267
- }
268
- Instruction::CreateIterator => {
269
- require_stack(1)?;
270
- state
271
- }
272
- Instruction::IteratorNext => {
273
- require_stack(1)?;
274
- ValidationState {
275
- stack_depth: state.stack_depth + 1,
276
- ..state
277
- }
278
- }
279
- Instruction::GetPropStatic { .. } => {
280
- require_stack(1)?;
281
- state
282
- }
283
- Instruction::GetPropComputed { .. } => {
284
- require_stack(2)?;
285
- ValidationState {
286
- stack_depth: state.stack_depth - 1,
287
- ..state
288
- }
289
- }
290
- Instruction::PatternArrayIndex(_)
291
- | Instruction::PatternArrayRest(_)
292
- | Instruction::PatternObjectRest(_)
293
- | Instruction::Update(_) => {
294
- require_stack(1)?;
295
- state
296
- }
297
- Instruction::SetPropStatic { .. } => {
298
- require_stack(2)?;
299
- ValidationState {
300
- stack_depth: state.stack_depth - 1,
301
- ..state
302
- }
303
- }
304
- Instruction::SetPropComputed => {
305
- require_stack(3)?;
306
- ValidationState {
307
- stack_depth: state.stack_depth - 2,
308
- ..state
309
- }
310
- }
311
- Instruction::Unary(_) => {
312
- require_stack(1)?;
313
- state
314
- }
315
- Instruction::Binary(_) => {
316
- require_stack(2)?;
317
- ValidationState {
318
- stack_depth: state.stack_depth - 1,
319
- ..state
320
- }
321
- }
322
- Instruction::Dup => {
323
- require_stack(1)?;
324
- ValidationState {
325
- stack_depth: state.stack_depth + 1,
326
- ..state
327
- }
328
- }
329
- Instruction::Dup2 => {
330
- require_stack(2)?;
331
- ValidationState {
332
- stack_depth: state.stack_depth + 2,
333
- ..state
334
- }
335
- }
336
- Instruction::PushHandler { .. } => ValidationState {
337
- handler_depth: state.handler_depth + 1,
338
- ..state
339
- },
340
- Instruction::PopHandler => {
341
- if state.handler_depth == 0 {
342
- return Err(MustardError::validation(
343
- format!(
344
- "bytecode validation failed: function {function_id} instruction {ip} pops an empty handler stack"
345
- ),
346
- None,
347
- ));
348
- }
349
- ValidationState {
350
- handler_depth: state.handler_depth - 1,
351
- ..state
352
- }
353
- }
354
- Instruction::EnterFinally { .. } => state,
355
- Instruction::Throw { .. } => {
356
- require_stack(1)?;
357
- state
358
- }
359
- Instruction::PushPendingJump {
360
- target_handler_depth,
361
- target_scope_depth,
362
- ..
363
- } => {
364
- if *target_handler_depth > state.handler_depth {
365
- return Err(MustardError::validation(
366
- format!(
367
- "bytecode validation failed: function {function_id} instruction {ip} targets handler depth {target_handler_depth} from depth {}",
368
- state.handler_depth
369
- ),
370
- None,
371
- ));
372
- }
373
- if *target_scope_depth > state.scope_depth {
374
- return Err(MustardError::validation(
375
- format!(
376
- "bytecode validation failed: function {function_id} instruction {ip} targets scope depth {target_scope_depth} from depth {}",
377
- state.scope_depth
378
- ),
379
- None,
380
- ));
381
- }
382
- ValidationState {
383
- pending_depth: state.pending_depth + 1,
384
- ..state
385
- }
386
- }
387
- Instruction::PushPendingReturn => {
388
- require_stack(1)?;
389
- ValidationState {
390
- stack_depth: state.stack_depth - 1,
391
- pending_depth: state.pending_depth + 1,
392
- ..state
393
- }
394
- }
395
- Instruction::PushPendingThrow => {
396
- require_stack(1)?;
397
- ValidationState {
398
- stack_depth: state.stack_depth - 1,
399
- pending_depth: state.pending_depth + 1,
400
- ..state
401
- }
402
- }
403
- Instruction::ContinuePending => {
404
- if state.pending_depth == 0 {
405
- return Err(MustardError::validation(
406
- format!(
407
- "bytecode validation failed: function {function_id} instruction {ip} resumes without a pending completion"
408
- ),
409
- None,
410
- ));
411
- }
412
- ValidationState {
413
- pending_depth: state.pending_depth - 1,
414
- ..state
415
- }
416
- }
417
- Instruction::Jump(_) => state,
418
- Instruction::JumpIfFalse(_)
419
- | Instruction::JumpIfTrue(_)
420
- | Instruction::JumpIfNullish(_) => {
421
- require_stack(1)?;
422
- state
423
- }
424
- Instruction::Call {
425
- argc, with_this, ..
426
- } => {
427
- let required = argc + 1 + usize::from(*with_this);
428
- require_stack(required)?;
429
- ValidationState {
430
- stack_depth: state.stack_depth - required + 1,
431
- ..state
432
- }
433
- }
434
- Instruction::CallWithArray { with_this, .. } => {
435
- let required = 2 + usize::from(*with_this);
436
- require_stack(required)?;
437
- ValidationState {
438
- stack_depth: state.stack_depth - required + 1,
439
- ..state
440
- }
441
- }
442
- Instruction::Await => {
443
- require_stack(1)?;
444
- state
445
- }
446
- Instruction::Construct { argc } => {
447
- let required = argc + 1;
448
- require_stack(required)?;
449
- ValidationState {
450
- stack_depth: state.stack_depth - required + 1,
451
- ..state
452
- }
453
- }
454
- Instruction::ConstructWithArray => {
455
- require_stack(2)?;
456
- ValidationState {
457
- stack_depth: state.stack_depth - 1,
458
- ..state
459
- }
460
- }
461
- Instruction::Return => state,
462
- };
463
- Ok(next)
464
- }
465
-
466
- fn validation_successors(ip: usize, instruction: &Instruction, code_len: usize) -> Vec<usize> {
467
- match instruction {
468
- Instruction::Jump(target) => vec![*target],
469
- Instruction::JumpIfFalse(target)
470
- | Instruction::JumpIfTrue(target)
471
- | Instruction::JumpIfNullish(target) => {
472
- let mut successors = vec![*target];
473
- if ip + 1 < code_len {
474
- successors.push(ip + 1);
475
- }
476
- successors
477
- }
478
- Instruction::ContinuePending | Instruction::Throw { .. } | Instruction::Return => {
479
- Vec::new()
480
- }
481
- _ if ip + 1 < code_len => vec![ip + 1],
482
- _ => Vec::new(),
483
- }
484
- }
@@ -1,14 +0,0 @@
1
- use std::collections::{HashSet, VecDeque};
2
-
3
- use crate::diagnostic::{DiagnosticKind, MustardError, MustardResult};
4
-
5
- use super::*;
6
-
7
- mod bytecode;
8
- mod policy;
9
- mod snapshot;
10
- mod walk;
11
-
12
- pub(super) use bytecode::validate_bytecode_program;
13
- pub(super) use policy::validate_snapshot_policy;
14
- pub(super) use snapshot::validate_snapshot;