5.1 구문 문법과 어휘 문법
5.1.1 문맥 자유 문법
문맥 자유 문법은 여러 생성 규칙으로 구성됩니다. 각 생성 규칙은 비단말 기호라고 하는 추상 기호를 좌변으로 가지며, 0개 이상의 비단말 기호와 단말 기호의 시퀀스를 우변으로 갖습니다. 각 문법의 단말 기호는 지정된 알파벳에서 선택됩니다.
연쇄 생성 규칙은 우변에 0개 이상의 단말 기호와 함께 정확히 하나의 비단말 기호를 갖는 생성 규칙입니다.
주어진 문맥 자유 문법은 목표 기호라고 하는 하나의 특별한 비단말 기호로 구성된 문장에서 시작하여 언어를 지정합니다. 이 언어는 시퀀스의 임의의 비단말 기호를 해당 비단말 기호가 좌변인 생성 규칙의 우변으로 반복해서 대체하여 얻을 수 있는 단말 기호 시퀀스들의 집합이며, 이 집합은 무한할 수도 있습니다.
5.1.2 어휘 문법과 RegExp 문법
ECMAScript의 어휘 문법은 절 12에 제시되어 있습니다. 이 문법은 11.1에 정의된 SourceCharacter 규칙을 따르는 유니코드 코드 포인트를 단말 기호로 갖습니다. 이 문법은 목표 기호 InputElementDiv, InputElementTemplateTail, InputElementRegExp, InputElementRegExpOrTemplateTail 또는 InputElementHashbangOrRegExp에서 시작하는 생성 규칙의 집합을 정의하며, 이러한 코드 포인트의 시퀀스가 입력 요소의 시퀀스로 변환되는 방법을 설명합니다.
공백과 주석을 제외한 입력 요소는 ECMAScript 구문 문법의 단말 기호를 구성하며, ECMAScript 토큰이라고 합니다. 이러한 토큰은 ECMAScript 언어의 예약어, 식별자, 리터럴 및 구두점 기호입니다. 또한 줄 종결자는 토큰으로 간주되지는 않지만 입력 요소 스트림의 일부가 되어 자동 세미콜론 삽입 과정(12.10)을 안내합니다. 단순 공백과 한 줄 주석은 버려지며 구문 문법의 입력 요소 스트림에 나타나지 않습니다. MultiLineComment(즉, 여러 줄에 걸쳐 있는지와 관계없이 /*…*/ 형식의 주석)도 줄 종결자를 포함하지 않으면 단순히 버려집니다. 그러나 MultiLineComment가 하나 이상의 줄 종결자를 포함하면 단일 줄 종결자로 대체되며, 이 줄 종결자는 구문 문법의 입력 요소 스트림의 일부가 됩니다.
ECMAScript의 RegExp 문법은 22.2.1에 제시되어 있습니다. 이 문법 역시 SourceCharacter로 정의되는 코드 포인트를 단말 기호로 갖습니다. 이 문법은 목표 기호 Pattern에서 시작하는 생성 규칙의 집합을 정의하며, 코드 포인트의 시퀀스가 정규 표현식 패턴으로 변환되는 방법을 설명합니다.
어휘 문법과 RegExp 문법의 생성 규칙은 구분 기호로 두 개의 콜론 “::”을 사용하여 구별합니다. 어휘 문법과 RegExp 문법은 일부 생성 규칙을 공유합니다.
5.1.3 숫자 문자열 문법
숫자 문자열 문법은 7.1.4.1에 제시되어 있습니다. 이 문법은 SourceCharacter를 단말 기호로 가지며, 목표 기호 StringNumericLiteral에서 시작하여 String을 숫자 값으로 변환하는 데 사용됩니다. 이는 숫자 리터럴의 어휘 문법과 유사하지만 서로 다릅니다.
숫자 문자열 문법의 생성 규칙은 구분 기호로 세 개의 콜론 “:::”을 사용하여 구별하며, 소스 텍스트를 파싱하는 데는 사용하지 않습니다.
5.1.4 구문 문법
ECMAScript의 구문 문법은 절 13부터 16까지에 제시되어 있습니다. 이 문법은 어휘 문법에서 정의한 ECMAScript 토큰을 단말 기호로 갖습니다(5.1.2). 이 문법은 두 가지 대안적인 목표 기호 Script와 Module에서 시작하는 생성 규칙의 집합을 정의하며, 토큰 시퀀스가 ECMAScript 프로그램의 구문적으로 올바른 독립 구성 요소를 형성하는 방법을 설명합니다.
코드 포인트 스트림을 ECMAScript Script 또는 Module로 파싱할 때는 먼저 어휘 문법을 반복 적용하여 입력 요소 스트림으로 변환합니다. 그런 다음 구문 문법을 한 번 적용하여 이 입력 요소 스트림을 파싱합니다. 입력 요소 스트림의 토큰을 남는 토큰 없이 목표 비단말 기호(Script 또는 Module)의 단일 인스턴스로 파싱할 수 없다면 입력 스트림에는 구문 오류가 있습니다.
파싱에 성공하면 각 노드가 파스 노드인 루트가 있는 트리 구조인 파스 트리를 구성합니다. 각 파스 노드는 문법 기호의 인스턴스이며, 해당 기호로부터 유도할 수 있는 소스 텍스트 구간을 나타냅니다. 전체 소스 텍스트를 나타내는 파스 트리의 루트 노드는 파싱 목표 기호의 인스턴스입니다. 파스 노드가 비단말 기호의 인스턴스이면, 해당 비단말 기호를 좌변으로 갖는 어떤 생성 규칙의 인스턴스이기도 합니다. 또한 이 노드는 생성 규칙 우변의 각 기호에 하나씩 대응하는 0개 이상의 자식을 갖습니다. 각 자식은 해당 기호의 인스턴스인 파스 노드입니다.
파서를 호출할 때마다 새로운 파스 노드를 생성하며, 동일한 소스 텍스트를 파싱하더라도 서로 다른 파싱 사이에서 재사용하지 않습니다. 파스 노드가 동일한 소스 텍스트 구간을 나타내고, 동일한 문법 기호의 인스턴스이며, 동일한 파서 호출에서 생성된 경우에만 동일한 파스 노드로 간주합니다.
참고 1
동일한 String을 여러 번 파싱하면 서로 다른 파스 노드가 생성됩니다. 예를 들어 다음을 고려하시기 바랍니다:
let str = "1 + 1;";
eval(str);
eval(str);
각 eval 호출은 str의 값을 ECMAScript 소스 텍스트로 변환하고 독립적으로 파싱하여 별도의 파스 노드 트리를 생성합니다. 각 파싱이 동일한 String 값에서 유래한 소스 텍스트에 대해 수행되더라도 트리는 서로 다릅니다.
참고 2파스 노드는 명세상의 구성 요소이며, 구현체가 유사한 데이터 구조를 사용할 필요는 없습니다.
구문 문법의 생성 규칙은 구분 기호로 하나의 콜론 “:”만 사용하여 구별합니다.
절 13부터 16까지에 제시된 구문 문법은 어떤 토큰 시퀀스가 올바른 ECMAScript Script 또는 Module로 허용되는지를 완전히 설명하지는 않습니다. 특정 추가 토큰 시퀀스도 허용됩니다. 즉, 시퀀스의 특정 위치(예: 줄 종결자 문자 앞)에 세미콜론을 추가하기만 하면 문법으로 설명할 수 있는 시퀀스도 허용됩니다. 또한 문법으로 설명되는 특정 토큰 시퀀스라도 줄 종결자 문자가 특정 “부적절한” 위치에 나타나면 허용되지 않는 것으로 간주됩니다.
특정 경우에는 모호성을 피하기 위해 구문 문법이 유효한 ECMAScript Script 또는 Module을 형성하지 않는 토큰 시퀀스도 허용하는 일반화된 생성 규칙을 사용합니다. 예를 들어 객체 리터럴과 객체 구조 분해 패턴에 이 기법을 사용합니다. 이러한 경우에는 허용되는 토큰 시퀀스를 추가로 제한하는 더 엄격한 보충 문법을 제공합니다. 일반적으로 조기 오류 규칙은 특정 문맥에서 “p는 n을 포괄해야 합니다”라고 명시합니다. 여기에서 p는 파스 노드(일반화된 생성 규칙의 인스턴스)이며, n은 보충 문법의 비단말 기호입니다. 이는 다음을 의미합니다:
- p 또는 그 하위 노드에는 어떠한 조기 오류 규칙도 적용하지 않습니다.
- 원래 p에 일치했던 토큰 시퀀스를 n을 목표 기호로 사용하여 다시 파싱합니다. n이 문법 매개변수를 받으면, 해당 매개변수는 p를 처음 파싱할 때 사용한 값과 동일하게 설정합니다.
- 남는 토큰 없이 토큰 시퀀스를 n의 단일 인스턴스로 파싱할 수 있으면:
- 해당 n의 인스턴스(주어진 p에 대해 고유한 파스 노드)를 “p에 의해 포괄되는 n”이라고 합니다.
- 추가적인 “포괄해야 합니다”의 경우에 따라 수정된 조기 오류 규칙을 p에 의해 포괄되는 n과 그 하위 노드에 적용합니다.
- 그렇지 않으면(파싱에 실패하면) 조기 구문 오류입니다.
5.1.5 문법 표기법
5.1.5.1 단말 기호
ECMAScript 문법에서 일부 단말 기호는 고정폭 글꼴로 표시됩니다. 이러한 기호는 소스 텍스트에 작성된 그대로 나타나야 합니다. 이 방식으로 명시된 모든 단말 기호의 코드 포인트는 다른 유니코드 범위의 비슷하게 생긴 코드 포인트가 아니라 기본 라틴 블록의 해당 유니코드 코드 포인트로 이해해야 합니다. 단말 기호의 코드 포인트는 \ UnicodeEscapeSequence로 표현할 수 없습니다.
단말 기호가 개별 유니코드 코드 포인트인 문법(즉, 어휘 문법, RegExp 문법 및 숫자 문자열 문법)에서 생성 규칙에 연속해서 나타나는 여러 고정폭 코드 포인트는 동일한 코드 포인트 시퀀스를 각각 독립된 단말 기호로 작성한 것의 간단한 축약 표현입니다.
예를 들어 다음 생성 규칙은:
HexIntegerLiteral ::
0x
HexDigits
다음의 축약 표현입니다:
HexIntegerLiteral ::
0
x
HexDigits
반면 구문 문법에서는 연속된 고정폭 코드 포인트가 하나의 단말 기호입니다.
단말 기호에는 다음과 같은 두 가지 다른 형식도 있습니다:
5.1.5.2 비단말 기호와 생성 규칙
비단말 기호는 기울임꼴로 표시됩니다. 비단말 기호의 정의(“생성 규칙”이라고도 함)는 정의할 비단말 기호의 이름과 그 뒤에 오는 하나 이상의 콜론으로 시작합니다. (콜론의 개수는 생성 규칙이 속하는 문법을 나타냅니다.) 그다음 줄에는 해당 비단말 기호의 대안적인 우변이 하나 이상 이어집니다. 예를 들어 다음 구문 정의는:
WhileStatement :
while
(
Expression
)
Statement
비단말 기호 WhileStatement가 while 토큰, 여는 괄호 토큰, Expression, 닫는 괄호 토큰, Statement가 차례로 이어지는 것을 나타낸다고 명시합니다. 여기에 나타나는 Expression과 Statement 자체도 비단말 기호입니다. 다른 예로, 다음 구문 정의는:
ArgumentList :
AssignmentExpression
ArgumentList
,
AssignmentExpression
ArgumentList가 단일 AssignmentExpression 또는 ArgumentList 뒤에 쉼표와 AssignmentExpression이 차례로 이어지는 것을 나타낼 수 있다고 명시합니다. 이러한 ArgumentList의 정의는 재귀적입니다. 즉, 자기 자신을 사용하여 정의됩니다. 그 결과 ArgumentList는 쉼표로 구분된 임의의 양수 개의 인수를 포함할 수 있으며, 각 인수 표현식은 AssignmentExpression입니다. 이러한 비단말 기호의 재귀적 정의는 흔히 사용됩니다.
5.1.5.3 선택적 기호
단말 기호 또는 비단말 기호 뒤에 나타날 수 있는 아래첨자 접미사 “opt”는 선택적 기호를 나타냅니다. 선택적 기호를 포함하는 대안은 실제로 두 개의 우변을 지정합니다. 하나는 선택적 요소를 생략하고, 다른 하나는 이를 포함합니다. 즉, 다음은:
VariableDeclaration :
BindingIdentifier
Initializeropt
다음을 편리하게 축약한 표현입니다:
VariableDeclaration :
BindingIdentifier
BindingIdentifier
Initializer
또한 다음은:
ForStatement :
for
(
LexicalDeclaration
Expressionopt
;
Expressionopt
)
Statement
다음을 편리하게 축약한 표현입니다:
ForStatement :
for
(
LexicalDeclaration
;
Expressionopt
)
Statement
for
(
LexicalDeclaration
Expression
;
Expressionopt
)
Statement
이 표현은 다시 다음의 축약 표현입니다:
ForStatement :
for
(
LexicalDeclaration
;
)
Statement
for
(
LexicalDeclaration
;
Expression
)
Statement
for
(
LexicalDeclaration
Expression
;
)
Statement
for
(
LexicalDeclaration
Expression
;
Expression
)
Statement
따라서 이 예에서 비단말 기호 ForStatement에는 실제로 네 개의 대안적인 우변이 있습니다.
5.1.5.4 문법 매개변수
생성 규칙은 “[parameters]” 형식의 아래첨자 주석으로 매개변수화할 수 있으며, 이 주석은 해당 생성 규칙에서 정의하는 비단말 기호의 접미사로 나타날 수 있습니다. “parameters”는 단일 이름 또는 쉼표로 구분된 이름 목록일 수 있습니다. 매개변수화된 생성 규칙은 매개변수 이름 앞에 밑줄을 붙여 매개변수화된 비단말 기호에 추가한 모든 조합을 정의하는 생성 규칙 집합의 축약 표현입니다. 즉, 다음은:
StatementList[Return] :
ReturnStatement
ExpressionStatement
다음을 편리하게 축약한 표현입니다:
StatementList :
ReturnStatement
ExpressionStatement
StatementList_Return :
ReturnStatement
ExpressionStatement
또한 다음은:
StatementList[Return, In] :
ReturnStatement
ExpressionStatement
다음의 축약 표현입니다:
StatementList :
ReturnStatement
ExpressionStatement
StatementList_Return :
ReturnStatement
ExpressionStatement
StatementList_In :
ReturnStatement
ExpressionStatement
StatementList_Return_In :
ReturnStatement
ExpressionStatement
여러 매개변수는 조합에 따른 수의 생성 규칙을 만들어 내며, 완전한 문법에서 이러한 생성 규칙이 모두 참조되는 것은 아닙니다.
생성 규칙 우변의 비단말 기호에 대한 참조도 매개변수화할 수 있습니다. 예를 들어:
StatementList :
ReturnStatement
ExpressionStatement[+In]
다음과 같이 표현하는 것과 같습니다:
StatementList :
ReturnStatement
ExpressionStatement_In
또한:
StatementList :
ReturnStatement
ExpressionStatement[~In]
다음과 같습니다:
StatementList :
ReturnStatement
ExpressionStatement
비단말 기호 참조에는 매개변수 목록과 “opt” 접미사가 모두 있을 수 있습니다. 예를 들어:
VariableDeclaration :
BindingIdentifier
Initializer[+In]opt
다음의 축약 표현입니다:
VariableDeclaration :
BindingIdentifier
BindingIdentifier
Initializer_In
우변의 비단말 기호 참조에서 매개변수 이름 앞에 “?”를 붙이면 해당 매개변수 값은 현재 생성 규칙의 좌변 기호에 대한 참조에 그 매개변수 이름이 나타나는지에 따라 달라집니다. 예를 들어:
VariableDeclaration[In] :
BindingIdentifier
Initializer[?In]
다음의 축약 표현입니다:
VariableDeclaration :
BindingIdentifier
Initializer
VariableDeclaration_In :
BindingIdentifier
Initializer_In
대안적인 우변 앞에 “[+parameter]”가 붙으면, 생성 규칙의 비단말 기호를 참조할 때 해당 이름의 매개변수를 사용한 경우에만 그 대안을 사용할 수 있습니다. 대안적인 우변 앞에 “[~parameter]”가 붙으면, 생성 규칙의 비단말 기호를 참조할 때 해당 이름의 매개변수를 사용하지 않은 경우에만 그 대안을 사용할 수 있습니다. 즉, 다음은:
StatementList[Return] : [+Return]
ReturnStatement
ExpressionStatement
다음의 축약 표현입니다:
StatementList :
ExpressionStatement
StatementList_Return :
ReturnStatement
ExpressionStatement
또한 다음은:
StatementList[Return] : [~Return]
ReturnStatement
ExpressionStatement
다음의 축약 표현입니다:
StatementList :
ReturnStatement
ExpressionStatement
StatementList_Return :
ExpressionStatement
5.1.5.5 one of
문법 정의의 콜론 뒤에 “one of”라는 문구가 오면, 다음 한 줄 또는 여러 줄에 있는 각 단말 기호가 대안적인 정의임을 나타냅니다. 예를 들어 ECMAScript의 어휘 문법에는 다음 생성 규칙이 포함됩니다:
BinaryDigit :: one of 0 1
이는 단지 다음을 편리하게 축약한 표현입니다:
BinaryDigit ::
0
1
5.1.5.6 [empty]
생성 규칙의 우변에 “[empty]”라는 문구가 나타나면, 해당 생성 규칙의 우변에 단말 기호나 비단말 기호가 없음을 나타냅니다.
5.1.5.7 미리 보기 제한
생성 규칙의 우변에 “[lookahead = seq]”라는 문구가 나타나면, 토큰 시퀀스 seq가 바로 뒤에 오는 입력 토큰 시퀀스의 접두 시퀀스인 경우에만 해당 생성 규칙을 사용할 수 있음을 나타냅니다. 마찬가지로 “[lookahead ∈ set]”는 set이 토큰 시퀀스의 비어 있지 않은 유한 집합일 때, set의 어떤 요소가 바로 뒤에 오는 토큰 시퀀스의 접두 시퀀스인 경우에만 해당 생성 규칙을 사용할 수 있음을 나타냅니다. 편의를 위해 집합을 비단말 기호로 작성할 수도 있으며, 이 경우에는 해당 비단말 기호가 전개될 수 있는 모든 토큰 시퀀스의 집합을 나타냅니다. 해당 비단말 기호가 무한히 많은 서로 다른 토큰 시퀀스로 전개될 수 있다면 편집 오류로 간주합니다.
이러한 조건은 부정할 수 있습니다. “[lookahead ≠ seq]”는 seq가 바로 뒤에 오는 입력 토큰 시퀀스의 접두 시퀀스가 아닌 경우에만 이를 포함하는 생성 규칙을 사용할 수 있음을 나타냅니다. “[lookahead ∉ set]”는 set의 어떤 요소도 바로 뒤에 오는 토큰 시퀀스의 접두 시퀀스가 아닌 경우에만 해당 생성 규칙을 사용할 수 있음을 나타냅니다.
예를 들어 다음 정의가 주어지면:
DecimalDigit :: one of 0 1 2 3 4 5 6 7 8 9
DecimalDigits ::
DecimalDigit
DecimalDigits
DecimalDigit
다음 정의는:
LookaheadExample ::
n
[lookahead ∉ { 1, 3, 5, 7, 9 }]
DecimalDigits
DecimalDigit
[lookahead ∉ DecimalDigit]
문자 n 뒤에 첫 번째 숫자가 짝수인 하나 이상의 십진 숫자가 이어지는 경우 또는 뒤에 다른 십진 숫자가 이어지지 않는 하나의 십진 숫자와 일치합니다.
이러한 문구를 구문 문법에서 사용하는 경우, 이후 토큰을 결정하려면 이후 위치에서 어떤 어휘 목표 기호를 사용할지 알아야 하므로 바로 뒤에 오는 토큰 시퀀스를 모호함 없이 식별할 수 없을 수 있습니다. 따라서 구문 문법에서 이를 사용할 때, 사용할 어휘 목표 기호의 선택에 따라 토큰 시퀀스 seq가 결과 토큰 시퀀스의 접두 시퀀스인지 여부가 달라질 수 있다면 seq를 미리 보기 제한에 사용하는 것은 편집 오류로 간주합니다. 여기에는 시퀀스 집합의 일부로 사용하는 경우도 포함됩니다.
구문 문법의 생성 규칙 우변에 “[no LineTerminator here]”라는 문구가 나타나면, 해당 생성 규칙이 제한된 생성 규칙임을 나타냅니다. 표시된 위치의 입력 스트림에 LineTerminator가 있으면 해당 생성 규칙을 사용할 수 없습니다. 예를 들어 다음 생성 규칙은:
ThrowStatement :
throw
[no LineTerminator here]
Expression
;
스크립트의 throw 토큰과 Expression 사이에 LineTerminator가 있으면 해당 생성 규칙을 사용할 수 없음을 나타냅니다.
제한된 생성 규칙에서 LineTerminator의 존재를 금지하지 않는 한, 입력 요소 스트림에서 연속된 두 토큰 사이에는 임의의 개수의 LineTerminator가 나타날 수 있으며, 이는 스크립트의 구문적 허용 여부에 영향을 주지 않습니다.
5.1.5.9 but not
생성 규칙의 우변에서는 “but not”이라는 문구를 사용한 다음 제외할 전개를 표시하여 특정 전개가 허용되지 않음을 명시할 수 있습니다. 예를 들어 다음 생성 규칙은:
Identifier ::
IdentifierName but not ReservedWord
비단말 기호 Identifier를 IdentifierName을 대체할 수 있는 임의의 코드 포인트 시퀀스로 대체할 수 있음을 의미합니다. 단, 동일한 코드 포인트 시퀀스로 ReservedWord를 대체할 수 없어야 합니다.
5.1.5.10 설명 문구
마지막으로, 모든 대안을 나열하기 어려운 경우에는 일부 비단말 기호를 산세리프 글꼴의 설명 문구로 기술합니다:
SourceCharacter ::
any Unicode code point
5.2 알고리즘 관례
이 명세는 알고리즘의 단계를 명시하기 위해 번호가 매겨진 목록을 자주 사용합니다. 이러한 알고리즘은 ECMAScript 언어 구문 요소에 요구되는 의미를 정확하게 명시하는 데 사용됩니다. 알고리즘은 특정 구현 기법의 사용을 암시하려는 것이 아닙니다. 실제로는 주어진 기능을 구현하는 데 더 효율적인 알고리즘이 있을 수 있습니다.
알고리즘은 쉼표로 구분된 순서 있는 별칭 이름의 시퀀스를 사용하여 명시적으로 매개변수화할 수 있습니다. 이러한 이름은 알고리즘 단계 내에서 해당 위치로 전달된 인수를 참조하는 데 사용할 수 있습니다. 선택적 매개변수는 대괄호로 둘러싸서 표시하며([ , name ]), 알고리즘 단계 내에서는 필수 매개변수와 다르지 않습니다. 나머지 매개변수는 매개변수 목록의 끝에 나타날 수 있으며, 앞에 줄임표를 붙여 표시합니다(, ...name). 나머지 매개변수는 필수 매개변수와 선택적 매개변수 뒤에 제공된 모든 인수를 List로 수집합니다. 이러한 추가 인수가 없으면 해당 List는 비어 있습니다.
알고리즘 단계는 순차적인 하위 단계로 세분할 수 있습니다. 하위 단계는 들여쓰며, 하위 단계 자체도 들여쓴 하위 단계로 더 세분할 수 있습니다. 하위 단계는 개요 번호 매기기 관례로 식별하며, 첫 번째 수준의 하위 단계에는 소문자 알파벳을, 두 번째 수준의 하위 단계에는 소문자 로마 숫자를 붙입니다. 세 수준보다 더 많은 수준이 필요하면 네 번째 수준에서 숫자를 사용하면서 이 규칙을 반복합니다. 예를 들어:
- 최상위 단계
- 하위 단계.
- 하위 단계.
- 하위 단계의 하위 단계.
- 하위 단계의 하위 단계의 하위 단계
- 하위 단계의 하위 단계의 하위 단계의 하위 단계
- 하위 단계의 하위 단계의 하위 단계의 하위 단계의 하위 단계
단계 또는 하위 단계는 그 하위 단계의 적용 조건을 지정하는 “만약” 술어로 작성할 수 있습니다. 이 경우 하위 단계는 해당 술어가 참일 때만 적용됩니다. 단계 또는 하위 단계가 “그렇지 않으면”이라는 말로 시작하면, 같은 수준에서 앞선 “만약” 술어 단계의 부정에 해당하는 술어입니다.
단계는 하위 단계의 반복 적용을 명시하기 위해 “각각에 대해” 또는 “반복”으로 시작할 수 있습니다.
“단언:”으로 시작하는 단계는 해당 알고리즘의 불변 조건을 단언합니다. 이러한 단언은 그렇지 않으면 암묵적일 알고리즘의 불변 조건을 명시적으로 드러내는 데 사용됩니다. 마찬가지로 “참고:”로 시작하는 단계는 인접한 단계와 관련된 문맥을 제공합니다. 단언 단계와 참고 단계는 순전히 정보 제공용입니다. 추가적인 의미적 요구 사항을 부과하지 않으므로 구현체가 검사할 필요가 없습니다.
알고리즘 단계는 “x를 someValue로 둡니다”라는 형식을 사용하여 임의의 값에 대해 이름 있는 별칭을 선언할 수 있습니다. 이러한 별칭은 x와 someValue가 동일한 기반 데이터를 참조하고 어느 쪽을 수정하든 양쪽 모두에서 보인다는 점에서 참조와 유사합니다. 이러한 참조 유사 동작을 피하려는 알고리즘 단계는 우변의 복사본을 명시적으로 만들어야 합니다. “x를 someValue의 복사본으로 둡니다”는 someValue의 얕은 복사본을 생성합니다.
별칭은 선언된 이후의 모든 단계에서 참조할 수 있으며, 선언 이전의 단계에서는 참조해서는 안 됩니다. 별칭은 “x를 someOtherValue로 설정합니다”라는 형식으로 수정할 수 있습니다.
5.2.1 평가 순서
알고리즘 단계에 복합 표현식이 나타나면, 왼쪽에서 오른쪽으로, 안쪽에서 바깥쪽으로 평가되는 것으로 이해해야 합니다. 예를 들어 다음 단계는
- A(B(), C.[[D]]) + E(F())를 반환합니다.
다음과 같습니다
- tmp1을 B()로 둡니다.
- tmp2를 C.[[D]]로 둡니다.
- tmp3을 A(tmp1, tmp2)로 둡니다.
- tmp4를 F()로 둡니다.
- tmp5를 E(tmp4)로 둡니다.
- tmp6을 tmp3 + tmp5로 둡니다.
- tmp6을 반환합니다.
여기에서 각 tmpN 별칭은 일시적이며 이 단계들에서만 보입니다.
5.2.2 추상 연산
이 명세의 여러 부분에서 쉽게 사용할 수 있도록 일부 알고리즘에는 이름을 붙이고 매개변수화된 함수 형식으로 작성하여 다른 알고리즘 내에서 이름으로 참조할 수 있게 합니다. 이러한 알고리즘을 추상 연산이라고 합니다. 추상 연산은 일반적으로 OperationName(arg1, arg2)과 같은 함수 적용 형식으로 참조합니다. 일부 추상 연산은 클래스와 유사한 명세 추상화의 다형적으로 디스패치되는 메서드로 취급됩니다. 이러한 메서드 유사 추상 연산은 일반적으로 someValue.OperationName(arg1, arg2)과 같은 메서드 적용 형식으로 참조합니다.
5.2.3 구문 지향 연산
구문 지향 연산은 이름이 있는 연산으로, 그 정의는 각각 ECMAScript 문법 중 하나의 생성 규칙 하나 이상과 연결된 알고리즘으로 구성됩니다. 여러 대안적인 정의를 갖는 생성 규칙에는 일반적으로 각 대안에 대해 별도의 알고리즘이 있습니다. 알고리즘이 문법 생성 규칙과 연결되면 해당 생성 규칙 대안의 단말 기호와 비단말 기호를 알고리즘의 매개변수처럼 참조할 수 있습니다. 이 방식으로 사용하는 비단말 기호는 소스 텍스트를 파싱할 때 일치하는 실제 대안 정의를 가리킵니다. 문법 생성 규칙 또는 그로부터 파생된 파스 노드에 일치하는 소스 텍스트는 일치에 참여한 첫 번째 단말 기호의 시작에서 일치에 참여한 마지막 단말 기호의 끝까지에 해당하는 소스 텍스트 부분입니다.
알고리즘이 생성 규칙의 대안과 연결되면 해당 대안은 일반적으로 “[ ]” 문법 주석 없이 표시됩니다. 이러한 주석은 대안의 구문적 인식에만 영향을 미쳐야 하며, 해당 대안에 연결된 의미에는 영향을 주지 않아야 합니다.
구문 지향 연산은 다음 알고리즘의 단계 1, 3 및 4에 있는 관례를 사용하여 파스 노드와 선택적인 추가 매개변수로 호출합니다:
- status를 SomeNonTerminal의 SyntaxDirectedOperation으로 둡니다.
- someParseNode를 어떤 소스 텍스트의 파싱 결과로 둡니다.
- someParseNode의 SyntaxDirectedOperation을 수행합니다.
- someParseNode의 SyntaxDirectedOperation을 인수 "value"로 수행합니다.
명시적으로 달리 지정하지 않는 한, 모든 연쇄 생성 규칙에는 해당 생성 규칙의 좌변 비단말 기호에 적용할 수 있는 모든 연산에 대한 암묵적인 정의가 있습니다. 이 암묵적인 정의는 동일한 연산을 동일한 매개변수(있는 경우)와 함께 연쇄 생성 규칙의 유일한 우변 비단말 기호에 다시 적용한 다음 결과를 반환합니다. 예를 들어 어떤 알고리즘에 “Block의 Evaluation을 반환합니다”라는 형식의 단계가 있고 다음 생성 규칙이 있다고 가정합니다:
Block :
{
StatementList
}
그러나 Evaluation 연산이 해당 생성 규칙에 알고리즘을 연결하지 않았다고 가정합니다. 이 경우 Evaluation 연산에는 다음 형식의 연결이 암묵적으로 포함됩니다:
Runtime Semantics: Evaluation
Block :
{
StatementList
}
- StatementList의 Evaluation을 반환합니다.
5.2.4 런타임 의미론
런타임에 호출해야 하는 의미를 명시하는 알고리즘을 런타임 의미론이라고 합니다. 런타임 의미론은 추상 연산 또는 구문 지향 연산으로 정의됩니다.
5.2.4.1 Completion ( completionRecord )
추상 연산 Completion. 인수 completionRecord (완료 레코드). 반환값: 완료 레코드. Completion Record가 반환된다는 점을 강조하는 데 사용됩니다. 호출되면 다음 단계를 수행한다.
- 단언: completionRecord는 Completion Record입니다.
- completionRecord를 반환합니다.
5.2.4.2 예외 던지기
알고리즘 단계에서 “던집니다”라는 말은 ThrowCompletion을 호출한 결과를 반환하는 것의 축약 표현입니다. 예를 들어,
- 만약 result.[[Error]]가 none이 아니면, result.[[Error]]를 던집니다.
다음과 같습니다
- 만약 result.[[Error]]가 none이 아니면, ThrowCompletion(result.[[Error]])을 반환합니다.
특정 타입의 예외를 던지도록 명시하는 알고리즘 단계는 던질 해당 타입의 예외를 구성합니다. 예를 들어,
- TypeError 예외를 던집니다.
다음과 같습니다
- ThrowCompletion(새로 생성한 TypeError 객체)을 반환합니다.
5.2.4.3 Completion Record의 래핑을 해제하는 축약 표현
접두사 “?”와 “!”는 Completion Record의 래핑을 해제하는 축약 표현으로 사용됩니다. “?”는 비정상 완료를 호출자에게 전파하거나, 그렇지 않으면 정상 완료의 래핑을 해제하는 데 사용됩니다. “!”는 Completion Record가 정상임을 단언하고 래핑을 해제하는 데 사용됩니다. 형식적으로 다음 단계는
- result를 ? record로 둡니다.
다음과 같습니다
- 단언: record는 Completion Record입니다.
- 만약 record가 비정상 완료이면, record를 반환합니다.
- result를 record.[[Value]]로 둡니다.
마찬가지로 다음 단계는
- result를 ! record로 둡니다.
다음과 같습니다
- 단언: record는 정상 완료입니다.
- result를 record.[[Value]]로 둡니다.
“?” 또는 “!”가 다른 문맥에서 사용되면 먼저 이 규칙을 적용할 수 있을 때까지 평가 순서에 제시된 재작성 방식을 적용한 다음 이 규칙을 적용합니다. 예를 들어 다음 단계는
- AO(? Other())를 수행합니다.
다음과 같이 재작성할 수 있습니다
- tmp1을 Other()로 둡니다.
- tmp2를 ? tmp1으로 둡니다.
- AO(tmp2)를 수행합니다.
이를 다시 전개하면 다음과 같습니다
- tmp1을 Other()로 둡니다.
- 단언: tmp1은 Completion Record입니다.
- 만약 tmp1이 비정상 완료이면, tmp1을 반환합니다.
- tmp2를 tmp1.[[Value]]로 둡니다.
- AO(tmp2)를 수행합니다.
5.2.4.4 암묵적인 정상 완료
Completion Record를 반환하도록 선언된 추상 연산 내의 알고리즘과 모든 내장 함수에서는 반환값을 먼저 NormalCompletion에 전달하고 그 결과를 대신 사용합니다. 이 규칙은 Completion 알고리즘 내부나 해당 단계에서 반환값이 Completion Record임을 명확히 표시한 경우에는 적용되지 않습니다. 이러한 경우는 다음과 같습니다:
이러한 추상 연산에서 다른 방법으로 Completion Record를 반환하면 편집 오류입니다. 예를 들어 이러한 추상 연산 내에서,
- true를 반환합니다.
다음 중 어느 것과도 같은 의미입니다
- NormalCompletion(true)를 반환합니다.
또는
- completion을 NormalCompletion(true)로 둡니다.
- Completion(completion)을 반환합니다.
또는
- Completion Record { [[Type]]: normal, [[Value]]: true, [[Target]]: empty }를 반환합니다.
? 축약 표현의 전개를 통해 다음 예가 허용된다는 점에 유의하시기 바랍니다. 전개된 단계에서 비정상인 경우에는 Completion을 적용한 결과를 직접 반환하고, 정상인 경우에는 래핑을 해제한 후 암묵적인 NormalCompletion 적용이 이루어지기 때문입니다.
- ? completion을 반환합니다.
다음 예는 해당 단계에 표시하지 않은 채 Completion Record를 반환하므로 편집 오류입니다.
- completion을 NormalCompletion(true)로 둡니다.
- completion을 반환합니다.
5.2.5 정적 의미론
문맥 자유 문법은 입력 요소 스트림이 평가할 수 있는 유효한 ECMAScript Script 또는 Module을 형성하는지 여부를 정의하는 모든 규칙을 표현할 만큼 강력하지 않습니다. 일부 상황에서는 ECMAScript 알고리즘 관례 또는 산문 형태의 요구 사항으로 표현할 수 있는 추가 규칙이 필요합니다. 이러한 규칙은 항상 문법의 생성 규칙과 연결되며, 해당 생성 규칙의 정적 의미론이라고 합니다.
정적 의미 규칙에는 이름이 있으며 일반적으로 알고리즘으로 정의됩니다. 이름 있는 정적 의미 규칙은 문법 생성 규칙과 연결됩니다. 여러 대안적인 정의를 갖는 생성 규칙에는 일반적으로 각 대안에 대해 적용 가능한 이름 있는 정적 의미 규칙마다 별도의 알고리즘이 있습니다.
정적 의미 규칙의 특별한 종류로 조기 오류 규칙이 있습니다. 조기 오류 규칙은 특정 문법 생성 규칙과 연결된 조기 오류 조건(절 17 참조)을 정의합니다. 대부분의 조기 오류 규칙 평가는 이 명세의 알고리즘 내에서 명시적으로 호출되지 않습니다. 적합한 구현체는 Script 또는 Module을 처음 평가하기 전에 해당 Script 또는 Module을 파싱하는 데 사용된 생성 규칙의 모든 조기 오류 규칙을 검증해야 합니다. 조기 오류 규칙 중 하나라도 위반하면 해당 Script 또는 Module은 유효하지 않으며 평가할 수 없습니다.
5.2.6 수학 연산
이 명세에서는 다음 종류의 숫자 값을 참조합니다:
이 명세의 표현에서는 서로 다른 숫자 종류를 아래 첨자 접미사를 사용하여 구별합니다. 아래 첨자 𝔽는 Number를 나타내고, 아래 첨자 ℤ는 BigInt를 나타냅니다. 아래 첨자 접미사가 없는 숫자 값은 수학적 값을 나타냅니다. 이 명세에서는 대부분의 숫자 값을 10진수로 나타내며, 0x 뒤에 숫자 0-9 또는 A-F가 오는 형식의 숫자 값은 16진수 값으로도 사용합니다.
일반적으로 이 명세에서 “y의 길이” 또는 “네 개의 16진수 숫자가 나타내는 정수 ...”와 같이 숫자 종류를 명시적으로 지정하지 않고 숫자 값을 언급하는 경우, 해당 표현은 수학적 값을 나타냅니다. Number 또는 BigInt 값을 나타내는 표현에는 이를 명시적으로 표시합니다. 예를 들어 “...의 코드 포인트 수에 대한 Number 값” 또는 “...에 대한 BigInt 값”과 같습니다.
이 명세에서 정수라는 용어를 사용할 때는 달리 명시되지 않는 한 정수 집합에 속하는 수학적 값을 나타냅니다. 이 명세에서 정수인 Number라는 용어를 사용할 때는 그 수학적 값이 정수 집합에 속하는 유한한 Number 값을 나타냅니다.
+, ×, =, ≥와 같은 숫자 연산자는 피연산자의 타입에 따라 결정되는 해당 연산을 나타냅니다. 수학적 값에 적용되는 경우 연산자는 일반적인 수학 연산을 나타냅니다. 확장 수학적 값에 적용되는 경우 연산자는 확장 실수에 대한 일반적인 수학 연산을 나타냅니다. 부정형은 정의되지 않으며 이 명세에서 이를 사용하는 것은 편집상의 오류로 간주해야 합니다. Number에 적용되는 경우 연산자는 IEEE 754-2019의 관련 연산을 나타냅니다. BigInt에 적용되는 경우 연산자는 BigInt의 수학적 값에 적용되는 일반적인 수학 연산을 나타냅니다. 서로 다른 타입의 피연산자(예: Number와 수학적 값)에 적용되는 숫자 연산자는 정의되지 않으며 이 명세의 편집상의 오류로 간주해야 합니다.
이 문서에서는 수학적 값과 Number 또는 BigInt 사이의 변환을 항상 명시적으로 나타냅니다. 수학적 값 또는 확장 수학적 값 x를 Number로 변환하는 것은 “x에 대한 Number 값” 또는 𝔽(x)로 나타내며, 6.1.6.1에 정의되어 있습니다. 정수 x를 BigInt로 변환하는 것은 “x에 대한 BigInt 값” 또는 ℤ(x)로 나타냅니다. Number 또는 BigInt x를 수학적 값으로 변환하는 것은 “x의 수학적 값” 또는 ℝ(x)로 나타냅니다. +0𝔽 및 -0𝔽의 수학적 값은 수학적 값 0입니다. 유한하지 않은 값의 수학적 값은 정의되지 않습니다. x의 확장 수학적 값은 유한한 값의 경우 x의 수학적 값이고, +∞𝔽 및 -∞𝔽의 경우 각각 +∞ 및 -∞입니다. NaN에 대해서는 정의되지 않습니다.
수학 함수 abs(x)는 x의 절댓값을 산출하며, x < 0이면 -x이고 그렇지 않으면 x 자체입니다.
수학 함수 ln(x)는 x의 자연로그를 산출합니다. 수학 함수 log10(x)는 x의 밑이 10인 로그를 산출합니다. 수학 함수 log2(x)는 x의 밑이 2인 로그를 산출합니다.
수학 함수 min(x1, x2, … , xN)는 x1부터 xN까지 중 수학적으로 가장 작은 값을 산출합니다. 수학 함수 max(x1, x2, ..., xN)는 x1부터 xN까지 중 수학적으로 가장 큰 값을 산출합니다. 이러한 수학 함수의 정의역과 치역은 확장 수학적 값입니다.
표기 “x modulo y”(y는 유한하고 0이 아니어야 합니다)는 어떤 정수 q에 대해 abs(k) < abs(y) and x - k = q × y를 만족하고 y와 같은 부호(또는 0)를 갖는 값 k를 계산합니다.
“x를 lower와 upper 사이로 클램핑한 결과”라는 표현(x는 확장 수학적 값이고 lower 및 upper는 lower ≤ upper를 만족하는 수학적 값)은 x < lower이면 lower를 산출하고, x > upper이면 upper를 산출하며, 그렇지 않으면 x를 산출합니다.
수학 함수 floor(x)는 x보다 크지 않은 가장 큰 정수(+∞에 가장 가까운 정수)를 산출합니다.
참고
floor(x) = x - (x modulo 1).
수학 함수 truncate(x)는 0 방향으로 반올림하여 x의 소수 부분을 제거합니다. x < 0이면 -floor(-x)를 생성하고, 그렇지 않으면 floor(x)를 생성합니다.
수학 함수 min, max, abs, floor 및 truncate는 Number와 BigInt에 대해 정의되지 않으며, 이러한 메서드에 수학적 값이 아닌 인수를 사용하는 것은 이 명세의 편집 오류입니다.
하한 a에서 상한 b까지의 구간은 동일한 숫자 타입의 숫자 값으로 구성된 집합이며, 무한하거나 비어 있을 수 있습니다. 각 경계는 포함 또는 제외 중 하나로 기술되며, 둘 다일 수는 없습니다. 구간에는 다음과 같은 네 가지 종류가 있습니다:
- a(포함)에서 b(포함)까지의 구간은 a에서 b까지의 닫힌 구간이라고도 하며, a ≤ x ≤ b를 만족하는 동일한 숫자 타입의 모든 값 x를 포함하고 그 밖의 값은 포함하지 않습니다.
- a(포함)에서 b(제외)까지의 구간은 a ≤ x < b를 만족하는 동일한 숫자 타입의 모든 값 x를 포함하고 그 밖의 값은 포함하지 않습니다.
- a(제외)에서 b(포함)까지의 구간은 a < x ≤ b를 만족하는 동일한 숫자 타입의 모든 값 x를 포함하고 그 밖의 값은 포함하지 않습니다.
- a(제외)에서 b(제외)까지의 구간은 a < x < b를 만족하는 동일한 숫자 타입의 모든 값 x를 포함하고 그 밖의 값은 포함하지 않습니다.
예를 들어 1(포함)에서 2(제외)까지의 구간은 1을 포함하고 2는 포함하지 않는, 1과 2 사이의 모든 수학적 값으로 구성됩니다. 구간을 정의할 때는 -0𝔽 < +0𝔽이므로, 예를 들어 하한이 +0𝔽인 닫힌 구간은 +0𝔽를 포함하지만 -0𝔽는 포함하지 않습니다. NaN은 어떤 구간에도 포함되지 않습니다.
5.2.7 값 표기법
이 명세에서 ECMAScript 언어 값은 굵은 글씨로 표시됩니다. 예로는 null, true 또는 "hello"가 있습니다. 이러한 값은 Function.prototype.apply 또는 let n = 42;와 같은 ECMAScript 소스 텍스트와 구별됩니다.
5.2.8 동일성
이 명세에서는 명세 값과 ECMAScript 언어 값 모두에 대해 동등성을 비교합니다. 동등성을 비교할 때 값은 두 범주 중 하나에 속합니다. 동일성이 없는 값은 정수의 크기나 시퀀스의 길이와 같은 모든 고유 특성이 같으면 다른 동일성이 없는 값과 동등합니다. 동일성이 없는 값은 그 특성을 완전히 기술함으로써 사전 참조 없이 나타낼 수 있습니다. 반면 각 동일성이 있는 값은 고유하므로 자기 자신과만 동등합니다. 동일성이 있는 값은 동일성이 없는 값과 유사하지만, 동일성이라는 추측할 수 없고 변경할 수 없으며 전역적으로 고유한 특성이 추가로 있습니다. 동일성 자체는 기술할 수 없으므로 기존의 동일성이 있는 값에 대한 참조는 단순히 해당 값을 기술하는 것만으로 나타낼 수 없습니다. 대신 이러한 값에 대한 참조를 한 곳에서 다른 곳으로 명시적으로 전달해야 합니다. 동일성이 있는 값 중 일부는 변경 가능하므로 동일성을 제외한 특성을 그 자리에서 변경할 수 있으며, 그 값을 보유한 모든 곳에서 새로운 특성을 관찰하게 됩니다. 동일성이 없는 값은 동일성이 있는 값과 결코 동등하지 않습니다.
이 명세의 관점에서 “이다”라는 말은 “만약 bool이 true이면, ...”와 같이 두 값의 동등성을 비교하는 데 사용되며, “포함한다”라는 말은 “만약 list가 r.[[Foo]]가 true인 Record r을 포함하면, ...”와 같이 동등성 비교를 사용하여 리스트 안에서 값을 찾는 데 사용됩니다. 값의 명세 동일성은 이러한 비교의 결과를 결정하며, 이 명세에서 공리적으로 주어집니다.
ECMAScript 언어의 관점에서 언어 값의 동등성은 SameValue 추상 연산과 이 연산이 전이적으로 호출하는 추상 연산을 사용하여 비교합니다. 이러한 비교 추상 연산의 알고리즘은 ECMAScript 언어 값의 언어 동일성을 결정합니다.
명세 값 중 명세 동일성이 없는 값의 예에는 수학적 값과 확장된 수학적 값; ECMAScript 소스 텍스트, 서로게이트 쌍, 지시문 프롤로그 등; UTF-16 코드 단위; 유니코드 코드 포인트; 열거 값; 구문 지향 연산과 호스트 훅 등을 포함하는 추상 연산; 순서쌍이 있으며, 이에 한정되지 않습니다. 명세 동일성이 있는 명세 값의 예에는 Property Descriptor, PrivateElement 등을 포함하는 모든 종류의 Record; 파스 노드; List; Set과 Relation; Abstract Closure; Data Block; Private Name; 실행 컨텍스트와 실행 컨텍스트 스택; 에이전트 식별자; WaiterList Record가 있으며, 이에 한정되지 않습니다.
Symbol.for로 생성한 Symbol 값을 제외한 모든 ECMAScript 언어 값에서 명세 동일성과 언어 동일성은 일치합니다. 명세 동일성과 언어 동일성이 모두 없는 ECMAScript 언어 값은 undefined, null, Boolean, String, Number 및 BigInt입니다. 명세 동일성과 언어 동일성이 모두 있는 ECMAScript 언어 값은 Symbol 중 Symbol.for로 생성하지 않은 값과 Object입니다. Symbol.for로 생성한 Symbol 값에는 명세 동일성이 있지만 언어 동일성은 없습니다.