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 +14 -2
- package/dist/errors.js +88 -7
- package/dist/index.js +34 -18
- package/dist/interpreter.d.ts +1 -0
- package/dist/interpreter.js +1173 -44
- package/dist/lexer.js +5 -0
- package/dist/repl.js +3 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
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
|
-
|
|
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(
|
|
106
|
-
console.log("
|
|
107
|
-
console.log("
|
|
108
|
-
console.log("
|
|
109
|
-
console.log("
|
|
110
|
-
console.log("
|
|
111
|
-
console.log("
|
|
112
|
-
console.log("
|
|
113
|
-
console.log("
|
|
114
|
-
console.log("
|
|
115
|
-
console.log("
|
|
116
|
-
console.log("
|
|
117
|
-
console.log("
|
|
118
|
-
|
|
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
|
-
|
|
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
|
}
|