You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
A leading + sign is dropped from the number spelling before parse_int/parse_float/parse_constant see it #159
The parser accepts a leading + on numbers (per JSON5's [-+]? sign rule, and it was added for +Infinity in #63), but the sign is dropped from the number token before the parse_int / parse_float / parse_constant hooks see it — while a leading - is kept. A hook therefore cannot distinguish +NaN from NaN, or +Infinity from Infinity, and parse_int receives a spelling that differs from the document.
loads()'s docstring documents the hook contract as "a custom callback is passed the integer string as written", and the same "as written" wording is what #152/#157 established for parse_constant (-NaN arrives as -NaN). The + sign is the one place that contract currently breaks.
All the values are still right (json5.loads('+0xff') == 255), so nothing was obviously broken — it is only the spelling passed to the hooks that is wrong.
Root cause: in json5/json5.g:
num_literal = '-' unsigned_lit:n -> '-' + n
| '+' unsigned_lit:n -> n
| unsigned_lit:n -> n
The '+' alternative consumes the sign but returns n without it, unlike the '-' alternative. The generated json5/parser.py (_num_literal__c1_) does the same (self._succeed(self._get('n'))).
Two small knock-on checks if the sign is kept: _walk_ast in json5/lib.py strips only - before the hex-prefix test (unsigned = v[1:] if v.startswith('-') else v), so a +0xff token would fall through to the base-10 parse_int; and the default _parse_int helper only lstrips - before the hex test (s.lstrip('-').startswith(('0x', '0X'))). Both would need the + sign handled the same way - is.
Suggested fix: make the '+' rule return '+' + n, mirror that in the generated parser, and extend the two sign checks in lib.py. Existing value tests (check('+1', 1), check('+0xf', 15), check('+Infinity', inf)) keep passing; only the hook spellings change.
While I'm not sure this actually changes anything useful in practice, and it might actually break existing hooks that won't be expecting the '+', I agree it's probably the right change to make.
Activity
fix: keep a leading + sign in the number spelling
fix: keep a leading + sign in the number spelling
fix: keep a leading + sign in the number spelling
test: parse hooks receive the as-written + spellings
dpranke commentedon Nov 2, 2026
While I'm not sure this actually changes anything useful in practice, and it might actually break existing hooks that won't be expecting the '+', I agree it's probably the right change to make.
Let's try it and see if we get any complaints.