nomen-lang 0.2.1 → 0.2.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/dist/index.mjs +85 -9
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -21164,7 +21164,8 @@ function build_return_node$1(node, status, nir_value) {
|
|
|
21164
21164
|
else if ((node.value.node_type === "match" || node.value.node_type === "switch") && !return_join_owned_string) needs_borrow_strdup = true;
|
|
21165
21165
|
}
|
|
21166
21166
|
if (needs_borrow_strdup) {
|
|
21167
|
-
|
|
21167
|
+
if (is_view_value(node.value, status) && (node.value.node_type === "value" || node.value.node_type === "access")) emit_view_materialize_owned(status);
|
|
21168
|
+
else emit_strdup_string(status);
|
|
21168
21169
|
if (!status.code.endsWith("\n")) status.code += "\n";
|
|
21169
21170
|
status.last_result_is_heap = true;
|
|
21170
21171
|
}
|
|
@@ -25996,6 +25997,12 @@ function build_assignment_node$1(node, status, nir_rhs, nir_swap) {
|
|
|
25996
25997
|
status.last_result_is_heap = false;
|
|
25997
25998
|
emit_rhs_value$1(node.right_value, nir_rhs, status);
|
|
25998
25999
|
if (!status.code.endsWith("\n")) status.code += "\n";
|
|
26000
|
+
const assign_lhs_type = status.scoped_declarations.find((d) => d.name === name)?.type ?? status.variable_types?.get(name);
|
|
26001
|
+
const rhs_is_view_into_owned = !node.swap && !node.operator && size === 16 && assign_lhs_type?.name === "string" && !assign_lhs_type.is_view && is_view_value(node.right_value, status);
|
|
26002
|
+
if (rhs_is_view_into_owned) {
|
|
26003
|
+
emit_view_materialize_owned(status);
|
|
26004
|
+
if (!status.code.endsWith("\n")) status.code += "\n";
|
|
26005
|
+
}
|
|
25999
26006
|
const saves_fat_pair = size === 16;
|
|
26000
26007
|
if (saves_fat_pair) status.code += `stp x0, x1, [sp, #-16]!\n`;
|
|
26001
26008
|
else status.code += `str x0, [sp, #-16]!\n`;
|
|
@@ -26011,7 +26018,10 @@ function build_assignment_node$1(node, status, nir_rhs, nir_swap) {
|
|
|
26011
26018
|
const move_source = rhs_is_string_var && node.last_use_move && move_on_last_use_enabled() ? rhs_value.value : void 0;
|
|
26012
26019
|
const explicit_move_source = !node.swap && !!rhs_value && rhs_value.is_moved && size === 16 && rhs_value.type?.name === "string" && !rhs_value.type?.is_view ? rhs_value.value : void 0;
|
|
26013
26020
|
const borrow_needs_dup = !node.swap && size === 16 && is_string_borrow(node.right_value) && !!status.force_heap_strings?.has(name);
|
|
26014
|
-
if (
|
|
26021
|
+
if (rhs_is_view_into_owned) {
|
|
26022
|
+
if (!status.heap_strings) status.heap_strings = /* @__PURE__ */ new Set();
|
|
26023
|
+
status.heap_strings.add(name);
|
|
26024
|
+
} else if (rhs_is_string_var && move_source === void 0 || borrow_needs_dup) emit_strdup_string(status);
|
|
26015
26025
|
if (rhs_is_string_var || borrow_needs_dup) {
|
|
26016
26026
|
if (move_source !== void 0) status.heap_strings?.delete(move_source);
|
|
26017
26027
|
if (!status.heap_strings) status.heap_strings = /* @__PURE__ */ new Set();
|
|
@@ -34108,6 +34118,7 @@ function build_return_node(node, status, nir_value) {
|
|
|
34108
34118
|
if (!returned_value_decl) returns_borrow_var = true;
|
|
34109
34119
|
else if (is_string_borrow(returned_value_decl.value) || !!status.string_borrow_vars?.has(var_name)) returns_borrow_var = true;
|
|
34110
34120
|
}
|
|
34121
|
+
const returns_view_value = ret_type.name === "string" && !ret_type.is_view && !ret_type.is_array && is_view_value(node.value, status) && (node.value.node_type === "value" || node.value.node_type === "access");
|
|
34111
34122
|
if (returns_borrowed_string) {
|
|
34112
34123
|
const access = node.value.access;
|
|
34113
34124
|
if (access.node_type === "access_func") {
|
|
@@ -34134,16 +34145,17 @@ function build_return_node(node, status, nir_value) {
|
|
|
34134
34145
|
}
|
|
34135
34146
|
}
|
|
34136
34147
|
const returns_string_zero = ret_type.name === "string" && !ret_type.is_view && !ret_type.is_array && node.value.node_type === "value" && (node.value.value === "0" || node.value.value === "null");
|
|
34137
|
-
if (!returns_string_zero && (returns_borrowed_string || returns_string_literal || returns_borrow_var)) status.code += `nomen_str_dup(`;
|
|
34148
|
+
if (!returns_string_zero && !returns_view_value && (returns_borrowed_string || returns_string_literal || returns_borrow_var)) status.code += `nomen_str_dup(`;
|
|
34138
34149
|
const wrap_view_string_return = !!ret_type.is_view && ret_type.name === "string" && !is_view_value(node.value, status);
|
|
34139
34150
|
const expr_type_name = node.type?.name || "";
|
|
34140
34151
|
const expr_is_simple = !status.structs.find((s) => s.name === expr_type_name && !s.is_simple_type);
|
|
34141
34152
|
if (is_struct && expr_is_simple && !returns_borrowed_string && !ret_type.is_view) status.code += return_is_class ? `(struct ${mono_ret_name}*)` : `(struct ${mono_ret_name})`;
|
|
34142
34153
|
if (wrap_view_string_return) status.code += `({ nomen_string _p = `;
|
|
34143
34154
|
if (returns_string_zero) status.code += `(nomen_string){0,0}`;
|
|
34155
|
+
else if (returns_view_value) c_materialize_view_string(node.value, status);
|
|
34144
34156
|
else emit_return_value(node.value, nir_value, status);
|
|
34145
34157
|
if (wrap_view_string_return) status.code += `; nomen_view _v = { (void*)_p.ptr, _p.len }; _v; })`;
|
|
34146
|
-
if (!returns_string_zero && (returns_borrowed_string || returns_string_literal || returns_borrow_var)) status.code += `)`;
|
|
34158
|
+
if (!returns_string_zero && !returns_view_value && (returns_borrowed_string || returns_string_literal || returns_borrow_var)) status.code += `)`;
|
|
34147
34159
|
status.code += `;\n`;
|
|
34148
34160
|
if (node.value.node_type === "func_call" && node.value.field_overrides?.length) emit_field_overrides("_return_val", node.value, build_node, status, "", ";\n");
|
|
34149
34161
|
reclaim_all_c_scopes(status);
|
|
@@ -35884,9 +35896,15 @@ function build_assignment_node(node, status, nir_rhs, nir_swap) {
|
|
|
35884
35896
|
} else {
|
|
35885
35897
|
if (lhs_is_string && !rhs_is_bare_value) {
|
|
35886
35898
|
const temp = `_reassign_${status.label_counter = (status.label_counter ?? 0) + 1}`;
|
|
35899
|
+
const rhs_is_view = is_view_value(node.right_value, status);
|
|
35887
35900
|
status.code += `nomen_string ${temp} = `;
|
|
35888
|
-
|
|
35901
|
+
if (rhs_is_view) c_materialize_view_string(node.right_value, status);
|
|
35902
|
+
else emit_rhs_value(node.right_value, nir_rhs, status);
|
|
35889
35903
|
status.code += `;\nfree(${lhs_name}.ptr);\n${lhs_name} = ${temp};\n`;
|
|
35904
|
+
if (rhs_is_view) {
|
|
35905
|
+
if (!status.heap_strings) status.heap_strings = /* @__PURE__ */ new Set();
|
|
35906
|
+
status.heap_strings.add(lhs_name);
|
|
35907
|
+
}
|
|
35890
35908
|
return;
|
|
35891
35909
|
}
|
|
35892
35910
|
status.code += `free(${lhs_name}.ptr);\n`;
|
|
@@ -35900,6 +35918,13 @@ function build_assignment_node(node, status, nir_rhs, nir_swap) {
|
|
|
35900
35918
|
if (rhs_is_bare_value) {
|
|
35901
35919
|
if (lhs_is_class) {
|
|
35902
35920
|
if (!node.swap) splice_decl_from_c_scopes(status, rhs.value);
|
|
35921
|
+
} else if (lhs_is_string && !node.swap && rhs.node_type === "value" && is_view_value(rhs, status)) {
|
|
35922
|
+
status.code += `${lhs_name} = `;
|
|
35923
|
+
c_materialize_view_string(rhs, status);
|
|
35924
|
+
status.code += `;\n`;
|
|
35925
|
+
if (!status.heap_strings) status.heap_strings = /* @__PURE__ */ new Set();
|
|
35926
|
+
status.heap_strings.add(lhs_name);
|
|
35927
|
+
return;
|
|
35903
35928
|
} else if (!node.swap && rhs.is_moved) {
|
|
35904
35929
|
const src_name = rhs.value;
|
|
35905
35930
|
if (string_var_owns_heap(status, src_name)) {
|
|
@@ -40222,6 +40247,15 @@ function evaluate_operation(op, status) {
|
|
|
40222
40247
|
}
|
|
40223
40248
|
if (op.op === "<=" && left_decl?.upper_bound_inclusive_exprs?.length && target_str) {
|
|
40224
40249
|
if (left_decl.upper_bound_inclusive_exprs.includes(target_str)) return true;
|
|
40250
|
+
if (left_decl.upper_bound_inclusive_exprs.some((u) => upper_implies(u, target_str))) return true;
|
|
40251
|
+
for (const u of left_decl.upper_bound_inclusive_exprs) {
|
|
40252
|
+
const v = parse_offset_expr(u);
|
|
40253
|
+
if (v && v.offset === 0 && u !== target_str) {
|
|
40254
|
+
const vdecl = status.values.findLast((vv) => vv.name === v.base);
|
|
40255
|
+
if (vdecl?.upper_bound_exprs?.includes(target_str)) return true;
|
|
40256
|
+
if (vdecl?.upper_bound_inclusive_exprs?.includes(target_str)) return true;
|
|
40257
|
+
}
|
|
40258
|
+
}
|
|
40225
40259
|
}
|
|
40226
40260
|
if (op.op === "<" && left_decl?.upper_bound_inclusive_exprs?.length && target_str && left_decl.upper_bound_inclusive_exprs.includes(target_str)) return "unsafe";
|
|
40227
40261
|
if (left_decl?.upper_bound_expr && target_str) {
|
|
@@ -40531,6 +40565,7 @@ function is_nonnegative_access(node, status) {
|
|
|
40531
40565
|
if (m) {
|
|
40532
40566
|
const field_path = m[1];
|
|
40533
40567
|
const offset_str = m[2];
|
|
40568
|
+
if (!field_path.includes(".")) return false;
|
|
40534
40569
|
const last = field_path.split(".").at(-1);
|
|
40535
40570
|
if (last && NON_NEGATIVE_FIELDS.has(last)) {
|
|
40536
40571
|
if (!offset_str) return true;
|
|
@@ -40738,6 +40773,30 @@ function materialize_type(type, status) {
|
|
|
40738
40773
|
//#endregion
|
|
40739
40774
|
//#region ../src/check/utils/view_fields.ts
|
|
40740
40775
|
/**
|
|
40776
|
+
* Whether the named struct (or any value struct embedded in its fields,
|
|
40777
|
+
* recursively) declares a `view T` field. A struct with view fields carries
|
|
40778
|
+
* non-owning borrows inside its bytes, which drives the borrow rules:
|
|
40779
|
+
* copies are sound (a pair copy aliases nothing owned), but escapes
|
|
40780
|
+
* (returning, outer-scope assignment) are checked against where those
|
|
40781
|
+
* borrows were taken.
|
|
40782
|
+
*/
|
|
40783
|
+
function struct_has_view_fields(type_name, status) {
|
|
40784
|
+
if (!type_name) return false;
|
|
40785
|
+
const struct = status.structs.find((s) => s.name === type_name && !s.is_simple_type);
|
|
40786
|
+
return !!struct && has_view_fields(struct, status, /* @__PURE__ */ new Set());
|
|
40787
|
+
}
|
|
40788
|
+
function has_view_fields(struct, status, visited) {
|
|
40789
|
+
if (visited.has(struct.name)) return false;
|
|
40790
|
+
visited.add(struct.name);
|
|
40791
|
+
for (const field of struct.fields) {
|
|
40792
|
+
if (field.type.is_view) return true;
|
|
40793
|
+
if (field.type.is_ref || field.type.is_array) continue;
|
|
40794
|
+
const field_struct = status.structs.find((s) => s.name === field.type.name && !s.is_simple_type && !s.is_class);
|
|
40795
|
+
if (field_struct && has_view_fields(field_struct, status, visited)) return true;
|
|
40796
|
+
}
|
|
40797
|
+
return false;
|
|
40798
|
+
}
|
|
40799
|
+
/**
|
|
40741
40800
|
* The root variable an access chain bottoms out at (`line.text` → "line",
|
|
40742
40801
|
* `a.b.c` → "a", bare `x` → "x"). Returns undefined when the chain does not
|
|
40743
40802
|
* bottom out in a plain name (e.g. a call receiver).
|
|
@@ -40859,6 +40918,23 @@ function view_borrows_root_at_self(sv) {
|
|
|
40859
40918
|
return !!owners?.size && [...owners].every((o) => o === "self");
|
|
40860
40919
|
}
|
|
40861
40920
|
/**
|
|
40921
|
+
* Whether a value of this type can carry a non-owning view borrow: the type
|
|
40922
|
+
* itself is a `view`, a `ref` (a borrow by definition — keep the existing
|
|
40923
|
+
* taint), a struct declaring (transitively) `view T` fields, or a generic
|
|
40924
|
+
* instantiation with such an argument. Anything else (primitives, owned
|
|
40925
|
+
* strings, containers of owned values) owns its storage outright, so a call
|
|
40926
|
+
* producing it does not propagate its view arguments' borrows — tainting it
|
|
40927
|
+
* is a false positive (e.g. returning `slice_string(view)` from a function
|
|
40928
|
+
* returning owned `string`). Callers pass an unset/unknown type through as
|
|
40929
|
+
* carrying, preserving today's behavior where nothing is known.
|
|
40930
|
+
*/
|
|
40931
|
+
function type_can_carry_view_borrow(type, status) {
|
|
40932
|
+
if (!type || !type.name) return true;
|
|
40933
|
+
if (type.is_view || type.is_ref) return true;
|
|
40934
|
+
if (struct_has_view_fields(type.name, status)) return true;
|
|
40935
|
+
return (type.type_args ?? []).some((t) => type_can_carry_view_borrow(t, status));
|
|
40936
|
+
}
|
|
40937
|
+
/**
|
|
40862
40938
|
* Whether reading view fields of `root` is currently rejected because their
|
|
40863
40939
|
* source was mutated (reassigned / ref-mutated).
|
|
40864
40940
|
*/
|
|
@@ -40983,7 +41059,7 @@ function check_declaration_node(decl, status) {
|
|
|
40983
41059
|
if (type_from_value_node(decl.value, status)?.is_const_ref) decl.type.is_const_ref = true;
|
|
40984
41060
|
}
|
|
40985
41061
|
let view_borrows;
|
|
40986
|
-
if (decl.value?.node_type === "func_call") {
|
|
41062
|
+
if (decl.value?.node_type === "func_call" && type_can_carry_view_borrow(decl.type, status)) {
|
|
40987
41063
|
view_borrows = ctor_call_view_borrow(decl.value, status);
|
|
40988
41064
|
if (view_borrows?.size) for (const [, info] of view_borrows) {
|
|
40989
41065
|
const depth = info.depth ?? status.scope_depth;
|
|
@@ -43904,7 +43980,7 @@ function check_function_call(node, status, func, target_type, self_value, self_p
|
|
|
43904
43980
|
lower_bound_inclusive_exprs = decl.lower_bound_inclusive_exprs;
|
|
43905
43981
|
upper_bound_expr = decl.upper_bound_expr;
|
|
43906
43982
|
lower_bound_expr = decl.lower_bound_expr;
|
|
43907
|
-
alias_of = decl.alias_of;
|
|
43983
|
+
alias_of = decl.alias_of ?? expr_to_string(param, status);
|
|
43908
43984
|
}
|
|
43909
43985
|
} else if (param.node_type === "op") {
|
|
43910
43986
|
const pop = param;
|
|
@@ -45189,7 +45265,7 @@ function check_assignment_node(assign, status) {
|
|
|
45189
45265
|
const src_name = value_from_value_node(assign.right_value);
|
|
45190
45266
|
const src_sv = assign.right_value.node_type === "value" ? status.values.findLast((v) => v.name === src_name) : void 0;
|
|
45191
45267
|
if (src_sv?.has_view_borrows) propagate_view_borrows(left_value, src_sv);
|
|
45192
|
-
} else if (assign.right_value.node_type === "func_call" && type_from_value_node(assign.right_value, status)?.name) {
|
|
45268
|
+
} else if (assign.right_value.node_type === "func_call" && type_from_value_node(assign.right_value, status)?.name && type_can_carry_view_borrow(type_from_value_node(assign.right_value, status), status)) {
|
|
45193
45269
|
const infos = ctor_call_view_borrow(assign.right_value, status);
|
|
45194
45270
|
if (infos?.size) {
|
|
45195
45271
|
for (const [, info] of infos) {
|
|
@@ -46031,7 +46107,7 @@ function check_return_node(ret, status) {
|
|
|
46031
46107
|
if (!safe_view_from_self && !explicit_mov) add_error(status, `cannot return a borrowed reference — use 'move' (with swap) to transfer ownership`, ret.value.start);
|
|
46032
46108
|
}
|
|
46033
46109
|
} else if (func && ret.value.node_type === "func_call") {
|
|
46034
|
-
const infos = ctor_call_view_borrow(ret.value, status);
|
|
46110
|
+
const infos = type_can_carry_view_borrow(ret.type, status) ? ctor_call_view_borrow(ret.value, status) : void 0;
|
|
46035
46111
|
if (infos?.size && ![...infos.keys()].every((o) => o === "self")) add_error(status, `cannot return '${ret.type.name}' — its 'view' field(s) borrow from this scope`, ret.value.start);
|
|
46036
46112
|
}
|
|
46037
46113
|
if (func) {
|