Skip to content

Quote a sheet name that reads as a boolean literal - #53

Draft
gthb wants to merge 3 commits into
borgar:masterfrom
gthb:quote-boolean-sheet-names
Draft

Quote a sheet name that reads as a boolean literal#53
gthb wants to merge 3 commits into
borgar:masterfrom
gthb:quote-boolean-sheet-names

Conversation

@gthb

@gthb gthb commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

What

Fix a formula normalization that turns a safe formula into one Excel will not open. A sheet name spelled as a logical literal loses the quotes it needs:

fixFormulaRanges("=SUM('TRUE'!A1)")   →  =SUM(TRUE!A1)
fixFormulaRanges("=SUM('FALSE'!A1)")  →  =SUM(FALSE!A1)

That is a round-trip loss inside the library: tokenize reads =SUM(TRUE!A1) as bool:TRUE, operator:!, range:A1, never as a sheet prefix, so the normalized formula no longer refers to the sheet the input did. Measured in Excel it is worse than misread — a workbook containing the unquoted spelling does not open at all, with no repair prompt and no repair log, exactly as one containing an unquoted $ in a sheet name does not.

Every serializer that qualifies a reference with a sheet name is affected, since all reach the same needQuotes call: fixFormulaRanges in both default and xlsx mode, the round trip back from R1C1, stringifyA1Ref for a range and for a defined-name qualifier, and stringifyStructRef.

Cause

needQuotes quotes a scope that contains a banned character, reads as an A1 or R1C1 range, or starts with a digit — each a spelling the lexer resolves ahead of a name. A logical literal is resolved ahead of a name in the same leading position, and no rule covered it. Only that position is at risk: =SUM([TRUE]Sheet1!A1) lexes back as a single range token, and Truer is one name.

Fix

Add reIsBoolean beside the existing reIsRangelike, and quote a scope matching it. It mirrors lexBoolean, which recognises TRUE and FALSE case-insensitively and nothing else — fx models no localized formula literals, so those two words are the whole set.

Deliberate over-quoting

needQuotes sees every scope in every position, so the clause also quotes one that is not leading and therefore not at risk: a workbook or path scope of that name, or a sheet scope behind a workbook scope. The digit-leading and range-like rules already do the same, quoting '[1040.xlsx]Sheet1'!A1 on a workbook name alone and '[Foo]Ab12'!B2 on a sheet name that is not leading either. Matching them keeps one rule per hazardous spelling rather than one per spelling and position, at the cost of quotes that are redundant rather than wrong. The XLSX test pins '[TRUE]'!A1, so the choice is recorded rather than inferred.

Relation to the other branches

#51 contains this fix among unrelated sheet-range work and drops it once this lands — the same arrangement as #52.

gthb added 3 commits August 1, 2026 02:28
Normalizing a formula dropped the quotes from 'TRUE'!A1 and 'FALSE'!A1,
emitting a spelling the library's own lexer reads back as a boolean joined
to a reference rather than as a sheet prefix, and one Excel will not open.

needQuotes now treats TRUE and FALSE like the digit-leading and range-like
names it already quotes.
The new quoting rule was covered only through stringifyA1Ref. The symptom
that prompted it is a whole-formula normalization, so pin it where the other
prefix-quoting rules are pinned, alongside the range-like and digit-leading
cases.
Four of the assertions in the two new blocks are unmoved by the rule and
document neighbouring behaviour instead; group them under one comment that
says so, in place of comments that named only some of them. Name the XLSX
block for the workbook case it also covers.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant