@fluffylabs/anan-as 1.1.3-dde58f0 → 1.1.3-e01d5ea

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/dist/bin/index.js CHANGED
@@ -4,7 +4,7 @@ import minimist from "minimist";
4
4
  import { disassemble, HasMetadata, InputKind, prepareProgram, runProgram } from "../build/release.js";
5
5
  const HELP_TEXT = `Usage:
6
6
  anan-as disassemble [--spi] [--no-metadata] <file.(jam|pvm|spi|bin)>
7
- anan-as run [--spi] [--no-logs] [--no-metadata] [--pc <number>] [--gas <number>] <file.jam> [spi-args.bin or hex]
7
+ anan-as run [--spi] [--no-logs] [--no-metadata] [--pc <number>] [--gas <number>] <file.jam> [spi-args.bin]
8
8
 
9
9
  Commands:
10
10
  disassemble Disassemble PVM bytecode to assembly
@@ -15,7 +15,7 @@ Flags:
15
15
  --no-metadata Input does not contain metadata
16
16
  --no-logs Disable execution logs (run command only)
17
17
  --pc <number> Set initial program counter (default: 0)
18
- --gas <number> Set initial gas amount (default: 10_000)
18
+ --gas <number> Set initial gas amount (default: 0)
19
19
  --help, -h Show this help message`;
20
20
  main();
21
21
  function main() {
@@ -42,9 +42,8 @@ function main() {
42
42
  }
43
43
  function handleDisassemble(args) {
44
44
  const parsed = minimist(args, {
45
- boolean: ["spi", "metadata", "help"],
45
+ boolean: ["spi", "no-metadata", "help"],
46
46
  alias: { h: "help" },
47
- default: { metadata: true },
48
47
  });
49
48
  if (parsed.help) {
50
49
  console.log(HELP_TEXT);
@@ -77,7 +76,7 @@ function handleDisassemble(args) {
77
76
  process.exit(1);
78
77
  }
79
78
  const kind = parsed.spi ? InputKind.SPI : InputKind.Generic;
80
- const hasMetadata = parsed.metadata ? HasMetadata.Yes : HasMetadata.No;
79
+ const hasMetadata = parsed["no-metadata"] ? HasMetadata.No : HasMetadata.Yes;
81
80
  const f = readFileSync(file);
82
81
  const name = kind === InputKind.Generic ? "generic PVM" : "JAM SPI";
83
82
  console.log(`🤖 Assembly of ${file} (as ${name})`);
@@ -85,11 +84,9 @@ function handleDisassemble(args) {
85
84
  }
86
85
  function handleRun(args) {
87
86
  const parsed = minimist(args, {
88
- boolean: ["spi", "logs", "metadata", "help"],
89
- /** Prevents parsing hex values as numbers. */
90
- string: ["pc", "gas", "_"],
87
+ boolean: ["spi", "no-logs", "no-metadata", "help"],
88
+ string: ["pc", "gas"],
91
89
  alias: { h: "help" },
92
- default: { metadata: true, logs: true },
93
90
  });
94
91
  if (parsed.help) {
95
92
  console.log(HELP_TEXT);
@@ -103,16 +100,16 @@ function handleRun(args) {
103
100
  }
104
101
  const kind = parsed.spi ? InputKind.SPI : InputKind.Generic;
105
102
  let programFile;
106
- let spiArgsStr;
103
+ let spiArgsFile;
107
104
  if (kind === InputKind.SPI) {
108
- // For SPI programs, expect: <program.spi> [spi-args.bin or hex]
105
+ // For SPI programs, expect: <program.spi> [spi-args.bin]
109
106
  if (files.length > 2) {
110
107
  console.error("Error: Too many arguments for SPI run command.");
111
- console.error("Usage: anan-as run --spi [--no-logs] [--no-metadata] [--pc <number>] [--gas <number>] <program.spi> [spi-args.bin or hex]");
108
+ console.error("Usage: anan-as run --spi [--no-logs] [--no-metadata] [--pc <number>] [--gas <number>] <program.spi> [spi-args.bin]");
112
109
  process.exit(1);
113
110
  }
114
111
  programFile = files[0];
115
- spiArgsStr = files[1]; // optional
112
+ spiArgsFile = files[1]; // optional
116
113
  }
117
114
  else {
118
115
  // For generic programs, expect exactly one file
@@ -123,116 +120,101 @@ function handleRun(args) {
123
120
  }
124
121
  programFile = files[0];
125
122
  }
123
+ // Validate program file extension
124
+ const expectedExt = kind === InputKind.SPI ? ".spi" : ".jam";
125
+ const dotIndex = programFile.lastIndexOf(".");
126
+ if (dotIndex === -1) {
127
+ console.error(`Error: File '${programFile}' has no extension.`);
128
+ console.error(`Expected: ${expectedExt}`);
129
+ process.exit(1);
130
+ }
131
+ const ext = programFile.substring(dotIndex);
132
+ if (ext !== expectedExt) {
133
+ console.error(`Error: Invalid file extension '${ext}' for run command.`);
134
+ console.error(`Expected: ${expectedExt}`);
135
+ process.exit(1);
136
+ }
126
137
  // Validate SPI args file if provided
127
- const spiArgs = parseSpiArgs(spiArgsStr);
128
- const logs = parsed.logs;
129
- const hasMetadata = parsed.metadata ? HasMetadata.Yes : HasMetadata.No;
138
+ let spiArgs;
139
+ if (spiArgsFile) {
140
+ const argsDotIndex = spiArgsFile.lastIndexOf(".");
141
+ if (argsDotIndex === -1) {
142
+ console.error(`Error: SPI args file '${spiArgsFile}' has no extension.`);
143
+ console.error(`Expected: .bin`);
144
+ process.exit(1);
145
+ }
146
+ const argsExt = spiArgsFile.substring(argsDotIndex);
147
+ if (argsExt !== ".bin") {
148
+ console.error(`Error: SPI args file must have .bin extension, got '${argsExt}'.`);
149
+ process.exit(1);
150
+ }
151
+ spiArgs = new Uint8Array(readFileSync(spiArgsFile));
152
+ }
153
+ const logs = !parsed["no-logs"];
154
+ const hasMetadata = parsed["no-metadata"] ? HasMetadata.No : HasMetadata.Yes;
130
155
  // Parse and validate PC and gas options
131
- const initialPc = parsePc(parsed);
132
- const initialGas = parseGas(parsed);
133
- const programCode = Array.from(readFileSync(programFile));
156
+ let initialPc = 0;
157
+ if (parsed.pc !== undefined) {
158
+ // Ensure it's a string/number, not boolean
159
+ if (typeof parsed.pc === "boolean") {
160
+ console.error("Error: --pc requires a value.");
161
+ process.exit(1);
162
+ }
163
+ const pcStr = String(parsed.pc);
164
+ // Reject floats and non-integer strings
165
+ if (pcStr.includes(".") || !/^-?\d+$/.test(pcStr)) {
166
+ console.error("Error: --pc must be a valid integer.");
167
+ process.exit(1);
168
+ }
169
+ const pcValue = parseInt(pcStr, 10);
170
+ if (!Number.isInteger(pcValue) || pcValue < 0 || pcValue > 0xffffffff) {
171
+ console.error("Error: --pc must be a non-negative integer <= 2^32-1.");
172
+ process.exit(1);
173
+ }
174
+ initialPc = pcValue;
175
+ }
176
+ let initialGas = BigInt(0);
177
+ if (parsed.gas !== undefined) {
178
+ // Ensure it's a string/number, not boolean
179
+ if (typeof parsed.gas === "boolean") {
180
+ console.error("Error: --gas requires a value.");
181
+ process.exit(1);
182
+ }
183
+ const gasStr = String(parsed.gas);
184
+ // Reject floats and non-integer strings
185
+ if (gasStr.includes(".") || !/^-?\d+$/.test(gasStr)) {
186
+ console.error("Error: --gas must be a valid integer.");
187
+ process.exit(1);
188
+ }
189
+ let gasValue;
190
+ try {
191
+ gasValue = BigInt(gasStr);
192
+ }
193
+ catch (_e) {
194
+ console.error("Error: --gas must be a valid integer.");
195
+ process.exit(1);
196
+ }
197
+ const MAX_I64 = (1n << 63n) - 1n;
198
+ if (gasValue < 0n || gasValue > MAX_I64) {
199
+ console.error("Error: --gas must be a non-negative integer <= 2^63-1.");
200
+ process.exit(1);
201
+ }
202
+ initialGas = gasValue;
203
+ }
204
+ const f = readFileSync(programFile);
134
205
  const name = kind === InputKind.Generic ? "generic PVM" : "JAM SPI";
135
206
  console.log(`🚀 Running ${programFile} (as ${name})`);
136
207
  try {
137
- const program = prepareProgram(kind, hasMetadata, programCode, [], [], [], spiArgs);
208
+ const program = prepareProgram(kind, hasMetadata, Array.from(f), [], [], [], spiArgs ? Array.from(spiArgs) : []);
138
209
  const result = runProgram(program, initialGas, initialPc, logs, false);
139
210
  console.log(`Status: ${result.status}`);
140
211
  console.log(`Exit code: ${result.exitCode}`);
141
212
  console.log(`Program counter: ${result.pc}`);
142
213
  console.log(`Gas remaining: ${result.gas}`);
143
214
  console.log(`Registers: [${result.registers.join(", ")}]`);
144
- console.log(`Result: [${hexEncode(result.result)}]`);
145
215
  }
146
216
  catch (error) {
147
217
  console.error(`Error running ${programFile}:`, error);
148
218
  process.exit(1);
149
219
  }
150
220
  }
151
- function parseGas(parsed) {
152
- if (parsed.gas === undefined) {
153
- return BigInt(10_000);
154
- }
155
- // Ensure it's a string/number, not boolean
156
- if (typeof parsed.gas === "boolean") {
157
- console.error("Error: --gas requires a value.");
158
- process.exit(1);
159
- }
160
- const gasStr = String(parsed.gas);
161
- // Reject floats and non-integer strings
162
- if (gasStr.includes(".") || !/^-?\d+$/.test(gasStr)) {
163
- console.error("Error: --gas must be a valid integer.");
164
- process.exit(1);
165
- }
166
- let gasValue;
167
- try {
168
- gasValue = BigInt(gasStr);
169
- }
170
- catch (_e) {
171
- console.error("Error: --gas must be a valid integer.");
172
- process.exit(1);
173
- }
174
- const MAX_I64 = (1n << 63n) - 1n;
175
- if (gasValue < 0n || gasValue > MAX_I64) {
176
- console.error("Error: --gas must be a non-negative integer <= 2^63-1.");
177
- process.exit(1);
178
- }
179
- return gasValue;
180
- }
181
- function parseSpiArgs(spiArgsStr) {
182
- if (!spiArgsStr) {
183
- return [];
184
- }
185
- try {
186
- return Array.from(hexDecode(spiArgsStr));
187
- }
188
- catch (e) {
189
- console.log(`Attempting to read ${spiArgsStr} as a file, since it's not a hex value: ${e}`);
190
- return Array.from(readFileSync(spiArgsStr));
191
- }
192
- }
193
- function parsePc(parsed) {
194
- if (parsed.pc === undefined) {
195
- return 0;
196
- }
197
- // Ensure it's a string/number, not boolean
198
- if (typeof parsed.pc === "boolean") {
199
- console.error("Error: --pc requires a value.");
200
- process.exit(1);
201
- }
202
- const pcStr = String(parsed.pc);
203
- // Reject floats and non-integer strings
204
- if (pcStr.includes(".") || !/^-?\d+$/.test(pcStr)) {
205
- console.error("Error: --pc must be a valid integer.");
206
- process.exit(1);
207
- }
208
- const pcValue = parseInt(pcStr, 10);
209
- if (!Number.isInteger(pcValue) || pcValue < 0 || pcValue > 0xffffffff) {
210
- console.error("Error: --pc must be a non-negative integer <= 2^32-1.");
211
- process.exit(1);
212
- }
213
- return pcValue;
214
- }
215
- function hexEncode(result) {
216
- return `0x${result.map((x) => x.toString(16).padStart(2, "0")).join("")}`;
217
- }
218
- function hexDecode(data) {
219
- if (!data.startsWith("0x")) {
220
- throw new Error("hex input must start with 0x");
221
- }
222
- const hex = data.substring(2);
223
- const len = hex.length;
224
- if (len % 2 === 1) {
225
- throw new Error("Odd number of nibbles");
226
- }
227
- const bytes = new Uint8Array(len / 2);
228
- for (let i = 0; i < len; i += 2) {
229
- const c = hex.substring(i, i + 2);
230
- const byteIndex = i / 2;
231
- const value = parseInt(c, 16);
232
- if (Number.isNaN(value)) {
233
- throw new Error(`hexDecode: invalid hex pair "${c}" in data "${data}" for bytes[${byteIndex}]`);
234
- }
235
- bytes[byteIndex] = value;
236
- }
237
- return bytes;
238
- }
@@ -68,8 +68,6 @@ function processW3f(data, options) {
68
68
  }
69
69
  // compare with expected values
70
70
  const expected = {
71
- // just copy JAM-output result field
72
- result: result.result,
73
71
  status: read(data, "expected-status"),
74
72
  registers: read(data, "expected-regs").map((x) => BigInt(x)),
75
73
  pc: read(data, "expected-pc"),