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,1762 @@
1
+ use super::*;
2
+
3
+ impl Runtime {
4
+ fn function_helper_method(key: &str) -> Option<Value> {
5
+ match key {
6
+ "call" => Some(Value::BuiltinFunction(BuiltinFunction::FunctionCall)),
7
+ "apply" => Some(Value::BuiltinFunction(BuiltinFunction::FunctionApply)),
8
+ "bind" => Some(Value::BuiltinFunction(BuiltinFunction::FunctionBind)),
9
+ _ => None,
10
+ }
11
+ }
12
+
13
+ fn callable_constructor() -> Value {
14
+ Value::BuiltinFunction(BuiltinFunction::FunctionCtor)
15
+ }
16
+
17
+ pub(super) fn array_length(&self, array: ArrayKey) -> MustardResult<usize> {
18
+ Ok(self
19
+ .arrays
20
+ .get(array)
21
+ .ok_or_else(|| MustardError::runtime("array missing"))?
22
+ .elements
23
+ .len())
24
+ }
25
+
26
+ pub(super) fn array_has_index(&self, array: ArrayKey, index: usize) -> MustardResult<bool> {
27
+ Ok(self
28
+ .arrays
29
+ .get(array)
30
+ .ok_or_else(|| MustardError::runtime("array missing"))?
31
+ .elements
32
+ .get(index)
33
+ .is_some_and(Option::is_some))
34
+ }
35
+
36
+ pub(super) fn array_value_at(&self, array: ArrayKey, index: usize) -> MustardResult<Value> {
37
+ Ok(self
38
+ .arrays
39
+ .get(array)
40
+ .ok_or_else(|| MustardError::runtime("array missing"))?
41
+ .elements
42
+ .get(index)
43
+ .cloned()
44
+ .flatten()
45
+ .unwrap_or(Value::Undefined))
46
+ }
47
+
48
+ pub(super) fn closure_own_property(
49
+ &self,
50
+ closure: ClosureKey,
51
+ key: &str,
52
+ ) -> MustardResult<Option<Value>> {
53
+ let closure_ref = self
54
+ .closures
55
+ .get(closure)
56
+ .ok_or_else(|| MustardError::runtime("closure missing"))?;
57
+ let function = self
58
+ .program
59
+ .functions
60
+ .get(closure_ref.function_id)
61
+ .ok_or_else(|| MustardError::runtime("function not found"))?;
62
+ Ok(match key {
63
+ "name" => Some(Value::String(
64
+ closure_ref
65
+ .name
66
+ .clone()
67
+ .or_else(|| function.name.clone())
68
+ .unwrap_or_default(),
69
+ )),
70
+ "length" => Some(Value::Number(function.length as f64)),
71
+ "prototype" => closure_ref.prototype.map(Value::Object),
72
+ _ => closure_ref.properties.get(key).cloned(),
73
+ })
74
+ }
75
+
76
+ pub(super) fn closure_has_own_property(
77
+ &self,
78
+ closure: ClosureKey,
79
+ key: &str,
80
+ ) -> MustardResult<bool> {
81
+ Ok(self.closure_own_property(closure, key)?.is_some())
82
+ }
83
+
84
+ fn set_closure_property(
85
+ &mut self,
86
+ closure: ClosureKey,
87
+ key: String,
88
+ value: Value,
89
+ ) -> MustardResult<()> {
90
+ if matches!(key.as_str(), "name" | "length" | "prototype") {
91
+ return Err(MustardError::runtime(
92
+ "TypeError: cannot assign to read-only function metadata",
93
+ ));
94
+ }
95
+ self.closures
96
+ .get_mut(closure)
97
+ .ok_or_else(|| MustardError::runtime("closure missing"))?
98
+ .properties
99
+ .insert(key, value);
100
+ self.refresh_closure_accounting(closure)?;
101
+ Ok(())
102
+ }
103
+
104
+ pub(super) fn builtin_function_custom_property(
105
+ &self,
106
+ function: BuiltinFunction,
107
+ key: &str,
108
+ ) -> MustardResult<Option<Value>> {
109
+ let Some(object) = self.builtin_function_objects.get(&function).copied() else {
110
+ return Ok(None);
111
+ };
112
+ Ok(self
113
+ .objects
114
+ .get(object)
115
+ .ok_or_else(|| MustardError::runtime("object missing"))?
116
+ .properties
117
+ .get(key)
118
+ .cloned())
119
+ }
120
+
121
+ pub(super) fn host_function_custom_property(
122
+ &self,
123
+ capability: &str,
124
+ key: &str,
125
+ ) -> MustardResult<Option<Value>> {
126
+ let Some(object) = self.host_function_objects.get(capability).copied() else {
127
+ return Ok(None);
128
+ };
129
+ Ok(self
130
+ .objects
131
+ .get(object)
132
+ .ok_or_else(|| MustardError::runtime("object missing"))?
133
+ .properties
134
+ .get(key)
135
+ .cloned())
136
+ }
137
+
138
+ pub(super) fn builtin_function_custom_keys(
139
+ &self,
140
+ function: BuiltinFunction,
141
+ ) -> MustardResult<Vec<String>> {
142
+ let Some(object) = self.builtin_function_objects.get(&function).copied() else {
143
+ return Ok(Vec::new());
144
+ };
145
+ Ok(ordered_own_property_keys(
146
+ &self
147
+ .objects
148
+ .get(object)
149
+ .ok_or_else(|| MustardError::runtime("object missing"))?
150
+ .properties,
151
+ ))
152
+ }
153
+
154
+ pub(super) fn host_function_custom_keys(&self, capability: &str) -> MustardResult<Vec<String>> {
155
+ let Some(object) = self.host_function_objects.get(capability).copied() else {
156
+ return Ok(Vec::new());
157
+ };
158
+ Ok(ordered_own_property_keys(
159
+ &self
160
+ .objects
161
+ .get(object)
162
+ .ok_or_else(|| MustardError::runtime("object missing"))?
163
+ .properties,
164
+ ))
165
+ }
166
+
167
+ fn set_builtin_function_property(
168
+ &mut self,
169
+ function: BuiltinFunction,
170
+ key: String,
171
+ value: Value,
172
+ ) -> MustardResult<()> {
173
+ if matches!(key.as_str(), "name" | "length" | "prototype") {
174
+ return Err(MustardError::runtime(
175
+ "TypeError: cannot assign to read-only function metadata",
176
+ ));
177
+ }
178
+ let object = match self.builtin_function_objects.get(&function).copied() {
179
+ Some(object) => object,
180
+ None => {
181
+ let object = self.insert_object(IndexMap::new(), ObjectKind::Plain)?;
182
+ self.builtin_function_objects.insert(function, object);
183
+ object
184
+ }
185
+ };
186
+ self.objects
187
+ .get_mut(object)
188
+ .ok_or_else(|| MustardError::runtime("object missing"))?
189
+ .properties
190
+ .insert(key, value);
191
+ self.refresh_object_accounting(object)?;
192
+ Ok(())
193
+ }
194
+
195
+ fn set_host_function_property(
196
+ &mut self,
197
+ capability: String,
198
+ key: String,
199
+ value: Value,
200
+ ) -> MustardResult<()> {
201
+ if matches!(key.as_str(), "name" | "length") {
202
+ return Err(MustardError::runtime(
203
+ "TypeError: cannot assign to read-only function metadata",
204
+ ));
205
+ }
206
+ let object = match self.host_function_objects.get(&capability).copied() {
207
+ Some(object) => object,
208
+ None => {
209
+ let object = self.insert_object(IndexMap::new(), ObjectKind::Plain)?;
210
+ self.host_function_objects.insert(capability, object);
211
+ object
212
+ }
213
+ };
214
+ self.objects
215
+ .get_mut(object)
216
+ .ok_or_else(|| MustardError::runtime("object missing"))?
217
+ .properties
218
+ .insert(key, value);
219
+ self.refresh_object_accounting(object)?;
220
+ Ok(())
221
+ }
222
+
223
+ fn builtin_function_name(function: BuiltinFunction) -> &'static str {
224
+ match function {
225
+ BuiltinFunction::FunctionCtor => "Function",
226
+ BuiltinFunction::FunctionCall => "call",
227
+ BuiltinFunction::FunctionApply => "apply",
228
+ BuiltinFunction::FunctionBind => "bind",
229
+ BuiltinFunction::ArrayCtor => "Array",
230
+ BuiltinFunction::ArrayFrom => "from",
231
+ BuiltinFunction::ArrayOf => "of",
232
+ BuiltinFunction::ArrayIsArray => "isArray",
233
+ BuiltinFunction::ArrayPush => "push",
234
+ BuiltinFunction::ArrayPop => "pop",
235
+ BuiltinFunction::ArraySlice => "slice",
236
+ BuiltinFunction::ArraySplice => "splice",
237
+ BuiltinFunction::ArrayConcat => "concat",
238
+ BuiltinFunction::ArrayAt => "at",
239
+ BuiltinFunction::ArrayJoin => "join",
240
+ BuiltinFunction::ArrayIncludes => "includes",
241
+ BuiltinFunction::ArrayIndexOf => "indexOf",
242
+ BuiltinFunction::ArrayLastIndexOf => "lastIndexOf",
243
+ BuiltinFunction::ArrayReverse => "reverse",
244
+ BuiltinFunction::ArrayFill => "fill",
245
+ BuiltinFunction::ArraySort => "sort",
246
+ BuiltinFunction::ArrayValues => "values",
247
+ BuiltinFunction::ArrayKeys => "keys",
248
+ BuiltinFunction::ArrayEntries => "entries",
249
+ BuiltinFunction::ArrayForEach => "forEach",
250
+ BuiltinFunction::ArrayMap => "map",
251
+ BuiltinFunction::ArrayFilter => "filter",
252
+ BuiltinFunction::ArrayFind => "find",
253
+ BuiltinFunction::ArrayFindIndex => "findIndex",
254
+ BuiltinFunction::ArraySome => "some",
255
+ BuiltinFunction::ArrayEvery => "every",
256
+ BuiltinFunction::ArrayFlat => "flat",
257
+ BuiltinFunction::ArrayFlatMap => "flatMap",
258
+ BuiltinFunction::ArrayReduce => "reduce",
259
+ BuiltinFunction::ArrayReduceRight => "reduceRight",
260
+ BuiltinFunction::ArrayFindLast => "findLast",
261
+ BuiltinFunction::ArrayFindLastIndex => "findLastIndex",
262
+ BuiltinFunction::ObjectCtor => "Object",
263
+ BuiltinFunction::ObjectAssign => "assign",
264
+ BuiltinFunction::ObjectCreate => "create",
265
+ BuiltinFunction::ObjectFreeze => "freeze",
266
+ BuiltinFunction::ObjectSeal => "seal",
267
+ BuiltinFunction::ObjectFromEntries => "fromEntries",
268
+ BuiltinFunction::ObjectKeys => "keys",
269
+ BuiltinFunction::ObjectValues => "values",
270
+ BuiltinFunction::ObjectEntries => "entries",
271
+ BuiltinFunction::ObjectHasOwn => "hasOwn",
272
+ BuiltinFunction::MapCtor => "Map",
273
+ BuiltinFunction::MapGet => "get",
274
+ BuiltinFunction::MapSet => "set",
275
+ BuiltinFunction::MapHas => "has",
276
+ BuiltinFunction::MapDelete => "delete",
277
+ BuiltinFunction::MapClear => "clear",
278
+ BuiltinFunction::MapEntries => "entries",
279
+ BuiltinFunction::MapKeys => "keys",
280
+ BuiltinFunction::MapValues => "values",
281
+ BuiltinFunction::MapForEach => "forEach",
282
+ BuiltinFunction::SetCtor => "Set",
283
+ BuiltinFunction::SetAdd => "add",
284
+ BuiltinFunction::SetHas => "has",
285
+ BuiltinFunction::SetDelete => "delete",
286
+ BuiltinFunction::SetClear => "clear",
287
+ BuiltinFunction::SetEntries => "entries",
288
+ BuiltinFunction::SetKeys => "keys",
289
+ BuiltinFunction::SetValues => "values",
290
+ BuiltinFunction::SetForEach => "forEach",
291
+ BuiltinFunction::IteratorNext => "next",
292
+ BuiltinFunction::PromiseCtor => "Promise",
293
+ BuiltinFunction::PromiseResolve => "resolve",
294
+ BuiltinFunction::PromiseReject => "reject",
295
+ BuiltinFunction::PromiseResolveFunction(_) => "",
296
+ BuiltinFunction::PromiseRejectFunction(_) => "",
297
+ BuiltinFunction::PromiseThen => "then",
298
+ BuiltinFunction::PromiseCatch => "catch",
299
+ BuiltinFunction::PromiseFinally => "finally",
300
+ BuiltinFunction::PromiseAll => "all",
301
+ BuiltinFunction::PromiseRace => "race",
302
+ BuiltinFunction::PromiseAny => "any",
303
+ BuiltinFunction::PromiseAllSettled => "allSettled",
304
+ BuiltinFunction::RegExpCtor => "RegExp",
305
+ BuiltinFunction::RegExpExec => "exec",
306
+ BuiltinFunction::RegExpTest => "test",
307
+ BuiltinFunction::ErrorCtor => "Error",
308
+ BuiltinFunction::TypeErrorCtor => "TypeError",
309
+ BuiltinFunction::ReferenceErrorCtor => "ReferenceError",
310
+ BuiltinFunction::RangeErrorCtor => "RangeError",
311
+ BuiltinFunction::SyntaxErrorCtor => "SyntaxError",
312
+ BuiltinFunction::NumberCtor => "Number",
313
+ BuiltinFunction::NumberParseInt => "parseInt",
314
+ BuiltinFunction::NumberParseFloat => "parseFloat",
315
+ BuiltinFunction::NumberIsNaN => "isNaN",
316
+ BuiltinFunction::NumberIsFinite => "isFinite",
317
+ BuiltinFunction::NumberIsInteger => "isInteger",
318
+ BuiltinFunction::NumberIsSafeInteger => "isSafeInteger",
319
+ BuiltinFunction::DateCtor => "Date",
320
+ BuiltinFunction::DateNow => "now",
321
+ BuiltinFunction::DateGetTime => "getTime",
322
+ BuiltinFunction::DateValueOf => "valueOf",
323
+ BuiltinFunction::DateToISOString => "toISOString",
324
+ BuiltinFunction::DateToJSON => "toJSON",
325
+ BuiltinFunction::DateGetUTCFullYear => "getUTCFullYear",
326
+ BuiltinFunction::DateGetUTCMonth => "getUTCMonth",
327
+ BuiltinFunction::DateGetUTCDate => "getUTCDate",
328
+ BuiltinFunction::DateGetUTCHours => "getUTCHours",
329
+ BuiltinFunction::DateGetUTCMinutes => "getUTCMinutes",
330
+ BuiltinFunction::DateGetUTCSeconds => "getUTCSeconds",
331
+ BuiltinFunction::IntlDateTimeFormatCtor => "DateTimeFormat",
332
+ BuiltinFunction::IntlNumberFormatCtor => "NumberFormat",
333
+ BuiltinFunction::IntlDateTimeFormatFormat => "format",
334
+ BuiltinFunction::IntlDateTimeFormatResolvedOptions => "resolvedOptions",
335
+ BuiltinFunction::IntlNumberFormatFormat => "format",
336
+ BuiltinFunction::IntlNumberFormatResolvedOptions => "resolvedOptions",
337
+ BuiltinFunction::StringCtor => "String",
338
+ BuiltinFunction::StringTrim => "trim",
339
+ BuiltinFunction::StringTrimStart => "trimStart",
340
+ BuiltinFunction::StringTrimEnd => "trimEnd",
341
+ BuiltinFunction::StringIncludes => "includes",
342
+ BuiltinFunction::StringStartsWith => "startsWith",
343
+ BuiltinFunction::StringEndsWith => "endsWith",
344
+ BuiltinFunction::StringIndexOf => "indexOf",
345
+ BuiltinFunction::StringLastIndexOf => "lastIndexOf",
346
+ BuiltinFunction::StringCharAt => "charAt",
347
+ BuiltinFunction::StringAt => "at",
348
+ BuiltinFunction::StringSlice => "slice",
349
+ BuiltinFunction::StringSubstring => "substring",
350
+ BuiltinFunction::StringToLowerCase => "toLowerCase",
351
+ BuiltinFunction::StringToUpperCase => "toUpperCase",
352
+ BuiltinFunction::StringRepeat => "repeat",
353
+ BuiltinFunction::StringConcat => "concat",
354
+ BuiltinFunction::StringPadStart => "padStart",
355
+ BuiltinFunction::StringPadEnd => "padEnd",
356
+ BuiltinFunction::StringSplit => "split",
357
+ BuiltinFunction::StringReplace => "replace",
358
+ BuiltinFunction::StringReplaceAll => "replaceAll",
359
+ BuiltinFunction::StringSearch => "search",
360
+ BuiltinFunction::StringMatch => "match",
361
+ BuiltinFunction::StringMatchAll => "matchAll",
362
+ BuiltinFunction::StringToString => "toString",
363
+ BuiltinFunction::StringValueOf => "valueOf",
364
+ BuiltinFunction::BooleanCtor => "Boolean",
365
+ BuiltinFunction::BooleanToString => "toString",
366
+ BuiltinFunction::BooleanValueOf => "valueOf",
367
+ BuiltinFunction::NumberToString => "toString",
368
+ BuiltinFunction::NumberValueOf => "valueOf",
369
+ BuiltinFunction::MathAbs => "abs",
370
+ BuiltinFunction::MathMax => "max",
371
+ BuiltinFunction::MathMin => "min",
372
+ BuiltinFunction::MathFloor => "floor",
373
+ BuiltinFunction::MathCeil => "ceil",
374
+ BuiltinFunction::MathRound => "round",
375
+ BuiltinFunction::MathPow => "pow",
376
+ BuiltinFunction::MathSqrt => "sqrt",
377
+ BuiltinFunction::MathTrunc => "trunc",
378
+ BuiltinFunction::MathSign => "sign",
379
+ BuiltinFunction::MathLog => "log",
380
+ BuiltinFunction::MathExp => "exp",
381
+ BuiltinFunction::MathLog2 => "log2",
382
+ BuiltinFunction::MathLog10 => "log10",
383
+ BuiltinFunction::MathSin => "sin",
384
+ BuiltinFunction::MathCos => "cos",
385
+ BuiltinFunction::MathAtan2 => "atan2",
386
+ BuiltinFunction::MathHypot => "hypot",
387
+ BuiltinFunction::MathCbrt => "cbrt",
388
+ BuiltinFunction::MathRandom => "random",
389
+ BuiltinFunction::JsonStringify => "stringify",
390
+ BuiltinFunction::JsonParse => "parse",
391
+ }
392
+ }
393
+
394
+ fn builtin_function_length(function: BuiltinFunction) -> usize {
395
+ match function {
396
+ BuiltinFunction::FunctionCtor => 1,
397
+ BuiltinFunction::FunctionCall => 1,
398
+ BuiltinFunction::FunctionApply => 2,
399
+ BuiltinFunction::FunctionBind => 1,
400
+ BuiltinFunction::ArrayCtor => 1,
401
+ BuiltinFunction::ArrayFrom => 1,
402
+ BuiltinFunction::ArrayOf => 0,
403
+ BuiltinFunction::ArrayIsArray => 1,
404
+ BuiltinFunction::ArrayPush => 1,
405
+ BuiltinFunction::ArrayPop => 0,
406
+ BuiltinFunction::ArraySlice => 2,
407
+ BuiltinFunction::ArraySplice => 2,
408
+ BuiltinFunction::ArrayConcat => 1,
409
+ BuiltinFunction::ArrayAt => 1,
410
+ BuiltinFunction::ArrayJoin => 1,
411
+ BuiltinFunction::ArrayIncludes => 1,
412
+ BuiltinFunction::ArrayIndexOf => 1,
413
+ BuiltinFunction::ArrayLastIndexOf => 1,
414
+ BuiltinFunction::ArrayReverse => 0,
415
+ BuiltinFunction::ArrayFill => 1,
416
+ BuiltinFunction::ArraySort => 1,
417
+ BuiltinFunction::ArrayValues => 0,
418
+ BuiltinFunction::ArrayKeys => 0,
419
+ BuiltinFunction::ArrayEntries => 0,
420
+ BuiltinFunction::ArrayForEach => 1,
421
+ BuiltinFunction::ArrayMap => 1,
422
+ BuiltinFunction::ArrayFilter => 1,
423
+ BuiltinFunction::ArrayFind => 1,
424
+ BuiltinFunction::ArrayFindIndex => 1,
425
+ BuiltinFunction::ArraySome => 1,
426
+ BuiltinFunction::ArrayEvery => 1,
427
+ BuiltinFunction::ArrayFlat => 0,
428
+ BuiltinFunction::ArrayFlatMap => 1,
429
+ BuiltinFunction::ArrayReduce => 1,
430
+ BuiltinFunction::ArrayReduceRight => 1,
431
+ BuiltinFunction::ArrayFindLast => 1,
432
+ BuiltinFunction::ArrayFindLastIndex => 1,
433
+ BuiltinFunction::ObjectCtor => 1,
434
+ BuiltinFunction::ObjectAssign => 2,
435
+ BuiltinFunction::ObjectCreate => 2,
436
+ BuiltinFunction::ObjectFreeze => 1,
437
+ BuiltinFunction::ObjectSeal => 1,
438
+ BuiltinFunction::ObjectFromEntries => 1,
439
+ BuiltinFunction::ObjectKeys => 1,
440
+ BuiltinFunction::ObjectValues => 1,
441
+ BuiltinFunction::ObjectEntries => 1,
442
+ BuiltinFunction::ObjectHasOwn => 2,
443
+ BuiltinFunction::MapCtor => 0,
444
+ BuiltinFunction::MapGet => 1,
445
+ BuiltinFunction::MapSet => 2,
446
+ BuiltinFunction::MapHas => 1,
447
+ BuiltinFunction::MapDelete => 1,
448
+ BuiltinFunction::MapClear => 0,
449
+ BuiltinFunction::MapEntries => 0,
450
+ BuiltinFunction::MapKeys => 0,
451
+ BuiltinFunction::MapValues => 0,
452
+ BuiltinFunction::MapForEach => 1,
453
+ BuiltinFunction::SetCtor => 0,
454
+ BuiltinFunction::SetAdd => 1,
455
+ BuiltinFunction::SetHas => 1,
456
+ BuiltinFunction::SetDelete => 1,
457
+ BuiltinFunction::SetClear => 0,
458
+ BuiltinFunction::SetEntries => 0,
459
+ BuiltinFunction::SetKeys => 0,
460
+ BuiltinFunction::SetValues => 0,
461
+ BuiltinFunction::SetForEach => 1,
462
+ BuiltinFunction::IteratorNext => 0,
463
+ BuiltinFunction::PromiseCtor => 1,
464
+ BuiltinFunction::PromiseResolve => 1,
465
+ BuiltinFunction::PromiseReject => 1,
466
+ BuiltinFunction::PromiseResolveFunction(_) => 1,
467
+ BuiltinFunction::PromiseRejectFunction(_) => 1,
468
+ BuiltinFunction::PromiseThen => 2,
469
+ BuiltinFunction::PromiseCatch => 1,
470
+ BuiltinFunction::PromiseFinally => 1,
471
+ BuiltinFunction::PromiseAll => 1,
472
+ BuiltinFunction::PromiseRace => 1,
473
+ BuiltinFunction::PromiseAny => 1,
474
+ BuiltinFunction::PromiseAllSettled => 1,
475
+ BuiltinFunction::RegExpCtor => 2,
476
+ BuiltinFunction::RegExpExec => 1,
477
+ BuiltinFunction::RegExpTest => 1,
478
+ BuiltinFunction::ErrorCtor => 1,
479
+ BuiltinFunction::TypeErrorCtor => 1,
480
+ BuiltinFunction::ReferenceErrorCtor => 1,
481
+ BuiltinFunction::RangeErrorCtor => 1,
482
+ BuiltinFunction::SyntaxErrorCtor => 1,
483
+ BuiltinFunction::NumberCtor => 1,
484
+ BuiltinFunction::NumberParseInt => 2,
485
+ BuiltinFunction::NumberParseFloat => 1,
486
+ BuiltinFunction::NumberIsNaN => 1,
487
+ BuiltinFunction::NumberIsFinite => 1,
488
+ BuiltinFunction::NumberIsInteger => 1,
489
+ BuiltinFunction::NumberIsSafeInteger => 1,
490
+ BuiltinFunction::DateCtor => 7,
491
+ BuiltinFunction::DateNow => 0,
492
+ BuiltinFunction::DateGetTime => 0,
493
+ BuiltinFunction::DateValueOf => 0,
494
+ BuiltinFunction::DateToISOString => 0,
495
+ BuiltinFunction::DateToJSON => 0,
496
+ BuiltinFunction::DateGetUTCFullYear => 0,
497
+ BuiltinFunction::DateGetUTCMonth => 0,
498
+ BuiltinFunction::DateGetUTCDate => 0,
499
+ BuiltinFunction::DateGetUTCHours => 0,
500
+ BuiltinFunction::DateGetUTCMinutes => 0,
501
+ BuiltinFunction::DateGetUTCSeconds => 0,
502
+ BuiltinFunction::IntlDateTimeFormatCtor => 0,
503
+ BuiltinFunction::IntlNumberFormatCtor => 0,
504
+ BuiltinFunction::IntlDateTimeFormatFormat => 1,
505
+ BuiltinFunction::IntlDateTimeFormatResolvedOptions => 0,
506
+ BuiltinFunction::IntlNumberFormatFormat => 1,
507
+ BuiltinFunction::IntlNumberFormatResolvedOptions => 0,
508
+ BuiltinFunction::StringCtor => 1,
509
+ BuiltinFunction::StringTrim => 0,
510
+ BuiltinFunction::StringTrimStart => 0,
511
+ BuiltinFunction::StringTrimEnd => 0,
512
+ BuiltinFunction::StringIncludes => 1,
513
+ BuiltinFunction::StringStartsWith => 1,
514
+ BuiltinFunction::StringEndsWith => 1,
515
+ BuiltinFunction::StringIndexOf => 1,
516
+ BuiltinFunction::StringLastIndexOf => 1,
517
+ BuiltinFunction::StringCharAt => 1,
518
+ BuiltinFunction::StringAt => 1,
519
+ BuiltinFunction::StringSlice => 2,
520
+ BuiltinFunction::StringSubstring => 2,
521
+ BuiltinFunction::StringToLowerCase => 0,
522
+ BuiltinFunction::StringToUpperCase => 0,
523
+ BuiltinFunction::StringRepeat => 1,
524
+ BuiltinFunction::StringConcat => 1,
525
+ BuiltinFunction::StringPadStart => 1,
526
+ BuiltinFunction::StringPadEnd => 1,
527
+ BuiltinFunction::StringSplit => 2,
528
+ BuiltinFunction::StringReplace => 2,
529
+ BuiltinFunction::StringReplaceAll => 2,
530
+ BuiltinFunction::StringSearch => 1,
531
+ BuiltinFunction::StringMatch => 1,
532
+ BuiltinFunction::StringMatchAll => 1,
533
+ BuiltinFunction::StringToString => 0,
534
+ BuiltinFunction::StringValueOf => 0,
535
+ BuiltinFunction::BooleanCtor => 1,
536
+ BuiltinFunction::BooleanToString => 0,
537
+ BuiltinFunction::BooleanValueOf => 0,
538
+ BuiltinFunction::NumberToString => 0,
539
+ BuiltinFunction::NumberValueOf => 0,
540
+ BuiltinFunction::MathAbs => 1,
541
+ BuiltinFunction::MathMax => 2,
542
+ BuiltinFunction::MathMin => 2,
543
+ BuiltinFunction::MathFloor => 1,
544
+ BuiltinFunction::MathCeil => 1,
545
+ BuiltinFunction::MathRound => 1,
546
+ BuiltinFunction::MathPow => 2,
547
+ BuiltinFunction::MathSqrt => 1,
548
+ BuiltinFunction::MathTrunc => 1,
549
+ BuiltinFunction::MathSign => 1,
550
+ BuiltinFunction::MathLog => 1,
551
+ BuiltinFunction::MathExp => 1,
552
+ BuiltinFunction::MathLog2 => 1,
553
+ BuiltinFunction::MathLog10 => 1,
554
+ BuiltinFunction::MathSin => 1,
555
+ BuiltinFunction::MathCos => 1,
556
+ BuiltinFunction::MathAtan2 => 2,
557
+ BuiltinFunction::MathHypot => 2,
558
+ BuiltinFunction::MathCbrt => 1,
559
+ BuiltinFunction::MathRandom => 0,
560
+ BuiltinFunction::JsonStringify => 3,
561
+ BuiltinFunction::JsonParse => 2,
562
+ }
563
+ }
564
+
565
+ pub(super) fn builtin_function_own_property(
566
+ &self,
567
+ function: BuiltinFunction,
568
+ key: &str,
569
+ ) -> Option<Value> {
570
+ match key {
571
+ "name" => Some(Value::String(
572
+ Self::builtin_function_name(function).to_string(),
573
+ )),
574
+ "length" => Some(Value::Number(Self::builtin_function_length(function) as f64)),
575
+ "prototype" => self
576
+ .builtin_prototypes
577
+ .get(&function)
578
+ .copied()
579
+ .map(Value::Object),
580
+ _ => match function {
581
+ BuiltinFunction::ArrayCtor => match key {
582
+ "isArray" => Some(Value::BuiltinFunction(BuiltinFunction::ArrayIsArray)),
583
+ "from" => Some(Value::BuiltinFunction(BuiltinFunction::ArrayFrom)),
584
+ "of" => Some(Value::BuiltinFunction(BuiltinFunction::ArrayOf)),
585
+ _ => None,
586
+ },
587
+ BuiltinFunction::ObjectCtor => match key {
588
+ "assign" => Some(Value::BuiltinFunction(BuiltinFunction::ObjectAssign)),
589
+ "create" => Some(Value::BuiltinFunction(BuiltinFunction::ObjectCreate)),
590
+ "freeze" => Some(Value::BuiltinFunction(BuiltinFunction::ObjectFreeze)),
591
+ "seal" => Some(Value::BuiltinFunction(BuiltinFunction::ObjectSeal)),
592
+ "fromEntries" => {
593
+ Some(Value::BuiltinFunction(BuiltinFunction::ObjectFromEntries))
594
+ }
595
+ "keys" => Some(Value::BuiltinFunction(BuiltinFunction::ObjectKeys)),
596
+ "values" => Some(Value::BuiltinFunction(BuiltinFunction::ObjectValues)),
597
+ "entries" => Some(Value::BuiltinFunction(BuiltinFunction::ObjectEntries)),
598
+ "hasOwn" => Some(Value::BuiltinFunction(BuiltinFunction::ObjectHasOwn)),
599
+ _ => None,
600
+ },
601
+ BuiltinFunction::DateCtor if key == "now" => {
602
+ Some(Value::BuiltinFunction(BuiltinFunction::DateNow))
603
+ }
604
+ BuiltinFunction::NumberCtor => match key {
605
+ "parseInt" => Some(Value::BuiltinFunction(BuiltinFunction::NumberParseInt)),
606
+ "parseFloat" => Some(Value::BuiltinFunction(BuiltinFunction::NumberParseFloat)),
607
+ "isNaN" => Some(Value::BuiltinFunction(BuiltinFunction::NumberIsNaN)),
608
+ "isFinite" => Some(Value::BuiltinFunction(BuiltinFunction::NumberIsFinite)),
609
+ "isInteger" => Some(Value::BuiltinFunction(BuiltinFunction::NumberIsInteger)),
610
+ "isSafeInteger" => {
611
+ Some(Value::BuiltinFunction(BuiltinFunction::NumberIsSafeInteger))
612
+ }
613
+ "MAX_SAFE_INTEGER" => Some(Value::Number(9_007_199_254_740_991.0)),
614
+ "MIN_SAFE_INTEGER" => Some(Value::Number(-9_007_199_254_740_991.0)),
615
+ "EPSILON" => Some(Value::Number(f64::EPSILON)),
616
+ "MAX_VALUE" => Some(Value::Number(f64::MAX)),
617
+ "MIN_VALUE" => Some(Value::Number(f64::MIN_POSITIVE)),
618
+ "POSITIVE_INFINITY" => Some(Value::Number(f64::INFINITY)),
619
+ "NEGATIVE_INFINITY" => Some(Value::Number(f64::NEG_INFINITY)),
620
+ "NaN" => Some(Value::Number(f64::NAN)),
621
+ _ => None,
622
+ },
623
+ BuiltinFunction::PromiseCtor => match key {
624
+ "resolve" => Some(Value::BuiltinFunction(BuiltinFunction::PromiseResolve)),
625
+ "reject" => Some(Value::BuiltinFunction(BuiltinFunction::PromiseReject)),
626
+ "all" => Some(Value::BuiltinFunction(BuiltinFunction::PromiseAll)),
627
+ "race" => Some(Value::BuiltinFunction(BuiltinFunction::PromiseRace)),
628
+ "any" => Some(Value::BuiltinFunction(BuiltinFunction::PromiseAny)),
629
+ "allSettled" => {
630
+ Some(Value::BuiltinFunction(BuiltinFunction::PromiseAllSettled))
631
+ }
632
+ _ => None,
633
+ },
634
+ BuiltinFunction::IntlDateTimeFormatCtor if key == "supportedLocalesOf" => None,
635
+ BuiltinFunction::IntlNumberFormatCtor if key == "supportedLocalesOf" => None,
636
+ _ => None,
637
+ },
638
+ }
639
+ }
640
+
641
+ pub(super) fn has_property_in_supported_surface(
642
+ &self,
643
+ object: Value,
644
+ property: Value,
645
+ ) -> MustardResult<bool> {
646
+ let key = self.to_property_key(property)?;
647
+ match object {
648
+ Value::Object(object) => {
649
+ let object = self
650
+ .objects
651
+ .get(object)
652
+ .ok_or_else(|| MustardError::runtime("object missing"))?;
653
+ if object.properties.contains_key(&key) {
654
+ return Ok(true);
655
+ }
656
+ Ok(match &object.kind {
657
+ ObjectKind::FunctionPrototype(constructor) => {
658
+ key == "constructor"
659
+ || matches!(
660
+ (constructor, key.as_str()),
661
+ (
662
+ Value::BuiltinFunction(BuiltinFunction::DateCtor),
663
+ "getTime"
664
+ | "valueOf"
665
+ | "toISOString"
666
+ | "toJSON"
667
+ | "getUTCFullYear"
668
+ | "getUTCMonth"
669
+ | "getUTCDate"
670
+ | "getUTCHours"
671
+ | "getUTCMinutes"
672
+ | "getUTCSeconds"
673
+ )
674
+ )
675
+ }
676
+ ObjectKind::BoundFunction(_) => {
677
+ key == "name"
678
+ || key == "length"
679
+ || key == "constructor"
680
+ || matches!(key.as_str(), "call" | "apply" | "bind")
681
+ }
682
+ ObjectKind::Date(_) => matches!(
683
+ key.as_str(),
684
+ "getTime"
685
+ | "valueOf"
686
+ | "toISOString"
687
+ | "toJSON"
688
+ | "getUTCFullYear"
689
+ | "getUTCMonth"
690
+ | "getUTCDate"
691
+ | "getUTCHours"
692
+ | "getUTCMinutes"
693
+ | "getUTCSeconds"
694
+ ),
695
+ ObjectKind::RegExp(_) => matches!(
696
+ key.as_str(),
697
+ "source"
698
+ | "flags"
699
+ | "global"
700
+ | "ignoreCase"
701
+ | "multiline"
702
+ | "dotAll"
703
+ | "unicode"
704
+ | "sticky"
705
+ | "lastIndex"
706
+ | "exec"
707
+ | "test"
708
+ ),
709
+ ObjectKind::Intl => matches!(key.as_str(), "DateTimeFormat" | "NumberFormat"),
710
+ ObjectKind::IntlDateTimeFormat(_) => {
711
+ matches!(key.as_str(), "constructor" | "format" | "resolvedOptions")
712
+ }
713
+ ObjectKind::IntlNumberFormat(_) => {
714
+ matches!(key.as_str(), "constructor" | "format" | "resolvedOptions")
715
+ }
716
+ ObjectKind::StringObject(value) => {
717
+ key == "constructor"
718
+ || key == "length"
719
+ || matches!(
720
+ key.as_str(),
721
+ "trim"
722
+ | "trimStart"
723
+ | "trimEnd"
724
+ | "includes"
725
+ | "startsWith"
726
+ | "endsWith"
727
+ | "indexOf"
728
+ | "lastIndexOf"
729
+ | "charAt"
730
+ | "at"
731
+ | "slice"
732
+ | "substring"
733
+ | "toLowerCase"
734
+ | "toUpperCase"
735
+ | "repeat"
736
+ | "concat"
737
+ | "padStart"
738
+ | "padEnd"
739
+ | "split"
740
+ | "replace"
741
+ | "replaceAll"
742
+ | "search"
743
+ | "match"
744
+ | "matchAll"
745
+ | "toString"
746
+ | "valueOf"
747
+ )
748
+ || array_index_from_property_key(&key)
749
+ .is_some_and(|index| value.chars().nth(index).is_some())
750
+ }
751
+ ObjectKind::NumberObject(_) | ObjectKind::BooleanObject(_) => {
752
+ matches!(key.as_str(), "constructor" | "toString" | "valueOf")
753
+ }
754
+ ObjectKind::Console => self.console_method(&key).is_some(),
755
+ ObjectKind::Plain
756
+ | ObjectKind::Global
757
+ | ObjectKind::Math
758
+ | ObjectKind::Json
759
+ | ObjectKind::Error(_) => key == "constructor",
760
+ })
761
+ }
762
+ Value::Array(array) => {
763
+ let array = self
764
+ .arrays
765
+ .get(array)
766
+ .ok_or_else(|| MustardError::runtime("array missing"))?;
767
+ Ok(key == "length"
768
+ || key.parse::<usize>().ok().is_some_and(|index| {
769
+ array.elements.get(index).is_some_and(Option::is_some)
770
+ })
771
+ || array.properties.contains_key(&key)
772
+ || matches!(
773
+ key.as_str(),
774
+ "constructor"
775
+ | "sort"
776
+ | "push"
777
+ | "pop"
778
+ | "slice"
779
+ | "splice"
780
+ | "concat"
781
+ | "at"
782
+ | "join"
783
+ | "includes"
784
+ | "indexOf"
785
+ | "lastIndexOf"
786
+ | "reverse"
787
+ | "fill"
788
+ | "values"
789
+ | "keys"
790
+ | "entries"
791
+ | "forEach"
792
+ | "map"
793
+ | "filter"
794
+ | "find"
795
+ | "findIndex"
796
+ | "some"
797
+ | "every"
798
+ | "flat"
799
+ | "flatMap"
800
+ | "reduce"
801
+ | "reduceRight"
802
+ | "findLast"
803
+ | "findLastIndex"
804
+ ))
805
+ }
806
+ Value::Map(map) => {
807
+ self.maps
808
+ .get(map)
809
+ .ok_or_else(|| MustardError::runtime("map missing"))?;
810
+ Ok(matches!(
811
+ key.as_str(),
812
+ "constructor"
813
+ | "size"
814
+ | "get"
815
+ | "set"
816
+ | "has"
817
+ | "delete"
818
+ | "clear"
819
+ | "entries"
820
+ | "keys"
821
+ | "values"
822
+ | "forEach"
823
+ ))
824
+ }
825
+ Value::Set(set) => {
826
+ self.sets
827
+ .get(set)
828
+ .ok_or_else(|| MustardError::runtime("set missing"))?;
829
+ Ok(matches!(
830
+ key.as_str(),
831
+ "constructor"
832
+ | "size"
833
+ | "add"
834
+ | "has"
835
+ | "delete"
836
+ | "clear"
837
+ | "entries"
838
+ | "keys"
839
+ | "values"
840
+ | "forEach"
841
+ ))
842
+ }
843
+ Value::Iterator(iterator) => {
844
+ self.iterators
845
+ .get(iterator)
846
+ .ok_or_else(|| MustardError::runtime("iterator missing"))?;
847
+ Ok(matches!(key.as_str(), "constructor" | "next"))
848
+ }
849
+ Value::Promise(promise) => {
850
+ self.promises
851
+ .get(promise)
852
+ .ok_or_else(|| MustardError::runtime("promise missing"))?;
853
+ Ok(matches!(
854
+ key.as_str(),
855
+ "constructor" | "then" | "catch" | "finally"
856
+ ))
857
+ }
858
+ Value::BuiltinFunction(function) => Ok(self
859
+ .builtin_function_custom_property(function, &key)?
860
+ .is_some()
861
+ || self.builtin_function_own_property(function, &key).is_some()
862
+ || key == "constructor"
863
+ || Self::function_helper_method(&key).is_some()),
864
+ Value::Closure(closure) => Ok(self.closure_has_own_property(closure, &key)?
865
+ || key == "constructor"
866
+ || Self::function_helper_method(&key).is_some()),
867
+ Value::HostFunction(capability) => Ok(self
868
+ .host_function_custom_property(&capability, &key)?
869
+ .is_some()
870
+ || matches!(key.as_str(), "name" | "length" | "constructor")
871
+ || Self::function_helper_method(&key).is_some()),
872
+ Value::Undefined
873
+ | Value::Null
874
+ | Value::Bool(_)
875
+ | Value::Number(_)
876
+ | Value::String(_)
877
+ | Value::BigInt(_) => Err(MustardError::runtime(
878
+ "TypeError: right-hand side of 'in' must be an object in the supported surface",
879
+ )),
880
+ }
881
+ }
882
+
883
+ pub(super) fn create_iterator(&mut self, iterable: Value) -> MustardResult<Value> {
884
+ let iterator = match iterable {
885
+ Value::Array(array) => {
886
+ self.insert_iterator(IteratorState::Array(ArrayIteratorState {
887
+ array,
888
+ next_index: 0,
889
+ }))?
890
+ }
891
+ Value::String(value) => {
892
+ self.insert_iterator(IteratorState::String(StringIteratorState {
893
+ value,
894
+ next_index: 0,
895
+ }))?
896
+ }
897
+ Value::Map(map) => {
898
+ self.insert_iterator(IteratorState::MapEntries(MapIteratorState {
899
+ map,
900
+ next_index: 0,
901
+ }))?
902
+ }
903
+ Value::Set(set) => {
904
+ self.insert_iterator(IteratorState::SetValues(SetIteratorState {
905
+ set,
906
+ next_index: 0,
907
+ }))?
908
+ }
909
+ Value::Iterator(iterator) => iterator,
910
+ _ => {
911
+ return Err(MustardError::runtime(
912
+ "TypeError: value is not iterable in the supported surface",
913
+ ));
914
+ }
915
+ };
916
+ Ok(Value::Iterator(iterator))
917
+ }
918
+
919
+ pub(super) fn iterator_next(&mut self, iterator: Value) -> MustardResult<(Value, bool)> {
920
+ let key = match iterator {
921
+ Value::Iterator(key) => key,
922
+ _ => return Err(MustardError::runtime("value is not an iterator")),
923
+ };
924
+
925
+ let state = self
926
+ .iterators
927
+ .get(key)
928
+ .ok_or_else(|| MustardError::runtime("iterator missing"))?
929
+ .state
930
+ .clone();
931
+
932
+ let value = match state {
933
+ IteratorState::Array(state) => self
934
+ .arrays
935
+ .get(state.array)
936
+ .ok_or_else(|| MustardError::runtime("array missing"))?
937
+ .elements
938
+ .get(state.next_index)
939
+ .map(|value| value.clone().unwrap_or(Value::Undefined)),
940
+ IteratorState::ArrayKeys(state) => self
941
+ .arrays
942
+ .get(state.array)
943
+ .ok_or_else(|| MustardError::runtime("array missing"))?
944
+ .elements
945
+ .get(state.next_index)
946
+ .map(|_| Value::Number(state.next_index as f64)),
947
+ IteratorState::ArrayEntries(state) => {
948
+ let value = self
949
+ .arrays
950
+ .get(state.array)
951
+ .ok_or_else(|| MustardError::runtime("array missing"))?
952
+ .elements
953
+ .get(state.next_index)
954
+ .map(|value| value.clone().unwrap_or(Value::Undefined));
955
+ match value {
956
+ Some(value) => Some(Value::Array(self.insert_array(
957
+ vec![Value::Number(state.next_index as f64), value],
958
+ IndexMap::new(),
959
+ )?)),
960
+ None => None,
961
+ }
962
+ }
963
+ IteratorState::String(state) => {
964
+ let chars = state.value.chars().collect::<Vec<_>>();
965
+ chars
966
+ .get(state.next_index)
967
+ .map(|ch| Value::String(ch.to_string()))
968
+ }
969
+ IteratorState::MapEntries(state) => {
970
+ let entry = self
971
+ .maps
972
+ .get(state.map)
973
+ .ok_or_else(|| MustardError::runtime("map missing"))?
974
+ .entries
975
+ .get(state.next_index)
976
+ .cloned();
977
+ match entry {
978
+ Some(entry) => Some(Value::Array(
979
+ self.insert_array(vec![entry.key, entry.value], IndexMap::new())?,
980
+ )),
981
+ None => None,
982
+ }
983
+ }
984
+ IteratorState::MapKeys(state) => self
985
+ .maps
986
+ .get(state.map)
987
+ .ok_or_else(|| MustardError::runtime("map missing"))?
988
+ .entries
989
+ .get(state.next_index)
990
+ .map(|entry| entry.key.clone()),
991
+ IteratorState::MapValues(state) => self
992
+ .maps
993
+ .get(state.map)
994
+ .ok_or_else(|| MustardError::runtime("map missing"))?
995
+ .entries
996
+ .get(state.next_index)
997
+ .map(|entry| entry.value.clone()),
998
+ IteratorState::SetEntries(state) => self
999
+ .sets
1000
+ .get(state.set)
1001
+ .ok_or_else(|| MustardError::runtime("set missing"))?
1002
+ .entries
1003
+ .get(state.next_index)
1004
+ .cloned()
1005
+ .map(|value| {
1006
+ self.insert_array(vec![value.clone(), value], IndexMap::new())
1007
+ .map(Value::Array)
1008
+ })
1009
+ .transpose()?,
1010
+ IteratorState::SetValues(state) => self
1011
+ .sets
1012
+ .get(state.set)
1013
+ .ok_or_else(|| MustardError::runtime("set missing"))?
1014
+ .entries
1015
+ .get(state.next_index)
1016
+ .cloned(),
1017
+ };
1018
+
1019
+ if value.is_some() {
1020
+ if let Some(iterator) = self.iterators.get_mut(key) {
1021
+ match &mut iterator.state {
1022
+ IteratorState::Array(state)
1023
+ | IteratorState::ArrayKeys(state)
1024
+ | IteratorState::ArrayEntries(state) => state.next_index += 1,
1025
+ IteratorState::String(state) => state.next_index += 1,
1026
+ IteratorState::MapEntries(state)
1027
+ | IteratorState::MapKeys(state)
1028
+ | IteratorState::MapValues(state) => state.next_index += 1,
1029
+ IteratorState::SetEntries(state) | IteratorState::SetValues(state) => {
1030
+ state.next_index += 1
1031
+ }
1032
+ }
1033
+ }
1034
+ self.refresh_iterator_accounting(key)?;
1035
+ }
1036
+
1037
+ Ok(match value {
1038
+ Some(value) => (value, false),
1039
+ None => (Value::Undefined, true),
1040
+ })
1041
+ }
1042
+
1043
+ pub(super) fn get_property(
1044
+ &self,
1045
+ object: Value,
1046
+ property: Value,
1047
+ optional: bool,
1048
+ ) -> MustardResult<Value> {
1049
+ if optional && matches!(object, Value::Null | Value::Undefined) {
1050
+ return Ok(Value::Undefined);
1051
+ }
1052
+ let key = self.to_property_key(property)?;
1053
+ match object {
1054
+ Value::Object(object) => {
1055
+ let object = self
1056
+ .objects
1057
+ .get(object)
1058
+ .ok_or_else(|| MustardError::runtime("object missing"))?;
1059
+ if let ObjectKind::Date(_) = &object.kind {
1060
+ let built_in = match key.as_str() {
1061
+ "getTime" => Some(Value::BuiltinFunction(BuiltinFunction::DateGetTime)),
1062
+ "valueOf" => Some(Value::BuiltinFunction(BuiltinFunction::DateValueOf)),
1063
+ "toISOString" => {
1064
+ Some(Value::BuiltinFunction(BuiltinFunction::DateToISOString))
1065
+ }
1066
+ "toJSON" => Some(Value::BuiltinFunction(BuiltinFunction::DateToJSON)),
1067
+ "getUTCFullYear" => {
1068
+ Some(Value::BuiltinFunction(BuiltinFunction::DateGetUTCFullYear))
1069
+ }
1070
+ "getUTCMonth" => {
1071
+ Some(Value::BuiltinFunction(BuiltinFunction::DateGetUTCMonth))
1072
+ }
1073
+ "getUTCDate" => {
1074
+ Some(Value::BuiltinFunction(BuiltinFunction::DateGetUTCDate))
1075
+ }
1076
+ "getUTCHours" => {
1077
+ Some(Value::BuiltinFunction(BuiltinFunction::DateGetUTCHours))
1078
+ }
1079
+ "getUTCMinutes" => {
1080
+ Some(Value::BuiltinFunction(BuiltinFunction::DateGetUTCMinutes))
1081
+ }
1082
+ "getUTCSeconds" => {
1083
+ Some(Value::BuiltinFunction(BuiltinFunction::DateGetUTCSeconds))
1084
+ }
1085
+ "constructor" => Some(Value::BuiltinFunction(BuiltinFunction::DateCtor)),
1086
+ _ => None,
1087
+ };
1088
+ if let Some(value) = built_in {
1089
+ return Ok(value);
1090
+ }
1091
+ }
1092
+ if let ObjectKind::RegExp(regex) = &object.kind {
1093
+ let built_in = match key.as_str() {
1094
+ "source" => Some(Value::String(regex.pattern.clone())),
1095
+ "flags" => Some(Value::String(regex.flags.clone())),
1096
+ "global" => Some(Value::Bool(regex.flags.contains('g'))),
1097
+ "ignoreCase" => Some(Value::Bool(regex.flags.contains('i'))),
1098
+ "multiline" => Some(Value::Bool(regex.flags.contains('m'))),
1099
+ "dotAll" => Some(Value::Bool(regex.flags.contains('s'))),
1100
+ "unicode" => Some(Value::Bool(regex.flags.contains('u'))),
1101
+ "sticky" => Some(Value::Bool(regex.flags.contains('y'))),
1102
+ "lastIndex" => Some(Value::Number(regex.last_index as f64)),
1103
+ "exec" => Some(Value::BuiltinFunction(BuiltinFunction::RegExpExec)),
1104
+ "test" => Some(Value::BuiltinFunction(BuiltinFunction::RegExpTest)),
1105
+ "constructor" => Some(Value::BuiltinFunction(BuiltinFunction::RegExpCtor)),
1106
+ _ => None,
1107
+ };
1108
+ if let Some(value) = built_in {
1109
+ return Ok(value);
1110
+ }
1111
+ }
1112
+ if let ObjectKind::StringObject(value) = &object.kind {
1113
+ if key == "length" {
1114
+ return Ok(Value::Number(value.chars().count() as f64));
1115
+ }
1116
+ if let Some(index) = array_index_from_property_key(&key)
1117
+ && let Some(ch) = value.chars().nth(index)
1118
+ {
1119
+ return Ok(Value::String(ch.to_string()));
1120
+ }
1121
+ if let Some(method) = match key.as_str() {
1122
+ "trim" => Some(Value::BuiltinFunction(BuiltinFunction::StringTrim)),
1123
+ "trimStart" => {
1124
+ Some(Value::BuiltinFunction(BuiltinFunction::StringTrimStart))
1125
+ }
1126
+ "trimEnd" => Some(Value::BuiltinFunction(BuiltinFunction::StringTrimEnd)),
1127
+ "includes" => Some(Value::BuiltinFunction(BuiltinFunction::StringIncludes)),
1128
+ "startsWith" => {
1129
+ Some(Value::BuiltinFunction(BuiltinFunction::StringStartsWith))
1130
+ }
1131
+ "endsWith" => Some(Value::BuiltinFunction(BuiltinFunction::StringEndsWith)),
1132
+ "indexOf" => Some(Value::BuiltinFunction(BuiltinFunction::StringIndexOf)),
1133
+ "lastIndexOf" => {
1134
+ Some(Value::BuiltinFunction(BuiltinFunction::StringLastIndexOf))
1135
+ }
1136
+ "charAt" => Some(Value::BuiltinFunction(BuiltinFunction::StringCharAt)),
1137
+ "at" => Some(Value::BuiltinFunction(BuiltinFunction::StringAt)),
1138
+ "slice" => Some(Value::BuiltinFunction(BuiltinFunction::StringSlice)),
1139
+ "substring" => {
1140
+ Some(Value::BuiltinFunction(BuiltinFunction::StringSubstring))
1141
+ }
1142
+ "toLowerCase" => {
1143
+ Some(Value::BuiltinFunction(BuiltinFunction::StringToLowerCase))
1144
+ }
1145
+ "toUpperCase" => {
1146
+ Some(Value::BuiltinFunction(BuiltinFunction::StringToUpperCase))
1147
+ }
1148
+ "repeat" => Some(Value::BuiltinFunction(BuiltinFunction::StringRepeat)),
1149
+ "concat" => Some(Value::BuiltinFunction(BuiltinFunction::StringConcat)),
1150
+ "padStart" => Some(Value::BuiltinFunction(BuiltinFunction::StringPadStart)),
1151
+ "padEnd" => Some(Value::BuiltinFunction(BuiltinFunction::StringPadEnd)),
1152
+ "split" => Some(Value::BuiltinFunction(BuiltinFunction::StringSplit)),
1153
+ "replace" => Some(Value::BuiltinFunction(BuiltinFunction::StringReplace)),
1154
+ "replaceAll" => {
1155
+ Some(Value::BuiltinFunction(BuiltinFunction::StringReplaceAll))
1156
+ }
1157
+ "search" => Some(Value::BuiltinFunction(BuiltinFunction::StringSearch)),
1158
+ "match" => Some(Value::BuiltinFunction(BuiltinFunction::StringMatch)),
1159
+ "matchAll" => Some(Value::BuiltinFunction(BuiltinFunction::StringMatchAll)),
1160
+ "toString" => Some(Value::BuiltinFunction(BuiltinFunction::StringToString)),
1161
+ "valueOf" => Some(Value::BuiltinFunction(BuiltinFunction::StringValueOf)),
1162
+ _ => None,
1163
+ } {
1164
+ return Ok(method);
1165
+ }
1166
+ }
1167
+ if let ObjectKind::NumberObject(_) = &object.kind {
1168
+ match key.as_str() {
1169
+ "toString" => {
1170
+ return Ok(Value::BuiltinFunction(BuiltinFunction::NumberToString));
1171
+ }
1172
+ "valueOf" => {
1173
+ return Ok(Value::BuiltinFunction(BuiltinFunction::NumberValueOf));
1174
+ }
1175
+ _ => {}
1176
+ }
1177
+ }
1178
+ if let ObjectKind::BooleanObject(_) = &object.kind {
1179
+ match key.as_str() {
1180
+ "toString" => {
1181
+ return Ok(Value::BuiltinFunction(BuiltinFunction::BooleanToString));
1182
+ }
1183
+ "valueOf" => {
1184
+ return Ok(Value::BuiltinFunction(BuiltinFunction::BooleanValueOf));
1185
+ }
1186
+ _ => {}
1187
+ }
1188
+ }
1189
+ if matches!(object.kind, ObjectKind::Intl) {
1190
+ let built_in = match key.as_str() {
1191
+ "DateTimeFormat" => Some(Value::BuiltinFunction(
1192
+ BuiltinFunction::IntlDateTimeFormatCtor,
1193
+ )),
1194
+ "NumberFormat" => Some(Value::BuiltinFunction(
1195
+ BuiltinFunction::IntlNumberFormatCtor,
1196
+ )),
1197
+ "constructor" => Some(Value::BuiltinFunction(BuiltinFunction::ObjectCtor)),
1198
+ _ => None,
1199
+ };
1200
+ if let Some(value) = built_in {
1201
+ return Ok(value);
1202
+ }
1203
+ }
1204
+ if matches!(object.kind, ObjectKind::IntlDateTimeFormat(_)) {
1205
+ let built_in = match key.as_str() {
1206
+ "constructor" => Some(Value::BuiltinFunction(
1207
+ BuiltinFunction::IntlDateTimeFormatCtor,
1208
+ )),
1209
+ "format" => Some(Value::BuiltinFunction(
1210
+ BuiltinFunction::IntlDateTimeFormatFormat,
1211
+ )),
1212
+ "resolvedOptions" => Some(Value::BuiltinFunction(
1213
+ BuiltinFunction::IntlDateTimeFormatResolvedOptions,
1214
+ )),
1215
+ _ => None,
1216
+ };
1217
+ if let Some(value) = built_in {
1218
+ return Ok(value);
1219
+ }
1220
+ }
1221
+ if matches!(object.kind, ObjectKind::IntlNumberFormat(_)) {
1222
+ let built_in = match key.as_str() {
1223
+ "constructor" => Some(Value::BuiltinFunction(
1224
+ BuiltinFunction::IntlNumberFormatCtor,
1225
+ )),
1226
+ "format" => Some(Value::BuiltinFunction(
1227
+ BuiltinFunction::IntlNumberFormatFormat,
1228
+ )),
1229
+ "resolvedOptions" => Some(Value::BuiltinFunction(
1230
+ BuiltinFunction::IntlNumberFormatResolvedOptions,
1231
+ )),
1232
+ _ => None,
1233
+ };
1234
+ if let Some(value) = built_in {
1235
+ return Ok(value);
1236
+ }
1237
+ }
1238
+ if let Some(value) = object.properties.get(&key) {
1239
+ return Ok(value.clone());
1240
+ }
1241
+ if let ObjectKind::FunctionPrototype(constructor) = &object.kind {
1242
+ if key == "constructor" {
1243
+ return Ok(constructor.clone());
1244
+ }
1245
+ if matches!(
1246
+ constructor,
1247
+ Value::BuiltinFunction(BuiltinFunction::DateCtor)
1248
+ ) {
1249
+ match key.as_str() {
1250
+ "getTime" => {
1251
+ return Ok(Value::BuiltinFunction(BuiltinFunction::DateGetTime));
1252
+ }
1253
+ "valueOf" => {
1254
+ return Ok(Value::BuiltinFunction(BuiltinFunction::DateValueOf));
1255
+ }
1256
+ "toISOString" => {
1257
+ return Ok(Value::BuiltinFunction(
1258
+ BuiltinFunction::DateToISOString,
1259
+ ));
1260
+ }
1261
+ "toJSON" => {
1262
+ return Ok(Value::BuiltinFunction(BuiltinFunction::DateToJSON));
1263
+ }
1264
+ "getUTCFullYear" => {
1265
+ return Ok(Value::BuiltinFunction(
1266
+ BuiltinFunction::DateGetUTCFullYear,
1267
+ ));
1268
+ }
1269
+ "getUTCMonth" => {
1270
+ return Ok(Value::BuiltinFunction(
1271
+ BuiltinFunction::DateGetUTCMonth,
1272
+ ));
1273
+ }
1274
+ "getUTCDate" => {
1275
+ return Ok(Value::BuiltinFunction(BuiltinFunction::DateGetUTCDate));
1276
+ }
1277
+ "getUTCHours" => {
1278
+ return Ok(Value::BuiltinFunction(
1279
+ BuiltinFunction::DateGetUTCHours,
1280
+ ));
1281
+ }
1282
+ "getUTCMinutes" => {
1283
+ return Ok(Value::BuiltinFunction(
1284
+ BuiltinFunction::DateGetUTCMinutes,
1285
+ ));
1286
+ }
1287
+ "getUTCSeconds" => {
1288
+ return Ok(Value::BuiltinFunction(
1289
+ BuiltinFunction::DateGetUTCSeconds,
1290
+ ));
1291
+ }
1292
+ _ => {}
1293
+ }
1294
+ }
1295
+ }
1296
+ if let ObjectKind::BoundFunction(bound) = &object.kind {
1297
+ match key.as_str() {
1298
+ "name" => {
1299
+ return Ok(Value::String(format!(
1300
+ "bound {}",
1301
+ self.callable_name(&bound.target)?
1302
+ )));
1303
+ }
1304
+ "length" => {
1305
+ let length = self
1306
+ .callable_length(&bound.target)?
1307
+ .saturating_sub(bound.args.len());
1308
+ return Ok(Value::Number(length as f64));
1309
+ }
1310
+ "constructor" => return Ok(Self::callable_constructor()),
1311
+ _ => {
1312
+ if let Some(method) = Self::function_helper_method(&key) {
1313
+ return Ok(method);
1314
+ }
1315
+ }
1316
+ }
1317
+ }
1318
+ if let ObjectKind::StringObject(_) = &object.kind
1319
+ && key == "constructor"
1320
+ {
1321
+ return Ok(Value::BuiltinFunction(BuiltinFunction::StringCtor));
1322
+ }
1323
+ if let ObjectKind::NumberObject(_) = &object.kind
1324
+ && key == "constructor"
1325
+ {
1326
+ return Ok(Value::BuiltinFunction(BuiltinFunction::NumberCtor));
1327
+ }
1328
+ if let ObjectKind::BooleanObject(_) = &object.kind
1329
+ && key == "constructor"
1330
+ {
1331
+ return Ok(Value::BuiltinFunction(BuiltinFunction::BooleanCtor));
1332
+ }
1333
+ if matches!(object.kind, ObjectKind::Console)
1334
+ && let Some(value) = self.console_method(&key)
1335
+ {
1336
+ return Ok(value);
1337
+ }
1338
+ if key == "constructor" {
1339
+ match &object.kind {
1340
+ ObjectKind::Plain
1341
+ | ObjectKind::Global
1342
+ | ObjectKind::Math
1343
+ | ObjectKind::Json
1344
+ | ObjectKind::Intl
1345
+ | ObjectKind::BoundFunction(_) => {
1346
+ return Ok(Value::BuiltinFunction(BuiltinFunction::ObjectCtor));
1347
+ }
1348
+ ObjectKind::Error(name) => {
1349
+ let ctor = match name.as_str() {
1350
+ "TypeError" => BuiltinFunction::TypeErrorCtor,
1351
+ "ReferenceError" => BuiltinFunction::ReferenceErrorCtor,
1352
+ "RangeError" => BuiltinFunction::RangeErrorCtor,
1353
+ "SyntaxError" => BuiltinFunction::SyntaxErrorCtor,
1354
+ _ => BuiltinFunction::ErrorCtor,
1355
+ };
1356
+ return Ok(Value::BuiltinFunction(ctor));
1357
+ }
1358
+ _ => {}
1359
+ }
1360
+ }
1361
+ Ok(Value::Undefined)
1362
+ }
1363
+ Value::Array(array) => {
1364
+ let array = self
1365
+ .arrays
1366
+ .get(array)
1367
+ .ok_or_else(|| MustardError::runtime("array missing"))?;
1368
+ if key == "length" {
1369
+ Ok(Value::Number(array.elements.len() as f64))
1370
+ } else if key == "constructor" {
1371
+ Ok(Value::BuiltinFunction(BuiltinFunction::ArrayCtor))
1372
+ } else if let Some(index) = array_index_from_property_key(&key) {
1373
+ Ok(array
1374
+ .elements
1375
+ .get(index)
1376
+ .cloned()
1377
+ .flatten()
1378
+ .unwrap_or(Value::Undefined))
1379
+ } else if let Some(value) = array.properties.get(&key) {
1380
+ Ok(value.clone())
1381
+ } else {
1382
+ match key.as_str() {
1383
+ "sort" => Ok(Value::BuiltinFunction(BuiltinFunction::ArraySort)),
1384
+ "push" => Ok(Value::BuiltinFunction(BuiltinFunction::ArrayPush)),
1385
+ "pop" => Ok(Value::BuiltinFunction(BuiltinFunction::ArrayPop)),
1386
+ "slice" => Ok(Value::BuiltinFunction(BuiltinFunction::ArraySlice)),
1387
+ "splice" => Ok(Value::BuiltinFunction(BuiltinFunction::ArraySplice)),
1388
+ "concat" => Ok(Value::BuiltinFunction(BuiltinFunction::ArrayConcat)),
1389
+ "at" => Ok(Value::BuiltinFunction(BuiltinFunction::ArrayAt)),
1390
+ "join" => Ok(Value::BuiltinFunction(BuiltinFunction::ArrayJoin)),
1391
+ "includes" => Ok(Value::BuiltinFunction(BuiltinFunction::ArrayIncludes)),
1392
+ "indexOf" => Ok(Value::BuiltinFunction(BuiltinFunction::ArrayIndexOf)),
1393
+ "lastIndexOf" => {
1394
+ Ok(Value::BuiltinFunction(BuiltinFunction::ArrayLastIndexOf))
1395
+ }
1396
+ "reverse" => Ok(Value::BuiltinFunction(BuiltinFunction::ArrayReverse)),
1397
+ "fill" => Ok(Value::BuiltinFunction(BuiltinFunction::ArrayFill)),
1398
+ "values" => Ok(Value::BuiltinFunction(BuiltinFunction::ArrayValues)),
1399
+ "keys" => Ok(Value::BuiltinFunction(BuiltinFunction::ArrayKeys)),
1400
+ "entries" => Ok(Value::BuiltinFunction(BuiltinFunction::ArrayEntries)),
1401
+ "forEach" => Ok(Value::BuiltinFunction(BuiltinFunction::ArrayForEach)),
1402
+ "map" => Ok(Value::BuiltinFunction(BuiltinFunction::ArrayMap)),
1403
+ "filter" => Ok(Value::BuiltinFunction(BuiltinFunction::ArrayFilter)),
1404
+ "find" => Ok(Value::BuiltinFunction(BuiltinFunction::ArrayFind)),
1405
+ "findIndex" => Ok(Value::BuiltinFunction(BuiltinFunction::ArrayFindIndex)),
1406
+ "some" => Ok(Value::BuiltinFunction(BuiltinFunction::ArraySome)),
1407
+ "every" => Ok(Value::BuiltinFunction(BuiltinFunction::ArrayEvery)),
1408
+ "flat" => Ok(Value::BuiltinFunction(BuiltinFunction::ArrayFlat)),
1409
+ "flatMap" => Ok(Value::BuiltinFunction(BuiltinFunction::ArrayFlatMap)),
1410
+ "reduce" => Ok(Value::BuiltinFunction(BuiltinFunction::ArrayReduce)),
1411
+ "reduceRight" => {
1412
+ Ok(Value::BuiltinFunction(BuiltinFunction::ArrayReduceRight))
1413
+ }
1414
+ "findLast" => Ok(Value::BuiltinFunction(BuiltinFunction::ArrayFindLast)),
1415
+ "findLastIndex" => {
1416
+ Ok(Value::BuiltinFunction(BuiltinFunction::ArrayFindLastIndex))
1417
+ }
1418
+ _ => Ok(Value::Undefined),
1419
+ }
1420
+ }
1421
+ }
1422
+ Value::Map(map) => {
1423
+ let map = self
1424
+ .maps
1425
+ .get(map)
1426
+ .ok_or_else(|| MustardError::runtime("map missing"))?;
1427
+ match key.as_str() {
1428
+ "constructor" => Ok(Value::BuiltinFunction(BuiltinFunction::MapCtor)),
1429
+ "size" => Ok(Value::Number(map.entries.len() as f64)),
1430
+ "get" => Ok(Value::BuiltinFunction(BuiltinFunction::MapGet)),
1431
+ "set" => Ok(Value::BuiltinFunction(BuiltinFunction::MapSet)),
1432
+ "has" => Ok(Value::BuiltinFunction(BuiltinFunction::MapHas)),
1433
+ "delete" => Ok(Value::BuiltinFunction(BuiltinFunction::MapDelete)),
1434
+ "clear" => Ok(Value::BuiltinFunction(BuiltinFunction::MapClear)),
1435
+ "entries" => Ok(Value::BuiltinFunction(BuiltinFunction::MapEntries)),
1436
+ "keys" => Ok(Value::BuiltinFunction(BuiltinFunction::MapKeys)),
1437
+ "values" => Ok(Value::BuiltinFunction(BuiltinFunction::MapValues)),
1438
+ "forEach" => Ok(Value::BuiltinFunction(BuiltinFunction::MapForEach)),
1439
+ _ => Ok(Value::Undefined),
1440
+ }
1441
+ }
1442
+ Value::Set(set) => {
1443
+ let set = self
1444
+ .sets
1445
+ .get(set)
1446
+ .ok_or_else(|| MustardError::runtime("set missing"))?;
1447
+ match key.as_str() {
1448
+ "constructor" => Ok(Value::BuiltinFunction(BuiltinFunction::SetCtor)),
1449
+ "size" => Ok(Value::Number(set.entries.len() as f64)),
1450
+ "add" => Ok(Value::BuiltinFunction(BuiltinFunction::SetAdd)),
1451
+ "has" => Ok(Value::BuiltinFunction(BuiltinFunction::SetHas)),
1452
+ "delete" => Ok(Value::BuiltinFunction(BuiltinFunction::SetDelete)),
1453
+ "clear" => Ok(Value::BuiltinFunction(BuiltinFunction::SetClear)),
1454
+ "entries" => Ok(Value::BuiltinFunction(BuiltinFunction::SetEntries)),
1455
+ "keys" => Ok(Value::BuiltinFunction(BuiltinFunction::SetKeys)),
1456
+ "values" => Ok(Value::BuiltinFunction(BuiltinFunction::SetValues)),
1457
+ "forEach" => Ok(Value::BuiltinFunction(BuiltinFunction::SetForEach)),
1458
+ _ => Ok(Value::Undefined),
1459
+ }
1460
+ }
1461
+ Value::Iterator(_) if key == "next" => {
1462
+ Ok(Value::BuiltinFunction(BuiltinFunction::IteratorNext))
1463
+ }
1464
+ Value::Iterator(_) if key == "constructor" => {
1465
+ Ok(Value::BuiltinFunction(BuiltinFunction::ObjectCtor))
1466
+ }
1467
+ Value::Iterator(_) => Ok(Value::Undefined),
1468
+ Value::Promise(_) => match key.as_str() {
1469
+ "constructor" => Ok(Value::BuiltinFunction(BuiltinFunction::PromiseCtor)),
1470
+ "then" => Ok(Value::BuiltinFunction(BuiltinFunction::PromiseThen)),
1471
+ "catch" => Ok(Value::BuiltinFunction(BuiltinFunction::PromiseCatch)),
1472
+ "finally" => Ok(Value::BuiltinFunction(BuiltinFunction::PromiseFinally)),
1473
+ _ => Ok(Value::Undefined),
1474
+ },
1475
+ Value::BuiltinFunction(function) => {
1476
+ if let Some(value) = self.builtin_function_custom_property(function, &key)? {
1477
+ return Ok(value);
1478
+ }
1479
+ if let Some(value) = self.builtin_function_own_property(function, &key) {
1480
+ return Ok(value);
1481
+ }
1482
+ if key == "constructor" {
1483
+ return Ok(Self::callable_constructor());
1484
+ }
1485
+ Ok(Self::function_helper_method(&key).unwrap_or(Value::Undefined))
1486
+ }
1487
+ Value::Closure(closure) => {
1488
+ if let Some(value) = self.closure_own_property(closure, &key)? {
1489
+ return Ok(value);
1490
+ }
1491
+ if key == "constructor" {
1492
+ return Ok(Self::callable_constructor());
1493
+ }
1494
+ Ok(Self::function_helper_method(&key).unwrap_or(Value::Undefined))
1495
+ }
1496
+ Value::HostFunction(capability) => {
1497
+ if let Some(value) = self.host_function_custom_property(&capability, &key)? {
1498
+ return Ok(value);
1499
+ }
1500
+ match key.as_str() {
1501
+ "name" => Ok(Value::String(capability)),
1502
+ "length" => Ok(Value::Number(0.0)),
1503
+ "constructor" => Ok(Self::callable_constructor()),
1504
+ _ => Ok(Self::function_helper_method(&key).unwrap_or(Value::Undefined)),
1505
+ }
1506
+ }
1507
+ Value::String(value) => match key.as_str() {
1508
+ "length" => Ok(Value::Number(value.chars().count() as f64)),
1509
+ "constructor" => Ok(Value::BuiltinFunction(BuiltinFunction::StringCtor)),
1510
+ "trim" => Ok(Value::BuiltinFunction(BuiltinFunction::StringTrim)),
1511
+ "trimStart" => Ok(Value::BuiltinFunction(BuiltinFunction::StringTrimStart)),
1512
+ "trimEnd" => Ok(Value::BuiltinFunction(BuiltinFunction::StringTrimEnd)),
1513
+ "includes" => Ok(Value::BuiltinFunction(BuiltinFunction::StringIncludes)),
1514
+ "startsWith" => Ok(Value::BuiltinFunction(BuiltinFunction::StringStartsWith)),
1515
+ "endsWith" => Ok(Value::BuiltinFunction(BuiltinFunction::StringEndsWith)),
1516
+ "indexOf" => Ok(Value::BuiltinFunction(BuiltinFunction::StringIndexOf)),
1517
+ "lastIndexOf" => Ok(Value::BuiltinFunction(BuiltinFunction::StringLastIndexOf)),
1518
+ "charAt" => Ok(Value::BuiltinFunction(BuiltinFunction::StringCharAt)),
1519
+ "at" => Ok(Value::BuiltinFunction(BuiltinFunction::StringAt)),
1520
+ "slice" => Ok(Value::BuiltinFunction(BuiltinFunction::StringSlice)),
1521
+ "substring" => Ok(Value::BuiltinFunction(BuiltinFunction::StringSubstring)),
1522
+ "toLowerCase" => Ok(Value::BuiltinFunction(BuiltinFunction::StringToLowerCase)),
1523
+ "toUpperCase" => Ok(Value::BuiltinFunction(BuiltinFunction::StringToUpperCase)),
1524
+ "repeat" => Ok(Value::BuiltinFunction(BuiltinFunction::StringRepeat)),
1525
+ "concat" => Ok(Value::BuiltinFunction(BuiltinFunction::StringConcat)),
1526
+ "padStart" => Ok(Value::BuiltinFunction(BuiltinFunction::StringPadStart)),
1527
+ "padEnd" => Ok(Value::BuiltinFunction(BuiltinFunction::StringPadEnd)),
1528
+ "split" => Ok(Value::BuiltinFunction(BuiltinFunction::StringSplit)),
1529
+ "replace" => Ok(Value::BuiltinFunction(BuiltinFunction::StringReplace)),
1530
+ "replaceAll" => Ok(Value::BuiltinFunction(BuiltinFunction::StringReplaceAll)),
1531
+ "search" => Ok(Value::BuiltinFunction(BuiltinFunction::StringSearch)),
1532
+ "match" => Ok(Value::BuiltinFunction(BuiltinFunction::StringMatch)),
1533
+ "matchAll" => Ok(Value::BuiltinFunction(BuiltinFunction::StringMatchAll)),
1534
+ "toString" => Ok(Value::BuiltinFunction(BuiltinFunction::StringToString)),
1535
+ "valueOf" => Ok(Value::BuiltinFunction(BuiltinFunction::StringValueOf)),
1536
+ _ if array_index_from_property_key(&key)
1537
+ .is_some_and(|index| value.chars().nth(index).is_some()) =>
1538
+ {
1539
+ let index = array_index_from_property_key(&key).expect("index already checked");
1540
+ Ok(Value::String(
1541
+ value
1542
+ .chars()
1543
+ .nth(index)
1544
+ .expect("index already checked")
1545
+ .to_string(),
1546
+ ))
1547
+ }
1548
+ _ => Ok(Value::Undefined),
1549
+ },
1550
+ Value::Number(_) => match key.as_str() {
1551
+ "constructor" => Ok(Value::BuiltinFunction(BuiltinFunction::NumberCtor)),
1552
+ "toString" => Ok(Value::BuiltinFunction(BuiltinFunction::NumberToString)),
1553
+ "valueOf" => Ok(Value::BuiltinFunction(BuiltinFunction::NumberValueOf)),
1554
+ _ => Ok(Value::Undefined),
1555
+ },
1556
+ Value::Bool(_) => match key.as_str() {
1557
+ "constructor" => Ok(Value::BuiltinFunction(BuiltinFunction::BooleanCtor)),
1558
+ "toString" => Ok(Value::BuiltinFunction(BuiltinFunction::BooleanToString)),
1559
+ "valueOf" => Ok(Value::BuiltinFunction(BuiltinFunction::BooleanValueOf)),
1560
+ _ => Ok(Value::Undefined),
1561
+ },
1562
+ Value::Null | Value::Undefined => Err(MustardError::runtime(
1563
+ "TypeError: cannot read properties of nullish value",
1564
+ )),
1565
+ _ => Ok(Value::Undefined),
1566
+ }
1567
+ }
1568
+
1569
+ pub(super) fn callable_name(&self, value: &Value) -> MustardResult<String> {
1570
+ Ok(match value {
1571
+ Value::Closure(closure) => match self.closure_own_property(*closure, "name")? {
1572
+ Some(Value::String(name)) => name,
1573
+ _ => String::new(),
1574
+ },
1575
+ Value::BuiltinFunction(function) => Self::builtin_function_name(*function).to_string(),
1576
+ Value::HostFunction(capability) => capability.clone(),
1577
+ Value::Object(object) => match &self
1578
+ .objects
1579
+ .get(*object)
1580
+ .ok_or_else(|| MustardError::runtime("object missing"))?
1581
+ .kind
1582
+ {
1583
+ ObjectKind::BoundFunction(bound) => {
1584
+ format!("bound {}", self.callable_name(&bound.target)?)
1585
+ }
1586
+ _ => String::new(),
1587
+ },
1588
+ _ => String::new(),
1589
+ })
1590
+ }
1591
+
1592
+ fn callable_length(&self, value: &Value) -> MustardResult<usize> {
1593
+ Ok(match value {
1594
+ Value::Closure(closure) => match self.closure_own_property(*closure, "length")? {
1595
+ Some(Value::Number(length)) => length.max(0.0) as usize,
1596
+ _ => 0,
1597
+ },
1598
+ Value::BuiltinFunction(function) => Self::builtin_function_length(*function),
1599
+ Value::HostFunction(_) => 0,
1600
+ Value::Object(object) => match &self
1601
+ .objects
1602
+ .get(*object)
1603
+ .ok_or_else(|| MustardError::runtime("object missing"))?
1604
+ .kind
1605
+ {
1606
+ ObjectKind::BoundFunction(bound) => self
1607
+ .callable_length(&bound.target)?
1608
+ .saturating_sub(bound.args.len()),
1609
+ _ => 0,
1610
+ },
1611
+ _ => 0,
1612
+ })
1613
+ }
1614
+
1615
+ pub(super) fn set_property(
1616
+ &mut self,
1617
+ object: Value,
1618
+ property: Value,
1619
+ value: Value,
1620
+ ) -> MustardResult<()> {
1621
+ let key = self.to_property_key(property)?;
1622
+ self.infer_closure_name(&value, &key)?;
1623
+ match object {
1624
+ Value::Object(object) => {
1625
+ if self.is_regexp_object(object) && key == "lastIndex" {
1626
+ let index = self.to_integer(value.clone())?.max(0) as usize;
1627
+ self.regexp_object_mut(object)?.last_index = index;
1628
+ self.refresh_object_accounting(object)?;
1629
+ return Ok(());
1630
+ }
1631
+ self.objects
1632
+ .get_mut(object)
1633
+ .ok_or_else(|| MustardError::runtime("object missing"))?
1634
+ .properties
1635
+ .insert(key, value);
1636
+ self.refresh_object_accounting(object)?;
1637
+ Ok(())
1638
+ }
1639
+ Value::Array(array) => {
1640
+ if key == "length" {
1641
+ self.set_array_length(array, value)?;
1642
+ return Ok(());
1643
+ }
1644
+ {
1645
+ let array_ref = self
1646
+ .arrays
1647
+ .get_mut(array)
1648
+ .ok_or_else(|| MustardError::runtime("array missing"))?;
1649
+ if let Some(index) = array_index_from_property_key(&key) {
1650
+ if index >= array_ref.elements.len() {
1651
+ array_ref.elements.resize(index + 1, None);
1652
+ }
1653
+ array_ref.elements[index] = Some(value);
1654
+ } else {
1655
+ array_ref.properties.insert(key, value);
1656
+ }
1657
+ }
1658
+ self.refresh_array_accounting(array)?;
1659
+ Ok(())
1660
+ }
1661
+ Value::Map(_) => Err(MustardError::runtime(
1662
+ "TypeError: custom properties on Map values are not supported",
1663
+ )),
1664
+ Value::Set(_) => Err(MustardError::runtime(
1665
+ "TypeError: custom properties on Set values are not supported",
1666
+ )),
1667
+ Value::Closure(closure) => self.set_closure_property(closure, key, value),
1668
+ Value::BuiltinFunction(function) => {
1669
+ self.set_builtin_function_property(function, key, value)
1670
+ }
1671
+ Value::HostFunction(capability) => {
1672
+ self.set_host_function_property(capability, key, value)
1673
+ }
1674
+ _ => Err(MustardError::runtime("TypeError: value is not an object")),
1675
+ }
1676
+ }
1677
+
1678
+ pub(super) fn console_method(&self, key: &str) -> Option<Value> {
1679
+ let capability = match key {
1680
+ "log" => "console.log",
1681
+ "warn" => "console.warn",
1682
+ "error" => "console.error",
1683
+ _ => return None,
1684
+ };
1685
+ self.capability_value(capability)
1686
+ }
1687
+ }
1688
+
1689
+ pub(super) fn canonicalize_collection_key(value: Value) -> Value {
1690
+ match value {
1691
+ Value::Number(number) if number == 0.0 && number.is_sign_negative() => Value::Number(0.0),
1692
+ other => other,
1693
+ }
1694
+ }
1695
+
1696
+ pub(super) fn property_name_to_key(name: &PropertyName) -> String {
1697
+ match name {
1698
+ PropertyName::Identifier(name) | PropertyName::String(name) => name.clone(),
1699
+ PropertyName::Number(number) => format_number_key(*number),
1700
+ }
1701
+ }
1702
+
1703
+ pub(super) fn format_number_key(value: f64) -> String {
1704
+ if value.fract() == 0.0 {
1705
+ format!("{}", value as i64)
1706
+ } else {
1707
+ value.to_string()
1708
+ }
1709
+ }
1710
+
1711
+ pub(super) fn array_index_from_property_key(key: &str) -> Option<usize> {
1712
+ if key == "0" {
1713
+ return Some(0);
1714
+ }
1715
+
1716
+ if key.is_empty() || key.starts_with('0') {
1717
+ return None;
1718
+ }
1719
+
1720
+ let index = key.parse::<u32>().ok()?;
1721
+ if index == u32::MAX {
1722
+ return None;
1723
+ }
1724
+
1725
+ if key == index.to_string() {
1726
+ Some(index as usize)
1727
+ } else {
1728
+ None
1729
+ }
1730
+ }
1731
+
1732
+ pub(super) fn ordered_own_property_keys(properties: &IndexMap<String, Value>) -> Vec<String> {
1733
+ ordered_own_property_keys_filtered(properties, |_, _| true)
1734
+ }
1735
+
1736
+ pub(super) fn ordered_own_property_keys_filtered<F>(
1737
+ properties: &IndexMap<String, Value>,
1738
+ mut include: F,
1739
+ ) -> Vec<String>
1740
+ where
1741
+ F: FnMut(&str, &Value) -> bool,
1742
+ {
1743
+ let mut keys = Vec::with_capacity(properties.len());
1744
+ let mut index_keys = properties
1745
+ .iter()
1746
+ .filter(|(key, value)| include(key, value))
1747
+ .filter_map(|(key, _)| array_index_from_property_key(key).map(|index| (index, key.clone())))
1748
+ .collect::<Vec<_>>();
1749
+ index_keys.sort_unstable_by_key(|(index, _)| *index);
1750
+ keys.extend(index_keys.into_iter().map(|(_, key)| key));
1751
+
1752
+ keys.extend(
1753
+ properties
1754
+ .iter()
1755
+ .filter(|(key, value)| {
1756
+ include(key, value) && array_index_from_property_key(key).is_none()
1757
+ })
1758
+ .map(|(key, _)| key.clone()),
1759
+ );
1760
+
1761
+ keys
1762
+ }