goscript 0.0.13 → 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/LICENSE +2 -1
- package/README.md +163 -45
- package/builtin/builtin.ts +1169 -178
- package/cmd/goscript/cmd_compile.go +2 -2
- 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/index.ts +1 -1
- 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 +846 -144
- package/dist/builtin/builtin.js.map +1 -1
- package/dist/compiler/index.d.ts +1 -1
- package/go.mod +5 -6
- package/go.sum +6 -11
- package/package.json +21 -5
- 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,146 +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
|
-
// For interfaces, check if the value has all the required methods
|
|
192
|
-
if (typeInfo.methods && typeof value === 'object') {
|
|
193
|
-
const allMethodsPresent = Array.from(typeInfo.methods).every((method) => typeof value[method] === 'function');
|
|
194
|
-
if (allMethodsPresent) {
|
|
195
|
-
return { value: value, ok: true };
|
|
196
|
-
}
|
|
655
|
+
else {
|
|
656
|
+
return typeof key === 'number';
|
|
197
657
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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;
|
|
755
|
+
}
|
|
207
756
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
// In Go, pointers can be nil which we represent as null/undefined in TS
|
|
212
|
-
if (value !== null && value !== undefined) {
|
|
213
|
-
return { value: value, ok: true };
|
|
757
|
+
if (info.elemType &&
|
|
758
|
+
!matchesType(v, normalizeTypeInfo(info.elemType))) {
|
|
759
|
+
return false;
|
|
214
760
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
761
|
+
}
|
|
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;
|
|
220
786
|
}
|
|
221
|
-
|
|
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);
|
|
222
861
|
case TypeKind.Map:
|
|
223
|
-
|
|
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 = [];
|
|
224
901
|
if (value instanceof Map) {
|
|
225
|
-
|
|
902
|
+
entries = Array.from(value.entries());
|
|
226
903
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
// For channels, check if the value has the required Channel interface methods
|
|
230
|
-
if (typeof value === 'object' &&
|
|
231
|
-
value !== null &&
|
|
232
|
-
'send' in value &&
|
|
233
|
-
'receive' in value &&
|
|
234
|
-
'close' in value &&
|
|
235
|
-
typeof value.send === 'function' &&
|
|
236
|
-
typeof value.receive === 'function' &&
|
|
237
|
-
typeof value.close === 'function') {
|
|
238
|
-
return { value: value, ok: true };
|
|
904
|
+
else {
|
|
905
|
+
entries = Object.entries(value);
|
|
239
906
|
}
|
|
240
|
-
|
|
241
|
-
case TypeKind.Function:
|
|
242
|
-
// For functions, check if the value is a function
|
|
243
|
-
if (typeof value === 'function') {
|
|
907
|
+
if (entries.length === 0) {
|
|
244
908
|
return { value: value, ok: true };
|
|
245
909
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
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 };
|
|
249
932
|
}
|
|
250
|
-
//
|
|
251
|
-
|
|
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 };
|
|
252
945
|
}
|
|
253
946
|
// A simple implementation of buffered channels
|
|
254
947
|
class BufferedChannel {
|
|
@@ -542,12 +1235,14 @@ export const makeChannel = (bufferSize, zeroValue) => {
|
|
|
542
1235
|
* Implements the `Disposable` interface for use with `using` declarations.
|
|
543
1236
|
*/
|
|
544
1237
|
export class DisposableStack {
|
|
545
|
-
|
|
1238
|
+
stack = [];
|
|
546
1239
|
/**
|
|
547
1240
|
* Adds a function to be executed when the stack is disposed.
|
|
548
1241
|
* @param fn The function to defer.
|
|
549
1242
|
*/
|
|
550
|
-
defer(fn) {
|
|
1243
|
+
defer(fn) {
|
|
1244
|
+
this.stack.push(fn);
|
|
1245
|
+
}
|
|
551
1246
|
/**
|
|
552
1247
|
* Disposes of the resources in the stack by executing the deferred functions
|
|
553
1248
|
* in Last-In, First-Out (LIFO) order.
|
|
@@ -556,8 +1251,8 @@ export class DisposableStack {
|
|
|
556
1251
|
*/
|
|
557
1252
|
[Symbol.dispose]() {
|
|
558
1253
|
// Emulate Go: if a deferred throws, stop and rethrow
|
|
559
|
-
while (this
|
|
560
|
-
const fn = this
|
|
1254
|
+
while (this.stack.length) {
|
|
1255
|
+
const fn = this.stack.pop();
|
|
561
1256
|
fn();
|
|
562
1257
|
}
|
|
563
1258
|
}
|
|
@@ -568,13 +1263,13 @@ export class DisposableStack {
|
|
|
568
1263
|
* Implements the `AsyncDisposable` interface for use with `await using` declarations.
|
|
569
1264
|
*/
|
|
570
1265
|
export class AsyncDisposableStack {
|
|
571
|
-
|
|
1266
|
+
stack = [];
|
|
572
1267
|
/**
|
|
573
1268
|
* Adds a synchronous or asynchronous function to be executed when the stack is disposed.
|
|
574
1269
|
* @param fn The function to defer. Can return void or a Promise<void>.
|
|
575
1270
|
*/
|
|
576
1271
|
defer(fn) {
|
|
577
|
-
this
|
|
1272
|
+
this.stack.push(fn);
|
|
578
1273
|
}
|
|
579
1274
|
/**
|
|
580
1275
|
* Asynchronously disposes of the resources in the stack by executing the deferred functions
|
|
@@ -582,9 +1277,16 @@ export class AsyncDisposableStack {
|
|
|
582
1277
|
*/
|
|
583
1278
|
async [Symbol.asyncDispose]() {
|
|
584
1279
|
// Execute in LIFO order, awaiting each potentially async function
|
|
585
|
-
for (let i = this
|
|
586
|
-
await this
|
|
1280
|
+
for (let i = this.stack.length - 1; i >= 0; --i) {
|
|
1281
|
+
await this.stack[i]();
|
|
587
1282
|
}
|
|
588
1283
|
}
|
|
589
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
|
+
}
|
|
590
1292
|
//# sourceMappingURL=builtin.js.map
|