nomen-lang 0.0.14 → 0.0.15
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 +148 -19
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -12110,13 +12110,7 @@ function build_spawn_node(node, status) {
|
|
|
12110
12110
|
if (!status.headers.includes("__nomen_pool_submit")) status.headers += POOL_HEADER;
|
|
12111
12111
|
const struct_name = `__nomen_spawn_${id}_args`;
|
|
12112
12112
|
const tramp_name = `__nomen_spawn_${id}_trampoline`;
|
|
12113
|
-
const arg_c_types =
|
|
12114
|
-
for (let i = 0; i < call.params.length; i++) {
|
|
12115
|
-
const mono_name = mono_type_name(type_from_value_node$1(call.params[i]));
|
|
12116
|
-
const is_class = !!status.structs.find((s) => s.name === mono_name && s.is_class);
|
|
12117
|
-
const is_trait = !!status.traits.find((t) => t.name === mono_name);
|
|
12118
|
-
arg_c_types.push(is_class || is_trait ? `struct ${mono_name} *` : c_type(mono_name));
|
|
12119
|
-
}
|
|
12113
|
+
const arg_c_types = spawn_arg_c_types(call, status);
|
|
12120
12114
|
const return_type_name = node.function_return_type?.name;
|
|
12121
12115
|
const returns_value = !!(return_type_name && return_type_name !== "void" && return_type_name !== "?");
|
|
12122
12116
|
const is_class_ret = returns_value && !!status.structs.find((s) => s.name === return_type_name && s.is_class);
|
|
@@ -12189,6 +12183,98 @@ function build_spawn_node(node, status) {
|
|
|
12189
12183
|
}
|
|
12190
12184
|
status.code += `})\n`;
|
|
12191
12185
|
}
|
|
12186
|
+
const C_BUILTIN_TYPES = /* @__PURE__ */ new Set([
|
|
12187
|
+
"bool",
|
|
12188
|
+
"int",
|
|
12189
|
+
"uint",
|
|
12190
|
+
"int8",
|
|
12191
|
+
"uint8",
|
|
12192
|
+
"int16",
|
|
12193
|
+
"uint16",
|
|
12194
|
+
"int32",
|
|
12195
|
+
"uint32",
|
|
12196
|
+
"int64",
|
|
12197
|
+
"uint64",
|
|
12198
|
+
"float",
|
|
12199
|
+
"ufloat",
|
|
12200
|
+
"float32",
|
|
12201
|
+
"ufloat32",
|
|
12202
|
+
"float64",
|
|
12203
|
+
"ufloat64",
|
|
12204
|
+
"char",
|
|
12205
|
+
"string",
|
|
12206
|
+
"func",
|
|
12207
|
+
"void",
|
|
12208
|
+
"null"
|
|
12209
|
+
]);
|
|
12210
|
+
/**
|
|
12211
|
+
* Resolve each spawn argument's C type. Classes/traits are pointers;
|
|
12212
|
+
* primitives and by-value structs use c_type's output directly. Generic
|
|
12213
|
+
* instantiations (e.g. Channel<uint64>) use the monomorphized C name
|
|
12214
|
+
* (`Channel_uint64`). The type comes from the CALLEE's declared parameter
|
|
12215
|
+
* whenever it can be resolved — an argument's own node type can differ
|
|
12216
|
+
* (e.g. an int literal `41` passed for a `uint64` param lowers to `long`,
|
|
12217
|
+
* conflicting with the emitted `unsigned long long` prototype). Falls back
|
|
12218
|
+
* to the argument's type when the callee (or its param type) can't be
|
|
12219
|
+
* resolved at build time.
|
|
12220
|
+
*/
|
|
12221
|
+
function spawn_arg_c_types(call, status) {
|
|
12222
|
+
const arg_c_types = [];
|
|
12223
|
+
const callee_params = find_spawn_callee(call.name, status)?.params?.filter((p) => !p.is_self_param) ?? [];
|
|
12224
|
+
for (let i = 0; i < call.params.length; i++) {
|
|
12225
|
+
const mono_name = mono_type_name(callee_params[i]?.type && is_resolvable_c_type(callee_params[i].type, status) ? callee_params[i].type : type_from_value_node$1(call.params[i]));
|
|
12226
|
+
const is_class = !!status.structs.find((s) => s.name === mono_name && s.is_class);
|
|
12227
|
+
const is_trait = !!status.traits.find((t) => t.name === mono_name);
|
|
12228
|
+
arg_c_types.push(is_class || is_trait ? `struct ${mono_name} *` : c_type(mono_name));
|
|
12229
|
+
}
|
|
12230
|
+
return arg_c_types;
|
|
12231
|
+
}
|
|
12232
|
+
/** Whether a Nomen type name lowers to a real C type in this build: a
|
|
12233
|
+
* builtin primitive or a struct/enum the backend knows (post-monomorphization).
|
|
12234
|
+
* Unresolved generic type params (`T`) fail this check. */
|
|
12235
|
+
function is_resolvable_c_type(type, status) {
|
|
12236
|
+
if (C_BUILTIN_TYPES.has(type.name)) return true;
|
|
12237
|
+
return !!status.structs.find((s) => s.name === type.name);
|
|
12238
|
+
}
|
|
12239
|
+
/**
|
|
12240
|
+
* Find the spawned function's definition — a top-level function, a function
|
|
12241
|
+
* nested in a block (parse wrappers hoist user code into `main`), or a
|
|
12242
|
+
* struct/trait method (matched by its mangled `Struct_method` name) — so the
|
|
12243
|
+
* trampoline's forward declaration can copy the callee's DECLARED parameter
|
|
12244
|
+
* types. Monomorphized clones are also reachable this way (they are appended
|
|
12245
|
+
* to the AST). A same-named pair would already collide at C level, so the
|
|
12246
|
+
* first match is as good as any.
|
|
12247
|
+
*/
|
|
12248
|
+
function find_spawn_callee(name, status) {
|
|
12249
|
+
let found;
|
|
12250
|
+
const visit = (node) => {
|
|
12251
|
+
if (found || !node || typeof node !== "object") return;
|
|
12252
|
+
if (node.node_type === "func") {
|
|
12253
|
+
if (node.name === name) {
|
|
12254
|
+
found = node;
|
|
12255
|
+
return;
|
|
12256
|
+
}
|
|
12257
|
+
} else if (node.node_type === "struct" || node.node_type === "trait") {
|
|
12258
|
+
const functions = node.functions ?? [];
|
|
12259
|
+
for (const func of functions) {
|
|
12260
|
+
const owner = node.name;
|
|
12261
|
+
if (func.name === name || `${owner}_${func.name}` === name) {
|
|
12262
|
+
found = func;
|
|
12263
|
+
return;
|
|
12264
|
+
}
|
|
12265
|
+
}
|
|
12266
|
+
}
|
|
12267
|
+
for (const key of Object.keys(node)) {
|
|
12268
|
+
if (key === "parent" || key === "scope") continue;
|
|
12269
|
+
const v = node[key];
|
|
12270
|
+
if (Array.isArray(v)) for (const item of v) visit(item);
|
|
12271
|
+
else if (v && typeof v === "object" && "node_type" in v) visit(v);
|
|
12272
|
+
if (found) return;
|
|
12273
|
+
}
|
|
12274
|
+
};
|
|
12275
|
+
visit(status.root);
|
|
12276
|
+
return found;
|
|
12277
|
+
}
|
|
12192
12278
|
//#endregion
|
|
12193
12279
|
//#region ../src/build_c/build_nursery_spawn.ts
|
|
12194
12280
|
/**
|
|
@@ -12214,13 +12300,7 @@ function build_nursery_spawn(node, nursery_ptr, status) {
|
|
|
12214
12300
|
if (!status.headers.includes("__nomen_pool_submit")) status.headers += POOL_HEADER;
|
|
12215
12301
|
const struct_name = `__nomen_spawn_${id}_args`;
|
|
12216
12302
|
const tramp_name = `__nomen_spawn_${id}_trampoline`;
|
|
12217
|
-
const arg_c_types =
|
|
12218
|
-
for (let i = 0; i < args.length; i++) {
|
|
12219
|
-
const mono_name = mono_type_name(type_from_value_node$1(args[i]));
|
|
12220
|
-
const is_class = !!status.structs.find((s) => s.name === mono_name && s.is_class);
|
|
12221
|
-
const is_trait = !!status.traits.find((t) => t.name === mono_name);
|
|
12222
|
-
arg_c_types.push(is_class || is_trait ? `struct ${mono_name} *` : c_type(mono_name));
|
|
12223
|
-
}
|
|
12303
|
+
const arg_c_types = spawn_arg_c_types(call, status);
|
|
12224
12304
|
const return_type_name = node.function_return_type?.name;
|
|
12225
12305
|
const returns_value = !!(return_type_name && return_type_name !== "void" && return_type_name !== "?");
|
|
12226
12306
|
const is_class_ret = returns_value && !!status.structs.find((s) => s.name === return_type_name && s.is_class);
|
|
@@ -13517,12 +13597,14 @@ function build_assignment_node(node, status) {
|
|
|
13517
13597
|
if (!node.operator && node.left_value.node_type === "access" && node.left_value.access.node_type === "access_field" && node.left_value.access.type?.name === "string" && !node.left_value.access.type?.is_ref && !node.left_value.access.type?.is_array) {
|
|
13518
13598
|
const access_lhs = node.left_value;
|
|
13519
13599
|
const field_access_node = access_lhs.access;
|
|
13520
|
-
|
|
13600
|
+
let target_type = type_from_value_node$1(access_lhs.target);
|
|
13601
|
+
if (!target_type?.name && access_lhs.target.node_type === "value" && access_lhs.target.value === "self" && status.current_struct) target_type = new Type(status.current_struct.name);
|
|
13521
13602
|
const target_struct = target_type?.name ? status.structs.find((s) => s.name === target_type.name && !s.is_simple_type) : null;
|
|
13522
13603
|
const target_var = access_lhs.target.node_type === "value" ? access_lhs.target.value : "";
|
|
13604
|
+
const self_target = target_var === "self";
|
|
13523
13605
|
const tracked_key = `${target_var}.${field_access_node.name}`;
|
|
13524
13606
|
const old_was_heap = !!target_struct?.is_class || !!status.heap_string_fields?.has(tracked_key);
|
|
13525
|
-
if (target_struct && target_var &&
|
|
13607
|
+
if (target_struct && target_var && (!self_target || target_struct.is_class)) {
|
|
13526
13608
|
const fresh_heap = is_owned_heap_temp(node.right_value, status);
|
|
13527
13609
|
const before_len = status.code.length;
|
|
13528
13610
|
build_node(node.left_value, status);
|
|
@@ -15808,6 +15890,52 @@ function emit_nullable_arg_flag(arg, status) {
|
|
|
15808
15890
|
status.code += `1`;
|
|
15809
15891
|
}
|
|
15810
15892
|
//#endregion
|
|
15893
|
+
//#region ../src/build_c/utils/build_condition.ts
|
|
15894
|
+
/**
|
|
15895
|
+
* Build a controlling expression (an if/while/for condition or a switch-case
|
|
15896
|
+
* comparison) and emit it without redundant fully-wrapping outer parentheses.
|
|
15897
|
+
* The codegen wraps every binary operation in parens (build_default_binary),
|
|
15898
|
+
* so emitting the condition verbatim would read `if ((a == b))`, which clang
|
|
15899
|
+
* flags as -Wparentheses-equality ("equality comparison with extraneous
|
|
15900
|
+
* parentheses").
|
|
15901
|
+
*/
|
|
15902
|
+
function build_condition(node, status) {
|
|
15903
|
+
const before = status.code.length;
|
|
15904
|
+
build_node(node, status);
|
|
15905
|
+
status.code = status.code.substring(0, before) + strip_outer_parens(status.code.substring(before));
|
|
15906
|
+
}
|
|
15907
|
+
/**
|
|
15908
|
+
* Strip outer paren layers that wrap the ENTIRE expression (the opening paren
|
|
15909
|
+
* matches only the final character). A layer is removed only when the inner
|
|
15910
|
+
* text does not start with `{` — a GCC/clang statement-expression
|
|
15911
|
+
* `({ ... })` must keep its wrapper to stay a valid expression. Parens
|
|
15912
|
+
* inside string/char literals can only make the scan conservative (they
|
|
15913
|
+
* unbalance the depth count, so nothing is stripped), never incorrect.
|
|
15914
|
+
*/
|
|
15915
|
+
function strip_outer_parens(expr) {
|
|
15916
|
+
let code = expr.trim();
|
|
15917
|
+
while (code.length > 1 && code.startsWith("(") && code.endsWith(")")) {
|
|
15918
|
+
let depth = 0;
|
|
15919
|
+
let wraps_whole = true;
|
|
15920
|
+
for (let i = 0; i < code.length; i++) {
|
|
15921
|
+
const ch = code[i];
|
|
15922
|
+
if (ch === "(") depth++;
|
|
15923
|
+
else if (ch === ")") {
|
|
15924
|
+
depth--;
|
|
15925
|
+
if (depth === 0 && i < code.length - 1) {
|
|
15926
|
+
wraps_whole = false;
|
|
15927
|
+
break;
|
|
15928
|
+
}
|
|
15929
|
+
}
|
|
15930
|
+
}
|
|
15931
|
+
if (!wraps_whole || depth !== 0) break;
|
|
15932
|
+
const inner = code.slice(1, -1).trim();
|
|
15933
|
+
if (inner.startsWith("{")) break;
|
|
15934
|
+
code = inner;
|
|
15935
|
+
}
|
|
15936
|
+
return code;
|
|
15937
|
+
}
|
|
15938
|
+
//#endregion
|
|
15811
15939
|
//#region ../src/build_c/build_if_else_node.ts
|
|
15812
15940
|
function build_if_else_node(node, status) {
|
|
15813
15941
|
const old_scoped_declarations = status.scoped_declarations;
|
|
@@ -15816,7 +15944,7 @@ function build_if_else_node(node, status) {
|
|
|
15816
15944
|
status.deferred_frees = [];
|
|
15817
15945
|
emit_allocations(node.condition, status);
|
|
15818
15946
|
status.code += `if (`;
|
|
15819
|
-
|
|
15947
|
+
build_condition(node.condition, status);
|
|
15820
15948
|
status.code += `) {\n`;
|
|
15821
15949
|
if (node.if_branch) {
|
|
15822
15950
|
build_block_node(node.if_branch, status);
|
|
@@ -16229,6 +16357,7 @@ function build_switch_node(node, status) {
|
|
|
16229
16357
|
}
|
|
16230
16358
|
cond_code = cond_code.trim();
|
|
16231
16359
|
while (cond_code.startsWith("(") && !cond_code.endsWith(")")) cond_code = cond_code.substring(1).trim();
|
|
16360
|
+
cond_code = strip_outer_parens(cond_code);
|
|
16232
16361
|
if (decls.length > 0) status.code += decls.join("\n") + "\n";
|
|
16233
16362
|
const prefix = status.code.endsWith("} else ") ? "" : "";
|
|
16234
16363
|
status.code += `${prefix}if (${cond_code}) {\n`;
|
|
@@ -16305,13 +16434,13 @@ function build_while_loop_node(node, status) {
|
|
|
16305
16434
|
emit_allocations(node.condition, status);
|
|
16306
16435
|
if (node.update) {
|
|
16307
16436
|
status.code += `for (; `;
|
|
16308
|
-
|
|
16437
|
+
build_condition(node.condition, status);
|
|
16309
16438
|
status.code += `; `;
|
|
16310
16439
|
build_node(node.update, status);
|
|
16311
16440
|
status.code += `) {\n`;
|
|
16312
16441
|
} else {
|
|
16313
16442
|
status.code += `while (`;
|
|
16314
|
-
|
|
16443
|
+
build_condition(node.condition, status);
|
|
16315
16444
|
status.code += `) {\n`;
|
|
16316
16445
|
}
|
|
16317
16446
|
build_block_node(node, status);
|