78

If I type 019 > 020 in the JavaScript console (tested in both Chrome and Firefox), I get the answer true.

This is due to 020 being interpreted as an OctalIntegerLiteral (equals 16) whereas 019 is apparently being interpreted as DecimalLiteral (and equals 19). As 19 is greater than 16, 019 > 020 is true.

What puzzles me is why 019 is interpreted as a DecimalLiteral in first place. Which production is it? DecimalIntegerLiteral does not allow 019:

DecimalIntegerLiteral ::
    0
    NonZeroDigit DecimalDigits_opt

OctalIntegerLiteral also does not allow 019 (as 9 is not an octal digit):

OctalIntegerLiteral ::
    0 OctalDigit
    OctalIntegerLiteral OctalDigit

OctalDigit :: one of
    0 1 2 3 4 5 6 7

So from what I see in the specification, 019 should actually be rejected, I don't see why it is interpreted as a decimal integer.

I guess there's some kind of compatibility rule in place here but I have failed to find a formal definition. Could please anyone help me with this?

(Why I need this: I'm developing a JavaScript/ECMAScript parser for Java with JavaCC and have to pay a special attention to the specification - and deviations thereof.)

lexicore
  • 42,748
  • 17
  • 132
  • 221
  • Could it be the left argument gets treated as a string, and (therefore) so does the right argument -- *after* being converted to a decimal? – Jongware Jan 24 '15 at 15:19
  • @Jongware No, it's not inside any quotes so not a string. – lexicore Jan 24 '15 at 15:21
  • JavaScript is pretty forgiving. Maybe it just converts the `019` by trimming the excess zeros. – Mouser Jan 24 '15 at 15:22
  • But you don't get any error... hm. What is `019+1`? – Jongware Jan 24 '15 at 15:22
  • 3
    `019 + 0 == 19` and `020 + 0 == 17` so it's ignoring the leading zero if it contains non Octal digits. – Reactgular Jan 24 '15 at 15:22
  • @MathewFoscarini This is what I'm saying. The question is *why* of *if* is it formally correct. – lexicore Jan 24 '15 at 15:23
  • 22
    Fun fact: `'use strict'; 019` → SyntaxError: octal literals and octal escape sequences are deprecated – goto-bus-stop Jan 24 '15 at 15:24
  • @lexicore this is a specific parsing issue. You're looking for the specifications of how JavaScript will interrupt a literal as Octal. Not sure where that would be documented. – Reactgular Jan 24 '15 at 15:26
  • 4
    @Mathew: surely `020 + 0 ≠≠ 17` :) – Jongware Jan 24 '15 at 15:27
  • @René Interesting. `019` is actually *not* an octal literal as far as I can tell. – lexicore Jan 24 '15 at 15:27
  • 1
    @lexicore, also interesting: `parseInt("020", 8)` = 16, while `parseInt("019", 8)` = 1. [mdn - parseInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt) – Mouser Jan 24 '15 at 15:31
  • 4
    @Mouser: not the same thing, parseInt just stops at the first invalid character. – Jongware Jan 24 '15 at 15:32
  • 2
    @FelixKling Because that's how the production is formulated. Either `0` or `NonZeroDigit DecimalDigits_opt`. If `0` is followed by anything, it's not `DecimalIntegerLiteral` anymore. – lexicore Jan 24 '15 at 15:58
  • 2
    Yeah, sorry, I didn't read it correctly. FYI, `019` throws an error in esprima. – Felix Kling Jan 24 '15 at 16:05

1 Answers1

52

From what I could find, it seems that some implementations of JavaScript just don't follow the spec on that point.

From the MDN site:

Note that decimal literals can start with a zero (0) followed by another decimal digit, but If the next digit after the leading 0 is smaller than 8, the number gets parsed as an octal number. This won't throw in JavaScript, see bug 957513. See also the page about parseInt().

This still doesn't explain why 019 == 19, given that the next digit after the leading 0 is 1 and the whole number should therefore be parsed as octal. But the referenced bug does seem related to your case. Its description says:

The following JavaScript program should throw an error:

08

As per the spec, DecimalIntegerLiteral can never be 0 directly followed by another decimal digit, although Chrome/Opera, PrestOpera, and Firefox do support it.

The bug is closed as WONTFIX

However, 019 would be a valid decimal literal, with value equal to 19, according to the draft of the next edition:

https://people.mozilla.org/~jorendorff/es6-draft.html#sec-additional-syntax-numeric-literals

(I've marked the relevant rules)

The syntax and semantics of 11.8.3 is extended as follows except that 
this extension is not allowed for strict mode code:

[...]

DecimalIntegerLiteral ::
    0
    NonZeroDigit DecimalDigits_opt
    NonOctalDecimalIntegerLiteral                         // (1)

NonOctalDecimalIntegerLiteral ::
    0 NonOctalDigit
    LegacyOctalLikeDecimalIntegerLiteral NonOctalDigit    // (2)
    NonOctalDecimalIntegerLiteral DecimalDigit

LegacyOctalLikeDecimalIntegerLiteral ::
    0 OctalDigit                                          // (3)
    LegacyOctalLikeDecimalIntegerLiteral OctalDigit

So 01 is a LegacyOctalLikeDecimalIntegerLiteral (3) . Then 019 is a NonOctalDecimalIntegerLiteral (2) which in turn is a DecimalIntegerLiteral (1).

abl
  • 5,970
  • 4
  • 25
  • 44
  • 2
    This is the correct answer. Chrome seems to have a similar problem. Evaluating `019` with Spidermonkey yields `1: warning: 09 is not a legal ECMA-262 octal constant: 019`. It seems like it was backed out because existing (important) sites would break. – Felix Kling Jan 24 '15 at 16:32
  • 2
    Not sure why you'd expect `019` to be an octal literal just because the second digit is a `1`? Surely anything that contains a `9` can't be octal… – Bergi Jan 24 '15 at 22:20
  • 2
    @Bergi I guess you should ask the guys at MDN about that, as I couldn't find any point in the ECMAScript spec that justifies this interpretation. – abl Jan 25 '15 at 02:40
  • 4
    Looking at V8 parsing scanner, it indeed assumes that if a number starts with 0 but has a digit 8 or 9, then the number is decimal (there is no comment explaining why though) https://github.com/v8/v8/blob/97757e2d8c5b706f1f642340a424b38e20022a2c/src/scanner.cc#L834 – Vitalii Fedorenko Jan 26 '15 at 03:24
  • 2
    @VitaliiFedorenko Very impressed how you digged it out. – lexicore Jan 26 '15 at 21:42