feat(master_data): 건설품셈 공통 6장 로직 60개 — 철근콘크리트공사

- 로직_건설품셈_공통6장.json: 콘크리트 · 철근 · 거푸집 · PSC · 교량 가설·부대공 · 조립식 구조물
- 일당 편성 표 = 편성 ÷ 시공량 · 기계 1대 × 8시간 ÷ 시공량 · 공구손료는 인력품(작업조 노임)의 %
- 8장: 기계 고르기 더함 · 조종원직종 입력 로직 새로(고소작업차 — 원문 운전사 구분에 이름 없음)
- 재료_자체: 에폭시 접착제 · 폼타이 규격 · 강재거푸집 · 문양거푸집 · 원형맨홀거푸집 · 쉬즈관
- 식 엔진: 맞는 줄이 여럿이면 찾는 값 칸이 있는 줄만 · 괄호 든 칸 이름은 작은따옴표
- 막힘: 6-2-5(절단공 노임 요소 없음) · 6-3-6 해체(특수비계공 노임 요소 없음)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1MKKZKpUHTPKb513FneU8
This commit is contained in:
2026-09-19 17:42:08 +09:00
co-authored by Claude Opus 5
parent 380f1bcef7
commit c68e26e882
6 changed files with 5763 additions and 12 deletions
@@ -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)
@@ -267,7 +274,7 @@ def _match(table: dict, row: dict, cond: str, want) -> bool:
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}")
@@ -277,6 +284,8 @@ def find(table: dict, conds: dict) -> dict:
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]
@@ -298,7 +307,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]]