Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow negative hexadecimal literals again #36

Closed
aseemk opened this issue Jan 27, 2013 · 7 comments
Closed

Allow negative hexadecimal literals again #36

aseemk opened this issue Jan 27, 2013 · 7 comments

Comments

@aseemk
Copy link
Member

aseemk commented Jan 27, 2013

I just hooked up Travis CI support, which is great for testing across multiple versions of Node, and indeed, one of our test cases fails on Node 0.9:

https://travis-ci.org/aseemk/json5/jobs/4405590

The test case is parsing -0xC8, a negative hexadecimal literal. I narrowed the problem down to these lines in the parser:

https://github.com/aseemk/json5/blob/v0.1.0/lib/json5.js#L154-L156

number = +string;
if (!isFinite(number)) {
    error("Bad number");

The problem is that converting the string -0xC8 to a number via the unary + operator used to work, but now returns NaN. This changed from Node 0.8 to 0.9.

I investigated, and indeed, this is a breaking change in V8, but a fix technically:

http://code.google.com/p/v8/issues/detail?id=2240

I'm not sure yet what this means for JSON5, but we have one failing test today on Node 0.9. We don't document that negative hexadecimal literals are supported anywhere, so I think we're fine there, and the parser correctly rejects them, but we should change the test. Not sure how to do this without causing test failures on Node 0.6 and 0.8.

/cc @MaxNanasy FYI =)

@ghost ghost assigned aseemk Jan 27, 2013
aseemk added a commit that referenced this issue Jan 27, 2013
Fixes issue #36:

#36

Negative hexadecimals will parse without throwing an error in ES5; they'll
just parse to NaN. So they're "well-formed" ES5, but invalid JSON5.
@aseemk
Copy link
Member Author

aseemk commented Jan 27, 2013

As commit 9cf34ad's message shows, I was able to test this easily since ES5 doesn't throw an error on negative hexadecimal literals -- it just evaluates them to NaN. Fixed.

@aseemk aseemk closed this as completed Jan 27, 2013
@aseemk
Copy link
Member Author

aseemk commented Jan 28, 2013

@rlidwka
Copy link
Contributor

rlidwka commented Dec 19, 2013

I don't entirely understand why signed hexadecimals are not valid.

This seem to work just fine for me:

> eval('(function(){"use strict";return -0xC8})()')
-200

@jordanbtucker
Copy link
Member

I wanted to open this back up for discussion, clarify some things, and see if we want to change this behavior.

TL;DR
This issue was originally a bug because of a change in V8. Instead of fixing the bug, the feature was removed even though the feature didn't really have anything to do with the V8 bug. It was the implementation of the feature that needed a fix.

Signed numbers vs numeric literals

Signed numbers, whether decimal or hexadecimal, are not treated as literals when parsed by ES5. They are parsed as two separate tokens: a Punctuator (+ or - in this case) and a NumericLiteral (an unsigned decimal or hexadecimal number).

That sequence produces a UnaryExpression using the + or - operators. In either case, the text of the NumericLiteral is converted to a number using ES5's ToNumber operation, and in the case of the - operator, the mathematical value is negated.

The discrepancy between signed decimals and signed hexadecimals occurs within the ToNumber(String) operation. It allows signed decimal numbers but prohibits signed hexadecimal numbers, returning NaN instead. Compare the following. (The global Number function uses the ToNumber operation):

> [  eval('1'),   eval('0x1'),   eval('-1'),   eval('-0x1')]
[ 1, 1, -1, -1 ]

> [Number('1'), Number('0x1'), Number('-1'), Number('-0x1')]
[ 1, 1, -1, NaN ]

The V8 bug

The + unary operator with a String argument (i.e. +'1.234') also applies the ToNumber operation, which is what the V8 bug was about. Expressions like +'-0xF' and Number('-0xF') were resulting in -15 instead of NaN as called for in the spec. Note that this is separate from the actual unary expression -0xF; this is the string '-0xF' being converted to a number.

Conclusion

Signed hexadecimals aren't evil, nor are they disallowed in ES5. They just can't be converted from strings for whatever reason the ES5 authors had. This really has nothing to do with JSON5.

JSON5 has freed us from the restrictions of JSON so that we can have a lightweight data-interchange format that is even easier for humans to read and write. Why disallow signed hexadecimals just because ES5 doesn't convert them from strings?

@jordanbtucker jordanbtucker reopened this Aug 1, 2014
@aseemk aseemk changed the title Negative hexadecimal literals have been disallowed in V8 Allow negative hexadecimal literals again Aug 3, 2014
@aseemk
Copy link
Member Author

aseemk commented Aug 3, 2014

Great argument @jordanbtucker, and fantastically thorough explanation! Thanks.

I'm convinced: let's re-add support for negative hexadecimals. Updated the issue title.

Now we just have to figure out how, right? =)

@aseemk
Copy link
Member Author

aseemk commented Aug 19, 2014

Fixed by @jordanbtucker in pull #74.

@aseemk
Copy link
Member Author

aseemk commented Nov 5, 2014

Oops, I'd forgotten to close this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants