nomen-lang 0.0.19 → 0.2.0

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 (62) hide show
  1. package/NOMEN_AGENTS.md +57 -12
  2. package/core/System/Array.nm +11 -11
  3. package/core/System/Buffer.nm +2 -2
  4. package/core/System/Channel.nm +146 -12
  5. package/core/System/ClassBuffer.nm +2 -2
  6. package/core/System/Console.nm +28 -17
  7. package/core/System/Controls/Button.nm +96 -8
  8. package/core/System/Controls/CheckBox.nm +117 -12
  9. package/core/System/Controls/Container.nm +114 -8
  10. package/core/System/Controls/Text.nm +98 -8
  11. package/core/System/Controls/TextBox.nm +120 -10
  12. package/core/System/Controls/Window.nm +231 -23
  13. package/core/System/Graph.nm +1 -1
  14. package/core/System/Init.nm +4 -8
  15. package/core/System/LinkedList.nm +1 -1
  16. package/core/System/List.nm +3 -3
  17. package/core/System/Map.nm +5 -5
  18. package/core/System/Math.nm +10 -32
  19. package/core/System/Result.nm +1 -1
  20. package/core/System/Set.nm +4 -4
  21. package/core/System/Stream/Directory.nm +189 -63
  22. package/core/System/Stream/DirectoryError.nm +21 -0
  23. package/core/System/Stream/File.nm +339 -141
  24. package/core/System/Stream/FileError.nm +21 -0
  25. package/core/System/Stream/Http.nm +109 -44
  26. package/core/System/Stream/HttpError.nm +20 -0
  27. package/core/System/String.nm +83 -69
  28. package/core/System/StringBuilder.nm +11 -13
  29. package/core/System/Task.nm +46 -12
  30. package/core/System/Test.nm +1 -1
  31. package/core/System/Text/Json.nm +5 -3
  32. package/core/System/Text/JsonTree.nm +23 -14
  33. package/core/System/Text/Regex.nm +124 -64
  34. package/core/System/Tree.nm +1 -1
  35. package/core/System/bool.nm +4 -9
  36. package/core/System/char.nm +3 -9
  37. package/core/System/float.nm +2 -1
  38. package/core/System/float32.nm +44 -0
  39. package/core/System/float64.nm +44 -0
  40. package/core/System/int.nm +3 -9
  41. package/core/System/int16.nm +47 -0
  42. package/core/System/int32.nm +47 -0
  43. package/core/System/int64.nm +3 -9
  44. package/core/System/int8.nm +3 -9
  45. package/core/System/ufloat.nm +44 -0
  46. package/core/System/ufloat32.nm +44 -0
  47. package/core/System/ufloat64.nm +44 -0
  48. package/core/System/uint.nm +3 -9
  49. package/core/System/uint16.nm +47 -0
  50. package/core/System/uint32.nm +47 -0
  51. package/core/System/uint64.nm +3 -9
  52. package/core/System/uint8.nm +3 -9
  53. package/core/docs/System/Channel.md +2 -0
  54. package/core/docs/System/Result.md +5 -1
  55. package/core/docs/System/Task.md +1 -1
  56. package/dist/index.mjs +38794 -21299
  57. package/package.json +38 -34
  58. package/src/args.ts +11 -0
  59. package/src/index.ts +21 -3
  60. package/src/init.ts +1 -1
  61. package/src/test.ts +48 -4
  62. package/src/types/Config.ts +2 -0
