arc-lang 0.6.3 → 0.6.4
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/README.md +65 -130
- package/dist/formatter.js +15 -3
- package/dist/interpreter.js +1 -1
- package/dist/linter.js +18 -0
- package/dist/parser.js +19 -0
- package/dist/repl.js +4 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,148 +1,83 @@
|
|
|
1
|
-
# Arc ⚡
|
|
1
|
+
# Arc Compiler ⚡
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The compiler/interpreter implementation for the [Arc programming language](https://github.com/kai-builds-ai/arc-lang).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Architecture
|
|
6
6
|
|
|
7
|
-
## Quick Start
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
# Clone and install
|
|
11
|
-
git clone https://github.com/kai-builds-ai/arc-lang.git
|
|
12
|
-
cd arc-lang/compiler && npm install && cd ..
|
|
13
|
-
|
|
14
|
-
# Run an example
|
|
15
|
-
npx tsx compiler/src/index.ts run examples/hello-world.arc
|
|
16
|
-
|
|
17
|
-
# Start the REPL
|
|
18
|
-
npx tsx compiler/src/index.ts repl
|
|
19
7
|
```
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
```arc
|
|
43
|
-
# AI agent that fetches data, analyzes it, and acts
|
|
44
|
-
let [weather, news] = fetch [
|
|
45
|
-
@GET "api/weather?city=NYC",
|
|
46
|
-
@GET "api/news/top?limit=3"
|
|
47
|
-
]
|
|
48
|
-
|
|
49
|
-
let headlines = news.articles
|
|
50
|
-
|> take(3)
|
|
51
|
-
|> map(a => "• {a.title}")
|
|
52
|
-
|> join("\n")
|
|
53
|
-
|
|
54
|
-
let advice = match weather.condition {
|
|
55
|
-
"rain" | "storm" => "Bring an umbrella!",
|
|
56
|
-
"snow" => "Bundle up!",
|
|
57
|
-
_ => "Enjoy the weather!"
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
print("{advice}\n\nTop News:\n{headlines}")
|
|
8
|
+
src/
|
|
9
|
+
├── index.ts # CLI entry point
|
|
10
|
+
├── lexer.ts # Tokenizer
|
|
11
|
+
├── parser.ts # Parser → AST
|
|
12
|
+
├── ast.ts # AST node types
|
|
13
|
+
├── interpreter.ts # Tree-walking interpreter
|
|
14
|
+
├── modules.ts # Module resolver & loader
|
|
15
|
+
├── ir.ts # Intermediate representation
|
|
16
|
+
├── optimizer.ts # IR optimizer
|
|
17
|
+
├── codegen.ts # WAT code generation
|
|
18
|
+
├── codegen-js.ts # JavaScript code generation
|
|
19
|
+
├── semantic.ts # Semantic analysis
|
|
20
|
+
├── typechecker.ts # Type checker
|
|
21
|
+
├── formatter.ts # Code formatter
|
|
22
|
+
├── linter.ts # Linter
|
|
23
|
+
├── errors.ts # Error types & pretty printing
|
|
24
|
+
├── security.ts # Security sandbox
|
|
25
|
+
├── repl.ts # Interactive REPL
|
|
26
|
+
├── build.ts # Build system & project scaffolding
|
|
27
|
+
├── package-manager.ts # Package manager
|
|
28
|
+
├── lsp.ts # Language Server Protocol
|
|
29
|
+
└── version.ts # Version info
|
|
61
30
|
```
|
|
62
31
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
## Standard Library
|
|
66
|
-
|
|
67
|
-
Arc ships with a growing standard library. Currently implemented:
|
|
32
|
+
## Development
|
|
68
33
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
| [`strings`](stdlib/strings.arc) | pad_left, pad_right, capitalize, words |
|
|
73
|
-
| [`collections`](stdlib/collections.arc) | set, unique, group_by, chunk, flatten, zip_with, partition, sort_by |
|
|
74
|
-
| [`map`](stdlib/map.arc) | merge, map_values, filter_map, from_pairs, pick, omit |
|
|
75
|
-
| [`io`](stdlib/io.arc) | read_lines, write_lines, exists, append |
|
|
76
|
-
| [`http`](stdlib/http.arc) | get, post, put, delete, fetch_all, parse_url |
|
|
77
|
-
| [`json`](stdlib/json.arc) | to_json, from_json, pretty, get_path |
|
|
78
|
-
| [`csv`](stdlib/csv.arc) | parse_csv, to_csv, parse_csv_headers |
|
|
79
|
-
| [`test`](stdlib/test.arc) | describe, it, expect_eq, expect_true, run_tests |
|
|
80
|
-
| [`result`](stdlib/result.arc) | ok, err, is_ok, unwrap, map_result, try_fn |
|
|
81
|
-
| [`time`](stdlib/time.arc) | now, format_duration, sleep |
|
|
82
|
-
|
|
83
|
-
Plus many built-in functions available without imports: `map`, `filter`, `reduce`, `print`, `len`, `split`, `join`, `trim`, and more.
|
|
84
|
-
|
|
85
|
-
📖 **[Standard Library Reference](docs/stdlib-reference.md)** | **[Standard Library Tutorial](docs/stdlib-tutorial.md)**
|
|
86
|
-
|
|
87
|
-
## Documentation
|
|
88
|
-
|
|
89
|
-
- **[Getting Started](docs/getting-started.md)** — Installation, first program, REPL, basics
|
|
90
|
-
- **[Language Tour](docs/language-tour.md)** — Complete feature walkthrough
|
|
91
|
-
- **[Standard Library Reference](docs/stdlib-reference.md)** — Full stdlib API reference
|
|
92
|
-
- **[Standard Library Tutorial](docs/stdlib-tutorial.md)** — Hands-on stdlib guide
|
|
93
|
-
- **[Examples](examples/)** — Real-world programs with token comparisons
|
|
94
|
-
- **[FAQ](docs/FAQ.md)** — Common questions answered
|
|
95
|
-
- **[Grammar Spec](spec/grammar.md)** — Formal language specification
|
|
96
|
-
|
|
97
|
-
## Status
|
|
98
|
-
|
|
99
|
-
🚀 **In Active Development** — Arc has a working compiler (lexer, parser, IR, optimizer, JS/WAT codegen), interpreter, REPL, 17 stdlib modules, LSP, VS Code extension, package manager, build system, formatter, linter, security sandbox, rich error reporting, benchmarking framework, and migration tools. 508+ tests passing.
|
|
100
|
-
|
|
101
|
-
Current phase: **Phase 6 — Community & Adoption**
|
|
34
|
+
```bash
|
|
35
|
+
# Install dependencies
|
|
36
|
+
npm install
|
|
102
37
|
|
|
103
|
-
|
|
38
|
+
# Build (TypeScript → JavaScript)
|
|
39
|
+
npm run build
|
|
104
40
|
|
|
105
|
-
|
|
41
|
+
# Run directly from source
|
|
42
|
+
npx tsx src/index.ts run ../examples/hello-world.arc
|
|
106
43
|
|
|
107
|
-
|
|
108
|
-
arc
|
|
109
|
-
├── README.md # You are here
|
|
110
|
-
├── PHILOSOPHY.md # Design principles & rationale
|
|
111
|
-
├── ROADMAP.md # Development phases & milestones
|
|
112
|
-
├── LICENSE # MIT License
|
|
113
|
-
├── docs/ # Comprehensive documentation
|
|
114
|
-
├── spec/ # Formal language specification
|
|
115
|
-
├── examples/ # Code samples & tutorials
|
|
116
|
-
├── compiler/ # Compiler/interpreter implementation
|
|
117
|
-
├── stdlib/ # Standard library
|
|
118
|
-
└── CONTRIBUTING.md # Contribution guidelines
|
|
44
|
+
# Run with compiled output
|
|
45
|
+
node dist/index.js run ../examples/hello-world.arc
|
|
119
46
|
```
|
|
120
47
|
|
|
121
|
-
##
|
|
48
|
+
## CLI Commands
|
|
122
49
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
50
|
+
```bash
|
|
51
|
+
arc run <file> # Execute an Arc file
|
|
52
|
+
arc repl # Interactive REPL
|
|
53
|
+
arc parse <file> # Print AST
|
|
54
|
+
arc ir <file> # Print IR
|
|
55
|
+
arc compile <file> # Compile to JS (or --target=wat)
|
|
56
|
+
arc check <file> # Semantic analysis
|
|
57
|
+
arc fmt <file> # Format code (--write to overwrite)
|
|
58
|
+
arc lint <file> # Lint code
|
|
59
|
+
arc builtins # List all built-in functions
|
|
60
|
+
arc builtins --modules # List stdlib modules
|
|
61
|
+
arc build # Build project
|
|
62
|
+
arc test # Run project tests
|
|
63
|
+
arc new <name> # Scaffold new project
|
|
64
|
+
arc version # Print version
|
|
65
|
+
```
|
|
139
66
|
|
|
140
|
-
|
|
67
|
+
## Publishing
|
|
141
68
|
|
|
142
|
-
|
|
69
|
+
```bash
|
|
70
|
+
npm run copy-stdlib # Copy stdlib into compiler package
|
|
71
|
+
npm run build # Compile TypeScript
|
|
72
|
+
npm publish # Publish to npm
|
|
73
|
+
```
|
|
143
74
|
|
|
144
|
-
|
|
75
|
+
The `prepublishOnly` script handles `copy-stdlib` and `build` automatically.
|
|
145
76
|
|
|
146
|
-
|
|
77
|
+
## See Also
|
|
147
78
|
|
|
148
|
-
|
|
79
|
+
- [Language documentation](../docs/)
|
|
80
|
+
- [Standard library](../stdlib/)
|
|
81
|
+
- [Examples](../examples/)
|
|
82
|
+
- [Architecture details](ARCHITECTURE.md)
|
|
83
|
+
- [Design decisions](DESIGN_DECISIONS.md)
|
package/dist/formatter.js
CHANGED
|
@@ -150,7 +150,7 @@ export function format(source, options) {
|
|
|
150
150
|
else {
|
|
151
151
|
elInline = formatBlockExpr(expr.else_, depth);
|
|
152
152
|
}
|
|
153
|
-
const single = `if ${cond} ${thenInline}
|
|
153
|
+
const single = `if ${cond} ${thenInline} else ${elInline}`;
|
|
154
154
|
if (single.length + depth * opts.indentSize <= opts.maxLineLength) {
|
|
155
155
|
return single;
|
|
156
156
|
}
|
|
@@ -159,12 +159,12 @@ export function format(source, options) {
|
|
|
159
159
|
? formatBlockMultiline(expr.then, depth)
|
|
160
160
|
: thenInline;
|
|
161
161
|
if (expr.else_.kind === "IfExpr") {
|
|
162
|
-
return `if ${cond} ${thenMulti}
|
|
162
|
+
return `if ${cond} ${thenMulti} else ${formatExpr(expr.else_, depth)}`;
|
|
163
163
|
}
|
|
164
164
|
const elMulti = expr.else_.kind === "BlockExpr"
|
|
165
165
|
? formatBlockMultiline(expr.else_, depth)
|
|
166
166
|
: elInline;
|
|
167
|
-
return `if ${cond} ${thenMulti}
|
|
167
|
+
return `if ${cond} ${thenMulti} else ${elMulti}`;
|
|
168
168
|
}
|
|
169
169
|
const single = `if ${cond} ${thenInline}`;
|
|
170
170
|
if (single.length + depth * opts.indentSize <= opts.maxLineLength) {
|
|
@@ -240,6 +240,8 @@ export function format(source, options) {
|
|
|
240
240
|
case "SpreadExpr": return `...${formatExpr(expr.expr, depth)}`;
|
|
241
241
|
case "OptionalMemberExpr": return `${formatExpr(expr.object, depth)}?.${expr.property}`;
|
|
242
242
|
case "TryExpr": return `${formatExpr(expr.expr, depth)}?`;
|
|
243
|
+
case "TryCatchExpr":
|
|
244
|
+
return `try ${formatBlockExpr(expr.body, depth)} catch ${expr.catchVar} ${formatBlockExpr(expr.catchBody, depth)}`;
|
|
243
245
|
default: return `/* unknown */`;
|
|
244
246
|
}
|
|
245
247
|
}
|
|
@@ -347,6 +349,16 @@ export function format(source, options) {
|
|
|
347
349
|
const pub = stmt.pub ? "pub " : "";
|
|
348
350
|
return `${pub}type ${stmt.name} = ${formatTypeExpr(stmt.def)}`;
|
|
349
351
|
}
|
|
352
|
+
case "RetStmt":
|
|
353
|
+
return stmt.value ? `return ${formatExpr(stmt.value, depth)}` : "return";
|
|
354
|
+
case "WhileStmt":
|
|
355
|
+
return `while ${formatExpr(stmt.condition, depth)} ${formatBlockExpr(stmt.body, depth)}`;
|
|
356
|
+
case "BreakStmt":
|
|
357
|
+
return "break";
|
|
358
|
+
case "ContinueStmt":
|
|
359
|
+
return "continue";
|
|
360
|
+
case "TryCatchStmt":
|
|
361
|
+
return `try ${formatBlockExpr(stmt.body, depth)} catch ${stmt.catchVar} ${formatBlockExpr(stmt.catchBody, depth)}`;
|
|
350
362
|
case "AssignStmt":
|
|
351
363
|
return `${stmt.target} = ${formatExpr(stmt.value, depth)}`;
|
|
352
364
|
case "MemberAssignStmt":
|
package/dist/interpreter.js
CHANGED
|
@@ -126,7 +126,7 @@ function syncFetch(method, url, body) {
|
|
|
126
126
|
const bodyJson = bodyStr != null ? JSON.stringify(bodyStr) : "null";
|
|
127
127
|
// Pass config via env to avoid shell escaping issues
|
|
128
128
|
const fetchConfig = JSON.stringify({ method, url, body: bodyStr, headers: customHeaders });
|
|
129
|
-
const script = `const c=JSON.parse(process.env.ARC_FETCH);(async()=>{const o={method:c.method,headers:{...c.headers}};if(c.body!==null){o.body=c.body;if(!o.headers["Content-Type"])o.headers["Content-Type"]="application/json";}try{const r=await fetch(c.url,o);const t=await r.text();let d;try{d=JSON.parse(t)}catch{d=t}console.log(JSON.stringify({ok:
|
|
129
|
+
const script = `const c=JSON.parse(process.env.ARC_FETCH);(async()=>{const o={method:c.method,headers:{...c.headers}};if(c.body!==null){o.body=c.body;if(!o.headers["Content-Type"])o.headers["Content-Type"]="application/json";}try{const r=await fetch(c.url,o);const t=await r.text();let d;try{d=JSON.parse(t)}catch{d=t}console.log(JSON.stringify({ok:r.status>=200&&r.status<300,status:r.status,data:d}))}catch(e){console.log(JSON.stringify({ok:false,status:0,data:e.message}))}})()`;
|
|
130
130
|
try {
|
|
131
131
|
const raw = execSync(`node -e "${script.replace(/"/g, '\\"')}"`, {
|
|
132
132
|
timeout: 30000,
|
package/dist/linter.js
CHANGED
|
@@ -343,6 +343,24 @@ export function lint(source, options) {
|
|
|
343
343
|
}
|
|
344
344
|
break;
|
|
345
345
|
}
|
|
346
|
+
case "WhileStmt":
|
|
347
|
+
analyzeExpr(stmt.condition, scope);
|
|
348
|
+
analyzeExpr(stmt.body, scope);
|
|
349
|
+
if (stmt.body.kind === "BlockExpr" && stmt.body.stmts.length === 0) {
|
|
350
|
+
warn("empty-block", "While loop has an empty body", stmt.loc);
|
|
351
|
+
}
|
|
352
|
+
break;
|
|
353
|
+
case "BreakStmt":
|
|
354
|
+
case "ContinueStmt":
|
|
355
|
+
break;
|
|
356
|
+
case "TryCatchStmt":
|
|
357
|
+
analyzeExpr(stmt.body, scope);
|
|
358
|
+
analyzeExpr(stmt.catchBody, scope);
|
|
359
|
+
break;
|
|
360
|
+
case "RetStmt":
|
|
361
|
+
if (stmt.value)
|
|
362
|
+
analyzeExpr(stmt.value, scope);
|
|
363
|
+
break;
|
|
346
364
|
case "DoStmt":
|
|
347
365
|
analyzeExpr(stmt.body, scope);
|
|
348
366
|
analyzeExpr(stmt.condition, scope);
|
package/dist/parser.js
CHANGED
|
@@ -703,6 +703,25 @@ export class Parser {
|
|
|
703
703
|
const body = this.parseBlock();
|
|
704
704
|
return { kind: "AsyncExpr", body, loc };
|
|
705
705
|
}
|
|
706
|
+
// Anonymous function expression: fn(params) { body } or fn(params) => expr
|
|
707
|
+
if (t.type === TokenType.Fn) {
|
|
708
|
+
this.advance();
|
|
709
|
+
this.expect(TokenType.LParen);
|
|
710
|
+
const params = [];
|
|
711
|
+
while (!this.at(TokenType.RParen)) {
|
|
712
|
+
params.push(this.expect(TokenType.Ident).value);
|
|
713
|
+
if (this.at(TokenType.Comma))
|
|
714
|
+
this.advance();
|
|
715
|
+
}
|
|
716
|
+
this.expect(TokenType.RParen);
|
|
717
|
+
if (this.at(TokenType.FatArrow)) {
|
|
718
|
+
this.advance();
|
|
719
|
+
const body = this.parseExpr();
|
|
720
|
+
return { kind: "LambdaExpr", params, body, loc };
|
|
721
|
+
}
|
|
722
|
+
const body = this.parseBlock();
|
|
723
|
+
return { kind: "LambdaExpr", params, body, loc };
|
|
724
|
+
}
|
|
706
725
|
// Try/catch expression: try { body } catch e { handler }
|
|
707
726
|
if (t.type === TokenType.Try) {
|
|
708
727
|
this.advance();
|
package/dist/repl.js
CHANGED
|
@@ -90,6 +90,9 @@ function execute(source) {
|
|
|
90
90
|
}
|
|
91
91
|
catch (e) {
|
|
92
92
|
console.log(`${RED}Error: ${e.message}${RESET}`);
|
|
93
|
+
if (e.suggestion) {
|
|
94
|
+
console.log(`${YELLOW}hint${RESET}: ${e.suggestion}`);
|
|
95
|
+
}
|
|
93
96
|
}
|
|
94
97
|
}
|
|
95
98
|
function main() {
|
|
@@ -98,7 +101,7 @@ function main() {
|
|
|
98
101
|
output: process.stdout,
|
|
99
102
|
prompt: "arc> ",
|
|
100
103
|
});
|
|
101
|
-
console.log(`${CYAN}Arc REPL v0.6.
|
|
104
|
+
console.log(`${CYAN}Arc REPL v0.6.4${RESET} — Type ${YELLOW}:help${RESET} for commands, ${YELLOW}:builtins${RESET} for functions`);
|
|
102
105
|
rl.prompt();
|
|
103
106
|
let buffer = "";
|
|
104
107
|
let braceDepth = 0;
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED