merge(master_data): dev 받기 · 공통8장 기계 고르기 · 재료_자체 손 병합
- 로직_건설품셈_공통8장: 양쪽 고르기 합침 - 재료_자체: 양쪽 줄 합침 · dev 쪽 겹친 열쇠 12개 한 줄로(비고 합침) - 로직_건설품셈_유지관리1장: 3-7-5 편성 칸 이름 크롤러드릴_공기식 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JgUhN55Z3BCYhUJTjwTNfj
This commit is contained in:
@@ -104,9 +104,16 @@ class _Parser:
|
||||
return ("neg", self.unary())
|
||||
node = self.primary()
|
||||
while self.take("."):
|
||||
node = ("field", node, self.name())
|
||||
node = ("field", node, self.quoted() if self.take("'") else self.name())
|
||||
return node
|
||||
|
||||
def quoted(self) -> str:
|
||||
end = self.s.find("'", self.i)
|
||||
if end < 0:
|
||||
self.fail("작은따옴표 안 닫힘")
|
||||
text, self.i = self.s[self.i : end], end + 1
|
||||
return text
|
||||
|
||||
def name(self) -> str:
|
||||
self.ws()
|
||||
m = _NAME.match(self.s, self.i)
|
||||
@@ -115,8 +122,9 @@ class _Parser:
|
||||
self.i = m.end()
|
||||
return m.group()
|
||||
|
||||
def ref(self) -> str:
|
||||
"""열쇠 글자 — 괄호 밖의 `,` · `)` · `.칸` · ` 연산자 ` 앞에서 멈춤(열쇠에 빈칸·괄호가 들어감)."""
|
||||
def ref(self, head: bool = False) -> str:
|
||||
"""열쇠 글자 — 괄호 밖의 `,` · `)` · `.칸` · ` 연산자 ` 앞에서 멈춤(열쇠에 빈칸·괄호가 들어감).
|
||||
head = 찾기·로직 머리 — `,` · `)` 에서만 멈춤(표 이름의 `P.P마대` 같은 점)."""
|
||||
start, depth = self.i, 0
|
||||
while self.i < len(self.s):
|
||||
ch = self.s[self.i]
|
||||
@@ -128,6 +136,8 @@ class _Parser:
|
||||
depth -= 1
|
||||
elif depth == 0 and ch == ",":
|
||||
break
|
||||
elif head:
|
||||
pass
|
||||
elif depth == 0 and ch == "." and not self.s[self.i + 1 : self.i + 2].isdigit():
|
||||
# 「K.P」「T.S」 처럼 영문자 사이 점은 열쇠 글자
|
||||
around = self.s[self.i - 1 : self.i + 2 : 2]
|
||||
@@ -141,7 +151,7 @@ class _Parser:
|
||||
def args(self) -> list[tuple[str, object]]:
|
||||
out = []
|
||||
while self.take(","):
|
||||
key = self.name()
|
||||
key = self.quoted() if self.take("'") else self.name()
|
||||
self.need("=")
|
||||
out.append((key, self.expr()))
|
||||
self.need(")")
|
||||
@@ -168,10 +178,10 @@ class _Parser:
|
||||
self.need("(")
|
||||
head = self.name()
|
||||
self.need(":")
|
||||
return ("find", f"{head}:{self.ref()}", self.args())
|
||||
return ("find", f"{head}:{self.ref(True)}", self.args())
|
||||
if word == "로직":
|
||||
self.need("(")
|
||||
return ("logic", self.ref(), self.args())
|
||||
return ("logic", self.ref(True), self.args())
|
||||
if word in FUNCS:
|
||||
self.need("(")
|
||||
items = [self.expr()]
|
||||
@@ -269,20 +279,24 @@ def _match(table: dict, row: dict, cond: str, want) -> bool:
|
||||
)
|
||||
if rule == "이하": # 칸마다 위 끝만 — 맞는 줄 가운데 위 끝이 가장 작은 줄(find)
|
||||
return (low is None or want > low) and (high is None or want <= high)
|
||||
if rule == "이상·이하": # 양 끝 포함 — 이웃 칸 끝이 겹치면 위 끝이 가장 작은 줄(find)
|
||||
return (low is None or want >= low) and (high is None or want <= high)
|
||||
raise FormulaError(f"모르는 범위규칙 「{table.get('범위규칙')}」")
|
||||
return have == want
|
||||
|
||||
|
||||
def find(table: dict, conds: dict) -> dict:
|
||||
def find(table: dict, conds: dict, want: str | None = None) -> dict:
|
||||
for cond in conds:
|
||||
if cond not in table.get("조건", {}):
|
||||
raise FormulaError(f"「{table['열쇠']}」 에 없는 조건 「{cond}」")
|
||||
hits = [row for row in table["줄"] if all(_match(table, row, c, v) for c, v in conds.items())]
|
||||
if len(hits) > 1 and table.get("범위규칙", "").split(" · ")[0] == "이하":
|
||||
if len(hits) > 1 and table.get("범위규칙", "").split(" · ")[0] in ("이하", "이상·이하"):
|
||||
for c in conds:
|
||||
ups = [r[c][1] for r in hits if table["조건"].get(c) == "범위" and r.get(c)]
|
||||
if ups and None not in ups:
|
||||
hits = [r for r in hits if not r.get(c) or r[c][1] == min(ups)]
|
||||
if len(hits) > 1 and want: # 여러 줄이면 찾는 값 칸이 있는 줄만
|
||||
hits = [row for row in hits if want in row]
|
||||
if len(hits) != 1:
|
||||
raise FormulaError(f"「{table['열쇠']}」 {conds} 맞는 줄 {len(hits)}개")
|
||||
return hits[0]
|
||||
@@ -304,7 +318,12 @@ def evaluate(node, env: dict, master: Master, depth: int = 0):
|
||||
raise FormulaError(f"「{node[1]}」 값이 범위 — 입력으로 받아야 함")
|
||||
return value
|
||||
if kind == "field":
|
||||
base = evaluate(node[1], env, master, depth)
|
||||
if node[1][0] == "find":
|
||||
table = master.get(fill(node[1][1], env))
|
||||
conds = {k: evaluate(v, env, master, depth) for k, v in node[1][2]}
|
||||
base = find(table, conds, node[2])
|
||||
else:
|
||||
base = evaluate(node[1], env, master, depth)
|
||||
if not isinstance(base, dict) or node[2] not in base:
|
||||
raise FormulaError(f"칸 「{node[2]}」 없음")
|
||||
value = base[node[2]]
|
||||
|
||||
Reference in New Issue
Block a user