@fraczak/k 6.5.0 → 6.7.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.
@@ -78,7 +78,6 @@ All tools accept `--help`.
78
78
 
79
79
  - `-S, --assembly`: Emit GNU ARM64 assembly text (`.s`) instead of an ELF binary.
80
80
  - `-o, --output <file>`: Specify the output file path.
81
- - `--entry <name>`: Specify the entry relation (defaults to `__main__`).
82
81
  - `--lib <file>`: Load one `.klib` or `.k` library dependency.
83
82
  - `--export <spec>`: Export library symbols into source scope (`name` or `libname:localname`).
84
83
  - `--json`: Format output as JSON instead of binary wire format.
@@ -22,7 +22,6 @@ function usage(stream = console.error) {
22
22
  stream("Options:");
23
23
  stream(" -S, --assembly Emit GNU ARM64 assembly (.s) instead of an executable binary.");
24
24
  stream(" -o, --output Specify output file path explicitly.");
25
- stream(" --entry name Specify entry relation name.");
26
25
  stream(" --lib file Load one .klib dependency before compiling.");
27
26
  stream(" --export spec Export a library alias into source scope. May be repeated.");
28
27
  stream(" spec is 'name' or 'libname:localname'.");
@@ -38,8 +37,6 @@ try {
38
37
 
39
38
  let emitAssembly = false;
40
39
  let explicitOutput = null;
41
- let entry = null;
42
-
43
40
  // Extract ARM64-specific flags
44
41
  const remainingArgs = [];
45
42
  while (args.length > 0) {
@@ -51,10 +48,6 @@ try {
51
48
  args.shift();
52
49
  explicitOutput = args.shift();
53
50
  if (!explicitOutput) throw new Error("-o/--output requires a file argument");
54
- } else if (arg === "--entry") {
55
- args.shift();
56
- entry = args.shift();
57
- if (!entry) throw new Error("--entry requires a name argument");
58
51
  } else {
59
52
  remainingArgs.push(args.shift());
60
53
  }
@@ -71,7 +64,6 @@ try {
71
64
  libraries,
72
65
  exportSpecs,
73
66
  stdin,
74
- entry,
75
67
  emit: emitAssembly ? "assembly" : null,
76
68
  outputPath: (!emitAssembly && outputPath) ? outputPath : null
77
69
  });
@@ -5,7 +5,21 @@
5
5
  #include <string.h>
6
6
  #include <time.h>
7
7
 
8
- #define ARENA_CAPACITY (64 * 1024 * 1024)
8
+ #define DEFAULT_ARENA_CAPACITY (256 * 1024 * 1024)
9
+
10
+ static int parse_size_arg(const char *text, size_t *out);
11
+
12
+ static size_t get_arena_capacity(void) {
13
+ const char *env = getenv("K_ARENA_CAPACITY_MB");
14
+ if (!env || !*env) env = getenv("K_ARENA_MB");
15
+ if (env && *env) {
16
+ size_t mb = 0;
17
+ if (parse_size_arg(env, &mb) && mb > 0) {
18
+ return mb * 1024 * 1024;
19
+ }
20
+ }
21
+ return DEFAULT_ARENA_CAPACITY;
22
+ }
9
23
 
10
24
  typedef enum {
11
25
  K_VALUE_UNIT,
@@ -601,8 +615,10 @@ static int run_bench_main(void *arena_mem, const char *count_text) {
601
615
  int main(int argc, char **argv) {
602
616
  init_tag_registry();
603
617
 
618
+ size_t arena_capacity = get_arena_capacity();
619
+
604
620
  if (argc == 2 && strcmp(argv[1], "--server") == 0) {
605
- void *arena_mem = malloc(ARENA_CAPACITY);
621
+ void *arena_mem = malloc(arena_capacity);
606
622
  if (!arena_mem) return 1;
607
623
  int rc = run_server(arena_mem);
608
624
  free(arena_mem);
@@ -610,7 +626,7 @@ int main(int argc, char **argv) {
610
626
  }
611
627
 
612
628
  if (argc == 3 && strcmp(argv[1], "--bench-main") == 0) {
613
- void *arena_mem = malloc(ARENA_CAPACITY);
629
+ void *arena_mem = malloc(arena_capacity);
614
630
  if (!arena_mem) return 1;
615
631
  int rc = run_bench_main(arena_mem, argv[2]);
616
632
  free(arena_mem);
@@ -647,7 +663,7 @@ int main(int argc, char **argv) {
647
663
  }
648
664
  }
649
665
 
650
- void *arena_mem = malloc(ARENA_CAPACITY);
666
+ void *arena_mem = malloc(arena_capacity);
651
667
  if (!arena_mem) {
652
668
  if (in_fp != stdin) fclose(in_fp);
653
669
  return 1;
@@ -105,7 +105,7 @@ node "$K_ROOT/backends/arm64/bin/k-arm64-compile.mjs" \
105
105
  '{succ int x,int y}+' \
106
106
  -o "$TMP_DIR/lib-add"
107
107
 
108
- node "$K_ROOT/codecs/k-parse.mjs" <<< '{"x":{"succ":"zero"},"y":{"succ":{"succ":"zero"}}}' |
108
+ node "$K_ROOT/codecs/k-parse.mjs" <<< '{"x":{"0":"_"},"y":{"+":{"0":"_"}}}' |
109
109
  "$TMP_DIR/lib-add" --json |
110
110
  grep -Fxq '{"+":{"1":"_"}}'
111
111
 
@@ -23,7 +23,7 @@ backend from `backends/llvm`:
23
23
  npm install
24
24
  cd backends/llvm
25
25
  node ../../objects/compile.mjs '()' /tmp/id.ko
26
- node ./bin/k-llvm-compile.mjs --input-pattern '[["open-product",[]]]' /tmp/id.ko /tmp/id.ll
26
+ node ./bin/k-llvm-compile.mjs /tmp/id.ko /tmp/id.ll
27
27
  ```
28
28
 
29
29
  The generated `.ll` embeds the envelope-specialized KIR-P contract as module
@@ -44,24 +44,26 @@ status in `k_result`. These operations can compose through KIR `comp`.
44
44
  ## CLI
45
45
 
46
46
  ```sh
47
- k-llvm-build [options] object.ko output-exe
48
- k-llvm-compile [options] object.ko [output.ll]
47
+ k-llvm-build [options] [source-snippet | input-file [output-exe]]
48
+ k-llvm-compile [options] [source-snippet | input-file [output.ll]]
49
49
  k-llvm-jit [options] object.ko
50
50
  k-llvm-run [options] object.ko [input.kv]
51
51
  ```
52
52
 
53
53
  Options:
54
54
 
55
- - `--retype rel`: current option spelling for the relation to
56
- envelope-specialize; defaults to the object's `main`.
57
- - `--input-pattern json-or-file`: KIR property-list input pattern; required
58
- for `k-llvm-build`.
59
- - `--expect value-or-file`: for `k-llvm-run`, compare the output value against
60
- expected value text.
55
+ - `-o, --output path`: specify output file path explicitly.
56
+ - `--lib file`: load one `.klib` or `.k` dependency before compiling.
57
+ - `--export spec`: export a library alias into source scope (`name` or `libname:localname`). May be repeated.
58
+ - `--input-pattern json-or-file`: for `k-llvm-run`, KIR property-list input pattern.
59
+ - `--retype rel`: for `k-llvm-run`, relation to specialize (defaults to object main).
60
+ - `--expect value-or-file`: for `k-llvm-run`, compare the output value against expected value text.
61
61
  - `-h`, `--help`: show usage.
62
62
 
63
- Only `.ko` / `.klib` object input is supported in this first prototype.
64
- Source compilation remains owned by core `k`.
63
+ The compile commands follow the unified k CLI input convention: pass inline
64
+ source, an existing `.k` source file, or a `.ko`/`.klib` object. Reads UTF-8
65
+ source from stdin when input is omitted. Output paths can be specified as a
66
+ positional argument or explicitly with `-o, --output`.
65
67
  Without `--expect`, `k-llvm-run` prints the result value as compact JSON.
66
68
  `k-llvm-build` emits a native executable that reads and writes the binary
67
69
  k pattern+value envelope used by `codecs/k-parse.mjs` and `codecs/k-print.mjs`.
@@ -1,14 +1,22 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import fs from "node:fs";
4
- import { argv, exit } from "node:process";
5
- import { decodeObject } from "@fraczak/k/object.mjs";
3
+ import { argv, exit, stdin } from "node:process";
4
+ import {
5
+ compileProgramInputToObject,
6
+ parseCompileOptions,
7
+ resolveProgramInput
8
+ } from "../src/cli.mjs";
6
9
  import { compileObjectToExecutable } from "../src/executable.mjs";
7
10
 
8
11
  function usage(stream = console.error) {
9
12
  const prog = argv[1] || "k-llvm-build.mjs";
10
- stream(`Usage: node ${prog} [options] object-file output-exe`);
11
- stream("Compile a k .ko/.klib object into a native executable.");
13
+ stream(`Usage: node ${prog} [options] [source-snippet | input-file [output-exe]]`);
14
+ stream("Compile k source, .ko, or .klib input into a native executable.");
15
+ stream("");
16
+ stream("Arguments:");
17
+ stream(" source-snippet Inline k source, in the same style as k.mjs.");
18
+ stream(" input-file Source .k, .ko, or .klib file. Reads UTF-8 source from stdin when omitted.");
19
+ stream(" output-exe Output executable path.");
12
20
  stream("");
13
21
  stream("The executable reads a binary k pattern+value envelope from stdin and");
14
22
  stream("writes a binary k pattern+value envelope to stdout.");
@@ -16,18 +24,11 @@ function usage(stream = console.error) {
16
24
  stream("stdout is encoded with the compiled output pattern.");
17
25
  stream("");
18
26
  stream("Options:");
19
- stream(" --retype rel Relation to specialize. Defaults to object main.");
20
- stream(" --input-pattern value Required input pattern property-list JSON, or a file containing it.");
21
- stream(" -h, --help Show this help.");
22
- }
23
-
24
- function readMaybeFile(textOrPath) {
25
- return fs.existsSync(textOrPath) ? fs.readFileSync(textOrPath, "utf8") : textOrPath;
26
- }
27
-
28
- function readPattern(inputPattern) {
29
- if (inputPattern == null) return null;
30
- return JSON.parse(readMaybeFile(inputPattern));
27
+ stream(" -o, --output path Specify output file path explicitly.");
28
+ stream(" --lib file Load one .klib dependency before compiling.");
29
+ stream(" --export spec Export a library alias into source scope. May be repeated.");
30
+ stream(" spec is 'name' or 'libname:localname'.");
31
+ stream(" -h, --help Show this help.");
31
32
  }
32
33
 
33
34
  try {
@@ -37,33 +38,34 @@ try {
37
38
  exit(0);
38
39
  }
39
40
 
40
- let relation = null;
41
- let inputPattern = null;
42
- while (args.length > 0 && args[0].startsWith("--")) {
43
- const option = args.shift();
44
- if (option === "--retype") {
45
- relation = args.shift();
46
- if (!relation) throw new Error("--retype requires a relation name");
47
- } else if (option === "--input-pattern") {
48
- inputPattern = args.shift();
49
- if (!inputPattern) throw new Error("--input-pattern requires JSON or a file path");
41
+ let explicitOutput = null;
42
+ const remainingArgs = [];
43
+ while (args.length > 0) {
44
+ const arg = args[0];
45
+ if (arg === "-o" || arg === "--output") {
46
+ args.shift();
47
+ explicitOutput = args.shift();
48
+ if (!explicitOutput) throw new Error("-o/--output requires a file argument");
50
49
  } else {
51
- throw new Error(`Unknown option: ${option}`);
50
+ remainingArgs.push(args.shift());
52
51
  }
53
52
  }
54
53
 
55
- const objectPath = args.shift() || null;
56
- const outputPath = args.shift() || null;
57
- if (objectPath == null) throw new Error("object-file is required");
58
- if (outputPath == null) throw new Error("output-exe is required");
59
- if (args.length > 0) throw new Error(`Unexpected argument: ${args[0]}`);
60
- if (inputPattern == null) throw new Error("--input-pattern is required for k-llvm-build");
54
+ const { libraries, exportSpecs } = parseCompileOptions(remainingArgs);
55
+ const input = resolveProgramInput(remainingArgs, { allowStdinSource: true });
56
+ const positionalOutput = remainingArgs.shift();
57
+ if (remainingArgs.length > 0) throw new Error("Too many arguments");
58
+
59
+ const outputPath = explicitOutput || positionalOutput || null;
60
+ if (outputPath == null) throw new Error("Output executable path is required (pass output-exe or -o/--output)");
61
61
 
62
- const object = decodeObject(fs.readFileSync(objectPath));
63
- compileObjectToExecutable(object, outputPath, {
64
- relation: relation || object.main,
65
- inputPattern: readPattern(inputPattern)
62
+ const object = await compileProgramInputToObject(input, {
63
+ libraries,
64
+ exportSpecs,
65
+ stdin
66
66
  });
67
+
68
+ compileObjectToExecutable(object, outputPath);
67
69
  } catch (error) {
68
70
  console.error(error.stack || error.message || String(error));
69
71
  usage();
@@ -2,29 +2,30 @@
2
2
 
3
3
  import fs from "node:fs";
4
4
  import { argv, exit, stdin, stdout } from "node:process";
5
- import { compileBufferToLLVM } from "../src/llvm.mjs";
5
+ import {
6
+ compileProgramInputToObject,
7
+ parseCompileOptions,
8
+ resolveProgramInput
9
+ } from "../src/cli.mjs";
10
+ import { compileObjectToLLVM } from "../src/llvm.mjs";
11
+ import { inputPatternForObjectRelation } from "../src/executable.mjs";
6
12
 
7
13
  function usage(stream = console.error) {
8
14
  const prog = argv[1] || "k-llvm-compile.mjs";
9
- stream(`Usage: node ${prog} [options] object-file [output.ll]`);
15
+ stream(`Usage: node ${prog} [options] [source-snippet | input-file [output.ll]]`);
10
16
  stream("Compile a k .ko/.klib object into prototype LLVM IR.");
11
17
  stream("");
12
18
  stream("Arguments:");
13
- stream(" object-file Input .ko or .klib file. Reads bytes from stdin when omitted.");
19
+ stream(" source-snippet Inline k source, in the same style as k.mjs.");
20
+ stream(" input-file Source .k, .ko, or .klib file. Reads UTF-8 source from stdin when omitted.");
14
21
  stream(" output.ll Output LLVM IR path. Writes to stdout when omitted.");
15
22
  stream("");
16
23
  stream("Options:");
17
- stream(" --retype rel Relation to specialize. Defaults to object main.");
18
- stream(" --input-pattern value Input pattern property-list JSON, or a file containing it.");
19
- stream(" -h, --help Show this help.");
20
- }
21
-
22
- async function readStdinBytes() {
23
- const chunks = [];
24
- for await (const chunk of stdin) {
25
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
26
- }
27
- return Buffer.concat(chunks);
24
+ stream(" -o, --output path Specify output file path explicitly.");
25
+ stream(" --lib file Load one .klib dependency before compiling.");
26
+ stream(" --export spec Export a library alias into source scope. May be repeated.");
27
+ stream(" spec is 'name' or 'libname:localname'.");
28
+ stream(" -h, --help Show this help.");
28
29
  }
29
30
 
30
31
  try {
@@ -34,32 +35,41 @@ try {
34
35
  exit(0);
35
36
  }
36
37
 
37
- let relation = null;
38
- let inputPattern = null;
39
- while (args.length > 0 && args[0].startsWith("--")) {
40
- const option = args.shift();
41
- if (option === "--retype") {
42
- relation = args.shift();
43
- if (!relation) throw new Error("--retype requires a relation name");
44
- } else if (option === "--input-pattern") {
45
- inputPattern = args.shift();
46
- if (!inputPattern) throw new Error("--input-pattern requires JSON or a file path");
38
+ let explicitOutput = null;
39
+ const remainingArgs = [];
40
+ while (args.length > 0) {
41
+ const arg = args[0];
42
+ if (arg === "-o" || arg === "--output") {
43
+ args.shift();
44
+ explicitOutput = args.shift();
45
+ if (!explicitOutput) throw new Error("-o/--output requires a file argument");
47
46
  } else {
48
- throw new Error(`Unknown option: ${option}`);
47
+ remainingArgs.push(args.shift());
49
48
  }
50
49
  }
51
- if (inputPattern == null) throw new Error("--input-pattern is required");
52
50
 
53
- const inputPath = args.shift() || null;
54
- const outputPath = args.shift() || null;
55
- if (args.length > 0) throw new Error(`Unexpected argument: ${args[0]}`);
51
+ const { libraries, exportSpecs } = parseCompileOptions(remainingArgs);
52
+ const input = resolveProgramInput(remainingArgs, { allowStdinSource: true });
53
+ const positionalOutput = remainingArgs.shift();
54
+ if (remainingArgs.length > 0) throw new Error("Too many arguments");
55
+
56
+ const outputPath = explicitOutput || positionalOutput || null;
57
+
58
+ const object = await compileProgramInputToObject(input, {
59
+ libraries,
60
+ exportSpecs,
61
+ stdin
62
+ });
63
+
64
+ const { llvm } = compileObjectToLLVM(object, {
65
+ relation: object.main,
66
+ inputPattern: inputPatternForObjectRelation(object, object.main)
67
+ });
56
68
 
57
- const input = inputPath == null ? await readStdinBytes() : fs.readFileSync(inputPath);
58
- const { llvm } = compileBufferToLLVM(input, { relation, inputPattern });
59
69
  if (outputPath == null) {
60
70
  stdout.write(llvm);
61
71
  } else {
62
- fs.writeFileSync(outputPath, llvm);
72
+ fs.writeFileSync(outputPath, llvm, "utf8");
63
73
  }
64
74
  } catch (error) {
65
75
  console.error(error.stack || error.message || String(error));