@chanmeng666/archlang 0.3.0 → 0.4.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/dist/{chunk-3YUQPQPZ.js → chunk-DHNWMOP7.js} +371 -62
- package/dist/chunk-DHNWMOP7.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +76 -21
- package/dist/index.js +1 -1
- package/examples/parametric.arch +31 -0
- package/package.json +1 -1
- package/dist/chunk-3YUQPQPZ.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lexer.ts","../src/expr.ts","../src/geometry.ts","../src/elements/wall.ts","../src/elements/room.ts","../src/elements/door.ts","../src/elements/window.ts","../src/elements/furniture.ts","../src/elements/dim.ts","../src/elements/column.ts","../src/elements/index.ts","../src/parser.ts","../src/ir.ts","../src/registry.ts","../src/render.ts","../src/diagnostics.ts","../src/index.ts"],"sourcesContent":["/** Hand-written lexer for ArchLang. Zero dependencies; tracks line/col. */\r\n\r\nexport type TokenType =\r\n | \"ident\"\r\n | \"number\"\r\n | \"string\"\r\n | \"dimension\" // e.g. 4000x3000\r\n | \"lparen\"\r\n | \"rparen\"\r\n | \"lcurly\"\r\n | \"rcurly\"\r\n | \"comma\"\r\n | \"equals\"\r\n | \"colon\"\r\n | \"arrow\" // ->\r\n | \"plus\" // +\r\n | \"minus\" // - (binary or unary; arrow -> is separate)\r\n | \"star\" // *\r\n | \"slash\" // /\r\n | \"percent\" // %\r\n | \"eof\";\r\n\r\nexport interface Token {\r\n type: TokenType;\r\n value: string;\r\n /** For \"number\": the parsed value. For \"dimension\": w. */\r\n num?: number;\r\n /** For \"dimension\": h. */\r\n num2?: number;\r\n line: number;\r\n col: number;\r\n /** Byte offset of the token's first character into the source. */\r\n start: number;\r\n /** Byte offset just past the token's last character. */\r\n end: number;\r\n}\r\n\r\nexport interface LexResult {\r\n tokens: Token[];\r\n errors: { message: string; span: { start: number; end: number } }[];\r\n}\r\n\r\nconst isDigit = (c: string) => c >= \"0\" && c <= \"9\";\r\nconst isIdentStart = (c: string) =>\r\n (c >= \"a\" && c <= \"z\") || (c >= \"A\" && c <= \"Z\") || c === \"_\";\r\nconst isIdentPart = (c: string) => isIdentStart(c) || isDigit(c);\r\n\r\nexport function lex(src: string): LexResult {\r\n const tokens: Token[] = [];\r\n const errors: { message: string; span: { start: number; end: number } }[] = [];\r\n let i = 0;\r\n let line = 1;\r\n let col = 1;\r\n\r\n const peek = (o = 0) => src[i + o] ?? \"\";\r\n const advance = () => {\r\n const c = src[i++];\r\n if (c === \"\\n\") {\r\n line++;\r\n col = 1;\r\n } else {\r\n col++;\r\n }\r\n return c;\r\n };\r\n const push = (\r\n type: TokenType,\r\n value: string,\r\n startLine: number,\r\n startCol: number,\r\n startIdx: number,\r\n extra?: Partial<Token>,\r\n ) => tokens.push({ type, value, line: startLine, col: startCol, ...extra, start: startIdx, end: i });\r\n\r\n while (i < src.length) {\r\n const c = peek();\r\n const startLine = line;\r\n const startCol = col;\r\n const startIdx = i;\r\n\r\n // Whitespace\r\n if (c === \" \" || c === \"\\t\" || c === \"\\r\" || c === \"\\n\") {\r\n advance();\r\n continue;\r\n }\r\n\r\n // Comment to end of line\r\n if (c === \"#\") {\r\n while (i < src.length && peek() !== \"\\n\") advance();\r\n continue;\r\n }\r\n\r\n // String literal with \\\" and \\\\ escapes\r\n if (c === '\"') {\r\n advance();\r\n let value = \"\";\r\n let terminated = false;\r\n while (i < src.length) {\r\n const ch = peek();\r\n if (ch === \"\\\\\") {\r\n advance();\r\n const esc = advance();\r\n value += esc === \"n\" ? \"\\n\" : esc;\r\n continue;\r\n }\r\n if (ch === '\"') {\r\n advance();\r\n terminated = true;\r\n break;\r\n }\r\n if (ch === \"\\n\") break; // strings don't span lines\r\n value += advance();\r\n }\r\n if (!terminated) {\r\n errors.push({ message: \"Unterminated string literal\", span: { start: startIdx, end: i } });\r\n }\r\n push(\"string\", value, startLine, startCol, startIdx);\r\n continue;\r\n }\r\n\r\n // Punctuation & operators\r\n if (c === \"(\") { advance(); push(\"lparen\", \"(\", startLine, startCol, startIdx); continue; }\r\n if (c === \")\") { advance(); push(\"rparen\", \")\", startLine, startCol, startIdx); continue; }\r\n if (c === \"{\") { advance(); push(\"lcurly\", \"{\", startLine, startCol, startIdx); continue; }\r\n if (c === \"}\") { advance(); push(\"rcurly\", \"}\", startLine, startCol, startIdx); continue; }\r\n if (c === \",\") { advance(); push(\"comma\", \",\", startLine, startCol, startIdx); continue; }\r\n if (c === \"=\") { advance(); push(\"equals\", \"=\", startLine, startCol, startIdx); continue; }\r\n if (c === \":\") { advance(); push(\"colon\", \":\", startLine, startCol, startIdx); continue; }\r\n if (c === \"-\" && peek(1) === \">\") { advance(); advance(); push(\"arrow\", \"->\", startLine, startCol, startIdx); continue; }\r\n\r\n // Arithmetic operators (unary minus is handled by the expression parser).\r\n if (c === \"+\") { advance(); push(\"plus\", \"+\", startLine, startCol, startIdx); continue; }\r\n if (c === \"-\") { advance(); push(\"minus\", \"-\", startLine, startCol, startIdx); continue; }\r\n if (c === \"*\") { advance(); push(\"star\", \"*\", startLine, startCol, startIdx); continue; }\r\n if (c === \"/\") { advance(); push(\"slash\", \"/\", startLine, startCol, startIdx); continue; }\r\n if (c === \"%\") { advance(); push(\"percent\", \"%\", startLine, startCol, startIdx); continue; }\r\n\r\n // Number (optionally part of a literal dimension WxH). Numbers are\r\n // non-negative; negation is a unary operator in expressions.\r\n if (isDigit(c) || (c === \".\" && isDigit(peek(1)))) {\r\n let raw = \"\";\r\n while (isDigit(peek())) raw += advance();\r\n if (peek() === \".\") {\r\n raw += advance();\r\n while (isDigit(peek())) raw += advance();\r\n }\r\n const first = parseFloat(raw);\r\n // Dimension: <num>x<num>\r\n if (peek() === \"x\" && (isDigit(peek(1)) || (peek(1) === \".\" && isDigit(peek(2))))) {\r\n advance(); // consume 'x'\r\n let raw2 = \"\";\r\n while (isDigit(peek())) raw2 += advance();\r\n if (peek() === \".\") {\r\n raw2 += advance();\r\n while (isDigit(peek())) raw2 += advance();\r\n }\r\n const second = parseFloat(raw2);\r\n push(\"dimension\", `${raw}x${raw2}`, startLine, startCol, startIdx, { num: first, num2: second });\r\n continue;\r\n }\r\n push(\"number\", raw, startLine, startCol, startIdx, { num: first });\r\n continue;\r\n }\r\n\r\n // Identifier / keyword\r\n if (isIdentStart(c)) {\r\n let value = \"\";\r\n while (i < src.length && isIdentPart(peek())) value += advance();\r\n push(\"ident\", value, startLine, startCol, startIdx);\r\n continue;\r\n }\r\n\r\n // Unknown character\r\n errors.push({ message: `Unexpected character ${JSON.stringify(c)}`, span: { start: startIdx, end: startIdx + 1 } });\r\n advance();\r\n }\r\n\r\n push(\"eof\", \"\", line, col, i);\r\n return { tokens, errors };\r\n}\r\n","/**\r\n * Arithmetic expressions: a small Pratt parser + a pure evaluator.\r\n *\r\n * Expressions appear anywhere a number does (coordinates, sizes, widths,\r\n * thickness, offsets). They are parsed into an {@link Expr} AST and evaluated\r\n * during `resolve` against an {@link Env} of `let`/parameter bindings.\r\n */\r\n\r\nimport type { Token, TokenType } from \"./lexer.js\";\r\nimport type { Diagnostic, Span } from \"./diagnostics.js\";\r\n\r\nexport type Expr =\r\n | { t: \"num\"; value: number }\r\n | { t: \"ref\"; name: string; span?: Span }\r\n | { t: \"unary\"; op: \"-\" | \"+\"; e: Expr }\r\n | { t: \"bin\"; op: \"+\" | \"-\" | \"*\" | \"/\" | \"%\"; l: Expr; r: Expr };\r\n\r\nexport type Env = Map<string, number>;\r\n\r\n/** Minimal token-stream the expression parser needs (satisfied by ParseCtx). */\r\nexport interface ExprTokens {\r\n peek(o?: number): Token;\r\n next(): Token;\r\n fail(msg: string, t?: Token): never;\r\n}\r\n\r\nconst BIN_PREC: Partial<Record<TokenType, number>> = {\r\n plus: 1,\r\n minus: 1,\r\n star: 2,\r\n slash: 2,\r\n percent: 2,\r\n};\r\nconst BIN_OP: Partial<Record<TokenType, \"+\" | \"-\" | \"*\" | \"/\" | \"%\">> = {\r\n plus: \"+\",\r\n minus: \"-\",\r\n star: \"*\",\r\n slash: \"/\",\r\n percent: \"%\",\r\n};\r\n\r\n/** Parse an expression (Pratt / precedence-climbing). */\r\nexport function parseExpr(ts: ExprTokens): Expr {\r\n return parseBin(ts, 1);\r\n}\r\n\r\nfunction parseBin(ts: ExprTokens, minPrec: number): Expr {\r\n let left = parseUnary(ts);\r\n for (;;) {\r\n const t = ts.peek();\r\n const prec = BIN_PREC[t.type];\r\n if (prec === undefined || prec < minPrec) break;\r\n ts.next();\r\n const right = parseBin(ts, prec + 1);\r\n left = { t: \"bin\", op: BIN_OP[t.type]!, l: left, r: right };\r\n }\r\n return left;\r\n}\r\n\r\nfunction parseUnary(ts: ExprTokens): Expr {\r\n const t = ts.peek();\r\n if (t.type === \"minus\" || t.type === \"plus\") {\r\n ts.next();\r\n return { t: \"unary\", op: t.type === \"minus\" ? \"-\" : \"+\", e: parseUnary(ts) };\r\n }\r\n return parseAtom(ts);\r\n}\r\n\r\nfunction parseAtom(ts: ExprTokens): Expr {\r\n const t = ts.peek();\r\n if (t.type === \"number\") {\r\n ts.next();\r\n return { t: \"num\", value: t.num! };\r\n }\r\n if (t.type === \"ident\") {\r\n ts.next();\r\n return { t: \"ref\", name: t.value, span: { start: t.start, end: t.end } };\r\n }\r\n if (t.type === \"lparen\") {\r\n ts.next();\r\n const e = parseExpr(ts);\r\n const close = ts.peek();\r\n if (close.type !== \"rparen\") ts.fail(`Expected \")\" but found ${describe(close)}`);\r\n ts.next();\r\n return e;\r\n }\r\n return ts.fail(`Expected a number, name, or \"(\" but found ${describe(t)}`);\r\n}\r\n\r\n/** Evaluate an expression. Errors (unknown ref, division by zero) emit a\r\n * diagnostic and yield 0 so resolution can continue and report everything. */\r\nexport function evalExpr(e: Expr, env: Env, onError: (d: Diagnostic) => void): number {\r\n switch (e.t) {\r\n case \"num\":\r\n return e.value;\r\n case \"ref\": {\r\n const v = env.get(e.name);\r\n if (v === undefined) {\r\n const hint = closest(e.name, [...env.keys()]);\r\n onError({\r\n severity: \"error\",\r\n message: `Unknown name \"${e.name}\"`,\r\n code: \"E_UNKNOWN_REF\",\r\n span: e.span,\r\n hints: hint ? [`did you mean \"${hint}\"?`] : undefined,\r\n });\r\n return 0;\r\n }\r\n return v;\r\n }\r\n case \"unary\": {\r\n const v = evalExpr(e.e, env, onError);\r\n return e.op === \"-\" ? -v : v;\r\n }\r\n case \"bin\": {\r\n const l = evalExpr(e.l, env, onError);\r\n const r = evalExpr(e.r, env, onError);\r\n switch (e.op) {\r\n case \"+\": return l + r;\r\n case \"-\": return l - r;\r\n case \"*\": return l * r;\r\n case \"/\":\r\n case \"%\":\r\n if (r === 0) {\r\n onError({ severity: \"error\", message: `${e.op === \"/\" ? \"Division\" : \"Modulo\"} by zero`, code: \"E_DIV_ZERO\" });\r\n return 0;\r\n }\r\n return e.op === \"/\" ? l / r : l % r;\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction describe(t: Token): string {\r\n if (t.type === \"eof\") return \"end of input\";\r\n if (t.type === \"string\") return `string ${JSON.stringify(t.value)}`;\r\n return `\"${t.value}\"`;\r\n}\r\n\r\n/** Nearest candidate within a small edit distance, for \"did you mean\" hints. */\r\nexport function closest(name: string, candidates: string[]): string | null {\r\n let best: string | null = null;\r\n let bestDist = Infinity;\r\n for (const c of candidates) {\r\n const d = levenshtein(name, c);\r\n if (d < bestDist) {\r\n bestDist = d;\r\n best = c;\r\n }\r\n }\r\n // Only suggest when reasonably close (≤ 2 edits, or ≤ a third of the length).\r\n const limit = Math.max(2, Math.floor(name.length / 3));\r\n return best !== null && bestDist <= limit ? best : null;\r\n}\r\n\r\nfunction levenshtein(a: string, b: string): number {\r\n const m = a.length;\r\n const n = b.length;\r\n const dp = Array.from({ length: m + 1 }, (_, i) => i);\r\n for (let j = 1; j <= n; j++) {\r\n let prev = dp[0];\r\n dp[0] = j;\r\n for (let i = 1; i <= m; i++) {\r\n const tmp = dp[i];\r\n dp[i] = Math.min(\r\n dp[i] + 1,\r\n dp[i - 1] + 1,\r\n prev + (a[i - 1] === b[j - 1] ? 0 : 1),\r\n );\r\n prev = tmp;\r\n }\r\n }\r\n return dp[m];\r\n}\r\n","/** Pure geometry helpers. All coordinates in millimetres. Deterministic. */\r\n\r\nimport type { Point } from \"./ast.js\";\r\n\r\nexport interface Vec {\r\n x: number;\r\n y: number;\r\n}\r\n\r\nexport const sub = (a: Point, b: Point): Vec => ({ x: a.x - b.x, y: a.y - b.y });\r\nexport const add = (a: Point, b: Vec): Point => ({ x: a.x + b.x, y: a.y + b.y });\r\nexport const mul = (v: Vec, s: number): Vec => ({ x: v.x * s, y: v.y * s });\r\nexport const length = (v: Vec): number => Math.hypot(v.x, v.y);\r\nexport function unit(v: Vec): Vec {\r\n const l = length(v);\r\n return l === 0 ? { x: 0, y: 0 } : { x: v.x / l, y: v.y / l };\r\n}\r\n/** Left normal (rotate +90°). */\r\nexport const normal = (v: Vec): Vec => ({ x: -v.y, y: v.x });\r\n\r\nexport interface Bounds {\r\n minX: number;\r\n minY: number;\r\n maxX: number;\r\n maxY: number;\r\n}\r\n\r\nexport const emptyBounds = (): Bounds => ({\r\n minX: Infinity,\r\n minY: Infinity,\r\n maxX: -Infinity,\r\n maxY: -Infinity,\r\n});\r\n\r\nexport function extendBounds(b: Bounds, x: number, y: number): void {\r\n if (x < b.minX) b.minX = x;\r\n if (y < b.minY) b.minY = y;\r\n if (x > b.maxX) b.maxX = x;\r\n if (y > b.maxY) b.maxY = y;\r\n}\r\n\r\n/** Distance from point p to segment ab. */\r\nexport function distPointToSegment(p: Point, a: Point, b: Point): number {\r\n const abx = b.x - a.x;\r\n const aby = b.y - a.y;\r\n const apx = p.x - a.x;\r\n const apy = p.y - a.y;\r\n const len2 = abx * abx + aby * aby;\r\n let t = len2 === 0 ? 0 : (apx * abx + apy * aby) / len2;\r\n t = Math.max(0, Math.min(1, t));\r\n const cx = a.x + t * abx;\r\n const cy = a.y + t * aby;\r\n return Math.hypot(p.x - cx, p.y - cy);\r\n}\r\n\r\n/** Axis-aligned rectangle corners (clockwise) from origin + size. */\r\nexport function rectCorners(x: number, y: number, w: number, h: number): Point[] {\r\n return [\r\n { x, y },\r\n { x: x + w, y },\r\n { x: x + w, y: y + h },\r\n { x, y: y + h },\r\n ];\r\n}\r\n\r\n/**\r\n * Square-capped offset rectangle for a wall segment: the segment is widened by\r\n * `thickness` and extended by `thickness/2` at each end so orthogonal corners\r\n * fill cleanly when adjacent segments are drawn.\r\n */\r\nexport function segmentRectangle(a: Point, b: Point, thickness: number): Point[] {\r\n const d = unit(sub(b, a));\r\n const n = normal(d);\r\n const half = thickness / 2;\r\n const a2 = add(a, mul(d, -half));\r\n const b2 = add(b, mul(d, half));\r\n return [\r\n add(a2, mul(n, half)),\r\n add(b2, mul(n, half)),\r\n add(b2, mul(n, -half)),\r\n add(a2, mul(n, -half)),\r\n ];\r\n}\r\n\r\nexport interface WallSegment {\r\n a: Point;\r\n b: Point;\r\n thickness: number;\r\n category: string;\r\n}\r\n\r\n/** Minimal wall shape needed by the segment/hosting helpers (a resolved wall). */\r\nexport interface WallLike {\r\n id: string;\r\n category: string;\r\n thickness: number;\r\n points: Point[];\r\n closed: boolean;\r\n}\r\n\r\n/** Flatten a single wall into its individual segments. */\r\nexport function segmentsOfWall(w: WallLike): WallSegment[] {\r\n const segs: WallSegment[] = [];\r\n for (let k = 0; k < w.points.length - 1; k++) {\r\n segs.push({ a: w.points[k], b: w.points[k + 1], thickness: w.thickness, category: w.category });\r\n }\r\n if (w.closed && w.points.length > 2) {\r\n segs.push({ a: w.points[w.points.length - 1], b: w.points[0], thickness: w.thickness, category: w.category });\r\n }\r\n return segs;\r\n}\r\n\r\n/** The wall segment hosting an opening point (nearest), filtered by ref if given. */\r\nexport function hostSegmentForWalls(walls: WallLike[], at: Point, ref?: string): WallSegment | null {\r\n const candidates = ref ? walls.filter((w) => w.id === ref || w.category === ref) : walls;\r\n let best: WallSegment | null = null;\r\n let bestDist = Infinity;\r\n for (const w of candidates) {\r\n for (const s of segmentsOfWall(w)) {\r\n const dist = distPointToSegment(at, s.a, s.b);\r\n if (dist < bestDist) {\r\n bestDist = dist;\r\n best = s;\r\n }\r\n }\r\n }\r\n return best;\r\n}\r\n\r\n/** Whether a point lies within tolerance of some wall (filtered by ref if given). */\r\nexport function isOnSomeWall(walls: WallLike[], at: Point, ref?: string): boolean {\r\n const candidates = ref ? walls.filter((w) => w.id === ref || w.category === ref) : walls;\r\n for (const w of candidates) {\r\n const tol = w.thickness / 2 + Math.max(w.thickness, 1);\r\n for (const s of segmentsOfWall(w)) {\r\n if (distPointToSegment(at, s.a, s.b) <= tol) return true;\r\n }\r\n }\r\n return false;\r\n}\r\n","/** `wall <category> thickness N { (x,y)… [close] }` — poché fill + crisp faces. */\r\n\r\nimport type { ExprPoint, Point, WallNode } from \"../ast.js\";\r\nimport type { ElementDef, ParseCtx, RenderCtx, RenderOp, ResolveCtx } from \"../registry.js\";\r\nimport type { RWall } from \"../ir.js\";\r\nimport { add, mul, normal, segmentRectangle, segmentsOfWall, sub, unit } from \"../geometry.js\";\r\n\r\nexport const wall: ElementDef = {\r\n kind: \"wall\",\r\n keyword: \"wall\",\r\n\r\n parse(ctx: ParseCtx): WallNode {\r\n const kw = ctx.eatKeyword(\"wall\");\r\n const id = ctx.parseIdOpt();\r\n const category = ctx.eatIdent().value;\r\n ctx.eatKeyword(\"thickness\");\r\n const thickness = ctx.parseExpr();\r\n ctx.eat(\"lcurly\");\r\n const points: ExprPoint[] = [];\r\n let closed = false;\r\n while (!ctx.isType(\"rcurly\") && !ctx.isType(\"eof\")) {\r\n if (ctx.isKeyword(\"close\")) {\r\n ctx.next();\r\n closed = true;\r\n break;\r\n }\r\n if (ctx.isType(\"lparen\")) {\r\n points.push(ctx.parsePoint());\r\n continue;\r\n }\r\n ctx.fail(`Expected a point \"(x,y)\" or \"close\" in wall body but found ${describe(ctx)}`);\r\n }\r\n ctx.eat(\"rcurly\");\r\n if (points.length < 2) ctx.fail(\"A wall needs at least two points\", kw);\r\n return { kind: \"wall\", id, category, thickness, points, closed, line: kw.line };\r\n },\r\n\r\n idPrefix: (node) => (node as WallNode).category || \"wall\",\r\n\r\n resolve(node, ctx: ResolveCtx): RWall {\r\n const n = node as WallNode;\r\n const id = ctx.id;\r\n const points = n.points.map((p) => ctx.snapPt(ctx.evalPt(p)));\r\n const tv = ctx.eval(n.thickness);\r\n const thickness = ctx.snap(tv) || tv;\r\n if (thickness <= 0) {\r\n ctx.diag({ severity: \"error\", message: `Wall \"${id}\" must have a positive thickness`, code: \"E_WALL_THICKNESS\", span: n.span });\r\n }\r\n return { kind: \"wall\", id, category: n.category, thickness, points, closed: n.closed, span: n.span };\r\n },\r\n\r\n bounds(resolved): Point[] {\r\n const w = resolved as RWall;\r\n return segmentsOfWall(w).flatMap((s) => segmentRectangle(s.a, s.b, s.thickness));\r\n },\r\n\r\n render(resolved, ctx: RenderCtx): RenderOp[] {\r\n const w = resolved as RWall;\r\n const { fmt, pt, theme, sizes } = ctx;\r\n const segs = segmentsOfWall(w);\r\n const ops: RenderOp[] = [];\r\n for (const s of segs) {\r\n const poly = segmentRectangle(s.a, s.b, s.thickness);\r\n ops.push({ pass: \"wallFill\", svg: `<polygon points=\"${poly.map(pt).join(\" \")}\" fill=\"url(#poche)\"/>` });\r\n }\r\n for (const s of segs) {\r\n const d = unit(sub(s.b, s.a));\r\n const n = normal(d);\r\n const h = s.thickness / 2;\r\n const fa1 = add(s.a, mul(n, h));\r\n const fb1 = add(s.b, mul(n, h));\r\n const fa2 = add(s.a, mul(n, -h));\r\n const fb2 = add(s.b, mul(n, -h));\r\n ops.push({\r\n pass: \"wallFace\",\r\n svg: `<line x1=\"${fmt(fa1.x)}\" y1=\"${fmt(fa1.y)}\" x2=\"${fmt(fb1.x)}\" y2=\"${fmt(fb1.y)}\" stroke=\"${theme.wallStroke}\" stroke-width=\"${fmt(sizes.wallStroke)}\" stroke-linecap=\"square\"/>`,\r\n });\r\n ops.push({\r\n pass: \"wallFace\",\r\n svg: `<line x1=\"${fmt(fa2.x)}\" y1=\"${fmt(fa2.y)}\" x2=\"${fmt(fb2.x)}\" y2=\"${fmt(fb2.y)}\" stroke=\"${theme.wallStroke}\" stroke-width=\"${fmt(sizes.wallStroke)}\" stroke-linecap=\"square\"/>`,\r\n });\r\n }\r\n return ops;\r\n },\r\n};\r\n\r\nfunction describe(ctx: ParseCtx): string {\r\n const t = ctx.peek();\r\n if (t.type === \"eof\") return \"end of input\";\r\n if (t.type === \"string\") return `string ${JSON.stringify(t.value)}`;\r\n return `\"${t.value}\"`;\r\n}\r\n","/** `room [id=] at (x,y) size WxH [label \"…\"]` — floor fill + label + computed area. */\r\n\r\nimport type { Point, RoomNode } from \"../ast.js\";\r\nimport type { ElementDef, ParseCtx, RenderCtx, RenderOp, ResolveCtx } from \"../registry.js\";\r\nimport type { RRoom } from \"../ir.js\";\r\nimport { rectCorners } from \"../geometry.js\";\r\n\r\nexport const room: ElementDef = {\r\n kind: \"room\",\r\n keyword: \"room\",\r\n\r\n parse(ctx: ParseCtx): RoomNode {\r\n const kw = ctx.eatKeyword(\"room\");\r\n const id = ctx.parseIdOpt();\r\n ctx.eatKeyword(\"at\");\r\n const at = ctx.parsePoint();\r\n ctx.eatKeyword(\"size\");\r\n const size = ctx.parseDimensions();\r\n const node: RoomNode = { kind: \"room\", id, at, size, line: kw.line };\r\n if (ctx.isKeyword(\"label\")) {\r\n ctx.next();\r\n node.label = ctx.eatString();\r\n }\r\n return node;\r\n },\r\n\r\n idPrefix: () => \"room\",\r\n\r\n resolve(node, ctx: ResolveCtx): RRoom {\r\n const n = node as RoomNode;\r\n const id = ctx.id;\r\n const at = ctx.snapPt(ctx.evalPt(n.at));\r\n const size = { w: ctx.snap(ctx.eval(n.size.w)), h: ctx.snap(ctx.eval(n.size.h)) };\r\n if (size.w <= 0 || size.h <= 0) {\r\n ctx.diag({ severity: \"error\", message: `Room \"${id}\" must have a positive size`, code: \"E_ROOM_SIZE\", span: n.span });\r\n }\r\n return { kind: \"room\", id, at, size, label: n.label, span: n.span };\r\n },\r\n\r\n bounds(resolved): Point[] {\r\n const r = resolved as RRoom;\r\n return rectCorners(r.at.x, r.at.y, r.size.w, r.size.h);\r\n },\r\n\r\n render(resolved, ctx: RenderCtx): RenderOp[] {\r\n const r = resolved as RRoom;\r\n const { fmt, pt, xml, theme, sizes } = ctx;\r\n const ops: RenderOp[] = [];\r\n const c = rectCorners(r.at.x, r.at.y, r.size.w, r.size.h);\r\n ops.push({ pass: \"floor\", svg: `<polygon points=\"${c.map(pt).join(\" \")}\" fill=\"${theme.roomFill}\"/>` });\r\n\r\n const cx = r.at.x + r.size.w / 2;\r\n const cy = r.at.y + r.size.h / 2;\r\n const areaM2 = ((r.size.w / 1000) * (r.size.h / 1000)).toFixed(1);\r\n if (r.label) {\r\n ops.push({\r\n pass: \"labels\",\r\n svg: `<text x=\"${fmt(cx)}\" y=\"${fmt(cy - sizes.roomFont * 0.2)}\" font-size=\"${fmt(sizes.roomFont)}\" fill=\"${theme.roomLabel}\" text-anchor=\"middle\" dominant-baseline=\"central\" font-weight=\"600\">${xml(r.label)}</text>`,\r\n });\r\n }\r\n ops.push({\r\n pass: \"labels\",\r\n svg: `<text x=\"${fmt(cx)}\" y=\"${fmt(cy + (r.label ? sizes.roomFont * 0.9 : 0))}\" font-size=\"${fmt(sizes.areaFont)}\" fill=\"${theme.areaLabel}\" text-anchor=\"middle\" dominant-baseline=\"central\">${areaM2} m²</text>`,\r\n });\r\n return ops;\r\n },\r\n};\r\n","/** `door [id=] at (x,y) width N [wall ref] [hinge l|r] [swing in|out]` — opening + leaf + swing arc. */\r\n\r\nimport type { DoorNode, Point } from \"../ast.js\";\r\nimport type { ElementDef, ParseCtx, RenderCtx, RenderOp, ResolveCtx } from \"../registry.js\";\r\nimport type { RDoor } from \"../ir.js\";\r\nimport { add, mul, normal, sub, unit } from \"../geometry.js\";\r\n\r\nexport const door: ElementDef = {\r\n kind: \"door\",\r\n keyword: \"door\",\r\n\r\n parse(ctx: ParseCtx): DoorNode {\r\n const kw = ctx.eatKeyword(\"door\");\r\n const id = ctx.parseIdOpt();\r\n ctx.eatKeyword(\"at\");\r\n const at = ctx.parsePoint();\r\n ctx.eatKeyword(\"width\");\r\n const width = ctx.parseExpr();\r\n const node: DoorNode = { kind: \"door\", id, at, width, hinge: \"left\", swing: \"in\", line: kw.line };\r\n if (ctx.isKeyword(\"wall\")) {\r\n ctx.next();\r\n node.wall = ctx.eatIdent().value;\r\n }\r\n if (ctx.isKeyword(\"hinge\")) {\r\n ctx.next();\r\n const h = ctx.eatIdent().value;\r\n if (h !== \"left\" && h !== \"right\") ctx.fail(`Expected hinge \"left\" or \"right\" but found \"${h}\"`);\r\n node.hinge = h;\r\n }\r\n if (ctx.isKeyword(\"swing\")) {\r\n ctx.next();\r\n const s = ctx.eatIdent().value;\r\n if (s !== \"in\" && s !== \"out\") ctx.fail(`Expected swing \"in\" or \"out\" but found \"${s}\"`);\r\n node.swing = s;\r\n }\r\n return node;\r\n },\r\n\r\n idPrefix: () => \"door\",\r\n\r\n resolve(node, ctx: ResolveCtx): RDoor {\r\n const n = node as DoorNode;\r\n const id = ctx.id;\r\n const at = ctx.snapPt(ctx.evalPt(n.at));\r\n const wv = ctx.eval(n.width);\r\n const width = ctx.snap(wv) || wv;\r\n if (width <= 0) {\r\n ctx.diag({ severity: \"error\", message: `Door \"${id}\" must have a positive width`, code: \"E_DOOR_WIDTH\", span: n.span });\r\n }\r\n if (ctx.walls.length > 0 && !ctx.isOnWall(at, n.wall)) {\r\n ctx.diag({ severity: \"warning\", message: `Door \"${id}\" does not lie on any wall`, code: \"W_DOOR_OFF_WALL\", span: n.span });\r\n }\r\n return { kind: \"door\", id, at, width, hinge: n.hinge, swing: n.swing, host: ctx.hostSegment(at, n.wall), span: n.span };\r\n },\r\n\r\n bounds: () => [],\r\n\r\n render(resolved, ctx: RenderCtx): RenderOp[] {\r\n const dr = resolved as RDoor;\r\n const seg = dr.host;\r\n if (!seg) return [];\r\n const { fmt, pt, theme, sizes } = ctx;\r\n const d = unit(sub(seg.b, seg.a));\r\n const n = normal(d);\r\n const h = seg.thickness / 2 + sizes.wallStroke;\r\n const hw = dr.width / 2;\r\n const cover: Point[] = [\r\n add(add(dr.at, mul(d, -hw)), mul(n, h)),\r\n add(add(dr.at, mul(d, hw)), mul(n, h)),\r\n add(add(dr.at, mul(d, hw)), mul(n, -h)),\r\n add(add(dr.at, mul(d, -hw)), mul(n, -h)),\r\n ];\r\n const ops: RenderOp[] = [];\r\n ops.push({ pass: \"doors\", svg: `<polygon points=\"${cover.map(pt).join(\" \")}\" fill=\"${theme.opening}\"/>` });\r\n const hinge = dr.hinge === \"left\" ? add(dr.at, mul(d, -hw)) : add(dr.at, mul(d, hw));\r\n const farJamb = dr.hinge === \"left\" ? add(dr.at, mul(d, hw)) : add(dr.at, mul(d, -hw));\r\n const leafDir = dr.swing === \"in\" ? n : mul(n, -1);\r\n const leafEnd = add(hinge, mul(leafDir, dr.width));\r\n const cross = (leafEnd.x - hinge.x) * (farJamb.y - hinge.y) - (leafEnd.y - hinge.y) * (farJamb.x - hinge.x);\r\n const sweep = cross < 0 ? 1 : 0;\r\n ops.push({\r\n pass: \"doors\",\r\n svg: `<line x1=\"${fmt(hinge.x)}\" y1=\"${fmt(hinge.y)}\" x2=\"${fmt(leafEnd.x)}\" y2=\"${fmt(leafEnd.y)}\" stroke=\"${theme.doorLeaf}\" stroke-width=\"${fmt(sizes.thin * 1.3)}\"/>`,\r\n });\r\n ops.push({\r\n pass: \"doors\",\r\n svg: `<path d=\"M ${pt(leafEnd)} A ${fmt(dr.width)} ${fmt(dr.width)} 0 0 ${sweep} ${pt(farJamb)}\" fill=\"none\" stroke=\"${theme.doorLeaf}\" stroke-width=\"${fmt(sizes.thin)}\" stroke-dasharray=\"${fmt(sizes.thin * 4)} ${fmt(sizes.thin * 3)}\"/>`,\r\n });\r\n return ops;\r\n },\r\n};\r\n","/** `window [id=] at (x,y) width N [wall ref]` — opening + glazing panes. */\r\n\r\nimport type { Point, WindowNode } from \"../ast.js\";\r\nimport type { ElementDef, ParseCtx, RenderCtx, RenderOp, ResolveCtx } from \"../registry.js\";\r\nimport type { RWindow } from \"../ir.js\";\r\nimport { add, mul, normal, sub, unit } from \"../geometry.js\";\r\n\r\nexport const windowEl: ElementDef = {\r\n kind: \"window\",\r\n keyword: \"window\",\r\n\r\n parse(ctx: ParseCtx): WindowNode {\r\n const kw = ctx.eatKeyword(\"window\");\r\n const id = ctx.parseIdOpt();\r\n ctx.eatKeyword(\"at\");\r\n const at = ctx.parsePoint();\r\n ctx.eatKeyword(\"width\");\r\n const width = ctx.parseExpr();\r\n const node: WindowNode = { kind: \"window\", id, at, width, line: kw.line };\r\n if (ctx.isKeyword(\"wall\")) {\r\n ctx.next();\r\n node.wall = ctx.eatIdent().value;\r\n }\r\n return node;\r\n },\r\n\r\n idPrefix: () => \"window\",\r\n\r\n resolve(node, ctx: ResolveCtx): RWindow {\r\n const n = node as WindowNode;\r\n const id = ctx.id;\r\n const at = ctx.snapPt(ctx.evalPt(n.at));\r\n const wv = ctx.eval(n.width);\r\n const width = ctx.snap(wv) || wv;\r\n if (width <= 0) {\r\n ctx.diag({ severity: \"error\", message: `Window \"${id}\" must have a positive width`, code: \"E_WINDOW_WIDTH\", span: n.span });\r\n }\r\n if (ctx.walls.length > 0 && !ctx.isOnWall(at, n.wall)) {\r\n ctx.diag({ severity: \"warning\", message: `Window \"${id}\" does not lie on any wall`, code: \"W_WINDOW_OFF_WALL\", span: n.span });\r\n }\r\n return { kind: \"window\", id, at, width, host: ctx.hostSegment(at, n.wall), span: n.span };\r\n },\r\n\r\n bounds: () => [],\r\n\r\n render(resolved, ctx: RenderCtx): RenderOp[] {\r\n const wn = resolved as RWindow;\r\n const seg = wn.host;\r\n if (!seg) return [];\r\n const { fmt, pt, theme, sizes } = ctx;\r\n const d = unit(sub(seg.b, seg.a));\r\n const n = normal(d);\r\n const h = seg.thickness / 2;\r\n const he = h + sizes.wallStroke;\r\n const hw = wn.width / 2;\r\n const cover: Point[] = [\r\n add(add(wn.at, mul(d, -hw)), mul(n, he)),\r\n add(add(wn.at, mul(d, hw)), mul(n, he)),\r\n add(add(wn.at, mul(d, hw)), mul(n, -he)),\r\n add(add(wn.at, mul(d, -hw)), mul(n, -he)),\r\n ];\r\n const ops: RenderOp[] = [];\r\n ops.push({ pass: \"windows\", svg: `<polygon points=\"${cover.map(pt).join(\" \")}\" fill=\"${theme.opening}\"/>` });\r\n const jA = add(wn.at, mul(d, -hw));\r\n const jB = add(wn.at, mul(d, hw));\r\n for (const off of [h, -h]) {\r\n const a = add(jA, mul(n, off));\r\n const bb = add(jB, mul(n, off));\r\n ops.push({\r\n pass: \"windows\",\r\n svg: `<line x1=\"${fmt(a.x)}\" y1=\"${fmt(a.y)}\" x2=\"${fmt(bb.x)}\" y2=\"${fmt(bb.y)}\" stroke=\"${theme.wallStroke}\" stroke-width=\"${fmt(sizes.thin)}\"/>`,\r\n });\r\n }\r\n ops.push({\r\n pass: \"windows\",\r\n svg: `<line x1=\"${fmt(jA.x)}\" y1=\"${fmt(jA.y)}\" x2=\"${fmt(jB.x)}\" y2=\"${fmt(jB.y)}\" stroke=\"${theme.windowPane}\" stroke-width=\"${fmt(sizes.thin)}\"/>`,\r\n });\r\n return ops;\r\n },\r\n};\r\n","/** `furniture <category> [id=] at (x,y) size WxH [label \"…\"]` — outlined fill + label. */\r\n\r\nimport type { FurnitureNode, Point } from \"../ast.js\";\r\nimport type { ElementDef, ParseCtx, RenderCtx, RenderOp, ResolveCtx } from \"../registry.js\";\r\nimport type { RFurniture } from \"../ir.js\";\r\nimport { rectCorners } from \"../geometry.js\";\r\n\r\nexport const furniture: ElementDef = {\r\n kind: \"furniture\",\r\n keyword: \"furniture\",\r\n\r\n parse(ctx: ParseCtx): FurnitureNode {\r\n const kw = ctx.eatKeyword(\"furniture\");\r\n const id = ctx.parseIdOpt();\r\n const category = ctx.eatIdent().value;\r\n ctx.eatKeyword(\"at\");\r\n const at = ctx.parsePoint();\r\n ctx.eatKeyword(\"size\");\r\n const size = ctx.parseDimensions();\r\n const node: FurnitureNode = { kind: \"furniture\", id, category, at, size, line: kw.line };\r\n if (ctx.isKeyword(\"label\")) {\r\n ctx.next();\r\n node.label = ctx.eatString();\r\n }\r\n return node;\r\n },\r\n\r\n idPrefix: (node) => (node as FurnitureNode).category || \"furniture\",\r\n\r\n resolve(node, ctx: ResolveCtx): RFurniture {\r\n const n = node as FurnitureNode;\r\n const id = ctx.id;\r\n const at = ctx.snapPt(ctx.evalPt(n.at));\r\n const size = { w: ctx.snap(ctx.eval(n.size.w)), h: ctx.snap(ctx.eval(n.size.h)) };\r\n if (size.w <= 0 || size.h <= 0) {\r\n ctx.diag({ severity: \"error\", message: `Furniture \"${id}\" must have a positive size`, code: \"E_FURN_SIZE\", span: n.span });\r\n }\r\n return { kind: \"furniture\", id, category: n.category, at, size, label: n.label, span: n.span };\r\n },\r\n\r\n bounds(resolved): Point[] {\r\n const f = resolved as RFurniture;\r\n return rectCorners(f.at.x, f.at.y, f.size.w, f.size.h);\r\n },\r\n\r\n render(resolved, ctx: RenderCtx): RenderOp[] {\r\n const f = resolved as RFurniture;\r\n const { fmt, pt, xml, theme, sizes } = ctx;\r\n const ops: RenderOp[] = [];\r\n const c = rectCorners(f.at.x, f.at.y, f.size.w, f.size.h);\r\n ops.push({\r\n pass: \"furniture\",\r\n svg: `<polygon points=\"${c.map(pt).join(\" \")}\" fill=\"${theme.furnitureFill}\" stroke=\"${theme.furnitureStroke}\" stroke-width=\"${fmt(sizes.thin)}\"/>`,\r\n });\r\n if (f.label) {\r\n const cx = f.at.x + f.size.w / 2;\r\n const cy = f.at.y + f.size.h / 2;\r\n ops.push({\r\n pass: \"furniture\",\r\n svg: `<text x=\"${fmt(cx)}\" y=\"${fmt(cy)}\" font-size=\"${fmt(sizes.furnFont)}\" fill=\"${theme.furnitureLabel}\" text-anchor=\"middle\" dominant-baseline=\"central\">${xml(f.label)}</text>`,\r\n });\r\n }\r\n return ops;\r\n },\r\n};\r\n","/** `dim (x,y)->(x,y) [offset N] [text \"…\"]` — dimension line with ticks + length. */\r\n\r\nimport type { DimNode } from \"../ast.js\";\r\nimport type { ElementDef, ParseCtx, RenderCtx, RenderOp, ResolveCtx } from \"../registry.js\";\r\nimport type { RDim } from \"../ir.js\";\r\nimport { add, length, mul, normal, sub, unit } from \"../geometry.js\";\r\n\r\nexport const dim: ElementDef = {\r\n kind: \"dim\",\r\n keyword: \"dim\",\r\n\r\n parse(ctx: ParseCtx): DimNode {\r\n const kw = ctx.eatKeyword(\"dim\");\r\n const from = ctx.parsePoint();\r\n ctx.eat(\"arrow\");\r\n const to = ctx.parsePoint();\r\n const node: DimNode = { kind: \"dim\", id: \"\", from, to, offset: { t: \"num\", value: 300 }, line: kw.line };\r\n if (ctx.isKeyword(\"offset\")) {\r\n ctx.next();\r\n node.offset = ctx.parseExpr();\r\n }\r\n if (ctx.isKeyword(\"text\")) {\r\n ctx.next();\r\n node.text = ctx.eatString();\r\n }\r\n return node;\r\n },\r\n\r\n idPrefix: () => \"dim\",\r\n\r\n resolve(node, ctx: ResolveCtx): RDim {\r\n const n = node as DimNode;\r\n return {\r\n kind: \"dim\",\r\n id: ctx.id,\r\n from: ctx.snapPt(ctx.evalPt(n.from)),\r\n to: ctx.snapPt(ctx.evalPt(n.to)),\r\n offset: ctx.eval(n.offset),\r\n text: n.text,\r\n span: n.span,\r\n };\r\n },\r\n\r\n bounds(resolved) {\r\n const dm = resolved as RDim;\r\n return [dm.from, dm.to];\r\n },\r\n\r\n render(resolved, ctx: RenderCtx): RenderOp[] {\r\n const dm = resolved as RDim;\r\n const { fmt, xml, theme, sizes } = ctx;\r\n const dir = unit(sub(dm.to, dm.from));\r\n const n = normal(dir);\r\n const off = mul(n, dm.offset);\r\n const p1 = add(dm.from, off);\r\n const p2 = add(dm.to, off);\r\n const tick = sizes.refDim * 0.012;\r\n const ops: RenderOp[] = [];\r\n ops.push({\r\n pass: \"dims\",\r\n svg: `<line x1=\"${fmt(dm.from.x)}\" y1=\"${fmt(dm.from.y)}\" x2=\"${fmt(p1.x)}\" y2=\"${fmt(p1.y)}\" stroke=\"${theme.dim}\" stroke-width=\"${fmt(sizes.thin * 0.7)}\"/>`,\r\n });\r\n ops.push({\r\n pass: \"dims\",\r\n svg: `<line x1=\"${fmt(dm.to.x)}\" y1=\"${fmt(dm.to.y)}\" x2=\"${fmt(p2.x)}\" y2=\"${fmt(p2.y)}\" stroke=\"${theme.dim}\" stroke-width=\"${fmt(sizes.thin * 0.7)}\"/>`,\r\n });\r\n ops.push({\r\n pass: \"dims\",\r\n svg: `<line x1=\"${fmt(p1.x)}\" y1=\"${fmt(p1.y)}\" x2=\"${fmt(p2.x)}\" y2=\"${fmt(p2.y)}\" stroke=\"${theme.dim}\" stroke-width=\"${fmt(sizes.thin)}\"/>`,\r\n });\r\n for (const p of [p1, p2]) {\r\n const t1 = add(p, mul(unit({ x: dir.x + n.x, y: dir.y + n.y }), tick));\r\n const t2 = add(p, mul(unit({ x: dir.x + n.x, y: dir.y + n.y }), -tick));\r\n ops.push({\r\n pass: \"dims\",\r\n svg: `<line x1=\"${fmt(t1.x)}\" y1=\"${fmt(t1.y)}\" x2=\"${fmt(t2.x)}\" y2=\"${fmt(t2.y)}\" stroke=\"${theme.dim}\" stroke-width=\"${fmt(sizes.thin)}\"/>`,\r\n });\r\n }\r\n const mid = { x: (p1.x + p2.x) / 2, y: (p1.y + p2.y) / 2 };\r\n const tp = add(mid, mul(n, sizes.dimFont * 0.7));\r\n let angle = (Math.atan2(dir.y, dir.x) * 180) / Math.PI;\r\n if (angle > 90) angle -= 180;\r\n if (angle < -90) angle += 180;\r\n const label = dm.text ?? String(Math.round(length(sub(dm.to, dm.from))));\r\n ops.push({\r\n pass: \"dims\",\r\n svg: `<text x=\"${fmt(tp.x)}\" y=\"${fmt(tp.y)}\" font-size=\"${fmt(sizes.dimFont)}\" fill=\"${theme.dim}\" text-anchor=\"middle\" dominant-baseline=\"central\" transform=\"rotate(${fmt(angle)} ${fmt(tp.x)} ${fmt(tp.y)})\">${xml(label)}</text>`,\r\n });\r\n return ops;\r\n },\r\n};\r\n","/**\r\n * `column [id=] at (x,y) size WxH` — a solid structural column.\r\n *\r\n * This module is the extensibility proof for the v0.3 registry: a brand-new\r\n * element type added as ONE file + one `register` line in `index.ts`, with no\r\n * edits to the parser, resolver, or renderer cores.\r\n */\r\n\r\nimport type { ColumnNode, Point } from \"../ast.js\";\r\nimport type { ElementDef, ParseCtx, RenderCtx, RenderOp, ResolveCtx } from \"../registry.js\";\r\nimport type { RColumn } from \"../ir.js\";\r\nimport { rectCorners } from \"../geometry.js\";\r\n\r\nexport const column: ElementDef = {\r\n kind: \"column\",\r\n keyword: \"column\",\r\n\r\n parse(ctx: ParseCtx): ColumnNode {\r\n const kw = ctx.eatKeyword(\"column\");\r\n const id = ctx.parseIdOpt();\r\n ctx.eatKeyword(\"at\");\r\n const at = ctx.parsePoint();\r\n ctx.eatKeyword(\"size\");\r\n const size = ctx.parseDimensions();\r\n return { kind: \"column\", id, at, size, line: kw.line };\r\n },\r\n\r\n idPrefix: () => \"column\",\r\n\r\n resolve(node, ctx: ResolveCtx): RColumn {\r\n const n = node as ColumnNode;\r\n const id = ctx.id;\r\n const at = ctx.snapPt(ctx.evalPt(n.at));\r\n const size = { w: ctx.snap(ctx.eval(n.size.w)), h: ctx.snap(ctx.eval(n.size.h)) };\r\n if (size.w <= 0 || size.h <= 0) {\r\n ctx.diag({ severity: \"error\", message: `Column \"${id}\" must have a positive size`, code: \"E_COLUMN_SIZE\", span: n.span });\r\n }\r\n return { kind: \"column\", id, at, size, span: n.span };\r\n },\r\n\r\n bounds(resolved): Point[] {\r\n const c = resolved as RColumn;\r\n return rectCorners(c.at.x, c.at.y, c.size.w, c.size.h);\r\n },\r\n\r\n render(resolved, ctx: RenderCtx): RenderOp[] {\r\n const c = resolved as RColumn;\r\n const { fmt, pt, theme, sizes } = ctx;\r\n const pts = rectCorners(c.at.x, c.at.y, c.size.w, c.size.h);\r\n return [\r\n {\r\n pass: \"furniture\",\r\n svg: `<polygon points=\"${pts.map(pt).join(\" \")}\" fill=\"${theme.column}\" stroke=\"${theme.wallStroke}\" stroke-width=\"${fmt(sizes.thin)}\"/>`,\r\n },\r\n ];\r\n },\r\n};\r\n","/**\r\n * Element registry assembly. Registration order is canonical: it drives id\r\n * assignment and resolve ordering (walls first, so openings can host against\r\n * them). To add an element: write one module and add one `register()` line.\r\n */\r\n\r\nimport type { ElementDef } from \"../registry.js\";\r\nimport { wall } from \"./wall.js\";\r\nimport { room } from \"./room.js\";\r\nimport { door } from \"./door.js\";\r\nimport { windowEl } from \"./window.js\";\r\nimport { furniture } from \"./furniture.js\";\r\nimport { dim } from \"./dim.js\";\r\nimport { column } from \"./column.js\";\r\n\r\n/** Defs in canonical (registration) order. */\r\nexport const registryOrder: ElementDef[] = [];\r\n/** Lookup by keyword. */\r\nexport const registry = new Map<string, ElementDef>();\r\n\r\nfunction register(def: ElementDef): void {\r\n registry.set(def.keyword, def);\r\n registryOrder.push(def);\r\n}\r\n\r\nregister(wall);\r\nregister(room);\r\nregister(door);\r\nregister(windowEl);\r\nregister(furniture);\r\nregister(dim);\r\nregister(column);\r\n","/** Recursive-descent parser: tokens -> PlanNode. Registry-driven element dispatch. */\r\n\r\nimport type { Token } from \"./lexer.js\";\r\nimport { lex } from \"./lexer.js\";\r\nimport type { Diagnostic, Span } from \"./diagnostics.js\";\r\nimport type {\r\n ComponentDef,\r\n ExprPoint,\r\n InstanceNode,\r\n LetNode,\r\n NorthDir,\r\n PlanNode,\r\n Statement,\r\n TitleNode,\r\n} from \"./ast.js\";\r\nimport type { Expr } from \"./expr.js\";\r\nimport { parseExpr as parseExprPratt } from \"./expr.js\";\r\nimport type { ParseCtx } from \"./registry.js\";\r\nimport { registry } from \"./elements/index.js\";\r\n\r\nexport interface ParseOutcome {\r\n plan?: PlanNode;\r\n diagnostics: Diagnostic[];\r\n}\r\n\r\n/** Plan-level settings + binding/definition keywords (not registry elements). */\r\nconst SETTINGS = [\"units\", \"grid\", \"scale\", \"north\", \"title\", \"let\", \"component\"];\r\n/** Keywords that begin a plan-body statement; recovery resynchronizes to one. */\r\nconst STATEMENT_STARTS = new Set<string>([...SETTINGS, ...registry.keys()]);\r\n\r\n/** Thrown internally by `eat*` helpers; always caught within the parser. */\r\nclass ParseError extends Error {\r\n constructor(public override message: string, public span: Span) {\r\n super(message);\r\n }\r\n}\r\n\r\nexport function parse(src: string): ParseOutcome {\r\n const { tokens, errors: lexErrors } = lex(src);\r\n const lexDiags: Diagnostic[] = lexErrors.map((e) => ({\r\n severity: \"error\" as const,\r\n message: e.message,\r\n span: e.span,\r\n }));\r\n\r\n const p = new Parser(tokens);\r\n let plan: PlanNode | undefined;\r\n try {\r\n plan = p.parsePlan();\r\n } catch (e) {\r\n // Only a malformed plan *header* escapes parsePlan's per-statement recovery.\r\n if (e instanceof ParseError) {\r\n p.diagnostics.push({ severity: \"error\", message: e.message, span: e.span });\r\n } else {\r\n throw e;\r\n }\r\n }\r\n return { plan, diagnostics: [...lexDiags, ...p.diagnostics] };\r\n}\r\n\r\nclass Parser {\r\n private pos = 0;\r\n public diagnostics: Diagnostic[] = [];\r\n /** Facade passed to element parse functions (see registry.ts). */\r\n private readonly ctx: ParseCtx;\r\n\r\n constructor(private toks: Token[]) {\r\n this.ctx = {\r\n peek: (o) => this.peek(o),\r\n next: () => this.next(),\r\n eat: (type) => this.eat(type),\r\n eatKeyword: (kw) => this.eatKeyword(kw),\r\n eatIdent: () => this.eatIdent(),\r\n eatNumber: () => this.eatNumber(),\r\n eatString: () => this.eatString(),\r\n isKeyword: (kw, o) => this.isKeyword(kw, o),\r\n isType: (type) => this.isType(type),\r\n parsePoint: () => this.parsePoint(),\r\n parseExpr: () => parseExprPratt(this.ctx),\r\n parseDimensions: () => this.parseDimensions(),\r\n parseIdOpt: () => this.parseIdOpt(),\r\n fail: (msg, t) => this.fail(msg, t),\r\n };\r\n }\r\n\r\n private peek(o = 0): Token {\r\n return this.toks[Math.min(this.pos + o, this.toks.length - 1)];\r\n }\r\n private next(): Token {\r\n return this.toks[Math.min(this.pos++, this.toks.length - 1)];\r\n }\r\n private fail(msg: string, t = this.peek()): never {\r\n throw new ParseError(msg, { start: t.start, end: t.end });\r\n }\r\n\r\n /** Span from a start offset to the end of the last consumed token. */\r\n private spanFrom(start: number): Span {\r\n const last = this.toks[Math.max(0, Math.min(this.pos - 1, this.toks.length - 1))];\r\n return { start, end: last.end };\r\n }\r\n\r\n /** Recover after a statement error: skip to the next statement start or block end. */\r\n private synchronize(): void {\r\n // Always make progress so a hard-stuck token can't loop forever.\r\n if (!this.isType(\"rcurly\") && !this.isType(\"eof\")) this.next();\r\n while (!this.isType(\"rcurly\") && !this.isType(\"eof\")) {\r\n const t = this.peek();\r\n if (t.type === \"ident\" && STATEMENT_STARTS.has(t.value)) return;\r\n this.next();\r\n }\r\n }\r\n\r\n private isKeyword(kw: string, o = 0): boolean {\r\n const t = this.peek(o);\r\n return t.type === \"ident\" && t.value === kw;\r\n }\r\n private eatKeyword(kw: string): Token {\r\n const t = this.peek();\r\n if (t.type !== \"ident\" || t.value !== kw) this.fail(`Expected \"${kw}\" but found ${describe(t)}`);\r\n return this.next();\r\n }\r\n private eat(type: Token[\"type\"]): Token {\r\n const t = this.peek();\r\n if (t.type !== type) this.fail(`Expected ${type} but found ${describe(t)}`);\r\n return this.next();\r\n }\r\n private eatIdent(): Token {\r\n return this.eat(\"ident\");\r\n }\r\n private eatNumber(): number {\r\n const t = this.eat(\"number\");\r\n return t.num!;\r\n }\r\n private eatString(): string {\r\n return this.eat(\"string\").value;\r\n }\r\n\r\n parsePlan(): PlanNode {\r\n this.eatKeyword(\"plan\");\r\n const name = this.eatString();\r\n this.eat(\"lcurly\");\r\n\r\n const plan: PlanNode = {\r\n name,\r\n units: \"mm\",\r\n grid: 0,\r\n north: \"up\",\r\n components: new Map(),\r\n body: [],\r\n };\r\n\r\n while (!this.isType(\"rcurly\") && !this.isType(\"eof\")) {\r\n const t = this.peek();\r\n const start = t.start;\r\n try {\r\n if (t.type !== \"ident\") this.fail(`Expected a statement but found ${describe(t)}`);\r\n const def = registry.get(t.value);\r\n if (def) {\r\n const node = def.parse(this.ctx);\r\n node.span = this.spanFrom(start);\r\n plan.body.push(node);\r\n continue;\r\n }\r\n // A defined component name followed by `(` is an instantiation.\r\n if (plan.components.has(t.value) && this.peek(1).type === \"lparen\") {\r\n const node = this.parseInstance();\r\n node.span = this.spanFrom(start);\r\n plan.body.push(node);\r\n continue;\r\n }\r\n switch (t.value) {\r\n case \"units\": {\r\n this.next();\r\n const u = this.eatIdent().value;\r\n if (u !== \"mm\") this.fail(`Unsupported units \"${u}\" (only \"mm\" is supported)`, t);\r\n plan.units = \"mm\";\r\n break;\r\n }\r\n case \"grid\":\r\n this.next();\r\n plan.grid = this.eatNumber();\r\n break;\r\n case \"scale\": {\r\n this.next();\r\n const a = this.eatNumber();\r\n this.eat(\"colon\");\r\n const b = this.eatNumber();\r\n plan.scale = `${a}:${b}`;\r\n break;\r\n }\r\n case \"north\":\r\n this.next();\r\n plan.north = this.parseNorth();\r\n break;\r\n case \"title\": {\r\n const n = this.parseTitle();\r\n n.span = this.spanFrom(start);\r\n plan.title = n;\r\n break;\r\n }\r\n case \"let\": {\r\n const n = this.parseLet();\r\n n.span = this.spanFrom(start);\r\n plan.body.push(n);\r\n break;\r\n }\r\n case \"component\": {\r\n const def = this.parseComponent(plan.components);\r\n def.span = this.spanFrom(start);\r\n if (plan.components.has(def.name)) {\r\n this.fail(`Component \"${def.name}\" is already defined`, t);\r\n }\r\n plan.components.set(def.name, def);\r\n break;\r\n }\r\n default:\r\n this.fail(`Unknown statement \"${t.value}\"`, t);\r\n }\r\n } catch (e) {\r\n if (e instanceof ParseError) {\r\n this.diagnostics.push({ severity: \"error\", message: e.message, span: e.span });\r\n this.synchronize();\r\n } else {\r\n throw e;\r\n }\r\n }\r\n }\r\n // A missing closing brace is reported but the partial plan is still returned.\r\n try {\r\n this.eat(\"rcurly\");\r\n } catch (e) {\r\n if (e instanceof ParseError) {\r\n this.diagnostics.push({ severity: \"error\", message: e.message, span: e.span });\r\n } else {\r\n throw e;\r\n }\r\n }\r\n return plan;\r\n }\r\n\r\n private isType(type: Token[\"type\"]): boolean {\r\n return this.peek().type === type;\r\n }\r\n\r\n /** Optional `id=<ident>` prefix; returns \"\" when absent. */\r\n private parseIdOpt(): string {\r\n if (this.isKeyword(\"id\")) {\r\n this.next();\r\n this.eat(\"equals\");\r\n return this.eatIdent().value;\r\n }\r\n return \"\";\r\n }\r\n\r\n private parseNorth(): NorthDir {\r\n const t = this.peek();\r\n if (t.type === \"number\") {\r\n this.next();\r\n return { deg: t.num! };\r\n }\r\n if (t.type === \"ident\" && [\"up\", \"down\", \"left\", \"right\"].includes(t.value)) {\r\n this.next();\r\n return t.value as NorthDir;\r\n }\r\n this.fail(`Expected a north direction (up|down|left|right|<degrees>) but found ${describe(t)}`);\r\n }\r\n\r\n private parsePoint(): ExprPoint {\r\n this.eat(\"lparen\");\r\n const x = parseExprPratt(this.ctx);\r\n this.eat(\"comma\");\r\n const y = parseExprPratt(this.ctx);\r\n this.eat(\"rparen\");\r\n return { x, y };\r\n }\r\n\r\n /** A size: either a `WxH` literal dimension token or `<expr> x <expr>`. */\r\n private parseDimensions(): { w: Expr; h: Expr } {\r\n if (this.isType(\"dimension\")) {\r\n const d = this.eat(\"dimension\");\r\n return { w: { t: \"num\", value: d.num! }, h: { t: \"num\", value: d.num2! } };\r\n }\r\n const w = parseExprPratt(this.ctx);\r\n if (this.isKeyword(\"x\")) this.next();\r\n else this.fail(`Expected \"x\" between width and height but found ${describe(this.peek())}`);\r\n const h = parseExprPratt(this.ctx);\r\n return { w, h };\r\n }\r\n\r\n private parseTitle(): TitleNode {\r\n const kw = this.eatKeyword(\"title\");\r\n this.eat(\"lcurly\");\r\n const node: TitleNode = { line: kw.line };\r\n while (!this.isType(\"rcurly\") && !this.isType(\"eof\")) {\r\n const t = this.peek();\r\n if (t.type !== \"ident\") this.fail(`Expected a title field but found ${describe(t)}`);\r\n switch (t.value) {\r\n case \"project\":\r\n this.next();\r\n node.project = this.eatString();\r\n break;\r\n case \"drawn_by\":\r\n this.next();\r\n node.drawnBy = this.eatString();\r\n break;\r\n case \"date\":\r\n this.next();\r\n node.date = this.eatString();\r\n break;\r\n default:\r\n this.fail(`Unknown title field \"${t.value}\"`, t);\r\n }\r\n }\r\n this.eat(\"rcurly\");\r\n return node;\r\n }\r\n\r\n private parseLet(): LetNode {\r\n const kw = this.eatKeyword(\"let\");\r\n const name = this.eatIdent().value;\r\n this.eat(\"equals\");\r\n const value = parseExprPratt(this.ctx);\r\n return { kind: \"let\", id: \"\", name, value, line: kw.line };\r\n }\r\n\r\n private parseInstance(): InstanceNode {\r\n const nameTok = this.eatIdent();\r\n this.eat(\"lparen\");\r\n const args: Expr[] = [];\r\n while (!this.isType(\"rparen\") && !this.isType(\"eof\")) {\r\n args.push(parseExprPratt(this.ctx));\r\n if (this.isType(\"comma\")) this.next();\r\n else break;\r\n }\r\n this.eat(\"rparen\");\r\n return { kind: \"instance\", id: \"\", name: nameTok.value, args, line: nameTok.line };\r\n }\r\n\r\n /** `component NAME(p1, p2, …) { <statements> }`. */\r\n private parseComponent(components: Map<string, ComponentDef>): ComponentDef {\r\n const kw = this.eatKeyword(\"component\");\r\n const name = this.eatIdent().value;\r\n this.eat(\"lparen\");\r\n const params: string[] = [];\r\n while (!this.isType(\"rparen\") && !this.isType(\"eof\")) {\r\n params.push(this.eatIdent().value);\r\n if (this.isType(\"comma\")) this.next();\r\n else break;\r\n }\r\n this.eat(\"rparen\");\r\n this.eat(\"lcurly\");\r\n const body: Statement[] = [];\r\n while (!this.isType(\"rcurly\") && !this.isType(\"eof\")) {\r\n const t = this.peek();\r\n const start = t.start;\r\n const def = registry.get(t.value);\r\n if (def) {\r\n const node = def.parse(this.ctx);\r\n node.span = this.spanFrom(start);\r\n body.push(node);\r\n continue;\r\n }\r\n if (t.value === \"let\") {\r\n const n = this.parseLet();\r\n n.span = this.spanFrom(start);\r\n body.push(n);\r\n continue;\r\n }\r\n // A previously-defined component (or this one, recursively) may be called.\r\n if ((components.has(t.value) || t.value === name) && this.peek(1).type === \"lparen\") {\r\n const n = this.parseInstance();\r\n n.span = this.spanFrom(start);\r\n body.push(n);\r\n continue;\r\n }\r\n this.fail(`Expected an element, \"let\", or component call in component body but found ${describe(t)}`, t);\r\n }\r\n this.eat(\"rcurly\");\r\n return { name, params, body, line: kw.line };\r\n }\r\n}\r\n\r\nfunction describe(t: Token): string {\r\n if (t.type === \"eof\") return \"end of input\";\r\n if (t.type === \"string\") return `string ${JSON.stringify(t.value)}`;\r\n return `\"${t.value}\"`;\r\n}\r\n","/**\r\n * Intermediate representation + `resolve(ast)`.\r\n *\r\n * `resolve` is the single place semantics live: it grid-snaps coordinates,\r\n * assigns ids, hosts openings, and runs semantic checks — producing a NEW\r\n * immutable IR (the input AST is never mutated). `render` consumes IR only.\r\n */\r\n\r\nimport type {\r\n AstElement,\r\n ComponentDef,\r\n ElementKind,\r\n ExprPoint,\r\n NorthDir,\r\n PlanNode,\r\n Point,\r\n Statement,\r\n TitleNode,\r\n} from \"./ast.js\";\r\nimport type { Diagnostic, Span } from \"./diagnostics.js\";\r\nimport type { Env, Expr } from \"./expr.js\";\r\nimport { closest, evalExpr } from \"./expr.js\";\r\nimport type { ResolveCtx } from \"./registry.js\";\r\nimport type { WallSegment } from \"./geometry.js\";\r\nimport { hostSegmentForWalls, isOnSomeWall } from \"./geometry.js\";\r\nimport { registryOrder } from \"./elements/index.js\";\r\n\r\nexport interface RBase {\r\n kind: ElementKind;\r\n id: string;\r\n span?: Span;\r\n}\r\n\r\nexport interface RWall extends RBase {\r\n kind: \"wall\";\r\n category: string;\r\n thickness: number;\r\n points: Point[];\r\n closed: boolean;\r\n}\r\nexport interface RRoom extends RBase {\r\n kind: \"room\";\r\n at: Point;\r\n size: { w: number; h: number };\r\n label?: string;\r\n}\r\nexport interface RDoor extends RBase {\r\n kind: \"door\";\r\n at: Point;\r\n width: number;\r\n hinge: \"left\" | \"right\";\r\n swing: \"in\" | \"out\";\r\n host: WallSegment | null;\r\n}\r\nexport interface RWindow extends RBase {\r\n kind: \"window\";\r\n at: Point;\r\n width: number;\r\n host: WallSegment | null;\r\n}\r\nexport interface RFurniture extends RBase {\r\n kind: \"furniture\";\r\n category: string;\r\n at: Point;\r\n size: { w: number; h: number };\r\n label?: string;\r\n}\r\nexport interface RDim extends RBase {\r\n kind: \"dim\";\r\n from: Point;\r\n to: Point;\r\n offset: number;\r\n text?: string;\r\n}\r\nexport interface RColumn extends RBase {\r\n kind: \"column\";\r\n at: Point;\r\n size: { w: number; h: number };\r\n}\r\n\r\nexport type ResolvedElement = RWall | RRoom | RDoor | RWindow | RFurniture | RDim | RColumn;\r\n\r\nexport interface ResolvedPlan {\r\n name: string;\r\n units: \"mm\";\r\n grid: number;\r\n scale?: string;\r\n north: NorthDir;\r\n title?: TitleNode;\r\n /** Resolved elements, in source order (for rendering). */\r\n elements: ResolvedElement[];\r\n /** Resolved walls (for bounds/hosting), in source order. */\r\n walls: RWall[];\r\n}\r\n\r\n/** Max component-instantiation nesting depth before bailing out. */\r\nconst MAX_DEPTH = 64;\r\n\r\n/** An element flattened out of the body, paired with the env its exprs use. */\r\ninterface Entry {\r\n node: AstElement;\r\n env: Env;\r\n id: string;\r\n resolved?: ResolvedElement;\r\n}\r\n\r\n/**\r\n * Expand a statement list into a flat element stream: evaluate `let`s into the\r\n * scope env (source order, no forward refs), and inline component instances.\r\n *\r\n * Scoping is lexical with the plan as the global scope: a component body sees\r\n * the plan-level `let`s (`global`) plus its own params and local `let`s, but\r\n * NOT the caller's locals. `env` is this scope's env; at the top level it *is*\r\n * `global`, so top-level `let`s populate the global scope.\r\n */\r\nfunction expandScope(\r\n body: Statement[],\r\n env: Env,\r\n defined: Set<string>,\r\n global: Env,\r\n components: Map<string, ComponentDef>,\r\n diagnostics: Diagnostic[],\r\n depth: number,\r\n): Entry[] {\r\n const diag = (d: Diagnostic) => diagnostics.push(d);\r\n const out: Entry[] = [];\r\n\r\n for (const stmt of body) {\r\n if (stmt.kind === \"let\") {\r\n if (defined.has(stmt.name)) {\r\n diag({ severity: \"error\", message: `\"${stmt.name}\" is already defined in this scope`, code: \"E_REDEF\", span: stmt.span });\r\n continue;\r\n }\r\n env.set(stmt.name, evalExpr(stmt.value, env, diag));\r\n defined.add(stmt.name);\r\n } else if (stmt.kind === \"instance\") {\r\n const comp = components.get(stmt.name);\r\n if (!comp) {\r\n const hint = closest(stmt.name, [...components.keys()]);\r\n diag({ severity: \"error\", message: `Unknown component \"${stmt.name}\"`, code: \"E_UNKNOWN_COMPONENT\", span: stmt.span, hints: hint ? [`did you mean \"${hint}\"?`] : undefined });\r\n continue;\r\n }\r\n if (depth >= MAX_DEPTH) {\r\n diag({ severity: \"error\", message: `Component recursion too deep (limit ${MAX_DEPTH}) instantiating \"${stmt.name}\"`, code: \"E_RECURSION\", span: stmt.span });\r\n continue;\r\n }\r\n if (stmt.args.length !== comp.params.length) {\r\n diag({ severity: \"error\", message: `Component \"${stmt.name}\" expects ${comp.params.length} argument(s) but got ${stmt.args.length}`, code: \"E_ARGCOUNT\", span: stmt.span });\r\n }\r\n const argVals = comp.params.map((_, i) => (stmt.args[i] !== undefined ? evalExpr(stmt.args[i], env, diag) : 0));\r\n // Component scope = plan global + params; its lets are local.\r\n const childEnv: Env = new Map(global);\r\n const childDefined = new Set<string>();\r\n comp.params.forEach((p, i) => {\r\n childEnv.set(p, argVals[i]);\r\n childDefined.add(p);\r\n });\r\n out.push(...expandScope(comp.body, childEnv, childDefined, global, components, diagnostics, depth + 1));\r\n } else {\r\n out.push({ node: stmt, env: new Map(env), id: \"\" });\r\n }\r\n }\r\n return out;\r\n}\r\n\r\nexport function resolve(ast: PlanNode): { ir: ResolvedPlan; diagnostics: Diagnostic[] } {\r\n const diagnostics: Diagnostic[] = [];\r\n const g = ast.grid;\r\n const snap = (v: number) => (g > 0 ? Math.round(v / g) * g : v);\r\n const snapPt = (p: Point): Point => ({ x: snap(p.x), y: snap(p.y) });\r\n\r\n // 0. Expand body (lets + component instantiation) into a flat element stream.\r\n // At the top level the scope env IS the global env (plan-level `let`s).\r\n const globalEnv: Env = new Map();\r\n const entries = expandScope(ast.body, globalEnv, new Set(), globalEnv, ast.components, diagnostics, 0);\r\n\r\n // 1. Assign ids in registry (canonical) order. The flat stream is numbered\r\n // globally per kind, so auto-ids stay unique across component instances.\r\n const seen = new Set<string>();\r\n const assignId = (provided: string, prefix: string, idx: number, span?: Span): string => {\r\n if (provided) {\r\n if (seen.has(provided)) {\r\n diagnostics.push({ severity: \"error\", message: `Duplicate id \"${provided}\"`, code: \"E_DUP_ID\", span });\r\n }\r\n seen.add(provided);\r\n return provided;\r\n }\r\n let auto = `${prefix}_${idx}`;\r\n while (seen.has(auto)) auto = `${auto}_`;\r\n seen.add(auto);\r\n return auto;\r\n };\r\n for (const def of registryOrder) {\r\n let idx = 0;\r\n for (const e of entries) {\r\n if (e.node.kind !== def.kind) continue;\r\n idx++;\r\n e.id = assignId(e.node.id, def.idPrefix(e.node), idx, e.node.span);\r\n }\r\n }\r\n\r\n // 2. Resolve in registry order (walls first → openings can host against them).\r\n // `activeEnv`/`activeId` are swapped per entry so each element evaluates\r\n // its expressions against the env captured during expansion.\r\n const walls: RWall[] = [];\r\n let activeEnv: Env = new Map();\r\n const evalNum = (e: Expr): number => evalExpr(e, activeEnv, (d) => diagnostics.push(d));\r\n const evalPt = (p: ExprPoint): Point => ({ x: evalNum(p.x), y: evalNum(p.y) });\r\n const ctx: ResolveCtx = {\r\n grid: g,\r\n snap,\r\n snapPt,\r\n eval: evalNum,\r\n evalPt,\r\n id: \"\",\r\n walls,\r\n hostSegment: (at, ref) => hostSegmentForWalls(walls, at, ref),\r\n isOnWall: (at, ref) => isOnSomeWall(walls, at, ref),\r\n diag: (d) => diagnostics.push(d),\r\n };\r\n for (const def of registryOrder) {\r\n for (const e of entries) {\r\n if (e.node.kind !== def.kind) continue;\r\n activeEnv = e.env;\r\n ctx.id = e.id;\r\n const r = def.resolve(e.node, ctx);\r\n e.resolved = r;\r\n if (r.kind === \"wall\") walls.push(r);\r\n }\r\n }\r\n\r\n // 3. IR element list in source order (for rendering).\r\n const elements = entries.map((e) => e.resolved!);\r\n\r\n // 4. Cross-element checks.\r\n const drawable = elements.some(\r\n (e) => e.kind === \"wall\" || e.kind === \"room\" || e.kind === \"furniture\" || e.kind === \"column\",\r\n );\r\n if (!drawable) {\r\n diagnostics.push({\r\n severity: \"warning\",\r\n message: \"Plan has no walls, rooms, or furniture — nothing to draw\",\r\n code: \"W_EMPTY_PLAN\",\r\n });\r\n }\r\n const rooms = elements.filter((e): e is RRoom => e.kind === \"room\");\r\n for (let a = 0; a < rooms.length; a++) {\r\n for (let b = a + 1; b < rooms.length; b++) {\r\n const r1 = rooms[a];\r\n const r2 = rooms[b];\r\n const ox = Math.max(0, Math.min(r1.at.x + r1.size.w, r2.at.x + r2.size.w) - Math.max(r1.at.x, r2.at.x));\r\n const oy = Math.max(0, Math.min(r1.at.y + r1.size.h, r2.at.y + r2.size.h) - Math.max(r1.at.y, r2.at.y));\r\n if (ox > 1 && oy > 1) {\r\n diagnostics.push({\r\n severity: \"warning\",\r\n message: `Rooms \"${r1.id}\" and \"${r2.id}\" overlap`,\r\n code: \"W_ROOM_OVERLAP\",\r\n span: r2.span,\r\n });\r\n }\r\n }\r\n }\r\n\r\n const ir: ResolvedPlan = {\r\n name: ast.name,\r\n units: ast.units,\r\n grid: ast.grid,\r\n scale: ast.scale,\r\n north: ast.north,\r\n title: ast.title,\r\n elements,\r\n walls,\r\n };\r\n return { ir, diagnostics };\r\n}\r\n","/**\r\n * Element registry: the single extension point. Each element type is one module\r\n * exporting an {@link ElementDef}; parse/resolve/render iterate the registry\r\n * rather than a hard-coded switch. Adding an element = one new module + one\r\n * `register` line in `elements/index.ts`.\r\n */\r\n\r\nimport type { Token } from \"./lexer.js\";\r\nimport type { AstElement, ElementKind, ExprPoint, Point } from \"./ast.js\";\r\nimport type { Expr } from \"./expr.js\";\r\nimport type { Diagnostic } from \"./diagnostics.js\";\r\nimport type { ResolvedElement, RWall } from \"./ir.js\";\r\nimport type { Bounds, WallSegment } from \"./geometry.js\";\r\n\r\n/**\r\n * Ordered render layers. Element ops are bucketed by pass and emitted in this\r\n * order, preserving source order within a pass — this exactly reproduces the\r\n * v0.1 global draw order (all wall fills, then all wall faces, doors before\r\n * windows, labels above fills, …).\r\n */\r\nexport const RENDER_PASSES = [\r\n \"floor\",\r\n \"furniture\",\r\n \"wallFill\",\r\n \"wallFace\",\r\n \"doors\",\r\n \"windows\",\r\n \"labels\",\r\n \"dims\",\r\n \"annotations\",\r\n] as const;\r\nexport type RenderPass = (typeof RENDER_PASSES)[number];\r\n\r\nexport interface RenderOp {\r\n pass: RenderPass;\r\n svg: string;\r\n}\r\n\r\n/** Parser facade handed to `ElementDef.parse` — the existing recursive-descent helpers. */\r\nexport interface ParseCtx {\r\n peek(o?: number): Token;\r\n next(): Token;\r\n eat(type: Token[\"type\"]): Token;\r\n eatKeyword(kw: string): Token;\r\n eatIdent(): Token;\r\n eatNumber(): number;\r\n eatString(): string;\r\n isKeyword(kw: string, o?: number): boolean;\r\n isType(type: Token[\"type\"]): boolean;\r\n /** Parse a `(expr, expr)` point. */\r\n parsePoint(): ExprPoint;\r\n /** Parse an arithmetic expression. */\r\n parseExpr(): Expr;\r\n /** Parse a size: either a `WxH` dimension literal or `<expr> x <expr>`. */\r\n parseDimensions(): { w: Expr; h: Expr };\r\n parseIdOpt(): string;\r\n /** Report a fatal parse error at `t` (defaults to the current token); never returns. */\r\n fail(msg: string, t?: Token): never;\r\n}\r\n\r\n/** Semantic-analysis facade handed to `ElementDef.resolve`. */\r\nexport interface ResolveCtx {\r\n grid: number;\r\n snap(v: number): number;\r\n snapPt(p: Point): Point;\r\n /** Evaluate an expression against the current binding environment. */\r\n eval(e: Expr): number;\r\n /** Evaluate an expression-point to a concrete point. */\r\n evalPt(p: ExprPoint): Point;\r\n /** Resolved id of the element currently being resolved. */\r\n id: string;\r\n /** Resolved walls, ready before openings resolve (walls resolve first). */\r\n walls: RWall[];\r\n hostSegment(at: Point, ref?: string): WallSegment | null;\r\n isOnWall(at: Point, ref?: string): boolean;\r\n diag(d: Diagnostic): void;\r\n}\r\n\r\nexport interface RenderSizes {\r\n refDim: number;\r\n wallStroke: number;\r\n thin: number;\r\n roomFont: number;\r\n areaFont: number;\r\n dimFont: number;\r\n furnFont: number;\r\n margin: number;\r\n hatchGap: number;\r\n}\r\n\r\n/** Render facade: number formatting, theme, derived sizes, and drawing bounds. */\r\nexport interface RenderCtx {\r\n fmt(v: number): string;\r\n pt(p: Point): string;\r\n xml(s: string): string;\r\n theme: Record<string, string>;\r\n sizes: RenderSizes;\r\n bounds: Bounds;\r\n}\r\n\r\n/**\r\n * One element type. `TNode`/`TResolved` are the concrete node/IR types; the\r\n * registry stores these widened to the unions, and each module narrows via the\r\n * `kind` discriminant.\r\n */\r\nexport interface ElementDef {\r\n kind: ElementKind;\r\n keyword: string;\r\n parse(ctx: ParseCtx): AstElement;\r\n /** Auto-id prefix (e.g. \"room\", or a wall/furniture's category). */\r\n idPrefix(node: AstElement): string;\r\n resolve(node: AstElement, ctx: ResolveCtx): ResolvedElement;\r\n /** Points this element contributes to the drawing bounds. */\r\n bounds(resolved: ResolvedElement): Point[];\r\n render(resolved: ResolvedElement, ctx: RenderCtx): RenderOp[];\r\n}\r\n","/** Renders a resolved plan (IR) to a professional SVG floor plan. Deterministic. */\r\n\r\nimport type { Point } from \"./ast.js\";\r\nimport type { CompileOptions } from \"./types.js\";\r\nimport type { ResolvedPlan } from \"./ir.js\";\r\nimport type { RenderCtx, RenderSizes } from \"./registry.js\";\r\nimport { RENDER_PASSES } from \"./registry.js\";\r\nimport { registry } from \"./elements/index.js\";\r\nimport type { Bounds } from \"./geometry.js\";\r\nimport { emptyBounds, extendBounds } from \"./geometry.js\";\r\n\r\nconst THEME: Record<string, string> = {\r\n bg: \"#ffffff\",\r\n pocheBase: \"#e9e4db\",\r\n pocheHatch: \"#b9b1a4\",\r\n wallStroke: \"#1b1b1b\",\r\n roomFill: \"#fbfaf7\",\r\n roomLabel: \"#222222\",\r\n areaLabel: \"#7a7a7a\",\r\n furnitureStroke: \"#a8a29a\",\r\n furnitureFill: \"#f4f2ee\",\r\n furnitureLabel: \"#9a948c\",\r\n opening: \"#ffffff\",\r\n doorLeaf: \"#555555\",\r\n windowPane: \"#3a6ea5\",\r\n dim: \"#0E5484\",\r\n annotation: \"#333333\",\r\n annotationMuted: \"#888888\",\r\n column: \"#4a4a4a\",\r\n};\r\n\r\n/** Round to 2 decimals and strip trailing zeros — keeps output stable & compact. */\r\nfunction fmt(v: number): string {\r\n const r = Math.round(v * 100) / 100;\r\n return Object.is(r, -0) ? \"0\" : String(r);\r\n}\r\nconst pt = (p: Point): string => `${fmt(p.x)},${fmt(p.y)}`;\r\n\r\nfunction xml(s: string): string {\r\n return s\r\n .replace(/&/g, \"&\")\r\n .replace(/</g, \"<\")\r\n .replace(/>/g, \">\")\r\n .replace(/\"/g, \""\");\r\n}\r\n\r\nconst NICE_LENGTHS = [500, 1000, 2000, 5000, 10000, 20000, 50000, 100000];\r\nfunction niceBarLength(target: number): number {\r\n let best = NICE_LENGTHS[0];\r\n for (const v of NICE_LENGTHS) if (v <= target) best = v;\r\n return best;\r\n}\r\n\r\n/** Drawing bounds: each element contributes points via its registry `bounds`. */\r\nfunction planBounds(ir: ResolvedPlan): Bounds {\r\n const b = emptyBounds();\r\n for (const el of ir.elements) {\r\n const def = registry.get(el.kind);\r\n if (!def) continue;\r\n for (const p of def.bounds(el)) extendBounds(b, p.x, p.y);\r\n }\r\n if (!isFinite(b.minX)) {\r\n // Nothing to draw; provide a default frame.\r\n return { minX: 0, minY: 0, maxX: 1000, maxY: 1000 };\r\n }\r\n return b;\r\n}\r\n\r\nexport function render(ir: ResolvedPlan, opts: CompileOptions = {}): string {\r\n const b = planBounds(ir);\r\n const drawW = b.maxX - b.minX;\r\n const drawH = b.maxY - b.minY;\r\n const refDim = Math.max(drawW, drawH, 1);\r\n\r\n const sizes: RenderSizes = {\r\n refDim,\r\n wallStroke: refDim * 0.0028,\r\n thin: refDim * 0.0016,\r\n roomFont: refDim * 0.03,\r\n areaFont: refDim * 0.022,\r\n dimFont: refDim * 0.02,\r\n furnFont: refDim * 0.017,\r\n margin: refDim * 0.17,\r\n hatchGap: refDim * 0.013,\r\n };\r\n const { thin, margin, hatchGap } = sizes;\r\n\r\n const vbX = b.minX - margin;\r\n const vbY = b.minY - margin;\r\n const vbW = drawW + margin * 2;\r\n const vbH = drawH + margin * 2;\r\n\r\n const out: string[] = [];\r\n const svgAttrs = opts.width\r\n ? `width=\"${fmt(opts.width)}\" height=\"${fmt((opts.width * vbH) / vbW)}\"`\r\n : \"\";\r\n out.push(\r\n `<svg xmlns=\"http://www.w3.org/2000/svg\" ${svgAttrs} viewBox=\"${fmt(vbX)} ${fmt(vbY)} ${fmt(vbW)} ${fmt(vbH)}\" font-family=\"Helvetica, Arial, sans-serif\">`,\r\n );\r\n\r\n // Defs: poché hatch pattern\r\n out.push(\r\n `<defs><pattern id=\"poche\" patternUnits=\"userSpaceOnUse\" width=\"${fmt(hatchGap)}\" height=\"${fmt(hatchGap)}\" patternTransform=\"rotate(45)\">` +\r\n `<rect width=\"${fmt(hatchGap)}\" height=\"${fmt(hatchGap)}\" fill=\"${THEME.pocheBase}\"/>` +\r\n `<line x1=\"0\" y1=\"0\" x2=\"0\" y2=\"${fmt(hatchGap)}\" stroke=\"${THEME.pocheHatch}\" stroke-width=\"${fmt(thin * 0.7)}\"/>` +\r\n `</pattern></defs>`,\r\n );\r\n\r\n // Background\r\n out.push(`<rect x=\"${fmt(vbX)}\" y=\"${fmt(vbY)}\" width=\"${fmt(vbW)}\" height=\"${fmt(vbH)}\" fill=\"${THEME.bg}\"/>`);\r\n\r\n // Elements: collect ops once (preserving source order), then emit pass by pass.\r\n const ctx: RenderCtx = { fmt, pt, xml, theme: THEME, sizes, bounds: b };\r\n const ops = ir.elements.flatMap((el) => {\r\n const def = registry.get(el.kind);\r\n return def ? def.render(el, ctx) : [];\r\n });\r\n for (const pass of RENDER_PASSES) {\r\n for (const op of ops) if (op.pass === pass) out.push(op.svg);\r\n }\r\n\r\n // Plan-level annotations (after element passes): north, scale bar, title block.\r\n out.push(northArrow(ir, b, margin, refDim));\r\n out.push(scaleBar(b, margin, refDim, thin));\r\n const tb = titleBlock(ir, b, margin, refDim, thin);\r\n if (tb) out.push(tb);\r\n\r\n out.push(\"</svg>\");\r\n return out.join(\"\\n\");\r\n}\r\n\r\nfunction northArrow(ir: ResolvedPlan, b: Bounds, margin: number, refDim: number): string {\r\n const r = refDim * 0.045;\r\n const cx = b.maxX - r;\r\n const cy = b.minY - margin * 0.55;\r\n let deg: number;\r\n switch (ir.north) {\r\n case \"up\": deg = 0; break;\r\n case \"down\": deg = 180; break;\r\n case \"left\": deg = 270; break;\r\n case \"right\": deg = 90; break;\r\n default: deg = typeof ir.north === \"object\" ? ir.north.deg : 0;\r\n }\r\n const fs = refDim * 0.026;\r\n // Triangle points \"up\" before rotation; only the arrow rotates — the \"N\"\r\n // label stays upright at the pointing end so it always reads correctly.\r\n const tri = `${fmt(cx)},${fmt(cy - r)} ${fmt(cx - r * 0.5)},${fmt(cy + r * 0.6)} ${fmt(cx)},${fmt(cy + r * 0.25)} ${fmt(cx + r * 0.5)},${fmt(cy + r * 0.6)}`;\r\n const rad = (deg * Math.PI) / 180;\r\n // North screen vector (rotate the \"up\" vector (0,-1) clockwise by deg).\r\n const nx = Math.sin(rad);\r\n const ny = -Math.cos(rad);\r\n const lx = cx + nx * (r + fs * 0.8);\r\n const ly = cy + ny * (r + fs * 0.8);\r\n return (\r\n `<g>` +\r\n `<polygon points=\"${tri}\" fill=\"${THEME.annotation}\" transform=\"rotate(${fmt(deg)} ${fmt(cx)} ${fmt(cy)})\"/>` +\r\n `<text x=\"${fmt(lx)}\" y=\"${fmt(ly)}\" font-size=\"${fmt(fs)}\" fill=\"${THEME.annotation}\" text-anchor=\"middle\" dominant-baseline=\"central\">N</text>` +\r\n `</g>`\r\n );\r\n}\r\n\r\nfunction scaleBar(b: Bounds, margin: number, refDim: number, thin: number): string {\r\n const barLen = niceBarLength(refDim * 0.3);\r\n const x0 = b.minX;\r\n const y0 = b.maxY + margin * 0.55;\r\n const hgt = refDim * 0.014;\r\n const fs = refDim * 0.02;\r\n const parts: string[] = [];\r\n const half = barLen / 2;\r\n // two-segment alternating bar\r\n parts.push(`<rect x=\"${fmt(x0)}\" y=\"${fmt(y0)}\" width=\"${fmt(half)}\" height=\"${fmt(hgt)}\" fill=\"${THEME.annotation}\"/>`);\r\n parts.push(\r\n `<rect x=\"${fmt(x0 + half)}\" y=\"${fmt(y0)}\" width=\"${fmt(half)}\" height=\"${fmt(hgt)}\" fill=\"none\" stroke=\"${THEME.annotation}\" stroke-width=\"${fmt(thin)}\"/>`,\r\n );\r\n parts.push(\r\n `<text x=\"${fmt(x0)}\" y=\"${fmt(y0 + hgt + fs)}\" font-size=\"${fmt(fs)}\" fill=\"${THEME.annotation}\" text-anchor=\"start\" dominant-baseline=\"central\">0</text>`,\r\n );\r\n parts.push(\r\n `<text x=\"${fmt(x0 + barLen)}\" y=\"${fmt(y0 + hgt + fs)}\" font-size=\"${fmt(fs)}\" fill=\"${THEME.annotation}\" text-anchor=\"middle\" dominant-baseline=\"central\">${barLen / 1000} m</text>`,\r\n );\r\n return `<g>${parts.join(\"\")}</g>`;\r\n}\r\n\r\nfunction titleBlock(ir: ResolvedPlan, b: Bounds, margin: number, refDim: number, thin: number): string | null {\r\n const t = ir.title;\r\n if (!t && !ir.scale) return null;\r\n const boxW = refDim * 0.34;\r\n const boxH = margin * 0.82;\r\n const x0 = b.maxX - boxW;\r\n const y0 = b.maxY + margin * 0.15;\r\n const fs = refDim * 0.019;\r\n const pad = boxW * 0.05;\r\n const lines: { k: string; v: string }[] = [];\r\n if (t?.project) lines.push({ k: \"PROJECT\", v: t.project });\r\n if (t?.drawnBy) lines.push({ k: \"DRAWN BY\", v: t.drawnBy });\r\n if (t?.date) lines.push({ k: \"DATE\", v: t.date });\r\n if (ir.scale) lines.push({ k: \"SCALE\", v: ir.scale });\r\n\r\n const parts: string[] = [];\r\n parts.push(\r\n `<rect x=\"${fmt(x0)}\" y=\"${fmt(y0)}\" width=\"${fmt(boxW)}\" height=\"${fmt(boxH)}\" fill=\"none\" stroke=\"${THEME.annotation}\" stroke-width=\"${fmt(thin)}\"/>`,\r\n );\r\n const rowH = boxH / Math.max(lines.length, 1);\r\n lines.forEach((ln, i) => {\r\n const ly = y0 + rowH * (i + 0.5);\r\n parts.push(\r\n `<text x=\"${fmt(x0 + pad)}\" y=\"${fmt(ly)}\" font-size=\"${fmt(fs * 0.8)}\" fill=\"${THEME.annotationMuted}\" dominant-baseline=\"central\">${xml(ln.k)}</text>`,\r\n );\r\n parts.push(\r\n `<text x=\"${fmt(x0 + boxW - pad)}\" y=\"${fmt(ly)}\" font-size=\"${fmt(fs)}\" fill=\"${THEME.annotation}\" text-anchor=\"end\" dominant-baseline=\"central\">${xml(ln.v)}</text>`,\r\n );\r\n if (i > 0)\r\n parts.push(\r\n `<line x1=\"${fmt(x0)}\" y1=\"${fmt(y0 + rowH * i)}\" x2=\"${fmt(x0 + boxW)}\" y2=\"${fmt(y0 + rowH * i)}\" stroke=\"${THEME.annotation}\" stroke-width=\"${fmt(thin * 0.5)}\"/>`,\r\n );\r\n });\r\n return `<g>${parts.join(\"\")}</g>`;\r\n}\r\n","/**\r\n * Diagnostics for the ArchLang compiler.\r\n *\r\n * A {@link Diagnostic} is the single, span-carrying problem record produced by\r\n * every compiler stage (lex/parse/validate). The legacy `{message, line, col}`\r\n * `errors`/`warnings` arrays on {@link import(\"./types.js\").CompileResult} are\r\n * *derived* from these. {@link formatDiagnostic} renders a codespan-style,\r\n * caret-framed snippet — zero dependencies, pure, isomorphic.\r\n */\r\n\r\n/** A half-open byte range `[start, end)` into the source string. */\r\nexport interface Span {\r\n start: number;\r\n end: number;\r\n}\r\n\r\nexport type Severity = \"error\" | \"warning\";\r\n\r\nexport interface Diagnostic {\r\n severity: Severity;\r\n message: string;\r\n /** Source location; absent for whole-program problems (e.g. an empty plan). */\r\n span?: Span;\r\n /** Stable machine code, e.g. `\"E_ROOM_SIZE\"`. */\r\n code?: string;\r\n /** Optional follow-up suggestions, each rendered as a `= help:` line. */\r\n hints?: string[];\r\n}\r\n\r\n/** Convert a byte offset into a 1-based `{line, col}`. Offsets are clamped. */\r\nexport function offsetToLineCol(source: string, offset: number): { line: number; col: number } {\r\n const o = Math.max(0, Math.min(offset, source.length));\r\n let line = 1;\r\n let col = 1;\r\n for (let k = 0; k < o; k++) {\r\n if (source[k] === \"\\n\") {\r\n line++;\r\n col = 1;\r\n } else {\r\n col++;\r\n }\r\n }\r\n return { line, col };\r\n}\r\n\r\n/** Byte offset of the start of the line containing `offset`. */\r\nfunction lineStart(source: string, offset: number): number {\r\n let k = Math.max(0, Math.min(offset, source.length));\r\n while (k > 0 && source[k - 1] !== \"\\n\") k--;\r\n return k;\r\n}\r\n\r\n/** Byte offset just past the end of the line containing `offset` (excludes `\\n`). */\r\nfunction lineEnd(source: string, offset: number): number {\r\n let k = Math.max(0, Math.min(offset, source.length));\r\n while (k < source.length && source[k] !== \"\\n\") k++;\r\n return k;\r\n}\r\n\r\n/**\r\n * Render a diagnostic as a framed source snippet:\r\n *\r\n * ```text\r\n * error[E_ROOM_SIZE]: room \"bed\" must have a positive size\r\n * --> 4:30\r\n * |\r\n * 4 | room id=bed at (0,0) size 0x4000\r\n * | ^^^^^^ width is 0\r\n * = help: did you mean 3000x4000?\r\n * ```\r\n *\r\n * With no `span`, only the header line is produced.\r\n */\r\nexport function formatDiagnostic(source: string, d: Diagnostic): string {\r\n const codeTag = d.code ? `[${d.code}]` : \"\";\r\n const header = `${d.severity}${codeTag}: ${d.message}`;\r\n const lines: string[] = [header];\r\n\r\n if (d.span) {\r\n const { line, col } = offsetToLineCol(source, d.span.start);\r\n const ls = lineStart(source, d.span.start);\r\n const le = lineEnd(source, d.span.start);\r\n const srcLine = source.slice(ls, le);\r\n // Underline within this one line; multi-line spans underline to line end.\r\n const caretStart = d.span.start - ls;\r\n const caretEnd = Math.min(d.span.end, le) - ls;\r\n const caretLen = Math.max(1, caretEnd - caretStart);\r\n\r\n const gutter = String(line);\r\n const pad = \" \".repeat(gutter.length);\r\n lines.push(`${pad} --> ${line}:${col}`);\r\n lines.push(`${pad} |`);\r\n lines.push(`${gutter} | ${srcLine}`);\r\n lines.push(`${pad} | ${\" \".repeat(caretStart)}${\"^\".repeat(caretLen)}`);\r\n for (const hint of d.hints ?? []) {\r\n lines.push(`${pad} = help: ${hint}`);\r\n }\r\n } else {\r\n for (const hint of d.hints ?? []) {\r\n lines.push(` = help: ${hint}`);\r\n }\r\n }\r\n\r\n return lines.join(\"\\n\");\r\n}\r\n","/**\r\n * ArchLang — compile declarative floor-plan source to a professional SVG.\r\n *\r\n * @example\r\n * import { compile } from \"@chanmeng666/archlang\";\r\n * const { svg, errors } = compile(`plan \"Demo\" { room at (0,0) size 4000x3000 label \"Room\" }`);\r\n */\r\n\r\nimport { parse } from \"./parser.js\";\r\nimport { resolve } from \"./ir.js\";\r\nimport { render } from \"./render.js\";\r\nimport { offsetToLineCol } from \"./diagnostics.js\";\r\nimport type { Diagnostic } from \"./diagnostics.js\";\r\nimport type { CompileError, CompileOptions, CompileResult } from \"./types.js\";\r\n\r\nexport type {\r\n CompileError,\r\n CompileOptions,\r\n CompileResult,\r\n CompileWarning,\r\n Diagnostic,\r\n Span,\r\n Severity,\r\n} from \"./types.js\";\r\nexport { formatDiagnostic, offsetToLineCol } from \"./diagnostics.js\";\r\nexport type * from \"./ast.js\";\r\n\r\n/** Small LRU-ish memo cache keyed by source+options. Bounded to 64 entries. */\r\nconst cache = new Map<string, CompileResult>();\r\nconst CACHE_MAX = 64;\r\n\r\nexport function compile(source: string, opts: CompileOptions = {}): CompileResult {\r\n const key = JSON.stringify([source, opts.width ?? null]);\r\n if (!opts.noCache) {\r\n const hit = cache.get(key);\r\n if (hit) return hit;\r\n }\r\n\r\n const result = compileUncached(source, opts);\r\n\r\n if (!opts.noCache) {\r\n if (cache.size >= CACHE_MAX) {\r\n const oldest = cache.keys().next().value;\r\n if (oldest !== undefined) cache.delete(oldest);\r\n }\r\n cache.set(key, result);\r\n }\r\n return result;\r\n}\r\n\r\n/** Project a span-carrying diagnostic onto the legacy `{message, line, col}` shape. */\r\nfunction toLegacy(source: string, d: Diagnostic): CompileError {\r\n if (!d.span) return { message: d.message };\r\n const { line, col } = offsetToLineCol(source, d.span.start);\r\n return { message: d.message, line, col };\r\n}\r\n\r\nfunction compileUncached(source: string, opts: CompileOptions): CompileResult {\r\n const { plan, diagnostics: parseDiags } = parse(source);\r\n\r\n // parse → resolve (AST→IR, the single place semantics live) → render.\r\n const resolved = plan ? resolve(plan) : null;\r\n const diagnostics: Diagnostic[] = resolved\r\n ? [...parseDiags, ...resolved.diagnostics]\r\n : [...parseDiags];\r\n\r\n const errs = diagnostics.filter((d) => d.severity === \"error\");\r\n const errors = errs.map((d) => toLegacy(source, d));\r\n const warnings = diagnostics\r\n .filter((d) => d.severity === \"warning\")\r\n .map((d) => toLegacy(source, d));\r\n\r\n // Warnings never block rendering; any error (or no plan) aborts with svg = \"\".\r\n const svg = resolved && errs.length === 0 ? render(resolved.ir, opts) : \"\";\r\n\r\n return { svg, errors, warnings, diagnostics, ast: plan };\r\n}\r\n\r\n/** Clear the internal compile cache (useful in long-lived processes/tests). */\r\nexport function clearCache(): void {\r\n cache.clear();\r\n}\r\n"],"mappings":"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","names":["describe","fmt","pt","fmt","pt","xml","fmt","pt","fmt","pt","fmt","pt","xml","fmt","xml","fmt","pt","describe","def"]}
|
package/dist/cli.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -44,6 +44,32 @@ declare function offsetToLineCol(source: string, offset: number): {
|
|
|
44
44
|
*/
|
|
45
45
|
declare function formatDiagnostic(source: string, d: Diagnostic): string;
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Arithmetic expressions: a small Pratt parser + a pure evaluator.
|
|
49
|
+
*
|
|
50
|
+
* Expressions appear anywhere a number does (coordinates, sizes, widths,
|
|
51
|
+
* thickness, offsets). They are parsed into an {@link Expr} AST and evaluated
|
|
52
|
+
* during `resolve` against an {@link Env} of `let`/parameter bindings.
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
type Expr = {
|
|
56
|
+
t: "num";
|
|
57
|
+
value: number;
|
|
58
|
+
} | {
|
|
59
|
+
t: "ref";
|
|
60
|
+
name: string;
|
|
61
|
+
span?: Span;
|
|
62
|
+
} | {
|
|
63
|
+
t: "unary";
|
|
64
|
+
op: "-" | "+";
|
|
65
|
+
e: Expr;
|
|
66
|
+
} | {
|
|
67
|
+
t: "bin";
|
|
68
|
+
op: "+" | "-" | "*" | "/" | "%";
|
|
69
|
+
l: Expr;
|
|
70
|
+
r: Expr;
|
|
71
|
+
};
|
|
72
|
+
|
|
47
73
|
/** Abstract syntax tree for an ArchLang `plan`. All distances are in millimetres.
|
|
48
74
|
*
|
|
49
75
|
* The AST is the raw, immutable output of parsing: `resolve()` (see ir.ts) reads
|
|
@@ -54,6 +80,11 @@ interface Point {
|
|
|
54
80
|
x: number;
|
|
55
81
|
y: number;
|
|
56
82
|
}
|
|
83
|
+
/** A point whose coordinates are expressions (evaluated during resolve). */
|
|
84
|
+
interface ExprPoint {
|
|
85
|
+
x: Expr;
|
|
86
|
+
y: Expr;
|
|
87
|
+
}
|
|
57
88
|
/** North orientation: a cardinal keyword or an explicit bearing in degrees. */
|
|
58
89
|
type NorthDir = "up" | "down" | "left" | "right" | {
|
|
59
90
|
deg: number;
|
|
@@ -72,25 +103,25 @@ interface WallNode extends NodeBase {
|
|
|
72
103
|
/** Free-form category, e.g. "exterior" or "partition". Also a door/window ref. */
|
|
73
104
|
category: string;
|
|
74
105
|
/** Wall thickness in mm. */
|
|
75
|
-
thickness:
|
|
106
|
+
thickness: Expr;
|
|
76
107
|
/** Polyline vertices in order. */
|
|
77
|
-
points:
|
|
108
|
+
points: ExprPoint[];
|
|
78
109
|
/** Whether the polyline closes back to its first vertex. */
|
|
79
110
|
closed: boolean;
|
|
80
111
|
}
|
|
81
112
|
interface RoomNode extends NodeBase {
|
|
82
113
|
kind: "room";
|
|
83
|
-
at:
|
|
114
|
+
at: ExprPoint;
|
|
84
115
|
size: {
|
|
85
|
-
w:
|
|
86
|
-
h:
|
|
116
|
+
w: Expr;
|
|
117
|
+
h: Expr;
|
|
87
118
|
};
|
|
88
119
|
label?: string;
|
|
89
120
|
}
|
|
90
121
|
interface DoorNode extends NodeBase {
|
|
91
122
|
kind: "door";
|
|
92
|
-
at:
|
|
93
|
-
width:
|
|
123
|
+
at: ExprPoint;
|
|
124
|
+
width: Expr;
|
|
94
125
|
/** Optional wall (id or category) the door is hosted by. */
|
|
95
126
|
wall?: string;
|
|
96
127
|
hinge: "left" | "right";
|
|
@@ -98,40 +129,62 @@ interface DoorNode extends NodeBase {
|
|
|
98
129
|
}
|
|
99
130
|
interface WindowNode extends NodeBase {
|
|
100
131
|
kind: "window";
|
|
101
|
-
at:
|
|
102
|
-
width:
|
|
132
|
+
at: ExprPoint;
|
|
133
|
+
width: Expr;
|
|
103
134
|
wall?: string;
|
|
104
135
|
}
|
|
105
136
|
interface FurnitureNode extends NodeBase {
|
|
106
137
|
kind: "furniture";
|
|
107
138
|
/** Free-form category, e.g. "bed" or "sofa". */
|
|
108
139
|
category: string;
|
|
109
|
-
at:
|
|
140
|
+
at: ExprPoint;
|
|
110
141
|
size: {
|
|
111
|
-
w:
|
|
112
|
-
h:
|
|
142
|
+
w: Expr;
|
|
143
|
+
h: Expr;
|
|
113
144
|
};
|
|
114
145
|
label?: string;
|
|
115
146
|
}
|
|
116
147
|
interface DimNode extends NodeBase {
|
|
117
148
|
kind: "dim";
|
|
118
|
-
from:
|
|
119
|
-
to:
|
|
149
|
+
from: ExprPoint;
|
|
150
|
+
to: ExprPoint;
|
|
120
151
|
/** Perpendicular offset of the dimension line from the measured segment, mm. */
|
|
121
|
-
offset:
|
|
152
|
+
offset: Expr;
|
|
122
153
|
/** Override text; defaults to the measured length. */
|
|
123
154
|
text?: string;
|
|
124
155
|
}
|
|
125
156
|
interface ColumnNode extends NodeBase {
|
|
126
157
|
kind: "column";
|
|
127
|
-
at:
|
|
158
|
+
at: ExprPoint;
|
|
128
159
|
size: {
|
|
129
|
-
w:
|
|
130
|
-
h:
|
|
160
|
+
w: Expr;
|
|
161
|
+
h: Expr;
|
|
131
162
|
};
|
|
132
163
|
}
|
|
133
164
|
/** Discriminated union of all element AST nodes (registry-dispatchable). */
|
|
134
165
|
type AstElement = WallNode | RoomNode | DoorNode | WindowNode | FurnitureNode | DimNode | ColumnNode;
|
|
166
|
+
/** `let NAME = <expr>` — a binding statement. */
|
|
167
|
+
interface LetNode extends NodeBase {
|
|
168
|
+
kind: "let";
|
|
169
|
+
name: string;
|
|
170
|
+
value: Expr;
|
|
171
|
+
}
|
|
172
|
+
/** `NAME(args)` — instantiate a component (expanded during resolve). */
|
|
173
|
+
interface InstanceNode extends NodeBase {
|
|
174
|
+
kind: "instance";
|
|
175
|
+
name: string;
|
|
176
|
+
args: Expr[];
|
|
177
|
+
}
|
|
178
|
+
/** A plan-body statement in source order: an element, a `let`, or an instance. */
|
|
179
|
+
type Statement = AstElement | LetNode | InstanceNode;
|
|
180
|
+
/** `component NAME(params) { body }` — a reusable parameterised sub-plan. */
|
|
181
|
+
interface ComponentDef {
|
|
182
|
+
name: string;
|
|
183
|
+
params: string[];
|
|
184
|
+
body: Statement[];
|
|
185
|
+
line: number;
|
|
186
|
+
span?: Span;
|
|
187
|
+
}
|
|
135
188
|
interface TitleNode {
|
|
136
189
|
project?: string;
|
|
137
190
|
drawnBy?: string;
|
|
@@ -149,8 +202,10 @@ interface PlanNode {
|
|
|
149
202
|
scale?: string;
|
|
150
203
|
north: NorthDir;
|
|
151
204
|
title?: TitleNode;
|
|
152
|
-
/**
|
|
153
|
-
|
|
205
|
+
/** Component definitions, by name. */
|
|
206
|
+
components: Map<string, ComponentDef>;
|
|
207
|
+
/** All statements (elements, `let`s, instances), in source order. */
|
|
208
|
+
body: Statement[];
|
|
154
209
|
}
|
|
155
210
|
|
|
156
211
|
interface CompileError {
|
|
@@ -199,4 +254,4 @@ declare function compile(source: string, opts?: CompileOptions): CompileResult;
|
|
|
199
254
|
/** Clear the internal compile cache (useful in long-lived processes/tests). */
|
|
200
255
|
declare function clearCache(): void;
|
|
201
256
|
|
|
202
|
-
export { type AstElement, type ColumnNode, type CompileError, type CompileOptions, type CompileResult, type CompileWarning, type Diagnostic, type DimNode, type DoorNode, type ElementKind, type FurnitureNode, type NodeBase, type NorthDir, type PlanNode, type Point, type RoomNode, type Severity, type Span, type TitleNode, type WallNode, type WindowNode, clearCache, compile, formatDiagnostic, offsetToLineCol };
|
|
257
|
+
export { type AstElement, type ColumnNode, type CompileError, type CompileOptions, type CompileResult, type CompileWarning, type ComponentDef, type Diagnostic, type DimNode, type DoorNode, type ElementKind, type ExprPoint, type FurnitureNode, type InstanceNode, type LetNode, type NodeBase, type NorthDir, type PlanNode, type Point, type RoomNode, type Severity, type Span, type Statement, type TitleNode, type WallNode, type WindowNode, clearCache, compile, formatDiagnostic, offsetToLineCol };
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Parametric plan: a row of identical studio units built from ONE component.
|
|
2
|
+
# Demonstrates `let` bindings, arithmetic, and reusable `component`s.
|
|
3
|
+
plan "Parametric — Studio Row" {
|
|
4
|
+
units mm
|
|
5
|
+
grid 50
|
|
6
|
+
scale 1:100
|
|
7
|
+
north up
|
|
8
|
+
|
|
9
|
+
# Plan-level constants (visible inside components — plan scope is global).
|
|
10
|
+
let WALL = 200
|
|
11
|
+
let W = 4000 # unit width
|
|
12
|
+
let H = 5000 # unit depth
|
|
13
|
+
let DOOR = 900
|
|
14
|
+
let WIN = 1600
|
|
15
|
+
|
|
16
|
+
# One studio unit, positioned at x. Everything is derived from the constants.
|
|
17
|
+
component unit(x) {
|
|
18
|
+
wall exterior thickness WALL { (x, 0) (x + W, 0) (x + W, H) (x, H) close }
|
|
19
|
+
room at (x, 0) size W x H label "Studio"
|
|
20
|
+
furniture bed at (x + 300, 300) size 1500x2000 label "Bed"
|
|
21
|
+
furniture kitch at (x + W - 1900, 300) size 1600x600 label "Kitchen"
|
|
22
|
+
door at (x + W / 2, H) width DOOR wall exterior hinge left swing in
|
|
23
|
+
window at (x + W / 2, 0) width WIN wall exterior
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
unit(0)
|
|
27
|
+
unit(W)
|
|
28
|
+
unit(W * 2)
|
|
29
|
+
|
|
30
|
+
dim (0,0)->(W * 3, 0) offset 700 text "3 units"
|
|
31
|
+
}
|
package/package.json
CHANGED