XLOOKUP als Formel, plus überspringbare optionale Argumente (;;)
Neue eingebaute Funktion XLOOKUP(Suchwert; Suchbereich; Rückgabebereich; [WennNichtGefunden]; [Vergleichsmodus]; [Suchmodus]). - Grammatik-Erweiterung (allgemein, nicht XLOOKUP-spezifisch): eine leere Argumentstelle zwischen zwei ";" (oder vor der schließenden ")") parst jetzt als neuer OmittedNode statt eines Parse-Fehlers -- Excels "dieses optionale Argument auslassen"-Idiom, z. B. XLOOKUP(x;a;b;;-1). Wertet überall wie eine leere Zelle aus (null); expand()/substitute() (userFunctions.ts) behandeln ihn als Blatt, collectRefs() ignoriert ihn stillschweigend. - evaluator.ts: XLOOKUP wird -- wie IF -- vor dem generischen eager/ flatten-Dispatch abgefangen (evalXLookup()), aus zwei Gründen: (1) WennNichtGefunden muss lazy ausgewertet werden (Kurzschluss wie bei IF), (2) Suchbereich/Rückgabebereich dürfen nicht in eine gemeinsame flache Werteliste geraten -- der generische Pfad würde die Grenze zwischen beiden Bereichen zerstören. Eigene xlookupEquals() (case-insensitiv/getrimmt für Text, kein Zahl-Text-Crossmatch) statt des `=`-Operators, der über toNumber() koerziert und nie auf Text träfe. Vergleichsmodus -1/1 (exakt/nächstkleiner/-größer, numerisch), Suchmodus 1/-1 (Richtung); Excels Platzhalter- und Binärsuch-Modi bewusst nicht unterstützt. - functions.ts: Platzhalter-Eintrag für Namensreservierung (analog IF). - types.ts: neuer Fehlercode #N/A (kein Treffer, kein WennNichtGefunden) -- dokumentierte Erweiterung, wie zuvor #VALUE!. - collectRefs() brauchte keine Änderung -- sein generischer case 'func' läuft schon konservativ durch alle Argumente. Tests: 22 neue (parser.spec.ts: OmittedNode leading/middle/trailing; evaluator.spec.ts: SUM(1;;3)-Smoke plus 15 XLOOKUP-Fälle; workbook.spec.ts: Neuberechnung bei Änderung in Such- ODER Rückgabebereich, keine bei unbeteiligten Zellen; document.spec.ts: Namenskollision). 298 -> 318 Tests, alle grün. vue-tsc/eslint/build sauber. Live per Playwright verifiziert (Treffer, #N/A, WennNichtGefunden, Kurzschluss-Beweis, übersprungenes Argument für Vergleichsmodus, Neuberechnung nach Umbenennen einer Suchbereich-Zelle inkl. nachträglich ausgelöstem #DIV/0! im vorher nicht ausgewerteten WennNichtGefunden-Zweig). READMEs aktualisiert (Funktionen, Fehlermodell, neue Abschnitte "Leere Argumentstelle" und "Nachschlagen (XLOOKUP)" in engine/README.md, Bekannte Grenzen, Testzahl; EBNF-Grammatik in parser.ts kommentiert). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -115,6 +115,25 @@ export const FUNCTIONS: Record<string, FunctionFn> = {
|
||||
if (values.length !== 0) return new FormulaError('#ERR', 'NOW erwartet keine Argumente');
|
||||
return nowSerial();
|
||||
},
|
||||
|
||||
// XLOOKUP(Suchwert; Suchbereich; Rückgabebereich; [WennNichtGefunden];
|
||||
// [Vergleichsmodus]; [Suchmodus]) -- like IF, evaluator.ts special-cases
|
||||
// this name *before* ever reaching FUNCTIONS. Two reasons, not just one:
|
||||
// 1. WennNichtGefunden must only be evaluated when actually needed
|
||||
// (short-circuit, same reasoning as IF's branches).
|
||||
// 2. By the time a function gets here, EVERY argument -- including
|
||||
// Suchbereich and Rückgabebereich, both ranges -- has already been
|
||||
// flattened into ONE combined array (see the module comment above).
|
||||
// That destroys the boundary between the two ranges, so there is no
|
||||
// way to even attempt a best-effort fallback here: unlike IF's
|
||||
// 2-3 scalar arguments, XLOOKUP's array arguments can't be recovered
|
||||
// from a flat `values` list of unknown split point. This entry exists
|
||||
// purely so XLOOKUP is a registered built-in (hasFunction() /
|
||||
// name-reservation) -- see evaluator.ts's evalXLookup() for the real
|
||||
// implementation. Reaching this in practice would be an engine bug.
|
||||
XLOOKUP() {
|
||||
return new FormulaError('#ERR', 'XLOOKUP must be evaluated by evaluator.ts, not called directly');
|
||||
},
|
||||
};
|
||||
|
||||
// AVERAGE is an alias of AVG.
|
||||
|
||||
Reference in New Issue
Block a user