Text-Vergleich, &-Verkettung und benannte Bereiche
- Vergleichsoperatoren (= <> > < >= <=) unterscheiden jetzt Text- von Zahlenvergleich statt jede Seite zwangsweise durch toNumber() zu schicken (=A1="Nord" gab vorher #VALUE! statt 1); ermöglicht Text-Kriterien in selbstgebauten COUNTIF/SUMIF/AVERAGEIF-Funktionen (neue README-Sektion "SUMIF/COUNTIF/AVERAGEIF nachbauen"). - Neuer &-Operator (Excel-Präzedenz zwischen Vergleich und +/-) plus CONCAT/CONCATENATE als Funktions-Äquivalent. - Benannte Bereiche: neuer Toolbar-Button "🏷" verwaltet dokumentweite Namen für eine feste Zelle/einen festen Bereich (z. B. Umsatz_Q1statt Umsatz!B2:B6), unqualifiziert in jeder Top-Level-Formel nutzbar. Live gegen die Tabellen-ID aufgelöst (übersteht Tabellen-Umbenennung), bewusst nicht innerhalb einer benutzerdefinierten Funktion selbst nutzbar (Aufrufer können sie aber als Argument übergeben). - Nebenbei: COUNT2s Autovervollständigungs-Hint korrigiert (zeigte "COUNT(...)" statt "COUNT2(...)"). 374 Tests, vue-tsc/eslint/build sauber, Playwright-live-verifiziert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -93,6 +93,7 @@ function expand(
|
||||
case 'string':
|
||||
case 'cell':
|
||||
case 'range':
|
||||
case 'namedref':
|
||||
case 'param':
|
||||
case 'omitted':
|
||||
return node; // leaves -- nothing to expand
|
||||
@@ -180,6 +181,7 @@ export function substitute(node: Node, bound: ReadonlyMap<string, Node>): Node {
|
||||
case 'string':
|
||||
case 'cell':
|
||||
case 'range':
|
||||
case 'namedref':
|
||||
case 'omitted':
|
||||
return node;
|
||||
case 'unary':
|
||||
@@ -293,16 +295,22 @@ export function declaredBlockNames(block: BlockNode, out: string[] = []): string
|
||||
|
||||
/** The first FOR loop, anywhere in the block (including nested inside
|
||||
* another FOR/IF), whose source isn't (syntactically) a parameter, a
|
||||
* single cell, or a range -- i.e. can never resolve to a concrete list of
|
||||
* cells no matter what the caller passes. Checked at save time so this is
|
||||
* caught immediately, not just on the first real call; the evaluator's
|
||||
* single cell, a range, or a named-range reference -- i.e. can never
|
||||
* resolve to a concrete list of cells no matter what the caller passes.
|
||||
* Checked at save time so this is caught immediately, not just on the
|
||||
* first real call; the evaluator's
|
||||
* interpreter re-checks the same thing on the *substituted* source at call
|
||||
* time regardless (needed either way, since a parameter's shape isn't
|
||||
* known until then) as the actual enforcement. */
|
||||
export function findInvalidForSource(block: BlockNode): ForNode | null {
|
||||
for (const stmt of block.statements) {
|
||||
if (stmt.kind === 'for') {
|
||||
if (stmt.source.kind !== 'param' && stmt.source.kind !== 'cell' && stmt.source.kind !== 'range') {
|
||||
if (
|
||||
stmt.source.kind !== 'param' &&
|
||||
stmt.source.kind !== 'cell' &&
|
||||
stmt.source.kind !== 'range' &&
|
||||
stmt.source.kind !== 'namedref'
|
||||
) {
|
||||
return stmt;
|
||||
}
|
||||
const nested = findInvalidForSource(stmt.body);
|
||||
|
||||
Reference in New Issue
Block a user