mustardscript 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/README.md +65 -22
  2. package/SECURITY.md +1 -1
  3. package/dist/index.js +2 -0
  4. package/dist/lib/executor.js +16 -1
  5. package/dist/lib/policy.js +301 -22
  6. package/dist/lib/progress.js +499 -113
  7. package/dist/lib/runtime.js +109 -40
  8. package/dist/lib/structured.js +327 -11
  9. package/dist/native-loader.js +11 -12
  10. package/index.d.ts +54 -6
  11. package/mustard.d.ts +23 -1
  12. package/package.json +34 -25
  13. package/Cargo.lock +0 -1579
  14. package/Cargo.toml +0 -40
  15. package/crates/mustard/Cargo.toml +0 -31
  16. package/crates/mustard/src/cancellation.rs +0 -28
  17. package/crates/mustard/src/diagnostic.rs +0 -145
  18. package/crates/mustard/src/ir.rs +0 -435
  19. package/crates/mustard/src/lib.rs +0 -21
  20. package/crates/mustard/src/limits.rs +0 -22
  21. package/crates/mustard/src/parser/expressions.rs +0 -723
  22. package/crates/mustard/src/parser/mod.rs +0 -115
  23. package/crates/mustard/src/parser/operators.rs +0 -105
  24. package/crates/mustard/src/parser/patterns.rs +0 -123
  25. package/crates/mustard/src/parser/scope.rs +0 -107
  26. package/crates/mustard/src/parser/statements.rs +0 -298
  27. package/crates/mustard/src/parser/tests/acceptance.rs +0 -339
  28. package/crates/mustard/src/parser/tests/mod.rs +0 -2
  29. package/crates/mustard/src/parser/tests/rejections.rs +0 -107
  30. package/crates/mustard/src/runtime/accounting.rs +0 -613
  31. package/crates/mustard/src/runtime/api.rs +0 -192
  32. package/crates/mustard/src/runtime/async_runtime/mod.rs +0 -5
  33. package/crates/mustard/src/runtime/async_runtime/promises.rs +0 -246
  34. package/crates/mustard/src/runtime/async_runtime/reactions.rs +0 -400
  35. package/crates/mustard/src/runtime/async_runtime/scheduler.rs +0 -224
  36. package/crates/mustard/src/runtime/builtins/arrays.rs +0 -1205
  37. package/crates/mustard/src/runtime/builtins/collections.rs +0 -573
  38. package/crates/mustard/src/runtime/builtins/install.rs +0 -501
  39. package/crates/mustard/src/runtime/builtins/intl.rs +0 -553
  40. package/crates/mustard/src/runtime/builtins/mod.rs +0 -25
  41. package/crates/mustard/src/runtime/builtins/objects.rs +0 -405
  42. package/crates/mustard/src/runtime/builtins/primitives.rs +0 -859
  43. package/crates/mustard/src/runtime/builtins/promises.rs +0 -335
  44. package/crates/mustard/src/runtime/builtins/regexp.rs +0 -356
  45. package/crates/mustard/src/runtime/builtins/strings.rs +0 -803
  46. package/crates/mustard/src/runtime/builtins/support.rs +0 -561
  47. package/crates/mustard/src/runtime/bytecode.rs +0 -123
  48. package/crates/mustard/src/runtime/compiler/assignments.rs +0 -690
  49. package/crates/mustard/src/runtime/compiler/bindings.rs +0 -92
  50. package/crates/mustard/src/runtime/compiler/context.rs +0 -46
  51. package/crates/mustard/src/runtime/compiler/control.rs +0 -342
  52. package/crates/mustard/src/runtime/compiler/expressions.rs +0 -372
  53. package/crates/mustard/src/runtime/compiler/mod.rs +0 -173
  54. package/crates/mustard/src/runtime/compiler/statements.rs +0 -459
  55. package/crates/mustard/src/runtime/conversions/boundary.rs +0 -293
  56. package/crates/mustard/src/runtime/conversions/coercions.rs +0 -217
  57. package/crates/mustard/src/runtime/conversions/errors.rs +0 -118
  58. package/crates/mustard/src/runtime/conversions/mod.rs +0 -14
  59. package/crates/mustard/src/runtime/conversions/operators.rs +0 -334
  60. package/crates/mustard/src/runtime/env.rs +0 -355
  61. package/crates/mustard/src/runtime/exceptions.rs +0 -377
  62. package/crates/mustard/src/runtime/gc.rs +0 -595
  63. package/crates/mustard/src/runtime/mod.rs +0 -318
  64. package/crates/mustard/src/runtime/properties.rs +0 -1762
  65. package/crates/mustard/src/runtime/serialization.rs +0 -127
  66. package/crates/mustard/src/runtime/shared.rs +0 -108
  67. package/crates/mustard/src/runtime/snapshot_validation_tests.rs +0 -93
  68. package/crates/mustard/src/runtime/state.rs +0 -652
  69. package/crates/mustard/src/runtime/tests/async_host.rs +0 -104
  70. package/crates/mustard/src/runtime/tests/collections.rs +0 -50
  71. package/crates/mustard/src/runtime/tests/diagnostics.rs +0 -36
  72. package/crates/mustard/src/runtime/tests/exceptions.rs +0 -122
  73. package/crates/mustard/src/runtime/tests/execution.rs +0 -553
  74. package/crates/mustard/src/runtime/tests/gc.rs +0 -533
  75. package/crates/mustard/src/runtime/tests/mod.rs +0 -56
  76. package/crates/mustard/src/runtime/tests/serialization.rs +0 -170
  77. package/crates/mustard/src/runtime/validation/bytecode.rs +0 -484
  78. package/crates/mustard/src/runtime/validation/mod.rs +0 -14
  79. package/crates/mustard/src/runtime/validation/policy.rs +0 -94
  80. package/crates/mustard/src/runtime/validation/snapshot.rs +0 -406
  81. package/crates/mustard/src/runtime/validation/walk.rs +0 -206
  82. package/crates/mustard/src/runtime/vm.rs +0 -1016
  83. package/crates/mustard/src/span.rs +0 -22
  84. package/crates/mustard/src/structured.rs +0 -107
  85. package/crates/mustard-bridge/Cargo.toml +0 -17
  86. package/crates/mustard-bridge/src/codec.rs +0 -46
  87. package/crates/mustard-bridge/src/dto.rs +0 -99
  88. package/crates/mustard-bridge/src/lib.rs +0 -12
  89. package/crates/mustard-bridge/src/operations.rs +0 -142
  90. package/crates/mustard-node/Cargo.toml +0 -24
  91. package/crates/mustard-node/build.rs +0 -3
  92. package/crates/mustard-node/src/lib.rs +0 -236
  93. package/crates/mustard-sidecar/Cargo.toml +0 -21
  94. package/crates/mustard-sidecar/src/lib.rs +0 -134
  95. package/crates/mustard-sidecar/src/main.rs +0 -36
  96. package/dist/install.js +0 -117
