Спецификация ECMAScript 5.1 с аннотациями

Поделиться

7 Лексические соглашения #

Исходный текст программы на ECMAScript предварительно преобразуется в последовательность входных элементов, которые представляют собой токены, символы окончания строки, комментарии или пробельные символы. Исходный текст анализируется слева направо, каждый раз принимая максимально возможную последовательность символов за следующий входной элемент.

В этой лексической грамматике существует два начальных символа. Символ InputElementDiv Входной элемент деления используется в контекстах синтаксической грамматики, в которых допускается использование оператора деления (/) или деления-с-присвоением (/=). В других контекстах синтаксической грамматики используется символ InputElementRegExp Входной элемент регулярного выражения.

ПРИМЕЧАНИЕ Нет таких контекстов синтаксической грамматики, где были бы допустимы одновременно и деление либо деление-с-присвоением, и ведущий RegularExpressionLiteral Литерал регулярного выражения. Подстановка точки с запятой (см. 7.9) на это не влияет. В таких примерах, как:

a = b
/hi/g.exec(c).map(d);

(где после LineTerminator первым символом, отличным от пробельного и не относящимся к комментарию, является символ "косая черта" (/), и где в соответствии с синтаксическим контекстом допускается деление или деление-с-присвоением), возле символа LineTerminator нет точки с запятой. То есть, толкование вышеприведенного примера должно быть следующим:

a = b / hi / g.exec(c).map(d);

Синтаксис

InputElementDiv ::

WhiteSpace
LineTerminator
Comment
Token
DivPunctuator

InputElementRegExp ::

WhiteSpace
LineTerminator
Comment
Token
RegularExpressionLiteral

7.1 Юникодные символы управления форматом #

Символы управления форматом в стандарте Юникод – то есть, символы в категории "Cf" в базе данных символов Юникода, такие как left-to-right mark метка слева направо или right-to-left mark метка справа налево – являются управляющими кодами для управления форматированием определенного фрагмента текста при отсутствии используемых для этой цели протоколов более высокого уровня (таких как языки разметки).

Для облегчения редактирования и вывода на экран полезно разрешить включение в исходный текст символов управления форматом. Все эти символы могут использоваться как часть комментариев, а также как часть строковых литералов и литералов регулярных выражений.

Символы управления форматом <ZWNJ> и <ZWJ> используются для того, чтобы обеспечить необходимые различия при образовании слов или фраз в определенных языках. В исходном тексте на ECMAScript эти символы <ZWNJ> и <ZWJ> также могут применяться как идентификатор после первого символа.

Символ форматирования <BOM> используется преимущественно в начале текста. Он помечает его как текст в Юникоде и позволяет определить кодировку текста и порядок байтов. Символы <BOM>, предназначенные для этой цели, также могут иногда появляться не в начале текста, а далее – это может быть, например, результатом объединения нескольких файлов в один. Символы <BOM> интерпретируются как пробельные символы (см. 7.2).

В Таблице 1 приводится трактовка определенных символов форматирования, которые не являются частью комментариев, строковых литералов и регулярных выражений.

Таблица 1. Использование символов управления форматом

Значение кодовой единицы

Наименование

Официальное название

Употребление

\u200C

Нулевая ширина без объединения

<ZWNJ>

IdentifierPart

\u200D

Объединитель нулевой ширины

<ZWJ>

IdentifierPart

\uFEFF

Метка порядка байтов

<BOM>

Whitespace

7.2 Пробельные символы #

Пробельные символы применяются в целях удобочитаемости исходного текста и для разделения токенов (неделимых лексических единиц). Никакого другого значения они не имеют. Встретиться они могут между двумя токенами, а также в начале или в конце ввода. Кроме того, пробельные символы могут встретиться внутри StringLiteral Строковый литерал или RegularExpressionLiteral Литерал регулярного выражения, где они считаются значимыми символами, образующими часть значения этого литерала, или в рамках Comment Комментарий. Больше ни в каком другом токене они не могут встретиться.

В Таблице 2 перечислены пробельные символы ECMAScript.

Таблица 2. Пробельные символы

Значение кодовой единицы

Наименование

Официальное название

