feat(800-2): 수식 변수 정의 영역 서버 — 정의 칸(안 탄 갈래 뺌 · 겹침 합침 · 열쇠 글 0) · 새 기호 연결 고침 · 후보 길

- 수식 응답 새 칸 정의 — 만약 탄 갈래 표지 걸림 그대로 · 같은 기호 한 줄 · 연결 사람 말 · 값 · 단위 · DB 열쇠 없음
- 고침 할일 연결(입력 · 표 · 요소 · 로직 · 상수) · 모르는 기호 까닭 · 후보 길 M01 · M02 equation/links
- 낡은 시험 test_796_1 「모르는 이름」 → 「모르는 기호」(까닭 문구 바뀜)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-07 16:46:39 +09:00
co-authored by Claude Sonnet 5.5
parent 972002417a
commit a262b43e83
10 changed files with 448 additions and 1 deletions
@@ -10,6 +10,7 @@
{할일: 지움, 열쇠} — 쓰는 식이 있으면 막고 쓰는 곳 목록
{할일: 변수, 열쇠, 이름?, 기호?, 위?, 아래?, 단위?} — 식은 열쇠로 부르니 안 깨짐
{할일: 표시, 열쇠, 표시: 0~6 | null}
{할일: 연결, 열쇠, 갈래: 입력|표|요소|로직|상수, …} — 새 기호의 연결 지정(`master_equation_link.py` 머리)
고친 중간 줄은 `표시` 없으면 `SHOW`(보이는 자리에서 잘라 셈 · 요구 658) — 고치지 않은 줄은 그대로.
키보드 한 줄 식 = 변수 글(기호_아래^위 · 이름 · 열쇠) · `× ÷ −` · 나머지는 엔진 식 말 그대로
(`[노임 …]` · `[별칭]` 은 M01 · M02 층이 `M02_Sangeun_Formula.to_engine` 으로 먼저 풂).
@@ -22,6 +23,7 @@ import re
from decimal import Decimal, InvalidOperation
import master_equation as meq
import master_equation_link as link
import master_formula as mf
KEY_FORM = re.compile(r"^[^\W\d][\w]{0,19}$") # 열쇠 = 글자로 시작 · 20 자까지
@@ -227,12 +229,39 @@ def _text_of(ed: dict, row: dict, words) -> tuple[str, list[str]]:
return words(text, row) if words and text else (text, [])
def unknown(text: str, row: dict) -> list[str]:
"""엔진 식 글 안 모르는 변수 글(변수 · 열쇠 · 예약어 · 함수 · 칸 · 인자 이름 · 요소 키 빼고)."""
known = set(_names(row)[0]) | _all_keys(row) | RESERVED
out, at = [], 0
while at < len(text):
if text[at] in "'[":
end = text.find("'" if text[at] == "'" else "]", at + 1)
at = len(text) if end < 0 else end + 1
continue
m = None if at and text[at - 1].isalnum() else _TOKEN.match(text, at)
if not m:
at += 1
continue
word, before, rest = m.group(), text[:at].rstrip(), text[m.end() :].lstrip()
at = m.end()
arg = rest.startswith("=") and not rest.startswith("==")
skip = before.endswith(".") or rest.startswith("(") or arg
if not (skip or word in known or mf.mk.KEY.fullmatch(word) or word in out):
out.append(word)
return out
def _set_formula(row: dict, ed: dict, why: list, spots: set, words=None) -> None:
spot = str(ed.get("자리") or "")
text, bad = _text_of(ed, row, words)
if bad:
why += [f"{spot} · {w}" for w in bad]
return
if not isinstance(ed.get("나무"), dict) and (miss := unknown(text, row)):
why.append(
f"{spot} · 모르는 기호 「{'」 「'.join(miss)}」 — 변수 정의 영역에서 연결을 지정"
)
return
if not text:
why.append(f"{spot} · 식이 빔")
return
@@ -383,6 +412,9 @@ def apply(master, row: dict, edits: list, words=None) -> tuple[dict, list[str],
_look(new, key, ed, why)
elif job == "표시":
_show(new, key, ed, why)
elif job == "연결":
add, bad = link.plan(master, ed)
_add(new, add, why, spots, words) if add else why.append(bad)
else:
why.append(f"모르는 할일 「{job}」")
except (mf.FormulaError, KeyError, TypeError, ValueError) as e: