arc-lang 0.5.9 → 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/dist/errors.d.ts CHANGED
@@ -40,13 +40,25 @@ export interface ArcError {
40
40
  }
41
41
  export declare function levenshtein(a: string, b: string): number;
42
42
  export declare function findClosestMatch(name: string, candidates: string[], maxDistance?: number): string | null;
43
- export declare function formatError(error: ArcError, useColor?: boolean): string;
43
+ export declare function formatError(error: ArcError, useColor?: boolean, filePath?: string): string;
44
44
  export declare function undefinedVariableError(name: string, candidates: string[], loc?: AST.Loc, source?: string): ArcError;
45
45
  export declare function parseError(message: string, loc?: AST.Loc, source?: string, suggestion?: string): ArcError;
46
46
  export declare function typeError(message: string, loc?: AST.Loc, source?: string): ArcError;
47
47
  export declare function runtimeError(code: ErrorCode, message: string, loc?: AST.Loc, source?: string, suggestion?: string): ArcError;
48
48
  export declare function importError(message: string, loc?: AST.Loc, source?: string): ArcError;
49
49
  export declare function securityError(code: ErrorCode, message: string): ArcError;
50
- export declare function prettyPrintError(err: Error, source?: string, useColor?: boolean): string;
50
+ export declare function prettyPrintError(err: Error, source?: string, useColor?: boolean, filePath?: string): string;
51
+ export declare class ArcRuntimeError extends Error {
52
+ loc?: AST.Loc;
53
+ arcCode: ErrorCode;
54
+ arcCategory: ErrorCategory;
55
+ suggestion?: string;
56
+ constructor(message: string, options?: {
57
+ code?: ErrorCode;
58
+ category?: ErrorCategory;
59
+ loc?: AST.Loc;
60
+ suggestion?: string;
61
+ });
62
+ }
51
63
  export declare function setPrettyErrors(enabled: boolean): void;
52
64
  export declare function isPrettyErrorsEnabled(): boolean;
package/dist/errors.js CHANGED
@@ -84,11 +84,18 @@ export function findClosestMatch(name, candidates, maxDistance = 3) {
84
84
  return best;
85
85
  }
86
86
  // Format a rich error message with source snippet
