AND/OR/NOT, Fehler-Literale und Zeilen/Spalten einfügen/löschen

- AND(...)/OR(...)/NOT(...) als gewöhnliche Funktionen (kein Kurzschluss-
  Sonderfall wie IF/XLOOKUP nötig, werten wie in echtem Excel alle
  Argumente eager aus). Dabei die bisher dreifach duplizierte
  Wahrheits-Prüfung zu functions.ts#isTruthy() zusammengezogen, jetzt
  von FUNCTIONS.IF, evalIf() und dem Block-IF-Statement gemeinsam genutzt.
  Schließt "kein AND/OR für zusammengesetzte Bedingungen" aus den
  Bekannten Grenzen, auch nutzbar in "Mit Schleife"-IF-Bedingungen.

- Neue Grammatik-Ergänzung: ErrorLiteralNode. Jeder der sieben Fehlercodes
  (#REF, #DIV/0!, #NAME?, #ERR, #CIRC, #VALUE!, #N/A) lässt sich jetzt
  direkt in eine Formel tippen (=IF(A1=0;#N/A;A1)) und wertet unbedingt zu
  genau diesem Fehler aus.

- Zeilen/Spalten einfügen/löschen mitten im Gitter (Rechtsklick auf einen
  Zeilen-/Spaltenkopf), nicht nur am Rand wie bisher: Zellinhalte, Formate
  und Zeilenhöhen/Spaltenbreiten verschieben sich innerhalb der Tabelle,
  und jede Formel im gesamten Dokument, die die Tabelle referenziert (auch
  über Tabelle!Zelle/Blatt!Tabelle::Zelle-Qualifier aus anderen Tabellen),
  wird automatisch mitgezogen. Ein Bereich, der die Stelle überspannt,
  wächst/schrumpft entsprechend; eine Referenz, die exakt die gelöschte
  Zeile/Spalte trifft, wird zu einem echten #REF-Literal im Formeltext
  (nutzt die neue ErrorLiteralNode-Grammatik). $-Sperren bleiben dabei
  bewusst wirkungslos (anders als beim Kopieren), unveränderte Referenzen
  bleiben byte-identisch. Token-Level-Splice wie shiftFormula (Kopieren/
  Ausschneiden), keine AST-Neuserialisierung.

406 Tests, vue-tsc/eslint/build sauber, Playwright-live-verifiziert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
wkh
2026-09-08 22:34:33 +02:00
co-authored by Claude Sonnet 5
parent 2c54537427
commit aef8f1349c
14 changed files with 937 additions and 22 deletions
+2
View File
@@ -91,6 +91,7 @@ function expand(
switch (node.kind) {
case 'number':
case 'string':
case 'errorliteral':
case 'cell':
case 'range':
case 'namedref':
@@ -179,6 +180,7 @@ export function substitute(node: Node, bound: ReadonlyMap<string, Node>): Node {
return bound.get(node.name.toUpperCase()) ?? node;
case 'number':
case 'string':
case 'errorliteral':
case 'cell':
case 'range':
case 'namedref':