fix(spreadsheet): 함수 인자 수를 입력 때 막음 — =SUM() 이 0 이 되던 흠

- 파서가 함수 표(B) 최소 · 최대 인자 수로 검사 → 「SUM 인수가 너무 적음(1 개부터)」 식 오류(편집기가 이 실패로 Enter 를 막는 이음은 sub7)
- B 표 min 0 인 SUM · MIN · MAX · COUNT · COUNTA · PRODUCT 는 엑셀대로 1 로 덧댐(sub5 가 표를 고치면 지움)
- 풀이 때 인자 수 검사는 파서로 옮겨 뺌(엔진 31,787 → 31,603 B)
- 시험: 엔진 오류 묶음에 인자 수 사례

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TULoa94ZFL26KU6ZqVpjkF
This commit is contained in:
2026-09-27 22:21:59 +09:00
co-authored by Claude Opus 5.5
parent a144d4019e
commit a3434e3c74
3 changed files with 30 additions and 10 deletions
+22 -2
View File
@@ -9,6 +9,7 @@
import { parseDecimal, ZERO } from "@ui/sheet/ui_template_sheet_frac";
import { colIndex, colName, quoteSheet, rowIndex } from "./spreadsheet_address";
import { getFunction } from "./spreadsheet_functions";
import { MAX_COLS, MAX_ROWS } from "./spreadsheet_types";
import type { ErrorCode, FormulaNode, ParseResult, RefCell, Token } from "./spreadsheet_types";
@@ -151,6 +152,15 @@ class Fail {
}
const COMPARE = ["=", "<>", "<", "<=", ">", ">="];
// ponytail: B 함수 표 min 이 엑셀보다 낮은 것만 덧댐 — sub5 가 표를 고치면 지움
const EXCEL_MIN: Record<string, number> = {
SUM: 1,
MIN: 1,
MAX: 1,
COUNT: 1,
COUNTA: 1,
PRODUCT: 1,
};
/** 앞 `=` 뺀 식 글 → 나무. 앞에 `=` 가 붙어 와도 됨. 함수 이름은 대문자로. */
export function parseFormula(formula: string): ParseResult {
@@ -199,9 +209,19 @@ export function parseFormula(formula: string): ParseResult {
const name = t.text.toUpperCase().replace(/^_XLFN\./, "");
p++; // `(`
const args: FormulaNode[] = [];
// 인자 수는 엑셀처럼 입력 때 막음(편집기가 이 실패로 Enter 를 막음) · 모르는 함수는 풀 때 #NAME?
const done = (): FormulaNode => {
const fn = getFunction(name);
const lo = Math.max(fn?.min ?? 0, EXCEL_MIN[name] ?? 0);
if (fn && args.length < lo)
throw new Fail(`${name} 인수가 너무 적음(${lo} 개부터)`, t.start);
if (fn?.max !== undefined && args.length > fn.max)
throw new Fail(`${name} 인수가 너무 많음(${fn.max} 개까지)`, t.start);
return { type: "call", name, args };
};
if (peek()?.text === ")") {
p++;
return { type: "call", name, args };
return done();
}
for (;;) {
const k = peek();
@@ -211,7 +231,7 @@ export function parseFormula(formula: string): ParseResult {
else args.push(compare());
const s = toks[p++];
if (s?.kind === "comma") continue;
if (s?.text === ")") return { type: "call", name, args };
if (s?.text === ")") return done();
throw new Fail("함수 괄호가 안 닫힘", s ? s.start : text.length);
}
}