87
- export function formatError(error, useColor = true) {
87
+ export function formatError(error, useColor = true, filePath) {
88
88
  const c = useColor ? COLORS : { red: "", yellow: "", cyan: "", gray: "", bold: "", reset: "", underline: "" };
89
89
  const lines = [];
90
90
  // Header: category[code]: message
91
91
  lines.push(`${c.red}${c.bold}${error.category}[${error.code}]${c.reset}: ${c.bold}${error.message}${c.reset}`);
92
+ // Location line
93
+ if (filePath && error.loc) {
94
+ lines.push(`${c.cyan} --> ${filePath}:${error.loc.line}:${error.loc.col}${c.reset}`);
95
+ }
96
+ else if (error.loc) {
97
+ lines.push(`${c.cyan} --> line ${error.loc.line}:${error.loc.col}${c.reset}`);
98
+ }
92
99
  // Source snippet with error pointer
93
100
  if (error.source && error.loc) {
94
101
  const sourceLines = error.source.split("\n");
@@ -188,10 +195,54 @@ export function securityError(code, message) {
188
195
  };
189
196
  }
190
197
  // Pretty-print an error that was caught during execution
191
- export function prettyPrintError(err, source, useColor = true) {
198
+ export function prettyPrintError(err, source, useColor = true, filePath) {
199
+ // Check for ParseError (has loc property)
200
+ if ("loc" in err && err.loc && err.message.startsWith("Parse error")) {
201
+ const loc = err.loc;
202
+ let cleanMsg = err.message.replace(/^Parse error at line \d+, col \d+: /, "");
203
+ // Make token names more human-friendly
204
+ cleanMsg = cleanMsg
205
+ .replace(/\bRBrace\b/g, "'}'")
206
+ .replace(/\bLBrace\b/g, "'{'")
207
+ .replace(/\bRParen\b/g, "')'")
208
+ .replace(/\bLParen\b/g, "'('")
209
+ .replace(/\bRBracket\b/g, "']'")
210
+ .replace(/\bLBracket\b/g, "'['")
211
+ .replace(/\bEOF ''/g, "end of file")
212
+ .replace(/^Expected /, "Expected ");
213
+ const rawMsg = err.message.replace(/^Parse error at line \d+, col \d+: /, "");
214
+ let suggestion;
215
+ if (rawMsg.includes("Expected RBrace"))
216
+ suggestion = "Add a closing '}' to match the opening brace.";
217
+ else if (rawMsg.includes("Expected RParen"))
218
+ suggestion = "Add a closing ')' to match the opening parenthesis.";
219
+ else if (rawMsg.includes("Expected RBracket"))
220
+ suggestion = "Add a closing ']' to match the opening bracket.";
221
+ return formatError({
222
+ code: ErrorCode.UNEXPECTED_TOKEN,
223
+ category: "ParseError",
224
+ message: cleanMsg,
225
+ loc,
226
+ source,
227
+ suggestion,
228
+ }, useColor, filePath);
229
+ }
230
+ // If it's already a structured ArcRuntimeError, use its fields directly
231
+ if (err instanceof ArcRuntimeError) {
232
+ const cleanMsg = err.message.replace(/ at line \d+(?:, col \d+)?$/, "");
233
+ return formatError({
234
+ code: err.arcCode,
235
+ category: err.arcCategory,
236
+ message: cleanMsg,
237
+ loc: err.loc,
238
+ source,
239
+ suggestion: err.suggestion,
240
+ }, useColor, filePath);
241
+ }
192
242
  // Try to extract location from error message
193
243
  const locMatch = err.message.match(/at line (\d+)(?:, col (\d+))?/);
194
244
  const loc = locMatch ? { line: parseInt(locMatch[1]), col: parseInt(locMatch[2] || "1") } : undefined;
245
+ const cleanMsg = err.message.replace(/ at line \d+(?:, col \d+)?$/, "");
195
246
  // Detect error category
196
247
  let category = "RuntimeError";
197
248
  let code = ErrorCode.UNDEFINED_VARIABLE;
@@ -199,13 +250,16 @@ export function prettyPrintError(err, source, useColor = true) {
199
250
  if (err.message.includes("Parse error")) {
200
251
  category = "ParseError";
201
252
  code = ErrorCode.UNEXPECTED_TOKEN;
253
+ // Extract suggestion for parse errors
254
+ if (err.message.includes("Expected RBrace"))
255
+ suggestion = "Missing closing brace '}'";
256
+ else if (err.message.includes("Expected RParen"))
257
+ suggestion = "Missing closing parenthesis ')'";
258
+ else if (err.message.includes("Expected RBracket"))
259
+ suggestion = "Missing closing bracket ']'";
202
260
  }
203
261
  else if (err.message.includes("Undefined variable")) {
204
262
  code = ErrorCode.UNDEFINED_VARIABLE;
205
- const nameMatch = err.message.match(/Undefined variable: (\w+)/);
206
- if (nameMatch) {
207
- suggestion = `Check that '${nameMatch[1]}' is defined before use`;
208
- }
209
263
  }
210
264
  else if (err.message.includes("Cannot reassign immutable")) {
211
265
  code = ErrorCode.IMMUTABLE_REASSIGN;
@@ -213,12 +267,39 @@ export function prettyPrintError(err, source, useColor = true) {
213
267
  }
214
268
  else if (err.message.includes("Not callable")) {
215
269
  code = ErrorCode.NOT_CALLABLE;
270
+ suggestion = "Only functions can be called. Check that the value is a function.";
271
+ }
272
+ else if (err.message.includes("Division by zero")) {
273
+ code = ErrorCode.DIVISION_BY_ZERO;
274
+ suggestion = "Check that the divisor is not zero before dividing.";
275
+ }
276
+ else if (err.message.includes("Module not found")) {
277
+ category = "ImportError";
278
+ code = ErrorCode.MODULE_NOT_FOUND;
216
279
  }
217
280
  else if (err.message.includes("SecurityError") || err.name === "SecurityError") {
218
281
  category = "SecurityError";
219
282
  code = ErrorCode.EXECUTION_LIMIT;
220
283
  }
221
- return formatError({ code, category, message: err.message, loc, source, suggestion }, useColor);
284
+ else if (err.message.includes("Cannot access property")) {
285
+ code = ErrorCode.PROPERTY_ACCESS;
286
+ }
287
+ return formatError({ code, category, message: cleanMsg, loc, source, suggestion }, useColor, filePath);
288
+ }
289
+ // Custom error class that carries structured location info
290
+ export class ArcRuntimeError extends Error {
291
+ loc;
292
+ arcCode;
293
+ arcCategory;
294
+ suggestion;
295
+ constructor(message, options = {}) {
296
+ super(message);
297
+ this.name = "ArcRuntimeError";
298
+ this.arcCode = options.code ?? ErrorCode.UNDEFINED_VARIABLE;
299
+ this.arcCategory = options.category ?? "RuntimeError";
300
+ this.loc = options.loc;
301
+ this.suggestion = options.suggestion;
302
+ }
222
303
  }
223
304
  let prettyErrorsEnabled = true;
224
305
  export function setPrettyErrors(enabled) {
package/dist/index.js CHANGED
@@ -13,8 +13,8 @@ import { generateJS } from "./codegen-js.js";
13
13
  import { generateWAT } from "./codegen.js";
14
14
  import { format } from "./formatter.js";
15
15
  import { lint, formatDiagnostic } from "./linter.js";
16
- import { printVersion } from "./version.js";
17
- import { setPrettyErrors } from "./errors.js";
16
+ import { printVersion, ARC_VERSION } from "./version.js";
17
+ import { prettyPrintError, setPrettyErrors } from "./errors.js";
18
18
  import { build, test as buildTest, newProject } from "./build.js";
19
19
  import { pkgInit, pkgAdd, pkgRemove, pkgList, pkgInstall } from "./package-manager.js";
20
20
  const args = process.argv.slice(2);
@@ -101,21 +101,32 @@ else if (command === "pkg") {
101
101
  process.exit(1);
102
102
  }
103
103
  }
104
- else if (!command || !file) {
105
- console.log("Usage:");
106
- console.log(" npx tsx src/index.ts run <file.arc> - Execute an Arc file");
107
- console.log(" npx tsx src/index.ts parse <file.arc> - Print the AST");
108
- console.log(" npx tsx src/index.ts ir <file.arc> - Print the IR");
109
- console.log(" npx tsx src/index.ts opt <file.arc> - Print optimized IR");
110
- console.log(" npx tsx src/index.ts compile <file.arc> - Compile to JS (or --target=wat)");
111
- console.log(" npx tsx src/index.ts check <file.arc> - Run semantic analysis");
112
- console.log(" npx tsx src/index.ts fmt <file.arc> - Format source code");
113
- console.log(" npx tsx src/index.ts lint <file.arc> - Lint source code");
114
- console.log(" npx tsx src/index.ts repl - Start interactive REPL");
115
- console.log(" npx tsx src/index.ts fuzz [--iterations=N] - Fuzz test the language");
116
- console.log(" npx tsx src/index.ts bench - Run performance benchmarks");
117
- console.log(" npx tsx src/index.ts bench --tokens - Run token efficiency comparison");
118
- process.exit(1);
104
+ else if (command === "help" || command === "--help" || command === "-h" || !command || !file) {
105
+ console.log(`Arc ${ARC_VERSION} — A programming language designed by AI agents, for AI agents.\n`);
106
+ console.log("Usage: arc <command> [options]\n");
107
+ console.log("Commands:");
108
+ console.log(" run <file.arc> Execute an Arc file");
109
+ console.log(" parse <file.arc> Print the AST");
110
+ console.log(" ir <file.arc> Print the IR");
111
+ console.log(" opt <file.arc> Print optimized IR");
112
+ console.log(" compile <file.arc> Compile to JS (or --target=wat)");
113
+ console.log(" check <file.arc> Run semantic analysis");
114
+ console.log(" fmt <file.arc> Format source code (--write to overwrite)");
115
+ console.log(" lint <file.arc> Lint source code");
116
+ console.log(" repl Start interactive REPL");
117
+ console.log(" build Build the current project");
118
+ console.log(" test Run project tests");
119
+ console.log(" new <name> Create a new project");
120
+ console.log(" pkg <sub> Package manager (init|add|remove|list|install)");
121
+ console.log(" version Print version info");
122
+ console.log("\nOptions:");
123
+ console.log(" --version, -v Print version");
124
+ console.log(" --help, -h Show this help");
125
+ console.log(" --no-pretty-errors Disable pretty error formatting");
126
+ if (!command || (command !== "help" && command !== "--help" && command !== "-h"))
127
+ process.exit(1);
128
+ else
129
+ process.exit(0);
119
130
  }
120
131
  else {
121
132
  const filePath = resolve(file);
@@ -210,7 +221,12 @@ else {
210
221
  }
211
222
  }
212
223
  catch (e) {
213
- console.error(e.message);
224
+ if (e instanceof Error) {
225
+ console.error(prettyPrintError(e, source, true, filePath));
226
+ }
227
+ else {
228
+ console.error(e.message ?? String(e));
229
+ }
214
230
  process.exit(1);
215
231
  }
216
232
  }
@@ -22,6 +22,7 @@ declare class Env {
22
22
  private _depth;
23
23
  constructor(parent?: Env | undefined);
24
24
  get(name: string): Value;
25
+ allNames(): string[];
25
26
  getEntry(name: string): {
26
27
  value: Value;
27
28
  mutable: boolean;