Repository navigation
Conversation
…cht#370) The number regexes accepted an optional leading minus anywhere, so in `1-1` or `a-1` the minus was consumed by the second number and the binary operator was lost (`1`, `-1` instead of `1`, `-`, `1`). As a result `select a-1 from foo` was not grouped as an Operation. A leading minus now only belongs to the number if it doesn't directly follow a name, number, closing bracket or quoted string/name. Unary minus after an operator, punctuation or whitespace (`x = -1`, `values(-1)`, `a -1`) is lexed as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #370.
The bug
The lexer let any number start with a
-, so in a subtraction written without spaces the minus was swallowed by the right-hand number and the operator disappeared:So
select a-1 from foowas grouped asIdentifier 'a'followed by a loose-1token instead of anOperation.a - 1with spaces was fine. Hex (x-0x1F) and float (a-1.5,a-.5,a-1e3) literals behaved the same way. This still reproduces on currentmaster.The fix
The leading minus in the hex, float and integer regexes is now only taken when it doesn't directly follow an operand. That means a word character (name, number, keyword),
),], or a closing quote (',",`). The lexer calls the compiled patterns withmatch(text, pos), so the lookbehind sees the preceding character, as the existing(?<!\w)[$:?]\w+and(?<![\w\])])(\[...\])rules already rely on.Unary minus is lexed exactly as before wherever it follows an operator, punctuation or whitespace:
x = -1,values(-1),in (1,-2),a*-1,select -1, and the ambiguousa -1all still give anInteger '-1'. TheE-?exponent sign is untouched.Notes
-now a separate token,format(..., reindent=True)aligns the next column aftera-1correctly.select a-1, b from tused to indentbone column too far.select-1,then-1) now lexes as keyword,-,1instead of keyword,-1, since a lookbehind can't tell keywords from names. Formatting output for those statements is unchanged. This is consistent with howselect - 1is already lexed.Tests
test_tokenize_minus_after_operand(parametrized over integer, float, exponent, hex, function call, array subscript and the three quoting styles). The1-1case is the test from the issue.test_operation_minus_without_whitespace:select a-1 from foogroupsa-1as anOperation.masterand pass with this change. Full suite: 518 passed, 2 xfailed, 1 xpassed (the xfail/xpass set is the same as onmaster).ruff check sqlparse/is clean.pytest)ruff)🤖 Generated with Claude Code