ECMAScript | Автоматическая вставка точки с запятой

ECMAScript | Автоматическая вставка точки с запятой

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

 

 

12.9.1 Правила автоматической вставки точки с запятой

В следующих правилах «токен» означает фактически распознанный лексический токен, определённый с использованием текущего лексического целевого символа, как описано в разделе 12.

 

Три основных правила вставки точки с запятой

Правило № 1

Когда исходный текст анализируется слева направо, встречается токен (называемый ошибочным токеном — offending token), который не разрешён никаким производством грамматики, то точка с запятой автоматически вставляется перед нарушающим токеном, если один или несколько из следующих условий выполняются:

  • Ошибочный токен отделён от предыдущего токена по крайней мере одним LineTerminator.
  • Ошибочный токен является закрывающей фигурной скобкой }.
  • Предыдущий токен является закрывающей круглой скобкой ), а вставленная точка с запятой затем будет анализироваться как завершающая точка с запятой оператора do-while (14.7.2).

Правило № 2

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

Правило № 3

Когда исходный текст разбирается слева направо, встречается токен, который разрешён некоторым производством грамматики, но производство является ограниченным, и токен будет первым токеном для терминала или нетерминала сразу после аннотации «[здесь нет LineTerminator]» в ограниченном продукте (и поэтому такой токен называется ограниченным токеном — restricted token), и ограниченный токен отделяется от предыдущего токена по крайней мере одним LineTerminator, затем точка с запятой автоматически вставляется перед ограниченным токеном.


 

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

 

Примечание!

Ниже приведены единственные ограниченные конструкции в грамматике:

UpdateExpression [Yield, Await] :

LeftHandSideExpression [?Yield, ?Await] [не LineTerminator здесь] ++

LeftHandSideExpression [?Yield, ?Await] [не LineTerminator здесь]

ContinueStatement [Yield, Await] :

continue ;

continue [не LineTerminator здесь] LabelIdentifier [?Yield, ?Await] ;

BreakStatement [Yield, Await] :

break ;

break [нет LineTerminator здесь] LabelIdentifier [?Yield, ?Await] ;

ReturnStatement [Yield, Await] :

return ;

return [не LineTerminator здесь] Expression [+In, ?Yield, ?Await] ;

ThrowStatement [Yield, Await] :

throw [не LineTerminator здесь] Expression [+In, ?Yield, ?Await] ;

ArrowFunction [In, Yield, Await] :

ArrowParameters [?Yield, ?Await] [не LineTerminator здесь] => ConciseBody [?In]

YieldExpression [In, Await] :

yield

yield [не LineTerminator здесь] AssignmentExpression [?In, +Yield, ?Await]

yield [не LineTerminator здесь] * AssignmentExpression [?In, +Yield, ?Await]

 

ArrowFunction [In, Yield, Await] :

ArrowParameters [?Yield, ?Await] [не LineTerminator здесь] => ConciseBody [?In]

AsyncFunctionDeclaration [Yield, Await, Default] :

async [не LineTerminator здесь] function BindingIdentifier [?Yield, ?Await] ( FormalParameters [~Yield, +Await] ) { AsyncFunctionBody }

[+Default] async [не LineTerminator здесь] function ( FormalParameters [~Yield, +Await] ) { AsyncFunctionBody }

AsyncFunctionExpression :

async [не LineTerminator здесь] function BindingIdentifier [~Yield, +Await] opt ( FormalParameters [~Yield, +Await] ) { AsyncFunctionBody }

AsyncMethod [Yield, Await] :

async [не LineTerminator здесь] ClassElementName [?Yield, ?Await] ( UniqueFormalParameters [~Yield, +Await] ) { AsyncFunctionBody }

AsyncGeneratorDeclaration [Yield, Await, Default] :

async [не LineTerminator здесь] function * BindingIdentifier [?Yield, ?Await] ( FormalParameters [+Yield, +Await] ) { AsyncGeneratorBody }

[+Default] async [не LineTerminator здесь] function * ( FormalParameters [+Yield, +Await] ) { AsyncGeneratorBody }

AsyncGeneratorExpression :

async [не LineTerminator здесь] function * BindingIdentifier [+Yield, +Await] opt ( FormalParameters [+Yield, +Await] ) { AsyncGeneratorBody }

AsyncGeneratorMethod [Yield, Await] :

async [не LineTerminator здесь] * ClassElementName [?Yield, ?Await] ( UniqueFormalParameters [+Yield, +Await] ) { AsyncGeneratorBody }

AsyncArrowFunction [In, Yield, Await] :

