/* ============================================================================= * formula_doc_render.ts * 수식 문서 닿는 기호(PLAN 802-3 · 804-6) — 줄 쌓기 산출근거(`line_stack_out.ts`)가 씀 * reach = 지금 탄 갈래로 닿는 기호(만약 안 탄 갈래 · 숨김 자리 인자 빼고) * 옛 수식 문서 탭의 조판 그림(renderNode · 값 식 · 수 바꿈)은 804-6 에 걷음 * ========================================================================== */ import { linkNames, varId, type FormulaDoc, type Node, } from "../common_util/common_util_formula_doc"; import { offLine, takenOf, tryParse, type Values, } from "../common_util/common_util_formula_doc_view"; /** 탄 갈래로 부르는 이름(만약 안 탄 갈래 · 숨김 자리 인자 빼고) */ function namesTaken(n: Node, vals: Values, out: string[] = []): string[] { const add = (x: string): void => { if (!out.includes(x)) out.push(x); }; switch (n[0]) { case "var": add(n[1]); break; case "bin": namesTaken(n[2], vals, out); namesTaken(n[3], vals, out); break; case "neg": case "pct": case "field": namesTaken(n[1], vals, out); break; case "call": { const pick = takenOf(n, vals); const items = pick ? [n[2][0], n[2][pick]] : n[2]; items.forEach((x) => namesTaken(x, vals, out)); break; } } return out; } const RESERVED_MONEY = new Set(["노무비", "재료비", "경비", "번지", "단계"]); /** 정의 영역에 보일 기호 — 식 줄 · 금액 줄 · 결과에서 지금 탄 갈래로 닿는 것(보이는 차례) */ export function reach(doc: FormulaDoc, vals: Values, showOff = false): string[] { const vars = new Map((doc.변수 ?? []).map((v) => [varId(v), v])); const lines = new Map((doc.식 ?? []).map((l) => [String(l.기호 ?? ""), l.식])); const money = new Set((doc.금액 ?? []).map((l) => String(l.기호 ?? "")).filter(Boolean)); const out: string[] = []; const visit = (name: string): void => { if (!name || out.includes(name) || RESERVED_MONEY.has(name) || money.has(name)) return; out.push(name); if (lines.has(name)) { const n = tryParse(lines.get(name)); if (n) namesTaken(n, vals).forEach(visit); } const v = vars.get(name); if (v?.연결 && v.연결.갈래 !== "식") linkNames(v.연결).forEach(visit); }; const from = (text: unknown): void => { const n = tryParse(text); if (n) namesTaken(n, vals).forEach(visit); }; for (const l of doc.식 ?? []) { visit(String(l.기호 ?? "")); from(l.식); } for (const l of doc.금액 ?? []) { if (!showOff && offLine(l, vals, lines)) continue; from(l.수량); from(l.단가); } if (doc.결과) visit(String(doc.결과)); return out; }