# -*- coding: utf-8 -*- """수식 변수 정의 영역(PLAN 800-2 · 요구 660-2 · 3 · 6) — 수식 나무 → 오른쪽 「변수 정의」 목록. 줄 구분 없이 한 목록 · 같은 변수는 한 번만(겹침 합침) · 기호 : 국문 이름 — 연결(입력 · 표 찾기 · 요소 · 로직 · 계산을 사람 말로) · 값 · 단위 · DB 열쇠 글은 담지 않음. 지금 고른 옵션 갈래만 — 만약의 탄 갈래 표지 `걸림`(1 참 · 2 거짓 · 0 모름 = 둘 다)을 그대로 씀(새 판정 없음) · `안씀` = 어느 식에도 안 쓰이는 입력(지울 수 있음) · 쓰는 변수 지움 막기는 `master_equation_edit._drop`. """ from __future__ import annotations CAT = {"LB": "인력", "EQ": "기계", "MT": "재료", "MO": "재료"} WHAT = { "입력": "입력", "중간": "계산", "결과": "계산 결과", "찾기": "표 찾기", "요소": "요소", "블록": "로직 부르기", } def visible(node: dict | None, out: list[dict]) -> list[dict]: """나무에서 보이는(탄 갈래) 변수 · 블록 마디를 차례대로.""" if not isinstance(node, dict): return out kind = node.get("꼴") if kind in ("변수", "블록"): out.append(node) elif kind == "조건": visible(node.get("조건"), out) for key, at in (("참", 1), ("거짓", 2)): if node.get("걸림") in (0, None, at): visible(node.get(key), out) else: for key in ("좌", "우", "안", "위", "아래"): visible(node.get(key), out) for arg in node.get("인자") or []: visible(arg, out) return out def _link(node: dict, spec: dict | None, leaf: dict | None) -> str: """연결 설명 — 사람 말(열쇠 · 값 · 단위 없음).""" kind = node.get("갈래") or ("블록" if node.get("꼴") == "블록" else "") if kind == "입력": return "입력 — " + ("옵션에서 고름" if (spec or {}).get("고르기") else "직접 적음") if kind == "중간" and leaf is not None and leaf is not node: return _link(leaf, None, None) if kind == "상수": return f"상수 — {node.get('글')}" if kind == "찾기": cond = " · ".join(f"{k} = {v}" for k, v in (node.get("조건식") or {}).items()) head = f"표 찾기 — {node.get('표이름') or '표'}" return head + (f" · 조건 {cond}" if cond else "") + f" · 칸 {node.get('칸') or ''}".rstrip() if kind == "요소": pick = node.get("고르기") if isinstance(pick, dict): return "요소 · 재료 고름 — " + " · ".join(str(v) for v in pick.values() if v) return f"요소 · {CAT.get(str(node.get('식') or '')[:2], '단가')} — {node.get('이름') or ''}" if kind == "블록": return f"로직 부르기 — {node.get('이름') or ''}" return WHAT.get(kind, "계산") + (" — 수식 영역의 식" if kind in ("중간", "결과") else "") def definitions(lines: list[dict], row: dict, rows: list[dict], unused) -> list[dict]: """보이는 식의 변수 정의 목록 — `rows` = 변수 표 · `unused(열쇠)` = 어느 식에도 안 쓰임.""" specs = {str(s.get("이름")): s for k in ("입력", "중간") for s in row.get(k) or []} table = {v["열쇠"]: v for v in rows} got: dict[str, dict] = {} leaf: dict[str, dict] = {} for line in lines: head, tree = line.get("결과"), line.get("이름식") if line.get("갈래") in ("중간", "결과") and isinstance(tree, dict): if tree.get("꼴") == "수": # 상수 — 연결 설명에 그 수 leaf[str(line.get("열쇠"))] = {"갈래": "상수", "글": tree.get("글")} elif tree.get("갈래") in ("찾기", "요소") or tree.get("꼴") == "블록": # 한 마디 식 leaf[str(line.get("열쇠"))] = tree found = ([head] if head and line.get("갈래") in ("중간", "결과") else []) + visible( tree, [] ) for node in found: key = str(node.get("열쇠") or "") if key and key not in got and node.get("갈래") in (*WHAT, "합", None): got[key] = node out: dict[tuple, dict] = {} # 같은 기호 글 = 같은 정의(겹침 합침) — 연결은 모아 보임 for key, node in got.items(): mine = table.get(key) look = mine or node kind = node.get("갈래") or "블록" if kind == "합": kind = "결과" if key == "결과" else "중간" if key.startswith("줄."): # 위 호표 줄 금액 부름 name, link = key[2:].strip("'"), f"호표 줄 금액 — {key[2:].strip(chr(39))}" else: link = _link({**node, "갈래": kind}, specs.get(key), leaf.get(key)) if kind == "블록" and not leaf.get(key): link = "로직 부르기" # 이름이 곧 그 로직 — 되풀이 안 함 name = (look.get("이름") or key) if mine else look.get("이름") or "" name = node.get("칸") or name if kind == "찾기" else name one = { "열쇠": key if mine else "", "기호": look.get("기호") or name, # 줄 참조도 씌운 기호(master_symbol 한 곳) "위": look.get("위") or "", "아래": look.get("아래") or "", "이름": name, "갈래": kind, "연결": [link], "고침": bool(mine), } same = out.setdefault((one["기호"], one["위"], one["아래"]), one) if same is not one: same["연결"] += [x for x in one["연결"] if x not in same["연결"]] if one["열쇠"] and not same["열쇠"]: same |= {k: one[k] for k in ("열쇠", "이름", "갈래", "고침")} out = list(out.values()) seen = {d["열쇠"] for d in out} for v in rows: # 어느 식에도 안 쓰이는 입력 — 지울 수 있게 if v["갈래"] == "입력" and v["열쇠"] not in seen and unused(v["열쇠"]): out.append( { "열쇠": v["열쇠"], "기호": v["기호"], "위": v["위"], "아래": v["아래"], "이름": v["이름"], "갈래": "입력", "연결": ["입력 — 쓰는 식 없음"], "고침": True, "안씀": True, } ) return out