\u0009

Табуляция

<TAB>

\u000B

Вертикальная табуляция

<VT>

\u000C

Перевод страницы

<FF>

\u0020

Пробел

<SP>

\u00A0

Неразрывный пробел

<#x0a>

\uFEFF

Другая категория “Zs”

Метка порядка байтов

Любой другой "пробельный разделитель" Юникода

<BOM>

<USP>

Реализации ECMAScript должны распознавать все пробельные символы, определенные в формате Юникод версии 3.0. Более поздние версии стандарта Юникод могут определять другие пробельные символы. Реализации ECMAScript могут распознавать пробельные символы из более поздних версий Юникода.

Синтаксис

WhiteSpace ::

<TAB>
<VT>
<FF>
<SP>
<#x0a>
<BOM>
<USP>

7.3 Символы окончания строки #

Как и пробельные символы, символы окончания строки применяются в целях удобочитаемости исходного текста и для разделения токенов (неделимых лексических единиц). Однако, в отличие от пробельных символов, символы окончания строки некоторым образом влияют на поведение синтаксической грамматики.

Символы окончания строки могут встретиться между любыми двумя токенами, однако в некоторых местах синтаксическая грамматика запрещает их применение. Кроме того, эти символы затрагивают процесс автоматической подстановки точки с запятой (7.9). Символ окончания строки не может использоваться внутри какого-либо токена, кроме StringLiteral, причем в этом случае он может использоваться в StringLiteral как часть LineContinuation Продолжение строки.

Символ окончания строки может встретиться внутри MultiLineComment Многострочный комментарий – см. 7.4, но не может встретиться в SingleLineComment Однострочный комментарий.

Символы окончания строки включены в набор пробельных символов, которым соответствует класс \s в регулярных выражениях.

В Таблице 3 перечислены символы окончания строки ECMAScript.

Таблица 3. Символы окончания строки

Значение кодовой единицы

Наименование

Официальное название

\u000A

Перевод строки

<LF>

\u000D

Возврат каретки

<CR>

\u2028

Разделитель строки

<LS>

\u2029

Разделитель параграфа

<PS>

Символами окончания строки являются только те символы, которые приведены в Таблице 3. Все другие символы новой строки или переноса строки интерпретируются не как символы окончания строки, а как пробельные символы. В качестве окончания строки часто используется последовательность символов <CR><LF>. При нумерации строк ее следует рассматривать как один символ.

Синтаксис

LineTerminator ::

<LF>
<CR>
<LS>
<PS>

LineTerminatorSequence ::

<LF>
<CR> [lookahead <LF> ]
<LS>
<PS>
<CR> <LF>

7.4 Комментарии #

Комментарии могут быть однострочными или многострочными, причем последние не могут образовывать вложений.

Поскольку однострочный комментарий может содержать любой символ, кроме символа LineTerminator, а также в соответствии с общим правилом о том, что токен должен быть как можно длиннее, однострочный комментарий всегда включает в себя все символы между маркером // и концом строки. Однако стоящий в конце строки символ LineTerminator не считается частью однострочного комментария. Он распознается лексической грамматикой отдельно и становится частью потока входных элементов для синтаксической грамматики. Этот момент очень важен, поскольку он свидетельствует о том, что наличие или отсутствие однострочных комментариев не влияет на процесс автоматической подстановки точки с запятой (см. 7.9).

Поведение комментариев аналогично поведению пробельных символов. Как правило, комментарии игнорируются, за исключением того, что если MultiLineComment содержит символ окончания строки, в этом случае весь комментарий, в целях его анализа синтаксической грамматикой, принимается за LineTerminator.

Синтаксис

Comment ::

MultiLineComment
SingleLineComment

MultiLineComment ::

/* MultiLineCommentCharsopt*/

MultiLineCommentChars ::

MultiLineNotAsteriskChar MultiLineCommentCharsopt
* PostAsteriskCommentCharsopt

PostAsteriskCommentChars ::

MultiLineNotForwardSlashOrAsteriskChar MultiLineCommentCharsopt
* PostAsteriskCommentCharsopt

MultiLineNotAsteriskChar::

