xbintsc 0.3.3 → 0.3.5
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/dist/src/ast/expressions.d.ts +8 -0
- package/dist/src/binder/binder.js +1 -0
- package/dist/src/binder/binder.js.map +1 -1
- package/dist/src/binder/references.d.ts +1 -1
- package/dist/src/binder/references.js +34 -5
- package/dist/src/binder/references.js.map +1 -1
- package/dist/src/binder/types.d.ts +4 -0
- package/dist/src/binder/types.js.map +1 -1
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/calls/access.d.ts +9 -1
- package/dist/src/codegen/generator/calls/access.js +146 -13
- package/dist/src/codegen/generator/calls/access.js.map +1 -1
- package/dist/src/codegen/generator/calls/closures.d.ts +1 -0
- package/dist/src/codegen/generator/calls/closures.js +25 -0
- package/dist/src/codegen/generator/calls/closures.js.map +1 -1
- package/dist/src/codegen/generator/calls/invocation.js +12 -1
- package/dist/src/codegen/generator/calls/invocation.js.map +1 -1
- package/dist/src/codegen/generator/calls/literals.js +12 -4
- package/dist/src/codegen/generator/calls/literals.js.map +1 -1
- package/dist/src/codegen/generator/calls/super.js +4 -7
- package/dist/src/codegen/generator/calls/super.js.map +1 -1
- package/dist/src/codegen/generator/context.d.ts +21 -2
- package/dist/src/codegen/generator/context.js +42 -5
- package/dist/src/codegen/generator/context.js.map +1 -1
- package/dist/src/codegen/generator/expressions/assignment.js +1 -3
- package/dist/src/codegen/generator/expressions/assignment.js.map +1 -1
- package/dist/src/codegen/generator/expressions/primary.d.ts +3 -1
- package/dist/src/codegen/generator/expressions/primary.js +99 -1
- package/dist/src/codegen/generator/expressions/primary.js.map +1 -1
- package/dist/src/codegen/generator/generator.js.map +1 -1
- package/dist/src/codegen/generator/module.js +25 -15
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/state.d.ts +15 -0
- package/dist/src/codegen/generator/state.js +28 -1
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/statements/control-flow.d.ts +3 -1
- package/dist/src/codegen/generator/statements/control-flow.js +85 -0
- package/dist/src/codegen/generator/statements/control-flow.js.map +1 -1
- package/dist/src/codegen/generator/statements/dispatch.js +15 -6
- package/dist/src/codegen/generator/statements/dispatch.js.map +1 -1
- package/dist/src/codegen/generator/statements/loops.d.ts +3 -0
- package/dist/src/codegen/generator/statements/loops.js +25 -11
- package/dist/src/codegen/generator/statements/loops.js.map +1 -1
- package/dist/src/codegen/generator/tables.d.ts +7 -0
- package/dist/src/codegen/generator/tables.js +41 -1
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/compiler.d.ts +1 -1
- package/dist/src/driver/compiler.js +33 -1
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/modules.d.ts +4 -3
- package/dist/src/driver/modules.js +61 -4
- package/dist/src/driver/modules.js.map +1 -1
- package/dist/src/driver/toolchain.js +1 -1
- package/dist/src/driver/toolchain.js.map +1 -1
- package/dist/src/lexer/scanner.js.map +1 -1
- package/dist/src/parser/declarations/classes.js +4 -0
- package/dist/src/parser/declarations/classes.js.map +1 -1
- package/dist/src/parser/declarations/type-members.js.map +1 -1
- package/dist/src/parser/expressions.d.ts +2 -1
- package/dist/src/parser/expressions.js +10 -1
- package/dist/src/parser/expressions.js.map +1 -1
- package/dist/src/parser/helpers.js +2 -2
- package/dist/src/parser/helpers.js.map +1 -1
- package/dist/src/parser/literals.js +79 -6
- package/dist/src/parser/literals.js.map +1 -1
- package/dist/src/parser/modules.js.map +1 -1
- package/dist/src/parser/parser.js +0 -1
- package/dist/src/parser/parser.js.map +1 -1
- package/dist/src/parser/statements.d.ts +1 -0
- package/dist/src/parser/statements.js +13 -1
- package/dist/src/parser/statements.js.map +1 -1
- package/dist/src/parser/types.js +2 -2
- package/dist/src/parser/types.js.map +1 -1
- package/dist/tests/ast/factory.test.d.ts +1 -0
- package/dist/tests/ast/factory.test.js +35 -0
- package/dist/tests/ast/factory.test.js.map +1 -0
- package/dist/tests/ast/visitor.test.d.ts +1 -0
- package/dist/tests/ast/visitor.test.js +53 -0
- package/dist/tests/ast/visitor.test.js.map +1 -0
- package/dist/tests/cli/main.test.js +109 -9
- package/dist/tests/cli/main.test.js.map +1 -1
- package/dist/tests/codegen/closures.test.d.ts +1 -0
- package/dist/tests/codegen/closures.test.js +32 -0
- package/dist/tests/codegen/closures.test.js.map +1 -0
- package/dist/tests/codegen/expressions.test.d.ts +1 -0
- package/dist/tests/codegen/expressions.test.js +149 -0
- package/dist/tests/codegen/expressions.test.js.map +1 -0
- package/dist/tests/codegen/llvm.test.js +14 -0
- package/dist/tests/codegen/llvm.test.js.map +1 -1
- package/dist/tests/codegen/values.test.d.ts +1 -0
- package/dist/tests/codegen/values.test.js +48 -0
- package/dist/tests/codegen/values.test.js.map +1 -0
- package/dist/tests/diagnostics/diagnostic.test.d.ts +1 -0
- package/dist/tests/diagnostics/diagnostic.test.js +117 -0
- package/dist/tests/diagnostics/diagnostic.test.js.map +1 -0
- package/dist/tests/diagnostics/source.test.d.ts +1 -0
- package/dist/tests/diagnostics/source.test.js +58 -0
- package/dist/tests/diagnostics/source.test.js.map +1 -0
- package/dist/tests/driver/modules.test.d.ts +1 -0
- package/dist/tests/driver/modules.test.js +140 -0
- package/dist/tests/driver/modules.test.js.map +1 -0
- package/dist/tests/driver/paths.test.js +17 -1
- package/dist/tests/driver/paths.test.js.map +1 -1
- package/dist/tests/driver/runtime-lib.test.d.ts +1 -0
- package/dist/tests/driver/runtime-lib.test.js +19 -0
- package/dist/tests/driver/runtime-lib.test.js.map +1 -0
- package/dist/tests/driver/toolchain-provider.test.js +91 -0
- package/dist/tests/driver/toolchain-provider.test.js.map +1 -1
- package/dist/tests/driver/toolchain.test.js +11 -1
- package/dist/tests/driver/toolchain.test.js.map +1 -1
- package/dist/tests/e2e/compile-node.test.js +14 -1
- package/dist/tests/e2e/compile-node.test.js.map +1 -1
- package/dist/tests/e2e/compile.test.js +465 -2
- package/dist/tests/e2e/compile.test.js.map +1 -1
- package/dist/tests/e2e/differential.test.d.ts +7 -0
- package/dist/tests/e2e/differential.test.js +581 -0
- package/dist/tests/e2e/differential.test.js.map +1 -0
- package/dist/tests/e2e/harness.d.ts +21 -0
- package/dist/tests/e2e/harness.js +26 -0
- package/dist/tests/e2e/harness.js.map +1 -1
- package/dist/tests/extensions/node.test.d.ts +1 -0
- package/dist/tests/extensions/node.test.js +32 -0
- package/dist/tests/extensions/node.test.js.map +1 -0
- package/dist/tests/lexer/identifiers.test.d.ts +1 -0
- package/dist/tests/lexer/identifiers.test.js +13 -0
- package/dist/tests/lexer/identifiers.test.js.map +1 -0
- package/dist/tests/lexer/numbers.test.d.ts +1 -0
- package/dist/tests/lexer/numbers.test.js +23 -0
- package/dist/tests/lexer/numbers.test.js.map +1 -0
- package/dist/tests/lexer/strings.test.d.ts +1 -0
- package/dist/tests/lexer/strings.test.js +72 -0
- package/dist/tests/lexer/strings.test.js.map +1 -0
- package/dist/tests/parser/declarations.test.d.ts +1 -0
- package/dist/tests/parser/declarations.test.js +70 -0
- package/dist/tests/parser/declarations.test.js.map +1 -0
- package/dist/tests/parser/expressions.test.d.ts +1 -0
- package/dist/tests/parser/expressions.test.js +47 -0
- package/dist/tests/parser/expressions.test.js.map +1 -0
- package/dist/tests/parser/helpers.test.d.ts +1 -0
- package/dist/tests/parser/helpers.test.js +58 -0
- package/dist/tests/parser/helpers.test.js.map +1 -0
- package/dist/tests/parser/literals.test.d.ts +1 -0
- package/dist/tests/parser/literals.test.js +70 -0
- package/dist/tests/parser/literals.test.js.map +1 -0
- package/dist/tests/parser/module-syntax.test.d.ts +1 -0
- package/dist/tests/parser/module-syntax.test.js +91 -0
- package/dist/tests/parser/module-syntax.test.js.map +1 -0
- package/dist/tests/parser/statements.test.d.ts +1 -0
- package/dist/tests/parser/statements.test.js +85 -0
- package/dist/tests/parser/statements.test.js.map +1 -0
- package/dist/tests/parser/type-members.test.d.ts +1 -0
- package/dist/tests/parser/type-members.test.js +86 -0
- package/dist/tests/parser/type-members.test.js.map +1 -0
- package/dist/tests/parser/types.test.d.ts +1 -0
- package/dist/tests/parser/types.test.js +143 -0
- package/dist/tests/parser/types.test.js.map +1 -0
- package/package.json +6 -1
- package/runtime/ext_node/fs/fs_ops.c +36 -1
- package/runtime/rt.h +17 -0
- package/runtime/rt_internal.h +88 -2
- package/runtime/xt_builtins.c +174 -6
- package/runtime/xt_containers.c +234 -42
- package/runtime/xt_generator.c +304 -0
- package/runtime/xt_io.c +170 -30
- package/runtime/xt_promise.c +6 -1
- package/runtime/xt_regex.h +105 -35
- package/runtime/xt_stdlib/dispatch.inc +255 -4
- package/runtime/xt_stdlib/strings.inc +17 -13
- package/runtime/xt_stdlib2/arrays.inc +126 -19
- package/runtime/xt_stdlib2/date.inc +9 -2
- package/runtime/xt_stdlib2/error.inc +162 -12
- package/runtime/xt_stdlib2/helpers.inc +4 -0
- package/runtime/xt_stdlib2/json.inc +19 -6
- package/runtime/xt_stdlib2/number-string-statics.inc +1 -1
- package/runtime/xt_stdlib2/numbers.inc +4 -5
- package/runtime/xt_stdlib2/objects.inc +29 -0
- package/runtime/xt_stdlib2/regexp-match.inc +293 -51
- package/runtime/xt_stdlib2/set.inc +58 -2
- package/runtime/xt_stdlib2/strings.inc +38 -0
- package/runtime/xt_symbol.c +149 -0
- package/runtime/xt_values.c +221 -15
- package/scripts/build-runtime.ts +1 -1
- package/src/ast/expressions.ts +8 -0
- package/src/binder/binder.ts +1 -1
- package/src/binder/references.ts +47 -4
- package/src/binder/types.ts +4 -0
- package/src/cli/main.ts +1 -2
- package/src/codegen/generator/calls/access.ts +158 -13
- package/src/codegen/generator/calls/closures.ts +24 -0
- package/src/codegen/generator/calls/invocation.ts +11 -1
- package/src/codegen/generator/calls/literals.ts +10 -4
- package/src/codegen/generator/calls/super.ts +6 -9
- package/src/codegen/generator/context.ts +44 -7
- package/src/codegen/generator/expressions/assignment.ts +1 -3
- package/src/codegen/generator/expressions/primary.ts +108 -2
- package/src/codegen/generator/generator.ts +0 -1
- package/src/codegen/generator/module.ts +24 -18
- package/src/codegen/generator/state.ts +44 -1
- package/src/codegen/generator/statements/control-flow.ts +86 -0
- package/src/codegen/generator/statements/dispatch.ts +18 -6
- package/src/codegen/generator/statements/loops.ts +29 -11
- package/src/codegen/generator/tables.ts +44 -1
- package/src/driver/compiler.ts +32 -2
- package/src/driver/modules.ts +64 -4
- package/src/driver/toolchain.ts +1 -1
- package/src/lexer/scanner.ts +0 -1
- package/src/parser/declarations/classes.ts +4 -0
- package/src/parser/declarations/type-members.ts +0 -2
- package/src/parser/expressions.ts +13 -1
- package/src/parser/helpers.ts +2 -2
- package/src/parser/literals.ts +82 -7
- package/src/parser/modules.ts +0 -1
- package/src/parser/parser.ts +0 -1
- package/src/parser/statements.ts +14 -0
- package/src/parser/types.ts +2 -2
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc runtime — Symbol primitives.
|
|
3
|
+
*
|
|
4
|
+
* Symbols are heap objects (`XT_OBJECT_KIND_SYMBOL`) tagged as `XT_TAG_OBJECT`
|
|
5
|
+
* so they can travel through the generic value plumbing, but they are
|
|
6
|
+
* distinguished by their header kind. Property keys are either strings or
|
|
7
|
+
* symbols; see `xt_to_property_key` in `xt_containers.c`.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#include "rt_internal.h"
|
|
11
|
+
|
|
12
|
+
#include <stdio.h>
|
|
13
|
+
#include <stdlib.h>
|
|
14
|
+
#include <string.h>
|
|
15
|
+
|
|
16
|
+
typedef struct {
|
|
17
|
+
xt_header header;
|
|
18
|
+
/* `XT_UNDEFINED` for `Symbol()` without a description, otherwise a string. */
|
|
19
|
+
xt_value description;
|
|
20
|
+
uint64_t id;
|
|
21
|
+
} xt_symbol_data;
|
|
22
|
+
|
|
23
|
+
static uint64_t g_symbol_counter = 0;
|
|
24
|
+
|
|
25
|
+
int xt_is_symbol(xt_value value) {
|
|
26
|
+
if (!XT_IS_OBJECT(value)) return 0;
|
|
27
|
+
return ((xt_header *)XT_GET_PTR(value))->kind == XT_OBJECT_KIND_SYMBOL;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static xt_symbol_data *xt_as_symbol(xt_value value) {
|
|
31
|
+
if (!xt_is_symbol(value)) return NULL;
|
|
32
|
+
return (xt_symbol_data *)XT_GET_PTR(value);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
xt_value xt_symbol_new(xt_value description) {
|
|
36
|
+
xt_symbol_data *symbol =
|
|
37
|
+
(xt_symbol_data *)xt_alloc(sizeof(xt_symbol_data), XT_OBJECT_KIND_SYMBOL);
|
|
38
|
+
symbol->description = description;
|
|
39
|
+
symbol->id = ++g_symbol_counter;
|
|
40
|
+
return XT_FROM_PTR(XT_TAG_OBJECT, symbol);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* -- well-known symbols --------------------------------------------------- */
|
|
44
|
+
|
|
45
|
+
static const char *const XT_WELL_KNOWN_NAMES[] = {
|
|
46
|
+
"asyncIterator", "hasInstance", "isConcatSpreadable", "iterator",
|
|
47
|
+
"match", "matchAll", "replace", "search",
|
|
48
|
+
"species", "split", "toPrimitive", "toStringTag",
|
|
49
|
+
"unscopables",
|
|
50
|
+
};
|
|
51
|
+
#define XT_WELL_KNOWN_COUNT \
|
|
52
|
+
((int)(sizeof(XT_WELL_KNOWN_NAMES) / sizeof(XT_WELL_KNOWN_NAMES[0])))
|
|
53
|
+
|
|
54
|
+
static xt_value g_well_known[XT_WELL_KNOWN_COUNT];
|
|
55
|
+
static int g_well_known_ready = 0;
|
|
56
|
+
|
|
57
|
+
static void xt_symbol_init_well_known(void) {
|
|
58
|
+
if (g_well_known_ready) return;
|
|
59
|
+
g_well_known_ready = 1;
|
|
60
|
+
for (int i = 0; i < XT_WELL_KNOWN_COUNT; i++) {
|
|
61
|
+
char buffer[64];
|
|
62
|
+
snprintf(buffer, sizeof(buffer), "Symbol.%s", XT_WELL_KNOWN_NAMES[i]);
|
|
63
|
+
g_well_known[i] = xt_symbol_new(xt_string_from_cstr(buffer));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
xt_value xt_symbol_well_known(const char *name) {
|
|
68
|
+
xt_symbol_init_well_known();
|
|
69
|
+
for (int i = 0; i < XT_WELL_KNOWN_COUNT; i++) {
|
|
70
|
+
if (strcmp(name, XT_WELL_KNOWN_NAMES[i]) == 0) return g_well_known[i];
|
|
71
|
+
}
|
|
72
|
+
return XT_UNDEFINED;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
xt_value xt_symbol_get(xt_value name) {
|
|
76
|
+
const char *text = xt_string_data(name);
|
|
77
|
+
if (!text) return XT_UNDEFINED;
|
|
78
|
+
return xt_symbol_well_known(text);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* -- description / toString ---------------------------------------------- */
|
|
82
|
+
|
|
83
|
+
xt_value xt_symbol_description(xt_value value) {
|
|
84
|
+
xt_symbol_data *symbol = xt_as_symbol(value);
|
|
85
|
+
return symbol ? symbol->description : XT_UNDEFINED;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
xt_value xt_symbol_to_string(xt_value value) {
|
|
89
|
+
xt_symbol_data *symbol = xt_as_symbol(value);
|
|
90
|
+
if (!symbol) {
|
|
91
|
+
xt_throw(xt_string_from_cstr(
|
|
92
|
+
"TypeError: Symbol.prototype.toString requires that 'this' be a Symbol"));
|
|
93
|
+
}
|
|
94
|
+
xt_string *description =
|
|
95
|
+
XT_IS_STRING(symbol->description) ? xt_as_string(symbol->description) : NULL;
|
|
96
|
+
size_t length = description ? description->length : 0;
|
|
97
|
+
char *buffer = (char *)malloc(8 + length);
|
|
98
|
+
if (!buffer) abort();
|
|
99
|
+
memcpy(buffer, "Symbol(", 7);
|
|
100
|
+
if (description) memcpy(buffer + 7, description->data, length);
|
|
101
|
+
buffer[7 + length] = ')';
|
|
102
|
+
xt_value result = xt_string_new(buffer, 8 + length);
|
|
103
|
+
free(buffer);
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* -- constructor and statics ---------------------------------------------- */
|
|
108
|
+
|
|
109
|
+
xt_value xt_symbol(int32_t argc, xt_value *argv) {
|
|
110
|
+
xt_value description = xt_arg_at(argc, argv, 0);
|
|
111
|
+
if (description != XT_UNDEFINED) description = xt_to_string(description);
|
|
112
|
+
return xt_symbol_new(description);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* Global symbol registry backing `Symbol.for` / `Symbol.keyFor`. */
|
|
116
|
+
static xt_value g_symbol_registry = XT_UNDEFINED;
|
|
117
|
+
|
|
118
|
+
xt_value xt_symbol_for(xt_value key) {
|
|
119
|
+
xt_value keyString = xt_to_string(key);
|
|
120
|
+
if (g_symbol_registry == XT_UNDEFINED) g_symbol_registry = xt_object_new();
|
|
121
|
+
xt_value existing = xt_object_get(g_symbol_registry, keyString);
|
|
122
|
+
if (existing != XT_UNDEFINED) return existing;
|
|
123
|
+
xt_value symbol = xt_symbol_new(keyString);
|
|
124
|
+
xt_object_set(g_symbol_registry, keyString, symbol);
|
|
125
|
+
return symbol;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
xt_value xt_symbol_key_for(xt_value value) {
|
|
129
|
+
if (!xt_is_symbol(value)) {
|
|
130
|
+
xt_throw(xt_string_from_cstr("TypeError: Symbol.keyFor requires a symbol"));
|
|
131
|
+
}
|
|
132
|
+
if (g_symbol_registry == XT_UNDEFINED) return XT_UNDEFINED;
|
|
133
|
+
xt_value keys = xt_object_keys(g_symbol_registry);
|
|
134
|
+
xt_array *array = xt_as_array(keys);
|
|
135
|
+
if (!array) return XT_UNDEFINED;
|
|
136
|
+
for (uint32_t i = 0; i < array->length; i++) {
|
|
137
|
+
xt_value key = array->items[i];
|
|
138
|
+
if (xt_object_get(g_symbol_registry, key) == value) return key;
|
|
139
|
+
}
|
|
140
|
+
return XT_UNDEFINED;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
xt_value xt_symbol_static(xt_value name, int32_t argc, xt_value *argv) {
|
|
144
|
+
const char *fn = xt_string_data(name);
|
|
145
|
+
if (!fn) return XT_UNDEFINED;
|
|
146
|
+
if (strcmp(fn, "for") == 0) return xt_symbol_for(xt_arg_at(argc, argv, 0));
|
|
147
|
+
if (strcmp(fn, "keyFor") == 0) return xt_symbol_key_for(xt_arg_at(argc, argv, 0));
|
|
148
|
+
return XT_UNDEFINED;
|
|
149
|
+
}
|
package/runtime/xt_values.c
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
#include "rt_internal.h"
|
|
9
9
|
|
|
10
10
|
#include <math.h>
|
|
11
|
+
#include <ctype.h>
|
|
11
12
|
#include <stdio.h>
|
|
12
13
|
#include <stdlib.h>
|
|
13
14
|
#include <string.h>
|
|
@@ -78,11 +79,57 @@ int xt_string_equals(xt_string *a, xt_string *b) {
|
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
/*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
82
|
+
* ECMAScript number formatting.
|
|
83
|
+
*
|
|
84
|
+
* A double is rendered as the shortest decimal string that round-trips, then
|
|
85
|
+
* laid out with JavaScript's notation rules: fixed notation unless the decimal
|
|
86
|
+
* exponent is < -6 or >= 21, and a bare (unpadded, explicitly signed) exponent.
|
|
87
|
+
* The `toFixed`/`toExponential`/`toPrecision` variants reuse the same renderer.
|
|
84
88
|
*/
|
|
85
|
-
static void
|
|
89
|
+
static void xt_render_decimal(int negative, const char *digits, int nd, int exp10, int expo, char *buffer, size_t size) {
|
|
90
|
+
size_t o = 0;
|
|
91
|
+
if (negative && o + 1 < size) buffer[o++] = '-';
|
|
92
|
+
if (expo) {
|
|
93
|
+
if (o + 1 < size) buffer[o++] = digits[0];
|
|
94
|
+
if (nd > 1) {
|
|
95
|
+
if (o + 1 < size) buffer[o++] = '.';
|
|
96
|
+
for (int i = 1; i < nd && o + 1 < size; i++) buffer[o++] = digits[i];
|
|
97
|
+
}
|
|
98
|
+
int written = snprintf(buffer + o, size - o, "e%c%d", exp10 < 0 ? '-' : '+', exp10 < 0 ? -exp10 : exp10);
|
|
99
|
+
if (written > 0) o += (size_t)written;
|
|
100
|
+
} else if (exp10 >= 0) {
|
|
101
|
+
int intDigits = exp10 + 1;
|
|
102
|
+
if (nd <= intDigits) {
|
|
103
|
+
for (int i = 0; i < nd && o + 1 < size; i++) buffer[o++] = digits[i];
|
|
104
|
+
for (int i = nd; i < intDigits && o + 1 < size; i++) buffer[o++] = '0';
|
|
105
|
+
} else {
|
|
106
|
+
for (int i = 0; i < intDigits && o + 1 < size; i++) buffer[o++] = digits[i];
|
|
107
|
+
if (o + 1 < size) buffer[o++] = '.';
|
|
108
|
+
for (int i = intDigits; i < nd && o + 1 < size; i++) buffer[o++] = digits[i];
|
|
109
|
+
}
|
|
110
|
+
} else {
|
|
111
|
+
if (o + 1 < size) buffer[o++] = '0';
|
|
112
|
+
if (o + 1 < size) buffer[o++] = '.';
|
|
113
|
+
for (int i = 0; i < -exp10 - 1 && o + 1 < size; i++) buffer[o++] = '0';
|
|
114
|
+
for (int i = 0; i < nd && o + 1 < size; i++) buffer[o++] = digits[i];
|
|
115
|
+
}
|
|
116
|
+
buffer[o] = '\0';
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/* Split a `%e`-formatted string into its significant digits and exponent. */
|
|
120
|
+
static void xt_parse_scientific(const char *sci, char *digits, int *nd, int *exp10) {
|
|
121
|
+
int n = 0;
|
|
122
|
+
*exp10 = 0;
|
|
123
|
+
const char *q = sci;
|
|
124
|
+
while (*q && *q != 'e' && *q != 'E') {
|
|
125
|
+
if (*q >= '0' && *q <= '9') digits[n++] = *q;
|
|
126
|
+
q++;
|
|
127
|
+
}
|
|
128
|
+
if (*q == 'e' || *q == 'E') *exp10 = atoi(q + 1);
|
|
129
|
+
*nd = n;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
void xt_number_to_js_string(double d, char *buffer, size_t size) {
|
|
86
133
|
if (isnan(d)) {
|
|
87
134
|
snprintf(buffer, size, "NaN");
|
|
88
135
|
return;
|
|
@@ -95,14 +142,121 @@ static void xt_format_double(double d, char *buffer, size_t size) {
|
|
|
95
142
|
snprintf(buffer, size, "0");
|
|
96
143
|
return;
|
|
97
144
|
}
|
|
98
|
-
|
|
99
|
-
|
|
145
|
+
int negative = d < 0;
|
|
146
|
+
double x = negative ? -d : d;
|
|
147
|
+
char sci[64];
|
|
148
|
+
for (int p = 1; p <= 17; p++) {
|
|
149
|
+
snprintf(sci, sizeof(sci), "%.*e", p - 1, x);
|
|
150
|
+
if (strtod(sci, NULL) == x) break;
|
|
151
|
+
}
|
|
152
|
+
char digits[32];
|
|
153
|
+
int nd = 0;
|
|
154
|
+
int exp10 = 0;
|
|
155
|
+
xt_parse_scientific(sci, digits, &nd, &exp10);
|
|
156
|
+
while (nd > 1 && digits[nd - 1] == '0') nd--;
|
|
157
|
+
xt_render_decimal(negative, digits, nd, exp10, exp10 < -6 || exp10 >= 21, buffer, size);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
void xt_number_to_exponential(double d, int precision, char *buffer, size_t size) {
|
|
161
|
+
if (isnan(d)) {
|
|
162
|
+
snprintf(buffer, size, "NaN");
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (isinf(d)) {
|
|
166
|
+
snprintf(buffer, size, d < 0 ? "-Infinity" : "Infinity");
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
int negative = d < 0;
|
|
170
|
+
double x = negative ? -d : d;
|
|
171
|
+
char sci[64];
|
|
172
|
+
if (precision < 0) {
|
|
173
|
+
/* No fractionDigits argument: use the shortest round-tripping form. */
|
|
174
|
+
for (int p = 1; p <= 17; p++) {
|
|
175
|
+
snprintf(sci, sizeof(sci), "%.*e", p - 1, x);
|
|
176
|
+
if (strtod(sci, NULL) == x) break;
|
|
177
|
+
}
|
|
178
|
+
} else {
|
|
179
|
+
snprintf(sci, sizeof(sci), "%.*e", precision, x);
|
|
180
|
+
}
|
|
181
|
+
char digits[64];
|
|
182
|
+
int nd = 0;
|
|
183
|
+
int exp10 = 0;
|
|
184
|
+
xt_parse_scientific(sci, digits, &nd, &exp10);
|
|
185
|
+
if (precision < 0) while (nd > 1 && digits[nd - 1] == '0') nd--;
|
|
186
|
+
xt_render_decimal(negative, digits, nd, exp10, 1, buffer, size);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
void xt_number_to_precision(double d, int precision, char *buffer, size_t size) {
|
|
190
|
+
if (isnan(d)) {
|
|
191
|
+
snprintf(buffer, size, "NaN");
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
if (isinf(d)) {
|
|
195
|
+
snprintf(buffer, size, d < 0 ? "-Infinity" : "Infinity");
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
int negative = d < 0;
|
|
199
|
+
double x = negative ? -d : d;
|
|
200
|
+
char sci[512];
|
|
201
|
+
snprintf(sci, sizeof(sci), "%.*e", precision - 1, x);
|
|
202
|
+
char digits[512];
|
|
203
|
+
int nd = 0;
|
|
204
|
+
int exp10 = 0;
|
|
205
|
+
xt_parse_scientific(sci, digits, &nd, &exp10);
|
|
206
|
+
xt_render_decimal(negative, digits, nd, exp10, exp10 < -6 || exp10 >= precision, buffer, size);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
void xt_number_to_fixed(double d, int precision, char *buffer, size_t size) {
|
|
210
|
+
if (isnan(d)) {
|
|
211
|
+
snprintf(buffer, size, "NaN");
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (isinf(d)) {
|
|
215
|
+
snprintf(buffer, size, d < 0 ? "-Infinity" : "Infinity");
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
if (fabs(d) >= 1e21) {
|
|
219
|
+
xt_number_to_js_string(d, buffer, size);
|
|
100
220
|
return;
|
|
101
221
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
222
|
+
int negative = d < 0;
|
|
223
|
+
double x = negative ? -d : d;
|
|
224
|
+
/* 20 guard digits let us round exactly half away from zero, which is what
|
|
225
|
+
ECMAScript specifies and what `printf`'s round-half-to-even does not. */
|
|
226
|
+
char raw[1024];
|
|
227
|
+
snprintf(raw, sizeof(raw), "%.*f", precision + 20, x);
|
|
228
|
+
const char *dot = strchr(raw, '.');
|
|
229
|
+
int intLen = dot ? (int)(dot - raw) : (int)strlen(raw);
|
|
230
|
+
int len = intLen;
|
|
231
|
+
if (precision > 0) len += 1 + precision;
|
|
232
|
+
if (len >= (int)sizeof(raw)) len = (int)sizeof(raw) - 1;
|
|
233
|
+
char work[1024];
|
|
234
|
+
memcpy(work, raw, (size_t)len);
|
|
235
|
+
work[len] = '\0';
|
|
236
|
+
/* The digit that decides rounding is the first one we dropped. With a
|
|
237
|
+
precision of zero that is the character after the decimal point. */
|
|
238
|
+
int firstDropped = precision > 0 ? len : (dot ? intLen + 1 : len);
|
|
239
|
+
if (dot && raw[firstDropped] >= '5') {
|
|
240
|
+
int i = len - 1;
|
|
241
|
+
while (i >= 0) {
|
|
242
|
+
if (work[i] == '.') {
|
|
243
|
+
i--;
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
if (work[i] < '9') {
|
|
247
|
+
work[i]++;
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
work[i] = '0';
|
|
251
|
+
i--;
|
|
252
|
+
}
|
|
253
|
+
if (i < 0) {
|
|
254
|
+
memmove(work + 1, work, strlen(work) + 1);
|
|
255
|
+
work[0] = '1';
|
|
256
|
+
}
|
|
105
257
|
}
|
|
258
|
+
if (negative) snprintf(buffer, size, "-%s", work);
|
|
259
|
+
else snprintf(buffer, size, "%s", work);
|
|
106
260
|
}
|
|
107
261
|
|
|
108
262
|
/* ------------------------------------------------------------------------- */
|
|
@@ -131,18 +285,39 @@ double xt_to_number(xt_value v) {
|
|
|
131
285
|
if (XT_IS_BIGINT(v)) return xt_bigint_to_double_value(v);
|
|
132
286
|
if (XT_IS_STRING(v)) {
|
|
133
287
|
xt_string *s = xt_as_string(v);
|
|
134
|
-
|
|
135
|
-
char *end =
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
288
|
+
const char *begin = s->data;
|
|
289
|
+
const char *end = s->data + s->length;
|
|
290
|
+
while (begin < end && isspace((unsigned char)*begin)) begin++;
|
|
291
|
+
while (end > begin && isspace((unsigned char)end[-1])) end--;
|
|
292
|
+
size_t length = (size_t)(end - begin);
|
|
293
|
+
if (length == 0) return 0.0;
|
|
294
|
+
char stackbuf[128];
|
|
295
|
+
char *tmp = length < sizeof(stackbuf) ? stackbuf : (char *)malloc(length + 1);
|
|
296
|
+
memcpy(tmp, begin, length);
|
|
297
|
+
tmp[length] = '\0';
|
|
298
|
+
double result;
|
|
299
|
+
int base = 0;
|
|
300
|
+
if (length > 2 && tmp[0] == '0' && (tmp[1] == 'x' || tmp[1] == 'X')) base = 16;
|
|
301
|
+
else if (length > 2 && tmp[0] == '0' && (tmp[1] == 'o' || tmp[1] == 'O')) base = 8;
|
|
302
|
+
else if (length > 2 && tmp[0] == '0' && (tmp[1] == 'b' || tmp[1] == 'B')) base = 2;
|
|
303
|
+
if (base != 0) {
|
|
304
|
+
char *stop = NULL;
|
|
305
|
+
unsigned long long parsed = strtoull(tmp + 2, &stop, base);
|
|
306
|
+
result = (*stop == '\0' && stop != tmp + 2) ? (double)parsed : NAN;
|
|
307
|
+
} else {
|
|
308
|
+
char *stop = NULL;
|
|
309
|
+
result = strtod(tmp, &stop);
|
|
310
|
+
if (stop != tmp + length) result = NAN;
|
|
311
|
+
}
|
|
312
|
+
if (tmp != stackbuf) free(tmp);
|
|
313
|
+
return result;
|
|
139
314
|
}
|
|
140
315
|
return NAN;
|
|
141
316
|
}
|
|
142
317
|
|
|
143
318
|
static xt_value xt_number_to_string_value(double d) {
|
|
144
319
|
char buffer[64];
|
|
145
|
-
|
|
320
|
+
xt_number_to_js_string(d, buffer, sizeof(buffer));
|
|
146
321
|
return xt_string_from_cstr(buffer);
|
|
147
322
|
}
|
|
148
323
|
|
|
@@ -178,6 +353,13 @@ xt_value xt_to_string(xt_value v) {
|
|
|
178
353
|
return result;
|
|
179
354
|
}
|
|
180
355
|
if (XT_IS_FUNCTION(v)) return xt_string_from_cstr("function () { [native code] }");
|
|
356
|
+
if (xt_is_symbol(v)) {
|
|
357
|
+
xt_throw(xt_string_from_cstr("TypeError: Cannot convert a Symbol value to a string"));
|
|
358
|
+
}
|
|
359
|
+
if (XT_IS_OBJECT(v) &&
|
|
360
|
+
((xt_object *)XT_GET_PTR(v))->header.kind == XT_OBJECT_KIND_ERROR) {
|
|
361
|
+
return xt_error_to_string(v);
|
|
362
|
+
}
|
|
181
363
|
return xt_string_from_cstr("[object Object]");
|
|
182
364
|
}
|
|
183
365
|
|
|
@@ -189,6 +371,7 @@ xt_value xt_typeof(xt_value v) {
|
|
|
189
371
|
if (v == XT_UNDEFINED) return xt_string_from_cstr("undefined");
|
|
190
372
|
if (XT_IS_FUNCTION(v)) return xt_string_from_cstr("function");
|
|
191
373
|
if (v == XT_NULL) return xt_string_from_cstr("object");
|
|
374
|
+
if (xt_is_symbol(v)) return xt_string_from_cstr("symbol");
|
|
192
375
|
return xt_string_from_cstr("object");
|
|
193
376
|
}
|
|
194
377
|
|
|
@@ -200,7 +383,15 @@ static void xt_throw_mixed_bigint(void) {
|
|
|
200
383
|
xt_throw(xt_string_from_cstr("TypeError: Cannot mix BigInt and other types, use explicit conversions"));
|
|
201
384
|
}
|
|
202
385
|
|
|
386
|
+
/* ToPrimitive for the operators: arrays/objects/functions stringify (their
|
|
387
|
+
`valueOf` is the object itself, so `toString` decides). */
|
|
388
|
+
static int xt_is_object_like(xt_value v) { return XT_IS_OBJECT(v) || XT_IS_ARRAY(v) || XT_IS_FUNCTION(v); }
|
|
389
|
+
|
|
390
|
+
static xt_value xt_to_primitive(xt_value v) { return xt_is_object_like(v) ? xt_to_string(v) : v; }
|
|
391
|
+
|
|
203
392
|
xt_value xt_add(xt_value a, xt_value b) {
|
|
393
|
+
a = xt_to_primitive(a);
|
|
394
|
+
b = xt_to_primitive(b);
|
|
204
395
|
if (XT_IS_NUMBER(a) && XT_IS_NUMBER(b)) {
|
|
205
396
|
return xt_number(xt_to_double(a) + xt_to_double(b));
|
|
206
397
|
}
|
|
@@ -364,6 +555,8 @@ static int xt_compare_numeric(xt_value a, xt_value b) {
|
|
|
364
555
|
}
|
|
365
556
|
|
|
366
557
|
xt_value xt_lt(xt_value a, xt_value b) {
|
|
558
|
+
a = xt_to_primitive(a);
|
|
559
|
+
b = xt_to_primitive(b);
|
|
367
560
|
if (XT_IS_STRING(a) && XT_IS_STRING(b)) {
|
|
368
561
|
xt_string *x = xt_as_string(a);
|
|
369
562
|
xt_string *y = xt_as_string(b);
|
|
@@ -377,6 +570,8 @@ xt_value xt_lt(xt_value a, xt_value b) {
|
|
|
377
570
|
}
|
|
378
571
|
|
|
379
572
|
xt_value xt_le(xt_value a, xt_value b) {
|
|
573
|
+
a = xt_to_primitive(a);
|
|
574
|
+
b = xt_to_primitive(b);
|
|
380
575
|
if (XT_IS_STRING(a) && XT_IS_STRING(b)) {
|
|
381
576
|
xt_string *x = xt_as_string(a);
|
|
382
577
|
xt_string *y = xt_as_string(b);
|
|
@@ -396,10 +591,21 @@ xt_value xt_gt(xt_value a, xt_value b) { return xt_lt(b, a); }
|
|
|
396
591
|
xt_value xt_ge(xt_value a, xt_value b) { return xt_le(b, a); }
|
|
397
592
|
|
|
398
593
|
static int xt_loose_equals(xt_value a, xt_value b) {
|
|
594
|
+
if (xt_is_symbol(a) || xt_is_symbol(b)) return a == b;
|
|
399
595
|
if (XT_IS_NUMBER(a) && XT_IS_NUMBER(b)) return xt_to_double(a) == xt_to_double(b);
|
|
400
596
|
if (XT_IS_STRING(a) && XT_IS_STRING(b)) return xt_string_equals(xt_as_string(a), xt_as_string(b));
|
|
401
597
|
if (a == b) return 1;
|
|
402
598
|
if ((a == XT_NULL && b == XT_UNDEFINED) || (a == XT_UNDEFINED && b == XT_NULL)) return 1;
|
|
599
|
+
/* Abstract equality converts an object operand to a primitive (via
|
|
600
|
+
ToPrimitive) before comparing, so `[] == 0`, `[1] == 1` and
|
|
601
|
+
`{} == "[object Object]"` are all true. */
|
|
602
|
+
if (XT_IS_OBJECT(a) || XT_IS_ARRAY(a) || XT_IS_FUNCTION(a)) {
|
|
603
|
+
if (XT_IS_OBJECT(b) || XT_IS_ARRAY(b) || XT_IS_FUNCTION(b)) return 0;
|
|
604
|
+
return xt_loose_equals(xt_to_string(a), b);
|
|
605
|
+
}
|
|
606
|
+
if (XT_IS_OBJECT(b) || XT_IS_ARRAY(b) || XT_IS_FUNCTION(b)) {
|
|
607
|
+
return xt_loose_equals(a, xt_to_string(b));
|
|
608
|
+
}
|
|
403
609
|
if (XT_IS_BIGINT(a) || XT_IS_BIGINT(b)) {
|
|
404
610
|
xt_value big = XT_IS_BIGINT(a) ? a : b;
|
|
405
611
|
xt_value other = XT_IS_BIGINT(a) ? b : a;
|
package/scripts/build-runtime.ts
CHANGED
|
@@ -73,7 +73,7 @@ function compile(sources: readonly string[], extension: string): string[] {
|
|
|
73
73
|
const object = join(objDir, `${extension}_${index}_${basename(source, ".c")}.o`);
|
|
74
74
|
const result = spawnSync(
|
|
75
75
|
clang,
|
|
76
|
-
["-O2", "-D_CRT_SECURE_NO_WARNINGS", "-c", source, "-o", object, `-I${runtimeDir}`],
|
|
76
|
+
["-O2", "-Wall", "-Wextra", "-D_CRT_SECURE_NO_WARNINGS", "-c", source, "-o", object, `-I${runtimeDir}`],
|
|
77
77
|
{ stdio: "inherit", env: childEnv },
|
|
78
78
|
);
|
|
79
79
|
if (result.status !== 0) {
|
package/src/ast/expressions.ts
CHANGED
|
@@ -55,11 +55,15 @@ export interface NoSubstitutionTemplateLiteral extends Node {
|
|
|
55
55
|
readonly kind: SyntaxKind.NoSubstitutionTemplateLiteral;
|
|
56
56
|
readonly text: string;
|
|
57
57
|
readonly value: string;
|
|
58
|
+
/** Raw text between the backticks (escapes preserved), for tagged templates. */
|
|
59
|
+
readonly raw?: string;
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
export interface TemplateLiteral extends Node {
|
|
61
63
|
readonly kind: SyntaxKind.TemplateLiteral;
|
|
62
64
|
readonly head: string;
|
|
65
|
+
/** Raw text of the head chunk, for tagged templates. */
|
|
66
|
+
readonly raw?: string;
|
|
63
67
|
readonly spans: TemplateSpan[];
|
|
64
68
|
}
|
|
65
69
|
|
|
@@ -67,6 +71,8 @@ export interface TemplateSpan extends Node {
|
|
|
67
71
|
readonly kind: SyntaxKind.TemplateSpan;
|
|
68
72
|
readonly expression: Expression;
|
|
69
73
|
readonly literal: string;
|
|
74
|
+
/** Raw text of the chunk that follows this substitution. */
|
|
75
|
+
readonly raw?: string;
|
|
70
76
|
/** True when this span terminates the template (tail) rather than continues it. */
|
|
71
77
|
readonly isTail: boolean;
|
|
72
78
|
}
|
|
@@ -108,6 +114,8 @@ export interface PropertyAssignment extends Node {
|
|
|
108
114
|
readonly kind: SyntaxKind.PropertyAssignment;
|
|
109
115
|
readonly name: PropertyName;
|
|
110
116
|
readonly initializer: Expression;
|
|
117
|
+
/** `get x() {}` / `set x(v) {}` in an object literal. */
|
|
118
|
+
readonly accessor?: "get" | "set";
|
|
111
119
|
}
|
|
112
120
|
|
|
113
121
|
export interface ShorthandPropertyAssignment extends Node {
|
package/src/binder/binder.ts
CHANGED
|
@@ -108,6 +108,7 @@ export class Binder {
|
|
|
108
108
|
isModule,
|
|
109
109
|
isArrow,
|
|
110
110
|
isAsync: (((node as { flags?: number }).flags ?? 0) & NodeFlags.Async) !== 0,
|
|
111
|
+
isGenerator: (((node as { flags?: number }).flags ?? 0) & NodeFlags.Generator) !== 0,
|
|
111
112
|
usesThis: false,
|
|
112
113
|
capturesThis: false,
|
|
113
114
|
};
|
|
@@ -120,7 +121,6 @@ export class Binder {
|
|
|
120
121
|
}
|
|
121
122
|
}
|
|
122
123
|
|
|
123
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
124
124
|
export interface Binder extends DeclarationMethods, ReferenceMethods {}
|
|
125
125
|
|
|
126
126
|
Object.assign(Binder.prototype, declarationMethods, referenceMethods);
|
package/src/binder/references.ts
CHANGED
|
@@ -49,7 +49,7 @@ export interface ReferenceMethods {
|
|
|
49
49
|
bindNode(this: Binder, node: Node | undefined, scope: Scope): void;
|
|
50
50
|
bindVariableList(this: Binder, list: VariableDeclarationList, scope: Scope): void;
|
|
51
51
|
bindBindingPattern(this: Binder, name: BindingName, scope: Scope): void;
|
|
52
|
-
bindFunction(this: Binder, node: FunctionDeclaration | FunctionExpression | ArrowFunction, parentScope: Scope, symbol: SymbolInfo | undefined): void;
|
|
52
|
+
bindFunction(this: Binder, node: FunctionDeclaration | FunctionExpression | ArrowFunction, parentScope: Scope, symbol: SymbolInfo | undefined, inferredName?: string): void;
|
|
53
53
|
bindClass(this: Binder, node: ClassDeclaration | ClassExpression, scope: Scope): void;
|
|
54
54
|
createClassFunction(this: Binder, member: Node, name: string, parameters: readonly Parameter[], body: Block | undefined, parentScope: Scope, info: ClassInfo, isStatic: boolean, isConstructor: boolean): FunctionInfo;
|
|
55
55
|
reference(this: Binder, identifier: Identifier, scope: Scope): void;
|
|
@@ -80,7 +80,6 @@ export const referenceMethods: ReferenceMethods = {
|
|
|
80
80
|
case SyntaxKind.FunctionDeclaration: {
|
|
81
81
|
const fn = node as FunctionDeclaration;
|
|
82
82
|
const symbol = this.symbolOfDeclaration.get(fn);
|
|
83
|
-
if (symbol) (symbol.declarations as Node[]).length; // keep declaration mapping warm
|
|
84
83
|
this.bindFunction(fn, scope, symbol);
|
|
85
84
|
return;
|
|
86
85
|
}
|
|
@@ -108,7 +107,24 @@ export const referenceMethods: ReferenceMethods = {
|
|
|
108
107
|
if (property.name.kind === SyntaxKind.ComputedPropertyName) {
|
|
109
108
|
this.bindNode((property.name as unknown as { expression: Expression }).expression, scope);
|
|
110
109
|
}
|
|
111
|
-
|
|
110
|
+
const initializer = property.initializer;
|
|
111
|
+
if (
|
|
112
|
+
initializer.kind === SyntaxKind.FunctionExpression ||
|
|
113
|
+
initializer.kind === SyntaxKind.ArrowFunction
|
|
114
|
+
) {
|
|
115
|
+
// Infer the function name from the property key (`{ sum() {} }`).
|
|
116
|
+
const accessor = (property as unknown as { accessor?: "get" | "set" }).accessor;
|
|
117
|
+
const key = classMemberName(property.name);
|
|
118
|
+
const inferred = accessor ? `${accessor} ${key}` : key;
|
|
119
|
+
this.bindFunction(
|
|
120
|
+
initializer as FunctionExpression | ArrowFunction,
|
|
121
|
+
scope,
|
|
122
|
+
undefined,
|
|
123
|
+
inferred,
|
|
124
|
+
);
|
|
125
|
+
} else {
|
|
126
|
+
this.bindNode(initializer, scope);
|
|
127
|
+
}
|
|
112
128
|
return;
|
|
113
129
|
}
|
|
114
130
|
case SyntaxKind.ShorthandPropertyAssignment: {
|
|
@@ -202,7 +218,23 @@ export const referenceMethods: ReferenceMethods = {
|
|
|
202
218
|
} else {
|
|
203
219
|
this.bindBindingPattern(declaration.name, scope);
|
|
204
220
|
}
|
|
205
|
-
|
|
221
|
+
const initializer = declaration.initializer;
|
|
222
|
+
if (
|
|
223
|
+
declaration.name.kind === SyntaxKind.Identifier &&
|
|
224
|
+
initializer &&
|
|
225
|
+
(initializer.kind === SyntaxKind.FunctionExpression ||
|
|
226
|
+
initializer.kind === SyntaxKind.ArrowFunction)
|
|
227
|
+
) {
|
|
228
|
+
// Infer the function name from the variable it is assigned to.
|
|
229
|
+
this.bindFunction(
|
|
230
|
+
initializer as FunctionExpression | ArrowFunction,
|
|
231
|
+
scope,
|
|
232
|
+
undefined,
|
|
233
|
+
(declaration.name as Identifier).text,
|
|
234
|
+
);
|
|
235
|
+
} else {
|
|
236
|
+
this.bindNode(initializer, scope);
|
|
237
|
+
}
|
|
206
238
|
}
|
|
207
239
|
},
|
|
208
240
|
|
|
@@ -221,6 +253,7 @@ export const referenceMethods: ReferenceMethods = {
|
|
|
221
253
|
node: FunctionDeclaration | FunctionExpression | ArrowFunction,
|
|
222
254
|
parentScope: Scope,
|
|
223
255
|
symbol: SymbolInfo | undefined,
|
|
256
|
+
inferredName?: string,
|
|
224
257
|
): void {
|
|
225
258
|
const name =
|
|
226
259
|
node.kind === SyntaxKind.FunctionDeclaration
|
|
@@ -230,6 +263,9 @@ export const referenceMethods: ReferenceMethods = {
|
|
|
230
263
|
: "(arrow)";
|
|
231
264
|
const parentFn = this.current;
|
|
232
265
|
const fn = this.createFunction(name, node, parentFn, false, node.kind === SyntaxKind.ArrowFunction);
|
|
266
|
+
if (inferredName && (name === "(anonymous)" || name === "(arrow)")) {
|
|
267
|
+
(fn as { name: string }).name = inferredName;
|
|
268
|
+
}
|
|
233
269
|
this.current = fn;
|
|
234
270
|
|
|
235
271
|
const scope = this.createScope(ScopeKind.Function, node, parentScope);
|
|
@@ -309,6 +345,13 @@ export const referenceMethods: ReferenceMethods = {
|
|
|
309
345
|
const method = member as MethodDeclaration;
|
|
310
346
|
const isStatic = method.modifiers.some((modifier) => modifier.modifierKind === ModifierKind.Static);
|
|
311
347
|
const fn = this.createClassFunction(method, classMemberName(method.name), method.parameters, method.body, classScope, info, isStatic, false);
|
|
348
|
+
if (method.name.kind === SyntaxKind.ComputedPropertyName) {
|
|
349
|
+
// Computed member names are evaluated in the enclosing scope when
|
|
350
|
+
// the class is defined, so bind them there.
|
|
351
|
+
const keyExpression = (method.name as unknown as { expression: Expression }).expression;
|
|
352
|
+
this.bindNode(keyExpression, scope);
|
|
353
|
+
(fn as MutableFunction & { computedKey: Expression }).computedKey = keyExpression;
|
|
354
|
+
}
|
|
312
355
|
if (isStatic) (info.statics as FunctionInfo[]).push(fn);
|
|
313
356
|
else (info.methods as FunctionInfo[]).push(fn);
|
|
314
357
|
}
|
package/src/binder/types.ts
CHANGED
|
@@ -61,12 +61,16 @@ export interface FunctionInfo {
|
|
|
61
61
|
readonly isArrow: boolean;
|
|
62
62
|
/** True when the function was declared `async`. */
|
|
63
63
|
readonly isAsync: boolean;
|
|
64
|
+
/** True for `function*` / generator methods; calling one creates a generator. */
|
|
65
|
+
readonly isGenerator: boolean;
|
|
64
66
|
/** True when this function's body mentions `this` directly. */
|
|
65
67
|
usesThis: boolean;
|
|
66
68
|
/** True when an arrow function must receive `this` from its enclosing scope. */
|
|
67
69
|
capturesThis: boolean;
|
|
68
70
|
/** Set for class methods/constructors; carries the owning class. */
|
|
69
71
|
classInfo?: ClassInfo;
|
|
72
|
+
/** Computed member name (`[expr]() {}`), evaluated at class definition. */
|
|
73
|
+
computedKey?: Expression;
|
|
70
74
|
/** True for `static` class members. */
|
|
71
75
|
isStatic?: boolean;
|
|
72
76
|
/** True for an explicit `constructor`. */
|
package/src/cli/main.ts
CHANGED
|
@@ -13,9 +13,8 @@
|
|
|
13
13
|
|
|
14
14
|
import { spawnSync } from "node:child_process";
|
|
15
15
|
import { readFileSync } from "node:fs";
|
|
16
|
-
import { resolve } from "node:path";
|
|
17
16
|
import { pathToFileURL } from "node:url";
|
|
18
|
-
import {
|
|
17
|
+
import { formatDiagnostic, type Diagnostic } from "../diagnostics/diagnostic.js";
|
|
19
18
|
import { SourceFile } from "../diagnostics/source.js";
|
|
20
19
|
import { build, compileEntry, COMPILER_VERSION, type EmitKind } from "../driver/compiler.js";
|
|
21
20
|
import { findRuntimeDir, platformSlug } from "../driver/paths.js";
|