¿Por qué 019 no es un error de sintaxis de JavaScript? O por qué 019> 020

78

Si escribo 019 > 020en la consola de JavaScript (probada tanto en Chrome como en Firefox), obtengo la respuestatrue .

Esto se debe a que 020se interpreta como OctalIntegerLiteral(igual 16) mientras 019que aparentemente se interpreta como DecimalLiteral(y es igual 19). Como 19es mayor que 16, 019 > 020es true.

Lo que me desconcierta es por qué 019se interpreta como un DecimalLiteralprimer lugar. ¿Qué producción es? DecimalIntegerLiteralno permite 019:

DecimalIntegerLiteral ::
    0
    NonZeroDigit DecimalDigits_opt

OctalIntegerLiteraltampoco permite 019(ya 9que no es un dígito octal):

OctalIntegerLiteral ::
    0 OctalDigit
    OctalIntegerLiteral OctalDigit

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

Por lo que veo en la especificación, 019 realidad debería rechazarse, no veo por qué se interpreta como un entero decimal.

Supongo que aquí hay algún tipo de regla de compatibilidad, pero no he podido encontrar una definición formal. ¿Podría alguien ayudarme con esto?

(Por qué necesito esto: estoy desarrollando un analizador JavaScript / ECMAScript para Java con JavaCC y tengo que prestar especial atención a la especificación y sus desviaciones).

lexicore
fuente
3
019 + 0 == 19y 020 + 0 == 17por lo que está ignorando el cero inicial si contiene dígitos octales no.
Reactgular
22
Dato 'use strict'; 019curioso : → SyntaxError: los literales octales y las secuencias de escape octal están en desuso
goto-bus-stop
4
@Mathew: seguramente 020 + 0 ≠≠ 17:)
Jongware
4
@Mouser: no es lo mismo, parseInt solo se detiene en el primer carácter no válido.
Jongware
2
@FelixKling Porque así se formula la producción. O 0bien NonZeroDigit DecimalDigits_opt. Si 0le sigue algo, ya no lo es DecimalIntegerLiteral.
lexicore

Respuestas:

52

Por lo que pude encontrar, parece que algunas implementaciones de JavaScript simplemente no siguen la especificación en ese punto.

Desde el sitio de MDN:

Tenga en cuenta que los literales decimales pueden comenzar con un cero (0) seguido de otro dígito decimal, pero si el siguiente dígito después del 0 inicial es menor que 8, el número se analiza como un número octal. Esto no arrojará JavaScript, consulte el error 957513 . Consulte también la página sobre parseInt ().

Esto todavía no explica por qué 019 == 19, dado que el siguiente dígito después del 0 inicial es 1 y, por lo tanto, el número entero debe analizarse como octal. Pero el error al que se hace referencia parece estar relacionado con su caso. Su descripción dice:

El siguiente programa de JavaScript debería generar un error:

08

Según la especificación, DecimalIntegerLiteralnunca puede ir 0seguido directamente de otro dígito decimal, aunque Chrome / Opera, PrestOpera y Firefox sí lo admiten.

El error está cerrado como WONTFIX

Sin embargo, 019sería un literal decimal válido, con valor igual a 19, según el borrador de la próxima edición:

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

(He marcado las reglas relevantes)

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

También lo 01es un LegacyOctalLikeDecimalIntegerLiteral(3). Entonces 019es unNonOctalDecimalIntegerLiteral (2) que a su vez es un DecimalIntegerLiteral(1).

abl
fuente
2
Esta es la respuesta correcta. Chrome parece tener un problema similar. Evaluar 019con los rendimientos de Spidermonkey 1: warning: 09 is not a legal ECMA-262 octal constant: 019. Parece que se retiró porque los sitios (importantes) existentes se romperían.
Felix Kling
2
¿No estoy seguro de por qué esperaría 019ser un literal octal solo porque el segundo dígito es un 1? Seguramente cualquier cosa que contenga un 9no puede ser octal…
Bergi
2
@Bergi Supongo que debería preguntarles a los chicos de MDN sobre eso, ya que no pude encontrar ningún punto en la especificación de ECMAScript que justifique esta interpretación.
abl
4
Mirando el escáner de análisis sintáctico V8, de hecho asume que si un número comienza con 0 pero tiene un dígito 8 o 9, entonces el número es decimal (no hay comentarios que expliquen por qué) github.com/v8/v8/blob/97757e2d8c5b706f1f642340a424b38e20022a2c/ …
Vitalii Fedorenko
2
@VitaliiFedorenko Muy impresionado por cómo lo descubrió.
lexicore