SourceCharacter но не asterisk *

MultiLineNotForwardSlashOrAsteriskChar ::

SourceCharacter но не forward-slash / или asterisk *

SingleLineComment ::

// SingleLineCommentCharsopt

SingleLineCommentChars ::

SingleLineCommentChar SingleLineCommentCharsopt

SingleLineCommentChar ::

SourceCharacter но не LineTerminator

7.5 Токены #

Синтаксис

Token ::

IdentifierName
Punctuator
NumericLiteral
StringLiteral

ПРИМЕЧАНИЕ Правила для DivPunctuator и RegularExpressionLiteral определяют токены, но не включены в правило для Token.

7.6 Имена идентификаторов и идентификаторы #

Имена идентификаторов представляют собой токены, толкование которых производится в соответствии с грамматикой, описанной в разделе "Идентификаторы" Главы 5 стандарта Юникод (с небольшими изменениями). Identifier Идентификатор представляет собой IdentifierName Имя идентификатора, которое не является ReservedWord Зарезервированное слово – см. 7.6.1. В основе грамматики идентификаторов Юникода лежат нормативные и информативные категории символов, описываемые стандартом Юникод. Все реализации ECMAScript, соответствующие требованиям данного Стандарта, должны обрабатывать символы в упомянутых категориях стандарта Юникод версии 3.0 как принадлежащие к этим категориям.

Этот стандарт добавляет еще два специфических символа: Знак доллара ($) и символ подчёркивания (_) — они допускаются в любом месте IdentifierName.

Кроме того, в IdentifierName допускаются и управляющие последовательности Юникода Unicode escape sequences: они трактуются как один символ IdentifierName, вычисленный символьным значением UnicodeEscapeSequence Юникодная управляющая последовательность – см. 7.8.4). Обратная косая черта \, стоящая перед UnicodeEscapeSequence, не трактуется как символ IdentifierName. UnicodeEscapeSequence не может использоваться для того, чтобы вставить в IdentifierName символ, который в противном случае был бы некорректным. Иными словами, если последовательность \ UnicodeEscapeSequence заменить на символьное значение для UnicodeEscapeSequence, результатом все равно должен являться корректный IdentifierName с точно такой же последовательностью символов, что и в оригинальном IdentifierName. В основе интерпретации всех идентификаторов в данной спецификации лежат их фактические символы, независимо от того, использовалась ли управляющая последовательность для передачи каких-либо конкретных символов.

Два символа IdentifierName, канонически эквивалентные в соответствии со стандартом Юникода, не являются одинаковыми, если они не представлены совершенно одинаковыми последовательностями кодовых единиц (иными словами, корректные реализации ECMAScript должны производить только побитовое сравнение значений IdentifierName). Смысл в том, чтобы прежде чем достичь компилятора, входящий исходный текст преобразовывался бы в соответствии с формой нормализации "С".

Реализации ECMAScript могут распознавать символы идентификатора из более поздних версий Юникода. В случае возможных проблем с межплатформенной переносимостью программы, при написании кода следует использовать только символы, описанные в стандарте Юникод версии 3.0.

Синтаксис

Identifier ::

IdentifierName но не ReservedWord

IdentifierName ::

IdentifierStart
IdentifierName IdentifierPart

IdentifierStart ::

UnicodeLetter
$
_

\ UnicodeEscapeSequence

IdentifierPart ::

IdentifierStart
UnicodeCombiningMark
UnicodeDigit
UnicodeConnectorPunctuation
<ZWNJ>
<ZWJ>

UnicodeLetter

– любой символ в категориях Юникода “Прописная буква (Lu)”, “Строчная буква (Ll)”, “Заглавная буква (Lt)”, “Буква-модификатор (Lm)”, “Другая буква (Lo)” или “Буква-число (Nl)”.

UnicodeCombiningMark

– любой символ в категориях Юникода “Не-пробельный знак (Mn)” или “Комбинирующий пробельный знак (Mc)”

UnicodeDigit

– любой символ в категории Юникода “Десятичное число (Nd)”

UnicodeConnectorPunctuation

– любой символ в категории Юникода “Соединяющая пунктуация (Pc)”

