nomen-lang 0.6.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/System/List.nm +12 -0
- package/core/System/StringBuilder.nm +126 -3
- package/core/System/Text/Regex.nm +345 -91
- package/dist/index.mjs +492 -62
- package/package.json +1 -1
- package/src/test.ts +45 -5
package/dist/index.mjs
CHANGED
|
@@ -19242,6 +19242,7 @@ function build_function_node$1(node, status) {
|
|
|
19242
19242
|
const old_struct_param_slots = status.function_struct_param_slots;
|
|
19243
19243
|
const old_function_param_types = status.function_param_types;
|
|
19244
19244
|
const old_function_local_types = status.function_local_types;
|
|
19245
|
+
const old_variable_types = status.variable_types;
|
|
19245
19246
|
status.function_param_regs = /* @__PURE__ */ new Map();
|
|
19246
19247
|
status.function_param_vars = /* @__PURE__ */ new Set();
|
|
19247
19248
|
status.function_array_params = /* @__PURE__ */ new Set();
|
|
@@ -19250,6 +19251,7 @@ function build_function_node$1(node, status) {
|
|
|
19250
19251
|
status.function_struct_param_slots = /* @__PURE__ */ new Set();
|
|
19251
19252
|
status.function_param_types = /* @__PURE__ */ new Map();
|
|
19252
19253
|
status.function_local_types = /* @__PURE__ */ new Map();
|
|
19254
|
+
status.variable_types = /* @__PURE__ */ new Map();
|
|
19253
19255
|
const old_variadic_params_aarch64 = status.function_variadic_params;
|
|
19254
19256
|
const old_view_params = status.function_view_params;
|
|
19255
19257
|
status.function_variadic_params = /* @__PURE__ */ new Set();
|
|
@@ -19658,6 +19660,7 @@ function build_function_node$1(node, status) {
|
|
|
19658
19660
|
status.function_struct_param_slots = old_struct_param_slots;
|
|
19659
19661
|
status.function_param_types = old_function_param_types;
|
|
19660
19662
|
status.function_local_types = old_function_local_types;
|
|
19663
|
+
status.variable_types = old_variable_types;
|
|
19661
19664
|
status.function_variadic_params = old_variadic_params_aarch64;
|
|
19662
19665
|
status.function_view_params = old_view_params;
|
|
19663
19666
|
status.function_return_label = old_return_label;
|
|
@@ -21418,6 +21421,67 @@ function call_in_set(set, call) {
|
|
|
21418
21421
|
return set.has(call.name.replace(/#/g, ""));
|
|
21419
21422
|
}
|
|
21420
21423
|
//#endregion
|
|
21424
|
+
//#region ../src/build_common/fold_string_const.ts
|
|
21425
|
+
/**
|
|
21426
|
+
* Fold a top-level `const`'s string `+` chain into a single string literal.
|
|
21427
|
+
*
|
|
21428
|
+
* Module-level `const` declarations are inlined at every use site (see
|
|
21429
|
+
* `top_level_consts` in both backends' BuildStatus): the build replays the
|
|
21430
|
+
* const's initializer expression wherever the name appears. For a composed
|
|
21431
|
+
* pattern like `pub const HTML_TAG_REGEX = "^(" + TAG_NAME + "|…)"` that
|
|
21432
|
+
* replay lowers to a malloc/copy/free `string_add` chain PER USE — the
|
|
21433
|
+
* allmark port's inline-token loop rebuilt its ~1 KB pattern on every
|
|
21434
|
+
* attempt, and the chain's calls were also the trigger for the aarch64
|
|
21435
|
+
* ref-argument clobber (PORT.md).
|
|
21436
|
+
*
|
|
21437
|
+
* When the initializer is a pure `+` chain of plain string literals and
|
|
21438
|
+
* references to other foldable consts, this returns one merged literal
|
|
21439
|
+
* ValueNode — semantically the string the source spells — that the use site
|
|
21440
|
+
* emits as rodata instead. Anything else (a runtime operand, a struct ctor,
|
|
21441
|
+
* an operator overload) returns null and the tree builds as before.
|
|
21442
|
+
*
|
|
21443
|
+
* Raw token merging is byte-preserving: escape sequences are self-contained
|
|
21444
|
+
* within a part's content (a content ending in a lone `\` would have
|
|
21445
|
+
* escaped that part's closing quote, so it cannot occur), and both
|
|
21446
|
+
* emitters' `\x`-as-octal re-encoding plus the 2/3-digit caps keep merged
|
|
21447
|
+
* escapes from absorbing a following part's text.
|
|
21448
|
+
*/
|
|
21449
|
+
const fold_cache = /* @__PURE__ */ new WeakMap();
|
|
21450
|
+
function fold_string_const(decl, consts) {
|
|
21451
|
+
if (fold_cache.has(decl)) return fold_cache.get(decl);
|
|
21452
|
+
const folded = fold_value(decl.value, consts, /* @__PURE__ */ new Set());
|
|
21453
|
+
fold_cache.set(decl, folded);
|
|
21454
|
+
return folded;
|
|
21455
|
+
}
|
|
21456
|
+
function fold_value(node, consts, active) {
|
|
21457
|
+
if (!node) return null;
|
|
21458
|
+
if (node.node_type === "value") {
|
|
21459
|
+
const raw = node.value;
|
|
21460
|
+
if (typeof raw !== "string") return null;
|
|
21461
|
+
if (raw.startsWith("\"")) return literal(raw, node.start);
|
|
21462
|
+
if (active.has(raw)) return null;
|
|
21463
|
+
const ref = consts.get(raw);
|
|
21464
|
+
if (!ref) return null;
|
|
21465
|
+
active.add(raw);
|
|
21466
|
+
const folded = fold_value(ref.value, consts, active);
|
|
21467
|
+
active.delete(raw);
|
|
21468
|
+
return folded;
|
|
21469
|
+
}
|
|
21470
|
+
if (node.node_type === "op") {
|
|
21471
|
+
const op = node;
|
|
21472
|
+
if (!(op.op === "+" && (!op.operator_func || op.operator_func.struct_name === "string"))) return null;
|
|
21473
|
+
const left = fold_value(op.left_value, consts, active);
|
|
21474
|
+
if (!left) return null;
|
|
21475
|
+
const right = fold_value(op.right_value, consts, active);
|
|
21476
|
+
if (!right) return null;
|
|
21477
|
+
return literal(left.value.slice(0, -1) + right.value.slice(1), node.start);
|
|
21478
|
+
}
|
|
21479
|
+
return null;
|
|
21480
|
+
}
|
|
21481
|
+
function literal(raw, start) {
|
|
21482
|
+
return new ValueNode(start, raw, new Type("string", true));
|
|
21483
|
+
}
|
|
21484
|
+
//#endregion
|
|
21421
21485
|
//#region ../src/build_common/string_escapes.ts
|
|
21422
21486
|
/**
|
|
21423
21487
|
* Source string-literal escape handling shared by both backends.
|
|
@@ -21452,8 +21516,8 @@ function reencode_hex_escapes(raw) {
|
|
|
21452
21516
|
let j = i + 2;
|
|
21453
21517
|
let value = 0;
|
|
21454
21518
|
let digits = 0;
|
|
21455
|
-
while (j < raw.length && digits < 2 && is_hex_digit(raw[j])) {
|
|
21456
|
-
value = value * 16 + hex_value(raw[j]);
|
|
21519
|
+
while (j < raw.length && digits < 2 && is_hex_digit$1(raw[j])) {
|
|
21520
|
+
value = value * 16 + hex_value$1(raw[j]);
|
|
21457
21521
|
j += 1;
|
|
21458
21522
|
digits += 1;
|
|
21459
21523
|
}
|
|
@@ -21468,10 +21532,10 @@ function reencode_hex_escapes(raw) {
|
|
|
21468
21532
|
}
|
|
21469
21533
|
return out;
|
|
21470
21534
|
}
|
|
21471
|
-
function is_hex_digit(c) {
|
|
21535
|
+
function is_hex_digit$1(c) {
|
|
21472
21536
|
return c >= "0" && c <= "9" || c >= "a" && c <= "f" || c >= "A" && c <= "F";
|
|
21473
21537
|
}
|
|
21474
|
-
function hex_value(c) {
|
|
21538
|
+
function hex_value$1(c) {
|
|
21475
21539
|
if (c <= "9") return c.charCodeAt(0) - 48;
|
|
21476
21540
|
if (c <= "F") return c.charCodeAt(0) - 55;
|
|
21477
21541
|
return c.charCodeAt(0) - 87;
|
|
@@ -21501,7 +21565,7 @@ function scan_string_escapes(raw) {
|
|
|
21501
21565
|
if (next === "x") {
|
|
21502
21566
|
let j = i + 2;
|
|
21503
21567
|
let digits = 0;
|
|
21504
|
-
while (j < end && digits < 2 && is_hex_digit(raw[j])) {
|
|
21568
|
+
while (j < end && digits < 2 && is_hex_digit$1(raw[j])) {
|
|
21505
21569
|
j += 1;
|
|
21506
21570
|
digits += 1;
|
|
21507
21571
|
}
|
|
@@ -21536,6 +21600,16 @@ function scan_string_escapes(raw) {
|
|
|
21536
21600
|
}
|
|
21537
21601
|
return issues;
|
|
21538
21602
|
}
|
|
21603
|
+
/** Escape one raw string-literal token (quotes included) for a GAS
|
|
21604
|
+
* `.asciz` directive: source `\xHH` hex escapes re-encode as 3-digit octal
|
|
21605
|
+
* (GAS consumes `\x` greedily — see reencode_hex_escapes) and raw newlines
|
|
21606
|
+
* (multi-line strings) become `\n` so the directive stays one line. */
|
|
21607
|
+
function escape_asciz(value) {
|
|
21608
|
+
const reencoded = reencode_hex_escapes(value);
|
|
21609
|
+
if (!reencoded.includes("\n")) return reencoded;
|
|
21610
|
+
const quote = reencoded[0];
|
|
21611
|
+
return quote + reencoded.slice(1, reencoded.endsWith(quote) ? -1 : void 0).replace(/\n/g, "\\n") + (reencoded.endsWith(quote) ? quote : "");
|
|
21612
|
+
}
|
|
21539
21613
|
//#endregion
|
|
21540
21614
|
//#region ../src/build_aarch64/build_range_node.ts
|
|
21541
21615
|
function build_range_node$1(node, status) {
|
|
@@ -21749,12 +21823,6 @@ function is_value_struct_type_node(node, status) {
|
|
|
21749
21823
|
const t = type_from_value_node$1(node);
|
|
21750
21824
|
return !!t?.name && !!status.structs.find((s) => s.name === t.name && !s.is_simple_type && !s.is_class);
|
|
21751
21825
|
}
|
|
21752
|
-
function escape_asciz(value) {
|
|
21753
|
-
const reencoded = reencode_hex_escapes(value);
|
|
21754
|
-
if (!reencoded.includes("\n")) return reencoded;
|
|
21755
|
-
const quote = reencoded[0];
|
|
21756
|
-
return quote + reencoded.slice(1, reencoded.endsWith(quote) ? -1 : void 0).replace(/\n/g, "\\n") + (reencoded.endsWith(quote) ? quote : "");
|
|
21757
|
-
}
|
|
21758
21826
|
/** Allocate an array on the stack with an 8-byte length prefix.
|
|
21759
21827
|
* Writes the length at the start and returns the offset of the first element. */
|
|
21760
21828
|
function alloc_array_with_prefix(status, length, element_size) {
|
|
@@ -22224,6 +22292,93 @@ function resolve_string_op(op, status) {
|
|
|
22224
22292
|
}
|
|
22225
22293
|
return null;
|
|
22226
22294
|
}
|
|
22295
|
+
const FLOAT_LITERAL_RE = /^(\+|-)?\d+\.\d+([eE](\+|-)?\d+)?$/;
|
|
22296
|
+
/**
|
|
22297
|
+
* Fold a module-level primitive `const`/`var` initializer to a literal string
|
|
22298
|
+
* when it is a compile-time constant: literal operands, references to other
|
|
22299
|
+
* foldable module-level consts, and arithmetic/bitwise operators over them.
|
|
22300
|
+
* Returns null when the value can only be computed at runtime (a call, a
|
|
22301
|
+
* field read, …), which a file-scope `.quad` initializer cannot express.
|
|
22302
|
+
*
|
|
22303
|
+
* Without this, `pub const N = 3 + 4` at module scope reserved
|
|
22304
|
+
* `N: .space 8` and emitted its store as dead code between functions, so
|
|
22305
|
+
* every read observed 0 (FOLLOWUP.md). Integer math is exact via BigInt so
|
|
22306
|
+
* 64-bit constants are not rounded through JS doubles; float arithmetic
|
|
22307
|
+
* falls back to JS doubles (which match Nomen's `float`).
|
|
22308
|
+
*/
|
|
22309
|
+
function fold_const_scalar(node, status, seen) {
|
|
22310
|
+
if (!node) return null;
|
|
22311
|
+
if (node.node_type === "grouped") return fold_const_scalar(node.value, status, seen);
|
|
22312
|
+
if (node.node_type === "value") {
|
|
22313
|
+
const raw = get_raw_value$1(node, status);
|
|
22314
|
+
if (is_int_literal(raw)) return to_decimal_string(raw);
|
|
22315
|
+
if (FLOAT_LITERAL_RE.test(raw)) return raw;
|
|
22316
|
+
if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(raw) && !seen.has(raw)) {
|
|
22317
|
+
const decl = find_global_const(raw, status);
|
|
22318
|
+
if (decl?.value) {
|
|
22319
|
+
seen.add(raw);
|
|
22320
|
+
const folded = fold_const_scalar(decl.value, status, seen);
|
|
22321
|
+
seen.delete(raw);
|
|
22322
|
+
return folded;
|
|
22323
|
+
}
|
|
22324
|
+
}
|
|
22325
|
+
return null;
|
|
22326
|
+
}
|
|
22327
|
+
if (node.node_type === "op") {
|
|
22328
|
+
const op = node;
|
|
22329
|
+
if (op.operator_func) return null;
|
|
22330
|
+
const left = fold_const_scalar(op.left_value, status, seen);
|
|
22331
|
+
if (left === null) return null;
|
|
22332
|
+
const right = fold_const_scalar(op.right_value, status, seen);
|
|
22333
|
+
if (right === null) return null;
|
|
22334
|
+
return apply_const_op(op.op, left, right);
|
|
22335
|
+
}
|
|
22336
|
+
return null;
|
|
22337
|
+
}
|
|
22338
|
+
/** Apply one arithmetic/bitwise operator to two folded literal strings.
|
|
22339
|
+
* Float operands use JS doubles; integral operands stay exact via BigInt. */
|
|
22340
|
+
function apply_const_op(op, left, right) {
|
|
22341
|
+
if (FLOAT_LITERAL_RE.test(left) || FLOAT_LITERAL_RE.test(right)) {
|
|
22342
|
+
const a = Number(left);
|
|
22343
|
+
const b = Number(right);
|
|
22344
|
+
if (!isFinite(a) || !isFinite(b)) return null;
|
|
22345
|
+
switch (op) {
|
|
22346
|
+
case "+": return String(a + b);
|
|
22347
|
+
case "-": return String(a - b);
|
|
22348
|
+
case "*": return String(a * b);
|
|
22349
|
+
case "/": return b === 0 ? null : String(a / b);
|
|
22350
|
+
default: return null;
|
|
22351
|
+
}
|
|
22352
|
+
}
|
|
22353
|
+
let a;
|
|
22354
|
+
let b;
|
|
22355
|
+
try {
|
|
22356
|
+
a = BigInt(left);
|
|
22357
|
+
b = BigInt(right);
|
|
22358
|
+
} catch {
|
|
22359
|
+
return null;
|
|
22360
|
+
}
|
|
22361
|
+
switch (op) {
|
|
22362
|
+
case "+": return (a + b).toString();
|
|
22363
|
+
case "-": return (a - b).toString();
|
|
22364
|
+
case "*": return (a * b).toString();
|
|
22365
|
+
case "/": return b === 0n ? null : (a / b).toString();
|
|
22366
|
+
case "%": return b === 0n ? null : (a % b).toString();
|
|
22367
|
+
case "<<": return (a << b).toString();
|
|
22368
|
+
case ">>": return (a >> b).toString();
|
|
22369
|
+
case "&": return (a & b).toString();
|
|
22370
|
+
case "|": return (a | b).toString();
|
|
22371
|
+
case "^": return (a ^ b).toString();
|
|
22372
|
+
default: return null;
|
|
22373
|
+
}
|
|
22374
|
+
}
|
|
22375
|
+
/** The root-scope `const` declaration named `name` (used to fold a const
|
|
22376
|
+
* reference through to its initializer). Mutable `var`s are deliberately
|
|
22377
|
+
* excluded: their value is established by module init, so baking in the
|
|
22378
|
+
* declaration's initializer could differ from the runtime value. */
|
|
22379
|
+
function find_global_const(name, status) {
|
|
22380
|
+
return (status.root.statements ?? []).find((s) => s.node_type === "declare" && s.declaration === "const" && s.name === name);
|
|
22381
|
+
}
|
|
22227
22382
|
/**
|
|
22228
22383
|
* Emit a declaration INITIALIZER expression. Under NIR-driven emission the
|
|
22229
22384
|
* lowered `NirExpr` rides in and descends through `emit_expr_from_nir` (the
|
|
@@ -22255,7 +22410,7 @@ function build_declaration_node$1(node, status, nir_init, nir_swap) {
|
|
|
22255
22410
|
const prev_heap = status.last_result_is_heap;
|
|
22256
22411
|
if (node.value?.node_type === "value") {
|
|
22257
22412
|
const inlined = status.top_level_consts?.get(node.value.value);
|
|
22258
|
-
if (inlined?.value) node.value = inlined.value;
|
|
22413
|
+
if (inlined?.value) node.value = fold_string_const(inlined, status.top_level_consts) ?? inlined.value;
|
|
22259
22414
|
}
|
|
22260
22415
|
function check_heap() {
|
|
22261
22416
|
if (status.last_result_is_heap) {
|
|
@@ -23197,7 +23352,15 @@ function build_declaration_node$1(node, status, nir_init, nir_swap) {
|
|
|
23197
23352
|
if (status.function_return_label) {
|
|
23198
23353
|
const offset = declare_slot_offset(status, node.name, size);
|
|
23199
23354
|
status.stack_offsets.set(node.name, offset);
|
|
23200
|
-
} else
|
|
23355
|
+
} else {
|
|
23356
|
+
const folded = fold_const_scalar(node.value, status, /* @__PURE__ */ new Set());
|
|
23357
|
+
if (folded !== null) {
|
|
23358
|
+
emit_data(status, `${node.name}: ${directive} ${folded}\n`);
|
|
23359
|
+
if (size % 4 !== 0) emit_data(status, `.p2align 2\n`);
|
|
23360
|
+
return;
|
|
23361
|
+
}
|
|
23362
|
+
emit_data(status, `${node.name}: .space ${size}\n`);
|
|
23363
|
+
}
|
|
23201
23364
|
if (node.type.name === "string" && !node.type.is_view && is_view_value(node.value, status)) {
|
|
23202
23365
|
emit_view_string_arg(node.value, status);
|
|
23203
23366
|
emit_view_materialize_owned(status);
|
|
@@ -35126,6 +35289,8 @@ function build_function_node(node, status) {
|
|
|
35126
35289
|
status.function_view_params = /* @__PURE__ */ new Set();
|
|
35127
35290
|
const old_return_type = status.function_return_type;
|
|
35128
35291
|
status.function_return_type = node.return_type;
|
|
35292
|
+
const old_variable_types = status.variable_types;
|
|
35293
|
+
status.variable_types = /* @__PURE__ */ new Map();
|
|
35129
35294
|
const old_nullable_ret_has = status.nullable_ret_has_param;
|
|
35130
35295
|
if (is_nullable_struct_type(node.return_type, status)) status.nullable_ret_has_param = "_ret_has";
|
|
35131
35296
|
else status.nullable_ret_has_param = void 0;
|
|
@@ -35181,6 +35346,7 @@ function build_function_node(node, status) {
|
|
|
35181
35346
|
status.function_variadic_params = old_variadic_params;
|
|
35182
35347
|
status.function_view_params = old_view_params;
|
|
35183
35348
|
status.function_return_type = old_return_type;
|
|
35349
|
+
status.variable_types = old_variable_types;
|
|
35184
35350
|
status.nullable_ret_has_param = old_nullable_ret_has;
|
|
35185
35351
|
status.current_function_name = old_function_name;
|
|
35186
35352
|
status.current_function = old_current_function;
|
|
@@ -36790,7 +36956,7 @@ function build_value_node$1(node, status) {
|
|
|
36790
36956
|
}
|
|
36791
36957
|
const inlined = status.top_level_consts?.get(value);
|
|
36792
36958
|
if (inlined?.value) {
|
|
36793
|
-
build_node$1(inlined.value, status);
|
|
36959
|
+
build_node$1(fold_string_const(inlined, status.top_level_consts) ?? inlined.value, status);
|
|
36794
36960
|
return;
|
|
36795
36961
|
}
|
|
36796
36962
|
if (node.is_enum_shorthand) {
|
|
@@ -37731,7 +37897,7 @@ function build_value_node(node, status) {
|
|
|
37731
37897
|
}
|
|
37732
37898
|
const inlined = status.top_level_consts?.get(original_value);
|
|
37733
37899
|
if (inlined?.value) {
|
|
37734
|
-
build_node(inlined.value, status);
|
|
37900
|
+
build_node(fold_string_const(inlined, status.top_level_consts) ?? inlined.value, status);
|
|
37735
37901
|
return;
|
|
37736
37902
|
}
|
|
37737
37903
|
if (node.is_enum_shorthand) {
|
|
@@ -42974,8 +43140,6 @@ function build_access_method(node, access_func, status) {
|
|
|
42974
43140
|
return true;
|
|
42975
43141
|
};
|
|
42976
43142
|
const overflow_count = Math.max(0, total_arg_slots - (8 - start_reg));
|
|
42977
|
-
let overflow_base = 0;
|
|
42978
|
-
if (overflow_count > 0) overflow_base = allocate_stack_space(status, overflow_count * 8, 16);
|
|
42979
43143
|
const lambda_arg_indices = /* @__PURE__ */ new Set();
|
|
42980
43144
|
for (let i = 0; i < access_func.params.length; i++) {
|
|
42981
43145
|
const p = access_func.params[i];
|
|
@@ -42986,21 +43150,17 @@ function build_access_method(node, access_func, status) {
|
|
|
42986
43150
|
lambda_arg_indices.add(i);
|
|
42987
43151
|
}
|
|
42988
43152
|
const lambda_arg_slots = [];
|
|
42989
|
-
const
|
|
42990
|
-
|
|
42991
|
-
|
|
42992
|
-
|
|
42993
|
-
|
|
42994
|
-
return
|
|
43153
|
+
const arg_builds_in_loop = (i) => {
|
|
43154
|
+
if (view_arg_set.has(i) || string_arg_set.has(i)) return true;
|
|
43155
|
+
if ((access_func.ref_param_indices ?? []).includes(i)) return true;
|
|
43156
|
+
const param_type = access_func.params[i].type?.name || "";
|
|
43157
|
+
if (is_struct_type(param_type, status) || is_enum_with_data_type(param_type, status)) return true;
|
|
43158
|
+
return !arg_deferrable(i);
|
|
42995
43159
|
};
|
|
42996
|
-
const
|
|
42997
|
-
|
|
42998
|
-
|
|
42999
|
-
const
|
|
43000
|
-
const param0_builds_in_loop = access_func.params.length > 0 && (param0_is_ref || is_struct_type(param0_type_name, status) || is_enum_with_data_type(param0_type_name, status) || !arg_deferrable(0));
|
|
43001
|
-
const static_arg0_needs_spill = start_reg === 0 && access_func.params.length > 0 && !param0_is_pair && param0_builds_in_loop;
|
|
43002
|
-
let static_arg0_spill = 0;
|
|
43003
|
-
if (static_arg0_needs_spill) static_arg0_spill = allocate_stack_space(status, 8, 8);
|
|
43160
|
+
const any_in_loop_arg = access_func.params.some((_, i) => arg_builds_in_loop(i));
|
|
43161
|
+
let arg_spill_base = 0;
|
|
43162
|
+
if (any_in_loop_arg) arg_spill_base = allocate_stack_space(status, total_arg_slots * 8, 16);
|
|
43163
|
+
const view_half_store = (j, half) => arg_spill_base + (arg_slot[j] + half) * 8;
|
|
43004
43164
|
const ref_class_param_reload = [];
|
|
43005
43165
|
const ref_class_sync_names = [];
|
|
43006
43166
|
for (let i = access_func.params.length - 1; i >= 0; i--) {
|
|
@@ -43070,31 +43230,20 @@ function build_access_method(node, access_func, status) {
|
|
|
43070
43230
|
lambda_arg_slots.push(dispose_slot);
|
|
43071
43231
|
}
|
|
43072
43232
|
}
|
|
43073
|
-
const slot = start_reg + arg_slot[i];
|
|
43074
43233
|
ensure_newline(status);
|
|
43075
|
-
|
|
43076
|
-
else {
|
|
43077
|
-
const reg = `x${slot}`;
|
|
43078
|
-
if (reg !== "x0") emit_asm(status, `mov ${reg}, x0\n`);
|
|
43079
|
-
else if (static_arg0_needs_spill) emit_asm(status, `str x0, [x29, #${static_arg0_spill}]\n`);
|
|
43080
|
-
}
|
|
43234
|
+
emit_asm(status, `str x0, [x29, #${arg_spill_base + arg_slot[i] * 8}]\n`);
|
|
43081
43235
|
}
|
|
43082
43236
|
deferred_args.sort((a, b) => b.slot - a.slot);
|
|
43083
43237
|
for (const d of deferred_args) {
|
|
43084
43238
|
build_operand(d.param, `x${start_reg + d.slot}`, status);
|
|
43085
43239
|
ensure_newline(status);
|
|
43086
43240
|
}
|
|
43087
|
-
|
|
43088
|
-
|
|
43089
|
-
|
|
43090
|
-
|
|
43091
|
-
|
|
43092
|
-
|
|
43093
|
-
}
|
|
43094
|
-
}
|
|
43095
|
-
if (static_arg0_needs_spill) {
|
|
43096
|
-
ensure_newline(status);
|
|
43097
|
-
emit_asm(status, `ldr x0, [x29, #${static_arg0_spill}]\n`);
|
|
43241
|
+
const deferred_slots = new Set(deferred_args.map((d) => start_reg + d.slot));
|
|
43242
|
+
for (let s = 0; s < total_arg_slots; s++) {
|
|
43243
|
+
const slot = start_reg + s;
|
|
43244
|
+
if (slot >= 8) continue;
|
|
43245
|
+
if (deferred_slots.has(slot)) continue;
|
|
43246
|
+
emit_asm(status, `ldr x${slot}, [x29, #${arg_spill_base + s * 8}]\n`);
|
|
43098
43247
|
}
|
|
43099
43248
|
ensure_newline(status);
|
|
43100
43249
|
if (receiver_is_string) emit_asm(status, frees_string_receiver ? `ldp x0, x1, [sp]\n` : `ldp x0, x1, [sp], #16\n`);
|
|
@@ -43104,8 +43253,9 @@ function build_access_method(node, access_func, status) {
|
|
|
43104
43253
|
if (overflow_count > 0) {
|
|
43105
43254
|
outgoing_size = Math.ceil(overflow_count * 8 / 16) * 16;
|
|
43106
43255
|
emit_asm(status, `sub sp, sp, #${outgoing_size}\n`);
|
|
43256
|
+
const overflow_first = 8 - start_reg;
|
|
43107
43257
|
for (let k = 0; k < overflow_count; k++) {
|
|
43108
|
-
emit_asm(status, `ldr x9, [x29, #${
|
|
43258
|
+
emit_asm(status, `ldr x9, [x29, #${arg_spill_base + (overflow_first + k) * 8}]\n`);
|
|
43109
43259
|
emit_asm(status, `str x9, [sp, #${k * 8}]\n`);
|
|
43110
43260
|
}
|
|
43111
43261
|
}
|
|
@@ -43171,7 +43321,7 @@ function build_access_method(node, access_func, status) {
|
|
|
43171
43321
|
emit_asm(status, `str x0, [sp, #-16]!\n`);
|
|
43172
43322
|
emit_asm(status, `str x1, [sp, #-16]!\n`);
|
|
43173
43323
|
emit_asm(status, `mov x0, x9\n`);
|
|
43174
|
-
|
|
43324
|
+
emit_free(status);
|
|
43175
43325
|
emit_asm(status, `ldr x1, [sp], #16\n`);
|
|
43176
43326
|
emit_asm(status, `ldr x0, [sp], #16\n`);
|
|
43177
43327
|
emit_asm(status, `add sp, sp, #16\n`);
|
|
@@ -44184,10 +44334,7 @@ function build(root, options = {}) {
|
|
|
44184
44334
|
}
|
|
44185
44335
|
if (status.strings && status.strings.size > 0) {
|
|
44186
44336
|
status.code += "\n";
|
|
44187
|
-
for (const [label, value] of status.strings) {
|
|
44188
|
-
const escaped = value.replace(/\n/g, "\\n");
|
|
44189
|
-
status.code += `${label}: .asciz ${escaped}\n`;
|
|
44190
|
-
}
|
|
44337
|
+
for (const [label, value] of status.strings) status.code += `${label}: .asciz ${escape_asciz(value)}\n`;
|
|
44191
44338
|
}
|
|
44192
44339
|
if (status.float_literals && status.float_literals.size > 0) {
|
|
44193
44340
|
status.code += "\n.p2align 2\n";
|
|
@@ -50012,16 +50159,22 @@ function must_use_type_display_name(en, type) {
|
|
|
50012
50159
|
*/
|
|
50013
50160
|
function gather_top_level_consts(block, status) {
|
|
50014
50161
|
const seen = /* @__PURE__ */ new Set();
|
|
50162
|
+
const candidates = [];
|
|
50015
50163
|
for (const child of block.statements) {
|
|
50016
50164
|
if (child.node_type !== "declare") continue;
|
|
50017
50165
|
const decl = child;
|
|
50018
50166
|
if (decl.declaration !== "const") continue;
|
|
50019
|
-
if (!decl.name
|
|
50020
|
-
if (decl.type.is_array) continue;
|
|
50167
|
+
if (!decl.name) continue;
|
|
50021
50168
|
if (seen.has(decl.name)) continue;
|
|
50022
50169
|
seen.add(decl.name);
|
|
50170
|
+
candidates.push(decl);
|
|
50171
|
+
}
|
|
50172
|
+
infer_const_decl_types(candidates, status);
|
|
50173
|
+
for (const decl of candidates) {
|
|
50174
|
+
if (!decl.type?.name) continue;
|
|
50175
|
+
if (decl.type.is_array) continue;
|
|
50023
50176
|
status.values.push({
|
|
50024
|
-
declaration:
|
|
50177
|
+
declaration: "const",
|
|
50025
50178
|
name: decl.name,
|
|
50026
50179
|
type: decl.type,
|
|
50027
50180
|
is_set: !!decl.value,
|
|
@@ -50031,6 +50184,60 @@ function gather_top_level_consts(block, status) {
|
|
|
50031
50184
|
}
|
|
50032
50185
|
}
|
|
50033
50186
|
/**
|
|
50187
|
+
* Give every root-level `const` a declared type BEFORE the statement walk,
|
|
50188
|
+
* so a const declared BELOW its first use resolves like a free function
|
|
50189
|
+
* (which hoists across the whole file). Parse can only infer the type when
|
|
50190
|
+
* the initializer is a bare literal; a composed chain (`const TAG = "<" +
|
|
50191
|
+
* TAG_NAME + ">"`, the allmark htmlPatterns shape) stayed typeless and its
|
|
50192
|
+
* use-above-declaration failed with "Unknown value".
|
|
50193
|
+
*
|
|
50194
|
+
* The inference iterates until nothing new is derivable, so a chain may
|
|
50195
|
+
* reference consts declared BELOW itself too. Recognized initializers:
|
|
50196
|
+
* literals, references to other (typed) consts, and arithmetic/concat
|
|
50197
|
+
* operations (the result type is the left operand's, mirroring
|
|
50198
|
+
* check_operation_node). Anything else (constructor calls, function calls)
|
|
50199
|
+
* keeps today's behavior: annotate the type or declare before use.
|
|
50200
|
+
*/
|
|
50201
|
+
function infer_const_decl_types(decls, status) {
|
|
50202
|
+
const known = /* @__PURE__ */ new Map();
|
|
50203
|
+
for (const decl of decls) if (decl.type?.name) known.set(decl.name, decl.type);
|
|
50204
|
+
let progress = true;
|
|
50205
|
+
while (progress) {
|
|
50206
|
+
progress = false;
|
|
50207
|
+
for (const decl of decls) {
|
|
50208
|
+
if (decl.type?.name) continue;
|
|
50209
|
+
const inferred = infer_const_expr_type(decl.value, known, status);
|
|
50210
|
+
if (!inferred) continue;
|
|
50211
|
+
decl.type = inferred;
|
|
50212
|
+
known.set(decl.name, inferred);
|
|
50213
|
+
progress = true;
|
|
50214
|
+
}
|
|
50215
|
+
}
|
|
50216
|
+
}
|
|
50217
|
+
function infer_const_expr_type(node, known, status) {
|
|
50218
|
+
if (!node) return void 0;
|
|
50219
|
+
if (node.node_type === "grouped") return infer_const_expr_type(node.value, known, status);
|
|
50220
|
+
if (node.node_type === "value") {
|
|
50221
|
+
const raw = node.value;
|
|
50222
|
+
if (typeof raw !== "string") return void 0;
|
|
50223
|
+
if (raw.startsWith("\"")) return new Type("string", true);
|
|
50224
|
+
if (raw === "true" || raw === "false") return new Type("bool", true);
|
|
50225
|
+
if (raw.startsWith("'") && raw.endsWith("'")) return new Type("char", true);
|
|
50226
|
+
if (is_int_literal(raw)) return new Type("int", true);
|
|
50227
|
+
if (/^(\+|-)*\d+.\d+([eE](\+|-)?\d+)?$/.test(raw)) return new Type("float", true);
|
|
50228
|
+
const declared = known.get(raw);
|
|
50229
|
+
if (declared) return declared;
|
|
50230
|
+
return;
|
|
50231
|
+
}
|
|
50232
|
+
if (node.node_type === "op") return infer_const_expr_type(node.left_value, known, status);
|
|
50233
|
+
if (node.node_type === "func_call") {
|
|
50234
|
+
const call = node;
|
|
50235
|
+
const target = status.structs.find((s) => s.name === call.name && !s.is_simple_type);
|
|
50236
|
+
if (target && target.type_params.length === 0) return new Type(target.name);
|
|
50237
|
+
return;
|
|
50238
|
+
}
|
|
50239
|
+
}
|
|
50240
|
+
/**
|
|
50034
50241
|
* A bare statement that constructs (or obtains) a class instance without
|
|
50035
50242
|
* binding it to a variable would leak: classes are heap-allocated and freed
|
|
50036
50243
|
* by the owning variable's scope-exit cleanup, so an unbound instance is
|
|
@@ -50368,6 +50575,7 @@ function clone_status(status) {
|
|
|
50368
50575
|
var_name_counter: status.var_name_counter,
|
|
50369
50576
|
type_params: status.type_params,
|
|
50370
50577
|
errors: status.errors,
|
|
50578
|
+
warnings: status.warnings,
|
|
50371
50579
|
buffer_caps: status.buffer_caps,
|
|
50372
50580
|
equal_lengths: status.equal_lengths?.slice(),
|
|
50373
50581
|
mutated_local_names: status.mutated_local_names,
|
|
@@ -52468,6 +52676,143 @@ function is_visible(declaring_scope, visibility, access_scope, stack, declaring_
|
|
|
52468
52676
|
return access_scope === declaring_scope;
|
|
52469
52677
|
}
|
|
52470
52678
|
//#endregion
|
|
52679
|
+
//#region ../src/check/utils/regex_pattern_lint.ts
|
|
52680
|
+
/**
|
|
52681
|
+
* Compile-time lint for Regex pattern literals (FOLLOWUP "Regex pattern
|
|
52682
|
+
* escapes").
|
|
52683
|
+
*
|
|
52684
|
+
* The Regex engine (core/System/Text/Regex.nm) recognizes only the
|
|
52685
|
+
* shorthands (`\d \D \w \W \s \S`), backreferences (`\1`-`\9`), the control
|
|
52686
|
+
* escapes (`\n \r \t`), and escaped metacharacters. Any OTHER engine escape
|
|
52687
|
+
— most notably a typo like `\z` — silently matches a literal letter. When a
|
|
52688
|
+
* Regex entry point's pattern argument is a static string literal, the check
|
|
52689
|
+
* can flag those as probable typos; dynamic runtime patterns can't be
|
|
52690
|
+
* validated this way.
|
|
52691
|
+
*
|
|
52692
|
+
* The literal arrives RAW (quotes included, Nomen escapes unresolved), so it
|
|
52693
|
+
* must first be decoded to the engine-visible bytes: a Nomen `"\n"` is a real
|
|
52694
|
+
* LF byte the engine treats as a literal, while `"\n"` reaches the engine as
|
|
52695
|
+
* a backslash + 'n' escape. Only the second spelling can carry a typo.
|
|
52696
|
+
*/
|
|
52697
|
+
/** Decode a raw string-literal token (quotes included) to its engine-visible
|
|
52698
|
+
* bytes, resolving Nomen's own string escapes. Mirrors the pair-counting of
|
|
52699
|
+
* string_literal_length and the decode rules of decode_char_literal. */
|
|
52700
|
+
function decode_string_literal_bytes(raw) {
|
|
52701
|
+
const bytes = [];
|
|
52702
|
+
let i = 1;
|
|
52703
|
+
const end = raw.endsWith("\"") ? raw.length - 1 : raw.length;
|
|
52704
|
+
while (i < end) {
|
|
52705
|
+
if (raw[i] !== "\\") {
|
|
52706
|
+
const cp = raw.codePointAt(i) ?? 0;
|
|
52707
|
+
if (cp < 128) {
|
|
52708
|
+
bytes.push(cp);
|
|
52709
|
+
i += 1;
|
|
52710
|
+
} else if (cp < 2048) {
|
|
52711
|
+
bytes.push(192 | cp >> 6, 128 | cp & 63);
|
|
52712
|
+
i += 1;
|
|
52713
|
+
} else if (cp < 65536) {
|
|
52714
|
+
bytes.push(224 | cp >> 12, 128 | cp >> 6 & 63, 128 | cp & 63);
|
|
52715
|
+
i += 1;
|
|
52716
|
+
} else {
|
|
52717
|
+
bytes.push(240 | cp >> 18, 128 | cp >> 12 & 63, 128 | cp >> 6 & 63, 128 | cp & 63);
|
|
52718
|
+
i += 2;
|
|
52719
|
+
}
|
|
52720
|
+
continue;
|
|
52721
|
+
}
|
|
52722
|
+
const next = raw[i + 1];
|
|
52723
|
+
if (next === void 0) break;
|
|
52724
|
+
if (next === "x") {
|
|
52725
|
+
let j = i + 2;
|
|
52726
|
+
let value = 0;
|
|
52727
|
+
let digits = 0;
|
|
52728
|
+
while (j < end && digits < 2 && is_hex_digit(raw[j])) {
|
|
52729
|
+
value = value * 16 + hex_value(raw[j]);
|
|
52730
|
+
j += 1;
|
|
52731
|
+
digits += 1;
|
|
52732
|
+
}
|
|
52733
|
+
if (digits > 0) {
|
|
52734
|
+
bytes.push(value & 255);
|
|
52735
|
+
i = j;
|
|
52736
|
+
continue;
|
|
52737
|
+
}
|
|
52738
|
+
i += 2;
|
|
52739
|
+
continue;
|
|
52740
|
+
}
|
|
52741
|
+
if (next >= "0" && next <= "7") {
|
|
52742
|
+
let j = i + 1;
|
|
52743
|
+
let value = 0;
|
|
52744
|
+
let digits = 0;
|
|
52745
|
+
while (j < end && digits < 3 && raw[j] >= "0" && raw[j] <= "7") {
|
|
52746
|
+
value = value * 8 + (raw[j].charCodeAt(0) - 48);
|
|
52747
|
+
j += 1;
|
|
52748
|
+
digits += 1;
|
|
52749
|
+
}
|
|
52750
|
+
bytes.push(value & 255);
|
|
52751
|
+
i = j;
|
|
52752
|
+
continue;
|
|
52753
|
+
}
|
|
52754
|
+
switch (next) {
|
|
52755
|
+
case "\\":
|
|
52756
|
+
bytes.push(92);
|
|
52757
|
+
break;
|
|
52758
|
+
case "n":
|
|
52759
|
+
bytes.push(10);
|
|
52760
|
+
break;
|
|
52761
|
+
case "t":
|
|
52762
|
+
bytes.push(9);
|
|
52763
|
+
break;
|
|
52764
|
+
case "r":
|
|
52765
|
+
bytes.push(13);
|
|
52766
|
+
break;
|
|
52767
|
+
case "0":
|
|
52768
|
+
bytes.push(0);
|
|
52769
|
+
break;
|
|
52770
|
+
case "\"":
|
|
52771
|
+
bytes.push(34);
|
|
52772
|
+
break;
|
|
52773
|
+
case "'":
|
|
52774
|
+
bytes.push(39);
|
|
52775
|
+
break;
|
|
52776
|
+
default: bytes.push(next.charCodeAt(0));
|
|
52777
|
+
}
|
|
52778
|
+
i += 2;
|
|
52779
|
+
}
|
|
52780
|
+
return bytes;
|
|
52781
|
+
}
|
|
52782
|
+
function is_hex_digit(c) {
|
|
52783
|
+
return c >= "0" && c <= "9" || c >= "a" && c <= "f" || c >= "A" && c <= "F";
|
|
52784
|
+
}
|
|
52785
|
+
function hex_value(c) {
|
|
52786
|
+
if (c <= "9") return c.charCodeAt(0) - 48;
|
|
52787
|
+
if (c <= "F") return c.charCodeAt(0) - 55;
|
|
52788
|
+
return c.charCodeAt(0) - 87;
|
|
52789
|
+
}
|
|
52790
|
+
function is_ascii_letter(code) {
|
|
52791
|
+
return code >= 65 && code <= 90 || code >= 97 && code <= 122;
|
|
52792
|
+
}
|
|
52793
|
+
/** Scan the decoded pattern bytes for escapes outside the engine's known set
|
|
52794
|
+
* (`\d \D \w \W \s \S`, `\1`-`\9`, `\n \r \t`, escaped punctuation) and
|
|
52795
|
+
* return one warning message per probable typo. */
|
|
52796
|
+
function lint_regex_pattern(raw) {
|
|
52797
|
+
const bytes = decode_string_literal_bytes(raw);
|
|
52798
|
+
const messages = [];
|
|
52799
|
+
let i = 0;
|
|
52800
|
+
while (i < bytes.length) {
|
|
52801
|
+
if (bytes[i] !== 92) {
|
|
52802
|
+
i += 1;
|
|
52803
|
+
continue;
|
|
52804
|
+
}
|
|
52805
|
+
const escaped = bytes[i + 1];
|
|
52806
|
+
if (escaped === void 0) break;
|
|
52807
|
+
if (!(escaped === 100 || escaped === 68 || escaped === 119 || escaped === 87 || escaped === 115 || escaped === 83 || escaped === 110 || escaped === 114 || escaped === 116 || escaped >= 49 && escaped <= 57) && is_ascii_letter(escaped)) {
|
|
52808
|
+
const letter = String.fromCharCode(escaped);
|
|
52809
|
+
messages.push(`Regex pattern: unsupported escape '\\${letter}' matches a literal '${letter}' — supported escapes are \\d \\D \\w \\W \\s \\S \\1-\\9 \\n \\r \\t and escaped punctuation`);
|
|
52810
|
+
}
|
|
52811
|
+
i += 2;
|
|
52812
|
+
}
|
|
52813
|
+
return messages;
|
|
52814
|
+
}
|
|
52815
|
+
//#endregion
|
|
52471
52816
|
//#region ../src/check/utils/string_mutation_scan.ts
|
|
52472
52817
|
/**
|
|
52473
52818
|
* Interprocedural no-mutation scan for borrow-position `to_string()` elision
|
|
@@ -52861,6 +53206,7 @@ function is_inside_core_method(status) {
|
|
|
52861
53206
|
}
|
|
52862
53207
|
function check_function_call(node, status, func, target_type, self_value, self_path) {
|
|
52863
53208
|
set_resolved_function(node, func);
|
|
53209
|
+
lint_regex_entry_pattern(node, func, status);
|
|
52864
53210
|
const access_scope = status.stack.at(-1);
|
|
52865
53211
|
if (func.name === "#init") {
|
|
52866
53212
|
const struct_name = target_type?.name || func.return_type.name;
|
|
@@ -53372,6 +53718,59 @@ function receiver_is_const(target_type, self_value, status) {
|
|
|
53372
53718
|
const binding = status.values.findLast((v) => v.name === self_value);
|
|
53373
53719
|
return !!binding && binding.declaration === "const" && !binding.type.is_ref;
|
|
53374
53720
|
}
|
|
53721
|
+
/**
|
|
53722
|
+
* Regex entry points whose FIRST parameter is the pattern. When that argument
|
|
53723
|
+
* is a static string literal, flag engine escapes outside the known set as
|
|
53724
|
+
* probable typos (see regex_pattern_lint.ts) — a dynamic runtime pattern
|
|
53725
|
+
* can't be validated this way.
|
|
53726
|
+
*/
|
|
53727
|
+
const REGEX_PATTERN_ENTRY_POINTS = /* @__PURE__ */ new Set([
|
|
53728
|
+
"test",
|
|
53729
|
+
"match",
|
|
53730
|
+
"count",
|
|
53731
|
+
"find",
|
|
53732
|
+
"replace_all",
|
|
53733
|
+
"captures",
|
|
53734
|
+
"test_ci",
|
|
53735
|
+
"match_ci",
|
|
53736
|
+
"find_ci",
|
|
53737
|
+
"captures_ci",
|
|
53738
|
+
"replace_all_ci"
|
|
53739
|
+
]);
|
|
53740
|
+
/**
|
|
53741
|
+
* Lint a static string-literal pattern passed to a Regex entry point. Only
|
|
53742
|
+
* the library's own `Regex` struct qualifies (a user struct of the same name
|
|
53743
|
+
* with a same-named method is left alone), and only when the first argument
|
|
53744
|
+
* is a literal — anything else is a runtime value.
|
|
53745
|
+
*/
|
|
53746
|
+
function lint_regex_entry_pattern(node, func, status) {
|
|
53747
|
+
if (!is_library_regex_func(func, status)) return;
|
|
53748
|
+
if (!REGEX_PATTERN_ENTRY_POINTS.has(func.name)) return;
|
|
53749
|
+
const pattern = node.params[0];
|
|
53750
|
+
if (!pattern || pattern.node_type !== "value") return;
|
|
53751
|
+
const raw = pattern.value;
|
|
53752
|
+
if (!raw.startsWith("\"")) return;
|
|
53753
|
+
if (!status.warnings) status.warnings = [];
|
|
53754
|
+
for (const message of lint_regex_pattern(raw)) status.warnings.push({
|
|
53755
|
+
message,
|
|
53756
|
+
start: pattern.start,
|
|
53757
|
+
line: 0,
|
|
53758
|
+
column: 0
|
|
53759
|
+
});
|
|
53760
|
+
}
|
|
53761
|
+
/**
|
|
53762
|
+
* Whether `func` is a method of the library's `Regex` struct. Two paths: the
|
|
53763
|
+
* method's enclosing struct is stamped on it for calls checked after the
|
|
53764
|
+
* struct gather (library bodies, later files), and for user call sites —
|
|
53765
|
+
* which are checked BEFORE the gather stamps `func.scope` — the callee is
|
|
53766
|
+
* matched against the gathered library struct's own methods.
|
|
53767
|
+
*/
|
|
53768
|
+
function is_library_regex_func(func, status) {
|
|
53769
|
+
const scope = func.scope;
|
|
53770
|
+
if (scope && scope.node_type === "struct" && scope.is_library && scope.name === "Regex") return true;
|
|
53771
|
+
const regex_struct = status.structs.find((s) => s.is_library && s.name === "Regex");
|
|
53772
|
+
return !!regex_struct && regex_struct.functions.includes(func);
|
|
53773
|
+
}
|
|
53375
53774
|
//#endregion
|
|
53376
53775
|
//#region ../src/check/check_access_node.ts
|
|
53377
53776
|
function check_access_node(node, status) {
|
|
@@ -55547,7 +55946,13 @@ function check_return_node(ret, status) {
|
|
|
55547
55946
|
} else if (!func.is_arrow_body) {
|
|
55548
55947
|
add_error(status, `Function returns a value but has no 'out' return type`, ret.start);
|
|
55549
55948
|
func.return_type = ret.type;
|
|
55550
|
-
} else
|
|
55949
|
+
} else {
|
|
55950
|
+
func.return_type = ret.type;
|
|
55951
|
+
if (!ret.type?.name) {
|
|
55952
|
+
func.return_type = new Type("void");
|
|
55953
|
+
ret.type = new Type("void");
|
|
55954
|
+
}
|
|
55955
|
+
}
|
|
55551
55956
|
}
|
|
55552
55957
|
}
|
|
55553
55958
|
//#endregion
|
|
@@ -58515,7 +58920,24 @@ function resolve_linked_types(source, library, file_path) {
|
|
|
58515
58920
|
}
|
|
58516
58921
|
const user_declared_funcs = /* @__PURE__ */ new Set();
|
|
58517
58922
|
for (let i = 0; i < tokens.length - 1; i++) if (tokens[i].value === "func" && /^\w+$/.test(tokens[i + 1].value)) user_declared_funcs.add(tokens[i + 1].value);
|
|
58518
|
-
|
|
58923
|
+
const import_tokens = /* @__PURE__ */ new Set();
|
|
58924
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
58925
|
+
if (tokens[i].value !== "import") continue;
|
|
58926
|
+
import_tokens.add(i);
|
|
58927
|
+
let j = i + 1;
|
|
58928
|
+
if (j < tokens.length && /^\w+$/.test(tokens[j].value)) {
|
|
58929
|
+
import_tokens.add(j);
|
|
58930
|
+
j += 1;
|
|
58931
|
+
while (j + 1 < tokens.length && tokens[j].value === "::" && /^\w+$/.test(tokens[j + 1].value)) {
|
|
58932
|
+
import_tokens.add(j);
|
|
58933
|
+
import_tokens.add(j + 1);
|
|
58934
|
+
j += 2;
|
|
58935
|
+
}
|
|
58936
|
+
}
|
|
58937
|
+
}
|
|
58938
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
58939
|
+
if (import_tokens.has(i)) continue;
|
|
58940
|
+
const token = tokens[i];
|
|
58519
58941
|
if (user_defined.has(token.value)) continue;
|
|
58520
58942
|
if (library.types.has(token.value) && !BASE_TYPES.includes(token.value)) needed.add(token.value);
|
|
58521
58943
|
else if (library.functions.has(token.value) && !user_declared_funcs.has(token.value)) needed.add(token.value);
|
|
@@ -59323,6 +59745,7 @@ function run_test_file(entry_path, lib_path, arch, audit = false, audit_runtime)
|
|
|
59323
59745
|
const parsed = parse(input + "\n" + harness, library, resolved);
|
|
59324
59746
|
if (parsed.errors.length) {
|
|
59325
59747
|
result.ok = false;
|
|
59748
|
+
result.phase = "parse";
|
|
59326
59749
|
result.crashed = parsed.errors.map((e) => `${e.message} (${e.line ?? "?"}:${e.column ?? "?"})`).join("\n");
|
|
59327
59750
|
result.ms = performance.now() - start;
|
|
59328
59751
|
return result;
|
|
@@ -59333,6 +59756,7 @@ function run_test_file(entry_path, lib_path, arch, audit = false, audit_runtime)
|
|
|
59333
59756
|
});
|
|
59334
59757
|
if (buildResult.errors && buildResult.errors.length) {
|
|
59335
59758
|
result.ok = false;
|
|
59759
|
+
result.phase = "build";
|
|
59336
59760
|
result.crashed = buildResult.errors.map((e) => `${e.message} (${e.line ?? "?"}:${e.column ?? "?"})`).join("\n");
|
|
59337
59761
|
result.ms = performance.now() - start;
|
|
59338
59762
|
return result;
|
|
@@ -59344,6 +59768,7 @@ function run_test_file(entry_path, lib_path, arch, audit = false, audit_runtime)
|
|
|
59344
59768
|
const runtime_src = audit_runtime ? path.resolve(audit_runtime) : find_audit_runtime(path.dirname(resolved));
|
|
59345
59769
|
if (!runtime_src || !fs.existsSync(runtime_src)) {
|
|
59346
59770
|
result.ok = false;
|
|
59771
|
+
result.phase = "setup";
|
|
59347
59772
|
result.crashed = "Audit enabled but audit_runtime.c was not found. Pass --audit-runtime <path>.";
|
|
59348
59773
|
result.ms = performance.now() - start;
|
|
59349
59774
|
return result;
|
|
@@ -59356,7 +59781,8 @@ function run_test_file(entry_path, lib_path, arch, audit = false, audit_runtime)
|
|
|
59356
59781
|
audit_obj
|
|
59357
59782
|
]);
|
|
59358
59783
|
}
|
|
59359
|
-
const
|
|
59784
|
+
const platform = default_platform();
|
|
59785
|
+
const ext = arch === "aarch64" ? ".s" : platform === "macos" || platform === "ios" ? ".m" : ".c";
|
|
59360
59786
|
const codefile = path.join(buildDir, path.basename(entry_path, ".nm") + ext);
|
|
59361
59787
|
const outfile = path.join(buildDir, path.basename(entry_path, ".nm"));
|
|
59362
59788
|
fs.writeFileSync(path.join(buildDir, "main.h"), buildResult.headers ?? "");
|
|
@@ -59367,6 +59793,7 @@ function run_test_file(entry_path, lib_path, arch, audit = false, audit_runtime)
|
|
|
59367
59793
|
codefile
|
|
59368
59794
|
];
|
|
59369
59795
|
if (audit_obj) link_args.push(audit_obj);
|
|
59796
|
+
if (platform === "macos" || platform === "ios") link_args.push("-framework", "CoreGraphics", "-framework", "Foundation", "-framework", "AppKit", "-lobjc");
|
|
59370
59797
|
try {
|
|
59371
59798
|
execFileSync("clang", link_args, {
|
|
59372
59799
|
encoding: "utf8",
|
|
@@ -59379,6 +59806,7 @@ function run_test_file(entry_path, lib_path, arch, audit = false, audit_runtime)
|
|
|
59379
59806
|
} catch (err) {
|
|
59380
59807
|
const stderr = err.stderr ? err.stderr.toString() : err.message ?? "";
|
|
59381
59808
|
result.ok = false;
|
|
59809
|
+
result.phase = "link";
|
|
59382
59810
|
result.crashed = `link failed: ${stderr.trim() || "clang error"}`;
|
|
59383
59811
|
result.ms = performance.now() - start;
|
|
59384
59812
|
return result;
|
|
@@ -59407,6 +59835,7 @@ function run_test_file(entry_path, lib_path, arch, audit = false, audit_runtime)
|
|
|
59407
59835
|
result.benches = records.benches;
|
|
59408
59836
|
result.other = records.other;
|
|
59409
59837
|
result.crashed = crashed;
|
|
59838
|
+
if (crashed) result.phase = "run";
|
|
59410
59839
|
result.ok = !(result.fails.length > 0 || result.tests.some((t) => t.failed > 0)) && crashed === void 0;
|
|
59411
59840
|
result.ms = performance.now() - start;
|
|
59412
59841
|
return result;
|
|
@@ -59434,7 +59863,8 @@ const C = {
|
|
|
59434
59863
|
function report_file(result) {
|
|
59435
59864
|
const rel = path.relative(process.cwd(), result.file);
|
|
59436
59865
|
if (result.crashed && result.tests.length === 0 && result.fails.length === 0) {
|
|
59437
|
-
|
|
59866
|
+
const label = result.phase === "run" ? "(crashed before records)" : result.phase === "link" ? "(link failed)" : result.phase === "setup" ? "(setup failed)" : "(failed to build)";
|
|
59867
|
+
console.log(` ${C.red("✗")} ${rel} ${C.red(label)}`);
|
|
59438
59868
|
console.log(C.red(result.crashed));
|
|
59439
59869
|
return;
|
|
59440
59870
|
}
|