goscript 0.0.23 → 0.0.24

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 (53) hide show
  1. package/README.md +1 -1
  2. package/cmd/goscript/cmd_compile.go +1 -1
  3. package/compiler/analysis.go +73 -131
  4. package/compiler/analysis_test.go +220 -0
  5. package/compiler/assignment.go +37 -43
  6. package/compiler/builtin_test.go +102 -0
  7. package/compiler/compiler.go +79 -14
  8. package/compiler/composite-lit.go +108 -43
  9. package/compiler/config.go +7 -3
  10. package/compiler/config_test.go +6 -33
  11. package/compiler/expr-selector.go +66 -41
  12. package/compiler/expr-star.go +57 -65
  13. package/compiler/expr-type.go +1 -1
  14. package/compiler/expr-value.go +1 -1
  15. package/compiler/expr.go +79 -18
  16. package/compiler/primitive.go +11 -10
  17. package/compiler/spec-struct.go +3 -3
  18. package/compiler/spec-value.go +75 -29
  19. package/compiler/spec.go +9 -3
  20. package/compiler/stmt-assign.go +36 -2
  21. package/compiler/stmt-for.go +11 -0
  22. package/compiler/stmt-range.go +110 -0
  23. package/compiler/stmt.go +52 -0
  24. package/compiler/type.go +36 -11
  25. package/dist/gs/builtin/builtin.js +37 -0
  26. package/dist/gs/builtin/builtin.js.map +1 -0
  27. package/dist/gs/builtin/channel.js +471 -0
  28. package/dist/gs/builtin/channel.js.map +1 -0
  29. package/dist/gs/builtin/defer.js +54 -0
  30. package/dist/gs/builtin/defer.js.map +1 -0
  31. package/dist/gs/builtin/io.js +15 -0
  32. package/dist/gs/builtin/io.js.map +1 -0
  33. package/dist/gs/builtin/map.js +44 -0
  34. package/dist/gs/builtin/map.js.map +1 -0
  35. package/dist/gs/builtin/slice.js +799 -0
  36. package/dist/gs/builtin/slice.js.map +1 -0
  37. package/dist/gs/builtin/type.js +745 -0
  38. package/dist/gs/builtin/type.js.map +1 -0
  39. package/dist/gs/builtin/varRef.js +14 -0
  40. package/dist/gs/builtin/varRef.js.map +1 -0
  41. package/dist/gs/context/context.js +55 -0
  42. package/dist/gs/context/context.js.map +1 -0
  43. package/dist/gs/context/index.js +2 -0
  44. package/dist/gs/context/index.js.map +1 -0
  45. package/dist/gs/runtime/index.js +2 -0
  46. package/dist/gs/runtime/index.js.map +1 -0
  47. package/dist/gs/runtime/runtime.js +158 -0
  48. package/dist/gs/runtime/runtime.js.map +1 -0
  49. package/dist/gs/time/index.js +2 -0
  50. package/dist/gs/time/index.js.map +1 -0
  51. package/dist/gs/time/time.js +115 -0
  52. package/dist/gs/time/time.js.map +1 -0
  53. package/package.json +3 -2
