Почему 019 не является синтаксической ошибкой JavaScript? Или почему 019 › 020

Если я наберу 019 > 020 в консоли JavaScript (проверено как в Chrome, так и в Firefox), я получу ответ true.

Это связано с тем, что 020 интерпретируется как OctalIntegerLiteral. (равно 16), тогда как 019, по-видимому, интерпретируется как DecimalLiteral (и равно 19). Поскольку 19 больше 16, 019 > 020 равно true.

Что меня озадачивает, так это то, почему 019 в первую очередь интерпретируется как DecimalLiteral. Какое это производство? DecimalIntegerLiteral не разрешает 019:

DecimalIntegerLiteral ::
    0
    NonZeroDigit DecimalDigits_opt

OctalIntegerLiteral также не допускает 019 (поскольку 9 не является восьмеричной цифрой):

OctalIntegerLiteral ::
    0 OctalDigit
    OctalIntegerLiteral OctalDigit

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

Итак, из того, что я вижу в спецификации, 019 на самом деле следует отклонить, я не понимаю, почему оно интерпретируется как десятичное целое число.

Я предполагаю, что здесь есть какое-то правило совместимости, но мне не удалось найти формальное определение. Может ли кто-нибудь помочь мне с этим?

(Зачем мне это нужно: я разрабатываю парсер JavaScript/ECMAScript для Java с JavaCC и имею обратить особое внимание на спецификацию и ее отклонения.)


person lexicore    schedule 24.01.2015    source источник
comment
Может быть, левый аргумент обрабатывается как строка, и (следовательно) правый аргумент -- после преобразования в десятичное число?   -  person Jongware    schedule 24.01.2015
comment
@Jongware Нет, это не кавычки, так что это не строка.   -  person lexicore    schedule 24.01.2015
comment
JavaScript довольно прощающий. Возможно, он просто преобразует 019, обрезая лишние нули.   -  person Mouser    schedule 24.01.2015
comment
Но вы не получаете никакой ошибки... хм. Что такое 019+1?   -  person Jongware    schedule 24.01.2015
comment
019 + 0 == 19 и 020 + 0 == 17, поэтому он игнорирует начальный ноль, если он содержит не восьмеричные цифры.   -  person Reactgular    schedule 24.01.2015
comment
@MathewFoscarini Вот что я говорю. Вопрос в том, почему из if это формально правильно.   -  person lexicore    schedule 24.01.2015
comment
Забавный факт: 'use strict'; 019 → SyntaxError: восьмеричные литералы и восьмеричные escape-последовательности устарели.   -  person goto-bus-stop    schedule 24.01.2015
comment
@lexicore это конкретная проблема синтаксического анализа. Вы ищете спецификации того, как JavaScript будет прерывать литерал как Octal. Не уверен, где это будет задокументировано.   -  person Reactgular    schedule 24.01.2015
comment
@Mathew: конечно 020 + 0 ≠≠ 17 :)   -  person Jongware    schedule 24.01.2015
comment
@ Рене Интересно. 019 на самом деле не восьмеричный литерал, насколько я могу судить.   -  person lexicore    schedule 24.01.2015
comment
@lexicore, тоже интересно: parseInt("020", 8) = 16, а parseInt("019", 8) = 1. mdn - parseInt   -  person Mouser    schedule 24.01.2015
comment
@Mouser: не то же самое, parseInt просто останавливается на первом недопустимом символе.   -  person Jongware    schedule 24.01.2015
comment
@FelixKling Потому что так сформулировано производство. Либо 0, либо NonZeroDigit DecimalDigits_opt. Если за 0 следует что-либо, это уже не DecimalIntegerLiteral.   -  person lexicore    schedule 24.01.2015
comment
Да, извините, я не правильно прочитал. К вашему сведению, 019 выдает ошибку в esprima.   -  person Felix Kling    schedule 24.01.2015


Ответы (1)


Из того, что я смог найти, кажется, что некоторые реализации JavaScript просто не соответствуют спецификации в этом вопросе.

С сайта MDN:

Обратите внимание, что десятичные литералы могут начинаться с нуля (0), за которым следует другая десятичная цифра, но если следующая цифра после начального 0 меньше 8, число анализируется как восьмеричное. Это не вызовет JavaScript, см. ошибка 957513. См. также страницу о parseInt().

Это по-прежнему не объясняет, почему 019 == 19, учитывая, что следующая цифра после начального 0 равна 1, и поэтому все число должно анализироваться как восьмеричное. Но указанная ошибка, похоже, связана с вашим случаем. В его описании сказано:

Следующая программа JavaScript должна выдавать ошибку:

08

Согласно спецификации, DecimalIntegerLiteral никогда не может быть 0, за которым непосредственно следует другая десятичная цифра, хотя Chrome/Opera, PrestOpera и Firefox поддерживают это.

Ошибка закрыта как WONTFIX

Однако 019 будет допустимым десятичным литералом со значением, равным 19, в соответствии с черновиком следующего издания:

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

(я отметил соответствующие правила)

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

Итак, 01 — это LegacyOctalLikeDecimalIntegerLiteral (3) . Тогда 019 является NonOctalDecimalIntegerLiteral (2), который, в свою очередь, является DecimalIntegerLiteral (1).

person abl    schedule 24.01.2015
comment
Это правильный ответ. Похоже, у Chrome похожая проблема. Вычисление 019 с помощью Spidermonkey дает 1: warning: 09 is not a legal ECMA-262 octal constant: 019. Похоже, что это было отменено, потому что существующие (важные) сайты сломались. - person Felix Kling; 24.01.2015
comment
Не уверен, почему вы ожидаете, что 019 будет восьмеричным литералом только потому, что вторая цифра - 1? Конечно, все, что содержит 9, не может быть восьмеричным... - person Bergi; 25.01.2015
comment
@Bergi Думаю, вам следует спросить об этом ребят из MDN, так как я не смог найти ни одного пункта в спецификации ECMAScript, оправдывающего эту интерпретацию. - person abl; 25.01.2015
comment
Глядя на сканер синтаксического анализа V8, он действительно предполагает, что если число начинается с 0, но имеет цифру 8 или 9, то число является десятичным (но нет комментариев, объясняющих, почему) github.com/v8/v8/blob/97757e2d8c5b706f1f642340a424b38a2e2000 - person Vitalii Fedorenko; 26.01.2015
comment
@VitaliiFedorenko Очень впечатлен тем, как ты это раскопал. - person lexicore; 27.01.2015