nomen-lang 0.2.0 → 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 +135 -20
- package/package.json +1 -1
- package/src/index.ts +8 -3
- package/src/paths.ts +9 -0
- package/src/types/Config.ts +1 -0
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
|
}
|
|
@@ -24379,13 +24380,17 @@ function emit_struct_address(node, status) {
|
|
|
24379
24380
|
/**
|
|
24380
24381
|
* Whether an argument expression is a fat string VALUE: either its static
|
|
24381
24382
|
* type names `string`, or it is a string literal (whose ValueNode.type may
|
|
24382
|
-
* be unset). Literals ride the pair ABI like any string.
|
|
24383
|
+
* be unset). Literals ride the pair ABI like any string. A `view string`
|
|
24384
|
+
* counts too — it IS the same (ptr, len) pair at runtime, so a view
|
|
24385
|
+
* argument to a non-view `string` param (e.g. a `.slice` receiver) must
|
|
24386
|
+
* occupy two slots just like an owned string. (`view` DECLARED params are
|
|
24387
|
+
* unaffected: the view_arg_set check runs first.)
|
|
24383
24388
|
*/
|
|
24384
24389
|
function arg_is_string$1(node) {
|
|
24385
24390
|
const v = node;
|
|
24386
24391
|
if (node.node_type === "value" && typeof v.value === "string" && v.value.startsWith("\"")) return true;
|
|
24387
24392
|
const t = type_from_value_node$1(node);
|
|
24388
|
-
return t?.name === "string" && !t.
|
|
24393
|
+
return t?.name === "string" && !t.is_array;
|
|
24389
24394
|
}
|
|
24390
24395
|
function build_function_call_node$1(node, status) {
|
|
24391
24396
|
if (node.is_enum_shorthand && node.params.length > 0) {
|
|
@@ -25992,6 +25997,12 @@ function build_assignment_node$1(node, status, nir_rhs, nir_swap) {
|
|
|
25992
25997
|
status.last_result_is_heap = false;
|
|
25993
25998
|
emit_rhs_value$1(node.right_value, nir_rhs, status);
|
|
25994
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
|
+
}
|
|
25995
26006
|
const saves_fat_pair = size === 16;
|
|
25996
26007
|
if (saves_fat_pair) status.code += `stp x0, x1, [sp, #-16]!\n`;
|
|
25997
26008
|
else status.code += `str x0, [sp, #-16]!\n`;
|
|
@@ -26007,7 +26018,10 @@ function build_assignment_node$1(node, status, nir_rhs, nir_swap) {
|
|
|
26007
26018
|
const move_source = rhs_is_string_var && node.last_use_move && move_on_last_use_enabled() ? rhs_value.value : void 0;
|
|
26008
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;
|
|
26009
26020
|
const borrow_needs_dup = !node.swap && size === 16 && is_string_borrow(node.right_value) && !!status.force_heap_strings?.has(name);
|
|
26010
|
-
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);
|
|
26011
26025
|
if (rhs_is_string_var || borrow_needs_dup) {
|
|
26012
26026
|
if (move_source !== void 0) status.heap_strings?.delete(move_source);
|
|
26013
26027
|
if (!status.heap_strings) status.heap_strings = /* @__PURE__ */ new Set();
|
|
@@ -29176,13 +29190,14 @@ function build_access_field(node, status) {
|
|
|
29176
29190
|
/**
|
|
29177
29191
|
* Whether an argument expression is a fat string VALUE: either its static
|
|
29178
29192
|
* type names `string`, or it is a string literal (whose ValueNode.type may
|
|
29179
|
-
* be unset). Literals ride the pair ABI like any string.
|
|
29193
|
+
* be unset). Literals ride the pair ABI like any string. A `view string`
|
|
29194
|
+
* counts too — same pair ABI (see build_function_call_node).
|
|
29180
29195
|
*/
|
|
29181
29196
|
function arg_is_string(node) {
|
|
29182
29197
|
const v = node;
|
|
29183
29198
|
if (node.node_type === "value" && typeof v.value === "string" && v.value.startsWith("\"")) return true;
|
|
29184
29199
|
const t = type_from_value_node$1(node);
|
|
29185
|
-
return t?.name === "string" && !t.
|
|
29200
|
+
return t?.name === "string" && !t.is_array;
|
|
29186
29201
|
}
|
|
29187
29202
|
function build_access_method(node, access_func, status) {
|
|
29188
29203
|
let target_type = type_from_value_node$1(node.target);
|
|
@@ -29742,7 +29757,7 @@ function build_access_method(node, access_func, status) {
|
|
|
29742
29757
|
status.stack_offsets.set(temp_addr, temp_offset);
|
|
29743
29758
|
status.code += `add x8, x29, #${temp_offset}\n`;
|
|
29744
29759
|
}
|
|
29745
|
-
const receiver_is_string = !access_func.is_static && target_type?.name === "string" && !target_type.
|
|
29760
|
+
const receiver_is_string = !access_func.is_static && target_type?.name === "string" && !target_type.is_array && !method_self_is_ref;
|
|
29746
29761
|
let frees_string_receiver = false;
|
|
29747
29762
|
if (receiver_is_string) {
|
|
29748
29763
|
status.last_result_is_heap = false;
|
|
@@ -32535,8 +32550,9 @@ function build_struct_functions(node, status, skip_init = false) {
|
|
|
32535
32550
|
} else if (return_type.startsWith("Array_")) status.code += `void* ${emit_label}(`;
|
|
32536
32551
|
else if (func.return_type.is_view) status.code += `nomen_view ${emit_label}(`;
|
|
32537
32552
|
else {
|
|
32538
|
-
const
|
|
32539
|
-
const
|
|
32553
|
+
const mono_return_type = mono_type_name(func.return_type);
|
|
32554
|
+
const return_struct = status.structs.find((s) => s.name === mono_return_type && !s.is_simple_type);
|
|
32555
|
+
const return_trait = status.traits.find((t) => t.name === mono_return_type);
|
|
32540
32556
|
if (return_struct && !return_struct.is_class) {
|
|
32541
32557
|
const swap = status.code;
|
|
32542
32558
|
status.code = status.headers;
|
|
@@ -32544,7 +32560,7 @@ function build_struct_functions(node, status, skip_init = false) {
|
|
|
32544
32560
|
status.headers = status.code;
|
|
32545
32561
|
status.code = swap;
|
|
32546
32562
|
}
|
|
32547
|
-
if (return_struct || return_trait) status.code += `struct ${
|
|
32563
|
+
if (return_struct || return_trait) status.code += `struct ${mono_return_type}`;
|
|
32548
32564
|
else status.code += `${c_type(return_type)}`;
|
|
32549
32565
|
if (return_struct?.is_class || return_trait) status.code += `*`;
|
|
32550
32566
|
status.code += ` ${emit_label}(`;
|
|
@@ -34102,6 +34118,7 @@ function build_return_node(node, status, nir_value) {
|
|
|
34102
34118
|
if (!returned_value_decl) returns_borrow_var = true;
|
|
34103
34119
|
else if (is_string_borrow(returned_value_decl.value) || !!status.string_borrow_vars?.has(var_name)) returns_borrow_var = true;
|
|
34104
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");
|
|
34105
34122
|
if (returns_borrowed_string) {
|
|
34106
34123
|
const access = node.value.access;
|
|
34107
34124
|
if (access.node_type === "access_func") {
|
|
@@ -34128,16 +34145,17 @@ function build_return_node(node, status, nir_value) {
|
|
|
34128
34145
|
}
|
|
34129
34146
|
}
|
|
34130
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");
|
|
34131
|
-
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(`;
|
|
34132
34149
|
const wrap_view_string_return = !!ret_type.is_view && ret_type.name === "string" && !is_view_value(node.value, status);
|
|
34133
34150
|
const expr_type_name = node.type?.name || "";
|
|
34134
34151
|
const expr_is_simple = !status.structs.find((s) => s.name === expr_type_name && !s.is_simple_type);
|
|
34135
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})`;
|
|
34136
34153
|
if (wrap_view_string_return) status.code += `({ nomen_string _p = `;
|
|
34137
34154
|
if (returns_string_zero) status.code += `(nomen_string){0,0}`;
|
|
34155
|
+
else if (returns_view_value) c_materialize_view_string(node.value, status);
|
|
34138
34156
|
else emit_return_value(node.value, nir_value, status);
|
|
34139
34157
|
if (wrap_view_string_return) status.code += `; nomen_view _v = { (void*)_p.ptr, _p.len }; _v; })`;
|
|
34140
|
-
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 += `)`;
|
|
34141
34159
|
status.code += `;\n`;
|
|
34142
34160
|
if (node.value.node_type === "func_call" && node.value.field_overrides?.length) emit_field_overrides("_return_val", node.value, build_node, status, "", ";\n");
|
|
34143
34161
|
reclaim_all_c_scopes(status);
|
|
@@ -35329,6 +35347,17 @@ function build_access_node(node, status) {
|
|
|
35329
35347
|
status.code += `]`;
|
|
35330
35348
|
return;
|
|
35331
35349
|
}
|
|
35350
|
+
if (access_func.name === "slice" && target_type.name === "string" && access_func.params.length === 2) {
|
|
35351
|
+
const tmp = `_vsl_${status.label_counter = (status.label_counter ?? 0) + 1}`;
|
|
35352
|
+
status.code += `({ nomen_view ${tmp} = `;
|
|
35353
|
+
build_node(node.target, status);
|
|
35354
|
+
status.code += `; long _s = `;
|
|
35355
|
+
build_node(access_func.params[0], status);
|
|
35356
|
+
status.code += `; nomen_view _r; _r.ptr = (void*)((char*)${tmp}.ptr + _s); _r.len = (long)(`;
|
|
35357
|
+
build_node(access_func.params[1], status);
|
|
35358
|
+
status.code += ` - _s); _r; })`;
|
|
35359
|
+
return;
|
|
35360
|
+
}
|
|
35332
35361
|
if (access_func.name === "to_string" && target_type.name === "string") {
|
|
35333
35362
|
const tmp = `_vts_${status.label_counter = (status.label_counter ?? 0) + 1}`;
|
|
35334
35363
|
status.code += `({ nomen_view ${tmp} = `;
|
|
@@ -35867,9 +35896,15 @@ function build_assignment_node(node, status, nir_rhs, nir_swap) {
|
|
|
35867
35896
|
} else {
|
|
35868
35897
|
if (lhs_is_string && !rhs_is_bare_value) {
|
|
35869
35898
|
const temp = `_reassign_${status.label_counter = (status.label_counter ?? 0) + 1}`;
|
|
35899
|
+
const rhs_is_view = is_view_value(node.right_value, status);
|
|
35870
35900
|
status.code += `nomen_string ${temp} = `;
|
|
35871
|
-
|
|
35901
|
+
if (rhs_is_view) c_materialize_view_string(node.right_value, status);
|
|
35902
|
+
else emit_rhs_value(node.right_value, nir_rhs, status);
|
|
35872
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
|
+
}
|
|
35873
35908
|
return;
|
|
35874
35909
|
}
|
|
35875
35910
|
status.code += `free(${lhs_name}.ptr);\n`;
|
|
@@ -35883,6 +35918,13 @@ function build_assignment_node(node, status, nir_rhs, nir_swap) {
|
|
|
35883
35918
|
if (rhs_is_bare_value) {
|
|
35884
35919
|
if (lhs_is_class) {
|
|
35885
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;
|
|
35886
35928
|
} else if (!node.swap && rhs.is_moved) {
|
|
35887
35929
|
const src_name = rhs.value;
|
|
35888
35930
|
if (string_var_owns_heap(status, src_name)) {
|
|
@@ -40205,6 +40247,15 @@ function evaluate_operation(op, status) {
|
|
|
40205
40247
|
}
|
|
40206
40248
|
if (op.op === "<=" && left_decl?.upper_bound_inclusive_exprs?.length && target_str) {
|
|
40207
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
|
+
}
|
|
40208
40259
|
}
|
|
40209
40260
|
if (op.op === "<" && left_decl?.upper_bound_inclusive_exprs?.length && target_str && left_decl.upper_bound_inclusive_exprs.includes(target_str)) return "unsafe";
|
|
40210
40261
|
if (left_decl?.upper_bound_expr && target_str) {
|
|
@@ -40363,7 +40414,7 @@ function evaluate_operation(op, status) {
|
|
|
40363
40414
|
const right_base_name = right_str.split(".")[0];
|
|
40364
40415
|
const rdecl = status.values.findLast((v) => v.name === right_base_name);
|
|
40365
40416
|
const ra = rdecl?.alias_of ? parse_offset_expr(rdecl.alias_of) : void 0;
|
|
40366
|
-
const right_base = ra ? ra.base : right_str;
|
|
40417
|
+
const right_base = ra && !(right_str === ra.base || ra.offset === 0 && right_str.startsWith(ra.base + ".")) ? ra.base : right_str;
|
|
40367
40418
|
const right_off = ra ? ra.offset : 0;
|
|
40368
40419
|
if (left_base === right_base) {
|
|
40369
40420
|
const d = left_off - right_off;
|
|
@@ -40514,6 +40565,7 @@ function is_nonnegative_access(node, status) {
|
|
|
40514
40565
|
if (m) {
|
|
40515
40566
|
const field_path = m[1];
|
|
40516
40567
|
const offset_str = m[2];
|
|
40568
|
+
if (!field_path.includes(".")) return false;
|
|
40517
40569
|
const last = field_path.split(".").at(-1);
|
|
40518
40570
|
if (last && NON_NEGATIVE_FIELDS.has(last)) {
|
|
40519
40571
|
if (!offset_str) return true;
|
|
@@ -40721,6 +40773,30 @@ function materialize_type(type, status) {
|
|
|
40721
40773
|
//#endregion
|
|
40722
40774
|
//#region ../src/check/utils/view_fields.ts
|
|
40723
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
|
+
/**
|
|
40724
40800
|
* The root variable an access chain bottoms out at (`line.text` → "line",
|
|
40725
40801
|
* `a.b.c` → "a", bare `x` → "x"). Returns undefined when the chain does not
|
|
40726
40802
|
* bottom out in a plain name (e.g. a call receiver).
|
|
@@ -40842,6 +40918,23 @@ function view_borrows_root_at_self(sv) {
|
|
|
40842
40918
|
return !!owners?.size && [...owners].every((o) => o === "self");
|
|
40843
40919
|
}
|
|
40844
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
|
+
/**
|
|
40845
40938
|
* Whether reading view fields of `root` is currently rejected because their
|
|
40846
40939
|
* source was mutated (reassigned / ref-mutated).
|
|
40847
40940
|
*/
|
|
@@ -40966,7 +41059,7 @@ function check_declaration_node(decl, status) {
|
|
|
40966
41059
|
if (type_from_value_node(decl.value, status)?.is_const_ref) decl.type.is_const_ref = true;
|
|
40967
41060
|
}
|
|
40968
41061
|
let view_borrows;
|
|
40969
|
-
if (decl.value?.node_type === "func_call") {
|
|
41062
|
+
if (decl.value?.node_type === "func_call" && type_can_carry_view_borrow(decl.type, status)) {
|
|
40970
41063
|
view_borrows = ctor_call_view_borrow(decl.value, status);
|
|
40971
41064
|
if (view_borrows?.size) for (const [, info] of view_borrows) {
|
|
40972
41065
|
const depth = info.depth ?? status.scope_depth;
|
|
@@ -43887,7 +43980,7 @@ function check_function_call(node, status, func, target_type, self_value, self_p
|
|
|
43887
43980
|
lower_bound_inclusive_exprs = decl.lower_bound_inclusive_exprs;
|
|
43888
43981
|
upper_bound_expr = decl.upper_bound_expr;
|
|
43889
43982
|
lower_bound_expr = decl.lower_bound_expr;
|
|
43890
|
-
alias_of = decl.alias_of;
|
|
43983
|
+
alias_of = decl.alias_of ?? expr_to_string(param, status);
|
|
43891
43984
|
}
|
|
43892
43985
|
} else if (param.node_type === "op") {
|
|
43893
43986
|
const pop = param;
|
|
@@ -43981,12 +44074,24 @@ function check_function_call(node, status, func, target_type, self_value, self_p
|
|
|
43981
44074
|
});
|
|
43982
44075
|
if (self_value && self_value !== "?") {
|
|
43983
44076
|
const self_type = target_type || func.params[0]?.type;
|
|
44077
|
+
const self_path_or_value = self_path ?? self_value;
|
|
44078
|
+
const self_base = status.values.findLast((v) => v.name === self_path_or_value.split(".")[0]);
|
|
43984
44079
|
status.values.push({
|
|
43985
44080
|
declaration: "const",
|
|
43986
44081
|
name: "self",
|
|
43987
44082
|
type: self_type,
|
|
43988
44083
|
is_set: true,
|
|
43989
|
-
alias_of:
|
|
44084
|
+
alias_of: self_path_or_value,
|
|
44085
|
+
range_lower: self_base?.range_lower,
|
|
44086
|
+
range_upper: self_base?.range_upper,
|
|
44087
|
+
upper_bound_exprs: self_base?.upper_bound_exprs?.slice(),
|
|
44088
|
+
lower_bound_exprs: self_base?.lower_bound_exprs?.slice(),
|
|
44089
|
+
upper_bound_inclusive_exprs: self_base?.upper_bound_inclusive_exprs?.slice(),
|
|
44090
|
+
lower_bound_inclusive_exprs: self_base?.lower_bound_inclusive_exprs?.slice(),
|
|
44091
|
+
upper_bound_expr: self_base?.upper_bound_expr,
|
|
44092
|
+
lower_bound_expr: self_base?.lower_bound_expr,
|
|
44093
|
+
known_length: self_base?.known_length,
|
|
44094
|
+
path_bounds: self_base?.path_bounds
|
|
43990
44095
|
});
|
|
43991
44096
|
}
|
|
43992
44097
|
const satisfied = evaluate_const_condition(func_param.constraint, status);
|
|
@@ -45160,7 +45265,7 @@ function check_assignment_node(assign, status) {
|
|
|
45160
45265
|
const src_name = value_from_value_node(assign.right_value);
|
|
45161
45266
|
const src_sv = assign.right_value.node_type === "value" ? status.values.findLast((v) => v.name === src_name) : void 0;
|
|
45162
45267
|
if (src_sv?.has_view_borrows) propagate_view_borrows(left_value, src_sv);
|
|
45163
|
-
} 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)) {
|
|
45164
45269
|
const infos = ctor_call_view_borrow(assign.right_value, status);
|
|
45165
45270
|
if (infos?.size) {
|
|
45166
45271
|
for (const [, info] of infos) {
|
|
@@ -46002,7 +46107,7 @@ function check_return_node(ret, status) {
|
|
|
46002
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);
|
|
46003
46108
|
}
|
|
46004
46109
|
} else if (func && ret.value.node_type === "func_call") {
|
|
46005
|
-
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;
|
|
46006
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);
|
|
46007
46112
|
}
|
|
46008
46113
|
if (func) {
|
|
@@ -49276,6 +49381,14 @@ function project_root_for(input_path) {
|
|
|
49276
49381
|
function build_dir_for(input_path, is_test) {
|
|
49277
49382
|
return is_test ? path.join(project_root_for(input_path), "build", "test") : path.join(project_root_for(input_path), "build");
|
|
49278
49383
|
}
|
|
49384
|
+
/**
|
|
49385
|
+
* The linked binary path for `input_path`: an explicit `--out` wins,
|
|
49386
|
+
* otherwise `<build dir>/<entry basename>`.
|
|
49387
|
+
*/
|
|
49388
|
+
function outfile_for(input_path, is_test, out) {
|
|
49389
|
+
if (out) return path.resolve(out);
|
|
49390
|
+
return path.join(build_dir_for(input_path, is_test), path.basename(input_path, ".nm"));
|
|
49391
|
+
}
|
|
49279
49392
|
//#endregion
|
|
49280
49393
|
//#region src/test.ts
|
|
49281
49394
|
const RECORD_PREFIX = "\\nomen|";
|
|
@@ -49746,6 +49859,7 @@ try {
|
|
|
49746
49859
|
if (args.audit_runtime) config.audit_runtime = args.audit_runtime;
|
|
49747
49860
|
if (args.release) config.release = args.release;
|
|
49748
49861
|
if (args.fast_math) config.fast_math = args.fast_math;
|
|
49862
|
+
if (args.out) config.out = args.out;
|
|
49749
49863
|
if (fs.lstatSync(args.in).isDirectory()) {
|
|
49750
49864
|
if (args.watch) watchPath(args.in, config, mode, args.program_args);
|
|
49751
49865
|
else processFolder(args.in, config, mode, args.program_args);
|
|
@@ -49872,7 +49986,8 @@ function processFile(filename, config, mode, program_args) {
|
|
|
49872
49986
|
const ext = arch === "aarch64" ? ".s" : platform === "macos" || platform === "ios" ? ".m" : ".c";
|
|
49873
49987
|
const headerfile = path.join(buildDir, "main.h");
|
|
49874
49988
|
const codefile = path.join(buildDir, basename + ext);
|
|
49875
|
-
const outfile =
|
|
49989
|
+
const outfile = outfile_for(resolved_path, filename.endsWith(".test.nm"), config.out);
|
|
49990
|
+
if (!fs.existsSync(path.dirname(outfile))) fs.mkdirSync(path.dirname(outfile), { recursive: true });
|
|
49876
49991
|
fs.writeFileSync(headerfile, result.headers);
|
|
49877
49992
|
fs.writeFileSync(codefile, result.code);
|
|
49878
49993
|
let companionfile;
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { parse_args, print_help, type Args } from "./args.ts";
|
|
|
14
14
|
import { run_docs } from "./docs.ts";
|
|
15
15
|
import render_errors, { render_warnings } from "./format_errors.ts";
|
|
16
16
|
import { find_bundled, run_init } from "./init.ts";
|
|
17
|
-
import { build_dir_for } from "./paths.ts";
|
|
17
|
+
import { build_dir_for, outfile_for } from "./paths.ts";
|
|
18
18
|
import { runTests } from "./test.ts";
|
|
19
19
|
import type Config from "./types/Config.ts";
|
|
20
20
|
|
|
@@ -170,6 +170,7 @@ try {
|
|
|
170
170
|
if (args.audit_runtime) config.audit_runtime = args.audit_runtime;
|
|
171
171
|
if (args.release) config.release = args.release;
|
|
172
172
|
if (args.fast_math) config.fast_math = args.fast_math;
|
|
173
|
+
if (args.out) config.out = args.out;
|
|
173
174
|
|
|
174
175
|
// Is the --in path a folder
|
|
175
176
|
if (fs.lstatSync(args.in).isDirectory()) {
|
|
@@ -370,7 +371,8 @@ function processFile(filename: string, config: Config, mode: Mode, program_args:
|
|
|
370
371
|
}
|
|
371
372
|
|
|
372
373
|
const basename = path.basename(filename, ".nm");
|
|
373
|
-
// Output lives in the project's `build/` — `build/test` for *.test.nm
|
|
374
|
+
// Output lives in the project's `build/` — `build/test` for *.test.nm —
|
|
375
|
+
// unless an explicit --out names the linked binary.
|
|
374
376
|
const buildDir = build_dir_for(resolved_path, filename.endsWith(".test.nm"));
|
|
375
377
|
if (!fs.existsSync(buildDir)) {
|
|
376
378
|
fs.mkdirSync(buildDir, { recursive: true });
|
|
@@ -378,7 +380,10 @@ function processFile(filename: string, config: Config, mode: Mode, program_args:
|
|
|
378
380
|
const ext = arch === "aarch64" ? ".s" : platform === "macos" || platform === "ios" ? ".m" : ".c";
|
|
379
381
|
const headerfile = path.join(buildDir, "main.h");
|
|
380
382
|
const codefile = path.join(buildDir, basename + ext);
|
|
381
|
-
const outfile =
|
|
383
|
+
const outfile = outfile_for(resolved_path, filename.endsWith(".test.nm"), config.out);
|
|
384
|
+
if (!fs.existsSync(path.dirname(outfile))) {
|
|
385
|
+
fs.mkdirSync(path.dirname(outfile), { recursive: true });
|
|
386
|
+
}
|
|
382
387
|
fs.writeFileSync(headerfile, result.headers);
|
|
383
388
|
fs.writeFileSync(codefile, result.code);
|
|
384
389
|
|
package/src/paths.ts
CHANGED
|
@@ -26,3 +26,12 @@ export function build_dir_for(input_path: string, is_test: boolean): string {
|
|
|
26
26
|
? path.join(project_root_for(input_path), "build", "test")
|
|
27
27
|
: path.join(project_root_for(input_path), "build");
|
|
28
28
|
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The linked binary path for `input_path`: an explicit `--out` wins,
|
|
32
|
+
* otherwise `<build dir>/<entry basename>`.
|
|
33
|
+
*/
|
|
34
|
+
export function outfile_for(input_path: string, is_test: boolean, out?: string): string {
|
|
35
|
+
if (out) return path.resolve(out);
|
|
36
|
+
return path.join(build_dir_for(input_path, is_test), path.basename(input_path, ".nm"));
|
|
37
|
+
}
|