UnicodeEscapeSequence

– см. пункт 7.8.4.

7.6.1 Зарезервированные слова #

IdentifierName, которое не может быть использовано как Identifier, является зарезервированным словом.

Синтаксис

ReservedWord ::

Keyword
FutureReservedWord
NullLiteral
BooleanLiteral

7.6.1.1 Ключевые слова #

Перечисленные ниже токены являются ключевыми словами ECMAScript. В программах на ECMAScript они не могут быть использованы как Identifiers Идентификаторы.

Синтаксис

Keyword :: одно из

break

do

instanceof

typeof

case

else

new

var

catch

finally

return

void

continue

for

switch

while

debugger

function

this

with

default

if

throw

delete

in

try

7.6.1.2 Слова, зарезервированные для использования в будущем #

Перечисленные ниже слова используются как ключевые слова в предполагаемых расширениях языка. Они зарезервированы, чтобы предусмотреть возможность применения этих расширений в будущем.

Синтаксис

FutureReservedWord :: одно из

class

enum

extends

super

const

export

import

Перечисленные ниже токены также рассматриваются как FutureReservedWords Зарезервированные на будущее слова если они встречаются в программе, написанной в строгом режиме языка (см. 10.1.1). Если в каком-либо контексте, в котором использование FutureReservedWord Зарезервированное на будущее слово вызвало бы ошибку, появится какой-либо из перечисленных ниже токенов в строгом режиме, это также должно вызвать аналогичную ошибку.

implements

let

private

public

yield

interface

package

protected

static

7.7 Знаки пунктуации #

Синтаксис

Punctuator :: одно из

{

}

(

)

[

]

.

;

,

<

>

<=

>=

==

!=

===

!==

+

-

*

%

++

--

<<

>>

>>>

&

|

^

!

~

&&

||

?

:

=

+=

-=

*=

%=

<<=

>>=

>>>=

&=

|=

^=

DivPunctuator :: одно из

/

/=

7.8 Литералы #

Синтаксис

Literal ::

NullLiteral
BooleanLiteral
NumericLiteral
StringLiteral
RegularExpressionLiteral

7.8.1 Литералы Null #

Синтаксис

NullLiteral ::

null

Семантика

Значением литерала null null является единственное значение типа Null, а именно – null.

7.8.2 Литералы Boolean #

Синтаксис

BooleanLiteral ::

true
false

Семантика

Значением литерала Boolean true является значение типа Boolean, а именно – true.

Значением литерала Boolean false является значение типа Boolean, а именно – false.

7.8.3 Числовые литералы #

Синтаксис

NumericLiteral ::

DecimalLiteral
HexIntegerLiteral

DecimalLiteral ::

DecimalIntegerLiteral . DecimalDigitsopt ExponentPartopt
. DecimalDigits ExponentPartopt
DecimalIntegerLiteral ExponentPart
opt

DecimalIntegerLiteral::

0
NonZeroDigit DecimalDigits
opt

DecimalDigits ::

DecimalDigit
DecimalDigits DecimalDigit

DecimalDigit :: одно из

0 1 2 3 4 5 6 7 8 9

НенулеваяЦифра :: одно из

1 2 3 4 5 6 7 8 9

ExponentPart ::

ExponentIndicator SignedInteger

ExponentIndicator :: одно из

e E

SignedInteger ::

DecimalDigits
+ DecimalDigits
- DecimalDigits

HexIntegerLiteral ::

0x HexDigit
0X HexDigit
HexIntegerLiteral HexDigit

HexDigit :: одно из

0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F

Исходный символ, следующий сразу же за NumericLiteral Числовой литерал, не должен быть IdentifierStart Начало идентификатора или DecimalDigit Десятичная цифра.

ПРИМЕЧАНИЕ Например, запись:

3in

не представляет собой два входные элемента 3 и in, а является ошибкой.

Семантика

Числовой литерал имеет значение типа Number. Это значение определяется в два этапа: сначала из литерала выводится его математическое значение MV (сокращение от "mathematical value" – прим. перев.), а затем это MV округляется в соответствии с приведенными ниже описаниями:

