Синтаксические и лексические грамматики (Syntactic and Lexical Grammars, раздел 5.1)
Контекстно-свободные грамматики
«Контекстно-свободная грамматика» (context-free grammar) состоит из ряда «производств» (productions). Каждое производство имеет абстрактный символ, называемый «нетерминальным» (nonterminal), «в левой части» (left-hand side) и последовательность из нуля или более нетерминальных и «терминальных» (terminal) символов в правой части. Для каждой грамматики терминальные символы взяты из определенного алфавита.
«Цепное производство» (chain production) — это производство, в правой части которого есть ровно один нетерминальный символ, а также ноль или более оконечных символов.
Начиная с предложения, состоящего из одного выделенного нетерминального символа, называемого «целевым символом» (goal symbol), данная контекстно-свободная грамматика определяет «язык» (language), а именно (возможно, бесконечный) набор возможных последовательностей терминальных символов, которые могут возникнуть в результате многократной замены любого нетерминального в последовательность с правой частью производства, для которой нетерминал является левой частью.
Лексическая грамматика и грамматика RegExp
«Лексическая грамматика» (lexical grammar) для ECMAScript приведена в разделе 12. Эта грамматика имеет в качестве оконечных символов кодовые точки Unicode, которые соответствуют правилам для SourceCharacter, определенным в разделе 11.1. Она определяет набор производств, начиная с символа цели InputElementDiv, InputElementTemplateTail, или InputElementRegExp, или InputElementRegExpOrTemplateTail, которые описывают, как последовательности таких кодовых точек преобразуются в последовательность входных элементов.
Элементы ввода, отличные от пробелов и комментариев, образуют терминальные символы для синтаксической грамматики для ECMAScript и называются «токенами» (tokens) ECMAScript. Эти токены являются зарезервированными словами, идентификаторами, литералами и пунктуаторами языка ECMAScript. Более того, терминаторы строки, хотя и не считаются маркерами, также становятся частью потока элементов ввода и направляют процесс автоматической вставки точки с запятой (раздел 12.9). Простые пробелы и однострочные комментарии отбрасываются и не отображаются в потоке входных элементов синтаксической грамматики. MultiLineComment (то есть комментарий формы / *… * / независимо от того, занимает ли он более одной строки) также просто отбрасывается, если он не содержит признака конца строки; но если MultiLineComment содержит один или несколько ограничителей строки, то он заменяется одним ограничителем строки, который становится частью потока входных элементов для синтаксической грамматики.
Грамматика регулярных выражений RegExp для ECMAScript приведена в разделе 22.2.1. Эта грамматика также имеет в качестве терминальных символов кодовые точки, как определено SourceCharacter. Он определяет набор производств, начиная с «шаблона» (Pattern) символа цели, который описывает, как последовательности кодовых точек преобразуются в шаблоны регулярных выражений.
Продукция лексической грамматики и грамматики RegExp отличается наличием двух двоеточий «::» в качестве разделительных знаков препинания. Лексическая грамматика и грамматика RegExp имеют несколько общих производств.
Грамматика числовой строки
Другая грамматика используется для перевода строк в числовые значения. Эта грамматика подобна той части лексической грамматики, которая связана с числовыми литералами и имеет в качестве терминальных символов SourceCharacter. Эта грамматика появляется в разделе 7.1.4.1.
Грамматика числовых строк отличается наличием трех двоеточий «:::» в качестве знаков препинания.
Синтаксическая грамматика
Синтаксическая грамматика для ECMAScript дается в разделах с 13 по 16. В этой грамматике есть токены ECMAScript, определенные лексической грамматикой в качестве конечных символов (раздел 5.1.2). Он определяет набор производств, начиная с двух альтернативных символов цели «сценария» Script и «модуля» Module, которые описывают, как последовательности токенов образуют синтаксически правильные независимые компоненты программ ECMAScript.
Когда поток кодовых точек должен быть проанализирован как сценарий или модуль ECMAScript (Script или Module), он сначала преобразуется в поток входных элементов путем повторного применения лексической грамматики; этот поток входных элементов затем анализируется с помощью одного приложения синтаксической грамматики. Входной поток синтаксически ошибочен, если токены в потоке входных элементов не могут быть проанализированы как единственный экземпляр целевого нетерминала (Script или Module) без каких-либо оставшихся токенов.
Когда синтаксический анализ успешен, он строит «дерево синтаксического анализа» (parse tree), корневую древовидную структуру, в которой каждый узел является «узлом синтаксического анализа» (Parse Node). Каждый узел синтаксического анализа является «экземпляром» (instance) символа в грамматике; он представляет собой диапазон исходного текста, который может быть получен из этого символа. Корневой узел дерева синтаксического анализа, представляющий весь исходный текст, является экземпляром символа цели синтаксического анализа. Когда узел синтаксического анализа является экземпляром нетерминала, он также является экземпляром некоторого продукта, который имеет этот нетерминал в левой части. Более того, у него ноль или более «детей» (children), по одному для каждого символа в правой части производства: каждый ребёнок является узлом синтаксического анализа, который является экземпляром соответствующего символа.
Новые Узлы Синтаксического Анализа создаются для каждого вызова анализатора и никогда не используются повторно между синтаксическими анализами даже идентичного исходного текста. Узлы синтаксического анализа считаются «одним и тем же узлом синтаксического анализа» (same Parse Node) тогда и только тогда, когда они представляют один и тот же диапазон исходного текста, являются экземплярами одного и того же грамматического символа и являются результатом одного и того же вызова синтаксического анализатора.
Многократный синтаксический анализ одной и той же строки приведет к разным узлам синтаксического анализа. Например, рассмотрите:
let str = «1 + 1;»;
eval(str);
eval(str);
Каждый вызов eval преобразует значение str в исходный текст ECMAScript и выполняет независимый синтаксический анализ, который создает собственное отдельное дерево узлов синтаксического анализа. Деревья различны, даже если каждый синтаксический анализ работает с исходным текстом, полученным из одного и того же значения String.
Узлы синтаксического анализа являются артефактами спецификации, и реализации не требуют использования аналогичной структуры данных.
Производство синтаксической грамматики отличается наличием только одного двоеточия «:» в качестве знака препинания.
Синтаксическая грамматика, представленная в разделах с 13 по 16, не является полным отчетом о том, какие последовательности токенов принимаются в качестве правильного сценария или модуля (Script или Module) ECMAScript. Также принимаются некоторые дополнительные последовательности токенов, а именно те, которые были бы описаны грамматикой, если бы в последовательность были добавлены только точки с запятой в определенных местах (например, перед символами конца строки). Более того, определенные последовательности токенов, описываемые грамматикой, не считаются приемлемыми, если символ конца строки появляется в определенных «неудобных» местах.
В некоторых случаях, чтобы избежать двусмысленности, синтаксическая грамматика использует обобщенные конструкции, которые разрешают последовательности токенов, которые не образуют допустимый скрипт или модуль (Script или Module) ECMAScript. Например, этот метод используется для объектных литералов и шаблонов деструктуризации объектов. В таких случаях предоставляется более строгая дополнительная грамматика, которая дополнительно ограничивает допустимые последовательности токенов. Как правило, правило ранней ошибки затем определяет состояние ошибки, если «P не покрывает (covering) N», где P — это узел синтаксического анализа (экземпляр обобщенной продукции), а N — нетерминал из дополнительной грамматики. Здесь последовательность токенов, изначально совпадающих с P, снова анализируется с использованием N в качестве символа цели. (Если N принимает грамматические параметры, то им присваиваются те же значения, которые использовались при первоначальном анализе P.) Ошибка возникает, если последовательность токенов не может быть проанализирована как один экземпляр N без остатка токенов. Впоследствии алгоритмы обращаются к результату синтаксического анализа, используя фразу формы «N, которая покрывается P». Это всегда будет узел синтаксического анализа (экземпляр N, уникальный для данного P), поскольку любой сбой синтаксического анализа был бы обнаружен правилом ранней ошибки.
Грамматические обозначения ()
Терминальные символы отображаются шрифтом фиксированной ширины (fixed width) как в грамматиках, так и в данной спецификации, когда текст напрямую ссылается на такой терминальный символ. Они должны появиться в сценарии точно так, как написано. Все указанные таким образом кодовые точки оконечных символов следует понимать как соответствующие кодовые точки Unicode из диапазона Basic Latin, в отличие от любых похожих на вид кодовых точек из других диапазонов Unicode. Кодовая точка в терминальном символе не может быть выражена с помощью обратной косой линии \ UnicodeEscapeSequence.
Нетерминальные символы выделены курсивом (italic). Определение нетерминала (также называемого «производство»“production”) вводится именем определяемого нетерминала, за которым следует одно или несколько двоеточий — :, ::, :::. (Число двоеточий указывает, к какой грамматике принадлежит «производство».) Одна или несколько альтернативных правых частей нетерминала следуют в следующих строках.
Например, синтаксическое определение оператора «while«:
while ( Expression ) Statement
утверждает, что нетерминальный объект WhileStatement представляет токен while, за которым следует токен ( левой круглой скобки, за которым следует выражение Expression, за которым следует токен ) правой круглой скобки, за которым следует оператор Statement. Вхождения выражения Expression и оператора Statement сами по себе нетерминалы.
Другой пример — синтаксическое определение «списка аргументов»:
ArgumentList , AssignmentExpression
заявляет, что «список аргументов» ArgumentList может представлять либо одно «выражение присвоения» AssignmentExpression, либо другой «список аргументов» ArgumentList, за которым следует «запятая»(comma ,), за которой следует «выражение присвоения» AssignmentExpression. Это определение ArgumentList является рекурсивным, то есть определяется в терминах самого себя. В результате ArgumentList может содержать любое положительное количество аргументов, разделенных запятыми, где каждое выражение аргумента является «выражением присвоения» AssignmentExpression. Такие рекурсивные определения нетерминалов широко распространены.
Нижний индекс «opt«, который может стоять после терминала или нетерминала, указывает на необязательный символ. Альтернатива, содержащая необязательный символ, на самом деле определяет две правые стороны: одна без необязательного элемента, а другая включает его. Это означает, что:
BindingIdentifier Initializeropt
удобное сокращение для:
Ещё пример грамматического обозначения (синтаксического определения) для оператора «for«:
for ( LexicalDeclaration Expressionopt ; Expressionopt ) Statement
удобное сокращение для:
for ( LexicalDeclaration ; Expressionopt ) Statement
for ( LexicalDeclaration Expression ; Expressionopt ) Statement
что, в свою очередь, является сокращением для:
for ( LexicalDeclaration ; ) Statement
for ( LexicalDeclaration ; Expression ) Statement
for ( LexicalDeclaration Expression ; ) Statement
for ( LexicalDeclaration Expression ; Expression ) Statement
Итак, в этом примере нетерминальный оператор for ForStatement фактически имеет четыре альтернативные правые части.
Производство может быть параметризовано с помощью подписанной аннотации формы «[parameters]«, которая может появляться как суффикс к нетерминальному символу, определенному производством. «Параметры» «[parameters]» могут быть либо одним именем, либо списком имен, разделенных запятыми. Параметризованное производство — это сокращение для набора производств, определяющих все комбинации имен параметров, которым предшествует подчеркивание, добавленное к параметризованному нетерминальному символу.
Это означает, что:
StatementList[Return] :
удобное сокращение для:
Ещё вариант обозначения
StatementList[Return, In] :
это сокращение от:
Множественные параметры производят комбинаторное количество продуктов, не все из которых обязательно упоминаются в полной грамматике.
Ссылки на нетерминалы в правой части продукции также могут быть параметризованы. Например:
ExpressionStatement[+In]
эквивалентно высказыванию:
ExpressionStatement_In
и:
ExpressionStatement[~In]
эквивалентно:
Нетерминальная ссылка может иметь как список параметров, так и суффикс «opt«. Например в объявлении переменной:
BindingIdentifier Initializer [+In] opt
это сокращение от:
BindingIdentifier Initializer_In
Добавление к имени параметра префикса «?» с правой стороны нетерминальная ссылка делает это значение параметра зависимым от появления имени параметра в ссылке на левый символ текущего производства.
Например:
VariableDeclaration[In] :
BindingIdentifier Initializer[?In]
это сокращение от:
BindingIdentifier Initializer_In
Если альтернатива с правой стороны имеет префикс «[+parameter]», эта альтернатива доступна только в том случае, если именованный параметр использовался для ссылки на нетерминальный символ продукции.
Если альтернатива с правой стороны имеет префикс «[~parameter]», эта альтернатива доступна только в том случае, если именованный параметр не использовался для ссылки на нетерминальный символ продукции.
Это означает, что:
StatementList[Return] :
[+Return]ReturnStatement
это сокращение от:
и что:
StatementList[Return] :
[~Return]ReturnStatement
это сокращение от:
Когда слова «один из» (one of) следуют за двоеточием в определении грамматики, они означают, что каждый из конечных символов в следующей строке или строках является альтернативным определением.
Например, лексическая грамматика для ECMAScript содержит продукцию:
NonZeroDigit :: one of
1 2 3 4 5 6 7 8 9
что просто удобное сокращение для:
NonZeroDigit ::
1
2
3
4
5
6
7
8
9
Если фраза «[пусто]» ([empty]) появляется в правой части производства, это означает, что правая часть производства не содержит терминалов или нетерминалов.
Если фраза «[lookahead = seq]» появляется в правой части производства, это указывает на то, что производство может использоваться только в том случае, если последовательность маркеров seq является префиксом непосредственно следующей за входной последовательностью маркеров. Точно так же «[lookahead ∈ set]», где set — это конечный непустой набор последовательностей токенов, указывает, что производство может использоваться только в том случае, если некоторый элемент множества является префиксом непосредственно следующей последовательности токенов. Для удобства набор также может быть записан как нетерминал, и в этом случае он представляет собой набор всех последовательностей токенов, до которых этот нетерминал может расширяться. Считается редакционной ошибкой, если нетерминал может расширяться до бесконечного числа различных последовательностей токенов.
Эти условия могут быть отменены. «[Lookahead ≠ seq]» указывает, что содержимое производства может использоваться только в том случае, если seq не является префиксом непосредственно следующей за входной последовательностью токенов, и «[lookahead ∉ set]» указывает, что производство может использоваться, только если НЕ элемент set является префиксом непосредственно следующей за последовательностью токенов.
В качестве примера приведем определения:
DecimalDigit :: one of
0 1 2 3 4 5 6 7 8 9
определение:
n [lookahead ∉ { 1, 3, 5, 7, 9 }] DecimalDigits
DecimalDigit [lookahead ∉ DecimalDigit]
соответствует либо букве n, за которой следует одна или несколько десятичных цифр, первая из которых четная, либо десятичной цифре, за которой не следует другая десятичная цифра.
Обратите внимание, что когда эти фразы используются в синтаксической грамматике, может оказаться невозможным однозначно идентифицировать следующую последовательность токенов, потому что определение последующих токенов требует знания того, какой символ лексической цели использовать в более поздних позициях. Таким образом, когда они используются в синтаксической грамматике, считается редакционной ошибкой появление последовательности токена seq в ограничении опережающего просмотра (в том числе как часть набора последовательностей), если выбор используемых символов лексической цели может измениться. будет ли seq префиксом результирующей последовательности токенов.
Если фраза «[здесь нет LineTerminator]» появляется в правой части синтаксической грамматики, это указывает на то, что производство является «производством с ограничениями»(restricted production): ее нельзя использовать, если LineTerminator встречается во входном потоке в указанное положение. Например, производство:
throw [no LineTerminator here] Expression ;
указывает, что продукция может не быть использована, если в сценарии между токеном выброса throw и выражением Expression встречается LineTerminator.
Если присутствие LineTerminator не запрещено ограниченным производством, любое количество вхождений LineTerminator может появиться между любыми двумя последовательными токенами в потоке входных элементов, не влияя на синтаксическую приемлемость скрипта.
Когда альтернативой при создании лексической грамматики или грамматики числовой строки оказывается токен с несколькими кодовыми точками, он представляет собой последовательность кодовых точек, из которых состоит такой токен.
Правая часть производства может указывать, что определенные расширения не разрешены, используя фразу «но не» (“but not”) и затем указывая расширения, которые должны быть исключены.
Например, производство:
Identifier ::
IdentifierName but not ReservedWord
означает, что нетерминальный идентификатор Identifier может быть заменен любой последовательностью кодовых точек, которая может заменить IdentifierName, при условии, что та же последовательность кодовых точек не может заменить ReservedWord.
Наконец, несколько нетерминальных символов описываются описательной фразой шрифтом без засечек в тех случаях, когда было бы непрактично перечислять все альтернативы:
any Unicode code point
Алгоритмические обозначения
В спецификации часто используется нумерованный список для определения шагов алгоритма. Эти алгоритмы используются для точного определения требуемой семантики языковых конструкций ECMAScript. Алгоритмы не предназначены для использования каких-либо конкретных методов реализации. На практике могут существовать более эффективные алгоритмы для реализации данной функции.
Алгоритмы могут быть явно параметризованы упорядоченной последовательностью псевдонимов, разделенных запятыми, которые могут использоваться на этапах алгоритма для ссылки на аргумент, переданный в этой позиции. Необязательные параметры обозначаются окружающими скобками ([ , name ]) и ничем не отличаются от обязательных параметров в шагах алгоритма. Остаточный параметр может находиться в конце списка параметров, обозначенных ведущим многоточием (, …name). Параметр rest записывает все аргументы, предоставленные после обязательных и дополнительных параметров, в Список. Если таких дополнительных аргументов нет, этот Список пуст.
Шаги алгоритма можно разделить на последовательные подэтапы. Подшаги имеют отступ и сами могут быть разделены на подшаги с отступом. Для идентификации подшагов используются схемы нумерации, при этом первый уровень подшагов помечен строчными буквенными символами, а второй уровень подшагов помечен римскими цифрами в нижнем регистре. Если требуется более трех уровней, эти правила повторяются с четвертым уровнем, используя числовые метки. Например:
1. Top-level step
a. Substep.
b. Substep.
i. Subsubstep.
1. Subsubsubstep
a. Subsubsubsubstep
i. Subsubsubsubsubstep
Шаг или подшаг можно записать как предикат «если»(if), который обуславливает его подшаги. В этом случае подшаги применяются только в том случае, если предикат истинен. Если шаг или подшаг начинается со слова «иначе»(else), это предикат, который является отрицанием предыдущего шага предиката «если»(if) на том же уровне.
Шаг может определять итеративное применение своих подшагов.
Шаг, начинающийся с «Assert:», утверждает неизменное условие его алгоритма. Такие утверждения используются для создания явных алгоритмических инвариантов, которые в противном случае были бы неявными. Такие утверждения не добавляют никаких дополнительных семантических требований и, следовательно, не требуют проверки реализацией. Они используются просто для уточнения алгоритмов.
Шаги алгоритма могут объявлять именованные псевдонимы для любого значения, используя форму «Пусть x будет someValue». Эти псевдонимы похожи на ссылки в том смысле, что и x, и someValue относятся к одним и тем же базовым данным, и модификации любого из них видны обоим. Шаги алгоритма, которые хотят избежать этого ссылочного поведения, должны явно делать копию правой части: «Пусть x будет копией someValue» создает неглубокую копию someValue.
После объявления псевдонима можно ссылаться на любых последующих шагах, и на него нельзя ссылаться с шагов до объявления псевдонима. Псевдонимы могут быть изменены с помощью формы «Установить x на someOtherValue».
Абстрактные операции (Abstract Operations)
Чтобы облегчить их использование в нескольких частях этой спецификации, некоторые алгоритмы, называемые «абстрактными операциями» (abstract operations), именуются и записываются в параметризованной функциональной форме, чтобы на них можно было ссылаться по имени из других алгоритмов. На абстрактные операции обычно ссылаются с использованием функционального стиля приложения, такого как OperationName(arg1, arg2). Некоторые абстрактные операции рассматриваются как полиморфно отправляемые методы абстракций спецификаций, подобных классам. На такие абстрактные операции, подобные методу, обычно ссылаются с использованием стиля приложения метода, такого как someValue.OperationName (arg1, arg2).
Операции, управляемые синтаксисом (Syntax-Directed Operations)
«Синтаксически управляемая операция» (syntax-directed operation) — это именованная операция, определение которой состоит из алгоритмов, каждый из которых связан с одним или несколькими производными одной из грамматик ECMAScript. Производство, которое имеет несколько альтернативных определений, обычно будет иметь отдельный алгоритм для каждой альтернативы. Когда алгоритм связан с производством грамматики, он может ссылаться на конечные и нетерминальные символы альтернативы производства, как если бы они были параметрами алгоритма. При использовании таким образом нетерминальные символы относятся к фактическому альтернативному определению, которое сопоставляется при синтаксическом анализе исходного текста. «Исходный текст, сопоставленный» (source text matched by) с грамматическим производством, — это часть исходного текста, которая начинается в начале первого терминала, участвовавшего в сопоставлении, и заканчивается в конце последнего терминала, участвовавшего в сопоставлении.
Когда алгоритм связан с производственной альтернативой, альтернатива обычно отображается без каких-либо грамматических аннотаций «[]». Такие аннотации должны влиять только на синтаксическое распознавание альтернативы и не влиять на связанную семантику альтернативы.
Операции, управляемые синтаксисом, вызываются с помощью узла синтаксического анализа и, необязательно, других параметров с использованием соглашений на этапах 1, 3 и 4 в следующем алгоритме:
1. Пусть status будет SyntaxDirectedOperation из SomeNonTerminal. 2. Пусть someParseNode будет анализом некоторого исходного текста. 3. Выполните SyntaxDirectedOperation для someParseNode. 4. Выполните SyntaxDirectedOperation для someParseNode, передав значение "value" в качестве аргумента.
Если явно не указано иное, все цепные производства имеют неявное определение для каждой операции, которая может быть применена к левому нетерминалу этой продукции. Неявное определение просто повторно применяет ту же операцию с теми же параметрами, если таковые имеются, к единственному правому нетерминалу цепного производства, а затем возвращает результат. Например, предположим, что у некоторого алгоритма есть шаг формы: «Вернуть результат оценки блока Block» и что существует производство:
Block :
{ StatementList }
но операция Оценки (Evaluation) не связывает алгоритм с этим производством. В этом случае операция Оценки (Evaluation) неявно включает ассоциацию в форме:
Runtime Semantics: Evaluation
Block : { StatementList }
1. Вернуть результат оценки StatementList.
Семантика времени выполнения (Runtime Semantics)
Алгоритмы, определяющие семантику, которая должна вызываться во время выполнения, называются «семантикой времени выполнения» (Runtime Semantics). Семантика времени выполнения определяется абстрактными операциями или операциями, управляемыми синтаксисом. Такие алгоритмы всегда возвращают запись о завершении.
Неявные значения завершения (Implicit Completion Values)
Алгоритмы этой спецификации часто неявно возвращают Записи Завершения, [[Type]] которых является normal
. Если иное не очевидно из контекста, оператор алгоритма, который возвращает значение, не являющееся записью о завершении, например:
1. Вернуть "Infinity".
означает то же, что и:
1. Вернуть NormalCompletion("Infinity").
Однако, если выражение значения оператора «return» является конструкционным литералом Записи Завершения, возвращается результирующая Запись Завершения. Если выражение значения является вызовом абстрактной операции, оператор «return» просто возвращает запись о завершении, созданную абстрактной операцией.
Абстрактная операция Completion(completionRecord) используется, чтобы подчеркнуть, что возвращается ранее вычисленная запись о завершении. Абстрактная операция Completion принимает единственный аргумент, completionRecord, и выполняет следующие шаги:
1. Assert: completionRecord является Completion Record. 2. Return completionRecord as the Completion Record of this abstract operation.
Оператор «return» без значения на шаге алгоритма означает то же самое, что:
1. Вернуть NormalCompletion(undefined).
Любая ссылка на значение Записи Завершения, которая находится в контексте, который явно не требует полного значения Записи Завершения, эквивалентна явной ссылке на поле [[Value]] значения Записи Завершения, если только Запись Завершения не является Внезапным Завершением.
Выбрасывание исключения (Throw an Exception)
Шаги алгоритмов, которые говорят о том, чтобы выбросить исключение, например
1. Вызвать исключение TypeError.
означают то же, что и:
1. Верните ThrowCompletion(вновь созданный объект TypeError).
Возврат, если обрыв (ReturnIfAbrupt)
Шаги алгоритма, которые говорят или иначе эквивалентны:
1. ReturnIfAbrupt(argument).
означает то же самое, что и:
1. Если argument является внезапным завершением, вернуть argument. 2. Иначе, если argument является Записью Завершения, установите argument на argument.[[Value]].
Шаги алгоритма, которые говорят или иначе эквивалентны:
1. ReturnIfAbrupt(AbstractOperation()).
означает то же самое, что и:
1. Пусть hygienicTemp будет AbstractOperation(). 2. Если hygienicTemp является Внезапным Завершением, верните hygienicTemp. 3. Иначе, если hygienicTemp является Записью Завершения, установите hygienicTemp на hygienicTemp.[[Value]].
Где hygienicTemp недолговечен и отображается только на этапах, относящихся к ReturnIfAbrupt.
Шаги алгоритма, которые говорят или иначе эквивалентны:
1. Пусть result будет AbstractOperation(ReturnIfAbrupt(argument)).
означает то же самое, что и:
1. Если argument является внезапным завершением, вернуть argument. 2. Если argument является Записью Завершения, установите argument на argument.[[Value]]. 3. Пусть result будет AbstractOperation(argument).
Возврат, если обрыв — сокращения (ReturnIfAbrupt Shorthands)
Вызов абстрактных операций и операций, управляемых синтаксисом, с префиксом значка вопроса ? указывают, что к результирующей Записи о Завершении следует применить ReturnIfAbrupt. Например, шаг:
1. ? OperationName().
эквивалентен следующему шагу:
1. ReturnIfAbrupt(OperationName()).
Точно так же для стиля приложения метода шаг:
1. ? someValue.OperationName().
эквивалентно:
1. ReturnIfAbrupt(someValue.OperationName()).
Аналогично префикс восклицательного знака ! используется, чтобы указать, что следующий вызов абстрактной или синтаксической операции никогда не вернет внезапное завершение и что результирующее поле Записи Завершения [[Value]] должно использоваться вместо возвращаемого значения операции. Например, шаг:
1. Пусть val будет ! OperationName().
эквивалентен следующим шагам:
1. Пусть val будет OperationName(). 2. Утверждено: val никогда не бывает внезапным завершением. 3. Если val является Записью Завершения, установите для val значение val.[[Value]].
Операции, управляемые синтаксисом для семантики времени выполнения, используют это сокращение, помещая ! или же ? перед вызовом операции:
1. Выполнить ! SyntaxDirectedOperation для NonTerminal.
Статическая семантика (Static Semantics)
Бесконтекстные грамматики не обладают достаточной мощью, чтобы выразить все правила, определяющие, образует ли поток входных элементов действительный Сценарий или Модуль (Script или Module) ECMAScript, который может быть оценен. В некоторых ситуациях требуются дополнительные правила, которые могут быть выражены либо с использованием соглашений об алгоритмах ECMAScript, либо с использованием требований прозы. Такие правила всегда связаны с производством грамматики и называются «статической семантикой» (static semantics) производства.
Статические семантические правила имеют имена и обычно определяются с помощью алгоритма. Именованные статические семантические правила связаны с грамматическими произведениями, и продукция, имеющая несколько альтернативных определений, обычно будет иметь для каждой альтернативы отдельный алгоритм для каждого применимого именованного статического семантического правила.
Особый вид статического семантического правила — это «правило ранней ошибки» (Early Error Rule). Правила ранней ошибки определяют условия ранней ошибки (см. Раздел 17), которые связаны с конкретными грамматическими произведениями. Оценка наиболее ранних правил ошибок не вызывается явно в алгоритмах этой спецификации. Соответствующая реализация должна перед первой оценкой Сценария или Модуля (Script или Module) проверить все правила производств ранних ошибок, используемых для синтаксического анализа этого сценария или модуля. Если какое-либо из правил ранней ошибки нарушено, Сценарий или Модуль (Script или Module) недействительны и не могут быть оценены.
Математические операции (Mathematical Operations)
Эта спецификация ссылается на следующие виды числовых значений:
- Математические значения (Mathematical values): произвольные действительные числа, используемые в качестве числового типа по умолчанию.
- Расширенные математические значения (Extended mathematical values): математические значения вместе с +∞ и -∞.
- Числа (Numbers): значения с плавающей запятой двойной точности IEEE 754-2019.
- Большие целые числа (BigInts): значения ECMAScript, представляющие произвольные целые числа во взаимно-однозначном соответствии.
На языке данной спецификации числовые значения различаются среди различных числовых типов с помощью суффиксов нижнего индекса. Нижний индекс 𝔽 относится к числам, а нижний индекс ℤ относится к BigInts. Числовые значения без суффикса нижнего индекса относятся к математическим значениям.
Числовые операторы, такие как +, ×, = и ≥, относятся к этим операциям, как определено типом операндов. Применительно к математическим значениям операторы относятся к обычным математическим операциям. Применительно к Numbers операторы ссылаются на соответствующие операции в IEEE 754-2019. Применительно к BigInts операторы относятся к обычным математическим операциям, применяемым к математическому значению BigInt.
Как правило, когда эта спецификация относится к числовому значению, например, во фразе «длина y» или «целое число, представленное четырьмя шестнадцатеричными цифрами …», без явного указания числового вида, фраза относится к математическому значению. Фразы, которые относятся к Number или значению BigInt, явно аннотируются как таковые; например, «Числовое значение для количества кодовых точек в…» или «значение BigInt для…».
Числовые операторы, применяемые к операндам смешанного типа (таким как Число и математическое значение), не определены и должны рассматриваться в данной спецификации как редакционная ошибка.
Эта спецификация обозначает большинство числовых значений в «base 10»; она также использует числовые значения формы «0x», за которыми следуют цифры 0-9 или буквы A-F в качестве значений с основанием 16 (base-16).
Когда термин «целое«(integer) используется в этой спецификации, он относится к математическому значению, которое находится в наборе целых чисел, если не указано иное. Когда в данной спецификации используется термин «целое число» (integral Number), он относится к Числовому значению, математическое значение которого находится в наборе целых чисел.
Преобразования между Математическими Значениями и Числами или BigInts всегда явным образом указаны в этом документе.
Преобразование математического значения или расширенного математического значения x в число обозначается как «Числовое значение для x» или 𝔽(x) и определено в пункте 6.1.6.1.
Преобразование целого x в BigInt обозначается как «значение BigInt для x» или ℤ(x).
Преобразование Number или BigInt x в математическое значение обозначается как «математическое значение x» или ℝ(x).
Математическое значение +0𝔽 и -0𝔽 является математическим значением 0. Математическое значение «не-конечных» значений не определено. Расширенное математическое значение (extended mathematical value) x является математическим значением x для конечных значений и равно +∞ и -∞ для +∞𝔽 и -∞𝔽 соответственно; это не определено для NaN.
Математическая функция abs(x) выдает абсолютное значение x, которое равно —x, если x <0, и в противном случае является самим x.
Математическая функция min(x1, x2,…, xN) производит математически наименьшее из значений от x1 до xN. Математическая функция max(x1, x2, …, xN) производит математически наибольшее из значений от x1 до xN. Область и диапазон этих математических функций представляют собой расширенные математические значения.
Обозначение «x по модулю y» (y должно быть конечным и отличным от нуля) вычисляет значение k того же знака, что и y (или ноль), так что abs(k) < abs(y) и x — k = q × y для некоторого целого q.
Фраза «результат зажатия(clamping) x между нижним lower и верхним upper» (где x — расширенное математическое значение, а lower и upper — математические значения, такие, что lower ≤ upper) дает значение «lower», если x < lower, дает upper, если x > upper, и в противном случае производит x.
Математическая функция floor(x) дает наибольшее целое (ближайшее к +∞), которое не превышает x.
Математические функции min, max, abs и floor не определены для Numbers и BigInts, и любое использование тех методов, которые имеют аргументы нематематического значения, было бы редакционной ошибкой в этой спецификации.
Обозначение Значения (Value Notation)
В этой спецификации значения языка ECMAScript выделены жирным шрифтом. Примеры включают null, true или «hello«. Они отличаются от более длинных последовательностей кода ECMAScript, таких как Function.prototype.apply
или let n = 42;
.
Значения, которые являются внутренними для спецификации и не наблюдаются напрямую из кода ECMAScript, обозначаются шрифтом без засечек (sans-serif
). Например, поле [[Type]] записи о завершении принимает такие значения, как normal
, return
или throw
.
Информационные ссылки
Стандарт ECMAScript — Раздел «5.1 Syntactic and Lexical Grammars» — https://tc39.es/ecma262/#sec-syntactic-and-lexical-grammars
Стандарт ECMAScript — Раздел «5.2 Algorithm Conventions» — https://tc39.es/ecma262/#sec-algorithm-conventions