package/package.json CHANGED
@@ -1,35 +1,39 @@
1
1
  {
2
- "name": "nomen-lang",
3
- "version": "0.0.19",
4
- "description": "The CLI for the Nomen programming language.",
5
- "keywords": [],
6
- "license": "ISC",
7
- "author": "",
8
- "bin": {
9
- "nomen": "dist/index.mjs"
10
- },
11
- "files": [
12
- "dist",
13
- "src",
14
- "core",
15
- "NOMEN_AGENTS.md"
16
- ],
17
- "type": "module",
18
- "scripts": {
19
- "build": "node scripts/bundle-assets.mjs && vp pack",
20
- "dev": "node scripts/bundle-assets.mjs && vp pack --watch",
21
- "test": "vp test",
22
- "check": "vp check",
23
- "format": "vp check --fix",
24
- "prepare": "vp config",
25
- "go": "tsx src/index.ts",
26
- "register": "pnpm build && pnpm add -g ."
27
- },
28
- "devDependencies": {
29
- "@types/node": "^26.2.0",
30
- "chokidar": "^5.0.0",
31
- "tsx": "^4.23.12",
32
- "typescript": "^7.0.2",
33
- "vite-plus": "catalog:"
34
- }
35
- }
2
+ "name": "nomen-lang",
3
+ "version": "0.2.0",
4
+ "description": "The CLI for the Nomen programming language.",
5
+ "keywords": [],
6
+ "license": "ISC",
7
+ "author": "",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/andrewjk/nomen",
11
+ "directory": "cli"
12
+ },
13
+ "bin": {
14
+ "nomen": "dist/index.mjs"
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "src",
19
+ "core",
20
+ "NOMEN_AGENTS.md"
21
+ ],
22
+ "type": "module",
23
+ "devDependencies": {
24
+ "@types/node": "^26.2.0",
25
+ "chokidar": "^5.0.0",
26
+ "tsx": "^4.23.12",
27
+ "typescript": "^7.0.2",
28
+ "vite-plus": "0.2.9"
29
+ },
30
+ "scripts": {
31
+ "build": "node scripts/bundle-assets.mjs && vp pack",
32
+ "dev": "node scripts/bundle-assets.mjs && vp pack --watch",
33
+ "test": "vp test",
34
+ "check": "vp check",
35
+ "format": "vp check --fix",
36
+ "go": "tsx src/index.ts",
37
+ "register": "pnpm build && pnpm add -g ."
38
+ }
39
+ }
package/src/args.ts CHANGED
@@ -12,6 +12,10 @@ export interface Args {
12
12
  audit: boolean;
13
13
  audit_runtime?: string;
14
14
  check: boolean;
15
+ release: boolean;
16
+ /** Opt in to FP reassociation: float reductions vectorize under NEON
17
+ * (results may differ in the last ulp vs the scalar loop). */
18
+ fast_math: boolean;
15
19
  // Everything after a bare `--` on the command line — forwarded verbatim to
16
20
  // the compiled program by `nomen run`. Lets a program receive its own argv
17
21
  // (`nomen run --in app/main.nm -- arg1 arg2`).
@@ -42,6 +46,9 @@ const BOOLEAN_OPTIONS: Map<string, string> = new Map([
42
46
  ["w", "watch"],
43
47
  ["audit", "audit"],
44
48
  ["check", "check"],
49
+ ["release", "release"],
50
+ ["r", "release"],
51
+ ["fast-math", "fast_math"],
45
52
  ]);
46
53
 
47
54
  const DEFAULTS: Partial<Args> = {
@@ -49,6 +56,8 @@ const DEFAULTS: Partial<Args> = {
49
56
  watch: false,
50
57
  audit: false,
51
58
  check: false,
59
+ release: false,
60
+ fast_math: false,
52
61
  };
53
62
 
54
63
  function set(args: Args, key: string, value: string | boolean): void {
@@ -166,6 +175,8 @@ export function print_help(): void {
166
175
  " --lib, -l <path> Path to System library directory (containing package.jsonc)",
167
176
  " --audit Audit the generated program for memory issues",
168
177
  " --audit-runtime <path> Path to audit_runtime.c, linked in when --audit is set",
178
+ " --release, -r Build with optimizations (clang -O2; asm passes on aarch64)",
179
+ " --fast-math Allow FP reassociation (float loop reductions vectorize on aarch64)",
169
180
  " --check For `nomen format`: report files that would change",
170
181
  " -h, --help Show this help",
171
182
  ].join("\n"),
package/src/index.ts CHANGED
@@ -104,7 +104,12 @@ try {
104
104
  const root = args.in ?? process.cwd();
105
105
  const filter = args.filter ? new RegExp(args.filter) : undefined;
106
106
  const arch = args.arch ?? "aarch64";
107
- const ok = runTests(root, { arch, filter });
107
+ const ok = runTests(root, {
108
+ arch,
109
+ filter,
110
+ audit: args.audit,
111
+ audit_runtime: args.audit_runtime,
112
+ });
108
113
  process.exit(ok ? 0 : 1);
109
114
  }
110
115
 
@@ -163,6 +168,8 @@ try {
163
168
  if (args.lib) config.lib = args.lib;
164
169
  if (args.audit) config.audit = args.audit;
165
170
  if (args.audit_runtime) config.audit_runtime = args.audit_runtime;
171
+ if (args.release) config.release = args.release;
172
+ if (args.fast_math) config.fast_math = args.fast_math;
166
173
 
167
174
  // Is the --in path a folder
168
175
  if (fs.lstatSync(args.in).isDirectory()) {
@@ -349,7 +356,13 @@ function processFile(filename: string, config: Config, mode: Mode, program_args:
349
356
  return;
350
357
  }
351
358
 
352
- const result = build(parsed.root, { arch, platform, audit: config.audit });
359
+ const result = build(parsed.root, {
360
+ arch,
361
+ platform,
362
+ audit: config.audit,
363
+ optimize: config.release,
364
+ fast_math: config.fast_math,
365
+ });
353
366
 
354
367
  if (result.errors && result.errors.length > 0) {
355
368
  console.log(render_errors(input, result.errors));
@@ -391,7 +404,12 @@ function processFile(filename: string, config: Config, mode: Mode, program_args:
391
404
  platform === "macos" || platform === "ios"
392
405
  ? " -framework CoreGraphics -framework Foundation -framework AppKit -lobjc"
393
406
  : "";
394
- execSync(`clang -o ${outfile} ${link_inputs}${framework_flags}`);
407
+ // Release mode compiles the C (and aarch64 companion C) with -O2,
408
+ // matching the optimized builds other toolchains produce by default.
409
+ // The aarch64 .s itself is assembled verbatim — its optimizations are
410
+ // the codegen passes enabled via `optimize` above.
411
+ const opt_flags = config.release ? " -O2" : "";
412
+ execSync(`clang${opt_flags} -o ${outfile} ${link_inputs}${framework_flags}`);
395
413
 
396
414
  if (mode === "build") {
397
415
  const buildTime = performance.now();
package/src/init.ts CHANGED
@@ -31,7 +31,7 @@ pub func main = (Init init) {
31
31
  `;
32
32
 
33
33
  const TEST_NM = `import System
34
- import System/Test
34
+ import System::Test
35
35
 
36
36
  pub func test_add = (ref Tester t) {
37
37
  t.expect(add(2, 2) == 4, "2 + 2 should equal 4")
package/src/test.ts CHANGED
@@ -183,7 +183,7 @@ export function generate_harness(tests: TestFunction[], benches: BenchFunction[]
183
183
  })
184
184
  .join("\n");
185
185
 
186
- let main = "\nimport System\nimport System/Test\n\npub func main = () {\n";
186
+ let main = "\nimport System\nimport System::Test\n\npub func main = () {\n";
187
187
  main += "\tvar Tester t = Tester()\n";
188
188
  for (const test of tests) {
189
189
  main += `\tt.begin_test("${escape_nm_string(test.name)}")\n`;
@@ -259,6 +259,8 @@ export function run_test_file(
259
259
  entry_path: string,
260
260
  lib_path: string | undefined,
261
261
  arch: string,
262
+ audit = false,
263
+ audit_runtime?: string,
262
264
  ): TestFileResult {
263
265
  const start = performance.now();
264
266
  const source_text = fs.readFileSync(entry_path, "utf8");
@@ -294,7 +296,10 @@ export function run_test_file(
294
296
  return result;
295
297
  }
296
298
 
297
- const buildResult = build(parsed.root, { arch: arch as "aarch64" | "c", audit: false });
299
+ const buildResult = build(parsed.root, {
300
+ arch: arch as "aarch64" | "c",
301
+ audit,
302
+ });
298
303
  if (buildResult.errors && buildResult.errors.length) {
299
304
  result.ok = false;
300
305
  result.crashed = buildResult.errors
@@ -306,6 +311,24 @@ export function run_test_file(
306
311
 
307
312
  const buildDir = build_dir_for(resolved, true);
308
313
  if (!fs.existsSync(buildDir)) fs.mkdirSync(buildDir, { recursive: true });
314
+ // With --audit, compile the audit runtime (malloc/free counting) and link
315
+ // it in; the generated main calls nomen_audit_check() at exit, printing
316
+ // "LEAK: N allocation(s)" when the balance is nonzero.
317
+ let audit_obj: string | undefined;
318
+ if (audit) {
319
+ const runtime_src = audit_runtime
320
+ ? path.resolve(audit_runtime)
321
+ : find_audit_runtime(path.dirname(resolved));
322
+ if (!runtime_src || !fs.existsSync(runtime_src)) {
323
+ result.ok = false;
324
+ result.crashed =
325
+ "Audit enabled but audit_runtime.c was not found. Pass --audit-runtime <path>.";
326
+ result.ms = performance.now() - start;
327
+ return result;
328
+ }
329
+ audit_obj = path.join(buildDir, "audit_runtime.o");
330
+ execFileSync("clang", ["-c", runtime_src, "-o", audit_obj]);
331
+ }
309
332
  const ext = arch === "aarch64" ? ".s" : ".c";
310
333
  const codefile = path.join(buildDir, path.basename(entry_path, ".nm") + ext);
311
334
  const outfile = path.join(buildDir, path.basename(entry_path, ".nm"));
@@ -316,8 +339,10 @@ export function run_test_file(
316
339
 
317
340
  // Link the harness binary. The harness uses only Console/Time (printf,
318
341
  // clock_gettime), so no platform frameworks are required.
342
+ const link_args = ["-o", outfile, codefile];
343
+ if (audit_obj) link_args.push(audit_obj);
319
344
  try {
320
- execFileSync("clang", ["-o", outfile, codefile], {
345
+ execFileSync("clang", link_args, {
321
346
  encoding: "utf8",
322
347
  stdio: ["ignore", "pipe", "pipe"],
323
348
  });
@@ -427,6 +452,25 @@ export function report_file(result: TestFileResult): void {
427
452
  export interface RunTestsOptions {
428
453
  arch?: string;
429
454
  filter?: RegExp;
455
+ audit?: boolean;
456
+ audit_runtime?: string;
457
+ }
458
+
459
+ /**
460
+ * Locate audit_runtime.c for an audited test build: an explicit path wins,
461
+ * otherwise walk up from `dir` looking for a `src/audit_runtime.c` (the same
462
+ * convention the run/build commands use).
463
+ */
464
+ function find_audit_runtime(dir: string): string | undefined {
465
+ let cur = dir;
466
+ for (let i = 0; i < 20; i++) {
467
+ const candidate = path.join(cur, "src", "audit_runtime.c");
468
+ if (fs.existsSync(candidate)) return candidate;
469
+ const parent = path.dirname(cur);
470
+ if (parent === cur) break;
471
+ cur = parent;
472
+ }
473
+ return undefined;
430
474
  }
431
475
 
432
476
  /** Discover, run, and report every `*.test.nm` under `root`. */
@@ -441,7 +485,7 @@ export function runTests(root: string, options: RunTestsOptions = {}): boolean {
441
485
 
442
486
  const results: TestFileResult[] = [];
443
487
  for (const file of files) {
444
- const result = run_test_file(file, lib, arch);
488
+ const result = run_test_file(file, lib, arch, options.audit, options.audit_runtime);
445
489
  report_file(result);
446
490
  results.push(result);
447
491
  }
@@ -4,4 +4,6 @@ export default interface Config {
4
4
  lib?: string;
5
5
  audit?: boolean;
6
6
  audit_runtime?: string;
7
+ release?: boolean;
8
+ fast_math?: boolean;
7
9
  }