nomen-lang 0.0.18 → 0.0.19
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/Array.nm +1 -1
- package/dist/index.mjs +80 -20
- package/package.json +1 -1
package/core/System/Array.nm
CHANGED
|
@@ -30,7 +30,7 @@ pub struct Array<T>: Viewable {
|
|
|
30
30
|
```
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
pub func at = (self, int index: index >= 0 && index < self.length, out T) {
|
|
33
|
+
pub inline func at = (self, int index: index >= 0 && index < self.length, out T) {
|
|
34
34
|
```
|
|
35
35
|
#arch: c
|
|
36
36
|
T* _data = (T*)((char*)self + sizeof(*self));
|
package/dist/index.mjs
CHANGED
|
@@ -2750,6 +2750,20 @@ function is_container_borrow_access(node) {
|
|
|
2750
2750
|
return !!node && node.node_type === "access" && node.access?.node_type === "access_func" && !node.access.owned_return && is_container_borrow_accessor_name(node.access.name);
|
|
2751
2751
|
}
|
|
2752
2752
|
/**
|
|
2753
|
+
* Whether `target` (the receiver of a `.to_string()` call) is a `view string`
|
|
2754
|
+
* VALUE — a named view local/param (the checker stamps variable references
|
|
2755
|
+
* with the declared type, and substitute_type preserves `is_view` across
|
|
2756
|
+
* monomorphization) or an inline `.slice(...)` chain (a slice call always
|
|
2757
|
+
* produces a view, even when its cached type lost the modifier). Such a call
|
|
2758
|
+
* MATERIALIZES a fresh owned heap copy (malloc + memcpy), unlike
|
|
2759
|
+
* `to_string` on an owned string (the `string_to_string` identity).
|
|
2760
|
+
*/
|
|
2761
|
+
function is_view_materialization_target(target) {
|
|
2762
|
+
if (!target || typeof target !== "object") return false;
|
|
2763
|
+
if (target.type?.is_view) return true;
|
|
2764
|
+
return target.node_type === "access" && target.access?.node_type === "access_func" && !target.access.owned_return && target.access.name === "slice";
|
|
2765
|
+
}
|
|
2766
|
+
/**
|
|
2753
2767
|
* Whether a function has any `return <expr>` statement in its body (used by
|
|
2754
2768
|
* the C backend's gather, which registers every string-returning function
|
|
2755
2769
|
* that actually returns — the backend strdup's borrows at the return site,
|
|
@@ -2858,6 +2872,7 @@ function value_is_owned_string(v, table, visiting, borrow_names, enclosing_fn) {
|
|
|
2858
2872
|
if (mangled.startsWith("_string_interpolate_")) return true;
|
|
2859
2873
|
if (mangled.endsWith("_to_string") && mangled !== "string_to_string") return true;
|
|
2860
2874
|
if (raw === "to_string" && v.target?.type?.name && v.target.type.name !== "string") return true;
|
|
2875
|
+
if (raw === "to_string" && is_view_materialization_target(v.target)) return true;
|
|
2861
2876
|
if (!v.access.owned_return && is_container_borrow_accessor_name(raw)) return !is_call_site_borrow_accessor(enclosing_fn);
|
|
2862
2877
|
const resolved = method_call_returns_owned(v, table, visiting);
|
|
2863
2878
|
if (resolved !== void 0) return resolved;
|
|
@@ -9569,6 +9584,7 @@ function is_owned_heap_temp$1(node, status) {
|
|
|
9569
9584
|
if (mangled.startsWith("_string_interpolate_")) return true;
|
|
9570
9585
|
if (mangled.endsWith("_to_string") && mangled !== "string_to_string") return true;
|
|
9571
9586
|
if (raw_name === "to_string" && target_type_name && target_type_name !== "string") return true;
|
|
9587
|
+
if (raw_name === "to_string" && status && node.node_type === "access" && is_view_value$1(node.target, status)) return true;
|
|
9572
9588
|
const heap_set = status?.heap_returning_functions;
|
|
9573
9589
|
if (heap_set?.has(mangled)) return true;
|
|
9574
9590
|
if (heap_set && target_value && heap_set.has(`${target_value}_${raw_name}`)) return true;
|
|
@@ -12237,10 +12253,17 @@ function build_naked_inline(struct_node, func, status) {
|
|
|
12237
12253
|
let asm = extract_aarch64_asm(func, status.platform);
|
|
12238
12254
|
const standalone_return_label = `.return_${struct_node.name}_${func.name.replace(/#/g, "")}`;
|
|
12239
12255
|
asm = asm.replaceAll(`b ${standalone_return_label}`, "");
|
|
12240
|
-
|
|
12256
|
+
const x19_reads = count_x19_reads(asm);
|
|
12257
|
+
let prologue = "";
|
|
12258
|
+
let epilogue = "";
|
|
12259
|
+
if (x19_reads === 1) asm = asm.replace(/\bx19\b/g, "x0");
|
|
12260
|
+
else if (x19_reads > 1) {
|
|
12261
|
+
prologue = `str x19, [sp, #-16]!\nmov x19, x0\n`;
|
|
12262
|
+
epilogue = `ldr x19, [sp], #16\n`;
|
|
12263
|
+
}
|
|
12241
12264
|
const site = inline_counter++;
|
|
12242
|
-
asm = asm.replace(/(\.L[A-Za-z0-9_]+)/g, `$
|
|
12243
|
-
status.code += asm + "\n";
|
|
12265
|
+
asm = asm.replace(/(\.L[A-Za-z0-9_]+)/g, `$1__ni${site}`);
|
|
12266
|
+
status.code += prologue + asm + "\n" + epilogue;
|
|
12244
12267
|
}
|
|
12245
12268
|
function build_inline_method(struct_node, func, status) {
|
|
12246
12269
|
if (emit_owning_buffer_inline_aarch64(struct_node, func.name, status)) return;
|
|
@@ -12688,6 +12711,14 @@ function emit_string_length$1(target, status) {
|
|
|
12688
12711
|
* struct element, with x0 = temp address)
|
|
12689
12712
|
* v.to_string() → malloc(len+1); memcpy; null-terminate; owned copy in x0
|
|
12690
12713
|
* (string views only)
|
|
12714
|
+
* The receiver is either a NAMED view local/param (pair in its two stack
|
|
12715
|
+
* slots) or an INLINE view-producing expression such as
|
|
12716
|
+
* `text.slice(start, end).to_string()` — the expression leaves the pair in
|
|
12717
|
+
* x0/x1, which is spilled to scratch slots first. Without this, the inline
|
|
12718
|
+
* chain falls through to struct-method dispatch and resolves to
|
|
12719
|
+
* `string_to_string` (an identity `mov x0, x19`), handing consumers the raw
|
|
12720
|
+
* slice pointer — not NUL-terminated at len — and strlen-based readers run
|
|
12721
|
+
* past the slice.
|
|
12691
12722
|
* Returns true if handled (caller skips struct-method dispatch).
|
|
12692
12723
|
*/
|
|
12693
12724
|
function build_view_op(node, access_func, status) {
|
|
@@ -12696,11 +12727,19 @@ function build_view_op(node, access_func, status) {
|
|
|
12696
12727
|
const vt = status.variable_types?.get(node.target.value);
|
|
12697
12728
|
if (vt?.is_view) t = vt;
|
|
12698
12729
|
}
|
|
12699
|
-
if (!t?.is_view) return false;
|
|
12700
|
-
|
|
12701
|
-
|
|
12702
|
-
if (base === void 0)
|
|
12703
|
-
|
|
12730
|
+
if (!t?.is_view && !is_view_value$1(node.target, status)) return false;
|
|
12731
|
+
let base;
|
|
12732
|
+
if (node.target.node_type === "value") base = status.stack_offsets?.get(node.target.value);
|
|
12733
|
+
if (base === void 0) {
|
|
12734
|
+
build_node$1(node.target, status);
|
|
12735
|
+
if (!status.code.endsWith("\n")) status.code += "\n";
|
|
12736
|
+
const temp_base = allocate_stack_space(status, 16, 16);
|
|
12737
|
+
status.code += `str x0, [x29, #${temp_base}]\n`;
|
|
12738
|
+
status.code += `str x1, [x29, #${temp_base + 8}]\n`;
|
|
12739
|
+
base = temp_base;
|
|
12740
|
+
}
|
|
12741
|
+
const view_elem = t?.name || "string";
|
|
12742
|
+
const elem_name = view_elem === "string" ? "char" : view_elem;
|
|
12704
12743
|
if (access_func.name === "at" && access_func.params.length === 1) {
|
|
12705
12744
|
build_node$1(access_func.params[0], status);
|
|
12706
12745
|
if (!status.code.endsWith("\n")) status.code += "\n";
|
|
@@ -12726,7 +12765,7 @@ function build_view_op(node, access_func, status) {
|
|
|
12726
12765
|
else status.code += `ldr x0, [x0, x1, lsl #3]\n`;
|
|
12727
12766
|
return true;
|
|
12728
12767
|
}
|
|
12729
|
-
if (access_func.name === "to_string" &&
|
|
12768
|
+
if (access_func.name === "to_string" && view_elem === "string") {
|
|
12730
12769
|
status.code += `ldr x0, [x29, #${base}]\n`;
|
|
12731
12770
|
status.code += `ldr x1, [x29, #${base + 8}]\n`;
|
|
12732
12771
|
emit_view_materialize_owned(status);
|
|
@@ -25034,6 +25073,29 @@ function clone_type(t) {
|
|
|
25034
25073
|
c.type_args = t.type_args;
|
|
25035
25074
|
return c;
|
|
25036
25075
|
}
|
|
25076
|
+
/**
|
|
25077
|
+
* Strip parallel-length equality clauses (`a.length == b.length`) from every
|
|
25078
|
+
* parameter's constraint of `func` at SIGNATURE-GATHER time — before any call
|
|
25079
|
+
* site can observe the signature, regardless of declaration order. A
|
|
25080
|
+
* forward-referenced callee must not hand its caller a clause no call site
|
|
25081
|
+
* could ever prove; the clause becomes an assumed equality for the callee's
|
|
25082
|
+
* own body instead (stashed on the param, seeded into scope when its params
|
|
25083
|
+
* are checked). Idempotent: a constraint already stripped has no clauses
|
|
25084
|
+
* left to extract. `check_function_node` re-runs the same extraction at
|
|
25085
|
+
* registration for function clones that never pass through a gather pass
|
|
25086
|
+
* (generic monomorphizations).
|
|
25087
|
+
*/
|
|
25088
|
+
function strip_param_length_equalities(func) {
|
|
25089
|
+
const param_names = new Set(func.params.map((p) => p.name));
|
|
25090
|
+
for (const param of func.params) {
|
|
25091
|
+
if (!param.constraint) continue;
|
|
25092
|
+
const { constraint, equalities } = extract_length_equalities_at_registration(param.constraint, param.name, param_names);
|
|
25093
|
+
if (equalities.length) {
|
|
25094
|
+
param.constraint = constraint;
|
|
25095
|
+
param.stripped_length_equalities = equalities;
|
|
25096
|
+
}
|
|
25097
|
+
}
|
|
25098
|
+
}
|
|
25037
25099
|
function gather_structs(block, status) {
|
|
25038
25100
|
const names_in_block = {
|
|
25039
25101
|
structs: /* @__PURE__ */ new Set(),
|
|
@@ -25050,6 +25112,7 @@ function gather_structs(block, status) {
|
|
|
25050
25112
|
names_in_block.structs.add(struct.name);
|
|
25051
25113
|
struct.scope = status.stack.at(-1) || block;
|
|
25052
25114
|
struct.is_generic = struct.type_params.length > 0;
|
|
25115
|
+
for (const func of struct.functions) strip_param_length_equalities(func);
|
|
25053
25116
|
status.types.push(struct.name);
|
|
25054
25117
|
status.structs.push(struct);
|
|
25055
25118
|
}
|
|
@@ -25062,6 +25125,7 @@ function gather_structs(block, status) {
|
|
|
25062
25125
|
names_in_block.traits.add(trait.name);
|
|
25063
25126
|
status.types.push(trait.name);
|
|
25064
25127
|
status.traits.push(trait);
|
|
25128
|
+
for (const func of trait.functions) strip_param_length_equalities(func);
|
|
25065
25129
|
}
|
|
25066
25130
|
break;
|
|
25067
25131
|
}
|
|
@@ -25073,15 +25137,7 @@ function gather_structs(block, status) {
|
|
|
25073
25137
|
func.scope = status.stack.at(-1) || block;
|
|
25074
25138
|
func.return_type = materialize_type(func.return_type, status);
|
|
25075
25139
|
instantiate_generic_type(func.return_type, status);
|
|
25076
|
-
|
|
25077
|
-
for (const param of func.params) {
|
|
25078
|
-
if (!param.constraint) continue;
|
|
25079
|
-
const { constraint, equalities } = extract_length_equalities_at_registration(param.constraint, param.name, param_names);
|
|
25080
|
-
if (equalities.length) {
|
|
25081
|
-
param.constraint = constraint;
|
|
25082
|
-
param.stripped_length_equalities = equalities;
|
|
25083
|
-
}
|
|
25084
|
-
}
|
|
25140
|
+
strip_param_length_equalities(func);
|
|
25085
25141
|
status.functions.push(func);
|
|
25086
25142
|
}
|
|
25087
25143
|
break;
|
|
@@ -25147,7 +25203,10 @@ function apply_extensions(block, status) {
|
|
|
25147
25203
|
continue;
|
|
25148
25204
|
}
|
|
25149
25205
|
ext.scope = target;
|
|
25150
|
-
for (const func of ext.functions)
|
|
25206
|
+
for (const func of ext.functions) {
|
|
25207
|
+
strip_param_length_equalities(func);
|
|
25208
|
+
target.functions.push(func);
|
|
25209
|
+
}
|
|
25151
25210
|
for (let i = 0; i < ext.traits.length; i++) {
|
|
25152
25211
|
if (target.traits.includes(ext.traits[i])) {
|
|
25153
25212
|
add_error(status, `Type '${ext.name}' already conforms to trait '${ext.traits[i]}'`, ext.start);
|
|
@@ -27886,7 +27945,7 @@ function check_if_else_node(if_else, status) {
|
|
|
27886
27945
|
const else_returns = if_else.else_branch && block_always_returns(if_else.else_branch);
|
|
27887
27946
|
const if_falls_through = if_reachable && !if_returns;
|
|
27888
27947
|
const else_falls_through = else_reachable && (!has_else || !else_returns);
|
|
27889
|
-
if (!has_else && else_reachable) apply_negated_bounds(if_else.condition, status);
|
|
27948
|
+
if (!has_else && else_reachable && !if_returns) apply_negated_bounds(if_else.condition, status);
|
|
27890
27949
|
for (let [i, value] of status.values.entries()) {
|
|
27891
27950
|
const contributing_sets = [];
|
|
27892
27951
|
if (if_falls_through) contributing_sets.push(!!if_status.values[i].is_set);
|
|
@@ -27940,6 +27999,7 @@ function check_if_else_node(if_else, status) {
|
|
|
27940
27999
|
}
|
|
27941
28000
|
}
|
|
27942
28001
|
}
|
|
28002
|
+
if (!has_else && if_returns && else_reachable) apply_negated_bounds(if_else.condition, status);
|
|
27943
28003
|
if (if_else.if_branch && !if_else.else_branch) {
|
|
27944
28004
|
const parent = status.stack.at(-1);
|
|
27945
28005
|
if (parent && (parent.node_type === "declare" || parent.node_type === "assign")) add_error(status, "If expression must have an else branch", if_else.start);
|