async [не LineTerminator здесь] AsyncArrowBindingIdentifier [?Yield] [no LineTerminator here] => AsyncConciseBody [?In]

CoverCallExpressionAndAsyncArrowHead [?Yield, ?Await] [no LineTerminator here] => AsyncConciseBody [?In]

AsyncArrowHead :

async [не LineTerminator здесь] ArrowFormalParameters [~Yield, +Await]

 

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

  • Когда встречается токен ++ или --, где синтаксический анализатор будет рассматривать его как постфиксный оператор, и хотя бы один LineTerminator возник между предыдущим токеном и токеном ++ или --, то точка с запятой автоматически вставляется перед токенами ++ или --.
  • Когда встречается токен continue, break, return, throw или yield и LineTerminator встречается перед следующим токеном, точка с запятой автоматически вставляется после токена continue, break, return, throw или yield.
  • Когда за параметром(ами) стрелочной функции следует символ LineTerminator перед токеном =>, автоматически вставляется точка с запятой, а знак препинания вызывает синтаксическую ошибку.
  • Когда за асинхронным токеном async следует LineTerminator перед function или IdentifierName или ( токеном, автоматически вставляется точка с запятой, и асинхронный токен async не рассматривается как часть того же выражения или элемента класса, что и следующие токены.
  • Когда за токеном async следует LineTerminator перед токеном *, автоматически вставляется точка с запятой, а знак препинания вызывает синтаксическую ошибку.

 

Итоговый практический совет программистам на ECMAScript:

  • Постфиксный оператор ++ или -- должен находиться в той же строке, что и его операнд.
  • Выражение Expression в операторе return или throw или AssignmentExpression в выражении yield должно начинаться в той же строке, что и токен return, throw или yield.
  • LabelIdentifier в операторе break или continue должен находиться в той же строке, что и токен break или continue.
  • Конец параметра(ов) стрелочной функции и его стрелки => должны быть на одной строке.
  • Асинхронный токен async, предшествующий асинхронной функции или методу, должен находиться в той же строке, что и следующий за ним токен.

 

12.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;

 

Примечание 1

Выражение a + b не рассматривается как значение, возвращаемое оператором return, потточникому что LineTerminator отделяет его от токена return.

 

Источник

a = b
++c

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

a = b;
++c;
Примечание 2

Токен ++ не рассматривается как постфиксный оператор, применяемый к переменной b, потому что LineTerminator встречается между b и ++.

 

Иссточник

if (a > b)
else c = d

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

 

Источник

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

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

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

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

 

 

12.9.3 Интересные случаи автоматической вставки точки с запятой

Этот раздел не является нормативным.

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

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

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

 

12.9.3.1 Интересные случаи автоматической вставки точки с запятой в списки операторов

В StatementList многие StatementListItem заканчиваются точкой с запятой, которые можно опустить, используя автоматическую вставку точки с запятой. Как следствие приведенных выше правил, в конце строки, заканчивающейся выражением, требуется точка с запятой, если следующая строка начинается с любого из следующего:

  • Открывающая круглая скобка(. Без точки с запятой две строки вместе рассматриваются как CallExpression.
  • Открывающая квадратная скобка[. Без точки с запятой две строки вместе рассматриваются как доступ к свойству, а не как ArrayLiteral или ArrayAssignmentPattern.
  • Литерал шаблона`. Без точки с запятой две строки вместе интерпретируются как помеченный шаблон (13.3.11) с предыдущим выражением как MemberExpression.
  • Унарный плюс + или унарный минус . Без точки с запятой две строки вместе интерпретируются как использование соответствующего бинарного оператора.
  • Литерал RegExp. Без точки с запятой две строки вместе могут анализироваться как / MultiplicativeOperator, например, если RegExp имеет флаги.

 

 

12.9.3.2 Случаи автоматической вставки точки с запятой и «[не LineTerminator здесь ]»

Этот раздел не является нормативным.

ECMAScript содержит грамматические конструкции, которые включают «[не LineTerminator здесь]». Эти произведения иногда являются средством наличия необязательных операндов в грамматике. Внедрение LineTerminator в этих местах изменит создание грамматики исходного текста с помощью создания грамматики без необязательного операнда.

Остальная часть этого раздела описывает ряд производств, использующих «[не LineTerminator здесь]» в этой версии ECMAScript.

 

12.9.3.2.1 Список грамматических произведений с необязательными операндами и «[не LineTerminator здесь ]»

 

Информационные ссылки

ECMAScript | Язык ECMAScript: лексическая грамматика

Стандарт ECMAScript — Раздел «12.9 Automatic Semicolon Insertion» — https://tc39.es/ecma262/#sec-automatic-semicolon-insertion