arc-lang 0.5.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.
- package/LICENSE +21 -0
- package/README.md +148 -0
- package/dist/ast.d.ts +298 -0
- package/dist/ast.js +2 -0
- package/dist/build.d.ts +7 -0
- package/dist/build.js +138 -0
- package/dist/codegen-js.d.ts +2 -0
- package/dist/codegen-js.js +168 -0
- package/dist/codegen.d.ts +2 -0
- package/dist/codegen.js +364 -0
- package/dist/errors.d.ts +52 -0
- package/dist/errors.js +229 -0
- package/dist/formatter.d.ts +5 -0
- package/dist/formatter.js +361 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +165 -0
- package/dist/interpreter.d.ts +39 -0
- package/dist/interpreter.js +668 -0
- package/dist/ir.d.ts +126 -0
- package/dist/ir.js +610 -0
- package/dist/lexer.d.ts +79 -0
- package/dist/lexer.js +335 -0
- package/dist/linter.d.ts +15 -0
- package/dist/linter.js +382 -0
- package/dist/lsp.d.ts +1 -0
- package/dist/lsp.js +253 -0
- package/dist/modules.d.ts +24 -0
- package/dist/modules.js +115 -0
- package/dist/optimizer.d.ts +17 -0
- package/dist/optimizer.js +481 -0
- package/dist/package-manager.d.ts +31 -0
- package/dist/package-manager.js +180 -0
- package/dist/parser.d.ts +42 -0
- package/dist/parser.js +779 -0
- package/dist/repl.d.ts +1 -0
- package/dist/repl.js +120 -0
- package/dist/security.d.ts +48 -0
- package/dist/security.js +198 -0
- package/dist/semantic.d.ts +7 -0
- package/dist/semantic.js +327 -0
- package/dist/typechecker.d.ts +7 -0
- package/dist/typechecker.js +132 -0
- package/dist/version.d.ts +26 -0
- package/dist/version.js +71 -0
- package/package.json +51 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
// Arc IR → JavaScript Code Generator
|
|
2
|
+
export function generateJS(module) {
|
|
3
|
+
const lines = [];
|
|
4
|
+
lines.push("// Generated by Arc Compiler");
|
|
5
|
+
lines.push("");
|
|
6
|
+
// Runtime helpers
|
|
7
|
+
lines.push(`// Arc Runtime`);
|
|
8
|
+
lines.push(`const __arc_runtime = {`);
|
|
9
|
+
lines.push(` len(a) { return Array.isArray(a) ? a.length : typeof a === "string" ? a.length : 0; },`);
|
|
10
|
+
lines.push(` str(v) { return String(v); },`);
|
|
11
|
+
lines.push(` push(arr, v) { arr.push(v); return arr; },`);
|
|
12
|
+
lines.push(` print(v) { console.log(typeof v === "object" && v !== null ? JSON.stringify(v) : v); },`);
|
|
13
|
+
lines.push(` head(a) { return a[0]; },`);
|
|
14
|
+
lines.push(` tail(a) { return a.slice(1); },`);
|
|
15
|
+
lines.push(` map(a, f) { return a.map(f); },`);
|
|
16
|
+
lines.push(` filter(a, f) { return a.filter(f); },`);
|
|
17
|
+
lines.push(` fold(a, init, f) { return a.reduce((acc, x) => f(acc, x), init); },`);
|
|
18
|
+
lines.push(` range(start, end) { const r = []; for (let i = start; i < end; i++) r.push(i); return r; },`);
|
|
19
|
+
lines.push(` keys(m) { return m && m.__map ? Array.from(m.entries.keys()) : Object.keys(m || {}); },`);
|
|
20
|
+
lines.push(` values(m) { return m && m.__map ? Array.from(m.entries.values()) : Object.values(m || {}); },`);
|
|
21
|
+
lines.push(` type(v) { if (v === null) return "nil"; if (Array.isArray(v)) return "list"; return typeof v; },`);
|
|
22
|
+
lines.push(` abs(n) { return Math.abs(n); },`);
|
|
23
|
+
lines.push(` max(a, b) { return Math.max(a, b); },`);
|
|
24
|
+
lines.push(` min(a, b) { return Math.min(a, b); },`);
|
|
25
|
+
lines.push(` floor(n) { return Math.floor(n); },`);
|
|
26
|
+
lines.push(` ceil(n) { return Math.ceil(n); },`);
|
|
27
|
+
lines.push(` round(n) { return Math.round(n); },`);
|
|
28
|
+
lines.push(` sort(a) { return [...a].sort((x,y) => x < y ? -1 : x > y ? 1 : 0); },`);
|
|
29
|
+
lines.push(` reverse(a) { return [...a].reverse(); },`);
|
|
30
|
+
lines.push(` contains(a, v) { return Array.isArray(a) ? a.includes(v) : typeof a === "string" ? a.includes(v) : false; },`);
|
|
31
|
+
lines.push(` join(a, sep) { return a.join(sep); },`);
|
|
32
|
+
lines.push(` split(s, sep) { return s.split(sep); },`);
|
|
33
|
+
lines.push(` trim(s) { return s.trim(); },`);
|
|
34
|
+
lines.push(` replace(s, old, nw) { return s.replaceAll(old, nw); },`);
|
|
35
|
+
lines.push(` uppercase(s) { return s.toUpperCase(); },`);
|
|
36
|
+
lines.push(` lowercase(s) { return s.toLowerCase(); },`);
|
|
37
|
+
lines.push(` sum(a) { return a.reduce((s, x) => s + x, 0); },`);
|
|
38
|
+
lines.push(` flat(a) { return a.flat(); },`);
|
|
39
|
+
lines.push(` zip(a, b) { return a.map((x, i) => [x, b[i]]); },`);
|
|
40
|
+
lines.push(` enumerate(a) { return a.map((x, i) => [i, x]); },`);
|
|
41
|
+
lines.push(` slice(a, s, e) { return a.slice(s, e); },`);
|
|
42
|
+
lines.push(` append(a, v) { return [...a, v]; },`);
|
|
43
|
+
lines.push(` concat(a, b) { return [...a, ...b]; },`);
|
|
44
|
+
lines.push(` unique(a) { return [...new Set(a)]; },`);
|
|
45
|
+
lines.push(` int(v) { return parseInt(v, 10); },`);
|
|
46
|
+
lines.push(` float(v) { return parseFloat(v); },`);
|
|
47
|
+
lines.push(` __await(v) { return v && v.__async ? v.thunk() : v; },`);
|
|
48
|
+
lines.push(` __fetch_parallel(...targets) { return targets; },`);
|
|
49
|
+
lines.push(` __make_map(keys, values) { const m = { __map: true, entries: new Map() }; for (let i = 0; i < keys.length; i++) m.entries.set(keys[i], values[i]); return m; },`);
|
|
50
|
+
lines.push(`};`);
|
|
51
|
+
lines.push("");
|
|
52
|
+
// Emit main with hoisted functions
|
|
53
|
+
lines.push("// Main");
|
|
54
|
+
lines.push("(function() {");
|
|
55
|
+
// Hoist function definitions inside the scope
|
|
56
|
+
for (const fn of module.functions) {
|
|
57
|
+
lines.push(emitFunction(fn, " "));
|
|
58
|
+
lines.push("");
|
|
59
|
+
}
|
|
60
|
+
for (const block of module.main) {
|
|
61
|
+
lines.push(...emitBlock(block, " "));
|
|
62
|
+
}
|
|
63
|
+
lines.push("})();");
|
|
64
|
+
return lines.join("\n");
|
|
65
|
+
}
|
|
66
|
+
function emitFunction(fn, baseIndent = "") {
|
|
67
|
+
const lines = [];
|
|
68
|
+
lines.push(`${baseIndent}function ${S(fn.name)}(${fn.params.map(S).join(", ")}) {`);
|
|
69
|
+
for (const block of fn.blocks) {
|
|
70
|
+
lines.push(...emitBlock(block, baseIndent + " "));
|
|
71
|
+
}
|
|
72
|
+
lines.push(`${baseIndent}}`);
|
|
73
|
+
return lines.join("\n");
|
|
74
|
+
}
|
|
75
|
+
function emitBlock(block, indent) {
|
|
76
|
+
const lines = [];
|
|
77
|
+
for (const instr of block.instrs) {
|
|
78
|
+
lines.push(indent + emitInstr(instr));
|
|
79
|
+
}
|
|
80
|
+
return lines;
|
|
81
|
+
}
|
|
82
|
+
function emitInstr(instr) {
|
|
83
|
+
switch (instr.op) {
|
|
84
|
+
case "const":
|
|
85
|
+
return `var ${S(instr.dest)} = ${JSON.stringify(instr.value)};`;
|
|
86
|
+
case "load":
|
|
87
|
+
if (instr.name.startsWith("@fn:")) {
|
|
88
|
+
return `var ${S(instr.dest)} = ${S(instr.name.slice(4))};`;
|
|
89
|
+
}
|
|
90
|
+
return `var ${S(instr.dest)} = ${S(instr.name)};`;
|
|
91
|
+
case "store":
|
|
92
|
+
if (instr.src.startsWith("@fn:")) {
|
|
93
|
+
return `var ${S(instr.name)} = ${S(instr.src.slice(4))};`;
|
|
94
|
+
}
|
|
95
|
+
return `var ${S(instr.name)} = ${S(instr.src)};`;
|
|
96
|
+
case "binop":
|
|
97
|
+
return `var ${S(instr.dest)} = ${emitBinop(instr.operator, S(instr.left), S(instr.right))};`;
|
|
98
|
+
case "unop":
|
|
99
|
+
return `var ${S(instr.dest)} = ${emitUnop(instr.operator, S(instr.operand))};`;
|
|
100
|
+
case "call":
|
|
101
|
+
return `var ${S(instr.dest)} = ${emitCall(instr.fn, instr.args.map(S))};`;
|
|
102
|
+
case "toolcall":
|
|
103
|
+
return `var ${S(instr.dest)} = await fetch(${S(instr.url)}, { method: ${JSON.stringify(instr.method)}${instr.body ? `, body: JSON.stringify(${S(instr.body)})` : ""} }).then(r => r.json());`;
|
|
104
|
+
case "field":
|
|
105
|
+
return `var ${S(instr.dest)} = (${S(instr.obj)} && ${S(instr.obj)}.__map) ? ${S(instr.obj)}.entries.get(${JSON.stringify(instr.prop)}) : ${S(instr.obj)}[${JSON.stringify(instr.prop)}];`;
|
|
106
|
+
case "index":
|
|
107
|
+
return `var ${S(instr.dest)} = ${S(instr.obj)}[${S(instr.idx)}];`;
|
|
108
|
+
case "setfield":
|
|
109
|
+
return `if (${S(instr.obj)} && ${S(instr.obj)}.__map) { ${S(instr.obj)}.entries.set(${JSON.stringify(instr.prop)}, ${S(instr.src)}); } else { ${S(instr.obj)}[${JSON.stringify(instr.prop)}] = ${S(instr.src)}; }`;
|
|
110
|
+
case "setindex":
|
|
111
|
+
return `${S(instr.obj)}[${S(instr.idx)}] = ${S(instr.src)};`;
|
|
112
|
+
case "jump":
|
|
113
|
+
return `/* jump ${instr.target} */`;
|
|
114
|
+
case "branch":
|
|
115
|
+
return `if (${S(instr.cond)}) { /* ${instr.ifTrue} */ } /* branch */`;
|
|
116
|
+
case "phi":
|
|
117
|
+
return `var ${S(instr.dest)} = undefined; /* phi */`;
|
|
118
|
+
case "ret":
|
|
119
|
+
return instr.value ? `return ${S(instr.value)};` : "return;";
|
|
120
|
+
case "list":
|
|
121
|
+
return `var ${S(instr.dest)} = [${instr.elements.map(S).join(", ")}];`;
|
|
122
|
+
case "map":
|
|
123
|
+
return `var ${S(instr.dest)} = __arc_runtime.__make_map([${instr.keys.map(S).join(", ")}], [${instr.values.map(S).join(", ")}]);`;
|
|
124
|
+
case "label":
|
|
125
|
+
return `/* ${instr.name}: */`;
|
|
126
|
+
case "print":
|
|
127
|
+
return `__arc_runtime.print(${S(instr.value)});`;
|
|
128
|
+
case "range":
|
|
129
|
+
return `var ${S(instr.dest)} = __arc_runtime.range(${S(instr.start)}, ${S(instr.end)});`;
|
|
130
|
+
case "nop":
|
|
131
|
+
return "/* nop */";
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function emitBinop(op, left, right) {
|
|
135
|
+
switch (op) {
|
|
136
|
+
case "++": return `String(${left}) + String(${right})`;
|
|
137
|
+
case "and": return `(${left} && ${right})`;
|
|
138
|
+
case "or": return `(${left} || ${right})`;
|
|
139
|
+
case "==": return `(${left} === ${right})`;
|
|
140
|
+
case "!=": return `(${left} !== ${right})`;
|
|
141
|
+
case "**": return `(${left} ** ${right})`;
|
|
142
|
+
case "%": return `(${left} % ${right})`;
|
|
143
|
+
default: return `(${left} ${op} ${right})`;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function emitUnop(op, operand) {
|
|
147
|
+
switch (op) {
|
|
148
|
+
case "not": return `(!${operand})`;
|
|
149
|
+
default: return `(${op}${operand})`;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function emitCall(fn, args) {
|
|
153
|
+
const builtins = [
|
|
154
|
+
"len", "str", "push", "print", "head", "tail", "map", "filter", "fold",
|
|
155
|
+
"range", "keys", "values", "type", "abs", "max", "min", "floor", "ceil",
|
|
156
|
+
"round", "sort", "reverse", "contains", "join", "split", "trim", "replace",
|
|
157
|
+
"uppercase", "lowercase", "sum", "flat", "zip", "enumerate", "slice",
|
|
158
|
+
"append", "concat", "unique", "int", "float", "__await", "__fetch_parallel"
|
|
159
|
+
];
|
|
160
|
+
if (builtins.includes(fn)) {
|
|
161
|
+
return `__arc_runtime.${fn}(${args.join(", ")})`;
|
|
162
|
+
}
|
|
163
|
+
return `${S(fn)}(${args.join(", ")})`;
|
|
164
|
+
}
|
|
165
|
+
function sanitizeName(name) {
|
|
166
|
+
return name.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
167
|
+
}
|
|
168
|
+
function S(name) { return sanitizeName(name); }
|
package/dist/codegen.js
ADDED
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
// Arc IR → WAT (WebAssembly Text Format) Code Generator
|
|
2
|
+
export function generateWAT(module) {
|
|
3
|
+
const gen = new WATGenerator();
|
|
4
|
+
return gen.generate(module);
|
|
5
|
+
}
|
|
6
|
+
class WATGenerator {
|
|
7
|
+
locals = new Set();
|
|
8
|
+
stringTable = new Map();
|
|
9
|
+
stringOffset = 0;
|
|
10
|
+
dataSegments = [];
|
|
11
|
+
generate(module) {
|
|
12
|
+
const lines = [];
|
|
13
|
+
// First pass: collect all strings and locals
|
|
14
|
+
this.collectStrings(module);
|
|
15
|
+
lines.push("(module");
|
|
16
|
+
// Import runtime functions
|
|
17
|
+
lines.push(' ;; Runtime imports');
|
|
18
|
+
lines.push(' (import "arc" "print_i32" (func $print_i32 (param i32)))');
|
|
19
|
+
lines.push(' (import "arc" "print_f64" (func $print_f64 (param f64)))');
|
|
20
|
+
lines.push(' (import "arc" "print_str" (func $print_str (param i32 i32)))');
|
|
21
|
+
lines.push(' (import "arc" "tool_call" (func $tool_call (param i32 i32 i32 i32) (result i32)))');
|
|
22
|
+
lines.push(' (import "arc" "alloc" (func $alloc (param i32) (result i32)))');
|
|
23
|
+
lines.push(' (import "arc" "list_new" (func $list_new (result i32)))');
|
|
24
|
+
lines.push(' (import "arc" "list_push" (func $list_push (param i32 i32) (result i32)))');
|
|
25
|
+
lines.push(' (import "arc" "list_get" (func $list_get (param i32 i32) (result i32)))');
|
|
26
|
+
lines.push(' (import "arc" "list_len" (func $list_len (param i32) (result i32)))');
|
|
27
|
+
lines.push(' (import "arc" "map_new" (func $map_new (result i32)))');
|
|
28
|
+
lines.push(' (import "arc" "map_set" (func $map_set (param i32 i32 i32) (result i32)))');
|
|
29
|
+
lines.push(' (import "arc" "map_get" (func $map_get (param i32 i32) (result i32)))');
|
|
30
|
+
lines.push("");
|
|
31
|
+
// Memory
|
|
32
|
+
lines.push(" (memory (export \"memory\") 1)");
|
|
33
|
+
lines.push("");
|
|
34
|
+
// Data segments for strings
|
|
35
|
+
if (this.dataSegments.length > 0) {
|
|
36
|
+
lines.push(" ;; String data");
|
|
37
|
+
for (const seg of this.dataSegments) {
|
|
38
|
+
lines.push(` ${seg}`);
|
|
39
|
+
}
|
|
40
|
+
lines.push("");
|
|
41
|
+
}
|
|
42
|
+
// Global variables for locals (simple approach: use globals for main scope)
|
|
43
|
+
lines.push(" ;; Globals");
|
|
44
|
+
lines.push(` (global $__sp (mut i32) (i32.const ${this.stringOffset}))`);
|
|
45
|
+
lines.push("");
|
|
46
|
+
// Emit functions
|
|
47
|
+
for (const fn of module.functions) {
|
|
48
|
+
lines.push(this.emitFunction(fn));
|
|
49
|
+
lines.push("");
|
|
50
|
+
}
|
|
51
|
+
// Emit main as _start
|
|
52
|
+
lines.push(' (func (export "_start")');
|
|
53
|
+
this.locals.clear();
|
|
54
|
+
// Collect locals from main blocks
|
|
55
|
+
for (const block of module.main) {
|
|
56
|
+
this.collectLocals(block);
|
|
57
|
+
}
|
|
58
|
+
for (const local of this.locals) {
|
|
59
|
+
lines.push(` (local $${sanitize(local)} i32)`);
|
|
60
|
+
}
|
|
61
|
+
for (const block of module.main) {
|
|
62
|
+
lines.push(...this.emitBlockInstrs(block, " "));
|
|
63
|
+
}
|
|
64
|
+
lines.push(" )");
|
|
65
|
+
lines.push(")");
|
|
66
|
+
return lines.join("\n");
|
|
67
|
+
}
|
|
68
|
+
collectStrings(module) {
|
|
69
|
+
const visit = (instrs) => {
|
|
70
|
+
for (const instr of instrs) {
|
|
71
|
+
if (instr.op === "const" && typeof instr.value === "string") {
|
|
72
|
+
this.addString(instr.value);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
for (const fn of module.functions) {
|
|
77
|
+
for (const block of fn.blocks)
|
|
78
|
+
visit(block.instrs);
|
|
79
|
+
}
|
|
80
|
+
for (const block of module.main)
|
|
81
|
+
visit(block.instrs);
|
|
82
|
+
}
|
|
83
|
+
addString(s) {
|
|
84
|
+
if (this.stringTable.has(s))
|
|
85
|
+
return this.stringTable.get(s);
|
|
86
|
+
const offset = this.stringOffset;
|
|
87
|
+
const encoded = new TextEncoder().encode(s);
|
|
88
|
+
this.stringTable.set(s, offset);
|
|
89
|
+
// Escape for WAT data segment
|
|
90
|
+
let escaped = "";
|
|
91
|
+
for (const b of encoded) {
|
|
92
|
+
escaped += "\\" + b.toString(16).padStart(2, "0");
|
|
93
|
+
}
|
|
94
|
+
this.dataSegments.push(`(data (i32.const ${offset}) "${escaped}")`);
|
|
95
|
+
this.stringOffset += encoded.length;
|
|
96
|
+
return offset;
|
|
97
|
+
}
|
|
98
|
+
collectLocals(block) {
|
|
99
|
+
for (const instr of block.instrs) {
|
|
100
|
+
if ("dest" in instr && instr.dest)
|
|
101
|
+
this.locals.add(instr.dest);
|
|
102
|
+
if (instr.op === "store")
|
|
103
|
+
this.locals.add(instr.name);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
emitFunction(fn) {
|
|
107
|
+
const lines = [];
|
|
108
|
+
this.locals.clear();
|
|
109
|
+
// Collect locals
|
|
110
|
+
for (const block of fn.blocks)
|
|
111
|
+
this.collectLocals(block);
|
|
112
|
+
const params = fn.params.map(p => `(param $${sanitize(p)} i32)`).join(" ");
|
|
113
|
+
lines.push(` (func $${sanitize(fn.name)} ${params} (result i32)`);
|
|
114
|
+
// Declare locals (excluding params)
|
|
115
|
+
const paramSet = new Set(fn.params);
|
|
116
|
+
for (const local of this.locals) {
|
|
117
|
+
if (!paramSet.has(local)) {
|
|
118
|
+
lines.push(` (local $${sanitize(local)} i32)`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
for (const block of fn.blocks) {
|
|
122
|
+
lines.push(...this.emitBlockInstrs(block, " "));
|
|
123
|
+
}
|
|
124
|
+
// Default return
|
|
125
|
+
lines.push(" i32.const 0");
|
|
126
|
+
lines.push(" )");
|
|
127
|
+
return lines.join("\n");
|
|
128
|
+
}
|
|
129
|
+
emitBlockInstrs(block, indent) {
|
|
130
|
+
const lines = [];
|
|
131
|
+
lines.push(`${indent};; ${block.label}:`);
|
|
132
|
+
for (const instr of block.instrs) {
|
|
133
|
+
lines.push(...this.emitInstr(instr, indent));
|
|
134
|
+
}
|
|
135
|
+
return lines;
|
|
136
|
+
}
|
|
137
|
+
emitInstr(instr, indent) {
|
|
138
|
+
const lines = [];
|
|
139
|
+
const I = indent;
|
|
140
|
+
switch (instr.op) {
|
|
141
|
+
case "const": {
|
|
142
|
+
if (typeof instr.value === "number") {
|
|
143
|
+
if (Number.isInteger(instr.value)) {
|
|
144
|
+
lines.push(`${I}i32.const ${instr.value}`);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
// Store float as i32 bits (simplified — real impl would use f64)
|
|
148
|
+
lines.push(`${I}i32.const ${Math.round(instr.value)}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
else if (typeof instr.value === "boolean") {
|
|
152
|
+
lines.push(`${I}i32.const ${instr.value ? 1 : 0}`);
|
|
153
|
+
}
|
|
154
|
+
else if (instr.value === null) {
|
|
155
|
+
lines.push(`${I}i32.const 0`);
|
|
156
|
+
}
|
|
157
|
+
else if (typeof instr.value === "string") {
|
|
158
|
+
const offset = this.stringTable.get(instr.value) ?? 0;
|
|
159
|
+
const len = new TextEncoder().encode(instr.value).length;
|
|
160
|
+
// Pack offset and length — simplified: just store offset
|
|
161
|
+
lines.push(`${I}i32.const ${offset} ;; str "${instr.value.slice(0, 20)}"`);
|
|
162
|
+
}
|
|
163
|
+
lines.push(`${I}local.set $${sanitize(instr.dest)}`);
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
case "load": {
|
|
167
|
+
if (instr.name.startsWith("@fn:")) {
|
|
168
|
+
lines.push(`${I}i32.const 0 ;; fn ref ${instr.name}`);
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
lines.push(`${I}local.get $${sanitize(instr.name)}`);
|
|
172
|
+
}
|
|
173
|
+
lines.push(`${I}local.set $${sanitize(instr.dest)}`);
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
case "store": {
|
|
177
|
+
if (instr.src.startsWith("@fn:")) {
|
|
178
|
+
lines.push(`${I}i32.const 0 ;; fn ref ${instr.src}`);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
lines.push(`${I}local.get $${sanitize(instr.src)}`);
|
|
182
|
+
}
|
|
183
|
+
lines.push(`${I}local.set $${sanitize(instr.name)}`);
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
case "binop": {
|
|
187
|
+
lines.push(`${I}local.get $${sanitize(instr.left)}`);
|
|
188
|
+
lines.push(`${I}local.get $${sanitize(instr.right)}`);
|
|
189
|
+
lines.push(`${I}${watBinop(instr.operator)}`);
|
|
190
|
+
lines.push(`${I}local.set $${sanitize(instr.dest)}`);
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
case "unop": {
|
|
194
|
+
if (instr.operator === "not" || instr.operator === "!") {
|
|
195
|
+
lines.push(`${I}local.get $${sanitize(instr.operand)}`);
|
|
196
|
+
lines.push(`${I}i32.eqz`);
|
|
197
|
+
}
|
|
198
|
+
else if (instr.operator === "-") {
|
|
199
|
+
lines.push(`${I}i32.const 0`);
|
|
200
|
+
lines.push(`${I}local.get $${sanitize(instr.operand)}`);
|
|
201
|
+
lines.push(`${I}i32.sub`);
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
lines.push(`${I}local.get $${sanitize(instr.operand)}`);
|
|
205
|
+
}
|
|
206
|
+
lines.push(`${I}local.set $${sanitize(instr.dest)}`);
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
case "call": {
|
|
210
|
+
// Push args
|
|
211
|
+
for (const arg of instr.args) {
|
|
212
|
+
lines.push(`${I}local.get $${sanitize(arg)}`);
|
|
213
|
+
}
|
|
214
|
+
// Call
|
|
215
|
+
if (isRuntimeBuiltin(instr.fn)) {
|
|
216
|
+
lines.push(`${I}call $__rt_${sanitize(instr.fn)}`);
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
lines.push(`${I}call $${sanitize(instr.fn)}`);
|
|
220
|
+
}
|
|
221
|
+
lines.push(`${I}local.set $${sanitize(instr.dest)}`);
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
case "toolcall": {
|
|
225
|
+
lines.push(`${I}local.get $${sanitize(instr.url)}`);
|
|
226
|
+
lines.push(`${I}i32.const ${this.stringTable.get(instr.method) ?? this.addString(instr.method)}`);
|
|
227
|
+
lines.push(`${I}i32.const ${instr.method.length}`);
|
|
228
|
+
if (instr.body) {
|
|
229
|
+
lines.push(`${I}local.get $${sanitize(instr.body)}`);
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
lines.push(`${I}i32.const 0`);
|
|
233
|
+
}
|
|
234
|
+
lines.push(`${I}call $tool_call`);
|
|
235
|
+
lines.push(`${I}local.set $${sanitize(instr.dest)}`);
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
case "field": {
|
|
239
|
+
lines.push(`${I}local.get $${sanitize(instr.obj)}`);
|
|
240
|
+
const propOffset = this.stringTable.get(instr.prop) ?? this.addString(instr.prop);
|
|
241
|
+
lines.push(`${I}i32.const ${propOffset}`);
|
|
242
|
+
lines.push(`${I}call $map_get`);
|
|
243
|
+
lines.push(`${I}local.set $${sanitize(instr.dest)}`);
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
case "index": {
|
|
247
|
+
lines.push(`${I}local.get $${sanitize(instr.obj)}`);
|
|
248
|
+
lines.push(`${I}local.get $${sanitize(instr.idx)}`);
|
|
249
|
+
lines.push(`${I}call $list_get`);
|
|
250
|
+
lines.push(`${I}local.set $${sanitize(instr.dest)}`);
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
case "setfield": {
|
|
254
|
+
lines.push(`${I}local.get $${sanitize(instr.obj)}`);
|
|
255
|
+
const pOff = this.stringTable.get(instr.prop) ?? this.addString(instr.prop);
|
|
256
|
+
lines.push(`${I}i32.const ${pOff}`);
|
|
257
|
+
lines.push(`${I}local.get $${sanitize(instr.src)}`);
|
|
258
|
+
lines.push(`${I}call $map_set`);
|
|
259
|
+
lines.push(`${I}drop`);
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
case "setindex": {
|
|
263
|
+
lines.push(`${I};; setindex ${instr.obj}[${instr.idx}] = ${instr.src}`);
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
case "list": {
|
|
267
|
+
lines.push(`${I}call $list_new`);
|
|
268
|
+
lines.push(`${I}local.set $${sanitize(instr.dest)}`);
|
|
269
|
+
for (const elem of instr.elements) {
|
|
270
|
+
lines.push(`${I}local.get $${sanitize(instr.dest)}`);
|
|
271
|
+
lines.push(`${I}local.get $${sanitize(elem)}`);
|
|
272
|
+
lines.push(`${I}call $list_push`);
|
|
273
|
+
lines.push(`${I}local.set $${sanitize(instr.dest)}`);
|
|
274
|
+
}
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
case "map": {
|
|
278
|
+
lines.push(`${I}call $map_new`);
|
|
279
|
+
lines.push(`${I}local.set $${sanitize(instr.dest)}`);
|
|
280
|
+
for (let i = 0; i < instr.keys.length; i++) {
|
|
281
|
+
lines.push(`${I}local.get $${sanitize(instr.dest)}`);
|
|
282
|
+
lines.push(`${I}local.get $${sanitize(instr.keys[i])}`);
|
|
283
|
+
lines.push(`${I}local.get $${sanitize(instr.values[i])}`);
|
|
284
|
+
lines.push(`${I}call $map_set`);
|
|
285
|
+
lines.push(`${I}local.set $${sanitize(instr.dest)}`);
|
|
286
|
+
}
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
case "jump": {
|
|
290
|
+
lines.push(`${I};; jump ${instr.target}`);
|
|
291
|
+
break;
|
|
292
|
+
}
|
|
293
|
+
case "branch": {
|
|
294
|
+
lines.push(`${I}local.get $${sanitize(instr.cond)}`);
|
|
295
|
+
lines.push(`${I};; branch -> ${instr.ifTrue} / ${instr.ifFalse}`);
|
|
296
|
+
break;
|
|
297
|
+
}
|
|
298
|
+
case "label": {
|
|
299
|
+
lines.push(`${I};; label ${instr.name}:`);
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
case "print": {
|
|
303
|
+
lines.push(`${I}local.get $${sanitize(instr.value)}`);
|
|
304
|
+
lines.push(`${I}call $print_i32`);
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
case "range": {
|
|
308
|
+
lines.push(`${I};; range(${instr.start}, ${instr.end})`);
|
|
309
|
+
lines.push(`${I}call $list_new`);
|
|
310
|
+
lines.push(`${I}local.set $${sanitize(instr.dest)}`);
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
case "ret": {
|
|
314
|
+
if (instr.value) {
|
|
315
|
+
lines.push(`${I}local.get $${sanitize(instr.value)}`);
|
|
316
|
+
lines.push(`${I}return`);
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
lines.push(`${I}i32.const 0`);
|
|
320
|
+
lines.push(`${I}return`);
|
|
321
|
+
}
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
case "phi": {
|
|
325
|
+
lines.push(`${I};; phi ${instr.dest}`);
|
|
326
|
+
lines.push(`${I}i32.const 0`);
|
|
327
|
+
lines.push(`${I}local.set $${sanitize(instr.dest)}`);
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
case "nop": {
|
|
331
|
+
lines.push(`${I}nop`);
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return lines;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
function watBinop(op) {
|
|
339
|
+
switch (op) {
|
|
340
|
+
case "+": return "i32.add";
|
|
341
|
+
case "-": return "i32.sub";
|
|
342
|
+
case "*": return "i32.mul";
|
|
343
|
+
case "/": return "i32.div_s";
|
|
344
|
+
case "%": return "i32.rem_s";
|
|
345
|
+
case "==": return "i32.eq";
|
|
346
|
+
case "!=": return "i32.ne";
|
|
347
|
+
case "<": return "i32.lt_s";
|
|
348
|
+
case ">": return "i32.gt_s";
|
|
349
|
+
case "<=": return "i32.le_s";
|
|
350
|
+
case ">=": return "i32.ge_s";
|
|
351
|
+
case "and": return "i32.and";
|
|
352
|
+
case "or": return "i32.or";
|
|
353
|
+
case "**": return "i32.mul ;; TODO: power";
|
|
354
|
+
case "++": return "i32.add ;; TODO: string concat";
|
|
355
|
+
default: return `i32.add ;; TODO: ${op}`;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
function isRuntimeBuiltin(fn) {
|
|
359
|
+
return ["len", "str", "push", "print", "head", "tail", "map", "filter", "fold",
|
|
360
|
+
"range", "keys", "values", "type", "__await", "__fetch_parallel"].includes(fn);
|
|
361
|
+
}
|
|
362
|
+
function sanitize(name) {
|
|
363
|
+
return name.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
364
|
+
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as AST from "./ast.js";
|
|
2
|
+
export declare enum ErrorCode {
|
|
3
|
+
UNEXPECTED_TOKEN = "ARC001",
|
|
4
|
+
MISSING_CLOSING_PAREN = "ARC002",
|
|
5
|
+
MISSING_CLOSING_BRACKET = "ARC003",
|
|
6
|
+
MISSING_CLOSING_BRACE = "ARC004",
|
|
7
|
+
EXPECTED_EXPRESSION = "ARC005",
|
|
8
|
+
INVALID_ASSIGNMENT = "ARC006",
|
|
9
|
+
UNTERMINATED_STRING = "ARC007",
|
|
10
|
+
INVALID_NUMBER = "ARC008",
|
|
11
|
+
TYPE_MISMATCH = "ARC100",
|
|
12
|
+
INVALID_OPERATOR = "ARC101",
|
|
13
|
+
NOT_CALLABLE = "ARC102",
|
|
14
|
+
WRONG_ARITY = "ARC103",
|
|
15
|
+
UNDEFINED_VARIABLE = "ARC200",
|
|
16
|
+
IMMUTABLE_REASSIGN = "ARC201",
|
|
17
|
+
INDEX_OUT_OF_BOUNDS = "ARC202",
|
|
18
|
+
DIVISION_BY_ZERO = "ARC203",
|
|
19
|
+
NOT_ITERABLE = "ARC204",
|
|
20
|
+
ASSERTION_FAILED = "ARC205",
|
|
21
|
+
PROPERTY_ACCESS = "ARC206",
|
|
22
|
+
MODULE_NOT_FOUND = "ARC300",
|
|
23
|
+
CIRCULAR_IMPORT = "ARC301",
|
|
24
|
+
SOURCE_TOO_LARGE = "ARC400",
|
|
25
|
+
NESTING_TOO_DEEP = "ARC401",
|
|
26
|
+
EXECUTION_LIMIT = "ARC402",
|
|
27
|
+
RECURSION_LIMIT = "ARC403",
|
|
28
|
+
TOOL_CALL_BLOCKED = "ARC404",
|
|
29
|
+
IMPORT_BLOCKED = "ARC405",
|
|
30
|
+
TIMEOUT = "ARC406"
|
|
31
|
+
}
|
|
32
|
+
export type ErrorCategory = "ParseError" | "TypeError" | "RuntimeError" | "ImportError" | "SecurityError";
|
|
33
|
+
export interface ArcError {
|
|
34
|
+
code: ErrorCode;
|
|
35
|
+
category: ErrorCategory;
|
|
36
|
+
message: string;
|
|
37
|
+
loc?: AST.Loc;
|
|
38
|
+
source?: string;
|
|
39
|
+
suggestion?: string;
|
|
40
|
+
}
|
|
41
|
+
export declare function levenshtein(a: string, b: string): number;
|
|
42
|
+
export declare function findClosestMatch(name: string, candidates: string[], maxDistance?: number): string | null;
|
|
43
|
+
export declare function formatError(error: ArcError, useColor?: boolean): string;
|
|
44
|
+
export declare function undefinedVariableError(name: string, candidates: string[], loc?: AST.Loc, source?: string): ArcError;
|
|
45
|
+
export declare function parseError(message: string, loc?: AST.Loc, source?: string, suggestion?: string): ArcError;
|
|
46
|
+
export declare function typeError(message: string, loc?: AST.Loc, source?: string): ArcError;
|
|
47
|
+
export declare function runtimeError(code: ErrorCode, message: string, loc?: AST.Loc, source?: string, suggestion?: string): ArcError;
|
|
48
|
+
export declare function importError(message: string, loc?: AST.Loc, source?: string): ArcError;
|
|
49
|
+
export declare function securityError(code: ErrorCode, message: string): ArcError;
|
|
50
|
+
export declare function prettyPrintError(err: Error, source?: string, useColor?: boolean): string;
|
|
51
|
+
export declare function setPrettyErrors(enabled: boolean): void;
|
|
52
|
+
export declare function isPrettyErrorsEnabled(): boolean;
|