goscript 0.0.14 → 0.0.16
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.
- package/README.md +154 -40
- package/builtin/builtin.ts +1168 -178
- package/compiler/analysis.go +726 -0
- package/compiler/compiler.go +5701 -4
- package/compiler/compiler_test.go +104 -0
- package/compiler/config.go +3 -3
- package/compiler/config_test.go +89 -0
- package/compiler/output.go +26 -0
- package/compiler/write-type-spec.go +506 -0
- package/compiler/writer.go +11 -0
- package/dist/builtin/builtin.d.ts +204 -67
- package/dist/builtin/builtin.js +845 -144
- package/dist/builtin/builtin.js.map +1 -1
- package/go.mod +4 -5
- package/go.sum +6 -11
- package/package.json +4 -3
- package/compiler/compile.go +0 -190
- package/compiler/compile_comment.go +0 -41
- package/compiler/compile_decls.go +0 -84
- package/compiler/compile_expr.go +0 -1022
- package/compiler/compile_field.go +0 -110
- package/compiler/compile_spec.go +0 -566
- package/compiler/compile_stmt.go +0 -1616
- package/compiler/context.go +0 -9
- package/compiler/file_compiler.go +0 -80
- package/compiler/output_path.go +0 -31
- package/compiler/pkg_compiler.go +0 -72
- package/compiler/types/tokens.go +0 -66
- package/compiler/types/types.go +0 -46
- package/dist/compliance/tests/array_literal/array_literal.gs.d.ts +0 -1
- package/dist/compliance/tests/array_literal/array_literal.gs.js +0 -15
- package/dist/compliance/tests/array_literal/array_literal.gs.js.map +0 -1
- package/dist/compliance/tests/async_basic/async_basic.gs.d.ts +0 -1
- package/dist/compliance/tests/async_basic/async_basic.gs.js +0 -24
- package/dist/compliance/tests/async_basic/async_basic.gs.js.map +0 -1
- package/dist/compliance/tests/async_defer_statement/async_defer_statement.gs.d.ts +0 -1
- package/dist/compliance/tests/async_defer_statement/async_defer_statement.gs.js +0 -82
- package/dist/compliance/tests/async_defer_statement/async_defer_statement.gs.js.map +0 -1
- package/dist/compliance/tests/basic_arithmetic/basic_arithmetic.gs.d.ts +0 -1
- package/dist/compliance/tests/basic_arithmetic/basic_arithmetic.gs.js +0 -16
- package/dist/compliance/tests/basic_arithmetic/basic_arithmetic.gs.js.map +0 -1
- package/dist/compliance/tests/boolean_logic/boolean_logic.gs.d.ts +0 -1
- package/dist/compliance/tests/boolean_logic/boolean_logic.gs.js +0 -14
- package/dist/compliance/tests/boolean_logic/boolean_logic.gs.js.map +0 -1
- package/dist/compliance/tests/channel_basic/channel_basic.gs.d.ts +0 -1
- package/dist/compliance/tests/channel_basic/channel_basic.gs.js +0 -14
- package/dist/compliance/tests/channel_basic/channel_basic.gs.js.map +0 -1
- package/dist/compliance/tests/composite_literal_assignment/composite_literal_assignment.gs.d.ts +0 -1
- package/dist/compliance/tests/composite_literal_assignment/composite_literal_assignment.gs.js +0 -27
- package/dist/compliance/tests/composite_literal_assignment/composite_literal_assignment.gs.js.map +0 -1
- package/dist/compliance/tests/constants/constants.gs.d.ts +0 -1
- package/dist/compliance/tests/constants/constants.gs.js +0 -16
- package/dist/compliance/tests/constants/constants.gs.js.map +0 -1
- package/dist/compliance/tests/copy_independence/copy_independence.gs.d.ts +0 -1
- package/dist/compliance/tests/copy_independence/copy_independence.gs.js +0 -33
- package/dist/compliance/tests/copy_independence/copy_independence.gs.js.map +0 -1
- package/dist/compliance/tests/defer_statement/defer_statement.gs.d.ts +0 -1
- package/dist/compliance/tests/defer_statement/defer_statement.gs.js +0 -75
- package/dist/compliance/tests/defer_statement/defer_statement.gs.js.map +0 -1
- package/dist/compliance/tests/embedded_interface_assertion/embedded_interface_assertion.gs.d.ts +0 -1
- package/dist/compliance/tests/embedded_interface_assertion/embedded_interface_assertion.gs.js +0 -37
- package/dist/compliance/tests/embedded_interface_assertion/embedded_interface_assertion.gs.js.map +0 -1
- package/dist/compliance/tests/flag_bitwise_op/flag_bitwise_op.gs.d.ts +0 -1
- package/dist/compliance/tests/flag_bitwise_op/flag_bitwise_op.gs.js +0 -29
- package/dist/compliance/tests/flag_bitwise_op/flag_bitwise_op.gs.js.map +0 -1
- package/dist/compliance/tests/float64/float64.gs.d.ts +0 -1
- package/dist/compliance/tests/float64/float64.gs.js +0 -24
- package/dist/compliance/tests/float64/float64.gs.js.map +0 -1
- package/dist/compliance/tests/for_loop_basic/for_loop_basic.gs.d.ts +0 -1
- package/dist/compliance/tests/for_loop_basic/for_loop_basic.gs.js +0 -10
- package/dist/compliance/tests/for_loop_basic/for_loop_basic.gs.js.map +0 -1
- package/dist/compliance/tests/for_loop_condition_only/for_loop_condition_only.gs.d.ts +0 -1
- package/dist/compliance/tests/for_loop_condition_only/for_loop_condition_only.gs.js +0 -11
- package/dist/compliance/tests/for_loop_condition_only/for_loop_condition_only.gs.js.map +0 -1
- package/dist/compliance/tests/for_loop_condition_only/main.gs.d.ts +0 -1
- package/dist/compliance/tests/for_loop_condition_only/main.gs.js +0 -10
- package/dist/compliance/tests/for_loop_condition_only/main.gs.js.map +0 -1
- package/dist/compliance/tests/for_loop_infinite/for_loop_infinite.gs.d.ts +0 -1
- package/dist/compliance/tests/for_loop_infinite/for_loop_infinite.gs.js +0 -14
- package/dist/compliance/tests/for_loop_infinite/for_loop_infinite.gs.js.map +0 -1
- package/dist/compliance/tests/for_range/for_range.gs.d.ts +0 -1
- package/dist/compliance/tests/for_range/for_range.gs.js +0 -39
- package/dist/compliance/tests/for_range/for_range.gs.js.map +0 -1
- package/dist/compliance/tests/for_range_index_use/for_range_index_use.gs.d.ts +0 -1
- package/dist/compliance/tests/for_range_index_use/for_range_index_use.gs.js +0 -15
- package/dist/compliance/tests/for_range_index_use/for_range_index_use.gs.js.map +0 -1
- package/dist/compliance/tests/func_literal/func_literal.gs.d.ts +0 -1
- package/dist/compliance/tests/func_literal/func_literal.gs.js +0 -10
- package/dist/compliance/tests/func_literal/func_literal.gs.js.map +0 -1
- package/dist/compliance/tests/function_call_result_assignment/function_call_result_assignment.gs.d.ts +0 -12
- package/dist/compliance/tests/function_call_result_assignment/function_call_result_assignment.gs.js +0 -30
- package/dist/compliance/tests/function_call_result_assignment/function_call_result_assignment.gs.js.map +0 -1
- package/dist/compliance/tests/if_statement/if_statement.gs.d.ts +0 -1
- package/dist/compliance/tests/if_statement/if_statement.gs.js +0 -13
- package/dist/compliance/tests/if_statement/if_statement.gs.js.map +0 -1
- package/dist/compliance/tests/interface_method_comments/interface_method_comments.gs.d.ts +0 -1
- package/dist/compliance/tests/interface_method_comments/interface_method_comments.gs.js +0 -12
- package/dist/compliance/tests/interface_method_comments/interface_method_comments.gs.js.map +0 -1
- package/dist/compliance/tests/interface_multi_param_return/interface_multi_param_return.gs.d.ts +0 -1
- package/dist/compliance/tests/interface_multi_param_return/interface_multi_param_return.gs.js +0 -34
- package/dist/compliance/tests/interface_multi_param_return/interface_multi_param_return.gs.js.map +0 -1
- package/dist/compliance/tests/interface_to_interface_type_assertion/interface_to_interface_type_assertion.gs.d.ts +0 -1
- package/dist/compliance/tests/interface_to_interface_type_assertion/interface_to_interface_type_assertion.gs.js +0 -32
- package/dist/compliance/tests/interface_to_interface_type_assertion/interface_to_interface_type_assertion.gs.js.map +0 -1
- package/dist/compliance/tests/interface_type_assertion/interface_type_assertion.gs.d.ts +0 -1
- package/dist/compliance/tests/interface_type_assertion/interface_type_assertion.gs.js +0 -40
- package/dist/compliance/tests/interface_type_assertion/interface_type_assertion.gs.js.map +0 -1
- package/dist/compliance/tests/interface_type_assertion_signature_mismatch/interface_type_assertion_signature_mismatch.gs.d.ts +0 -1
- package/dist/compliance/tests/interface_type_assertion_signature_mismatch/interface_type_assertion_signature_mismatch.gs.js +0 -51
- package/dist/compliance/tests/interface_type_assertion_signature_mismatch/interface_type_assertion_signature_mismatch.gs.js.map +0 -1
- package/dist/compliance/tests/map_support/map_support.gs.d.ts +0 -1
- package/dist/compliance/tests/map_support/map_support.gs.js +0 -88
- package/dist/compliance/tests/map_support/map_support.gs.js.map +0 -1
- package/dist/compliance/tests/method_call_on_pointer_receiver/method_call_on_pointer_receiver.gs.d.ts +0 -1
- package/dist/compliance/tests/method_call_on_pointer_receiver/method_call_on_pointer_receiver.gs.js +0 -24
- package/dist/compliance/tests/method_call_on_pointer_receiver/method_call_on_pointer_receiver.gs.js.map +0 -1
- package/dist/compliance/tests/method_call_on_pointer_via_value/method_call_on_pointer_via_value.gs.d.ts +0 -1
- package/dist/compliance/tests/method_call_on_pointer_via_value/method_call_on_pointer_via_value.gs.js +0 -33
- package/dist/compliance/tests/method_call_on_pointer_via_value/method_call_on_pointer_via_value.gs.js.map +0 -1
- package/dist/compliance/tests/method_call_on_value_receiver/method_call_on_value_receiver.gs.d.ts +0 -1
- package/dist/compliance/tests/method_call_on_value_receiver/method_call_on_value_receiver.gs.js +0 -22
- package/dist/compliance/tests/method_call_on_value_receiver/method_call_on_value_receiver.gs.js.map +0 -1
- package/dist/compliance/tests/method_call_on_value_via_pointer/method_call_on_value_via_pointer.gs.d.ts +0 -1
- package/dist/compliance/tests/method_call_on_value_via_pointer/method_call_on_value_via_pointer.gs.js +0 -33
- package/dist/compliance/tests/method_call_on_value_via_pointer/method_call_on_value_via_pointer.gs.js.map +0 -1
- package/dist/compliance/tests/multiple_return_values/multiple_return_values.gs.d.ts +0 -1
- package/dist/compliance/tests/multiple_return_values/multiple_return_values.gs.js +0 -17
- package/dist/compliance/tests/multiple_return_values/multiple_return_values.gs.js.map +0 -1
- package/dist/compliance/tests/pointer_assignment_no_copy/pointer_assignment_no_copy.gs.d.ts +0 -1
- package/dist/compliance/tests/pointer_assignment_no_copy/pointer_assignment_no_copy.gs.js +0 -29
- package/dist/compliance/tests/pointer_assignment_no_copy/pointer_assignment_no_copy.gs.js.map +0 -1
- package/dist/compliance/tests/pointer_composite_literal_assignment/pointer_composite_literal_assignment.gs.d.ts +0 -1
- package/dist/compliance/tests/pointer_composite_literal_assignment/pointer_composite_literal_assignment.gs.js +0 -27
- package/dist/compliance/tests/pointer_composite_literal_assignment/pointer_composite_literal_assignment.gs.js.map +0 -1
- package/dist/compliance/tests/pointer_deref_multiassign/pointer_deref_multiassign.gs.d.ts +0 -1
- package/dist/compliance/tests/pointer_deref_multiassign/pointer_deref_multiassign.gs.js +0 -22
- package/dist/compliance/tests/pointer_deref_multiassign/pointer_deref_multiassign.gs.js.map +0 -1
- package/dist/compliance/tests/pointer_initialization/pointer_initialization.gs.d.ts +0 -1
- package/dist/compliance/tests/pointer_initialization/pointer_initialization.gs.js +0 -20
- package/dist/compliance/tests/pointer_initialization/pointer_initialization.gs.js.map +0 -1
- package/dist/compliance/tests/select_receive_on_closed_channel_no_default/select_receive_on_closed_channel_no_default.gs.d.ts +0 -1
- package/dist/compliance/tests/select_receive_on_closed_channel_no_default/select_receive_on_closed_channel_no_default.gs.js +0 -28
- package/dist/compliance/tests/select_receive_on_closed_channel_no_default/select_receive_on_closed_channel_no_default.gs.js.map +0 -1
- package/dist/compliance/tests/select_send_on_full_buffered_channel_with_default/select_send_on_full_buffered_channel_with_default.gs.d.ts +0 -1
- package/dist/compliance/tests/select_send_on_full_buffered_channel_with_default/select_send_on_full_buffered_channel_with_default.gs.js +0 -30
- package/dist/compliance/tests/select_send_on_full_buffered_channel_with_default/select_send_on_full_buffered_channel_with_default.gs.js.map +0 -1
- package/dist/compliance/tests/select_statement/select_statement.gs.d.ts +0 -1
- package/dist/compliance/tests/select_statement/select_statement.gs.js +0 -207
- package/dist/compliance/tests/select_statement/select_statement.gs.js.map +0 -1
- package/dist/compliance/tests/simple/simple.gs.d.ts +0 -1
- package/dist/compliance/tests/simple/simple.gs.js +0 -6
- package/dist/compliance/tests/simple/simple.gs.js.map +0 -1
- package/dist/compliance/tests/simple_deref_assignment/simple_deref_assignment.gs.d.ts +0 -1
- package/dist/compliance/tests/simple_deref_assignment/simple_deref_assignment.gs.js +0 -24
- package/dist/compliance/tests/simple_deref_assignment/simple_deref_assignment.gs.js.map +0 -1
- package/dist/compliance/tests/slices/slices.gs.d.ts +0 -1
- package/dist/compliance/tests/slices/slices.gs.js +0 -294
- package/dist/compliance/tests/slices/slices.gs.js.map +0 -1
- package/dist/compliance/tests/string_conversion/string_conversion.gs.d.ts +0 -1
- package/dist/compliance/tests/string_conversion/string_conversion.gs.js +0 -41
- package/dist/compliance/tests/string_conversion/string_conversion.gs.js.map +0 -1
- package/dist/compliance/tests/string_rune_conversion/string_rune_conversion.gs.d.ts +0 -1
- package/dist/compliance/tests/string_rune_conversion/string_rune_conversion.gs.js +0 -17
- package/dist/compliance/tests/string_rune_conversion/string_rune_conversion.gs.js.map +0 -1
- package/dist/compliance/tests/struct_embedding/struct_embedding.gs.d.ts +0 -1
- package/dist/compliance/tests/struct_embedding/struct_embedding.gs.js +0 -48
- package/dist/compliance/tests/struct_embedding/struct_embedding.gs.js.map +0 -1
- package/dist/compliance/tests/struct_field_access/struct_field_access.gs.d.ts +0 -1
- package/dist/compliance/tests/struct_field_access/struct_field_access.gs.js +0 -19
- package/dist/compliance/tests/struct_field_access/struct_field_access.gs.js.map +0 -1
- package/dist/compliance/tests/struct_pointer_interface_fields/struct_pointer_interface_fields.gs.d.ts +0 -1
- package/dist/compliance/tests/struct_pointer_interface_fields/struct_pointer_interface_fields.gs.js +0 -26
- package/dist/compliance/tests/struct_pointer_interface_fields/struct_pointer_interface_fields.gs.js.map +0 -1
- package/dist/compliance/tests/struct_value_init_clone/struct_value_init_clone.gs.d.ts +0 -1
- package/dist/compliance/tests/struct_value_init_clone/struct_value_init_clone.gs.js +0 -30
- package/dist/compliance/tests/struct_value_init_clone/struct_value_init_clone.gs.js.map +0 -1
- package/dist/compliance/tests/switch_statement/switch_statement.gs.d.ts +0 -1
- package/dist/compliance/tests/switch_statement/switch_statement.gs.js +0 -76
- package/dist/compliance/tests/switch_statement/switch_statement.gs.js.map +0 -1
- package/dist/compliance/tests/value_type_copy_behavior/value_type_copy_behavior.gs.d.ts +0 -1
- package/dist/compliance/tests/value_type_copy_behavior/value_type_copy_behavior.gs.js +0 -31
- package/dist/compliance/tests/value_type_copy_behavior/value_type_copy_behavior.gs.js.map +0 -1
package/dist/builtin/builtin.js
CHANGED
|
@@ -1,32 +1,165 @@
|
|
|
1
|
+
export function asArray(slice) {
|
|
2
|
+
return slice;
|
|
3
|
+
}
|
|
1
4
|
/**
|
|
2
|
-
*
|
|
3
|
-
* @param len The length of the slice.
|
|
4
|
-
* @param cap The capacity of the slice (optional).
|
|
5
|
-
* @returns A new TypeScript array representing the slice.
|
|
5
|
+
* isComplexSlice checks if a slice is a complex slice (has __meta__ property)
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
function isComplexSlice(slice) {
|
|
8
|
+
return (slice !== null &&
|
|
9
|
+
slice !== undefined &&
|
|
10
|
+
'__meta__' in slice &&
|
|
11
|
+
slice.__meta__ !== undefined);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Creates a new slice with the specified length and capacity.
|
|
15
|
+
* @param length The length of the slice.
|
|
16
|
+
* @param capacity The capacity of the slice (optional).
|
|
17
|
+
* @returns A new slice.
|
|
18
|
+
*/
|
|
19
|
+
export const makeSlice = (length, capacity) => {
|
|
20
|
+
if (capacity === undefined) {
|
|
21
|
+
capacity = length;
|
|
22
|
+
}
|
|
23
|
+
if (length < 0 || capacity < 0 || length > capacity) {
|
|
24
|
+
throw new Error(`Invalid slice length (${length}) or capacity (${capacity})`);
|
|
25
|
+
}
|
|
26
|
+
const arr = new Array(length);
|
|
27
|
+
// Always create a complex slice with metadata to preserve capacity information
|
|
28
|
+
const proxy = arr;
|
|
29
|
+
proxy.__meta__ = {
|
|
30
|
+
backing: new Array(capacity),
|
|
31
|
+
offset: 0,
|
|
32
|
+
length: length,
|
|
33
|
+
capacity: capacity,
|
|
34
|
+
};
|
|
35
|
+
for (let i = 0; i < length; i++) {
|
|
36
|
+
proxy.__meta__.backing[i] = arr[i];
|
|
37
|
+
}
|
|
38
|
+
return proxy;
|
|
11
39
|
};
|
|
12
40
|
/**
|
|
13
|
-
*
|
|
41
|
+
* goSlice creates a slice from s[low:high:max]
|
|
14
42
|
* Arguments mirror Go semantics; omitted indices are undefined.
|
|
15
43
|
*
|
|
16
|
-
* @param
|
|
17
|
-
* @param low
|
|
18
|
-
* @param high Ending index (defaults to
|
|
19
|
-
* @param max
|
|
20
|
-
*/
|
|
21
|
-
export const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
44
|
+
* @param s The original slice
|
|
45
|
+
* @param low Starting index (defaults to 0)
|
|
46
|
+
* @param high Ending index (defaults to s.length)
|
|
47
|
+
* @param max Capacity limit (defaults to original capacity)
|
|
48
|
+
*/
|
|
49
|
+
export const goSlice = (s, low, high, max) => {
|
|
50
|
+
if (s === null || s === undefined) {
|
|
51
|
+
throw new Error('Cannot slice nil');
|
|
52
|
+
}
|
|
53
|
+
const slen = len(s);
|
|
54
|
+
low = low ?? 0;
|
|
55
|
+
high = high ?? slen;
|
|
56
|
+
if (low < 0 || high < low) {
|
|
57
|
+
throw new Error(`Invalid slice indices: ${low}:${high}`);
|
|
58
|
+
}
|
|
59
|
+
// In Go, high can be up to capacity, not just length
|
|
60
|
+
const scap = cap(s);
|
|
61
|
+
if (high > scap) {
|
|
62
|
+
throw new Error(`Slice index out of range: ${high} > ${scap}`);
|
|
63
|
+
}
|
|
64
|
+
if (Array.isArray(s) &&
|
|
65
|
+
!isComplexSlice(s) &&
|
|
66
|
+
low === 0 &&
|
|
67
|
+
high === s.length &&
|
|
68
|
+
max === undefined) {
|
|
69
|
+
return s;
|
|
70
|
+
}
|
|
71
|
+
let backing;
|
|
72
|
+
let oldOffset = 0;
|
|
73
|
+
let oldCap = scap;
|
|
74
|
+
// Get the backing array and offset
|
|
75
|
+
if (isComplexSlice(s)) {
|
|
76
|
+
backing = s.__meta__.backing;
|
|
77
|
+
oldOffset = s.__meta__.offset;
|
|
78
|
+
oldCap = s.__meta__.capacity;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
backing = s;
|
|
82
|
+
}
|
|
83
|
+
let newCap;
|
|
84
|
+
if (max !== undefined) {
|
|
85
|
+
if (max < high) {
|
|
86
|
+
throw new Error(`Invalid slice indices: ${low}:${high}:${max}`);
|
|
87
|
+
}
|
|
88
|
+
if (isComplexSlice(s) && max > oldOffset + oldCap) {
|
|
89
|
+
throw new Error(`Slice index out of range: ${max} > ${oldOffset + oldCap}`);
|
|
90
|
+
}
|
|
91
|
+
if (!isComplexSlice(s) && max > s.length) {
|
|
92
|
+
throw new Error(`Slice index out of range: ${max} > ${s.length}`);
|
|
93
|
+
}
|
|
94
|
+
newCap = max - low;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
// For slices of slices, capacity should be the capacity of the original slice minus the low index
|
|
98
|
+
if (isComplexSlice(s)) {
|
|
99
|
+
newCap = oldCap - low;
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
newCap = s.length - low;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const newLength = high - low;
|
|
106
|
+
const newOffset = oldOffset + low;
|
|
107
|
+
const target = {
|
|
108
|
+
__meta__: {
|
|
109
|
+
backing: backing,
|
|
110
|
+
offset: newOffset,
|
|
111
|
+
length: newLength,
|
|
112
|
+
capacity: newCap,
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
const handler = {
|
|
116
|
+
get(target, prop) {
|
|
117
|
+
if (typeof prop === 'string' && /^\d+$/.test(prop)) {
|
|
118
|
+
const index = Number(prop);
|
|
119
|
+
if (index >= 0 && index < target.__meta__.length) {
|
|
120
|
+
return target.__meta__.backing[target.__meta__.offset + index];
|
|
121
|
+
}
|
|
122
|
+
throw new Error(`Slice index out of range: ${index} >= ${target.__meta__.length}`);
|
|
123
|
+
}
|
|
124
|
+
if (prop === 'length') {
|
|
125
|
+
return target.__meta__.length;
|
|
126
|
+
}
|
|
127
|
+
if (prop === '__meta__') {
|
|
128
|
+
return target.__meta__;
|
|
129
|
+
}
|
|
130
|
+
if (prop === 'slice' ||
|
|
131
|
+
prop === 'map' ||
|
|
132
|
+
prop === 'filter' ||
|
|
133
|
+
prop === 'reduce' ||
|
|
134
|
+
prop === 'forEach' ||
|
|
135
|
+
prop === Symbol.iterator) {
|
|
136
|
+
const backingSlice = target.__meta__.backing.slice(target.__meta__.offset, target.__meta__.offset + target.__meta__.length);
|
|
137
|
+
return backingSlice[prop].bind(backingSlice);
|
|
138
|
+
}
|
|
139
|
+
return Reflect.get(target, prop);
|
|
140
|
+
},
|
|
141
|
+
set(target, prop, value) {
|
|
142
|
+
if (typeof prop === 'string' && /^\d+$/.test(prop)) {
|
|
143
|
+
const index = Number(prop);
|
|
144
|
+
if (index >= 0 && index < target.__meta__.length) {
|
|
145
|
+
target.__meta__.backing[target.__meta__.offset + index] = value;
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
if (index === target.__meta__.length &&
|
|
149
|
+
target.__meta__.length < target.__meta__.capacity) {
|
|
150
|
+
target.__meta__.backing[target.__meta__.offset + index] = value;
|
|
151
|
+
target.__meta__.length++;
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
throw new Error(`Slice index out of range: ${index} >= ${target.__meta__.length}`);
|
|
155
|
+
}
|
|
156
|
+
if (prop === 'length' || prop === '__meta__') {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
return Reflect.set(target, prop, value);
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
return new Proxy(target, handler);
|
|
30
163
|
};
|
|
31
164
|
/**
|
|
32
165
|
* Creates a new map (TypeScript Map).
|
|
@@ -36,26 +169,293 @@ export const makeMap = () => {
|
|
|
36
169
|
return new Map();
|
|
37
170
|
};
|
|
38
171
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
172
|
+
* Converts a JavaScript array to a Go slice.
|
|
173
|
+
* For multi-dimensional arrays, recursively converts nested arrays to slices.
|
|
174
|
+
* @param arr The JavaScript array to convert
|
|
175
|
+
* @param depth How many levels of nesting to convert (default: 1, use Infinity for all levels)
|
|
176
|
+
* @returns A Go slice containing the same elements
|
|
177
|
+
*/
|
|
178
|
+
export const arrayToSlice = (arr, depth = 1) => {
|
|
179
|
+
if (arr == null)
|
|
180
|
+
return [];
|
|
181
|
+
if (arr.length === 0)
|
|
182
|
+
return arr;
|
|
183
|
+
const target = {
|
|
184
|
+
__meta__: {
|
|
185
|
+
backing: arr,
|
|
186
|
+
offset: 0,
|
|
187
|
+
length: arr.length,
|
|
188
|
+
capacity: arr.length,
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
const handler = {
|
|
192
|
+
get(target, prop) {
|
|
193
|
+
if (typeof prop === 'string' && /^\d+$/.test(prop)) {
|
|
194
|
+
const index = Number(prop);
|
|
195
|
+
if (index >= 0 && index < target.__meta__.length) {
|
|
196
|
+
return target.__meta__.backing[target.__meta__.offset + index];
|
|
197
|
+
}
|
|
198
|
+
throw new Error(`Slice index out of range: ${index} >= ${target.__meta__.length}`);
|
|
199
|
+
}
|
|
200
|
+
if (prop === 'length') {
|
|
201
|
+
return target.__meta__.length;
|
|
202
|
+
}
|
|
203
|
+
if (prop === '__meta__') {
|
|
204
|
+
return target.__meta__;
|
|
205
|
+
}
|
|
206
|
+
if (prop === 'slice' ||
|
|
207
|
+
prop === 'map' ||
|
|
208
|
+
prop === 'filter' ||
|
|
209
|
+
prop === 'reduce' ||
|
|
210
|
+
prop === 'forEach' ||
|
|
211
|
+
prop === Symbol.iterator) {
|
|
212
|
+
const backingSlice = target.__meta__.backing.slice(target.__meta__.offset, target.__meta__.offset + target.__meta__.length);
|
|
213
|
+
return backingSlice[prop].bind(backingSlice);
|
|
214
|
+
}
|
|
215
|
+
return Reflect.get(target, prop);
|
|
216
|
+
},
|
|
217
|
+
set(target, prop, value) {
|
|
218
|
+
if (typeof prop === 'string' && /^\d+$/.test(prop)) {
|
|
219
|
+
const index = Number(prop);
|
|
220
|
+
if (index >= 0 && index < target.__meta__.length) {
|
|
221
|
+
target.__meta__.backing[target.__meta__.offset + index] = value;
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
if (index === target.__meta__.length &&
|
|
225
|
+
target.__meta__.length < target.__meta__.capacity) {
|
|
226
|
+
target.__meta__.backing[target.__meta__.offset + index] = value;
|
|
227
|
+
target.__meta__.length++;
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
throw new Error(`Slice index out of range: ${index} >= ${target.__meta__.length}`);
|
|
231
|
+
}
|
|
232
|
+
if (prop === 'length' || prop === '__meta__') {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
return Reflect.set(target, prop, value);
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
// Recursively convert nested arrays if depth > 1
|
|
239
|
+
if (depth > 1 && arr.length > 0) {
|
|
240
|
+
for (let i = 0; i < arr.length; i++) {
|
|
241
|
+
const item = arr[i];
|
|
242
|
+
if (isComplexSlice(item)) {
|
|
243
|
+
}
|
|
244
|
+
else if (Array.isArray(item)) {
|
|
245
|
+
arr[i] = arrayToSlice(item, depth - 1);
|
|
246
|
+
}
|
|
247
|
+
else if (item &&
|
|
248
|
+
typeof item === 'object' &&
|
|
249
|
+
isComplexSlice(item)) {
|
|
250
|
+
// Preserve capacity information for complex slices
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return new Proxy(target, handler);
|
|
255
|
+
};
|
|
256
|
+
/**
|
|
257
|
+
* Returns the length of a collection (string, array, slice, map, or set).
|
|
258
|
+
* @param obj The collection to get the length of.
|
|
41
259
|
* @returns The length of the collection.
|
|
42
260
|
*/
|
|
43
|
-
export const len = (
|
|
44
|
-
if (
|
|
45
|
-
return
|
|
261
|
+
export const len = (obj) => {
|
|
262
|
+
if (obj === null || obj === undefined) {
|
|
263
|
+
return 0;
|
|
46
264
|
}
|
|
47
|
-
|
|
48
|
-
return
|
|
265
|
+
if (typeof obj === 'string') {
|
|
266
|
+
return obj.length;
|
|
267
|
+
}
|
|
268
|
+
if (obj instanceof Map || obj instanceof Set) {
|
|
269
|
+
return obj.size;
|
|
270
|
+
}
|
|
271
|
+
if (isComplexSlice(obj)) {
|
|
272
|
+
return obj.__meta__.length;
|
|
273
|
+
}
|
|
274
|
+
if (Array.isArray(obj)) {
|
|
275
|
+
return obj.length;
|
|
49
276
|
}
|
|
50
277
|
return 0; // Default fallback
|
|
51
278
|
};
|
|
52
279
|
/**
|
|
53
|
-
* Returns the capacity of a slice
|
|
54
|
-
* @param
|
|
280
|
+
* Returns the capacity of a slice.
|
|
281
|
+
* @param obj The slice.
|
|
55
282
|
* @returns The capacity of the slice.
|
|
56
283
|
*/
|
|
57
|
-
export const cap = (
|
|
58
|
-
|
|
284
|
+
export const cap = (obj) => {
|
|
285
|
+
if (obj === null || obj === undefined) {
|
|
286
|
+
return 0;
|
|
287
|
+
}
|
|
288
|
+
if (isComplexSlice(obj)) {
|
|
289
|
+
return obj.__meta__.capacity;
|
|
290
|
+
}
|
|
291
|
+
if (Array.isArray(obj)) {
|
|
292
|
+
return obj.length;
|
|
293
|
+
}
|
|
294
|
+
return 0;
|
|
295
|
+
};
|
|
296
|
+
/**
|
|
297
|
+
* Appends elements to a slice.
|
|
298
|
+
* Note: In Go, append can return a new slice if the underlying array is reallocated.
|
|
299
|
+
* This helper emulates that by returning the modified or new slice.
|
|
300
|
+
* @param slice The slice to append to.
|
|
301
|
+
* @param elements The elements to append.
|
|
302
|
+
* @returns The modified or new slice.
|
|
303
|
+
*/
|
|
304
|
+
export const append = (slice, ...elements) => {
|
|
305
|
+
if (slice === null || slice === undefined) {
|
|
306
|
+
if (elements.length === 0) {
|
|
307
|
+
return [];
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
return elements.slice(0);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
if (elements.length === 0) {
|
|
314
|
+
return slice;
|
|
315
|
+
}
|
|
316
|
+
const oldLen = len(slice);
|
|
317
|
+
const oldCap = cap(slice);
|
|
318
|
+
const newLen = oldLen + elements.length;
|
|
319
|
+
if (newLen <= oldCap) {
|
|
320
|
+
if (isComplexSlice(slice)) {
|
|
321
|
+
const offset = slice.__meta__.offset;
|
|
322
|
+
const backing = slice.__meta__.backing;
|
|
323
|
+
for (let i = 0; i < elements.length; i++) {
|
|
324
|
+
backing[offset + oldLen + i] = elements[i];
|
|
325
|
+
}
|
|
326
|
+
const result = new Array(newLen);
|
|
327
|
+
for (let i = 0; i < oldLen; i++) {
|
|
328
|
+
result[i] = backing[offset + i];
|
|
329
|
+
}
|
|
330
|
+
for (let i = 0; i < elements.length; i++) {
|
|
331
|
+
result[oldLen + i] = elements[i];
|
|
332
|
+
}
|
|
333
|
+
result.__meta__ = {
|
|
334
|
+
backing: backing,
|
|
335
|
+
offset: offset,
|
|
336
|
+
length: newLen,
|
|
337
|
+
capacity: oldCap,
|
|
338
|
+
};
|
|
339
|
+
return result;
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
const result = new Array(newLen);
|
|
343
|
+
for (let i = 0; i < oldLen; i++) {
|
|
344
|
+
result[i] = slice[i];
|
|
345
|
+
}
|
|
346
|
+
for (let i = 0; i < elements.length; i++) {
|
|
347
|
+
result[i + oldLen] = elements[i];
|
|
348
|
+
if (i + oldLen < oldCap && Array.isArray(slice)) {
|
|
349
|
+
slice[i + oldLen] = elements[i];
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
result.__meta__ = {
|
|
353
|
+
backing: slice,
|
|
354
|
+
offset: 0,
|
|
355
|
+
length: newLen,
|
|
356
|
+
capacity: oldCap,
|
|
357
|
+
};
|
|
358
|
+
return result;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
let newCap = oldCap;
|
|
363
|
+
if (newCap == 0) {
|
|
364
|
+
newCap = elements.length;
|
|
365
|
+
}
|
|
366
|
+
else {
|
|
367
|
+
if (newCap < 1024) {
|
|
368
|
+
newCap *= 2;
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
newCap += newCap / 4;
|
|
372
|
+
}
|
|
373
|
+
// Ensure the new capacity fits all the elements
|
|
374
|
+
if (newCap < newLen) {
|
|
375
|
+
newCap = newLen;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
const newBacking = new Array(newCap);
|
|
379
|
+
if (isComplexSlice(slice)) {
|
|
380
|
+
const offset = slice.__meta__.offset;
|
|
381
|
+
const backing = slice.__meta__.backing;
|
|
382
|
+
for (let i = 0; i < oldLen; i++) {
|
|
383
|
+
newBacking[i] = backing[offset + i];
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
for (let i = 0; i < oldLen; i++) {
|
|
388
|
+
newBacking[i] = slice[i];
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
for (let i = 0; i < elements.length; i++) {
|
|
392
|
+
newBacking[oldLen + i] = elements[i];
|
|
393
|
+
}
|
|
394
|
+
if (newLen === newCap) {
|
|
395
|
+
return newBacking.slice(0, newLen);
|
|
396
|
+
}
|
|
397
|
+
const result = new Array(newLen);
|
|
398
|
+
for (let i = 0; i < newLen; i++) {
|
|
399
|
+
result[i] = newBacking[i];
|
|
400
|
+
}
|
|
401
|
+
result.__meta__ = {
|
|
402
|
+
backing: newBacking,
|
|
403
|
+
offset: 0,
|
|
404
|
+
length: newLen,
|
|
405
|
+
capacity: newCap,
|
|
406
|
+
};
|
|
407
|
+
return result;
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
/**
|
|
411
|
+
* Copies elements from src to dst.
|
|
412
|
+
* @param dst The destination slice.
|
|
413
|
+
* @param src The source slice.
|
|
414
|
+
* @returns The number of elements copied.
|
|
415
|
+
*/
|
|
416
|
+
export const copy = (dst, src) => {
|
|
417
|
+
if (dst === null || src === null) {
|
|
418
|
+
return 0;
|
|
419
|
+
}
|
|
420
|
+
const dstLen = len(dst);
|
|
421
|
+
const srcLen = len(src);
|
|
422
|
+
const count = Math.min(dstLen, srcLen);
|
|
423
|
+
if (count === 0) {
|
|
424
|
+
return 0;
|
|
425
|
+
}
|
|
426
|
+
if (isComplexSlice(dst)) {
|
|
427
|
+
const dstOffset = dst.__meta__.offset;
|
|
428
|
+
const dstBacking = dst.__meta__.backing;
|
|
429
|
+
if (isComplexSlice(src)) {
|
|
430
|
+
const srcOffset = src.__meta__.offset;
|
|
431
|
+
const srcBacking = src.__meta__.backing;
|
|
432
|
+
for (let i = 0; i < count; i++) {
|
|
433
|
+
dstBacking[dstOffset + i] = srcBacking[srcOffset + i];
|
|
434
|
+
dst[i] = srcBacking[srcOffset + i]; // Update the proxy array
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
for (let i = 0; i < count; i++) {
|
|
439
|
+
dstBacking[dstOffset + i] = src[i];
|
|
440
|
+
dst[i] = src[i]; // Update the proxy array
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
if (isComplexSlice(src)) {
|
|
446
|
+
const srcOffset = src.__meta__.offset;
|
|
447
|
+
const srcBacking = src.__meta__.backing;
|
|
448
|
+
for (let i = 0; i < count; i++) {
|
|
449
|
+
dst[i] = srcBacking[srcOffset + i];
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
for (let i = 0; i < count; i++) {
|
|
454
|
+
dst[i] = src[i];
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return count;
|
|
59
459
|
};
|
|
60
460
|
/**
|
|
61
461
|
* Converts a string to an array of Unicode code points (runes).
|
|
@@ -71,8 +471,30 @@ export const stringToRunes = (str) => {
|
|
|
71
471
|
* @returns The resulting string.
|
|
72
472
|
*/
|
|
73
473
|
export const runesToString = (runes) => {
|
|
74
|
-
return String.fromCharCode(...runes);
|
|
474
|
+
return runes?.length ? String.fromCharCode(...runes) : '';
|
|
75
475
|
};
|
|
476
|
+
/**
|
|
477
|
+
* Converts a number to a byte (uint8) by truncating to the range 0-255.
|
|
478
|
+
* Equivalent to Go's byte() conversion.
|
|
479
|
+
* @param n The number to convert to a byte.
|
|
480
|
+
* @returns The byte value (0-255).
|
|
481
|
+
*/
|
|
482
|
+
export const byte = (n) => {
|
|
483
|
+
return n & 0xff; // Bitwise AND with 255 ensures we get a value in the range 0-255
|
|
484
|
+
};
|
|
485
|
+
/** Wrap a non-null T in a pointer‐box. */
|
|
486
|
+
export function box(v) {
|
|
487
|
+
// We create a new object wrapper for every box call to ensure
|
|
488
|
+
// distinct pointer identity, crucial for pointer comparisons (p1 == p2).
|
|
489
|
+
return { value: v };
|
|
490
|
+
}
|
|
491
|
+
/** Dereference a pointer‐box, throws on null → simulates Go panic. */
|
|
492
|
+
export function unbox(b) {
|
|
493
|
+
if (b === null) {
|
|
494
|
+
throw new Error('runtime error: invalid memory address or nil pointer dereference');
|
|
495
|
+
}
|
|
496
|
+
return b.value;
|
|
497
|
+
}
|
|
76
498
|
/**
|
|
77
499
|
* Gets a value from a map, with a default value if the key doesn't exist.
|
|
78
500
|
* @param map The map to get from.
|
|
@@ -109,147 +531,417 @@ export const deleteMapEntry = (map, key) => {
|
|
|
109
531
|
export const mapHas = (map, key) => {
|
|
110
532
|
return map.has(key);
|
|
111
533
|
};
|
|
112
|
-
/**
|
|
113
|
-
* Appends elements to a slice (TypeScript array).
|
|
114
|
-
* Note: In Go, append can return a new slice if the underlying array is reallocated.
|
|
115
|
-
* This helper emulates that by returning the modified array.
|
|
116
|
-
* @param slice The slice (TypeScript array) to append to.
|
|
117
|
-
* @param elements The elements to append.
|
|
118
|
-
* @returns The modified slice (TypeScript array).
|
|
119
|
-
*/
|
|
120
|
-
export const append = (slice, ...elements) => {
|
|
121
|
-
slice.push(...elements);
|
|
122
|
-
if (slice.__capacity !== undefined && slice.length > slice.__capacity) {
|
|
123
|
-
slice.__capacity = slice.length;
|
|
124
|
-
}
|
|
125
|
-
return slice;
|
|
126
|
-
};
|
|
127
534
|
/**
|
|
128
535
|
* Represents the kinds of Go types that can be registered at runtime.
|
|
129
536
|
*/
|
|
130
537
|
export var TypeKind;
|
|
131
538
|
(function (TypeKind) {
|
|
132
|
-
TypeKind["Struct"] = "struct";
|
|
133
|
-
TypeKind["Interface"] = "interface";
|
|
134
539
|
TypeKind["Basic"] = "basic";
|
|
135
|
-
TypeKind["
|
|
136
|
-
TypeKind["
|
|
540
|
+
TypeKind["Interface"] = "interface";
|
|
541
|
+
TypeKind["Struct"] = "struct";
|
|
137
542
|
TypeKind["Map"] = "map";
|
|
138
|
-
TypeKind["
|
|
543
|
+
TypeKind["Slice"] = "slice";
|
|
544
|
+
TypeKind["Array"] = "array";
|
|
545
|
+
TypeKind["Pointer"] = "pointer";
|
|
139
546
|
TypeKind["Function"] = "function";
|
|
547
|
+
TypeKind["Channel"] = "channel";
|
|
140
548
|
})(TypeKind || (TypeKind = {}));
|
|
549
|
+
// Type guard functions for TypeInfo variants
|
|
550
|
+
export function isStructTypeInfo(info) {
|
|
551
|
+
return info.kind === TypeKind.Struct;
|
|
552
|
+
}
|
|
553
|
+
export function isInterfaceTypeInfo(info) {
|
|
554
|
+
return info.kind === TypeKind.Interface;
|
|
555
|
+
}
|
|
556
|
+
export function isBasicTypeInfo(info) {
|
|
557
|
+
return info.kind === TypeKind.Basic;
|
|
558
|
+
}
|
|
559
|
+
export function isMapTypeInfo(info) {
|
|
560
|
+
return info.kind === TypeKind.Map;
|
|
561
|
+
}
|
|
562
|
+
export function isSliceTypeInfo(info) {
|
|
563
|
+
return info.kind === TypeKind.Slice;
|
|
564
|
+
}
|
|
565
|
+
export function isArrayTypeInfo(info) {
|
|
566
|
+
return info.kind === TypeKind.Array;
|
|
567
|
+
}
|
|
568
|
+
export function isPointerTypeInfo(info) {
|
|
569
|
+
return info.kind === TypeKind.Pointer;
|
|
570
|
+
}
|
|
571
|
+
export function isFunctionTypeInfo(info) {
|
|
572
|
+
return info.kind === TypeKind.Function;
|
|
573
|
+
}
|
|
574
|
+
export function isChannelTypeInfo(info) {
|
|
575
|
+
return info.kind === TypeKind.Channel;
|
|
576
|
+
}
|
|
141
577
|
// Registry to store runtime type information
|
|
142
578
|
const typeRegistry = new Map();
|
|
143
579
|
/**
|
|
144
|
-
* Registers a type with the runtime type system.
|
|
580
|
+
* Registers a struct type with the runtime type system.
|
|
145
581
|
*
|
|
146
582
|
* @param name The name of the type.
|
|
147
|
-
* @param kind The kind of the type.
|
|
148
583
|
* @param zeroValue The zero value for the type.
|
|
149
|
-
* @param methods
|
|
150
|
-
* @param
|
|
151
|
-
* @returns The type information object
|
|
584
|
+
* @param methods Set of method names for the struct.
|
|
585
|
+
* @param ctor Constructor for the struct.
|
|
586
|
+
* @returns The struct type information object.
|
|
152
587
|
*/
|
|
153
|
-
export const
|
|
588
|
+
export const registerStructType = (name, zeroValue, methods, ctor) => {
|
|
154
589
|
const typeInfo = {
|
|
155
590
|
name,
|
|
156
|
-
kind,
|
|
591
|
+
kind: TypeKind.Struct,
|
|
157
592
|
zeroValue,
|
|
158
593
|
methods,
|
|
159
|
-
|
|
594
|
+
ctor: ctor,
|
|
160
595
|
};
|
|
161
596
|
typeRegistry.set(name, typeInfo);
|
|
162
597
|
return typeInfo;
|
|
163
598
|
};
|
|
164
599
|
/**
|
|
165
|
-
*
|
|
600
|
+
* Registers an interface type with the runtime type system.
|
|
166
601
|
*
|
|
167
|
-
* @param
|
|
168
|
-
* @param
|
|
169
|
-
* @
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const typeInfo =
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
602
|
+
* @param name The name of the type.
|
|
603
|
+
* @param zeroValue The zero value for the type (usually null).
|
|
604
|
+
* @param methods Set of method names the interface requires.
|
|
605
|
+
* @returns The interface type information object.
|
|
606
|
+
*/
|
|
607
|
+
export const registerInterfaceType = (name, zeroValue, methods) => {
|
|
608
|
+
const typeInfo = {
|
|
609
|
+
name,
|
|
610
|
+
kind: TypeKind.Interface,
|
|
611
|
+
zeroValue,
|
|
612
|
+
methods,
|
|
613
|
+
};
|
|
614
|
+
typeRegistry.set(name, typeInfo);
|
|
615
|
+
return typeInfo;
|
|
616
|
+
};
|
|
617
|
+
/**
|
|
618
|
+
* Normalizes a type info to a structured TypeInfo object.
|
|
619
|
+
*
|
|
620
|
+
* @param info The type info or name.
|
|
621
|
+
* @returns A normalized TypeInfo object.
|
|
622
|
+
*/
|
|
623
|
+
function normalizeTypeInfo(info) {
|
|
624
|
+
if (typeof info === 'string') {
|
|
625
|
+
const typeInfo = typeRegistry.get(info);
|
|
626
|
+
if (typeInfo) {
|
|
627
|
+
return typeInfo;
|
|
628
|
+
}
|
|
629
|
+
return {
|
|
630
|
+
kind: TypeKind.Basic,
|
|
631
|
+
name: info,
|
|
632
|
+
};
|
|
181
633
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
634
|
+
return info;
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Validates that a map key matches the expected type info.
|
|
638
|
+
*
|
|
639
|
+
* @param key The key to validate
|
|
640
|
+
* @param keyTypeInfo The normalized type info for the key
|
|
641
|
+
* @returns True if the key matches the type info, false otherwise
|
|
642
|
+
*/
|
|
643
|
+
function validateMapKey(key, keyTypeInfo) {
|
|
644
|
+
if (keyTypeInfo.kind === TypeKind.Basic) {
|
|
645
|
+
// For string keys
|
|
646
|
+
if (keyTypeInfo.name === 'string') {
|
|
647
|
+
return typeof key === 'string';
|
|
648
|
+
}
|
|
649
|
+
else if (keyTypeInfo.name === 'int' ||
|
|
650
|
+
keyTypeInfo.name === 'float64' ||
|
|
651
|
+
keyTypeInfo.name === 'number') {
|
|
652
|
+
if (typeof key === 'string') {
|
|
653
|
+
return /^-?\d+(\.\d+)?$/.test(key);
|
|
188
654
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
655
|
+
else {
|
|
656
|
+
return typeof key === 'number';
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
return false;
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Checks if a value matches a basic type info.
|
|
664
|
+
*
|
|
665
|
+
* @param value The value to check.
|
|
666
|
+
* @param info The basic type info to match against.
|
|
667
|
+
* @returns True if the value matches the basic type, false otherwise.
|
|
668
|
+
*/
|
|
669
|
+
function matchesBasicType(value, info) {
|
|
670
|
+
if (info.name === 'string')
|
|
671
|
+
return typeof value === 'string';
|
|
672
|
+
if (info.name === 'number' || info.name === 'int' || info.name === 'float64')
|
|
673
|
+
return typeof value === 'number';
|
|
674
|
+
if (info.name === 'boolean' || info.name === 'bool')
|
|
675
|
+
return typeof value === 'boolean';
|
|
676
|
+
return false;
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* Checks if a value matches a struct type info.
|
|
680
|
+
*
|
|
681
|
+
* @param value The value to check.
|
|
682
|
+
* @param info The struct type info to match against.
|
|
683
|
+
* @returns True if the value matches the struct type, false otherwise.
|
|
684
|
+
*/
|
|
685
|
+
function matchesStructType(value, info) {
|
|
686
|
+
if (!isStructTypeInfo(info))
|
|
687
|
+
return false;
|
|
688
|
+
// For structs, use instanceof with the constructor
|
|
689
|
+
if (info.ctor && value instanceof info.ctor) {
|
|
690
|
+
return true;
|
|
691
|
+
}
|
|
692
|
+
if (info.fields && typeof value === 'object') {
|
|
693
|
+
// For struct type assertions, we need to check that the value has exactly
|
|
694
|
+
const descFields = Array.from(info.fields);
|
|
695
|
+
const valueFields = Object.keys(value);
|
|
696
|
+
const condition1 = descFields.every((field) => field in value);
|
|
697
|
+
const condition2 = valueFields.length === descFields.length;
|
|
698
|
+
const condition3 = valueFields.every((field) => descFields.includes(field));
|
|
699
|
+
console.log('Struct field matching debug:', {
|
|
700
|
+
descFields,
|
|
701
|
+
valueFields,
|
|
702
|
+
allDescFieldsInValue: condition1,
|
|
703
|
+
sameFieldCount: condition2,
|
|
704
|
+
allValueFieldsInDesc: condition3,
|
|
705
|
+
});
|
|
706
|
+
return condition1 && condition2 && condition3;
|
|
707
|
+
}
|
|
708
|
+
return false;
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Checks if a value matches an interface type info.
|
|
712
|
+
*
|
|
713
|
+
* @param value The value to check.
|
|
714
|
+
* @param info The interface type info to match against.
|
|
715
|
+
* @returns True if the value matches the interface type, false otherwise.
|
|
716
|
+
*/
|
|
717
|
+
function matchesInterfaceType(value, info) {
|
|
718
|
+
// For interfaces, check if the value has all the required methods
|
|
719
|
+
if (isInterfaceTypeInfo(info) &&
|
|
720
|
+
info.methods &&
|
|
721
|
+
typeof value === 'object' &&
|
|
722
|
+
value !== null) {
|
|
723
|
+
return Array.from(info.methods).every((method) => typeof value[method] === 'function');
|
|
724
|
+
}
|
|
725
|
+
return false;
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* Checks if a value matches a map type info.
|
|
729
|
+
*
|
|
730
|
+
* @param value The value to check.
|
|
731
|
+
* @param info The map type info to match against.
|
|
732
|
+
* @returns True if the value matches the map type, false otherwise.
|
|
733
|
+
*/
|
|
734
|
+
function matchesMapType(value, info) {
|
|
735
|
+
if (typeof value !== 'object' || value === null)
|
|
736
|
+
return false;
|
|
737
|
+
if (!isMapTypeInfo(info))
|
|
738
|
+
return false;
|
|
739
|
+
if (info.keyType || info.elemType) {
|
|
740
|
+
let entries = [];
|
|
741
|
+
if (value instanceof Map) {
|
|
742
|
+
entries = Array.from(value.entries());
|
|
743
|
+
}
|
|
744
|
+
else {
|
|
745
|
+
entries = Object.entries(value);
|
|
746
|
+
}
|
|
747
|
+
if (entries.length === 0)
|
|
748
|
+
return true; // Empty map matches any map type
|
|
749
|
+
const sampleSize = Math.min(5, entries.length);
|
|
750
|
+
for (let i = 0; i < sampleSize; i++) {
|
|
751
|
+
const [k, v] = entries[i];
|
|
752
|
+
if (info.keyType) {
|
|
753
|
+
if (!validateMapKey(k, normalizeTypeInfo(info.keyType))) {
|
|
754
|
+
return false;
|
|
196
755
|
}
|
|
197
756
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
// This is a simple check for common basic types
|
|
202
|
-
const basicType = typeof value;
|
|
203
|
-
if (basicType === 'string' ||
|
|
204
|
-
basicType === 'number' ||
|
|
205
|
-
basicType === 'boolean') {
|
|
206
|
-
return { value: value, ok: true };
|
|
757
|
+
if (info.elemType &&
|
|
758
|
+
!matchesType(v, normalizeTypeInfo(info.elemType))) {
|
|
759
|
+
return false;
|
|
207
760
|
}
|
|
208
|
-
break;
|
|
209
761
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
762
|
+
}
|
|
763
|
+
return true;
|
|
764
|
+
}
|
|
765
|
+
/**
|
|
766
|
+
* Checks if a value matches an array or slice type info.
|
|
767
|
+
*
|
|
768
|
+
* @param value The value to check.
|
|
769
|
+
* @param info The array or slice type info to match against.
|
|
770
|
+
* @returns True if the value matches the array or slice type, false otherwise.
|
|
771
|
+
*/
|
|
772
|
+
function matchesArrayOrSliceType(value, info) {
|
|
773
|
+
// For slices and arrays, check if the value is an array and sample element types
|
|
774
|
+
if (!Array.isArray(value))
|
|
775
|
+
return false;
|
|
776
|
+
if (!isArrayTypeInfo(info) && !isSliceTypeInfo(info))
|
|
777
|
+
return false;
|
|
778
|
+
if (info.elemType) {
|
|
779
|
+
const arr = value;
|
|
780
|
+
if (arr.length === 0)
|
|
781
|
+
return true; // Empty array matches any array type
|
|
782
|
+
const sampleSize = Math.min(5, arr.length);
|
|
783
|
+
for (let i = 0; i < sampleSize; i++) {
|
|
784
|
+
if (!matchesType(arr[i], normalizeTypeInfo(info.elemType))) {
|
|
785
|
+
return false;
|
|
221
786
|
}
|
|
222
|
-
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
return true;
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* Checks if a value matches a pointer type info.
|
|
793
|
+
*
|
|
794
|
+
* @param value The value to check.
|
|
795
|
+
* @param info The pointer type info to match against.
|
|
796
|
+
* @returns True if the value matches the pointer type, false otherwise.
|
|
797
|
+
*/
|
|
798
|
+
function matchesPointerType(value, info) {
|
|
799
|
+
// For pointers, check if value is a Box (has a 'value' property)
|
|
800
|
+
if (value === null || value === undefined) {
|
|
801
|
+
return false;
|
|
802
|
+
}
|
|
803
|
+
// Check if the value is a Box (has a 'value' property)
|
|
804
|
+
if (typeof value !== 'object' || !('value' in value)) {
|
|
805
|
+
return false;
|
|
806
|
+
}
|
|
807
|
+
if (!isPointerTypeInfo(info))
|
|
808
|
+
return false;
|
|
809
|
+
if (info.elemType) {
|
|
810
|
+
const elemTypeInfo = normalizeTypeInfo(info.elemType);
|
|
811
|
+
return matchesType(value.value, elemTypeInfo);
|
|
812
|
+
}
|
|
813
|
+
return true;
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* Checks if a value matches a function type info.
|
|
817
|
+
*
|
|
818
|
+
* @param value The value to check.
|
|
819
|
+
* @param info The function type info to match against.
|
|
820
|
+
* @returns True if the value matches the function type, false otherwise.
|
|
821
|
+
*/
|
|
822
|
+
function matchesFunctionType(value, info) {
|
|
823
|
+
// For functions, check if the value is a function
|
|
824
|
+
return typeof value === 'function';
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* Checks if a value matches a channel type info.
|
|
828
|
+
*
|
|
829
|
+
* @param value The value to check.
|
|
830
|
+
* @param info The channel type info to match against.
|
|
831
|
+
* @returns True if the value matches the channel type, false otherwise.
|
|
832
|
+
*/
|
|
833
|
+
function matchesChannelType(value, info) {
|
|
834
|
+
return (typeof value === 'object' &&
|
|
835
|
+
value !== null &&
|
|
836
|
+
'send' in value &&
|
|
837
|
+
'receive' in value &&
|
|
838
|
+
'close' in value &&
|
|
839
|
+
typeof value.send === 'function' &&
|
|
840
|
+
typeof value.receive === 'function' &&
|
|
841
|
+
typeof value.close === 'function');
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* Checks if a value matches a type info.
|
|
845
|
+
*
|
|
846
|
+
* @param value The value to check.
|
|
847
|
+
* @param info The type info to match against.
|
|
848
|
+
* @returns True if the value matches the type info, false otherwise.
|
|
849
|
+
*/
|
|
850
|
+
function matchesType(value, info) {
|
|
851
|
+
if (value === null || value === undefined) {
|
|
852
|
+
return false;
|
|
853
|
+
}
|
|
854
|
+
switch (info.kind) {
|
|
855
|
+
case TypeKind.Basic:
|
|
856
|
+
return matchesBasicType(value, info);
|
|
857
|
+
case TypeKind.Struct:
|
|
858
|
+
return matchesStructType(value, info);
|
|
859
|
+
case TypeKind.Interface:
|
|
860
|
+
return matchesInterfaceType(value, info);
|
|
223
861
|
case TypeKind.Map:
|
|
224
|
-
|
|
862
|
+
return matchesMapType(value, info);
|
|
863
|
+
case TypeKind.Slice:
|
|
864
|
+
case TypeKind.Array:
|
|
865
|
+
return matchesArrayOrSliceType(value, info);
|
|
866
|
+
case TypeKind.Pointer:
|
|
867
|
+
return matchesPointerType(value, info);
|
|
868
|
+
case TypeKind.Function:
|
|
869
|
+
return matchesFunctionType(value, info);
|
|
870
|
+
case TypeKind.Channel:
|
|
871
|
+
return matchesChannelType(value, info);
|
|
872
|
+
default:
|
|
873
|
+
console.warn(`Type matching for kind '${info.kind}' not implemented.`);
|
|
874
|
+
return false;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
export function typeAssert(value, typeInfo) {
|
|
878
|
+
const normalizedType = normalizeTypeInfo(typeInfo);
|
|
879
|
+
if (isStructTypeInfo(normalizedType) &&
|
|
880
|
+
normalizedType.fields &&
|
|
881
|
+
typeof value === 'object' &&
|
|
882
|
+
value !== null) {
|
|
883
|
+
const descFields = Array.from(normalizedType.fields);
|
|
884
|
+
const valueFields = Object.keys(value);
|
|
885
|
+
// For struct type assertions, we need exact field matching
|
|
886
|
+
const structMatch = descFields.length === valueFields.length &&
|
|
887
|
+
descFields.every((field) => field in value) &&
|
|
888
|
+
valueFields.every((field) => descFields.includes(field));
|
|
889
|
+
if (structMatch) {
|
|
890
|
+
return { value: value, ok: true };
|
|
891
|
+
}
|
|
892
|
+
else {
|
|
893
|
+
return { value: null, ok: false };
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
if (isMapTypeInfo(normalizedType) &&
|
|
897
|
+
typeof value === 'object' &&
|
|
898
|
+
value !== null) {
|
|
899
|
+
if (normalizedType.keyType || normalizedType.elemType) {
|
|
900
|
+
let entries = [];
|
|
225
901
|
if (value instanceof Map) {
|
|
226
|
-
|
|
902
|
+
entries = Array.from(value.entries());
|
|
227
903
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
// For channels, check if the value has the required Channel interface methods
|
|
231
|
-
if (typeof value === 'object' &&
|
|
232
|
-
value !== null &&
|
|
233
|
-
'send' in value &&
|
|
234
|
-
'receive' in value &&
|
|
235
|
-
'close' in value &&
|
|
236
|
-
typeof value.send === 'function' &&
|
|
237
|
-
typeof value.receive === 'function' &&
|
|
238
|
-
typeof value.close === 'function') {
|
|
239
|
-
return { value: value, ok: true };
|
|
904
|
+
else {
|
|
905
|
+
entries = Object.entries(value);
|
|
240
906
|
}
|
|
241
|
-
|
|
242
|
-
case TypeKind.Function:
|
|
243
|
-
// For functions, check if the value is a function
|
|
244
|
-
if (typeof value === 'function') {
|
|
907
|
+
if (entries.length === 0) {
|
|
245
908
|
return { value: value, ok: true };
|
|
246
909
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
910
|
+
const sampleSize = Math.min(5, entries.length);
|
|
911
|
+
for (let i = 0; i < sampleSize; i++) {
|
|
912
|
+
const [k, v] = entries[i];
|
|
913
|
+
if (normalizedType.keyType) {
|
|
914
|
+
if (!validateMapKey(k, normalizeTypeInfo(normalizedType.keyType))) {
|
|
915
|
+
return { value: null, ok: false };
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
if (normalizedType.elemType) {
|
|
919
|
+
const elemTypeInfo = normalizeTypeInfo(normalizedType.elemType);
|
|
920
|
+
if (!matchesType(v, elemTypeInfo)) {
|
|
921
|
+
return { value: null, ok: false };
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
// If we get here, the map type assertion passes
|
|
926
|
+
return { value: value, ok: true };
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
const matches = matchesType(value, normalizedType);
|
|
930
|
+
if (matches) {
|
|
931
|
+
return { value: value, ok: true };
|
|
250
932
|
}
|
|
251
|
-
//
|
|
252
|
-
|
|
933
|
+
// If we get here, the assertion failed
|
|
934
|
+
// For registered types, use the zero value from the registry
|
|
935
|
+
if (typeof typeInfo === 'string') {
|
|
936
|
+
const registeredType = typeRegistry.get(typeInfo);
|
|
937
|
+
if (registeredType && registeredType.zeroValue !== undefined) {
|
|
938
|
+
return { value: registeredType.zeroValue, ok: false };
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
else if (normalizedType.zeroValue !== undefined) {
|
|
942
|
+
return { value: normalizedType.zeroValue, ok: false };
|
|
943
|
+
}
|
|
944
|
+
return { value: null, ok: false };
|
|
253
945
|
}
|
|
254
946
|
// A simple implementation of buffered channels
|
|
255
947
|
class BufferedChannel {
|
|
@@ -543,12 +1235,14 @@ export const makeChannel = (bufferSize, zeroValue) => {
|
|
|
543
1235
|
* Implements the `Disposable` interface for use with `using` declarations.
|
|
544
1236
|
*/
|
|
545
1237
|
export class DisposableStack {
|
|
546
|
-
|
|
1238
|
+
stack = [];
|
|
547
1239
|
/**
|
|
548
1240
|
* Adds a function to be executed when the stack is disposed.
|
|
549
1241
|
* @param fn The function to defer.
|
|
550
1242
|
*/
|
|
551
|
-
defer(fn) {
|
|
1243
|
+
defer(fn) {
|
|
1244
|
+
this.stack.push(fn);
|
|
1245
|
+
}
|
|
552
1246
|
/**
|
|
553
1247
|
* Disposes of the resources in the stack by executing the deferred functions
|
|
554
1248
|
* in Last-In, First-Out (LIFO) order.
|
|
@@ -557,8 +1251,8 @@ export class DisposableStack {
|
|
|
557
1251
|
*/
|
|
558
1252
|
[Symbol.dispose]() {
|
|
559
1253
|
// Emulate Go: if a deferred throws, stop and rethrow
|
|
560
|
-
while (this
|
|
561
|
-
const fn = this
|
|
1254
|
+
while (this.stack.length) {
|
|
1255
|
+
const fn = this.stack.pop();
|
|
562
1256
|
fn();
|
|
563
1257
|
}
|
|
564
1258
|
}
|
|
@@ -569,13 +1263,13 @@ export class DisposableStack {
|
|
|
569
1263
|
* Implements the `AsyncDisposable` interface for use with `await using` declarations.
|
|
570
1264
|
*/
|
|
571
1265
|
export class AsyncDisposableStack {
|
|
572
|
-
|
|
1266
|
+
stack = [];
|
|
573
1267
|
/**
|
|
574
1268
|
* Adds a synchronous or asynchronous function to be executed when the stack is disposed.
|
|
575
1269
|
* @param fn The function to defer. Can return void or a Promise<void>.
|
|
576
1270
|
*/
|
|
577
1271
|
defer(fn) {
|
|
578
|
-
this
|
|
1272
|
+
this.stack.push(fn);
|
|
579
1273
|
}
|
|
580
1274
|
/**
|
|
581
1275
|
* Asynchronously disposes of the resources in the stack by executing the deferred functions
|
|
@@ -583,9 +1277,16 @@ export class AsyncDisposableStack {
|
|
|
583
1277
|
*/
|
|
584
1278
|
async [Symbol.asyncDispose]() {
|
|
585
1279
|
// Execute in LIFO order, awaiting each potentially async function
|
|
586
|
-
for (let i = this
|
|
587
|
-
await this
|
|
1280
|
+
for (let i = this.stack.length - 1; i >= 0; --i) {
|
|
1281
|
+
await this.stack[i]();
|
|
588
1282
|
}
|
|
589
1283
|
}
|
|
590
1284
|
}
|
|
1285
|
+
/**
|
|
1286
|
+
* Implementation of Go's built-in println function
|
|
1287
|
+
* @param args Arguments to print
|
|
1288
|
+
*/
|
|
1289
|
+
export function println(...args) {
|
|
1290
|
+
console.log(...args);
|
|
1291
|
+
}
|
|
591
1292
|
//# sourceMappingURL=builtin.js.map
|