nomen-lang 0.0.6 → 0.0.8
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/NOMEN_AGENTS.md +235 -0
- package/core/System/Ansi.nm +150 -0
- package/core/System/Array.nm +358 -0
- package/core/System/BigInt.nm +887 -0
- package/core/System/Buffer.nm +526 -0
- package/core/System/Channel.nm +198 -0
- package/core/System/ClassBuffer.nm +229 -0
- package/core/System/Console.nm +211 -0
- package/core/System/Controls/Button.nm +138 -0
- package/core/System/Controls/CheckBox.nm +158 -0
- package/core/System/Controls/Container.nm +1562 -0
- package/core/System/Controls/Control.nm +28 -0
- package/core/System/Controls/Geometry.nm +101 -0
- package/core/System/Controls/Layout.nm +228 -0
- package/core/System/Controls/LayoutParams.nm +50 -0
- package/core/System/Controls/Text.nm +129 -0
- package/core/System/Controls/TextBox.nm +157 -0
- package/core/System/Controls/Window.nm +280 -0
- package/core/System/Disposable.nm +8 -0
- package/core/System/Enumerable.nm +10 -0
- package/core/System/Equatable.nm +10 -0
- package/core/System/Graph.nm +68 -0
- package/core/System/Hashable.nm +13 -0
- package/core/System/Init.nm +21 -0
- package/core/System/LinkedList.nm +64 -0
- package/core/System/List.nm +44 -0
- package/core/System/Map.nm +153 -0
- package/core/System/Math.nm +54 -0
- package/core/System/Mutex.nm +78 -0
- package/core/System/Nursery.nm +27 -0
- package/core/System/Sendable.nm +9 -0
- package/core/System/Set.nm +97 -0
- package/core/System/Stream/Directory.nm +176 -0
- package/core/System/Stream/File.nm +432 -0
- package/core/System/Stream/Http.nm +453 -0
- package/core/System/String.nm +154 -0
- package/core/System/StringBuilder.nm +249 -0
- package/core/System/Stringable.nm +8 -0
- package/core/System/Task.nm +263 -0
- package/core/System/Test.nm +241 -0
- package/core/System/Text/Json.nm +377 -0
- package/core/System/Text/JsonTree.nm +187 -0
- package/core/System/Text/Regex.nm +655 -0
- package/core/System/Time.nm +112 -0
- package/core/System/Tree.nm +70 -0
- package/core/System/Viewable.nm +27 -0
- package/core/System/bool.nm +66 -0
- package/core/System/char.nm +42 -0
- package/core/System/float.nm +43 -0
- package/core/System/int.nm +54 -0
- package/core/System/int64.nm +42 -0
- package/core/System/int8.nm +42 -0
- package/core/System/uint.nm +42 -0
- package/core/System/uint64.nm +42 -0
- package/core/System/uint8.nm +42 -0
- package/core/docs/System/Ansi.md +40 -0
- package/core/docs/System/Array.md +16 -0
- package/core/docs/System/BigInt.md +30 -0
- package/core/docs/System/Buffer.md +31 -0
- package/core/docs/System/Channel.md +10 -0
- package/core/docs/System/ClassBuffer.md +15 -0
- package/core/docs/System/Console.md +13 -0
- package/core/docs/System/Controls/Button.md +12 -0
- package/core/docs/System/Controls/CheckBox.md +15 -0
- package/core/docs/System/Controls/Container.md +82 -0
- package/core/docs/System/Controls/Control.md +5 -0
- package/core/docs/System/Controls/Geometry.md +26 -0
- package/core/docs/System/Controls/Layout.md +37 -0
- package/core/docs/System/Controls/LayoutParams.md +13 -0
- package/core/docs/System/Controls/Text.md +12 -0
- package/core/docs/System/Controls/TextBox.md +13 -0
- package/core/docs/System/Controls/Window.md +20 -0
- package/core/docs/System/Disposable.md +5 -0
- package/core/docs/System/Enumerable.md +5 -0
- package/core/docs/System/Graph.md +17 -0
- package/core/docs/System/Init.md +9 -0
- package/core/docs/System/LinkedList.md +16 -0
- package/core/docs/System/List.md +13 -0
- package/core/docs/System/Map.md +14 -0
- package/core/docs/System/Math.md +11 -0
- package/core/docs/System/Mutex.md +10 -0
- package/core/docs/System/Nursery.md +5 -0
- package/core/docs/System/Sendable.md +5 -0
- package/core/docs/System/Set.md +14 -0
- package/core/docs/System/Stream/Directory.md +12 -0
- package/core/docs/System/Stream/File.md +21 -0
- package/core/docs/System/String.md +14 -0
- package/core/docs/System/StringBuilder.md +12 -0
- package/core/docs/System/Stringable.md +5 -0
- package/core/docs/System/Task.md +15 -0
- package/core/docs/System/Text/Json.md +12 -0
- package/core/docs/System/Text/JsonTree.md +21 -0
- package/core/docs/System/Text/Regex.md +12 -0
- package/core/docs/System/Time.md +11 -0
- package/core/docs/System/Tree.md +18 -0
- package/core/docs/System/Viewable.md +5 -0
- package/core/docs/System/bool.md +9 -0
- package/core/docs/System/char.md +9 -0
- package/core/docs/System/float.md +9 -0
- package/core/docs/System/int.md +10 -0
- package/core/docs/System/int64.md +9 -0
- package/core/docs/System/int8.md +9 -0
- package/core/docs/System/uint.md +9 -0
- package/core/docs/System/uint64.md +9 -0
- package/core/docs/System/uint8.md +9 -0
- package/core/package.jsonc +4 -0
- package/dist/index.mjs +17039 -21482
- package/package.json +33 -30
- package/src/args.ts +171 -0
- package/src/bench_loop.nm +113 -0
- package/src/index.ts +61 -95
- package/src/init.ts +128 -0
- package/src/test.ts +522 -0
- package/tsconfig.json +0 -21
- package/vite.config.ts +0 -7
package/package.json
CHANGED
|
@@ -1,31 +1,34 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
2
|
+
"name": "nomen-lang",
|
|
3
|
+
"version": "0.0.8",
|
|
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
|
+
"devDependencies": {
|
|
19
|
+
"@types/node": "^26.1.2",
|
|
20
|
+
"chokidar": "^5.0.0",
|
|
21
|
+
"tsx": "^4.23.1",
|
|
22
|
+
"typescript": "^7.0.2",
|
|
23
|
+
"vite-plus": "0.2.7"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "node scripts/bundle-assets.mjs && vp pack",
|
|
27
|
+
"dev": "node scripts/bundle-assets.mjs && vp pack --watch",
|
|
28
|
+
"test": "vp test",
|
|
29
|
+
"check": "vp check",
|
|
30
|
+
"format": "vp check --fix",
|
|
31
|
+
"go": "tsx src/index.ts",
|
|
32
|
+
"register": "pnpm build && pnpm add -g ."
|
|
33
|
+
}
|
|
34
|
+
}
|
package/src/args.ts
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
export interface Args {
|
|
2
|
+
command: string | undefined;
|
|
3
|
+
name?: string;
|
|
4
|
+
in?: string;
|
|
5
|
+
out?: string;
|
|
6
|
+
config?: string;
|
|
7
|
+
watch: boolean;
|
|
8
|
+
filter?: string;
|
|
9
|
+
arch: string;
|
|
10
|
+
platform?: string;
|
|
11
|
+
lib?: string;
|
|
12
|
+
audit: boolean;
|
|
13
|
+
audit_runtime?: string;
|
|
14
|
+
check: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Canonical option name for each accepted long/short spelling.
|
|
18
|
+
const STRING_OPTIONS: Map<string, string> = new Map([
|
|
19
|
+
["in", "in"],
|
|
20
|
+
["i", "in"],
|
|
21
|
+
["out", "out"],
|
|
22
|
+
["o", "out"],
|
|
23
|
+
["config", "config"],
|
|
24
|
+
["c", "config"],
|
|
25
|
+
["filter", "filter"],
|
|
26
|
+
["f", "filter"],
|
|
27
|
+
["arch", "arch"],
|
|
28
|
+
["a", "arch"],
|
|
29
|
+
["platform", "platform"],
|
|
30
|
+
["p", "platform"],
|
|
31
|
+
["lib", "lib"],
|
|
32
|
+
["l", "lib"],
|
|
33
|
+
["audit-runtime", "audit_runtime"],
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
const BOOLEAN_OPTIONS: Map<string, string> = new Map([
|
|
37
|
+
["watch", "watch"],
|
|
38
|
+
["w", "watch"],
|
|
39
|
+
["audit", "audit"],
|
|
40
|
+
["check", "check"],
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
const DEFAULTS: Partial<Args> = {
|
|
44
|
+
arch: "aarch64",
|
|
45
|
+
watch: false,
|
|
46
|
+
audit: false,
|
|
47
|
+
check: false,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
function set(args: Args, key: string, value: string | boolean): void {
|
|
51
|
+
(args as unknown as Record<string, string | boolean>)[key] = value;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Parse `argv` (excluding the node binary and script path) into an `Args` object. */
|
|
55
|
+
export function parse_args(argv: string[] = process.argv.slice(2)): Args {
|
|
56
|
+
const args: Args = { command: undefined, ...DEFAULTS } as Args;
|
|
57
|
+
const positional: string[] = [];
|
|
58
|
+
let only_positional = false;
|
|
59
|
+
|
|
60
|
+
const next_value = (i: number, spelling: string): string => {
|
|
61
|
+
if (i + 1 >= argv.length) throw new Error(`Option ${spelling} requires a value`);
|
|
62
|
+
return argv[i + 1];
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
for (let i = 0; i < argv.length; i++) {
|
|
66
|
+
const arg = argv[i];
|
|
67
|
+
|
|
68
|
+
if (only_positional) {
|
|
69
|
+
positional.push(arg);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (arg === "--") {
|
|
74
|
+
only_positional = true;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (arg === "-h" || arg === "--help") {
|
|
79
|
+
print_help();
|
|
80
|
+
process.exit(0);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Long option: --name, --name=value, or --name value
|
|
84
|
+
if (arg.startsWith("--") && arg.length > 2) {
|
|
85
|
+
const eq = arg.indexOf("=");
|
|
86
|
+
const name = eq === -1 ? arg.slice(2) : arg.slice(2, eq);
|
|
87
|
+
const inline = eq === -1 ? undefined : arg.slice(eq + 1);
|
|
88
|
+
|
|
89
|
+
if (STRING_OPTIONS.has(name)) {
|
|
90
|
+
const key = STRING_OPTIONS.get(name)!;
|
|
91
|
+
set(args, key, inline !== undefined ? inline : next_value(i, `--${name}`));
|
|
92
|
+
if (inline === undefined) i++;
|
|
93
|
+
} else if (BOOLEAN_OPTIONS.has(name)) {
|
|
94
|
+
const key = BOOLEAN_OPTIONS.get(name)!;
|
|
95
|
+
set(args, key, inline === undefined ? true : inline !== "false");
|
|
96
|
+
} else {
|
|
97
|
+
throw new Error(`Unknown option: --${name}`);
|
|
98
|
+
}
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Short option(s): -i value, -ivalue, -i=value, or combined -wv
|
|
103
|
+
if (arg.startsWith("-") && arg.length > 1 && !/^-\d/.test(arg)) {
|
|
104
|
+
const chars = arg.slice(1);
|
|
105
|
+
for (let j = 0; j < chars.length; j++) {
|
|
106
|
+
const c = chars[j];
|
|
107
|
+
|
|
108
|
+
if (c === "h") {
|
|
109
|
+
print_help();
|
|
110
|
+
process.exit(0);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (STRING_OPTIONS.has(c)) {
|
|
114
|
+
const key = STRING_OPTIONS.get(c)!;
|
|
115
|
+
const rest = chars.slice(j + 1);
|
|
116
|
+
if (rest.length > 0) {
|
|
117
|
+
set(args, key, rest.startsWith("=") ? rest.slice(1) : rest);
|
|
118
|
+
} else {
|
|
119
|
+
set(args, key, next_value(i, `-${c}`));
|
|
120
|
+
i++;
|
|
121
|
+
}
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (BOOLEAN_OPTIONS.has(c)) {
|
|
126
|
+
set(args, BOOLEAN_OPTIONS.get(c)!, true);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
throw new Error(`Unknown option: -${c}`);
|
|
131
|
+
}
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
positional.push(arg);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
args.command = positional[0];
|
|
139
|
+
args.name = positional[1];
|
|
140
|
+
return args;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function print_help(): void {
|
|
144
|
+
console.log(
|
|
145
|
+
[
|
|
146
|
+
"Usage:",
|
|
147
|
+
" nomen run --in [file/folder] Parse, check, build and run a program",
|
|
148
|
+
" nomen build --in [file/folder] Parse, check and build (no run)",
|
|
149
|
+
" nomen check --in [file/folder] Parse and check only",
|
|
150
|
+
" nomen format [--in folder] Reformat every .nm file",
|
|
151
|
+
" nomen docs [--in file] Generate markdown documentation",
|
|
152
|
+
" nomen test [--in folder] Discover and run *.test.nm files",
|
|
153
|
+
" nomen init <name> Scaffold a new project in ./<name>",
|
|
154
|
+
" nomen lib-path Print the bundled System library path",
|
|
155
|
+
"",
|
|
156
|
+
"Options:",
|
|
157
|
+
" --in, -i <path> Input file or folder",
|
|
158
|
+
" --out, -o <path> Output file",
|
|
159
|
+
" --config, -c <path> Path to a config file",
|
|
160
|
+
" --watch, -w Watch for file changes",
|
|
161
|
+
" --filter, -f <regex> Only run test files whose path matches this regex",
|
|
162
|
+
" --arch, -a <arch> Target architecture: aarch64 | c (default: aarch64)",
|
|
163
|
+
" --platform, -p <name> Target platform: macos, ios, linux, android, windows, web",
|
|
164
|
+
" --lib, -l <path> Path to System library directory (containing package.jsonc)",
|
|
165
|
+
" --audit Audit the generated program for memory issues",
|
|
166
|
+
" --audit-runtime <path> Path to audit_runtime.c, linked in when --audit is set",
|
|
167
|
+
" --check For `nomen format`: report files that would change",
|
|
168
|
+
" -h, --help Show this help",
|
|
169
|
+
].join("\n"),
|
|
170
|
+
);
|
|
171
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// Template for one benchmark's timing loop. The CLI substitutes __NAME__,
|
|
2
|
+
// __TARGET__ and __N__ and concatenates this after the test file's source
|
|
3
|
+
// (so it is user code and can call the test file's functions). Kept as a
|
|
4
|
+
// separate .nm file (not a TS template literal) because Nomen's generic syntax
|
|
5
|
+
// (List<int>) is not valid TypeScript and would break the CLI's own build.
|
|
6
|
+
//
|
|
7
|
+
// Placeholders use the leading-AND-trailing `__NAME__` convention so they don't
|
|
8
|
+
// collide with the `__w` / `__i` / `__samples` locals (leading-only).
|
|
9
|
+
//
|
|
10
|
+
// min / max / sum / sum-of-squares are tracked as running aggregates during
|
|
11
|
+
// sampling, so mean and stddev need no `List.at` calls at all. Only the median
|
|
12
|
+
// needs sorted data, so the samples are insertion-sorted afterwards. Every
|
|
13
|
+
// `List.at` / `List.set` is guarded by `idx >= 0 && idx < __samples.length` —
|
|
14
|
+
// the exact bound `List.at`'s constraint requires — because the constraint
|
|
15
|
+
// checker treats an unverifiable index as an out-of-bounds risk (the backends
|
|
16
|
+
// emit unchecked strided loads).
|
|
17
|
+
func bench_loop___NAME__ = (ref Tester t) {
|
|
18
|
+
// Warm up so the first samples don't pay for cold caches / lazy binding.
|
|
19
|
+
var int __w = 0
|
|
20
|
+
while __w < 8 {
|
|
21
|
+
__TARGET__()
|
|
22
|
+
__w += 1
|
|
23
|
+
}
|
|
24
|
+
// Collect __N__ samples, tracking running aggregates for every statistic
|
|
25
|
+
// except the median (which needs sorted data).
|
|
26
|
+
var List<int> __samples = List<int>()
|
|
27
|
+
var int __sum = 0
|
|
28
|
+
var float __sum_sq = 0.0
|
|
29
|
+
var int __min = 0
|
|
30
|
+
var int __max = 0
|
|
31
|
+
var int __i = 0
|
|
32
|
+
while __i < __N__ {
|
|
33
|
+
const uint64 __t0 = Time.now_ns()
|
|
34
|
+
__TARGET__()
|
|
35
|
+
const uint64 __t1 = Time.now_ns()
|
|
36
|
+
const int __dt = (__t1 - __t0) as int
|
|
37
|
+
__samples.push(__dt)
|
|
38
|
+
__sum += __dt
|
|
39
|
+
__sum_sq = __sum_sq + (__dt as float) * (__dt as float)
|
|
40
|
+
if __i == 0 {
|
|
41
|
+
__min = __dt
|
|
42
|
+
__max = __dt
|
|
43
|
+
}
|
|
44
|
+
if __i > 0 {
|
|
45
|
+
if __dt < __min {
|
|
46
|
+
__min = __dt
|
|
47
|
+
}
|
|
48
|
+
if __dt > __max {
|
|
49
|
+
__max = __dt
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
__i += 1
|
|
53
|
+
}
|
|
54
|
+
const int __n = __samples.length
|
|
55
|
+
if __n > 0 {
|
|
56
|
+
const float __fn = __n as float
|
|
57
|
+
const float __mean = (__sum as float) / __fn
|
|
58
|
+
var float __variance = __sum_sq / __fn - __mean * __mean
|
|
59
|
+
if __variance < 0.0 {
|
|
60
|
+
__variance = 0.0
|
|
61
|
+
}
|
|
62
|
+
const float __stddev = Math.sqrt(__variance)
|
|
63
|
+
// Insertion sort the samples so we can pick a median. `length` is
|
|
64
|
+
// stable throughout (only `set` mutates), so every access is guarded
|
|
65
|
+
// against `__samples.length` directly.
|
|
66
|
+
var int __s = 1
|
|
67
|
+
while __s < __n {
|
|
68
|
+
if __s >= 0 && __s < __samples.length {
|
|
69
|
+
const int __v = __samples.at(__s)
|
|
70
|
+
var int __j = __s
|
|
71
|
+
var bool __more = true
|
|
72
|
+
while __more {
|
|
73
|
+
var int __pm1 = __j - 1
|
|
74
|
+
if __pm1 >= 0 && __pm1 < __samples.length {
|
|
75
|
+
const int __prev = __samples.at(__pm1)
|
|
76
|
+
if __prev > __v {
|
|
77
|
+
if __j >= 0 && __j < __samples.length {
|
|
78
|
+
__samples.set(__j, __prev)
|
|
79
|
+
}
|
|
80
|
+
__j -= 1
|
|
81
|
+
} else {
|
|
82
|
+
__more = false
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
__more = false
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if __j >= 0 && __j < __samples.length {
|
|
89
|
+
__samples.set(__j, __v)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
__s += 1
|
|
93
|
+
}
|
|
94
|
+
// Median of the sorted samples. Indices are precomputed into locals so
|
|
95
|
+
// the guards are simple variable bounds.
|
|
96
|
+
var int __median = __min
|
|
97
|
+
var int __hi = __n / 2
|
|
98
|
+
if __hi >= 0 && __hi < __samples.length {
|
|
99
|
+
__median = __samples.at(__hi)
|
|
100
|
+
}
|
|
101
|
+
if __n % 2 == 0 {
|
|
102
|
+
var int __lo = __n / 2 - 1
|
|
103
|
+
if __lo >= 0 && __lo < __samples.length {
|
|
104
|
+
if __hi >= 0 && __hi < __samples.length {
|
|
105
|
+
var int __a = __samples.at(__lo)
|
|
106
|
+
var int __b = __samples.at(__hi)
|
|
107
|
+
__median = (__a + __b) / 2
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
t.record_bench(t.bench_label, __n, __min, __median, __max, __mean, __stddev)
|
|
112
|
+
}
|
|
113
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -4,16 +4,17 @@ import fs from "node:fs";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
|
|
6
6
|
import chokidar from "chokidar";
|
|
7
|
-
import { hideBin } from "yargs/helpers";
|
|
8
|
-
import yargs from "yargs/yargs";
|
|
9
7
|
|
|
10
8
|
import build, { default_platform } from "../../src/build.ts";
|
|
11
9
|
import { format_source, type FormatOptions } from "../../src/format.ts";
|
|
12
10
|
import join from "../../src/join.ts";
|
|
13
11
|
import { get_library } from "../../src/lib.ts";
|
|
14
12
|
import parse from "../../src/parse.ts";
|
|
13
|
+
import { parse_args, print_help, type Args } from "./args.ts";
|
|
15
14
|
import { run_docs } from "./docs.ts";
|
|
16
15
|
import render_errors, { render_warnings } from "./format_errors.ts";
|
|
16
|
+
import { find_bundled, run_init } from "./init.ts";
|
|
17
|
+
import { runTests } from "./test.ts";
|
|
17
18
|
import type Config from "./types/Config.ts";
|
|
18
19
|
|
|
19
20
|
const SUPPORTED_EXTENSION = ".nm";
|
|
@@ -72,84 +73,48 @@ let build_root: string | undefined;
|
|
|
72
73
|
|
|
73
74
|
console.log("\n~ NOMEN ~\n");
|
|
74
75
|
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
"Usage:\n" +
|
|
78
|
-
" nomen run --in [file/folder] Parse, check, build and run a program\n" +
|
|
79
|
-
" nomen build --in [file/folder] Parse, check and build (no run)\n" +
|
|
80
|
-
" nomen check --in [file/folder] Parse and check only\n" +
|
|
81
|
-
" nomen format [--in folder] Reformat every .nm file\n" +
|
|
82
|
-
" nomen docs [--in file] Generate markdown documentation",
|
|
83
|
-
)
|
|
84
|
-
.command("run", "Parse, check, build and run a program")
|
|
85
|
-
.command("build", "Parse, check and build (compile and link, but do not run)")
|
|
86
|
-
.command("check", "Parse and check only")
|
|
87
|
-
.command("format", "Reformat every .nm file")
|
|
88
|
-
.command("docs", "Generate markdown documentation")
|
|
89
|
-
.option("in", {
|
|
90
|
-
alias: "i",
|
|
91
|
-
describe: "Input file or folder",
|
|
92
|
-
type: "string",
|
|
93
|
-
})
|
|
94
|
-
.option("out", {
|
|
95
|
-
alias: "o",
|
|
96
|
-
describe: "Output file",
|
|
97
|
-
type: "string",
|
|
98
|
-
})
|
|
99
|
-
.option("config", {
|
|
100
|
-
alias: "c",
|
|
101
|
-
describe: "The path to a config file",
|
|
102
|
-
type: "string",
|
|
103
|
-
})
|
|
104
|
-
.option("watch", {
|
|
105
|
-
alias: "w",
|
|
106
|
-
describe: "Whether to watch for file changes",
|
|
107
|
-
type: "boolean",
|
|
108
|
-
})
|
|
109
|
-
.option("arch", {
|
|
110
|
-
alias: "a",
|
|
111
|
-
describe: "Target architecture (aarch64 or c)",
|
|
112
|
-
type: "string",
|
|
113
|
-
default: "aarch64",
|
|
114
|
-
})
|
|
115
|
-
.option("platform", {
|
|
116
|
-
alias: "p",
|
|
117
|
-
describe: "Target platform (macos, ios, linux, android, windows, web)",
|
|
118
|
-
type: "string",
|
|
119
|
-
})
|
|
120
|
-
.option("lib", {
|
|
121
|
-
alias: "l",
|
|
122
|
-
describe: "Path to System library directory (containing package.jsonc)",
|
|
123
|
-
type: "string",
|
|
124
|
-
})
|
|
125
|
-
.option("audit", {
|
|
126
|
-
describe: "Whether to audit the generated program for memory issues",
|
|
127
|
-
type: "boolean",
|
|
128
|
-
})
|
|
129
|
-
.option("audit-runtime", {
|
|
130
|
-
describe: "Path to audit_runtime.c, linked in when --audit is set",
|
|
131
|
-
type: "string",
|
|
132
|
-
})
|
|
133
|
-
.option("check", {
|
|
134
|
-
describe: "For `nomen format`: report files that would change without writing them",
|
|
135
|
-
type: "boolean",
|
|
136
|
-
})
|
|
137
|
-
.help(true);
|
|
138
|
-
|
|
139
|
-
const options = parser.parseSync();
|
|
140
|
-
|
|
141
|
-
const command = options._[0];
|
|
76
|
+
const args: Args = parse_args();
|
|
77
|
+
const command = args.command;
|
|
142
78
|
|
|
143
79
|
try {
|
|
80
|
+
// `nomen init <name>` scaffolds a new project under ./<name>.
|
|
81
|
+
if (command === "init") {
|
|
82
|
+
run_init(args.name);
|
|
83
|
+
process.exit(0);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// `nomen lib-path` prints the absolute path to the System library
|
|
87
|
+
// bundled with this CLI. Used by tooling (e.g. the VS Code extension)
|
|
88
|
+
// to locate the standard library for projects without a local one.
|
|
89
|
+
if (command === "lib-path") {
|
|
90
|
+
const lib = find_bundled("core");
|
|
91
|
+
if (lib) {
|
|
92
|
+
process.stdout.write(lib + "\n");
|
|
93
|
+
process.exit(0);
|
|
94
|
+
}
|
|
95
|
+
console.log("No bundled System library found alongside the CLI.");
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
|
|
144
99
|
// `nomen docs` generates markdown documentation instead of compiling.
|
|
145
100
|
if (command === "docs") {
|
|
146
|
-
run_docs(
|
|
101
|
+
run_docs(args.in);
|
|
147
102
|
process.exit(0);
|
|
148
103
|
}
|
|
149
104
|
|
|
105
|
+
// `nomen test` discovers and runs every `*.test.nm` file under --in (or
|
|
106
|
+
// the cwd), compiling each into a Tester harness and reporting results.
|
|
107
|
+
if (command === "test") {
|
|
108
|
+
const root = args.in ?? process.cwd();
|
|
109
|
+
const filter = args.filter ? new RegExp(args.filter) : undefined;
|
|
110
|
+
const arch = args.arch ?? "aarch64";
|
|
111
|
+
const ok = runTests(root, { arch, filter });
|
|
112
|
+
process.exit(ok ? 0 : 1);
|
|
113
|
+
}
|
|
114
|
+
|
|
150
115
|
// `nomen format` re-indents and tidies every .nm file under a folder.
|
|
151
116
|
if (command === "format") {
|
|
152
|
-
const root =
|
|
117
|
+
const root = args.in ?? process.cwd();
|
|
153
118
|
const format_options = load_format_options(root);
|
|
154
119
|
const files = collect_nm_files(root);
|
|
155
120
|
let changed = 0;
|
|
@@ -161,7 +126,7 @@ try {
|
|
|
161
126
|
continue;
|
|
162
127
|
}
|
|
163
128
|
if (result.changed) {
|
|
164
|
-
if (!
|
|
129
|
+
if (!args.check) fs.writeFileSync(file, result.code);
|
|
165
130
|
changed += 1;
|
|
166
131
|
console.log(`Formatted ${file}`);
|
|
167
132
|
}
|
|
@@ -179,59 +144,59 @@ try {
|
|
|
179
144
|
else if (command === "check") mode = "check";
|
|
180
145
|
|
|
181
146
|
if (!mode) {
|
|
182
|
-
|
|
147
|
+
print_help();
|
|
183
148
|
process.exit(1);
|
|
184
149
|
}
|
|
185
150
|
|
|
186
151
|
// An explicit --in wins; otherwise discover what to compile from the
|
|
187
152
|
// working folder — a package.jsonc `entry`, or a lone .nm file.
|
|
188
|
-
|
|
189
|
-
if (!
|
|
153
|
+
args.in = args.in ?? resolve_input();
|
|
154
|
+
if (!args.in) {
|
|
190
155
|
process.exit(0);
|
|
191
156
|
}
|
|
192
157
|
// For an explicit --in, build next to whatever was passed (the folder
|
|
193
158
|
// itself, or the file's folder). Discovery cases set build_root themselves.
|
|
194
159
|
if (!build_root) {
|
|
195
|
-
build_root = fs.lstatSync(
|
|
160
|
+
build_root = fs.lstatSync(args.in).isDirectory() ? args.in : path.dirname(args.in);
|
|
196
161
|
}
|
|
197
162
|
|
|
198
|
-
if (fs.existsSync(
|
|
163
|
+
if (fs.existsSync(args.in)) {
|
|
199
164
|
let config: Config = { arch: "aarch64", platform: default_platform() };
|
|
200
165
|
// Load the config from a file
|
|
201
|
-
if (
|
|
202
|
-
config = JSON.parse(fs.readFileSync(
|
|
166
|
+
if (args.config && fs.existsSync(args.config)) {
|
|
167
|
+
config = JSON.parse(fs.readFileSync(args.config, "utf-8"));
|
|
203
168
|
}
|
|
204
169
|
// Overwrite with args
|
|
205
|
-
if (
|
|
206
|
-
if (
|
|
207
|
-
if (
|
|
208
|
-
if (
|
|
209
|
-
if (
|
|
170
|
+
if (args.arch) config.arch = args.arch as "aarch64" | "c";
|
|
171
|
+
if (args.platform) config.platform = args.platform;
|
|
172
|
+
if (args.lib) config.lib = args.lib;
|
|
173
|
+
if (args.audit) config.audit = args.audit;
|
|
174
|
+
if (args.audit_runtime) config.audit_runtime = args.audit_runtime;
|
|
210
175
|
|
|
211
176
|
// Is the --in path a folder
|
|
212
|
-
if (fs.lstatSync(
|
|
213
|
-
if (
|
|
214
|
-
watchPath(
|
|
177
|
+
if (fs.lstatSync(args.in).isDirectory()) {
|
|
178
|
+
if (args.watch) {
|
|
179
|
+
watchPath(args.in, config, mode);
|
|
215
180
|
} else {
|
|
216
|
-
processFolder(
|
|
181
|
+
processFolder(args.in, config, mode);
|
|
217
182
|
}
|
|
218
183
|
} else {
|
|
219
184
|
// Process the supplied file
|
|
220
|
-
const extname = path.extname(
|
|
221
|
-
if (shouldProcessFile(
|
|
185
|
+
const extname = path.extname(args.in);
|
|
186
|
+
if (shouldProcessFile(args.in)) {
|
|
222
187
|
// NOTE: We get add notifications for all watched files immediately
|
|
223
188
|
// TODO: Is this the case on Windows etc too?
|
|
224
|
-
if (
|
|
225
|
-
watchPath(
|
|
189
|
+
if (args.watch) {
|
|
190
|
+
watchPath(args.in, config, mode);
|
|
226
191
|
} else {
|
|
227
|
-
processFile(
|
|
192
|
+
processFile(args.in, config, mode);
|
|
228
193
|
}
|
|
229
194
|
} else {
|
|
230
195
|
console.log("Unsupported file type: " + extname);
|
|
231
196
|
}
|
|
232
197
|
}
|
|
233
198
|
} else {
|
|
234
|
-
console.log("Path not found: " +
|
|
199
|
+
console.log("Path not found: " + args.in);
|
|
235
200
|
}
|
|
236
201
|
} catch (err) {
|
|
237
202
|
console.log("UH", err);
|
|
@@ -303,7 +268,8 @@ function resolve_lib(file_path: string): string | undefined {
|
|
|
303
268
|
if (parent === dir) break;
|
|
304
269
|
dir = parent;
|
|
305
270
|
}
|
|
306
|
-
|
|
271
|
+
// Nothing local — fall back to the System library bundled with the CLI.
|
|
272
|
+
return find_bundled("core");
|
|
307
273
|
}
|
|
308
274
|
|
|
309
275
|
function resolve_audit_runtime(config: Config, input_path: string): string | undefined {
|