# -*- coding: utf-8 -*- """수식 마디 기호 다듬기(PLAN 801-1 · 801-2 · 요구 662-4) — 기호 씌운(`master_symbol.apply`) 뒤 · 정의 영역 앞. 보이기만 — 셈 · 엔진 열쇠 · 식(`식` 칸) 안 바꿈. - 한 마디 줄: 중간 · 결과 줄 식이 표 찾기 · 요소 · 로직 부르기 한 마디뿐이면 그 마디 = 줄 기호 · 줄 `한마디` (화면은 「q = 0.7」 — 표 칸 글 「적용」 · 로직 이름은 정의 영역에만). - 로직 부르기 마디 = 기호(부른 로직 결과 기호 + 아래 = 로직 이름 앞말) — 이름은 정의 영역 · 펼침 머리. - 뜻 없는 표 칸 글(`PLAIN` — 적용 · 값 · 기준)로 지은 표 찾기 기호 = 그 행 조건 값(없으면 표 이름)으로. - 한 로직 안 겹침 = 아래첨자 끝 숫자(`master_symbol.apply` 와 같은 꼴). """ from __future__ import annotations import master_symbol as msym PLAIN = {"적용", "값", "기준"} LEAF = ("찾기", "요소") def _sign(n: dict) -> str: return f"{n.get('기호') or ''}_{n.get('아래') or ''}^{n.get('위') or ''}" def _nodes(tree, out: list[dict]) -> list[dict]: """변수 · 블록 마디(블록 속 나무는 따로 다듬음 — 안 들어감).""" if isinstance(tree, list): for one in tree: _nodes(one, out) elif isinstance(tree, dict): if tree.get("꼴") in ("변수", "블록"): out.append(tree) for k, v in tree.items(): if k != "나무" and isinstance(v, (dict, list)): _nodes(v, out) return out def lone(line: dict) -> bool: """줄 식이 표 찾기 · 요소 · 로직 부르기 한 마디뿐인 중간 · 결과 줄.""" tree = line.get("이름식") or {} one = tree.get("꼴") == "블록" or (tree.get("꼴") == "변수" and tree.get("갈래") in LEAF) return line.get("갈래") in ("중간", "결과") and one and isinstance(line.get("결과"), dict) def _block_sign(node: dict) -> tuple[str, str, str]: sub = node.get("나무") or {} last = next((x for x in reversed(sub.get("줄") or []) if x.get("갈래") == "결과"), None) head = (last or {}).get("결과") or {} sign = head.get("기호") if msym.is_symbol(str(head.get("기호") or "")) else "" sign = sign or msym.rule(str(node.get("결과단위") or ""), "결과")[0] return sign, msym.short(str(node.get("이름") or node.get("열쇠") or "")), "" def _find_sign(node: dict) -> tuple[str, str, str]: said = [str(v) for v in (node.get("행") or {}).values() if isinstance(v, str) and v] name = said[-1] if said else str(node.get("표이름") or "") node["칸글"] = True # 정의 이름 = 표 · 조건 값(칸 글 아님) node["이름"] = " ".join(x for x in (str(node.get("표이름") or ""), *said[-1:]) if x) if msym.is_symbol(name): return name, "", "표" sign, low, _ = msym.lookup(name, "찾기") return sign, low, "표" def settle(out: dict) -> dict: """내보낸 수식 한 벌(한 깊이) 다듬기 — 제자리 고침 · 같은 것 돌려줌.""" lines = out.get("줄") or [] for line in lines: if lone(line): line["한마디"] = True head = line["결과"] line["이름식"] |= {k: head.get(k) or "" for k in ("기호", "아래", "위")} nodes = _nodes(lines, []) heads = [x["결과"] for x in lines if isinstance(x.get("결과"), dict)] used = {_sign(n) for n in [*nodes, *heads, *(out.get("변수표") or [])]} done: dict[str, tuple[str, str, str]] = {} for line in lines: skip = line["이름식"] if line.get("한마디") else None for node in _nodes(line.get("이름식"), []): if node is skip: continue if node.get("꼴") == "블록": want = _block_sign elif node.get("갈래") == "찾기" and node.get("칸") in PLAIN: want = _find_sign else: continue key = str(node.get("식") or node.get("열쇠")) if key not in done: used.discard(_sign(node)) sign, low, up = want(node) n, base = 1, low while _sign({"기호": sign, "아래": low, "위": up}) in used: n += 1 low = base[: msym.SUBMAX - len(str(n))] + str(n) used.add(_sign({"기호": sign, "아래": low, "위": up})) done[key] = (sign, low, up) node["기호"], node["아래"], node["위"] = done[key] return out