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,92 @@
1
+ use crate::{
2
+ diagnostic::{MustardError, MustardResult},
3
+ ir::{AssignOp, BinaryOp, BindingKind, FunctionExpr, Pattern, Stmt},
4
+ };
5
+
6
+ #[derive(Debug)]
7
+ pub(super) struct BlockBindings {
8
+ pub(super) lexicals: Vec<(String, bool)>,
9
+ pub(super) functions: Vec<FunctionBinding>,
10
+ }
11
+
12
+ #[derive(Debug)]
13
+ pub(super) struct FunctionBinding {
14
+ pub(super) name: String,
15
+ pub(super) expr: FunctionExpr,
16
+ }
17
+
18
+ pub(super) fn collect_block_bindings(statements: &[Stmt]) -> BlockBindings {
19
+ let mut lexicals = Vec::new();
20
+ let mut functions = Vec::new();
21
+ for statement in statements {
22
+ match statement {
23
+ Stmt::VariableDecl {
24
+ kind, declarators, ..
25
+ } => {
26
+ for declarator in declarators {
27
+ for (name, _) in pattern_bindings(&declarator.pattern) {
28
+ lexicals.push((name, *kind == BindingKind::Let));
29
+ }
30
+ }
31
+ }
32
+ Stmt::FunctionDecl { function, .. } => {
33
+ if let Some(name) = &function.name {
34
+ functions.push(FunctionBinding {
35
+ name: name.clone(),
36
+ expr: function.clone(),
37
+ });
38
+ }
39
+ }
40
+ _ => {}
41
+ }
42
+ }
43
+ BlockBindings {
44
+ lexicals,
45
+ functions,
46
+ }
47
+ }
48
+
49
+ pub(super) fn pattern_bindings(pattern: &Pattern) -> Vec<(String, bool)> {
50
+ let mut bindings = Vec::new();
51
+ collect_pattern_bindings(pattern, &mut bindings);
52
+ bindings
53
+ }
54
+
55
+ fn collect_pattern_bindings(pattern: &Pattern, bindings: &mut Vec<(String, bool)>) {
56
+ match pattern {
57
+ Pattern::Identifier { name, .. } => bindings.push((name.clone(), true)),
58
+ Pattern::Object {
59
+ properties, rest, ..
60
+ } => {
61
+ for property in properties {
62
+ collect_pattern_bindings(&property.value, bindings);
63
+ }
64
+ if let Some(rest) = rest {
65
+ collect_pattern_bindings(rest, bindings);
66
+ }
67
+ }
68
+ Pattern::Array { elements, rest, .. } => {
69
+ for element in elements.iter().flatten() {
70
+ collect_pattern_bindings(element, bindings);
71
+ }
72
+ if let Some(rest) = rest {
73
+ collect_pattern_bindings(rest, bindings);
74
+ }
75
+ }
76
+ Pattern::Default { target, .. } => collect_pattern_bindings(target, bindings),
77
+ }
78
+ }
79
+
80
+ pub(super) fn assign_op_to_binary(operator: AssignOp) -> MustardResult<BinaryOp> {
81
+ match operator {
82
+ AssignOp::Assign | AssignOp::OrAssign | AssignOp::AndAssign | AssignOp::NullishAssign => {
83
+ Err(MustardError::runtime("invalid compound assignment"))
84
+ }
85
+ AssignOp::AddAssign => Ok(BinaryOp::Add),
86
+ AssignOp::SubAssign => Ok(BinaryOp::Sub),
87
+ AssignOp::MulAssign => Ok(BinaryOp::Mul),
88
+ AssignOp::DivAssign => Ok(BinaryOp::Div),
89
+ AssignOp::RemAssign => Ok(BinaryOp::Rem),
90
+ AssignOp::PowAssign => Ok(BinaryOp::Pow),
91
+ }
92
+ }
@@ -0,0 +1,46 @@
1
+ use super::super::bytecode::Instruction;
2
+
3
+ #[derive(Debug, Default)]
4
+ pub(super) struct CompileContext {
5
+ pub(super) code: Vec<Instruction>,
6
+ pub(super) loop_stack: Vec<LoopContext>,
7
+ pub(super) active_handlers: Vec<ActiveHandlerContext>,
8
+ pub(super) active_finally: Vec<ActiveFinallyContext>,
9
+ pub(super) finally_regions: Vec<FinallyRegionContext>,
10
+ pub(super) scope_depth: usize,
11
+ pub(super) internal_name_counter: usize,
12
+ }
13
+
14
+ #[derive(Debug, Default)]
15
+ pub(super) struct LoopContext {
16
+ pub(super) break_jumps: Vec<ControlTransferPatch>,
17
+ pub(super) continue_jumps: Vec<ControlTransferPatch>,
18
+ pub(super) continue_target: Option<usize>,
19
+ pub(super) handler_depth: usize,
20
+ pub(super) scope_depth: usize,
21
+ }
22
+
23
+ #[derive(Debug, Clone, Copy)]
24
+ pub(super) struct ActiveHandlerContext {
25
+ pub(super) finally_region: Option<usize>,
26
+ pub(super) scope_depth: usize,
27
+ }
28
+
29
+ #[derive(Debug, Default)]
30
+ pub(super) struct FinallyRegionContext {
31
+ pub(super) handler_sites: Vec<usize>,
32
+ pub(super) jump_sites: Vec<usize>,
33
+ }
34
+
35
+ #[derive(Debug, Default)]
36
+ pub(super) struct ActiveFinallyContext {
37
+ pub(super) exit_patch_site: usize,
38
+ pub(super) jump_sites: Vec<usize>,
39
+ pub(super) scope_depth: usize,
40
+ }
41
+
42
+ #[derive(Debug, Clone, Copy)]
43
+ pub(super) enum ControlTransferPatch {
44
+ DirectJump(usize),
45
+ PendingJump(usize),
46
+ }
@@ -0,0 +1,342 @@
1
+ use super::super::bytecode::Instruction;
2
+ use super::{
3
+ Compiler,
4
+ context::{
5
+ ActiveFinallyContext, ActiveHandlerContext, CompileContext, ControlTransferPatch,
6
+ FinallyRegionContext,
7
+ },
8
+ pattern_bindings,
9
+ };
10
+ use crate::{diagnostic::MustardResult, ir::Stmt};
11
+
12
+ impl Compiler {
13
+ pub(super) fn compile_try(
14
+ &mut self,
15
+ context: &mut CompileContext,
16
+ body: &Stmt,
17
+ catch: Option<&crate::ir::CatchClause>,
18
+ finally: Option<&Stmt>,
19
+ ) -> MustardResult<()> {
20
+ let finally_region = finally.map(|_| {
21
+ context
22
+ .finally_regions
23
+ .push(FinallyRegionContext::default());
24
+ context.finally_regions.len() - 1
25
+ });
26
+
27
+ let try_handler_site = context.code.len();
28
+ context.code.push(Instruction::PushHandler {
29
+ catch: catch.map(|_| usize::MAX),
30
+ finally: finally_region.map(|_| usize::MAX),
31
+ });
32
+ if let Some(region) = finally_region {
33
+ context.finally_regions[region]
34
+ .handler_sites
35
+ .push(try_handler_site);
36
+ }
37
+
38
+ context.active_handlers.push(ActiveHandlerContext {
39
+ finally_region,
40
+ scope_depth: context.scope_depth,
41
+ });
42
+ self.compile_stmt(context, body)?;
43
+ context.active_handlers.pop();
44
+ context.code.push(Instruction::PopHandler);
45
+
46
+ let mut skip_catch_jump = None;
47
+ let mut after_finally_patches = Vec::new();
48
+ let outer_handler_depth = context.active_handlers.len();
49
+
50
+ if let Some(region) = finally_region {
51
+ let patch = context.code.len();
52
+ context.code.push(Instruction::PushPendingJump {
53
+ target: usize::MAX,
54
+ target_handler_depth: outer_handler_depth,
55
+ target_scope_depth: context.scope_depth,
56
+ });
57
+ after_finally_patches.push(patch);
58
+ self.emit_jump_to_finally(context, region);
59
+ } else if catch.is_some() {
60
+ skip_catch_jump = Some(self.emit_jump(context, Instruction::Jump(usize::MAX)));
61
+ }
62
+
63
+ if let Some(catch_clause) = catch {
64
+ self.patch_handler_catch(context, try_handler_site, context.code.len());
65
+
66
+ if let Some(region) = finally_region {
67
+ let catch_handler_site = context.code.len();
68
+ context.code.push(Instruction::PushHandler {
69
+ catch: None,
70
+ finally: Some(usize::MAX),
71
+ });
72
+ context.finally_regions[region]
73
+ .handler_sites
74
+ .push(catch_handler_site);
75
+ context.active_handlers.push(ActiveHandlerContext {
76
+ finally_region: Some(region),
77
+ scope_depth: context.scope_depth,
78
+ });
79
+ }
80
+
81
+ context.code.push(Instruction::PushEnv);
82
+ context.scope_depth += 1;
83
+ if let Some(parameter) = &catch_clause.parameter {
84
+ for (name, mutable) in pattern_bindings(parameter) {
85
+ context
86
+ .code
87
+ .push(Instruction::DeclareName { name, mutable });
88
+ }
89
+ }
90
+ context.code.push(Instruction::BeginCatch);
91
+ if let Some(parameter) = &catch_clause.parameter {
92
+ self.compile_pattern_binding(context, parameter)?;
93
+ } else {
94
+ context.code.push(Instruction::Pop);
95
+ }
96
+ self.compile_stmt(context, catch_clause.body.as_ref())?;
97
+ context.scope_depth -= 1;
98
+ context.code.push(Instruction::PopEnv);
99
+
100
+ if let Some(region) = finally_region {
101
+ context.active_handlers.pop();
102
+ context.code.push(Instruction::PopHandler);
103
+ let patch = context.code.len();
104
+ context.code.push(Instruction::PushPendingJump {
105
+ target: usize::MAX,
106
+ target_handler_depth: outer_handler_depth,
107
+ target_scope_depth: context.scope_depth,
108
+ });
109
+ after_finally_patches.push(patch);
110
+ self.emit_jump_to_finally(context, region);
111
+ }
112
+ }
113
+
114
+ if let Some(finally_stmt) = finally {
115
+ let finally_ip = context.code.len();
116
+ self.patch_finally_region(
117
+ context,
118
+ finally_region.expect("finally region should exist"),
119
+ finally_ip,
120
+ );
121
+ let enter_finally = context.code.len();
122
+ context
123
+ .code
124
+ .push(Instruction::EnterFinally { exit: usize::MAX });
125
+ context.active_finally.push(ActiveFinallyContext {
126
+ exit_patch_site: enter_finally,
127
+ jump_sites: Vec::new(),
128
+ scope_depth: context.scope_depth,
129
+ });
130
+ self.compile_stmt(context, finally_stmt)?;
131
+ let continue_ip = context.code.len();
132
+ let active_finally = context
133
+ .active_finally
134
+ .pop()
135
+ .expect("finally context should exist");
136
+ self.patch_finally_exit(context, active_finally, continue_ip);
137
+ context.code.push(Instruction::ContinuePending);
138
+ let after_finally = context.code.len();
139
+ for patch in after_finally_patches {
140
+ self.patch_pending_jump(context, patch, after_finally);
141
+ }
142
+ if let Some(skip_catch_jump) = skip_catch_jump {
143
+ self.patch_jump(context, skip_catch_jump, after_finally);
144
+ }
145
+ } else if let Some(skip_catch_jump) = skip_catch_jump {
146
+ let after_catch = context.code.len();
147
+ self.patch_jump(context, skip_catch_jump, after_catch);
148
+ }
149
+
150
+ Ok(())
151
+ }
152
+
153
+ pub(super) fn emit_return(&self, context: &mut CompileContext) {
154
+ if let Some(active_finally) = context.active_finally.last() {
155
+ self.emit_scope_cleanup(context, active_finally.scope_depth);
156
+ context.code.push(Instruction::PushPendingReturn);
157
+ self.emit_jump_to_active_finally_exit(context);
158
+ return;
159
+ }
160
+ if let Some((handler_depth, region)) = self.nearest_finally_region(context, 0) {
161
+ self.emit_scope_cleanup(context, context.active_handlers[handler_depth].scope_depth);
162
+ self.emit_handler_cleanup(context, handler_depth);
163
+ context.code.push(Instruction::PushPendingReturn);
164
+ self.emit_jump_to_finally(context, region);
165
+ } else {
166
+ context.code.push(Instruction::Return);
167
+ }
168
+ }
169
+
170
+ pub(super) fn emit_jump_transfer(
171
+ &self,
172
+ context: &mut CompileContext,
173
+ target_handler_depth: usize,
174
+ target_scope_depth: usize,
175
+ ) -> ControlTransferPatch {
176
+ if let Some(active_finally) = context.active_finally.last() {
177
+ self.emit_scope_cleanup(context, active_finally.scope_depth);
178
+ let patch = context.code.len();
179
+ context.code.push(Instruction::PushPendingJump {
180
+ target: usize::MAX,
181
+ target_handler_depth,
182
+ target_scope_depth,
183
+ });
184
+ self.emit_jump_to_active_finally_exit(context);
185
+ return ControlTransferPatch::PendingJump(patch);
186
+ }
187
+ if let Some((handler_depth, region)) =
188
+ self.nearest_finally_region(context, target_handler_depth)
189
+ {
190
+ self.emit_scope_cleanup(context, context.active_handlers[handler_depth].scope_depth);
191
+ self.emit_handler_cleanup(context, handler_depth);
192
+ let patch = context.code.len();
193
+ context.code.push(Instruction::PushPendingJump {
194
+ target: usize::MAX,
195
+ target_handler_depth,
196
+ target_scope_depth,
197
+ });
198
+ self.emit_jump_to_finally(context, region);
199
+ ControlTransferPatch::PendingJump(patch)
200
+ } else {
201
+ self.emit_scope_cleanup(context, target_scope_depth);
202
+ self.emit_handler_cleanup(context, target_handler_depth);
203
+ ControlTransferPatch::DirectJump(self.emit_jump(context, Instruction::Jump(usize::MAX)))
204
+ }
205
+ }
206
+
207
+ pub(super) fn emit_scope_cleanup(
208
+ &self,
209
+ context: &mut CompileContext,
210
+ target_scope_depth: usize,
211
+ ) {
212
+ for _ in target_scope_depth..context.scope_depth {
213
+ context.code.push(Instruction::PopEnv);
214
+ }
215
+ }
216
+
217
+ pub(super) fn emit_handler_cleanup(
218
+ &self,
219
+ context: &mut CompileContext,
220
+ target_handler_depth: usize,
221
+ ) {
222
+ for _ in target_handler_depth..context.active_handlers.len() {
223
+ context.code.push(Instruction::PopHandler);
224
+ }
225
+ }
226
+
227
+ pub(super) fn nearest_finally_region(
228
+ &self,
229
+ context: &CompileContext,
230
+ target_handler_depth: usize,
231
+ ) -> Option<(usize, usize)> {
232
+ for handler_depth in (target_handler_depth..context.active_handlers.len()).rev() {
233
+ if let Some(region) = context.active_handlers[handler_depth].finally_region {
234
+ return Some((handler_depth, region));
235
+ }
236
+ }
237
+ None
238
+ }
239
+
240
+ pub(super) fn emit_jump_to_finally(&self, context: &mut CompileContext, region: usize) {
241
+ let jump_site = self.emit_jump(context, Instruction::Jump(usize::MAX));
242
+ context.finally_regions[region].jump_sites.push(jump_site);
243
+ }
244
+
245
+ pub(super) fn emit_jump_to_active_finally_exit(&self, context: &mut CompileContext) {
246
+ let jump_site = self.emit_jump(context, Instruction::Jump(usize::MAX));
247
+ context
248
+ .active_finally
249
+ .last_mut()
250
+ .expect("finally context should exist")
251
+ .jump_sites
252
+ .push(jump_site);
253
+ }
254
+
255
+ pub(super) fn patch_handler_catch(
256
+ &self,
257
+ context: &mut CompileContext,
258
+ index: usize,
259
+ target: usize,
260
+ ) {
261
+ if let Instruction::PushHandler { catch, .. } = &mut context.code[index] {
262
+ *catch = Some(target);
263
+ }
264
+ }
265
+
266
+ pub(super) fn patch_finally_region(
267
+ &self,
268
+ context: &mut CompileContext,
269
+ region: usize,
270
+ target: usize,
271
+ ) {
272
+ let handler_sites = context.finally_regions[region].handler_sites.clone();
273
+ let jump_sites = context.finally_regions[region].jump_sites.clone();
274
+ for site in handler_sites {
275
+ if let Instruction::PushHandler { finally, .. } = &mut context.code[site] {
276
+ *finally = Some(target);
277
+ }
278
+ }
279
+ for site in jump_sites {
280
+ self.patch_jump(context, site, target);
281
+ }
282
+ }
283
+
284
+ pub(super) fn patch_finally_exit(
285
+ &self,
286
+ context: &mut CompileContext,
287
+ finally: ActiveFinallyContext,
288
+ target: usize,
289
+ ) {
290
+ if let Instruction::EnterFinally { exit } = &mut context.code[finally.exit_patch_site] {
291
+ *exit = target;
292
+ }
293
+ for jump_site in finally.jump_sites {
294
+ self.patch_jump(context, jump_site, target);
295
+ }
296
+ }
297
+
298
+ pub(super) fn patch_pending_jump(
299
+ &self,
300
+ context: &mut CompileContext,
301
+ index: usize,
302
+ target: usize,
303
+ ) {
304
+ if let Instruction::PushPendingJump { target: jump, .. } = &mut context.code[index] {
305
+ *jump = target;
306
+ }
307
+ }
308
+
309
+ pub(super) fn patch_control_transfer(
310
+ &self,
311
+ context: &mut CompileContext,
312
+ patch: ControlTransferPatch,
313
+ target: usize,
314
+ ) {
315
+ match patch {
316
+ ControlTransferPatch::DirectJump(index) => self.patch_jump(context, index, target),
317
+ ControlTransferPatch::PendingJump(index) => {
318
+ self.patch_pending_jump(context, index, target)
319
+ }
320
+ }
321
+ }
322
+
323
+ pub(super) fn emit_jump(
324
+ &self,
325
+ context: &mut CompileContext,
326
+ instruction: Instruction,
327
+ ) -> usize {
328
+ let index = context.code.len();
329
+ context.code.push(instruction);
330
+ index
331
+ }
332
+
333
+ pub(super) fn patch_jump(&self, context: &mut CompileContext, index: usize, target: usize) {
334
+ match &mut context.code[index] {
335
+ Instruction::Jump(address)
336
+ | Instruction::JumpIfFalse(address)
337
+ | Instruction::JumpIfTrue(address)
338
+ | Instruction::JumpIfNullish(address) => *address = target,
339
+ _ => {}
340
+ }
341
+ }
342
+ }