nomen-lang 0.6.0 → 0.6.1
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/core/System/StringBuilder.nm +115 -0
- package/core/System/Text/Regex.nm +55 -27
- package/dist/index.mjs +35 -4
- package/package.json +1 -1
- package/src/test.ts +22 -4
|
@@ -120,6 +120,121 @@ pub struct StringBuilder {
|
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
// Read-back: how many bytes the buffer currently holds. (The `len` field
|
|
124
|
+
// is private; this is the O(1) peek the incremental-builder flow needs —
|
|
125
|
+
// e.g. recording a mark before appending a section.)
|
|
126
|
+
pub func length = (self, out int) {
|
|
127
|
+
return self.len
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Whether the buffer's current bytes end with `suffix` (an empty suffix
|
|
131
|
+
// is always true). Reads the buffer tail in place — no copy of either
|
|
132
|
+
// side (`view string` avoids materializing the checked suffix).
|
|
133
|
+
pub func ends_with = (ref self, view string suffix, out bool) {
|
|
134
|
+
unsafe {
|
|
135
|
+
var int sl = suffix.length
|
|
136
|
+
if sl > self.len {
|
|
137
|
+
return false
|
|
138
|
+
}
|
|
139
|
+
var int start = self.len - sl
|
|
140
|
+
var int i = 0
|
|
141
|
+
while i < sl; i += 1 {
|
|
142
|
+
if (self.data as ptr char)[start + i] != (suffix as ptr char)[i] {
|
|
143
|
+
return false
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return true
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Truncate the buffer to `new_len` bytes (clamped to [0, len]). Capacity
|
|
151
|
+
// is kept, so a subsequent append reuses the storage without a realloc.
|
|
152
|
+
pub func truncate = (ref self, int new_len) {
|
|
153
|
+
var int n = new_len
|
|
154
|
+
if n < 0 {
|
|
155
|
+
n = 0
|
|
156
|
+
}
|
|
157
|
+
if n > self.len {
|
|
158
|
+
n = self.len
|
|
159
|
+
}
|
|
160
|
+
self.len = n
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Drop the last byte (a no-op when the buffer is empty). The common
|
|
164
|
+
// chomp-the-trailing-separator shape.
|
|
165
|
+
pub func chomp = (ref self) {
|
|
166
|
+
if self.len > 0 {
|
|
167
|
+
self.len = self.len - 1
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Extract the bytes from `mark` to the end as a fresh owned string and
|
|
172
|
+
// rewind the buffer to `mark` bytes (capacity kept). The mid-render
|
|
173
|
+
// measure-and-restart shape: record `length()`, append a section, then
|
|
174
|
+
// `take_since(mark)` to measure it and re-emit decorated. `mark` clamps
|
|
175
|
+
// to [0, len]; the returned string is always an independent allocation.
|
|
176
|
+
// (`move out string` — the raw body mallocs the result, so the caller
|
|
177
|
+
// owns it by signature, like `Console.read_line`.)
|
|
178
|
+
func take_since = (ref self, int mark, move out string) {
|
|
179
|
+
```
|
|
180
|
+
#arch: c
|
|
181
|
+
int start = mark;
|
|
182
|
+
if (start < 0) start = 0;
|
|
183
|
+
if (start > self->len) start = self->len;
|
|
184
|
+
int n = self->len - start;
|
|
185
|
+
char* buf = (char*)malloc((size_t)n + 1);
|
|
186
|
+
if (n > 0) memcpy(buf, (void*)(unsigned long long)(self->data + start), n);
|
|
187
|
+
buf[n] = 0;
|
|
188
|
+
self->len = start;
|
|
189
|
+
// Fat-string ABI: return the (ptr, len) pair — no strlen.
|
|
190
|
+
return (nomen_string){ buf, n };
|
|
191
|
+
```
|
|
192
|
+
```
|
|
193
|
+
#arch: aarch64
|
|
194
|
+
// x19 = self, x1 = mark. Clamp start to [0, len]; malloc(n+1),
|
|
195
|
+
// copy the tail, null-terminate, rewind len. Live values live in a
|
|
196
|
+
// 32-byte (16-aligned) frame across the calls (x0-x18 are
|
|
197
|
+
// caller-saved): [sp]=start, [sp+8]=n, [sp+16]=buf.
|
|
198
|
+
ldr x2, [x19, #16] // len
|
|
199
|
+
mov x3, x1 // start = mark
|
|
200
|
+
cmp x3, #0
|
|
201
|
+
b.ge .Lsb_tk_hi
|
|
202
|
+
mov x3, #0
|
|
203
|
+
.Lsb_tk_hi:
|
|
204
|
+
cmp x3, x2
|
|
205
|
+
b.le .Lsb_tk_ok
|
|
206
|
+
mov x3, x2 // start = min(start, len)
|
|
207
|
+
.Lsb_tk_ok:
|
|
208
|
+
sub x4, x2, x3 // n = len - start
|
|
209
|
+
sub sp, sp, #32
|
|
210
|
+
str x3, [sp, #0] // start
|
|
211
|
+
str x4, [sp, #8] // n
|
|
212
|
+
add x0, x4, #1
|
|
213
|
+
// buf = malloc(n + 1) — bare call line: the audit pass rewrites
|
|
214
|
+
// `bl _malloc` (line-exact) to the counter-wrapped allocator.
|
|
215
|
+
bl _malloc
|
|
216
|
+
str x0, [sp, #16]
|
|
217
|
+
ldr x1, [sp, #8] // n
|
|
218
|
+
cbz x1, .Lsb_tk_copied
|
|
219
|
+
ldr x0, [sp, #16] // dst = buf
|
|
220
|
+
ldr x3, [x19, #8] // data
|
|
221
|
+
ldr x4, [sp, #0] // start
|
|
222
|
+
add x1, x3, x4 // src = data + start
|
|
223
|
+
ldr x2, [sp, #8] // n
|
|
224
|
+
bl _memcpy
|
|
225
|
+
.Lsb_tk_copied:
|
|
226
|
+
ldr x0, [sp, #16] // buf
|
|
227
|
+
ldr x1, [sp, #8] // n
|
|
228
|
+
add x2, x0, x1
|
|
229
|
+
strb wzr, [x2] // buf[n] = 0
|
|
230
|
+
ldr x3, [sp, #0] // start
|
|
231
|
+
str x3, [x19, #16] // len = start
|
|
232
|
+
ldr x0, [sp, #16] // return pair: (buf, n)
|
|
233
|
+
ldr x1, [sp, #8]
|
|
234
|
+
add sp, sp, #32
|
|
235
|
+
```
|
|
236
|
+
}
|
|
237
|
+
|
|
123
238
|
// Finalize: null-terminate, return the byte buffer as a string, and
|
|
124
239
|
// release ownership (sets `data` to 0 so the destructor won't free it).
|
|
125
240
|
func to_string = (ref self, out string) {
|
|
@@ -469,10 +469,10 @@ func collect_first_bytes = (
|
|
|
469
469
|
//
|
|
470
470
|
// Handles the shapes the engine's matcher can produce: a leading anchor is
|
|
471
471
|
// zero-width (skipped), a leading group contributes its CONTENT's first bytes
|
|
472
|
-
// (recursively over the group's own top-level alternatives), and
|
|
473
|
-
// quantified with '?'/'*' is
|
|
474
|
-
//
|
|
475
|
-
// set indeterminable.
|
|
472
|
+
// (recursively over the group's own top-level alternatives), and ANY leading
|
|
473
|
+
// atom — literal, escaped, class, or group — quantified with '?'/'*' is
|
|
474
|
+
// nullable: what FOLLOWS it can also be first, so the scan continues past it.
|
|
475
|
+
// A wildcard '.' or an empty alternative makes the set indeterminable.
|
|
476
476
|
func alt_first_bytes = (string pattern, int start, int end, ref StringBuilder sb, out int) {
|
|
477
477
|
var int i = start
|
|
478
478
|
while i < end {
|
|
@@ -490,9 +490,17 @@ func alt_first_bytes = (string pattern, int start, int end, ref StringBuilder sb
|
|
|
490
490
|
if shorthand_members(e, ref sb) < 0 {
|
|
491
491
|
return -1
|
|
492
492
|
}
|
|
493
|
+
} else {
|
|
494
|
+
sb.append_char(e)
|
|
495
|
+
}
|
|
496
|
+
// A '?'/'*' quantifier makes the atom nullable — the first
|
|
497
|
+
// byte can also come from whatever follows it.
|
|
498
|
+
var int cont = nullable_quant_after(pattern, i + 2, end)
|
|
499
|
+
if cont < 0 {
|
|
493
500
|
return 0
|
|
494
501
|
}
|
|
495
|
-
|
|
502
|
+
i = cont
|
|
503
|
+
continue
|
|
496
504
|
}
|
|
497
505
|
return 0
|
|
498
506
|
}
|
|
@@ -509,7 +517,12 @@ func alt_first_bytes = (string pattern, int start, int end, ref StringBuilder sb
|
|
|
509
517
|
}
|
|
510
518
|
}
|
|
511
519
|
add_class_chars(pattern, i + 1, a_end - 1, ref sb)
|
|
512
|
-
|
|
520
|
+
var int cont = nullable_quant_after(pattern, a_end, end)
|
|
521
|
+
if cont < 0 {
|
|
522
|
+
return 0
|
|
523
|
+
}
|
|
524
|
+
i = cont
|
|
525
|
+
continue
|
|
513
526
|
}
|
|
514
527
|
if c == '(' {
|
|
515
528
|
var int a_end = atom_end_pos(pattern, i, end)
|
|
@@ -518,27 +531,11 @@ func alt_first_bytes = (string pattern, int start, int end, ref StringBuilder sb
|
|
|
518
531
|
if collect_first_bytes(pattern, i + 1, a_end - 1, ref sb) < 0 {
|
|
519
532
|
return -1
|
|
520
533
|
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
// quantifier lazy and is skipped either way.
|
|
524
|
-
var int after = a_end
|
|
525
|
-
var nullable = 0
|
|
526
|
-
if after < end {
|
|
527
|
-
var char q = pattern.at(after)
|
|
528
|
-
if q == '?' || q == '*' {
|
|
529
|
-
nullable = 1
|
|
530
|
-
after += 1
|
|
531
|
-
if after < end {
|
|
532
|
-
if pattern.at(after) == '?' {
|
|
533
|
-
after += 1
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
if nullable == 0 {
|
|
534
|
+
var int cont = nullable_quant_after(pattern, a_end, end)
|
|
535
|
+
if cont < 0 {
|
|
539
536
|
return 0
|
|
540
537
|
}
|
|
541
|
-
i =
|
|
538
|
+
i = cont
|
|
542
539
|
continue
|
|
543
540
|
}
|
|
544
541
|
if c == '^' || c == '$' {
|
|
@@ -552,9 +549,40 @@ func alt_first_bytes = (string pattern, int start, int end, ref StringBuilder sb
|
|
|
552
549
|
return -1
|
|
553
550
|
}
|
|
554
551
|
sb.append_char(c)
|
|
555
|
-
|
|
552
|
+
var int cont = nullable_quant_after(pattern, i + 1, end)
|
|
553
|
+
if cont < 0 {
|
|
554
|
+
return 0
|
|
555
|
+
}
|
|
556
|
+
i = cont
|
|
557
|
+
continue
|
|
558
|
+
}
|
|
559
|
+
// An empty alternative (nothing left after nullable atoms — or nothing at
|
|
560
|
+
// all) can match at any position — indeterminable.
|
|
561
|
+
return -1
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// If the atom ending at `after` carries a nullable quantifier ('?' or '*',
|
|
565
|
+
// optionally marked lazy by a second '?'), return the position just past the
|
|
566
|
+
// quantifier; otherwise return -1. Callers keep scanning from the returned
|
|
567
|
+
// position: a nullable leading atom means the alternative's match can also
|
|
568
|
+
// START with whatever follows, so those bytes belong in the first-byte set
|
|
569
|
+
// too. ('+' is NOT nullable — the atom must match once — so it leaves the
|
|
570
|
+
// atom's own bytes as the whole first set.)
|
|
571
|
+
func nullable_quant_after = (string pattern, int after, int end, out int) {
|
|
572
|
+
var int j = after
|
|
573
|
+
if j >= end {
|
|
574
|
+
return -1
|
|
575
|
+
}
|
|
576
|
+
var char q = pattern.at(j)
|
|
577
|
+
if q == '?' || q == '*' {
|
|
578
|
+
j += 1
|
|
579
|
+
if j < end {
|
|
580
|
+
if pattern.at(j) == '?' {
|
|
581
|
+
j += 1
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
return j
|
|
556
585
|
}
|
|
557
|
-
// An empty alternative can match at any position — indeterminable.
|
|
558
586
|
return -1
|
|
559
587
|
}
|
|
560
588
|
|
package/dist/index.mjs
CHANGED
|
@@ -19242,6 +19242,7 @@ function build_function_node$1(node, status) {
|
|
|
19242
19242
|
const old_struct_param_slots = status.function_struct_param_slots;
|
|
19243
19243
|
const old_function_param_types = status.function_param_types;
|
|
19244
19244
|
const old_function_local_types = status.function_local_types;
|
|
19245
|
+
const old_variable_types = status.variable_types;
|
|
19245
19246
|
status.function_param_regs = /* @__PURE__ */ new Map();
|
|
19246
19247
|
status.function_param_vars = /* @__PURE__ */ new Set();
|
|
19247
19248
|
status.function_array_params = /* @__PURE__ */ new Set();
|
|
@@ -19250,6 +19251,7 @@ function build_function_node$1(node, status) {
|
|
|
19250
19251
|
status.function_struct_param_slots = /* @__PURE__ */ new Set();
|
|
19251
19252
|
status.function_param_types = /* @__PURE__ */ new Map();
|
|
19252
19253
|
status.function_local_types = /* @__PURE__ */ new Map();
|
|
19254
|
+
status.variable_types = /* @__PURE__ */ new Map();
|
|
19253
19255
|
const old_variadic_params_aarch64 = status.function_variadic_params;
|
|
19254
19256
|
const old_view_params = status.function_view_params;
|
|
19255
19257
|
status.function_variadic_params = /* @__PURE__ */ new Set();
|
|
@@ -19658,6 +19660,7 @@ function build_function_node$1(node, status) {
|
|
|
19658
19660
|
status.function_struct_param_slots = old_struct_param_slots;
|
|
19659
19661
|
status.function_param_types = old_function_param_types;
|
|
19660
19662
|
status.function_local_types = old_function_local_types;
|
|
19663
|
+
status.variable_types = old_variable_types;
|
|
19661
19664
|
status.function_variadic_params = old_variadic_params_aarch64;
|
|
19662
19665
|
status.function_view_params = old_view_params;
|
|
19663
19666
|
status.function_return_label = old_return_label;
|
|
@@ -35126,6 +35129,8 @@ function build_function_node(node, status) {
|
|
|
35126
35129
|
status.function_view_params = /* @__PURE__ */ new Set();
|
|
35127
35130
|
const old_return_type = status.function_return_type;
|
|
35128
35131
|
status.function_return_type = node.return_type;
|
|
35132
|
+
const old_variable_types = status.variable_types;
|
|
35133
|
+
status.variable_types = /* @__PURE__ */ new Map();
|
|
35129
35134
|
const old_nullable_ret_has = status.nullable_ret_has_param;
|
|
35130
35135
|
if (is_nullable_struct_type(node.return_type, status)) status.nullable_ret_has_param = "_ret_has";
|
|
35131
35136
|
else status.nullable_ret_has_param = void 0;
|
|
@@ -35181,6 +35186,7 @@ function build_function_node(node, status) {
|
|
|
35181
35186
|
status.function_variadic_params = old_variadic_params;
|
|
35182
35187
|
status.function_view_params = old_view_params;
|
|
35183
35188
|
status.function_return_type = old_return_type;
|
|
35189
|
+
status.variable_types = old_variable_types;
|
|
35184
35190
|
status.nullable_ret_has_param = old_nullable_ret_has;
|
|
35185
35191
|
status.current_function_name = old_function_name;
|
|
35186
35192
|
status.current_function = old_current_function;
|
|
@@ -43171,7 +43177,7 @@ function build_access_method(node, access_func, status) {
|
|
|
43171
43177
|
emit_asm(status, `str x0, [sp, #-16]!\n`);
|
|
43172
43178
|
emit_asm(status, `str x1, [sp, #-16]!\n`);
|
|
43173
43179
|
emit_asm(status, `mov x0, x9\n`);
|
|
43174
|
-
|
|
43180
|
+
emit_free(status);
|
|
43175
43181
|
emit_asm(status, `ldr x1, [sp], #16\n`);
|
|
43176
43182
|
emit_asm(status, `ldr x0, [sp], #16\n`);
|
|
43177
43183
|
emit_asm(status, `add sp, sp, #16\n`);
|
|
@@ -55547,7 +55553,13 @@ function check_return_node(ret, status) {
|
|
|
55547
55553
|
} else if (!func.is_arrow_body) {
|
|
55548
55554
|
add_error(status, `Function returns a value but has no 'out' return type`, ret.start);
|
|
55549
55555
|
func.return_type = ret.type;
|
|
55550
|
-
} else
|
|
55556
|
+
} else {
|
|
55557
|
+
func.return_type = ret.type;
|
|
55558
|
+
if (!ret.type?.name) {
|
|
55559
|
+
func.return_type = new Type("void");
|
|
55560
|
+
ret.type = new Type("void");
|
|
55561
|
+
}
|
|
55562
|
+
}
|
|
55551
55563
|
}
|
|
55552
55564
|
}
|
|
55553
55565
|
//#endregion
|
|
@@ -58515,7 +58527,24 @@ function resolve_linked_types(source, library, file_path) {
|
|
|
58515
58527
|
}
|
|
58516
58528
|
const user_declared_funcs = /* @__PURE__ */ new Set();
|
|
58517
58529
|
for (let i = 0; i < tokens.length - 1; i++) if (tokens[i].value === "func" && /^\w+$/.test(tokens[i + 1].value)) user_declared_funcs.add(tokens[i + 1].value);
|
|
58518
|
-
|
|
58530
|
+
const import_tokens = /* @__PURE__ */ new Set();
|
|
58531
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
58532
|
+
if (tokens[i].value !== "import") continue;
|
|
58533
|
+
import_tokens.add(i);
|
|
58534
|
+
let j = i + 1;
|
|
58535
|
+
if (j < tokens.length && /^\w+$/.test(tokens[j].value)) {
|
|
58536
|
+
import_tokens.add(j);
|
|
58537
|
+
j += 1;
|
|
58538
|
+
while (j + 1 < tokens.length && tokens[j].value === "::" && /^\w+$/.test(tokens[j + 1].value)) {
|
|
58539
|
+
import_tokens.add(j);
|
|
58540
|
+
import_tokens.add(j + 1);
|
|
58541
|
+
j += 2;
|
|
58542
|
+
}
|
|
58543
|
+
}
|
|
58544
|
+
}
|
|
58545
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
58546
|
+
if (import_tokens.has(i)) continue;
|
|
58547
|
+
const token = tokens[i];
|
|
58519
58548
|
if (user_defined.has(token.value)) continue;
|
|
58520
58549
|
if (library.types.has(token.value) && !BASE_TYPES.includes(token.value)) needed.add(token.value);
|
|
58521
58550
|
else if (library.functions.has(token.value) && !user_declared_funcs.has(token.value)) needed.add(token.value);
|
|
@@ -59356,7 +59385,8 @@ function run_test_file(entry_path, lib_path, arch, audit = false, audit_runtime)
|
|
|
59356
59385
|
audit_obj
|
|
59357
59386
|
]);
|
|
59358
59387
|
}
|
|
59359
|
-
const
|
|
59388
|
+
const platform = default_platform();
|
|
59389
|
+
const ext = arch === "aarch64" ? ".s" : platform === "macos" || platform === "ios" ? ".m" : ".c";
|
|
59360
59390
|
const codefile = path.join(buildDir, path.basename(entry_path, ".nm") + ext);
|
|
59361
59391
|
const outfile = path.join(buildDir, path.basename(entry_path, ".nm"));
|
|
59362
59392
|
fs.writeFileSync(path.join(buildDir, "main.h"), buildResult.headers ?? "");
|
|
@@ -59367,6 +59397,7 @@ function run_test_file(entry_path, lib_path, arch, audit = false, audit_runtime)
|
|
|
59367
59397
|
codefile
|
|
59368
59398
|
];
|
|
59369
59399
|
if (audit_obj) link_args.push(audit_obj);
|
|
59400
|
+
if (platform === "macos" || platform === "ios") link_args.push("-framework", "CoreGraphics", "-framework", "Foundation", "-framework", "AppKit", "-lobjc");
|
|
59370
59401
|
try {
|
|
59371
59402
|
execFileSync("clang", link_args, {
|
|
59372
59403
|
encoding: "utf8",
|
package/package.json
CHANGED
package/src/test.ts
CHANGED
|
@@ -3,7 +3,7 @@ import fs from "node:fs";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
|
|
6
|
-
import build from "../../src/build.ts";
|
|
6
|
+
import build, { default_platform } from "../../src/build.ts";
|
|
7
7
|
import join from "../../src/join.ts";
|
|
8
8
|
import { get_library } from "../../src/lib.ts";
|
|
9
9
|
import parse from "../../src/parse.ts";
|
|
@@ -329,7 +329,12 @@ export function run_test_file(
|
|
|
329
329
|
audit_obj = path.join(buildDir, "audit_runtime.o");
|
|
330
330
|
execFileSync("clang", ["-c", runtime_src, "-o", audit_obj]);
|
|
331
331
|
}
|
|
332
|
-
const
|
|
332
|
+
const platform = default_platform();
|
|
333
|
+
// Match the run/build command's emission: ObjC-bearing sources (GUI code
|
|
334
|
+
// pulled in through the library graph) must land in a `.m` TU on Apple
|
|
335
|
+
// platforms — the ObjC framework headers are Objective-C, and including
|
|
336
|
+
// them from a plain `.c` TU fails with `@class NSString` syntax errors.
|
|
337
|
+
const ext = arch === "aarch64" ? ".s" : platform === "macos" || platform === "ios" ? ".m" : ".c";
|
|
333
338
|
const codefile = path.join(buildDir, path.basename(entry_path, ".nm") + ext);
|
|
334
339
|
const outfile = path.join(buildDir, path.basename(entry_path, ".nm"));
|
|
335
340
|
// The C backend's generated source does `#include "main.h"`, so write the
|
|
@@ -337,10 +342,23 @@ export function run_test_file(
|
|
|
337
342
|
fs.writeFileSync(path.join(buildDir, "main.h"), buildResult.headers ?? "");
|
|
338
343
|
fs.writeFileSync(codefile, buildResult.code);
|
|
339
344
|
|
|
340
|
-
// Link the harness binary.
|
|
341
|
-
//
|
|
345
|
+
// Link the harness binary. Frameworks are passed on Apple platforms for
|
|
346
|
+
// the same reason as the run/build command: the joined source may reference
|
|
347
|
+
// ObjC runtime symbols even when the test body doesn't, and unused
|
|
348
|
+
// frameworks cost nothing at link time.
|
|
342
349
|
const link_args = ["-o", outfile, codefile];
|
|
343
350
|
if (audit_obj) link_args.push(audit_obj);
|
|
351
|
+
if (platform === "macos" || platform === "ios") {
|
|
352
|
+
link_args.push(
|
|
353
|
+
"-framework",
|
|
354
|
+
"CoreGraphics",
|
|
355
|
+
"-framework",
|
|
356
|
+
"Foundation",
|
|
357
|
+
"-framework",
|
|
358
|
+
"AppKit",
|
|
359
|
+
"-lobjc",
|
|
360
|
+
);
|
|
361
|
+
}
|
|
344
362
|
try {
|
|
345
363
|
execFileSync("clang", link_args, {
|
|
346
364
|
encoding: "utf8",
|