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,372 @@
1
+ use super::super::{bytecode::Instruction, format_number_key};
2
+ use super::{Compiler, context::CompileContext};
3
+ use crate::{
4
+ diagnostic::MustardResult,
5
+ ir::{
6
+ ArrayElement, BinaryOp, CallArgument, Expr, MemberProperty, ObjectProperty,
7
+ ObjectPropertyKey, PropertyName,
8
+ },
9
+ span::SourceSpan,
10
+ };
11
+
12
+ impl Compiler {
13
+ pub(super) fn compile_expr(
14
+ &mut self,
15
+ context: &mut CompileContext,
16
+ expression: &Expr,
17
+ ) -> MustardResult<()> {
18
+ match expression {
19
+ Expr::Undefined { .. } => context.code.push(Instruction::PushUndefined),
20
+ Expr::Null { .. } => context.code.push(Instruction::PushNull),
21
+ Expr::Bool { value, .. } => context.code.push(Instruction::PushBool(*value)),
22
+ Expr::Number { value, .. } => context.code.push(Instruction::PushNumber(*value)),
23
+ Expr::BigInt { value, .. } => context.code.push(Instruction::PushBigInt(value.clone())),
24
+ Expr::String { value, .. } => context.code.push(Instruction::PushString(value.clone())),
25
+ Expr::RegExp { pattern, flags, .. } => context.code.push(Instruction::PushRegExp {
26
+ pattern: pattern.clone(),
27
+ flags: flags.clone(),
28
+ }),
29
+ Expr::Identifier { name, .. } => context.code.push(Instruction::LoadName(name.clone())),
30
+ Expr::This { .. } => context.code.push(Instruction::LoadName("this".to_string())),
31
+ Expr::Array { elements, .. } => {
32
+ if elements
33
+ .iter()
34
+ .all(|element| matches!(element, ArrayElement::Value(_)))
35
+ {
36
+ for element in elements {
37
+ let ArrayElement::Value(element) = element else {
38
+ unreachable!("dense array fast-path should only see value entries");
39
+ };
40
+ self.compile_expr(context, element)?;
41
+ }
42
+ context.code.push(Instruction::MakeArray {
43
+ count: elements.len(),
44
+ });
45
+ } else {
46
+ context.code.push(Instruction::MakeArray { count: 0 });
47
+ for element in elements {
48
+ match element {
49
+ ArrayElement::Value(element) => {
50
+ self.compile_expr(context, element)?;
51
+ context.code.push(Instruction::ArrayPush);
52
+ }
53
+ ArrayElement::Hole { .. } => {
54
+ context.code.push(Instruction::ArrayPushHole);
55
+ }
56
+ ArrayElement::Spread { value, .. } => {
57
+ self.compile_expr(context, value)?;
58
+ context.code.push(Instruction::ArrayExtend);
59
+ }
60
+ }
61
+ }
62
+ }
63
+ }
64
+ Expr::Object { properties, .. } => {
65
+ context
66
+ .code
67
+ .push(Instruction::MakeObject { keys: Vec::new() });
68
+ for property in properties {
69
+ context.code.push(Instruction::Dup);
70
+ match property {
71
+ ObjectProperty::Property { key, value, .. } => match key {
72
+ ObjectPropertyKey::Static(PropertyName::Identifier(name))
73
+ | ObjectPropertyKey::Static(PropertyName::String(name)) => {
74
+ self.compile_expr(context, value)?;
75
+ context
76
+ .code
77
+ .push(Instruction::SetPropStatic { name: name.clone() });
78
+ }
79
+ ObjectPropertyKey::Static(PropertyName::Number(number)) => {
80
+ self.compile_expr(context, value)?;
81
+ context.code.push(Instruction::SetPropStatic {
82
+ name: format_number_key(*number),
83
+ });
84
+ }
85
+ ObjectPropertyKey::Computed(expression) => {
86
+ self.compile_expr(context, expression)?;
87
+ self.compile_expr(context, value)?;
88
+ context.code.push(Instruction::SetPropComputed);
89
+ }
90
+ },
91
+ ObjectProperty::Spread { value, .. } => {
92
+ self.compile_expr(context, value)?;
93
+ context.code.push(Instruction::CopyDataProperties);
94
+ }
95
+ }
96
+ context.code.push(Instruction::Pop);
97
+ }
98
+ }
99
+ Expr::Function(function) => {
100
+ context.code.push(Instruction::MakeClosure {
101
+ function_id: self.compile_function(function)?,
102
+ });
103
+ }
104
+ Expr::Unary {
105
+ operator, argument, ..
106
+ } => {
107
+ self.compile_expr(context, argument)?;
108
+ context.code.push(Instruction::Unary(*operator));
109
+ }
110
+ Expr::Binary {
111
+ operator,
112
+ left,
113
+ right,
114
+ ..
115
+ } => {
116
+ self.compile_expr(context, left)?;
117
+ self.compile_expr(context, right)?;
118
+ context.code.push(Instruction::Binary(*operator));
119
+ }
120
+ Expr::Sequence { expressions, .. } => {
121
+ if expressions.is_empty() {
122
+ context.code.push(Instruction::PushUndefined);
123
+ } else {
124
+ for (index, expression) in expressions.iter().enumerate() {
125
+ self.compile_expr(context, expression)?;
126
+ if index + 1 != expressions.len() {
127
+ context.code.push(Instruction::Pop);
128
+ }
129
+ }
130
+ }
131
+ }
132
+ Expr::Logical {
133
+ operator,
134
+ left,
135
+ right,
136
+ ..
137
+ } => {
138
+ self.compile_expr(context, left)?;
139
+ match operator {
140
+ crate::ir::LogicalOp::And => {
141
+ let jump = self.emit_jump(context, Instruction::JumpIfFalse(usize::MAX));
142
+ context.code.push(Instruction::Pop);
143
+ self.compile_expr(context, right)?;
144
+ let end_ip = context.code.len();
145
+ self.patch_jump(context, jump, end_ip);
146
+ }
147
+ crate::ir::LogicalOp::Or => {
148
+ let jump = self.emit_jump(context, Instruction::JumpIfTrue(usize::MAX));
149
+ context.code.push(Instruction::Pop);
150
+ self.compile_expr(context, right)?;
151
+ let end_ip = context.code.len();
152
+ self.patch_jump(context, jump, end_ip);
153
+ }
154
+ crate::ir::LogicalOp::NullishCoalesce => {
155
+ let jump = self.emit_jump(context, Instruction::JumpIfNullish(usize::MAX));
156
+ let end = self.emit_jump(context, Instruction::Jump(usize::MAX));
157
+ let rhs = context.code.len();
158
+ self.patch_jump(context, jump, rhs);
159
+ context.code.push(Instruction::Pop);
160
+ self.compile_expr(context, right)?;
161
+ let end_ip = context.code.len();
162
+ self.patch_jump(context, end, end_ip);
163
+ }
164
+ }
165
+ }
166
+ Expr::Conditional {
167
+ test,
168
+ consequent,
169
+ alternate,
170
+ ..
171
+ } => {
172
+ self.compile_expr(context, test)?;
173
+ let else_jump = self.emit_jump(context, Instruction::JumpIfFalse(usize::MAX));
174
+ context.code.push(Instruction::Pop);
175
+ self.compile_expr(context, consequent)?;
176
+ let end_jump = self.emit_jump(context, Instruction::Jump(usize::MAX));
177
+ let else_ip = context.code.len();
178
+ self.patch_jump(context, else_jump, else_ip);
179
+ context.code.push(Instruction::Pop);
180
+ self.compile_expr(context, alternate)?;
181
+ let end_ip = context.code.len();
182
+ self.patch_jump(context, end_jump, end_ip);
183
+ }
184
+ Expr::Assignment {
185
+ target,
186
+ operator,
187
+ value,
188
+ ..
189
+ } => self.compile_assignment(context, target.as_ref(), *operator, value)?,
190
+ Expr::Update {
191
+ target,
192
+ operator,
193
+ prefix,
194
+ ..
195
+ } => self.compile_update(context, target.as_ref(), *operator, *prefix)?,
196
+ Expr::Member {
197
+ object,
198
+ property,
199
+ optional,
200
+ ..
201
+ } => {
202
+ self.compile_expr(context, object)?;
203
+ match property {
204
+ MemberProperty::Static(PropertyName::Identifier(name))
205
+ | MemberProperty::Static(PropertyName::String(name)) => {
206
+ context.code.push(Instruction::GetPropStatic {
207
+ name: name.clone(),
208
+ optional: *optional,
209
+ })
210
+ }
211
+ MemberProperty::Static(PropertyName::Number(number)) => {
212
+ context.code.push(Instruction::GetPropStatic {
213
+ name: format_number_key(*number),
214
+ optional: *optional,
215
+ })
216
+ }
217
+ MemberProperty::Computed(expression) => {
218
+ self.compile_expr(context, expression)?;
219
+ context.code.push(Instruction::GetPropComputed {
220
+ optional: *optional,
221
+ });
222
+ }
223
+ }
224
+ }
225
+ Expr::Call {
226
+ callee,
227
+ arguments,
228
+ optional,
229
+ ..
230
+ } => {
231
+ let with_this = matches!(callee.as_ref(), Expr::Member { .. });
232
+ if let Expr::Member {
233
+ object,
234
+ property,
235
+ optional: member_optional,
236
+ ..
237
+ } = callee.as_ref()
238
+ {
239
+ self.compile_expr(context, object)?;
240
+ context.code.push(Instruction::Dup);
241
+ match property {
242
+ MemberProperty::Static(PropertyName::Identifier(name))
243
+ | MemberProperty::Static(PropertyName::String(name)) => {
244
+ context.code.push(Instruction::GetPropStatic {
245
+ name: name.clone(),
246
+ optional: *member_optional,
247
+ })
248
+ }
249
+ MemberProperty::Static(PropertyName::Number(number)) => {
250
+ context.code.push(Instruction::GetPropStatic {
251
+ name: format_number_key(*number),
252
+ optional: *member_optional,
253
+ })
254
+ }
255
+ MemberProperty::Computed(expression) => {
256
+ self.compile_expr(context, expression)?;
257
+ context.code.push(Instruction::GetPropComputed {
258
+ optional: *member_optional,
259
+ });
260
+ }
261
+ }
262
+ } else {
263
+ self.compile_expr(context, callee)?;
264
+ }
265
+ if arguments
266
+ .iter()
267
+ .all(|argument| matches!(argument, CallArgument::Value(_)))
268
+ {
269
+ for argument in arguments {
270
+ let CallArgument::Value(argument) = argument else {
271
+ unreachable!(
272
+ "non-spread call fast-path should only see value arguments"
273
+ );
274
+ };
275
+ self.compile_expr(context, argument)?;
276
+ }
277
+ context.code.push(Instruction::Call {
278
+ argc: arguments.len(),
279
+ with_this,
280
+ optional: *optional,
281
+ });
282
+ } else {
283
+ context.code.push(Instruction::MakeArray { count: 0 });
284
+ for argument in arguments {
285
+ match argument {
286
+ CallArgument::Value(argument) => {
287
+ self.compile_expr(context, argument)?;
288
+ context.code.push(Instruction::ArrayPush);
289
+ }
290
+ CallArgument::Spread { value, .. } => {
291
+ self.compile_expr(context, value)?;
292
+ context.code.push(Instruction::ArrayExtend);
293
+ }
294
+ }
295
+ }
296
+ context.code.push(Instruction::CallWithArray {
297
+ with_this,
298
+ optional: *optional,
299
+ });
300
+ }
301
+ }
302
+ Expr::New {
303
+ callee, arguments, ..
304
+ } => {
305
+ self.compile_expr(context, callee)?;
306
+ if arguments
307
+ .iter()
308
+ .all(|argument| matches!(argument, CallArgument::Value(_)))
309
+ {
310
+ for argument in arguments {
311
+ let CallArgument::Value(argument) = argument else {
312
+ unreachable!(
313
+ "non-spread constructor fast-path should only see value arguments"
314
+ );
315
+ };
316
+ self.compile_expr(context, argument)?;
317
+ }
318
+ context.code.push(Instruction::Construct {
319
+ argc: arguments.len(),
320
+ });
321
+ } else {
322
+ context.code.push(Instruction::MakeArray { count: 0 });
323
+ for argument in arguments {
324
+ match argument {
325
+ CallArgument::Value(argument) => {
326
+ self.compile_expr(context, argument)?;
327
+ context.code.push(Instruction::ArrayPush);
328
+ }
329
+ CallArgument::Spread { value, .. } => {
330
+ self.compile_expr(context, value)?;
331
+ context.code.push(Instruction::ArrayExtend);
332
+ }
333
+ }
334
+ }
335
+ context.code.push(Instruction::ConstructWithArray);
336
+ }
337
+ }
338
+ Expr::Template {
339
+ quasis,
340
+ expressions,
341
+ ..
342
+ } => {
343
+ let mut parts = Vec::new();
344
+ for (index, quasi) in quasis.iter().enumerate() {
345
+ if !quasi.is_empty() {
346
+ parts.push(Expr::String {
347
+ span: SourceSpan::new(0, 0),
348
+ value: quasi.clone(),
349
+ });
350
+ }
351
+ if let Some(expression) = expressions.get(index) {
352
+ parts.push(expression.clone());
353
+ }
354
+ }
355
+ if parts.is_empty() {
356
+ context.code.push(Instruction::PushString(String::new()));
357
+ } else {
358
+ self.compile_expr(context, &parts[0])?;
359
+ for part in parts.iter().skip(1) {
360
+ self.compile_expr(context, part)?;
361
+ context.code.push(Instruction::Binary(BinaryOp::Add));
362
+ }
363
+ }
364
+ }
365
+ Expr::Await { value, .. } => {
366
+ self.compile_expr(context, value)?;
367
+ context.code.push(Instruction::Await);
368
+ }
369
+ }
370
+ Ok(())
371
+ }
372
+ }
@@ -0,0 +1,173 @@
1
+ mod assignments;
2
+ mod bindings;
3
+ mod context;
4
+ mod control;
5
+ mod expressions;
6
+ mod statements;
7
+
8
+ use std::collections::HashSet;
9
+
10
+ use bindings::collect_block_bindings;
11
+ use context::CompileContext;
12
+
13
+ use crate::{
14
+ diagnostic::MustardResult,
15
+ ir::{CompiledProgram, FunctionExpr, Pattern, Stmt},
16
+ span::SourceSpan,
17
+ };
18
+
19
+ use super::{
20
+ bytecode::{BytecodeProgram, FunctionPrototype, Instruction},
21
+ validation::validate_bytecode_program,
22
+ };
23
+
24
+ pub(super) fn pattern_bindings(pattern: &Pattern) -> Vec<(String, bool)> {
25
+ bindings::pattern_bindings(pattern)
26
+ }
27
+
28
+ pub fn lower_to_bytecode(program: &CompiledProgram) -> MustardResult<BytecodeProgram> {
29
+ let mut compiler = Compiler::default();
30
+ let root = compiler.compile_root(&program.script.body, program.script.span)?;
31
+ let program = BytecodeProgram {
32
+ functions: compiler.functions,
33
+ root,
34
+ };
35
+ validate_bytecode_program(&program)?;
36
+ Ok(program)
37
+ }
38
+
39
+ #[derive(Debug, Default)]
40
+ struct Compiler {
41
+ functions: Vec<FunctionPrototype>,
42
+ }
43
+
44
+ impl Compiler {
45
+ fn compile_root(&mut self, statements: &[Stmt], span: SourceSpan) -> MustardResult<usize> {
46
+ let mut context = CompileContext::default();
47
+ self.emit_block_prologue(&mut context, statements, true)?;
48
+ let mut produced_result = false;
49
+ for (index, statement) in statements.iter().enumerate() {
50
+ let is_last = index + 1 == statements.len();
51
+ if is_last && let Stmt::Expression { expression, .. } = statement {
52
+ self.compile_expr(&mut context, expression)?;
53
+ produced_result = true;
54
+ continue;
55
+ }
56
+ self.compile_stmt(&mut context, statement)?;
57
+ }
58
+ if !produced_result {
59
+ context.code.push(Instruction::PushUndefined);
60
+ }
61
+ context.code.push(Instruction::Return);
62
+ let id = self.functions.len();
63
+ self.functions.push(FunctionPrototype {
64
+ name: None,
65
+ length: 0,
66
+ display_source: String::new(),
67
+ params: Vec::new(),
68
+ rest: None,
69
+ code: context.code,
70
+ is_async: false,
71
+ is_arrow: false,
72
+ span,
73
+ });
74
+ Ok(id)
75
+ }
76
+
77
+ fn compile_function(&mut self, function: &FunctionExpr) -> MustardResult<usize> {
78
+ self.compile_function_body(function)
79
+ }
80
+
81
+ fn compile_function_body(&mut self, function: &FunctionExpr) -> MustardResult<usize> {
82
+ let mut context = CompileContext::default();
83
+ for statement in &function.param_init {
84
+ if let Stmt::VariableDecl { declarators, .. } = statement {
85
+ for declarator in declarators {
86
+ for (name, _) in pattern_bindings(&declarator.pattern) {
87
+ context.code.push(Instruction::DeclareName {
88
+ name,
89
+ mutable: true,
90
+ });
91
+ }
92
+ if let Some(initializer) = &declarator.initializer {
93
+ self.compile_expr(&mut context, initializer)?;
94
+ } else {
95
+ context.code.push(Instruction::PushUndefined);
96
+ }
97
+ self.compile_pattern_binding(&mut context, &declarator.pattern)?;
98
+ }
99
+ }
100
+ }
101
+ self.emit_block_prologue(&mut context, &function.body, false)?;
102
+ for statement in &function.body {
103
+ self.compile_stmt(&mut context, statement)?;
104
+ }
105
+ context.code.push(Instruction::PushUndefined);
106
+ context.code.push(Instruction::Return);
107
+ let id = self.functions.len();
108
+ self.functions.push(FunctionPrototype {
109
+ name: function.name.clone(),
110
+ length: function.length,
111
+ display_source: function.display_source.clone(),
112
+ params: function.params.clone(),
113
+ rest: function.rest.clone(),
114
+ code: context.code,
115
+ is_async: function.is_async,
116
+ is_arrow: function.is_arrow,
117
+ span: function.span,
118
+ });
119
+ Ok(id)
120
+ }
121
+
122
+ fn emit_block_prologue(
123
+ &mut self,
124
+ context: &mut CompileContext,
125
+ statements: &[Stmt],
126
+ root_scope: bool,
127
+ ) -> MustardResult<()> {
128
+ let mut declared = HashSet::new();
129
+ let bindings = collect_block_bindings(statements);
130
+ for (name, mutable) in bindings.lexicals {
131
+ if declared.insert(name.clone()) {
132
+ context
133
+ .code
134
+ .push(Instruction::DeclareName { name, mutable });
135
+ }
136
+ }
137
+ for function in bindings.functions {
138
+ let function_name = function.name.clone();
139
+ if declared.insert(function_name.clone()) {
140
+ context.code.push(Instruction::DeclareName {
141
+ name: function_name.clone(),
142
+ mutable: false,
143
+ });
144
+ }
145
+ context.code.push(Instruction::MakeClosure {
146
+ function_id: self.compile_function(&function.expr)?,
147
+ });
148
+ context
149
+ .code
150
+ .push(Instruction::InitializePattern(Pattern::Identifier {
151
+ span: function.expr.span,
152
+ name: function_name.clone(),
153
+ }));
154
+ if root_scope {
155
+ context.code.push(Instruction::LoadGlobalObject);
156
+ context
157
+ .code
158
+ .push(Instruction::LoadName(function_name.clone()));
159
+ context.code.push(Instruction::SetPropStatic {
160
+ name: function_name,
161
+ });
162
+ context.code.push(Instruction::Pop);
163
+ }
164
+ }
165
+ Ok(())
166
+ }
167
+
168
+ fn fresh_internal_name(&self, context: &mut CompileContext, prefix: &str) -> String {
169
+ let name = format!("\0mustard_{prefix}_{}", context.internal_name_counter);
170
+ context.internal_name_counter += 1;
171
+ name
172
+ }
173
+ }