@@ -0,0 +1,799 @@
1
+ // asArray type-asserts a slice to an array type.
2
+ export function asArray(slice) {
3
+ return slice;
4
+ }
5
+ /**
6
+ * isComplexSlice checks if a slice is a complex slice (has __meta__ property)
7
+ */
8
+ function isComplexSlice(slice) {
9
+ return (slice !== null &&
10
+ slice !== undefined &&
11
+ typeof slice === 'object' &&
12
+ '__meta__' in slice &&
13
+ slice.__meta__ !== undefined);
14
+ }
15
+ /**
16
+ * Creates a new slice with the specified length and capacity.
17
+ * @param length The length of the slice.
18
+ * @param capacity The capacity of the slice (optional).
19
+ * @returns A new slice.
20
+ */
21
+ export const makeSlice = (length, capacity, typeHint) => {
22
+ if (typeHint === "byte") {
23
+ // Uint8Array is initialized to zeros by default.
24
+ // Capacity for Uint8Array is its length.
25
+ return new Uint8Array(length);
26
+ }
27
+ const actualCapacity = capacity === undefined ? length : capacity;
28
+ if (length < 0 || actualCapacity < 0 || length > actualCapacity) {
29
+ throw new Error(`Invalid slice length (${length}) or capacity (${actualCapacity})`);
30
+ }
31
+ let zeroVal;
32
+ switch (typeHint) {
33
+ case "number":
34
+ zeroVal = 0;
35
+ break;
36
+ case "boolean":
37
+ zeroVal = false;
38
+ break;
39
+ case "string":
40
+ zeroVal = "";
41
+ break;
42
+ default: zeroVal = null; // Default for objects, complex types, or unspecified
43
+ }
44
+ const backingArr = new Array(actualCapacity);
45
+ // Initialize the relevant part of the backing array
46
+ for (let i = 0; i < length; i++) {
47
+ backingArr[i] = zeroVal;
48
+ }
49
+ // The rest of backingArr (from length to actualCapacity-1) remains uninitialized (undefined),
50
+ // representing available capacity.
51
+ // The proxyTargetArray serves as the shell for the proxy.
52
+ // Its elements up to 'length' should reflect the initialized part of the slice.
53
+ const proxyTargetArray = new Array(length);
54
+ for (let i = 0; i < length; i++) {
55
+ proxyTargetArray[i] = backingArr[i]; // Or simply zeroVal
56
+ }
57
+ const proxy = proxyTargetArray;
58
+ proxy.__meta__ = {
59
+ backing: backingArr,
60
+ offset: 0,
61
+ length: length,
62
+ capacity: actualCapacity,
63
+ };
64
+ return proxy;
65
+ };
66
+ /**
67
+ * goSlice creates a slice from s[low:high:max]
68
+ * Arguments mirror Go semantics; omitted indices are undefined.
69
+ *
70
+ * @param s The original slice
71
+ * @param low Starting index (defaults to 0)
72
+ * @param high Ending index (defaults to s.length)
73
+ * @param max Capacity limit (defaults to original capacity)
74
+ */
75
+ export const goSlice = (// T can be number for Uint8Array case
76
+ s, low, high, max) => {
77
+ const handler = {
78
+ get(target, prop) {
79
+ if (typeof prop === 'string' && /^\d+$/.test(prop)) {
80
+ const index = Number(prop);
81
+ if (index >= 0 && index < target.__meta__.length) {
82
+ return target.__meta__.backing[target.__meta__.offset + index];
83
+ }
84
+ throw new Error(`Slice index out of range: ${index} >= ${target.__meta__.length}`);
85
+ }
86
+ if (prop === 'length') {
87
+ return target.__meta__.length;
88
+ }
89
+ if (prop === '__meta__') {
90
+ return target.__meta__;
91
+ }
92
+ if (prop === 'slice' ||
93
+ prop === 'map' ||
94
+ prop === 'filter' ||
95
+ prop === 'reduce' ||
96
+ prop === 'forEach' ||
97
+ prop === Symbol.iterator) {
98
+ const backingSlice = target.__meta__.backing.slice(target.__meta__.offset, target.__meta__.offset + target.__meta__.length);
99
+ return backingSlice[prop].bind(backingSlice);
100
+ }
101
+ return Reflect.get(target, prop);
102
+ },
103
+ set(target, prop, value) {
104
+ if (typeof prop === 'string' && /^\d+$/.test(prop)) {
105
+ const index = Number(prop);
106
+ if (index >= 0 && index < target.__meta__.length) {
107
+ target.__meta__.backing[target.__meta__.offset + index] = value;
108
+ return true;
109
+ }
110
+ if (index === target.__meta__.length &&
111
+ target.__meta__.length < target.__meta__.capacity) {
112
+ target.__meta__.backing[target.__meta__.offset + index] = value;
113
+ target.__meta__.length++;
114
+ return true;
115
+ }
116
+ throw new Error(`Slice index out of range: ${index} >= ${target.__meta__.length}`);
117
+ }
118
+ if (prop === 'length' || prop === '__meta__') {
119
+ return false;
120
+ }
121
+ return Reflect.set(target, prop, value);
122
+ },
123
+ };
124
+ if (s instanceof Uint8Array) {
125
+ const actualLow = low ?? 0;
126
+ const actualHigh = high ?? s.length;
127
+ if (actualLow < 0 || actualHigh < actualLow || actualHigh > s.length) {
128
+ throw new Error(`Invalid slice indices: low ${actualLow}, high ${actualHigh} for Uint8Array of length ${s.length}`);
129
+ }
130
+ const subArrayView = s.subarray(actualLow, actualHigh); // This is Uint8Array
131
+ if (max !== undefined) {
132
+ if (max < actualHigh || max > s.length) { // max is relative to the original s.length (capacity)
133
+ throw new Error(`Invalid max index: ${max}. Constraints: low ${actualLow} <= high ${actualHigh} <= max <= original_length ${s.length}`);
134
+ }
135
+ const newLength = subArrayView.length; // actualHigh - actualLow
136
+ const newCap = max - actualLow; // Capacity of the new slice view
137
+ if (newCap !== newLength) {
138
+ // Capacity is different from length, so return SliceProxy<number>
139
+ // The original s was Uint8Array, so T is effectively 'number' for this path.
140
+ const backingNumbers = Array.from(subArrayView); // Convert Uint8Array data to number[]
141
+ const proxyTarget = {
142
+ __meta__: {
143
+ backing: backingNumbers, // number[]
144
+ offset: 0, // Offset is 0 because backingNumbers is a direct copy
145
+ length: newLength,
146
+ capacity: newCap,
147
+ },
148
+ };
149
+ // Explicitly cast to Slice<T> after ensuring T is number for this branch.
150
+ return new Proxy(proxyTarget, handler);
151
+ }
152
+ else {
153
+ // newCap === newLength, standard Uint8Array is fine.
154
+ return subArrayView; // T is number
155
+ }
156
+ }
157
+ else {
158
+ // max is not defined, return the Uint8Array subarray view directly.
159
+ return subArrayView; // T is number
160
+ }
161
+ }
162
+ if (s === null || s === undefined) {
163
+ throw new Error('Cannot slice nil');
164
+ }
165
+ const slen = len(s);
166
+ low = low ?? 0;
167
+ high = high ?? slen;
168
+ if (low < 0 || high < low) {
169
+ throw new Error(`Invalid slice indices: ${low}:${high}`);
170
+ }
171
+ // In Go, high can be up to capacity, not just length
172
+ const scap = cap(s);
173
+ if (high > scap) {
174
+ throw new Error(`Slice index out of range: ${high} > ${scap}`);
175
+ }
176
+ if (Array.isArray(s) &&
177
+ !isComplexSlice(s) &&
178
+ low === 0 &&
179
+ high === s.length &&
180
+ max === undefined) {
181
+ return s;
182
+ }
183
+ let backing;
184
+ let oldOffset = 0;
185
+ let oldCap = scap;
186
+ // Get the backing array and offset
187
+ if (isComplexSlice(s)) {
188
+ backing = s.__meta__.backing;
189
+ oldOffset = s.__meta__.offset;
190
+ oldCap = s.__meta__.capacity;
191
+ }
192
+ else {
193
+ backing = s;
194
+ }
195
+ let newCap;
196
+ if (max !== undefined) {
197
+ if (max < high) {
198
+ throw new Error(`Invalid slice indices: ${low}:${high}:${max}`);
199
+ }
200
+ if (isComplexSlice(s) && max > oldOffset + oldCap) {
201
+ throw new Error(`Slice index out of range: ${max} > ${oldOffset + oldCap}`);
202
+ }
203
+ if (!isComplexSlice(s) && max > s.length) {
204
+ throw new Error(`Slice index out of range: ${max} > ${s.length}`);
205
+ }
206
+ newCap = max - low;
207
+ }
208
+ else {
209
+ // For slices of slices, capacity should be the capacity of the original slice minus the low index
210
+ if (isComplexSlice(s)) {
211
+ newCap = oldCap - low;
212
+ }
213
+ else {
214
+ newCap = s.length - low;
215
+ }
216
+ }
217
+ const newLength = high - low;
218
+ const newOffset = oldOffset + low;
219
+ const target = {
220
+ __meta__: {
221
+ backing: backing,
222
+ offset: newOffset,
223
+ length: newLength,
224
+ capacity: newCap,
225
+ },
226
+ };
227
+ // const handler = { ... } // Handler is now defined at the top
228
+ return new Proxy(target, handler);
229
+ };
230
+ /**
231
+ * Converts a JavaScript array to a Go slice.
232
+ * For multi-dimensional arrays, recursively converts nested arrays to slices.
233
+ * @param arr The JavaScript array to convert
234
+ * @param depth How many levels of nesting to convert (default: 1, use Infinity for all levels)
235
+ * @returns A Go slice containing the same elements
236
+ */
237
+ export const arrayToSlice = (arr, depth = 1) => {
238
+ if (arr == null)
239
+ return [];
240
+ if (arr.length === 0)
241
+ return arr;
242
+ const target = {
243
+ __meta__: {
244
+ backing: arr,
245
+ offset: 0,
246
+ length: arr.length,
247
+ capacity: arr.length,
248
+ },
249
+ };
250
+ const handler = {
251
+ get(target, prop) {
252
+ if (typeof prop === 'string' && /^\d+$/.test(prop)) {
253
+ const index = Number(prop);
254
+ if (index >= 0 && index < target.__meta__.length) {
255
+ return target.__meta__.backing[target.__meta__.offset + index];
256
+ }
257
+ throw new Error(`Slice index out of range: ${index} >= ${target.__meta__.length}`);
258
+ }
259
+ if (prop === 'length') {
260
+ return target.__meta__.length;
261
+ }
262
+ if (prop === '__meta__') {
263
+ return target.__meta__;
264
+ }
265
+ if (prop === 'slice' ||
266
+ prop === 'map' ||
267
+ prop === 'filter' ||
268
+ prop === 'reduce' ||
269
+ prop === 'forEach' ||
270
+ prop === Symbol.iterator) {
271
+ const backingSlice = target.__meta__.backing.slice(target.__meta__.offset, target.__meta__.offset + target.__meta__.length);
272
+ return backingSlice[prop].bind(backingSlice);
273
+ }
274
+ return Reflect.get(target, prop);
275
+ },
276
+ set(target, prop, value) {
277
+ if (typeof prop === 'string' && /^\d+$/.test(prop)) {
278
+ const index = Number(prop);
279
+ if (index >= 0 && index < target.__meta__.length) {
280
+ target.__meta__.backing[target.__meta__.offset + index] = value;
281
+ return true;
282
+ }
283
+ if (index === target.__meta__.length &&
284
+ target.__meta__.length < target.__meta__.capacity) {
285
+ target.__meta__.backing[target.__meta__.offset + index] = value;
286
+ target.__meta__.length++;
287
+ return true;
288
+ }
289
+ throw new Error(`Slice index out of range: ${index} >= ${target.__meta__.length}`);
290
+ }
291
+ if (prop === 'length' || prop === '__meta__') {
292
+ return false;
293
+ }
294
+ return Reflect.set(target, prop, value);
295
+ },
296
+ };
297
+ // Recursively convert nested arrays if depth > 1
298
+ if (depth > 1 && arr.length > 0) {
299
+ for (let i = 0; i < arr.length; i++) {
300
+ const item = arr[i];
301
+ if (isComplexSlice(item)) {
302
+ }
303
+ else if (Array.isArray(item)) {
304
+ arr[i] = arrayToSlice(item, depth - 1);
305
+ }
306
+ else if (item &&
307
+ typeof item === 'object' &&
308
+ isComplexSlice(item)) {
309
+ // Preserve capacity information for complex slices
310
+ }
311
+ }
312
+ }
313
+ return new Proxy(target, handler);
314
+ };
315
+ /**
316
+ * Returns the length of a collection (string, array, slice, map, or set).
317
+ * @param obj The collection to get the length of.
318
+ * @returns The length of the collection.
319
+ */
320
+ export const len = (obj) => {
321
+ if (obj === null || obj === undefined) {
322
+ return 0;
323
+ }
324
+ if (typeof obj === 'string') {
325
+ return stringLen(obj); // Call new stringLen for strings
326
+ }
327
+ if (obj instanceof Map || obj instanceof Set) {
328
+ return obj.size;
329
+ }
330
+ if (obj instanceof Uint8Array) {
331
+ return obj.length;
332
+ }
333
+ if (isComplexSlice(obj)) {
334
+ return obj.__meta__.length;
335
+ }
336
+ if (Array.isArray(obj)) {
337
+ return obj.length;
338
+ }
339
+ throw new Error("cannot determine len of this type");
340
+ };
341
+ /**
342
+ * Returns the capacity of a slice.
343
+ * @param obj The slice.
344
+ * @returns The capacity of the slice.
345
+ */
346
+ export const cap = (obj) => {
347
+ if (obj === null || obj === undefined) {
348
+ return 0;
349
+ }
350
+ if (obj instanceof Uint8Array) {
351
+ return obj.length; // Uint8Array capacity is its length
352
+ }
353
+ if (isComplexSlice(obj)) {
354
+ return obj.__meta__.capacity;
355
+ }
356
+ if (Array.isArray(obj)) {
357
+ return obj.length;
358
+ }
359
+ return 0;
360
+ };
361
+ /**
362
+ * Appends elements to a slice.
363
+ * Note: In Go, append can return a new slice if the underlying array is reallocated.
364
+ * This helper emulates that by returning the modified or new slice.
365
+ * @param slice The slice to append to.
366
+ * @param elements The elements to append.
367
+ * @returns The modified or new slice.
368
+ */
369
+ export const append = (slice, ...elements) => {
370
+ // 1. Flatten all elements from the varargs `...elements` into `varargsElements`.
371
+ // Determine if the result should be a Uint8Array.
372
+ const inputIsUint8Array = slice instanceof Uint8Array;
373
+ const appendingUint8Array = elements.some(el => el instanceof Uint8Array);
374
+ const produceUint8Array = inputIsUint8Array || appendingUint8Array || (slice === null && appendingUint8Array);
375
+ // If producing Uint8Array, all elements must be numbers and potentially flattened from other Uint8Arrays/number slices.
376
+ if (produceUint8Array) {
377
+ let combinedBytes = [];
378
+ // Add bytes from the original slice if it exists and is numeric.
379
+ if (inputIsUint8Array) {
380
+ combinedBytes.push(...Array.from(slice));
381
+ }
382
+ else if (slice !== null && slice !== undefined) { // Original was Slice<number> or number[]
383
+ const sliceLen = len(slice);
384
+ for (let i = 0; i < sliceLen; i++) {
385
+ const val = slice[i];
386
+ if (typeof val !== 'number') {
387
+ throw new Error("Cannot produce Uint8Array: original slice contains non-number elements.");
388
+ }
389
+ combinedBytes.push(val);
390
+ }
391
+ }
392
+ // Add bytes from the varargs elements.
393
+ // For Uint8Array, elements are always flattened if they are slices/Uint8Arrays.
394
+ for (const item of elements) {
395
+ if (item instanceof Uint8Array) {
396
+ combinedBytes.push(...Array.from(item));
397
+ }
398
+ else if (isComplexSlice(item) || Array.isArray(item)) {
399
+ const itemLen = len(item);
400
+ for (let i = 0; i < itemLen; i++) {
401
+ const val = item[i];
402
+ if (typeof val !== 'number') {
403
+ throw new Error("Cannot produce Uint8Array: appended elements contain non-numbers.");
404
+ }
405
+ combinedBytes.push(val);
406
+ }
407
+ }
408
+ else {
409
+ if (typeof item !== 'number') {
410
+ throw new Error("Cannot produce Uint8Array: appended elements contain non-numbers.");
411
+ }
412
+ combinedBytes.push(item);
413
+ }
414
+ }
415
+ const newArr = new Uint8Array(combinedBytes.length);
416
+ newArr.set(combinedBytes);
417
+ return newArr;
418
+ }
419
+ // Handle generic Slice<T> (non-Uint8Array result).
420
+ // In this case, `elements` are treated as individual items to append,
421
+ // as the Go transpiler is responsible for spreading (`...`) if needed.
422
+ const numAdded = elements.length;
423
+ if (numAdded === 0) {
424
+ return slice;
425
+ }
426
+ let originalElements = [];
427
+ let oldCapacity;
428
+ let isOriginalComplex = false;
429
+ let originalBacking = undefined;
430
+ let originalOffset = 0;
431
+ if (slice === null || slice === undefined) {
432
+ oldCapacity = 0;
433
+ }
434
+ else if (isComplexSlice(slice)) {
435
+ const meta = slice.__meta__;
436
+ for (let i = 0; i < meta.length; i++)
437
+ originalElements.push(meta.backing[meta.offset + i]);
438
+ oldCapacity = meta.capacity;
439
+ isOriginalComplex = true;
440
+ originalBacking = meta.backing;
441
+ originalOffset = meta.offset;
442
+ }
443
+ else { // Simple T[] array
444
+ originalElements = slice.slice();
445
+ oldCapacity = slice.length;
446
+ }
447
+ const oldLength = originalElements.length;
448
+ const newLength = oldLength + numAdded;
449
+ // Case 1: Modify in-place if original was SliceProxy and has enough capacity.
450
+ if (isOriginalComplex && newLength <= oldCapacity && originalBacking) {
451
+ for (let i = 0; i < numAdded; i++) {
452
+ originalBacking[originalOffset + oldLength + i] = elements[i];
453
+ }
454
+ const resultProxy = new Array(newLength);
455
+ for (let i = 0; i < newLength; i++)
456
+ resultProxy[i] = originalBacking[originalOffset + i];
457
+ resultProxy.__meta__ = {
458
+ backing: originalBacking,
459
+ offset: originalOffset,
460
+ length: newLength,
461
+ capacity: oldCapacity,
462
+ };
463
+ return resultProxy;
464
+ }
465
+ // Case 2: Reallocation is needed.
466
+ let newCapacity = oldCapacity;
467
+ if (newCapacity === 0) {
468
+ newCapacity = newLength;
469
+ }
470
+ else if (oldLength < 1024) {
471
+ newCapacity = Math.max(oldCapacity * 2, newLength);
472
+ }
473
+ else {
474
+ newCapacity = Math.max(oldCapacity + Math.floor(oldCapacity / 4), newLength);
475
+ }
476
+ if (newCapacity < newLength) {
477
+ newCapacity = newLength;
478
+ }
479
+ const newBacking = new Array(newCapacity);
480
+ for (let i = 0; i < oldLength; i++) {
481
+ newBacking[i] = originalElements[i];
482
+ }
483
+ for (let i = 0; i < numAdded; i++) {
484
+ newBacking[oldLength + i] = elements[i];
485
+ }
486
+ const resultProxy = new Array(newLength);
487
+ for (let i = 0; i < newLength; i++)
488
+ resultProxy[i] = newBacking[i];
489
+ resultProxy.__meta__ = {
490
+ backing: newBacking,
491
+ offset: 0,
492
+ length: newLength,
493
+ capacity: newCapacity,
494
+ };
495
+ return resultProxy;
496
+ };
497
+ /**
498
+ * Copies elements from src to dst.
499
+ * @param dst The destination slice.
500
+ * @param src The source slice.
501
+ * @returns The number of elements copied.
502
+ */
503
+ export const copy = (dst, src) => {
504
+ if (dst === null || src === null) {
505
+ return 0;
506
+ }
507
+ const dstLen = len(dst);
508
+ const srcLen = len(src);
509
+ const count = Math.min(dstLen, srcLen);
510
+ if (count === 0) {
511
+ return 0;
512
+ }
513
+ const isDstUint8Array = dst instanceof Uint8Array;
514
+ const isSrcUint8Array = src instanceof Uint8Array;
515
+ if (isDstUint8Array && isSrcUint8Array) {
516
+ dst.set(src.subarray(0, count));
517
+ }
518
+ else if (isDstUint8Array) { // dst is Uint8Array, src is Slice<number> or number[]
519
+ const dstUint8 = dst;
520
+ if (isComplexSlice(src)) {
521
+ const srcMeta = src.__meta__;
522
+ for (let i = 0; i < count; i++) {
523
+ dstUint8[i] = srcMeta.backing[srcMeta.offset + i];
524
+ }
525
+ }
526
+ else { // src is number[]
527
+ const srcArray = src;
528
+ for (let i = 0; i < count; i++) {
529
+ dstUint8[i] = srcArray[i];
530
+ }
531
+ }
532
+ }
533
+ else if (isSrcUint8Array) { // src is Uint8Array, dst is Slice<number> or number[]
534
+ const srcUint8 = src;
535
+ if (isComplexSlice(dst)) {
536
+ const dstMeta = dst.__meta__;
537
+ const dstBacking = dstMeta.backing;
538
+ const dstOffset = dstMeta.offset;
539
+ for (let i = 0; i < count; i++) {
540
+ dstBacking[dstOffset + i] = srcUint8[i];
541
+ // Also update the proxy view if dst is a proxy
542
+ dst[i] = srcUint8[i];
543
+ }
544
+ }
545
+ else { // dst is number[]
546
+ const dstArray = dst;
547
+ for (let i = 0; i < count; i++) {
548
+ dstArray[i] = srcUint8[i];
549
+ }
550
+ }
551
+ }
552
+ else { // Both are Slice<T> or T[] (original logic)
553
+ if (isComplexSlice(dst)) {
554
+ const dstOffset = dst.__meta__.offset;
555
+ const dstBacking = dst.__meta__.backing;
556
+ if (isComplexSlice(src)) {
557
+ const srcOffset = src.__meta__.offset;
558
+ const srcBacking = src.__meta__.backing;
559
+ for (let i = 0; i < count; i++) {
560
+ dstBacking[dstOffset + i] = srcBacking[srcOffset + i];
561
+ dst[i] = srcBacking[srcOffset + i]; // Update proxy
562
+ }
563
+ }
564
+ else { // src is T[]
565
+ const srcArray = src;
566
+ for (let i = 0; i < count; i++) {
567
+ dstBacking[dstOffset + i] = srcArray[i];
568
+ dst[i] = srcArray[i]; // Update proxy
569
+ }
570
+ }
571
+ }
572
+ else { // dst is T[]
573
+ const dstArray = dst;
574
+ if (isComplexSlice(src)) {
575
+ const srcOffset = src.__meta__.offset;
576
+ const srcBacking = src.__meta__.backing;
577
+ for (let i = 0; i < count; i++) {
578
+ dstArray[i] = srcBacking[srcOffset + i];
579
+ }
580
+ }
581
+ else { // src is T[]
582
+ const srcArray = src;
583
+ for (let i = 0; i < count; i++) {
584
+ dstArray[i] = srcArray[i];
585
+ }
586
+ }
587
+ }
588
+ }
589
+ return count;
590
+ };
591
+ /**
592
+ * Accesses an element at a specific index for various Go-like types (string, slice, array).
593
+ * Mimics Go's indexing behavior: `myCollection[index]`
594
+ * For strings, it returns the byte value at the specified byte index.
595
+ * For slices/arrays, it returns the element at the specified index.
596
+ * This is used when dealing with types like "string | []byte"
597
+ * @param collection The string, Slice, or Array to access.
598
+ * @param index The index.
599
+ * @returns The element or byte value at the specified index.
600
+ * @throws Error if index is out of bounds or type is unsupported.
601
+ */
602
+ export function index(collection, index) {
603
+ if (collection === null || collection === undefined) {
604
+ throw new Error('runtime error: index on nil or undefined collection');
605
+ }
606
+ if (typeof collection === 'string') {
607
+ return indexString(collection, index); // Use the existing indexString for byte access
608
+ }
609
+ else if (collection instanceof Uint8Array) {
610
+ if (index < 0 || index >= collection.length) {
611
+ throw new Error(`runtime error: index out of range [${index}] with length ${collection.length}`);
612
+ }
613
+ return collection[index];
614
+ }
615
+ else if (isComplexSlice(collection)) {
616
+ if (index < 0 || index >= collection.__meta__.length) {
617
+ throw new Error(`runtime error: index out of range [${index}] with length ${collection.__meta__.length}`);
618
+ }
619
+ return collection.__meta__.backing[collection.__meta__.offset + index];
620
+ }
621
+ else if (Array.isArray(collection)) {
622
+ if (index < 0 || index >= collection.length) {
623
+ throw new Error(`runtime error: index out of range [${index}] with length ${collection.length}`);
624
+ }
625
+ return collection[index];
626
+ }
627
+ throw new Error('runtime error: index on unsupported type');
628
+ }
629
+ /**
630
+ * Converts a string to an array of Unicode code points (runes).
631
+ * @param str The input string.
632
+ * @returns An array of numbers representing the Unicode code points.
633
+ */
634
+ export const stringToRunes = (str) => {
635
+ return Array.from(str).map((c) => c.codePointAt(0) || 0);
636
+ };
637
+ /**
638
+ * Converts an array of Unicode code points (runes) to a string.
639
+ * @param runes The input array of numbers representing Unicode code points.
640
+ * @returns The resulting string.
641
+ */
642
+ export const runesToString = (runes) => {
643
+ return runes?.length ? String.fromCharCode(...runes) : '';
644
+ };
645
+ /**
646
+ * Converts a number to a byte (uint8) by truncating to the range 0-255.
647
+ * Equivalent to Go's byte() conversion.
648
+ * @param n The number to convert to a byte.
649
+ * @returns The byte value (0-255).
650
+ */
651
+ export const byte = (n) => {
652
+ return n & 0xff; // Bitwise AND with 255 ensures we get a value in the range 0-255
653
+ };
654
+ /**
655
+ * Accesses the byte value at a specific index of a UTF-8 encoded string.
656
+ * Mimics Go's string indexing behavior: `myString[index]`
657
+ * @param str The string to access.
658
+ * @param index The byte index.
659
+ * @returns The byte value (0-255) at the specified index.
660
+ * @throws Error if index is out of bounds.
661
+ */
662
+ export const indexString = (str, index) => {
663
+ const bytes = new TextEncoder().encode(str);
664
+ if (index < 0 || index >= bytes.length) {
665
+ throw new Error(`runtime error: index out of range [${index}] with length ${bytes.length}`);
666
+ }
667
+ return bytes[index];
668
+ };
669
+ /**
670
+ * Returns the byte length of a string.
671
+ * Mimics Go's `len(string)` behavior.
672
+ * @param str The string.
673
+ * @returns The number of bytes in the UTF-8 representation of the string.
674
+ */
675
+ export const stringLen = (str) => {
676
+ return new TextEncoder().encode(str).length;
677
+ };
678
+ /**
679
+ * Slices a string based on byte indices.
680
+ * Mimics Go's string slicing behavior: `myString[low:high]` for valid UTF-8 slices only.
681
+ * @param str The string to slice.
682
+ * @param low The starting byte index (inclusive). Defaults to 0.
683
+ * @param high The ending byte index (exclusive). Defaults to string byte length.
684
+ * @returns The sliced string.
685
+ * @throws Error if the slice would create invalid UTF-8.
686
+ */
687
+ export const sliceString = (str, low, high) => {
688
+ const bytes = new TextEncoder().encode(str);
689
+ const actualLow = low === undefined ? 0 : low;
690
+ const actualHigh = high === undefined ? bytes.length : high;
691
+ if (actualLow < 0 || actualHigh < actualLow || actualHigh > bytes.length) {
692
+ // Go's behavior for out-of-bounds slice on string is a panic.
693
+ // For simple slices like s[len(s):len(s)], it should produce an empty string.
694
+ // For s[len(s)+1:], it panics.
695
+ // Let's ensure high <= bytes.length and low <= high.
696
+ // If low == high, it's an empty string.
697
+ if (actualLow === actualHigh &&
698
+ actualLow >= 0 &&
699
+ actualLow <= bytes.length) {
700
+ return '';
701
+ }
702
+ throw new Error(`runtime error: slice bounds out of range [${actualLow}:${actualHigh}] with length ${bytes.length}`);
703
+ }
704
+ const slicedBytes = bytes.subarray(actualLow, actualHigh);
705
+ try {
706
+ // Attempt to decode with strict UTF-8 validation
707
+ const result = new TextDecoder('utf-8', { fatal: true }).decode(slicedBytes);
708
+ return result;
709
+ }
710
+ catch (e) {
711
+ // If we get here, the slice would create invalid UTF-8
712
+ // This is a fundamental limitation of JavaScript string handling
713
+ throw new Error(`Cannot slice string at byte indices [${actualLow}:${actualHigh}] because it would create invalid UTF-8. ` +
714
+ `This is a limitation of JavaScript's string handling.`);
715
+ }
716
+ };
717
+ /**
718
+ * Converts a Slice<number> (byte array) to a string using TextDecoder.
719
+ * @param bytes The Slice<number> to convert.
720
+ * @returns The resulting string.
721
+ */
722
+ export const bytesToString = (bytes) => {
723
+ if (bytes === null)
724
+ return '';
725
+ if (bytes instanceof Uint8Array) {
726
+ return new TextDecoder().decode(bytes);
727
+ }
728
+ // Ensure we get a plain number[] for Uint8Array.from
729
+ let byteArray;
730
+ if (isComplexSlice(bytes)) {
731
+ // For complex slices, extract the relevant part of the backing array
732
+ byteArray = bytes.__meta__.backing.slice(bytes.__meta__.offset, bytes.__meta__.offset + bytes.__meta__.length);
733
+ }
734
+ else {
735
+ // For simple T[] slices
736
+ byteArray = bytes;
737
+ }
738
+ return new TextDecoder().decode(Uint8Array.from(byteArray));
739
+ };
740
+ /**
741
+ * Converts a string to a Uint8Array (byte slice).
742
+ * @param s The input string.
743
+ * @returns A Uint8Array representing the UTF-8 bytes of the string.
744
+ */
745
+ export function stringToBytes(s) {
746
+ return new TextEncoder().encode(s);
747
+ }
748
+ /**
749
+ * Handles string() conversion for values that could be either string or []byte.
750
+ * Used for generic type parameters with constraint []byte|string.
751
+ * @param value Value that is either a string or Uint8Array
752
+ * @returns The string representation
753
+ */
754
+ export function genericBytesOrStringToString(value) {
755
+ if (typeof value === 'string') {
756
+ return value;
757
+ }
758
+ return bytesToString(value);
759
+ }
760
+ /**
761
+ * Indexes into a value that could be either a string or Uint8Array.
762
+ * Used for generic type parameters with constraint string | []byte.
763
+ * Both cases return a byte value (number).
764
+ * @param value Value that is either a string or Uint8Array
765
+ * @param index The index to access
766
+ * @returns The byte value at the specified index
767
+ */
768
+ export function indexStringOrBytes(value, index) {
769
+ if (typeof value === 'string') {
770
+ return indexString(value, index);
771
+ }
772
+ else {
773
+ // For Uint8Array, direct access returns the byte value
774
+ if (index < 0 || index >= value.length) {
775
+ throw new Error(`runtime error: index out of range [${index}] with length ${value.length}`);
776
+ }
777
+ return value[index];
778
+ }
779
+ }
780
+ /**
781
+ * Slices a value that could be either a string or Uint8Array.
782
+ * Used for generic type parameters with constraint string | []byte.
783
+ * @param value Value that is either a string or Uint8Array
784
+ * @param low Starting index (inclusive). Defaults to 0.
785
+ * @param high Ending index (exclusive). Defaults to length.
786
+ * @param max Capacity limit (only used for Uint8Array, ignored for strings)
787
+ * @returns The sliced value of the same type as input
788
+ */
789
+ export function sliceStringOrBytes(value, low, high, max) {
790
+ if (typeof value === 'string') {
791
+ // For strings, use sliceString and ignore max parameter
792
+ return sliceString(value, low, high);
793
+ }
794
+ else {
795
+ // For Uint8Array, use goSlice
796
+ return goSlice(value, low, high, max);
797
+ }
798
+ }
799
+ //# sourceMappingURL=slice.js.map