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.
Files changed (2) hide show
  1. package/dist/index.mjs +148 -19
  2. 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
- const target_type = type_from_value_node$1(access_lhs.target);
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 && target_var !== "self") {
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
- build_node(node.condition, status);
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
- build_node(node.condition, status);
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
- build_node(node.condition, status);
16443
+ build_condition(node.condition, status);
16315
16444
  status.code += `) {\n`;
16316
16445
  }
16317
16446
  build_block_node(node, status);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nomen-lang",
3
- "version": "0.0.14",
3
+ "version": "0.0.15",
4
4
  "description": "The CLI for the Nomen programming language.",
5
5
  "keywords": [],
6
6
  "license": "ISC",