@@ -1,561 +0,0 @@
1
- use std::time::{SystemTime, UNIX_EPOCH};
2
-
3
- use super::*;
4
-
5
- const MAX_TIME_MS: f64 = 8_640_000_000_000_000.0;
6
- const MS_PER_SECOND: i64 = 1_000;
7
- const MS_PER_MINUTE: i64 = 60 * MS_PER_SECOND;
8
- const MS_PER_HOUR: i64 = 60 * MS_PER_MINUTE;
9
- const MS_PER_DAY: i64 = 24 * MS_PER_HOUR;
10
-
11
- #[derive(Debug, Clone, Copy)]
12
- pub(super) struct RegExpFlagsState {
13
- pub(super) global: bool,
14
- pub(super) ignore_case: bool,
15
- pub(super) multiline: bool,
16
- pub(super) dot_all: bool,
17
- pub(super) unicode: bool,
18
- pub(super) sticky: bool,
19
- }
20
-
21
- #[derive(Debug, Clone)]
22
- pub(crate) struct RegExpMatchData {
23
- pub(crate) start_byte: usize,
24
- pub(crate) end_byte: usize,
25
- pub(crate) start_index: usize,
26
- pub(crate) end_index: usize,
27
- pub(crate) captures: Vec<Option<String>>,
28
- pub(crate) named_groups: IndexMap<String, Option<String>>,
29
- }
30
-
31
- #[derive(Debug, Clone)]
32
- pub(super) enum StringSearchPattern {
33
- Literal(String),
34
- RegExp {
35
- object: ObjectKey,
36
- regex: RegExpObject,
37
- },
38
- }
39
-
40
- #[derive(Debug, Clone, Copy)]
41
- pub(super) struct DateTimeFields {
42
- pub(super) year: i64,
43
- pub(super) month: u8,
44
- pub(super) day: u8,
45
- pub(super) hour: u8,
46
- pub(super) minute: u8,
47
- pub(super) second: u8,
48
- pub(super) millisecond: u16,
49
- }
50
-
51
- pub(super) fn current_time_millis() -> f64 {
52
- SystemTime::now()
53
- .duration_since(UNIX_EPOCH)
54
- .map(|duration| duration.as_millis() as f64)
55
- .unwrap_or(0.0)
56
- }
57
-
58
- pub(super) fn parse_date_timestamp_ms(value: &str) -> f64 {
59
- parse_iso_date_timestamp_ms(value).unwrap_or(f64::NAN)
60
- }
61
-
62
- pub(super) fn time_clip(timestamp_ms: f64) -> f64 {
63
- if !timestamp_ms.is_finite() || timestamp_ms.abs() > MAX_TIME_MS {
64
- f64::NAN
65
- } else {
66
- let clipped = timestamp_ms.trunc();
67
- if clipped == 0.0 { 0.0 } else { clipped }
68
- }
69
- }
70
-
71
- fn parse_iso_date_timestamp_ms(value: &str) -> Option<f64> {
72
- let (year, mut index) = parse_iso_year(value)?;
73
- index += 1;
74
- let month = parse_two_digits(value, &mut index)?;
75
- require_byte(value, &mut index, b'-')?;
76
- let day = parse_two_digits(value, &mut index)?;
77
- if !is_valid_date(year, month, day) {
78
- return None;
79
- }
80
-
81
- let days = days_from_civil(year, month, day);
82
- if index == value.len() {
83
- return Some(days as f64 * MS_PER_DAY as f64);
84
- }
85
-
86
- require_byte(value, &mut index, b'T')?;
87
- let hour = parse_two_digits(value, &mut index)?;
88
- require_byte(value, &mut index, b':')?;
89
- let minute = parse_two_digits(value, &mut index)?;
90
- require_byte(value, &mut index, b':')?;
91
- let second = parse_two_digits(value, &mut index)?;
92
- if hour > 23 || minute > 59 || second > 59 {
93
- return None;
94
- }
95
-
96
- let mut millisecond = 0i64;
97
- if matches!(value.as_bytes().get(index), Some(b'.')) {
98
- index += 1;
99
- let start = index;
100
- while value.as_bytes().get(index).is_some_and(u8::is_ascii_digit) {
101
- index += 1;
102
- }
103
- if index == start {
104
- return None;
105
- }
106
- let digits = &value.as_bytes()[start..index];
107
- let mut parsed = 0i64;
108
- for digit in digits.iter().take(3) {
109
- parsed = parsed * 10 + i64::from(digit - b'0');
110
- }
111
- for _ in digits.len().min(3)..3 {
112
- parsed *= 10;
113
- }
114
- millisecond = parsed;
115
- }
116
-
117
- let offset_ms = match value.as_bytes().get(index).copied() {
118
- Some(b'Z') if index + 1 == value.len() => 0i64,
119
- Some(sign @ (b'+' | b'-')) => {
120
- index += 1;
121
- let offset_hours = parse_two_digits(value, &mut index)?;
122
- require_byte(value, &mut index, b':')?;
123
- let offset_minutes = parse_two_digits(value, &mut index)?;
124
- if offset_hours > 23 || offset_minutes > 59 || index != value.len() {
125
- return None;
126
- }
127
- let magnitude =
128
- i64::from(offset_hours) * MS_PER_HOUR + i64::from(offset_minutes) * MS_PER_MINUTE;
129
- if sign == b'+' { magnitude } else { -magnitude }
130
- }
131
- _ => return None,
132
- };
133
-
134
- let time_ms = i64::from(hour) * MS_PER_HOUR
135
- + i64::from(minute) * MS_PER_MINUTE
136
- + i64::from(second) * MS_PER_SECOND
137
- + millisecond;
138
- let timestamp_ms =
139
- i128::from(days) * i128::from(MS_PER_DAY) + i128::from(time_ms) - i128::from(offset_ms);
140
- if !(i128::from(i64::MIN)..=i128::from(i64::MAX)).contains(&timestamp_ms) {
141
- return None;
142
- }
143
- Some(timestamp_ms as f64)
144
- }
145
-
146
- pub(super) fn date_time_fields_from_timestamp_ms(timestamp_ms: f64) -> Option<DateTimeFields> {
147
- if !timestamp_ms.is_finite() {
148
- return None;
149
- }
150
- let timestamp_ms = if timestamp_ms.trunc() == 0.0 {
151
- 0.0
152
- } else {
153
- timestamp_ms.trunc()
154
- };
155
- if timestamp_ms < i64::MIN as f64 || timestamp_ms > i64::MAX as f64 {
156
- return None;
157
- }
158
- let timestamp_ms = timestamp_ms as i64;
159
- let days = timestamp_ms.div_euclid(MS_PER_DAY);
160
- let day_ms = timestamp_ms.rem_euclid(MS_PER_DAY);
161
- let (year, month, day) = civil_from_days(days);
162
- Some(DateTimeFields {
163
- year,
164
- month,
165
- day,
166
- hour: (day_ms / MS_PER_HOUR) as u8,
167
- minute: ((day_ms % MS_PER_HOUR) / MS_PER_MINUTE) as u8,
168
- second: ((day_ms % MS_PER_MINUTE) / MS_PER_SECOND) as u8,
169
- millisecond: (day_ms % MS_PER_SECOND) as u16,
170
- })
171
- }
172
-
173
- pub(super) fn format_iso_datetime(timestamp_ms: f64) -> Option<String> {
174
- let datetime = date_time_fields_from_timestamp_ms(timestamp_ms)?;
175
- Some(format!(
176
- "{}-{:02}-{:02}T{:02}:{:02}:{:02}.{:03}Z",
177
- format_iso_year(datetime.year),
178
- datetime.month,
179
- datetime.day,
180
- datetime.hour,
181
- datetime.minute,
182
- datetime.second,
183
- datetime.millisecond,
184
- ))
185
- }
186
-
187
- fn parse_iso_year(value: &str) -> Option<(i64, usize)> {
188
- let bytes = value.as_bytes();
189
- let mut index = 0usize;
190
- let signed = matches!(bytes.first(), Some(b'+' | b'-'));
191
- if signed {
192
- index += 1;
193
- }
194
- while bytes.get(index).is_some_and(u8::is_ascii_digit) {
195
- index += 1;
196
- }
197
- let digits = if signed {
198
- index.saturating_sub(1)
199
- } else {
200
- index
201
- };
202
- if digits == 0 || bytes.get(index) != Some(&b'-') {
203
- return None;
204
- }
205
- if (!signed && digits != 4) || (signed && digits != 6) {
206
- return None;
207
- }
208
- Some((value[..index].parse::<i64>().ok()?, index))
209
- }
210
-
211
- fn parse_two_digits(value: &str, index: &mut usize) -> Option<u8> {
212
- let bytes = value.as_bytes();
213
- let tens = *bytes.get(*index)?;
214
- let ones = *bytes.get(*index + 1)?;
215
- if !tens.is_ascii_digit() || !ones.is_ascii_digit() {
216
- return None;
217
- }
218
- *index += 2;
219
- Some((tens - b'0') * 10 + (ones - b'0'))
220
- }
221
-
222
- fn require_byte(value: &str, index: &mut usize, expected: u8) -> Option<()> {
223
- if value.as_bytes().get(*index) == Some(&expected) {
224
- *index += 1;
225
- Some(())
226
- } else {
227
- None
228
- }
229
- }
230
-
231
- fn is_valid_date(year: i64, month: u8, day: u8) -> bool {
232
- matches!(month, 1..=12) && (1..=days_in_month(year, month)).contains(&day)
233
- }
234
-
235
- fn is_leap_year(year: i64) -> bool {
236
- (year % 4 == 0 && year % 100 != 0) || year % 400 == 0
237
- }
238
-
239
- fn days_in_month(year: i64, month: u8) -> u8 {
240
- match month {
241
- 1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
242
- 4 | 6 | 9 | 11 => 30,
243
- 2 if is_leap_year(year) => 29,
244
- 2 => 28,
245
- _ => 0,
246
- }
247
- }
248
-
249
- fn days_from_civil(year: i64, month: u8, day: u8) -> i64 {
250
- let year = year - i64::from(month <= 2);
251
- let era = if year >= 0 { year } else { year - 399 } / 400;
252
- let year_of_era = year - era * 400;
253
- let shifted_month = i64::from(month) + if month > 2 { -3 } else { 9 };
254
- let day_of_year = (153 * shifted_month + 2) / 5 + i64::from(day) - 1;
255
- let day_of_era = year_of_era * 365 + year_of_era / 4 - year_of_era / 100 + day_of_year;
256
- era * 146_097 + day_of_era - 719_468
257
- }
258
-
259
- fn civil_from_days(days: i64) -> (i64, u8, u8) {
260
- let shifted = days + 719_468;
261
- let era = if shifted >= 0 {
262
- shifted
263
- } else {
264
- shifted - 146_096
265
- } / 146_097;
266
- let day_of_era = shifted - era * 146_097;
267
- let year_of_era =
268
- (day_of_era - day_of_era / 1_460 + day_of_era / 36_524 - day_of_era / 146_096) / 365;
269
- let year = year_of_era + era * 400;
270
- let day_of_year = day_of_era - (365 * year_of_era + year_of_era / 4 - year_of_era / 100);
271
- let month_prime = (5 * day_of_year + 2) / 153;
272
- let day = day_of_year - (153 * month_prime + 2) / 5 + 1;
273
- let month = month_prime + if month_prime < 10 { 3 } else { -9 };
274
- (year + i64::from(month <= 2), month as u8, day as u8)
275
- }
276
-
277
- fn format_iso_year(year: i64) -> String {
278
- if (0..=9_999).contains(&year) {
279
- format!("{year:04}")
280
- } else if year < 0 {
281
- format!("-{:06}", year.unsigned_abs())
282
- } else {
283
- format!("+{:06}", year as u64)
284
- }
285
- }
286
-
287
- pub(super) fn format_en_us_number_grouped(integer: &str) -> String {
288
- let mut chars = integer.chars().collect::<Vec<_>>();
289
- let negative = matches!(chars.first(), Some('-'));
290
- if negative {
291
- chars.remove(0);
292
- }
293
- let mut grouped = String::new();
294
- for (index, ch) in chars.iter().rev().enumerate() {
295
- if index > 0 && index % 3 == 0 {
296
- grouped.push(',');
297
- }
298
- grouped.push(*ch);
299
- }
300
- let grouped = grouped.chars().rev().collect::<String>();
301
- if negative {
302
- format!("-{grouped}")
303
- } else {
304
- grouped
305
- }
306
- }
307
-
308
- pub(super) fn clamp_index(index: i64, len: usize) -> usize {
309
- if index < 0 {
310
- 0
311
- } else {
312
- (index as usize).min(len)
313
- }
314
- }
315
-
316
- pub(super) fn normalize_relative_bound(index: i64, len: usize) -> usize {
317
- let len = len as i64;
318
- if index < 0 {
319
- (len + index).max(0) as usize
320
- } else {
321
- index.min(len) as usize
322
- }
323
- }
324
-
325
- pub(super) fn normalize_search_index(index: i64, len: usize) -> usize {
326
- if index < 0 {
327
- normalize_relative_bound(index, len)
328
- } else {
329
- clamp_index(index, len)
330
- }
331
- }
332
-
333
- pub(super) fn collect_literal_matches(value: &str, needle: &str) -> Vec<RegExpMatchData> {
334
- if needle.is_empty() {
335
- let total = value.chars().count();
336
- return (0..=total)
337
- .map(|index| {
338
- let byte = char_index_to_byte_index(value, index);
339
- RegExpMatchData {
340
- start_byte: byte,
341
- end_byte: byte,
342
- start_index: index,
343
- end_index: index,
344
- captures: Vec::new(),
345
- named_groups: IndexMap::new(),
346
- }
347
- })
348
- .collect();
349
- }
350
-
351
- let mut matches = Vec::new();
352
- let mut start_index = 0usize;
353
- while let Some(matched) = find_string_pattern(value, needle, start_index).map(|index| {
354
- let start_byte = char_index_to_byte_index(value, index);
355
- let end_index = index + needle.chars().count();
356
- let end_byte = char_index_to_byte_index(value, end_index);
357
- RegExpMatchData {
358
- start_byte,
359
- end_byte,
360
- start_index: index,
361
- end_index,
362
- captures: Vec::new(),
363
- named_groups: IndexMap::new(),
364
- }
365
- }) {
366
- start_index = matched.end_index;
367
- matches.push(matched);
368
- }
369
- matches
370
- }
371
-
372
- pub(super) fn char_index_to_byte_index(value: &str, index: usize) -> usize {
373
- if index == 0 {
374
- return 0;
375
- }
376
- value
377
- .char_indices()
378
- .nth(index)
379
- .map(|(byte, _)| byte)
380
- .unwrap_or_else(|| value.len())
381
- }
382
-
383
- pub(super) fn byte_index_to_char_index(value: &str, byte_index: usize) -> usize {
384
- value[..byte_index].chars().count()
385
- }
386
-
387
- pub(super) fn advance_char_index(value: &str, index: usize) -> usize {
388
- let total = value.chars().count();
389
- (index + 1).min(total)
390
- }
391
-
392
- pub(super) fn find_string_pattern(value: &str, needle: &str, start: usize) -> Option<usize> {
393
- let start_byte = char_index_to_byte_index(value, start);
394
- value[start_byte..]
395
- .find(needle)
396
- .map(|byte_index| byte_index_to_char_index(value, start_byte + byte_index))
397
- }
398
-
399
- pub(super) fn split_string_by_pattern(
400
- value: &str,
401
- separator: Option<&str>,
402
- limit: usize,
403
- ) -> Vec<String> {
404
- let mut parts = Vec::new();
405
- match separator {
406
- None => {
407
- parts.push(value.to_string());
408
- }
409
- Some("") => {
410
- if limit == 0 {
411
- return Vec::new();
412
- }
413
- if value.is_empty() {
414
- return parts;
415
- }
416
- for ch in value.chars() {
417
- if parts.len() == limit {
418
- break;
419
- }
420
- parts.push(ch.to_string());
421
- }
422
- return parts;
423
- }
424
- Some(separator) => {
425
- let mut remaining = value;
426
- while let Some(index) = remaining.find(separator) {
427
- if parts.len() + 1 == limit {
428
- parts.push(remaining[..index].to_string());
429
- return parts;
430
- }
431
- parts.push(remaining[..index].to_string());
432
- remaining = &remaining[index + separator.len()..];
433
- }
434
- if parts.len() < limit {
435
- parts.push(remaining.to_string());
436
- }
437
- }
438
- }
439
- parts
440
- }
441
-
442
- pub(super) fn replace_all_string_matches(value: &str, search: &str, replacement: &str) -> String {
443
- if search.is_empty() {
444
- let mut result = String::new();
445
- for ch in value.chars() {
446
- result.push_str(replacement);
447
- result.push(ch);
448
- }
449
- result.push_str(replacement);
450
- return result;
451
- }
452
-
453
- let mut result = String::new();
454
- let mut start_index = 0usize;
455
- while let Some(index) = find_string_pattern(value, search, start_index) {
456
- let start_byte = char_index_to_byte_index(value, index);
457
- let end_index = index + search.chars().count();
458
- let end_byte = char_index_to_byte_index(value, end_index);
459
- result.push_str(&value[char_index_to_byte_index(value, start_index)..start_byte]);
460
- result.push_str(replacement);
461
- start_index = end_index;
462
- if start_byte == end_byte {
463
- start_index = advance_char_index(value, start_index);
464
- }
465
- }
466
- result.push_str(&value[char_index_to_byte_index(value, start_index)..]);
467
- result
468
- }
469
-
470
- pub(super) fn replace_first_string_match(value: &str, search: &str, replacement: &str) -> String {
471
- if search.is_empty() {
472
- let mut result = String::new();
473
- result.push_str(replacement);
474
- result.push_str(value);
475
- return result;
476
- }
477
- let Some(index) = find_string_pattern(value, search, 0) else {
478
- return value.to_string();
479
- };
480
- let start_byte = char_index_to_byte_index(value, index);
481
- let end_index = index + search.chars().count();
482
- let end_byte = char_index_to_byte_index(value, end_index);
483
- let mut result = String::new();
484
- result.push_str(&value[..start_byte]);
485
- result.push_str(replacement);
486
- result.push_str(&value[end_byte..]);
487
- result
488
- }
489
-
490
- pub(super) fn expand_regexp_replacement_template(
491
- replacement: &str,
492
- input: &str,
493
- matched: &RegExpMatchData,
494
- ) -> String {
495
- let mut result = String::new();
496
- let mut chars = replacement.chars().peekable();
497
- while let Some(ch) = chars.next() {
498
- if ch != '$' {
499
- result.push(ch);
500
- continue;
501
- }
502
- match chars.peek().copied() {
503
- Some('$') => {
504
- chars.next();
505
- result.push('$');
506
- }
507
- Some('&') => {
508
- chars.next();
509
- result.push_str(&input[matched.start_byte..matched.end_byte]);
510
- }
511
- Some('`') => {
512
- chars.next();
513
- result.push_str(&input[..matched.start_byte]);
514
- }
515
- Some('\'') => {
516
- chars.next();
517
- result.push_str(&input[matched.end_byte..]);
518
- }
519
- Some('<') => {
520
- chars.next();
521
- let mut name = String::new();
522
- let mut closed = false;
523
- for next in chars.by_ref() {
524
- if next == '>' {
525
- closed = true;
526
- break;
527
- }
528
- name.push(next);
529
- }
530
- if closed {
531
- if let Some(Some(value)) = matched.named_groups.get(&name) {
532
- result.push_str(value);
533
- }
534
- } else {
535
- result.push('$');
536
- result.push('<');
537
- result.push_str(&name);
538
- break;
539
- }
540
- }
541
- Some(digit @ '1'..='9') => {
542
- let mut index = digit.to_digit(10).unwrap() as usize;
543
- chars.next();
544
- if let Some(next_digit @ '0'..='9') = chars.peek().copied() {
545
- let candidate = index * 10 + next_digit.to_digit(10).unwrap() as usize;
546
- if candidate <= matched.captures.len() {
547
- index = candidate;
548
- chars.next();
549
- }
550
- }
551
- if index > 0
552
- && let Some(Some(value)) = matched.captures.get(index - 1)
553
- {
554
- result.push_str(value);
555
- }
556
- }
557
- _ => result.push('$'),
558
- }
559
- }
560
- result
561
- }
@@ -1,123 +0,0 @@
1
- use serde::{Deserialize, Serialize};
2
-
3
- use crate::{
4
- ir::{BinaryOp, Pattern, PropertyName, UnaryOp, UpdateOp},
5
- span::SourceSpan,
6
- };
7
-
8
- #[derive(Debug, Clone, Serialize, Deserialize)]
9
- pub struct BytecodeProgram {
10
- pub functions: Vec<FunctionPrototype>,
11
- pub root: usize,
12
- }
13
-
14
- #[derive(Debug, Clone, Serialize, Deserialize)]
15
- pub struct FunctionPrototype {
16
- pub name: Option<String>,
17
- pub length: usize,
18
- pub display_source: String,
19
- pub params: Vec<Pattern>,
20
- pub rest: Option<Pattern>,
21
- pub code: Vec<Instruction>,
22
- pub is_async: bool,
23
- pub is_arrow: bool,
24
- pub span: SourceSpan,
25
- }
26
-
27
- #[derive(Debug, Clone, Serialize, Deserialize)]
28
- pub enum Instruction {
29
- PushUndefined,
30
- PushNull,
31
- PushBool(bool),
32
- PushNumber(f64),
33
- PushString(String),
34
- PushRegExp {
35
- pattern: String,
36
- flags: String,
37
- },
38
- LoadName(String),
39
- LoadGlobalObject,
40
- StoreName(String),
41
- InitializePattern(Pattern),
42
- PushEnv,
43
- PopEnv,
44
- DeclareName {
45
- name: String,
46
- mutable: bool,
47
- },
48
- MakeClosure {
49
- function_id: usize,
50
- },
51
- MakeArray {
52
- count: usize,
53
- },
54
- ArrayPush,
55
- ArrayPushHole,
56
- ArrayExtend,
57
- MakeObject {
58
- keys: Vec<PropertyName>,
59
- },
60
- CopyDataProperties,
61
- CreateIterator,
62
- IteratorNext,
63
- GetPropStatic {
64
- name: String,
65
- optional: bool,
66
- },
67
- GetPropComputed {
68
- optional: bool,
69
- },
70
- SetPropStatic {
71
- name: String,
72
- },
73
- SetPropComputed,
74
- Unary(UnaryOp),
75
- Binary(BinaryOp),
76
- Update(UpdateOp),
77
- PatternArrayIndex(usize),
78
- PatternArrayRest(usize),
79
- PatternObjectRest(Vec<String>),
80
- Pop,
81
- Dup,
82
- Dup2,
83
- PushHandler {
84
- catch: Option<usize>,
85
- finally: Option<usize>,
86
- },
87
- PopHandler,
88
- EnterFinally {
89
- exit: usize,
90
- },
91
- BeginCatch,
92
- Throw {
93
- span: SourceSpan,
94
- },
95
- PushPendingJump {
96
- target: usize,
97
- target_handler_depth: usize,
98
- target_scope_depth: usize,
99
- },
100
- PushPendingReturn,
101
- PushPendingThrow,
102
- ContinuePending,
103
- Jump(usize),
104
- JumpIfFalse(usize),
105
- JumpIfTrue(usize),
106
- JumpIfNullish(usize),
107
- Call {
108
- argc: usize,
109
- with_this: bool,
110
- optional: bool,
111
- },
112
- CallWithArray {
113
- with_this: bool,
114
- optional: bool,
115
- },
116
- Await,
117
- Construct {
118
- argc: usize,
119
- },
120
- ConstructWithArray,
121
- Return,
122
- PushBigInt(String),
123
- }