5.1 구문 및 렉시컬 문법
5.1.1 문맥 자유 문법
문맥 자유 문법은 여러 개의 생산식으로 구성됩니다. 각 생산식에는 비단말기라 불리는 추상 기호가 좌변에, 0개 이상의 비단말기와 단말기 기호가 우변에 나열됩니다. 각 문법에서 단말기 기호는 지정된 알파벳에서 선택됩니다.
체인 생산식은 우변에 단 하나의 비단말기 기호와 0개 이상의 단말기 기호가 있는 생산식입니다.
단일 특수 비단말기로 구성된 문장에서 시작하여, 주어진 문맥 자유 문법은 언어를 정의합니다. 즉, 비단말기를 해당 비단말기가 좌변인 생산식의 우변으로 반복적으로 치환함으로써 생성될 수 있는 단말기 기호의 (아마도 무한한) 가능한 시퀀스 집합입니다.
5.1.2 렉시컬 및 정규식 문법
ECMAScript의 렉시컬 문법은 12 절에 있습니다. 이 문법의 단말기 기호는 11.1에서 정의된 SourceCharacter 규칙을 따르는 유니코드 코드 포인트입니다. 목표 기호 InputElementDiv, InputElementTemplateTail, InputElementRegExp, InputElementRegExpOrTemplateTail, 또는 InputElementHashbangOrRegExp에서 시작하여, 이러한 코드 포인트 시퀀스를 입력 요소 시퀀스로 변환하는 방법을 설명하는 생산식 집합을 정의합니다.
공백과 주석을 제외한 입력 요소는 ECMAScript의 구문 문법의 단말기 기호를 구성하며, ECMAScript 토큰이라고 합니다. 이 토큰은 ECMAScript 언어의 예약어, 식별자, 리터럴, 구두점입니다. 또한 줄 종결자는 토큰으로 간주되지 않지만 입력 요소 스트림의 일부가 되어 자동 세미콜론 삽입 과정(12.10)을 안내합니다. 단순 공백과 한 줄 주석은 버려져서 구문 문법의 입력 요소 스트림에 나타나지 않습니다. MultiLineComment(/*
…*/
형태의 주석, 줄을 넘나들든 아니든 관계 없음)도 줄 종결자가 포함되지 않았다면 단순히 버려집니다. 하지만 줄 종결자가 하나 이상 포함된 경우, 단일 줄 종결자로 대체되어 구문 문법의 입력 요소 스트림에 포함됩니다.
ECMAScript의 정규식 문법은 22.2.1에 있습니다. 이 문법 역시 단말기 기호로 SourceCharacter에서 정의된 코드 포인트를 사용합니다. 목표 기호 Pattern에서 시작하여, 코드 포인트 시퀀스를 정규 표현식 패턴으로 변환하는 생산식 집합을 정의합니다.
렉시컬 및 정규식 문법의 생산식은 구분 기호로 두 개의 콜론 “::”을 사용해 구분됩니다. 렉시컬 문법과 정규식 문법은 일부 생산식을 공유합니다.
5.1.3 숫자 문자열 문법
숫자 문자열 문법은 7.1.4.1에 나옵니다. 단말기 기호로 SourceCharacter를 가지며, 목표 기호 StringNumericLiteral에서 시작하여 문자열을 숫자 값으로 변환하는 데 사용됩니다(이는 숫자 리터럴의 렉시컬 문법과 유사하지만 다릅니다).
숫자 문자열 문법의 생산식은 세 개의 콜론 “:::”을 구분 기호로 가지며, 소스 텍스트 파싱에는 사용되지 않습니다.
5.1.4 구문 문법
ECMAScript의 구문 문법은 13 절부터 16 절까지 제시되어 있습니다. 이 문법의 단말기 기호는 렉시컬 문법에서 정의된 ECMAScript 토큰입니다(5.1.2). 목표 기호 Script와 Module 두 가지에서 시작하여, 토큰 시퀀스가 ECMAScript 프로그램의 구문적으로 올바른 독립된 구성 요소를 형성하는 방법을 설명하는 생산식 집합을 정의합니다.
코드 포인트 스트림을 ECMAScript Script 또는 Module로 파싱하려면, 먼저 렉시컬 문법을 반복적으로 적용하여 입력 요소 스트림으로 변환합니다. 그 후 입력 요소 스트림을 구문 문법을 단일 적용으로 파싱합니다. 입력 스트림의 토큰이 목표 비단말기(Script 또는 Module)의 단일 인스턴스로 파싱될 수 없거나 토큰이 남는다면 구문 오류입니다.
파싱이 성공하면 파스 트리가 구성되며, 트리의 각 노드는 파스 노드입니다. 각 파스 노드는 문법 기호의 인스턴스이며, 해당 기호에서 유도할 수 있는 소스 텍스트의 범위를 나타냅니다. 파스 트리의 루트 노드는 전체 소스 텍스트를 나타내며, 파싱의 목표 기호의 인스턴스입니다. 파스 노드가 비단말기의 인스턴스라면, 해당 비단말기를 좌변으로 하는 생산식 인스턴스이기도 합니다. 그리고 우변의 각 기호마다 자식을 하나씩 가집니다. 각 자식은 해당 기호의 인스턴스인 파스 노드입니다.
새로운 파스 노드는 파서가 호출될 때마다 인스턴스화되며, 동일한 소스 텍스트를 파싱하더라도 파싱 간에 재사용되지 않습니다. 파스 노드는 동일한 소스 텍스트 범위를 나타내고, 동일한 문법 기호의 인스턴스이며, 동일한 파서 호출에서 생성된 경우에만 동일한 파스 노드로 간주됩니다.
Note 1
같은 문자열을 여러 번 파싱하면 서로 다른 파스 노드가 생성됩니다. 예를 들어:
let str = "1 + 1;";
eval(str);
eval(str);
eval
을 호출할 때마다 str의 값을 ECMAScript 소스 텍스트로 변환하고, 각각 독립적으로 자신만의 파스 노드 트리를 생성합니다. 이 트리들은 각각의 파싱이 동일한 문자열 값에서 유도된 소스 텍스트를 대상으로 하더라도 서로 다릅니다.
Note 2파스 노드는 명세상의 산출물이며, 실제 구현에서는 유사한 데이터 구조를 사용할 필요가 없습니다.
구문 문법의 생산식은 구분 기호로 한 개의 콜론 “:”만을 사용합니다.
13부터 16까지 제시된 구문 문법은 ECMAScript Script 또는 Module로서 올바르게 받아들여지는 토큰 시퀀스를 완전히 설명한 것은 아닙니다. 추가적인 토큰 시퀀스도 허용되며, 예를 들어 일부 위치(줄 종결자 앞 등)에 세미콜론만 추가하면 문법에서 기술될 토큰 시퀀스가 허용됩니다. 또한, 일부 위치에 줄 종결자가 나타나면 문법에서 기술된 토큰 시퀀스라 해도 허용되지 않을 수 있습니다.
일부 경우, 모호성을 피하기 위해 구문 문법은 유효한 ECMAScript Script 또는 Module을 형성하지 않는 토큰 시퀀스를 허용하는 일반화된 생산식을 사용합니다. 예를 들어, 객체 리터럴 및 객체 구조 분해 패턴에 이 기법이 사용됩니다. 이런 경우, 더 제한적인 보조 문법이 제공되어 허용되는 토큰 시퀀스를 추가로 제한합니다. 일반적으로, 초기 오류 규칙은 특정 문맥에서 "P 는 반드시 N을 커버해야 한다"고 명시합니다. 여기서 P는 파스 노드(일반화된 생산식의 인스턴스), N은 보조 문법의 비단말기입니다. 이는 다음을 의미합니다:
- P가 원래 일치시킨 토큰 시퀀스를 N을 목표 기호로 하여 다시 파싱합니다. N에 문법적 매개변수가 있다면, P가 처음 파싱될 때 사용된 값으로 설정합니다.
- 토큰 시퀀스를 토큰 남김 없이 N의 단일 인스턴스로 파싱할 수 있다면:
- 해당 N 인스턴스(특정 P에 대해 유일한 파스 노드)를 "P가 커버하는 N"이라고 합니다.
- N 및 그 파생 생산식에 대한 모든 Early Error 규칙은 P가 커버하는 N에도 적용됩니다.
- 그렇지 않으면(파싱이 실패하면), 이는 초기 구문 오류입니다.
5.1.5 문법 표기법
5.1.5.1 단말기 기호
ECMAScript 문법에서 일부 단말기 기호는 고정폭
글꼴로 표시됩니다. 이는 소스 텍스트에 정확히 표시된 대로 나타나야 함을 의미합니다. 이렇게 지정된 모든 단말기 기호 코드 포인트는 다른 유사한 유니코드 범위가 아니라 기본 라틴 블록의 적절한 유니코드 코드 포인트로 이해해야 합니다. 단말기 기호의 코드 포인트는 \
UnicodeEscapeSequence로 표현할 수 없습니다.
단말기 기호가 개별 유니코드 코드 포인트인 문법(즉, 렉시컬, 정규식, 숫자 문자열 문법)에서는 생산식에 여러 개의 고정폭 코드 포인트가 연속해서 나타날 때, 이는 동일한 시퀀스를 독립된 단말기 기호로 쓴 것과 같습니다.
예를 들어, 다음과 같은 생산식이 있습니다:
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의 렉시컬 문법에는 다음과 같은 생산식이 있습니다:
NonZeroDigit :: one of 1 2 3 4 5 6 7 8 9
이는 다음과 같은 약어일 뿐입니다:
NonZeroDigit ::
1
2
3
4
5
6
7
8
9
5.1.5.6 [empty]
생산식의 우변에 “[empty]”가 나타나면, 해당 생산식의 우변이 단말기나 비단말기 기호를 전혀 포함하지 않음을 의미합니다.
5.1.5.7 앞보기 제한
생산식의 우변에 “[lookahead = seq]”가 나타나면, 해당 생산식은 토큰 시퀀스 seq가 바로 뒤따르는 입력 토큰 시퀀스의 접두사일 때만 사용될 수 있음을 의미합니다. 마찬가지로 “[lookahead ∈ set]”에서 set은 유한하고 비어 있지 않은 토큰 시퀀스 집합일 때, 집합의 어떤 요소가 바로 뒤따르는 토큰 시퀀스의 접두사일 때만 사용될 수 있음을 의미합니다. 편의상 집합을 비단말기로 쓸 수도 있는데, 이 경우 해당 비단말기가 확장할 수 있는 모든 토큰 시퀀스 집합을 나타냅니다. 비단말기가 무한히 많은 서로 다른 토큰 시퀀스로 확장될 수 있다면 이는 편집 오류로 간주합니다.
이 조건들은 부정될 수도 있습니다. “[lookahead ≠ seq]”는 해당 생산식이 seq가 바로 뒤따르는 입력 토큰 시퀀스의 접두사가 아니어야만 사용할 수 있음을 의미하고, “[lookahead ∉ 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 ])로 나타내며, 알고리즘 단계 내에서는 필수 매개변수와 차이가 없습니다. 나머지 매개변수(rest parameter)는 매개변수 리스트 끝에 ...name 형태로 나타내며, 필수 및 선택적 매개변수 뒤에 전달된 모든 인자를 List로 수집합니다. 추가 인자가 없는 경우 해당 List는 비어 있습니다.
알고리즘 단계는 순차적 하위 단계로 세분화될 수 있습니다. 하위 단계는 들여쓰기되며, 그 자체로 더 들여쓰기된 하위 단계로 나뉠 수 있습니다. 개요 번호 매기기 규칙은 첫 번째 하위 단계는 소문자 알파벳, 두 번째 하위 단계는 소문자 로마 숫자를 사용합니다. 세 단계보다 더 깊은 단계가 필요할 경우, 네 번째 단계부터는 숫자를 사용합니다. 예시:
- 최상위 단계
- 하위 단계.
- 하위 단계.
- 하위 하위 단계.
- 하위 하위 하위 단계
- 하위 하위 하위 하위 단계
- 하위 하위 하위 하위 하위 단계
단계나 하위 단계는 "if" 조건문으로 작성될 수 있으며, 이 경우 조건이 true일 때만 하위 단계를 적용합니다. 단계나 하위 단계가 "else"로 시작하면, 해당 단계는 같은 수준의 직전 “if” 조건문의 부정이 됩니다.
단계는 하위 단계의 반복적 적용을 지정할 수 있습니다.
"Assert:"로 시작하는 단계는 알고리즘의 불변 조건을 단언합니다. 이러한 단언은 암묵적일 수 있는 알고리즘 불변 조건을 명시적으로 만듭니다. 이러한 단언은 추가적인 의미 요구사항을 더하지 않으므로 구현에서는 검사할 필요가 없습니다. 단순히 알고리즘을 명확히 하기 위해 사용됩니다.
알고리즘 단계에서는 "Let x be someValue" 형식으로 어떤 값에 대한 별칭을 선언할 수 있습니다. 이 별칭은 참조와 유사하여 x와 someValue가 동일한 데이터에 연결되며, 둘 중 하나를 수정하면 모두에 반영됩니다. 참조와 유사한 동작을 피하고 싶으면, 오른쪽 값을 명시적으로 복사하도록 "Let x be a copy of someValue"를 사용합니다. 이는 someValue의 얕은 복사를 만듭니다.
별칭이 선언된 이후에는 모든 이후 단계에서 참조할 수 있으며, 선언 이전 단계에서 참조해서는 안 됩니다. 별칭은 "Set x to someOtherValue" 형태로 수정할 수 있습니다.
5.2.1 추상 연산
이 명세서의 여러 부분에서 사용할 수 있도록, 일부 알고리즘(추상 연산)은 이름을 붙이고 매개변수화된 함수 형태로 작성되며, 다른 알고리즘 내에서 이름으로 참조될 수 있습니다. 추상 연산은 일반적으로 함수 호출 형태(OperationName(arg1, arg2))로 참조됩니다. 일부 추상 연산은 클래스와 유사한 명세 추상화의 다형적 메서드로 취급됩니다. 이러한 메서드형 추상 연산은 someValue.OperationName(arg1, arg2)와 같은 메서드 호출 형태로 참조됩니다.
5.2.2 구문 지향 연산
구문 지향 연산은 이름이 붙은 연산으로, 각 연산은 ECMAScript 문법의 하나 이상의 생산식과 연결된 알고리즘으로 정의됩니다. 여러 대안 정의가 있는 생산식은 일반적으로 각 대안마다 별도의 알고리즘을 가집니다. 알고리즘이 문법 생산식과 연결되어 있을 때, 해당 생산식의 단말기와 비단말기 기호를 알고리즘의 매개변수처럼 참조할 수 있습니다. 이때 비단말기 기호는 소스 텍스트를 파싱할 때 실제로 일치된 대안 정의를 참조합니다. 문법 생산식 또는 그로부터 파생된 파스 노드가 일치시킨 소스 텍스트는 일치에 참여한 첫 번째 단말기에서 시작하여 마지막 단말기에서 끝나는 소스 텍스트의 부분입니다.
알고리즘이 생산식 대안과 연결될 때, 대안은 일반적으로 “[ ]” 문법 주석 없이 표시됩니다. 이러한 주석은 대안의 구문 인식에만 영향을 주며, 연결된 의미에는 영향을 주지 않습니다.
구문 지향 연산은 파스 노드와 필요에 따라 추가 매개변수를 넘겨 호출합니다. 다음 알고리즘의 1, 3, 4 단계를 참고하세요:
- Let status be SyntaxDirectedOperation of SomeNonTerminal.
- Let someParseNode be the parse of some source text.
- Perform SyntaxDirectedOperation of someParseNode.
- Perform SyntaxDirectedOperation of someParseNode with argument "value".
별도로 명시되지 않는 한, 모든 체인 생산식은 해당 좌변 비단말기에 적용될 수 있는 모든 연산에 대해 암시적 정의를 가집니다. 암시적 정의는 동일한 연산을 동일한 매개변수로 체인 생산식의 유일한 우변 비단말기에 다시 적용한 다음 그 결과를 반환합니다. 예를 들어, 어떤 알고리즘에 “Return Evaluation of Block”이라는 단계가 있고, 다음과 같은 생산식이 있다고 가정합니다:
Block :
{
StatementList
}
Evaluation 연산이 해당 생산식과 연결된 알고리즘을 갖지 않는 경우, Evaluation 연산은 다음과 같은 연결을 암시적으로 포함합니다:
런타임 의미론: Evaluation
Block :
{
StatementList
}
- Return Evaluation of StatementList.
5.2.3 런타임 의미론
런타임에 호출되어야 하는 의미론을 명시하는 알고리즘을 런타임 의미론이라고 합니다. 런타임 의미론은 추상 연산 또는 구문 지향 연산으로 정의됩니다.
5.2.3.1 Completion ( completionRecord )
The abstract operation Completion takes argument completionRecord (a Completion Record) and returns a Completion Record. It performs the following steps when called:
- Assert: completionRecord는 Completion Record이다.
- completionRecord를 반환한다.
5.2.3.2 예외 던지기
알고리즘 단계에서 예외를 던지라고 명시된 경우(예:
- TypeError 예외를 던진다.
)는 다음과 동일한 의미입니다:
- Return ThrowCompletion(새로 생성된 TypeError 객체).
5.2.3.3 ReturnIfAbrupt
다음과 같이 명시된 알고리즘 단계:
- ReturnIfAbrupt(argument).
는 다음과 동일합니다:
- Assert: argument는 Completion Record이다.
- argument가 abrupt completion이면 Completion(argument)를 반환한다.
- 그렇지 않으면, argument를 argument.[[Value]]로 설정한다.
다음과 같이 명시된 알고리즘 단계:
- ReturnIfAbrupt(AbstractOperation()).
는 다음과 동일합니다:
- Let hygienicTemp be AbstractOperation().
- Assert: hygienicTemp는 Completion Record이다.
- hygienicTemp가 abrupt completion이면 Completion(hygienicTemp)를 반환한다.
- 그렇지 않으면, hygienicTemp를 hygienicTemp.[[Value]]로 설정한다.
여기서 hygienicTemp는 일시적이며, ReturnIfAbrupt 관련 단계에서만 보입니다.
다음과 같이 명시된 알고리즘 단계:
- Let result be AbstractOperation(ReturnIfAbrupt(argument)).
는 다음과 동일합니다:
- Assert: argument는 Completion Record이다.
- argument가 abrupt completion이면 Completion(argument)를 반환한다.
- 그렇지 않으면, argument를 argument.[[Value]]로 설정한다.
- Let result be AbstractOperation(argument).
5.2.3.4 ReturnIfAbrupt 축약 표기
추상 연산 및 구문 지향 연산의 호출 앞에 ?
가 붙으면, 결과 Completion Record에 ReturnIfAbrupt를 적용해야 함을 나타냅니다. 예를 들어:
- ? OperationName().
는 다음 단계와 같습니다:
- ReturnIfAbrupt(OperationName()).
메서드 호출 형태에서도 마찬가지로 다음 단계:
- ? someValue.OperationName().
는 다음과 같습니다:
- ReturnIfAbrupt(someValue.OperationName()).
마찬가지로, !
를 앞에 붙이면, 해당 추상 또는 구문 지향 연산이 abrupt completion을 반환하지 않음을 의미하며, 결과 Completion Record의 [[Value]] 필드를 연산의 반환값으로 사용함을 나타냅니다. 예를 들어:
- Let val be ! OperationName().
는 다음 단계와 같습니다:
- Let val be OperationName().
- Assert: val은 정상 completion이다.
- val을 val.[[Value]]로 설정한다.
런타임 의미론용 구문 지향 연산에서는 이 축약 표기를 사용하여 연산 호출 앞에 !
또는 ?
를 둡니다:
- Perform ! SyntaxDirectedOperation of NonTerminal.
5.2.3.5 암시적 정상 Completion
Completion Record를 반환하도록 선언된 추상 연산 내부 알고리즘과 모든 내장 함수에서는 반환값이 먼저 NormalCompletion에 전달되고, 그 결과가 대신 사용됩니다. 이 규칙은 Completion 알고리즘 내부 또는 반환되는 값이 해당 단계에서 Completion Record로 명확히 표시된 경우에는 적용되지 않습니다. 적용 예시는 다음과 같습니다:
이러한 추상 연산에서 다른 방식으로 Completion Record를 반환하면 편집 오류입니다. 예를 들어, 다음과 같은 경우,
- Return true.
는 다음 중 아무거나와 동일합니다:
- Return NormalCompletion(true).
또는
- Let completion be NormalCompletion(true).
- Return Completion(completion).
또는
- Return Completion Record { [[Type]]: normal, [[Value]]: true, [[Target]]: empty }.
ReturnIfAbrupt 확장에 따라, 다음 예시는 허용됩니다. 확장된 단계 내에서는 Completion 적용 결과가 abrupt인 경우 바로 반환되고, normal인 경우 unwrapping 후 암시적 NormalCompletion이 적용됩니다.
- Return ? completion.
다음 예시는 Completion Record가 해당 단계에서 명시되지 않은 채 반환되므로 편집 오류입니다.
- Let completion be NormalCompletion(true).
- Return completion.
5.2.4 정적 의미론
문맥 자유 문법만으로는 입력 요소 스트림이 평가 가능한 ECMAScript Script 또는 Module로서 유효한지를 정의하는 모든 규칙을 표현할 수 없습니다. 일부 상황에서는 ECMAScript 알고리즘 관례나 산문 요구사항을 활용해서 추가 규칙을 명시해야 하며, 이러한 규칙은 항상 문법의 생산식과 연결되어 해당 생산식의 정적 의미론이라 불립니다.
정적 의미론 규칙에는 이름이 있으며, 일반적으로 알고리즘으로 정의됩니다. 이름이 붙은 정적 의미론 규칙은 문법 생산식과 연결되며, 여러 대안 정의가 있는 생산식은 각 대안마다 해당 규칙에 대해 별도의 알고리즘을 가집니다.
정적 의미론 규칙의 특별한 종류가 초기 오류 규칙(Early Error Rule)입니다. 초기 오류 규칙은 특정 문법 생산식과 연결된 초기 오류 조건을 정의하며(17 참조), 대부분의 초기 오류 규칙은 이 명세서 알고리즘에서 명시적으로 호출되지 않습니다. 적합한 구현체는 Script 또는 Module을 최초로 평가하기 전에, 해당 Script 또는 Module을 파싱하는 데 사용된 모든 생산식의 초기 오류 규칙을 반드시 검증해야 합니다. 초기 오류 규칙이 하나라도 위반되면 Script 또는 Module은 유효하지 않으며 평가될 수 없습니다.
5.2.5 수학 연산
이 명세서에서 참조하는 숫자값 종류는 다음과 같습니다:
- 수학적 값: 임의의 실수. 기본 숫자 타입으로 사용됨.
- 확장 수학적 값: 수학적 값과 +∞, -∞ 포함.
- Numbers: IEEE 754-2019 binary64(배정밀도 부동소수점) 값.
- BigInts: ECMAScript 언어값으로, 임의의 정수와 일대일 대응됨.
이 명세서에서 숫자값은 첨자 표기로 종류를 구분합니다. 첨자 𝔽는 Numbers를, ℤ는 BigInts를 나타냅니다. 첨자 없는 숫자값은 수학적 값을 의미합니다. 대부분의 숫자값은 10진수로 표기되며, 0x로 시작하고 0-9 또는 A-F로 이어지는 값은 16진수로 사용됩니다.
명세서에서 "the length of y"나 "the integer represented by the four hexadecimal digits ..."와 같이 명시적 숫자 종류 없이 숫자값을 언급하면, 이는 수학적 값을 의미합니다. Number나 BigInt 값을 명시할 경우, "the Number value for ..." 또는 "the BigInt value for ..."와 같이 명시적으로 구분합니다.
integer라는 용어는 별도 명시가 없는 한, 정수 집합에 속하는 수학적 값을 의미합니다. integral Number라는 용어는 수학적으로 정수 집합에 속하는 유한한 Number 값을 의미합니다.
+, ×, =, ≥ 등 숫자 연산자는 피연산자의 타입에 따라 연산이 결정됩니다. 수학적 값에 적용하면 일반 수학 연산을, 확장 수학적 값에 적용하면 확장 실수에 대한 연산을 의미합니다. 정의되지 않은 형태는 사용해서는 안 되며, 명세서에 사용되면 편집 오류입니다. Numbers에 적용하면 IEEE 754-2019에 따른 연산을, BigInts에 적용하면 BigInt의 수학적 값에 대한 연산을 의미합니다. 타입이 혼합된(예: Number와 수학적 값) 피연산자에 대한 숫자 연산은 정의되지 않으며, 명세서에서 사용되면 편집 오류입니다.
수학적 값과 Number 또는 BigInt 간의 변환은 항상 명시적으로 나타납니다. 수학적 값 또는 확장 수학적 값 x를 Number로 변환하면 "the Number value for x" 또는 𝔽(x)로 표기하며, 6.1.6.1에서 정의됩니다. 정수 x를 BigInt로 변환하면 "the BigInt value for x" 또는 ℤ(x)로 표기합니다. Number 또는 BigInt x를 수학적 값으로 변환하면 "the mathematical value of x" 또는 ℝ(x)로 표기합니다. +0𝔽와 -0𝔽의 수학적 값은 0입니다. 비유한 값의 수학적 값은 정의되지 않습니다. extended mathematical value of x는 유한 값에는 수학적 값, +∞𝔽와 -∞𝔽에는 각각 +∞, -∞가 되며, NaN에는 정의되지 않습니다.
수학 함수 abs(x)는 x의 절댓값을 반환하며, x < 0이면 -x, 그렇지 않으면 x 자체입니다.
수학 함수 min(x1, x2, … , xN)은 x1 ~ xN 중 가장 작은 값을 반환합니다. max(x1, x2, ..., xN)은 가장 큰 값을 반환합니다. 이 수학 함수의 정의역과 값의 범위는 확장 수학적 값입니다.
“x modulo y”(y는 유한하고 0이 아니어야 함)은 y와 같은 부호(또는 0)를 가진 값 k를 계산하며, abs(k) < abs(y) and x - k = q × y를 만족하는 정수 q가 존재합니다.
"the result of clamping x between lower and upper"(x는 확장 수학적 값, lower, upper는 lower ≤ upper인 수학적 값)란, x < lower면 lower, x > upper면 upper, 아니면 x를 반환합니다.
수학 함수 floor(x)는 x보다 크지 않은 가장 큰 정수(가장 +∞에 가까운)를 반환합니다.
Note
floor(x) = x - (x modulo 1).
수학 함수 truncate(x)는 x의 소수 부분을 제거하며, x < 0이면 -floor(-x), 아니면 floor(x)를 반환합니다.
min, max, abs, floor, truncate 함수는 Numbers와 BigInts에는 정의되지 않으며, 수학적 값이 아닌 인자를 사용하는 경우 명세서에서 편집 오류입니다.
하한 a ~ 상한 b의 구간은 동일 숫자 타입의 값 집합이며, 무한 혹은 빈 집합일 수 있습니다. 각 구간의 경계는 포함 또는 제외로 표시되나, 둘 다는 아닙니다. 구간 종류는 다음 네 가지입니다:
- a (포함) ~ b (포함) 구간(inclusive interval)은 a ≤ x ≤ b인 값만 포함합니다.
- a (포함) ~ b (제외) 구간은 a ≤ x < b인 값만 포함합니다.
- a (제외) ~ b (포함) 구간은 a < x ≤ b인 값만 포함합니다.
- a (제외) ~ b (제외) 구간은 a < x < b인 값만 포함합니다.
예를 들어 1(포함) ~ 2(제외) 구간은 1 이상 2 미만의 모든 수학적 값을 포함하며, 1은 포함, 2는 포함하지 않습니다. 구간 정의에서 -0𝔽 < +0𝔽이므로, 하한이 +0𝔽인 포함 구간은 +0𝔽는 포함하나 -0𝔽는 포함하지 않습니다. NaN은 절대 구간에 포함되지 않습니다.
5.2.6 값 표기법
이 명세서에서 ECMAScript 언어값은 굵게 표시됩니다. 예시로 null, true, "hello" 등이 있으며, Function.prototype.apply
나 let n = 42;
처럼 ECMAScript 소스 텍스트와 구분됩니다.
5.2.7 동일성
이 명세서에서는 명세 값과 ECMAScript 언어값 모두 동등성 비교를 합니다. 동등성 비교 시 값은 두 가지 범주로 나뉩니다. 동일성 없는 값은 모든 고유 특성이 동일하면 서로 동등합니다(예: 정수 크기나 시퀀스 길이). 이러한 값은 특성만으로 참조 없이 나타낼 수 있습니다. 반면 동일성 있는 값은 유일하며 자기 자신과만 동등합니다. 동일성 있는 값은 동일성 없는 값과 같으나, 동일성이라는 추정 불가, 변경 불가, 전역적으로 유일한 특성을 추가로 가집니다. 기존 동일성 있는 값 참조는 특성 설명만으로 나타낼 수 없으며, 반드시 값을 명시적으로 전달해야 합니다. 일부 동일성 있는 값은 변경 가능하여, 동일성 외 특성이 변하면 모든 참조자가 변경을 관찰합니다. 동일성 없는 값은 동일성 있는 값과 결코 동등하지 않습니다.
명세 관점에서 “is”는 두 값을 동등 비교하는 데 사용되며(예: “If bool is true, then ...”), “contains”는 리스트 내 값을 동등 비교로 찾는 데 사용됩니다(예: "If list contains a Record r such that r.[[Foo]] is true, then ..."). 값의 명세 동일성이 비교 결과를 결정하며, 이는 명세적으로 자명합니다.
ECMAScript 언어 관점에서는 언어값을 SameValue 추상 연산 및 그 하위 추상 연산으로 비교합니다. 이 비교 추상 연산 알고리즘이 ECMAScript 언어값의 언어 동일성을 결정합니다.
명세 값 중 동일성 없는 예시는: 수학적 값과 확장 수학적 값, ECMAScript 소스 텍스트, surrogate pair, Directive Prologue 등, UTF-16 코드 유닛, 유니코드 코드 포인트, enum, 추상 연산(구문 지향 연산, host hook 등), 정렬된 쌍 등이 있습니다. 동일성 있는 예시는: Property Descriptor, PrivateElement 등 다양한 Record, Parse Node, List, Set과 Relation, Abstract Closure, Data Block, Private Name, 실행 컨텍스트 및 스택, agent signifier, WaiterList Record 등이 있습니다.
명세 동일성은 ECMAScript 언어값 중 Symbol.for로 생성된 Symbol을 제외하고 언어 동일성과 일치합니다. 명세 동일성 및 언어 동일성 모두 없는 ECMAScript 언어값은 undefined, null, Boolean, String, Number, BigInt입니다. 명세 동일성과 언어 동일성을 모두 가지는 ECMAScript 언어값은 Symbol(단, Symbol.for 생성이 아닌 경우) 및 Object입니다. Symbol.for로 생성된 Symbol은 명세 동일성은 있으나 언어 동일성은 없습니다.