import { lex } from "../compiler/lexer.js"; import { parse } from "../compiler/parser.js"; import { checkModule } from "../compiler/checker.js"; import { moduleInfoFromNative, type ModuleInfo } from "../compiler/checker.js"; import { NATIVE_MODULES } from "../compiler/builtins.js"; import { renderDiagnostic } from "../compiler/diagnostics.js"; const sources: Record = { "src/main.xan": ` import std.string import std.collections import std.math import std.io struct Point { x: Int, y: Int } enum Color { Red, Green, Blue } type Shape = | Circle(r: Float) | Rect(w: Float, h: Float) schema User { name: String(minLen: 1, maxLen: 50) age: Int(min: 0, max: 150) = 0 email: String? = None } class Counter { export mut count: Int = 0 fun increment() { this.count += 1 } fun peek() -> Int { this.count } } let mut total = 0 fun area(s: Shape) -> Float { match s { Circle(r) -> 3.14159 * r * r Rect(w, h) -> w * h } } fun describe(p: Point) -> String { if p.x > 0 { "positive" } else { "non-positive" } } fun safeDiv(a: Int, b: Int) -> Int! { if b == 0 { raise "division by zero" } a / b } fun parseAge(s: String) -> Int! { let n = Int.parse(s)? if n < 0 { raise "negative" } n } fun lookup(key: String, m: Map) -> Int { m.get(key) or 0 } fun maybeGreet(name: String?) -> String { let n = name or "stranger" "hello, {n}" } fun useCounter() -> Int { let c = Counter { count: 5 } c.increment() c.peek() } fun useShape() -> Float { let c = Circle(2.0) area(c) } fun useAll() -> Int { let xs = [1, 2, 3] xs.map(fun (x: Int) -> Int { x * 2 }).sum() } async fun fetch() -> Int { let a = await 1 a } fun falliblePair() -> (Int, String)! { let x = safeDiv(10, 2)? ok((x, "ten")) } fun checkColors(c: Color) -> String { match c { Red -> "r" Green -> "g" Blue -> "b" } } fun uppercase(s: String) -> String { s.toUpper() } fun typeTest(v: Any) -> String { if v is String { "string" } else { "other" } } fun consts() -> Float { math.pi } test "math works" { expect(2 + 2).eq(4) } export fun main() { let u = User.parse("\\{\\"name\\": \\"alice\\", \\"age\\": 30\\}") match u { Ok(user) -> io.print(user.name) Err(e) -> io.print(e) } } `, }; const checkers = new Map>(); function resolveImport(ref: { kind: "std"; segments: string[] } | { kind: "rel"; path: string } | { kind: "pkg"; name: string } | { kind: "js"; name: string }): ModuleInfo | null { if (ref.kind === "std") { const key = "std." + ref.segments.join("."); const mod = NATIVE_MODULES[key]; if (mod) return moduleInfoFromNative(mod); return null; } if (ref.kind === "rel") { const id = ref.path.replace(/\.xan$/, ""); const src = sources[id]; if (src) { return { id, kind: "ex", name: id, exports: checkers.get(id)?.exports ?? [] }; } } return null; } const src = sources["src/main.xan"]!; const program = parse(src, "src/main.xan"); const cm = checkModule({ moduleId: "src/main", file: "src/main.xan", source: src, program, resolveImport, resolveChecked: (id) => checkers.get(id) ?? null, }); checkers.set("src/main", cm); if (cm.diagnostics.length === 0) { console.log("OK: no diagnostics"); } else { console.log(`FAIL: ${cm.diagnostics.length} diagnostic(s)`); for (const d of cm.diagnostics) console.log(renderDiagnostic(d)); process.exit(1); }