После определения точного MV числового литерала оно затем округляется до значения типа Number. Если MV равно 0, тогда округленное значение равно +0; в противном случае округленное значение должно представлять собой именно это числовое значение MV (в соответствии с определением в пункте 8.5), за исключением случаев, когда литерал является DecimalLiteral и имеет более 20 значимых чисел – в этом случае числовое значение может быть либо числовым значением MV литерала, полученного при замене на число 0 каждой значащей цифры после 20-й, либо числовым значением MV литерала, полученного в результате замены на число 0 каждой значащей цифры после 20-й, с последующим приращением литерала в позиции 20-й значащей цифры. Цифра является значащей, если она не является частью ExponentPart, и

В корректной реализации при обработки программы в строгом режиме (см. пункт 10.1.1) синтаксис для NumericLiteral не должен распространяться на OctalIntegerLiteral Восьмеричный целый литерал, определение которого содержится в B.1.1.

7.8.4 Строковые литералы #

Строковый литерал представляет собой символы в количестве ноль или более, заключённые в одиночные или двойные кавычки. Каждый символ может быть представлен управляющей последовательностью. В строковом литерале могут появляться буквально все символы, кроме символа закрывающей кавычки, обратной косой черты, возврата каретки, разделителя строки, разделителя параграфа и перевода строки. Каждый символ может быть представлен в виде управляющей последовательности.

Синтаксис

StringLiteral ::

" DoubleStringCharactersopt"
'
SingleStringCharactersopt'

DoubleStringCharacters ::

DoubleStringCharacter DoubleStringCharactersopt

SingleStringCharacters ::

SingleStringCharacter SingleStringCharactersopt

DoubleStringCharacter ::

SourceCharacter но не double-quote " или backslash \ или LineTerminator
\ EscapeSequence
LineContinuation

SingleStringCharacter ::

SourceCharacter но не single-quote ' или backslash \ или LineTerminator
\ EscapeSequence
LineContinuation

LineContinuation ::

\ LineTerminatorSequence

EscapeSequence ::

CharacterEscapeSequence
0 [lookahead DecimalDigit]
HexEscapeSequence
UnicodeEscapeSequence

CharacterEscapeSequence ::

SingleEscapeCharacter
NonEscapeCharacter

SingleEscapeCharacter ::одно из

' " \ b f n r t v

NonEscapeCharacter::

SourceCharacter но не EscapeCharacter или LineTerminator

EscapeCharacter ::

SingleEscapeCharacter
DecimalDigit
x
u

HexEscapeSequence ::

x HexDigit HexDigit

UnicodeEscapeSequence ::

u HexDigit HexDigit HexDigit HexDigit

Определения нетерминального HexDigit Шестнадцатеричная цифра содержится в пункте 7.6. Определение SourceCharacter Исходный символ содержится в пункте 6.

Семантика

Строковый литерал представляет собой значение типа String. Строковое значение SV (сокращение от "string value" – прим. перев.) литерала описывается на основе символьных значений CV (сокращение от "character value" – прим. перев.) различных частей строкового литерала. В рамках этого процесса некоторые символы строкового литерала трактуются как имеющие математическое значение MV в соответствии с описанием, приведенным ниже или в пункте 7.8.3.

В корректной реализации при обработке программы в строгом режиме (см. пункт 10.1.1) синтаксис для EscapeSequence не может распространяться на OctalEscapeSequence, определение которой содержится в B.1.2.

ПРИМЕЧАНИЕ Символ окончания строки не может встретиться в строковом литерале, за исключением случая, когда он как часть LineContinuation используется для создания пустой последовательности символов. Чтобы появление символа окончания строки в строковом значении строкового литерала было корректным, необходимо использовать управляющую последовательность \n или \u000A.

7.8.5 Литералы регулярного выражения #

Литерал регулярного выражения представляет собой входной элемент, который каждый раз при обработке литерала преобразовывается к объекту RegExp (см. 15.10). Два литерала регулярного выражения в программе преобразовываются к объектам регулярного выражения, которые никогда не сравниваются друг с другом в виде ===, даже если содержание этих двух литералов идентично. Объект RegExp также может быть создан во время выполнения программы – либо посредством команды new RegExp (см. 15.10.4), либо с помощью вызова конструктора RegExp в качестве функции (15.10.3).

Приведённые ниже правила описывают синтаксис литералов регулярного выражения. Эти правила используются предварительным лексическим анализатором (сканером) входного элемента, чтобы найти конец литерала регулярного выражения. Строки символов, составляющих RegularExpressionBody Тело регулярного выражения и RegularExpressionFlags Флаги регулярного выражения, передаются в необработанном виде конструктору регулярных выражений, который затем обрабатывает их в соответствии со своей более строгой грамматикой. Реализация может расширить грамматику конструктора регулярных выражений, однако она не должна расширять правила RegularExpressionBody и RegularExpressionFlags, или правила, используемые этими правилами.

Синтаксис

RegularExpressionLiteral ::

/ RegularExpressionBody / RegularExpressionFlags

RegularExpressionBody::

RegularExpressionFirstChar RegularExpressionChars

RegularExpressionChars ::

[пусто]
RegularExpressionChars RegularExpressionChar

RegularExpressionFirstChar ::

RegularExpressionNonTerminator но не * или \ или / или [
RegularExpressionBackslashSequence
RegularExpressionClass

RegularExpressionChar ::

RegularExpressionNonTerminator но не \ или / или [
RegularExpressionBackslashSequence
RegularExpressionClass

RegularExpressionBackslashSequence ::

\ RegularExpressionNonTerminator

RegularExpressionNonTerminator ::

SourceCharacter но не LineTerminator

RegularExpressionClass ::

[ RegularExpressionClassChars]

RegularExpressionClassChars::

[пусто]
RegularExpressionClassChars
RegularExpressionClassChar

RegularExpressionClassChar::

RegularExpressionNonTerminator но не ] или \
RegularExpressionBackslashSequence

RegularExpressionFlags::

[пусто]
RegularExpressionFlags IdentifierPart

ПРИМЕЧАНИЕ Литералы регулярного выражения не могут быть пустыми. Символы // не представляют пустой литерал регулярного выражения – они начинают однострочный комментарий. Чтобы задать пустое регулярное выражение, необходимо использовать /(?:)/.

Семантика

Литерал регулярного выражения преобразовыается к значению типа Object, который является экземпляром стандартного встроенного конструктора RegExp. Это значение определяется в два этапа: сначала символы, составляющие развёртывания правил RegularExpressionBody и RegularExpressionFlags для регулярных выражений, собираются в необработанном виде в две строки – Pattern Шаблон и Flags Флаги соответственно. Затем каждый раз при оценке литерала создается новый объект посредством выражения new RegExp(Pattern, Flags), где RegExp является стандартным встроенным конструктором с этим именем. Этот созданный объект становится значением для RegularExpressionLiteral. Если при вызове конструктора new RegExp получена ошибка, описанная в пункте 15.10.4.1, ее следует обрабатывать как "раннюю ошибку" early error, см. Статью 16.

7.9 Автоматическая подстановка точки с запятой #

Некоторые инструкции ECMAScript (пустая инструкция, инструкция переменной, инструкция-выражение, инструкции do-while, continue, break, return и throw) должна завершать точка с запятой. Она всегда может быть указана в исходном тексте явным образом, но иногда её можно опустить, чтобы облегчить чтение кода. В этих случаях говорят, что символы точки с запятой подставляются в поток токенов исходного кода автоматически.

7.9.1 Правила автоматической подстановки точки с запятой #

Существует 3 основных правила подстановки точки с запятой:

  1. Если при распознавании программы слева направо встречается "токен-нарушитель" offending token, который ни одно из правил грамматики не разрешает, перед ним происходит автоматическая подстановка точки с запятой, если выполняется одно или оба условия:

  1. Если при распознавании программы слева направо встречается конец входного потока токенов, и анализатор не может распознать поток входных токенов как единую готовую программу Program на ECMAScript, происходит автоматическая подстановка точки с запятой в конце входного потока.

  2. Если при распознавании программы слева направо встречается токен, разрешенный правилом этой грамматики, однако это правило является ограниченным правилом, и в результате применения этого токен станет первым токеном для терминала или нетерминала, следующего сразу же за комментарием “[no LineTerminator here]”, содержащимся в ограниченном правиле (именно поэтому он и называется "ограниченным токеном"), и ограниченный токен отделен от предыдущего токена хотя бы одним LineTerminator, то перед ограниченным токеном происходит автоматическая подстановка точки с запятой.

Есть еще одно, дополнительное условие, которое перекрывает предыдущие правила. Автоматическая подстановка точки с запятой не производится, если затем эта точка с запятой даст пустую инструкцию, или если она станет одной из двух точек с запятой в заголовке инструкции for (см. пункт 12.6.3).

ПРИМЕЧАНИЕ Ниже перечислены все ограниченные правила грамматики:

PostfixExpression :

LeftHandSideExpression [no LineTerminator here]++
LeftHandSideExpression
[no LineTerminator here]--

ContinueStatement :

continue [no LineTerminator here] Identifier;

BreakStatement :

break [no LineTerminator here] Identifier;

ReturnStatement :

return [no LineTerminator here] Expression;

ThrowStatement:

throw [no LineTerminator here] Expression;

На практике эти ограниченные правила действуют следующим образом:

Если встречается токен ++ или -- там, где анализатор трактует его как постфиксный оператор, и при этом между предыдущим токеном и токеном ++ или -- встречается хотя бы один LineTerminator, тогда перед токеном ++ или -- происходит автоматическая подстановка точки с запятой.

Если встречается токен continue, break, return или throw, при этом перед следующим токеном встречается LineTerminator, тогда перед токеном continue, break, return или throw происходит автоматическая подстановка точки с запятой.

Отсюда можно вывести практические советы для программистов, пишущих на ECMAScript:

Постфиксный оператор ++ или -- должен находиться на той же строке, что и его операнд.

Expression Выражение в инструкции return или throw должно начинаться на той же строке, что и токен return или throw.

Identifier Идентификатор в инструкции break или continue должен быть на той же строке, что и токен break илиcontinue.

7.9.2 Примеры автоматической подстановки точки с запятой #

Исходный текст

{ 1 2 } 3

не является корректным предложением в соответствии с правилами грамматики ECMAScript – даже если применить правила автоматической подстановки точки с запятой. В отличие от него, исходный текст

{ 1
2 } 3

также не является корректным предложением ECMAScript, однако посредством автоматической подстановки точки с запятой он преобразовывается в следующее предложение:

{ 1
;2 ;} 3;

которое является корректным предложением ECMAScript.

Исходный текст

for (a; b
)

не является корректным предложением ECMAScript, при этом автоматическая подстановка точки с запятой не изменяет его, так как точка с запятой требуется для заголовка инструкции for, а, в соответствии с правилами, одна из этих двух точек с запятой не вставляется в заголовок инструкции for.

Исходный текст

return
a + b

посредством автоматической подстановки точки с запятой преобразовывается в следующее предложение:

return;
a + b;

ПРИМЕЧАНИЕ Выражение a + b не считается значением, возвращаемым инструкцией return, так как оно отделено от токена return LineTerminator.

Исходный текст

a = b
++c

посредством автоматической подстановки точки с запятой преобразовывается в следующее предложение:

a = b;
++c;

ПРИМЕЧАНИЕ Токен ++ не считается постфиксным оператором, применённым к переменной b, поскольку между b и ++ находится LineTerminator.

Исходный текст

if (a > b)
else c = d

не является корректным предложением ECMAScript, при этом автоматическая подстановка точки с запятой перед токеном else не изменяет его, несмотря на то, что в этом месте не применяется никакое правило грамматики, поскольку в этом случае автоматически вставленная точка с запятой была бы воспринята как пустая инструкция.

Исходный текст

a = b + c
(d + e).print()

не преобразовывается в результате автоматической подстановки точки с запятой, поскольку выражение в круглых скобках в начале второй строки может трактоваться как список аргументов для вызова функции:

a = b + c(d + e).print()

Если инструкция присваивания начинается с открывающей скобки, то отличная идея – поставить точку с запятой в конце предыдущей инструкции, а не полагаться на её автоматическую подстановку.