5 표기 관례

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로부터 시작하여 문자열을 숫자 값으로 변환하는 데 사용된다(이는 숫자 리터럴에 대한 어휘 문법과 유사하지만 구별된다).

숫자 문자열 문법의 생성 규칙은 구두점으로 콜론 세 개 “:::”를 가진다는 점으로 구별되며, 소스 텍스트 파싱에는 결코 사용되지 않는다.

5.1.4 구문 문법

ECMAScript의 구문 문법은 절 13부터 16까지에 제시되어 있다. 이 문법은 어휘 문법에 의해 정의되는 ECMAScript 토큰을 단말 기호로 가진다(5.1.2). 이 문법은 두 개의 대안적 목표 기호 ScriptModule로부터 시작하는 생성 규칙 집합을 정의하며, 토큰 시퀀스가 어떻게 ECMAScript 프로그램의 구문적으로 올바른 독립 구성 요소를 형성하는지를 설명한다.

코드 포인트 스트림을 ECMAScript Script 또는 Module로 파싱해야 할 때, 먼저 어휘 문법을 반복 적용하여 입력 요소 스트림으로 변환하고, 그 다음 이 입력 요소 스트림을 구문 문법의 단일 적용으로 파싱한다. 입력 요소 스트림 안의 토큰들이 목표 비단말(Script 또는 Module)의 단일 인스턴스로, 남는 토큰 없이 파싱될 수 없다면 입력 스트림은 구문 오류이다.

파싱이 성공하면 파스 트리가 구성된다. 이는 각 노드가 파스 노드인 루트가 있는 트리 구조이다. 각 파스 노드는 문법의 기호 하나의 인스턴스이며, 그 기호로부터 유도될 수 있는 소스 텍스트의 범위를 나타낸다. 전체 소스 텍스트를 나타내는 파스 트리의 루트 노드는 파스의 목표 기호의 인스턴스이다. 파스 노드가 비단말의 인스턴스인 경우, 그것은 또한 그 비단말을 왼쪽 항으로 가지는 어떤 생성 규칙의 인스턴스이기도 하다. 또한 그것은 0개 이상의 자식을 가지며, 각 자식은 생성 규칙 오른쪽 항의 각 기호 하나에 대응한다. 각 자식은 대응하는 기호의 인스턴스인 파스 노드이다.

새 파스 노드는 파서가 호출될 때마다 인스턴스화되며, 동일한 소스 텍스트를 파싱하는 경우에도 파스들 사이에서 재사용되지 않는다. 파스 노드는 동일한 소스 텍스트 범위를 나타내고, 동일한 문법 기호의 인스턴스이며, 동일한 파서 호출에서 생성된 경우에만 같은 파스 노드로 간주된다.

Note 1

같은 String을 여러 번 파싱하면 서로 다른 파스 노드가 생성된다. 예를 들어 다음을 보라.

let str = "1 + 1;";
eval(str);
eval(str);

eval을 호출할 때마다 str의 값은 ECMAScript 소스 텍스트로 변환되고, 그 자체의 별도 파스 노드 트리를 생성하는 독립적인 파싱이 수행된다. 각 파스가 동일한 String 값으로부터 유도된 소스 텍스트를 대상으로 하더라도, 그 트리들은 서로 구별된다.

Note 2
파스 노드는 명세상의 인공물이며, 구현이 이에 상응하는 자료 구조를 사용할 필요는 없다.

구문 문법의 생성 규칙은 구두점으로 단 하나의 콜론 “:”만 가진다는 점으로 구별된다.

13부터 16까지에 제시된 구문 문법은 어떤 토큰 시퀀스가 올바른 ECMAScript Script 또는 Module로 받아들여지는지에 대한 완전한 설명은 아니다. 특정 위치(예: 줄 종료 문자 앞)에 세미콜론을 추가하기만 하면 문법으로 기술될 수 있는 추가 토큰 시퀀스도 받아들여진다. 또한 문법으로 기술되더라도 특정 “어색한” 위치에 줄 종료 문자가 나타나면 받아들여지지 않는 토큰 시퀀스도 있다.

어떤 경우에는 모호성을 피하기 위해, 구문 문법이 유효한 ECMAScript Script 또는 Module을 형성하지 않는 토큰 시퀀스를 허용하는 일반화된 생성 규칙을 사용한다. 예를 들어 이 기법은 객체 리터럴과 객체 구조 분해 패턴에 사용된다. 그러한 경우 허용 가능한 토큰 시퀀스를 추가로 제한하는 더 엄격한 보충 문법이 제공된다. 일반적으로 조기 오류 규칙은 특정 맥락에서 "p must cover an n"이라고 기술한다. 여기서 p는 파스 노드(일반화된 생성 규칙의 인스턴스)이고 n은 보충 문법의 비단말이다. 이는 다음을 의미한다.

  1. 원래 p와 일치한 토큰 시퀀스를 목표 기호n을 사용하여 다시 파싱한다. n이 문법 매개변수를 가진다면, p가 원래 파싱될 때 사용된 것과 같은 값으로 설정된다.
  2. 그 토큰 시퀀스가 남는 토큰 없이 n의 단일 인스턴스로 파싱될 수 있다면:
    1. n의 인스턴스(주어진 p에 대해 유일한 파스 노드)를 "p에 의해 덮이는 n"이라고 부른다.
    2. n 및 그것으로부터 유도된 생성 규칙에 대한 모든 조기 오류 규칙p에 의해 덮이는 n에도 적용된다.
  3. 그렇지 않으면(파싱이 실패하면), 이는 조기 Syntax Error이다.

5.1.5 문법 표기법

5.1.5.1 단말 기호

ECMAScript 문법에서 일부 단말 기호는 fixed-width 글꼴로 표시된다. 이러한 것은 소스 텍스트에 정확히 적힌 그대로 나타나야 한다. 이 방식으로 명세된 모든 단말 기호 코드 포인트는 다른 유니코드 범위의 유사하게 생긴 코드 포인트가 아니라 Basic Latin 블록의 적절한 유니코드 코드 포인트로 이해되어야 한다. 단말 기호 안의 코드 포인트는 \ UnicodeEscapeSequence로 표현될 수 없다.

단말 기호가 개별 유니코드 코드 포인트인 문법(즉, 어휘, RegExp, 숫자 문자열 문법)에서는, 생성 규칙에 나타나는 여러 개의 고정 폭 코드 포인트의 연속은 그것들을 각각 독립된 단말 기호로 쓴 것과 같은 코드 포인트 시퀀스에 대한 단순한 약식 표기이다.

예를 들어, 생성 규칙

HexIntegerLiteral :: 0x HexDigits

는 다음의 약식이다.

HexIntegerLiteral :: 0 x HexDigits

반대로, 구문 문법에서는 고정 폭 코드 포인트의 연속이 하나의 단말 기호이다.

단말 기호는 두 가지 다른 형태도 가진다.

  • 어휘 및 RegExp 문법에서, 관례적인 인쇄 표현이 없는 유니코드 코드 포인트는 대신 "<ABBREV>" 형식으로 표시되며, 여기서 "ABBREV"는 그 코드 포인트 또는 코드 포인트 집합을 나타내는 기억 보조어이다. 이러한 형태는 유니코드 형식 제어 문자, 공백, 그리고 줄 종결자에서 정의된다.
  • 구문 문법에서, 특정 단말 기호(예: IdentifierNameRegularExpressionLiteral)는 같은 이름의 어휘 문법 비단말을 가리키므로 이탤릭체로 표시된다.

5.1.5.2 비단말 기호와 생성 규칙

비단말 기호는 이탤릭체로 표시된다. 비단말의 정의(“생성 규칙”이라고도 부른다)는 정의되는 비단말의 이름 뒤에 하나 이상의 콜론이 따라오는 형태로 도입된다. (콜론의 개수는 그 생성 규칙이 어느 문법에 속하는지를 나타낸다.) 그 다음 줄들에는 해당 비단말의 하나 이상의 대체 오른쪽 항이 이어진다. 예를 들어, 구문 정의

WhileStatement : while ( Expression ) Statement

는 비단말 WhileStatement가 토큰 while, 그 다음 왼쪽 괄호 토큰, 그 다음 Expression, 그 다음 오른쪽 괄호 토큰, 그 다음 Statement를 나타낸다는 뜻이다. ExpressionStatement의 출현은 그 자체로 비단말이다. 또 다른 예로, 구문 정의

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일 때에만 그 생성 규칙을 사용할 수 있음을 뜻한다. 마찬가지로, set유한하고 비어 있지 않은 토큰 시퀀스 집합일 때 “[lookahead ∈ 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가 결과 토큰 시퀀스의 접두사인지 여부를 바꿀 수 있다면, 이는 편집 오류로 간주된다.

5.1.5.8 [no LineTerminator here]

구문 문법의 생성 규칙 오른쪽 항에 “[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

는 비단말 IdentifierIdentifierName을 대체할 수 있는 어떤 코드 포인트 시퀀스로도 대체될 수 있지만, 동일한 코드 포인트 시퀀스가 ReservedWord를 대체할 수도 있는 경우는 제외됨을 뜻한다.

5.1.5.10 설명적 구문

마지막으로, 몇몇 비단말 기호는 모든 대안을 나열하는 것이 비현실적인 경우 산세리프체의 설명적 구문으로 기술된다.

SourceCharacter :: 임의의 유니코드 코드 포인트

5.2 알고리즘 관례

이 명세서는 종종 알고리즘의 단계를 명세하기 위해 번호가 매겨진 목록을 사용한다. 이러한 알고리즘은 ECMAScript 언어 구성 요소에 요구되는 의미론을 정확하게 명세하기 위해 사용된다. 이 알고리즘들은 특정 구현 기법의 사용을 암시하려는 의도가 아니다. 실제로는 주어진 기능을 구현하기 위해 더 효율적인 알고리즘이 있을 수 있다.

알고리즘은 위치별로 전달된 인수를 참조하기 위해 알고리즘 단계 내에서 사용할 수 있는 별칭 이름의 순서 있는 쉼표 구분 시퀀스로 명시적으로 매개변수화될 수 있다. 선택 매개변수는 대괄호([ , name ])로 표시되며 알고리즘 단계 안에서는 필수 매개변수와 다르지 않다. 가변(rest) 매개변수는 매개변수 목록의 끝에 나타날 수 있으며, 앞에 생략 부호를 붙여 (, ...name) 표기한다. 가변 매개변수는 필수 및 선택 매개변수 뒤에 제공되는 모든 인수를 List로 포착한다. 그러한 추가 인수가 없다면, 그 List는 비어 있다.

알고리즘 단계는 순차적인 하위 단계로 세분될 수 있다. 하위 단계는 들여쓰기되며, 그 자체로도 더 들여쓰기된 하위 단계로 세분될 수 있다. 윤곽 번호 매기기 관례를 사용하여 하위 단계를 식별하며, 첫 번째 수준의 하위 단계는 소문자 알파벳으로, 두 번째 수준의 하위 단계는 소문자 로마 숫자로 표기한다. 세 수준보다 더 많은 수준이 필요하면, 네 번째 수준에서 숫자 레이블을 사용하는 방식으로 이 규칙이 반복된다. 예를 들면 다음과 같다.

  1. 최상위 단계
    1. 하위 단계.
    2. 하위 단계.
      1. 하위하위 단계.
        1. 하위하위하위 단계
          1. 하위하위하위하위 단계
            1. 하위하위하위하위하위 단계

어떤 단계나 하위 단계는 그 하위 단계들에 조건을 거는 “if” 술어로 작성될 수 있다. 이 경우 그 하위 단계들은 술어가 참일 때에만 적용된다. 어떤 단계나 하위 단계가 “else”라는 단어로 시작하면, 그것은 같은 수준의 바로 앞 “if” 술어 단계의 부정이다.

어떤 단계는 그 하위 단계들의 반복 적용을 명시하기 위해 "For each" 또는 "Repeat"로 시작할 수 있다.

Assert:”로 시작하는 단계는 그 알고리즘의 불변 조건을 주장한다. 이러한 주장은 그렇지 않으면 암묵적일 알고리즘 불변식을 명시적으로 드러내는 데 사용된다. 마찬가지로 “NOTE:”로 시작하는 단계는 인근 단계들에 대한 관련 맥락을 제공한다. Assertion 단계와 note 단계는 엄격히 정보 제공용이며, 추가적인 의미론적 요구 사항을 더하지 않으므로 구현이 이를 검사할 필요는 없다.

알고리즘 단계는 “Let x be someValue” 형식을 사용하여 어떤 값에 대해서도 이름 있는 별칭을 선언할 수 있다. 이러한 별칭은 xsomeValue가 동일한 기저 데이터를 참조하고 어느 한쪽에 대한 수정이 양쪽 모두에 보인다는 점에서 참조와 유사하다. 이러한 참조 유사 동작을 피하고자 하는 알고리즘 단계는 오른쪽 항의 복사본을 명시적으로 만들어야 한다. “Let x be a copy of someValue”는 someValue의 얕은 복사본을 만든다.

한번 선언된 별칭은 이후 어떤 단계에서든 참조될 수 있으며, 그 선언 이전의 단계에서 참조되어서는 안 된다. 별칭은 “Set x to someOtherValue” 형식으로 수정될 수 있다.

5.2.1 평가 순서

복잡한 표현식이 알고리즘 단계에 나타날 때, 그것들은 왼쪽에서 오른쪽으로, 안쪽에서 바깥쪽으로 평가되는 것으로 이해해야 한다. 예를 들어 다음 단계

  1. Return A(B(), C.[[D]]) + E(F()).

는 다음과 동등하다.

  1. Let tmp1 be B().
  2. Let tmp2 be C.[[D]].
  3. Let tmp3 be A(tmp1, tmp2).
  4. Let tmp4 be F().
  5. Let tmp5 be E(tmp4).
  6. Let tmp6 be tmp3 + tmp5.
  7. Return tmp6.

여기서 다양한 tmpN 별칭은 일시적이며 이 단계들 안에서만 보인다.

5.2.2 추상 연산

이 명세서의 여러 부분에서 사용하기 쉽게 하기 위해, 추상 연산이라 불리는 일부 알고리즘은 이름이 주어지고 매개변수화된 함수 형태로 작성되어, 다른 알고리즘 안에서 이름으로 참조될 수 있다. 추상 연산은 일반적으로 OperationName(arg1, arg2)와 같은 함수 적용 스타일로 참조된다. 일부 추상 연산은 클래스 유사 명세 추상의 다형적으로 디스패치되는 메서드처럼 취급된다. 이러한 메서드형 추상 연산은 일반적으로 someValue.OperationName(arg1, arg2)와 같은 메서드 적용 스타일로 참조된다.

5.2.3 구문 지시 연산

구문 지시 연산은 정의가 알고리즘들로 이루어진 이름 있는 연산이며, 각 알고리즘은 ECMAScript 문법 중 하나의 하나 이상의 생성 규칙과 연관된다. 여러 대안 정의를 가진 생성 규칙은 일반적으로 각 대안마다 서로 다른 알고리즘을 가진다. 알고리즘이 어떤 문법 생성 규칙과 연관되면, 그 알고리즘은 생성 규칙 대안의 단말 및 비단말 기호를 마치 알고리즘의 매개변수인 것처럼 참조할 수 있다. 이렇게 사용될 때 비단말 기호는 소스 텍스트를 파싱할 때 실제로 일치한 대안 정의를 가리킨다. 문법 생성 규칙 또는 그것으로부터 유도된 파스 노드에 의해 일치한 소스 텍스트는 일치에 참여한 첫 번째 단말의 시작에서 시작하여 마지막 단말의 끝에서 끝나는 소스 텍스트의 부분이다.

알고리즘이 어떤 생성 규칙 대안과 연관될 때, 그 대안은 일반적으로 어떤 “[ ]” 문법 주석도 없이 표시된다. 그러한 주석은 대안의 구문적 인식에만 영향을 주어야 하며, 대안과 연관된 의미론에는 영향을 주지 않아야 한다.

구문 지시 연산은 다음 알고리즘의 단계 1, 3, 그리고 4의 관례를 사용하여 파스 노드와, 선택적으로 다른 매개변수와 함께 호출된다.

  1. Let status be SyntaxDirectedOperation of SomeNonTerminal.
  2. Let someParseNode be the parse of some source text.
  3. Perform SyntaxDirectedOperation of someParseNode.
  4. Perform SyntaxDirectedOperation of someParseNode with argument "value".

명시적으로 달리 지정되지 않는 한, 모든 체인 생성 규칙은 그 생성 규칙의 왼쪽 항 비단말에 적용될 수 있는 모든 연산에 대해 암묵적 정의를 가진다. 이 암묵적 정의는 단지 같은 연산을 같은 매개변수와 함께(있다면) 체인 생성 규칙의 유일한 오른쪽 항 비단말에 다시 적용하고 그 결과를 반환한다. 예를 들어 어떤 알고리즘이 “Return Evaluation of Block” 형태의 단계를 가지고 있고, 다음 생성 규칙이 있다고 가정하자.

Block : { StatementList }

그런데 Evaluation 연산이 그 생성 규칙과 연관된 알고리즘을 가지지 않는다고 하자. 그 경우 Evaluation 연산은 암묵적으로 다음과 같은 연관을 포함한다.

Runtime Semantics: Evaluation

Block : { StatementList }
  1. Return Evaluation of StatementList.

5.2.4 런타임 의미론

런타임에 호출되어야 하는 의미론을 명세하는 알고리즘은 런타임 의미론이라 불린다. 런타임 의미론은 추상 연산 또는 구문 지시 연산으로 정의된다.

5.2.4.1 Completion ( completionRecord )

The abstract operation Completion takes argument completionRecord (a Completion Record) and returns a Completion Record. Completion Record가 반환되고 있음을 강조하는 데 사용된다. It performs the following steps when called:

  1. Assert: completionRecord is a Completion Record.
  2. Return completionRecord.

5.2.4.2 Throw

알고리즘 단계에서 "throw"라는 단어는 ThrowCompletion을 호출한 결과를 반환하는 것의 축약형이다. 예를 들어,

  1. If result.[[Error]] is not none, throw result.[[Error]].

는 다음과 동등하다.

  1. If result.[[Error]] is not none, return ThrowCompletion(result.[[Error]]).

특정 타입의 예외를 던지라고 말하는 알고리즘 단계는, 던질 그 타입의 예외를 생성한다. 예를 들어,

  1. Throw a TypeError exception.

는 다음과 동등하다.

  1. Return ThrowCompletion(a newly created TypeError object).

5.2.4.3 Completion Record 언래핑 축약형

접두사 ?!Completion Record를 언래핑하는 축약형으로 사용된다. ?는 급작 완료를 호출자에게 전파하거나, 그렇지 않으면 정상 완료를 언래핑하는 데 사용된다. !Completion Record가 정상임을 단정하고 이를 언래핑하는 데 사용된다. 형식적으로, 다음 단계

  1. Let result be ? record.

는 다음과 동등하다.

  1. Assert: record is a Completion Record.
  2. If record is an abrupt completion, return record.
  3. Let result be record.[[Value]].

마찬가지로, 다음 단계

  1. Let result be ! record.

는 다음과 동등하다.

  1. Assert: record is a normal completion.
  2. Let result be record.[[Value]].

? 또는 !가 다른 어떤 맥락에서 사용될 때는, 먼저 평가 순서에 주어진 재작성 규칙을 이 규칙을 적용할 수 있을 때까지 적용한 다음, 이 규칙을 적용한다. 예를 들어 다음 단계

  1. Perform AO(? Other()).

는 다음과 같이 재작성될 수 있다.

  1. Let tmp1 be Other().
  2. Let tmp2 be ? tmp1.
  3. Perform AO(tmp2).

이는 다시 다음으로 확장된다.

  1. Let tmp1 be Other().
  2. Assert: tmp1 is a Completion Record.
  3. If tmp1 is an abrupt completion, return tmp1.
  4. Let tmp2 be tmp1.[[Value]].
  5. Perform AO(tmp2).

5.2.4.4 암묵적 정상 완료

Completion Record를 반환한다고 선언된 추상 연산 내부의 알고리즘과 모든 내장 함수 내부에서는, 반환되는 값이 먼저 NormalCompletion에 전달되고 그 결과가 대신 사용된다. 이 규칙은 Completion 알고리즘 내부에는 적용되지 않으며, 또는 그 단계에서 반환되는 값이 명백히 Completion Record로 표시된 경우에도 적용되지 않는다. 이러한 경우는 다음과 같다.

그 외의 어떤 수단으로든 그러한 추상 연산으로부터 Completion Record가 반환된다면 그것은 편집 오류이다. 예를 들어, 이러한 추상 연산 내부에서

  1. Return true.

는 다음 중 어느 것과도 같은 뜻이다.

  1. Return NormalCompletion(true).

또는

  1. Let completion be NormalCompletion(true).
  2. Return Completion(completion).

또는

  1. Return Completion Record { [[Type]]: normal, [[Value]]: true, [[Target]]: empty }.

? 축약형 확장을 통해, 다음 예시는 허용된다는 점에 유의하라. 확장된 단계들 안에서는 급작 경우에 Completion 적용 결과가 직접 반환되고, 정상 경우에는 언래핑 후 암묵적 NormalCompletion 적용이 일어나기 때문이다.

  1. Return ? completion.

다음 예시는 그 단계에서 표시되지 않은 채 Completion Record가 반환되고 있으므로 편집 오류가 된다.

  1. Let completion be NormalCompletion(true).
  2. Return completion.

5.2.5 정적 의미론

문맥 자유 문법은 입력 요소 스트림이 평가될 수 있는 유효한 ECMAScript Script 또는 Module을 형성하는지 여부를 정의하는 모든 규칙을 표현하기에 충분히 강력하지 않다. 어떤 상황에서는 ECMAScript 알고리즘 관례나 산문 요구 사항을 사용하여 표현할 수 있는 추가 규칙이 필요하다. 이러한 규칙은 항상 문법의 생성 규칙과 연관되며, 그 생성 규칙의 정적 의미론이라 불린다.

정적 의미론 규칙은 이름을 가지며 일반적으로 알고리즘을 사용하여 정의된다. 이름 있는 정적 의미론 규칙은 문법 생성 규칙과 연관되며, 여러 대안 정의를 가진 생성 규칙은 일반적으로 각 대안마다 적용 가능한 각 이름 있는 정적 의미론 규칙에 대해 서로 다른 알고리즘을 가진다.

정적 의미론 규칙의 특별한 종류는 조기 오류 규칙이다. 조기 오류 규칙은 특정 문법 생성 규칙과 연관된 조기 오류 조건(절 17 참조)을 정의한다. 대부분의 조기 오류 규칙 평가는 이 명세서의 알고리즘 안에서 명시적으로 호출되지 않는다. 적합한 구현은 Script 또는 Module의 첫 번째 평가 전에, 그 Script 또는 Module을 파싱하는 데 사용된 생성 규칙들의 모든 조기 오류 규칙을 검증해야 한다. 어떤 조기 오류 규칙이라도 위반되면, 그 Script 또는 Module은 유효하지 않으며 평가될 수 없다.

5.2.6 수학 연산

이 명세서는 다음과 같은 종류의 숫자 값을 참조한다.

  • 수학적 값: 기본 숫자 타입으로 사용되는 임의의 실수.
  • 확장 수학적 값: 수학적 값에 +∞ 및 -∞를 더한 것.
  • Numbers: IEEE 754-2019 binary64(배정밀도 부동소수점) 값.
  • BigInts: 임의의 정수와 일대일 대응을 이루는 ECMAScript 언어 값.

이 명세서의 언어에서는 숫자 값들이 아래첨자 접미사를 사용하여 서로 다른 숫자 종류 사이에서 구별된다. 아래첨자 𝔽는 Number를, 아래첨자 는 BigInt를 가리킨다. 아래첨자 접미사가 없는 숫자 값은 수학적 값을 가리킨다. 이 명세서는 대부분의 숫자 값을 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 number of code points in …" 또는 "the BigInt value for …"와 같다.

이 명세서에서 정수라는 용어가 사용될 때, 달리 명시되지 않는 한 그것은 정수 집합에 속하는 수학적 값을 가리킨다. 이 명세서에서 정수형 Number라는 용어가 사용될 때, 그것은 그 수학적 값정수 집합에 속하는 유한한 Number 값을 가리킨다.

+, ×, =, ≥와 같은 숫자 연산자는 피연산자의 타입에 의해 결정되는 해당 연산을 가리킨다. 수학적 값에 적용될 때, 연산자는 일반적인 수학 연산을 가리킨다. 확장 수학적 값에 적용될 때, 연산자는 확장 실수에 대한 일반적인 수학 연산을 가리킨다. 부정형은 정의되지 않으며, 이 명세서에서 그것을 사용하는 것은 편집 오류로 간주되어야 한다. Number에 적용될 때, 연산자는 IEEE 754-2019 내의 შესაბამის 연산을 가리킨다. BigInt에 적용될 때, 연산자는 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이다. 유한하지 않은 값의 수학적 값은 정의되지 않는다. xextended mathematical value of유한한 값들에 대해서는 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이 아니어야 함)는, y와 같은 부호를 가지는(또는 0인) 값 k를 계산하며, 어떤 정수 q에 대해 abs(k) < abs(y) and x - k = q × y를 만족한다.

"the result of clamping x between lower and upper"라는 구(여기서 x확장 수학적 값이고 lowerupperlowerupper를 만족하는 수학적 값이다)는, x < lower이면 lower를 생성하고, x > upper이면 upper를 생성하며, 그렇지 않으면 x를 생성한다.

수학 함수 floor(x)x보다 크지 않은 가장 큰 정수(+∞에 가장 가까운)를 생성한다.

Note

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까지의 포함 구간이라고도 하며, 동일한 숫자 타입의 모든 값 xaxb를 만족하는 것만 포함한다.
  • a(포함)에서 b(배제)까지의 구간은 동일한 숫자 타입의 모든 값 xax < b를 만족하는 것만 포함한다.
  • a(배제)에서 b(포함)까지의 구간은 동일한 숫자 타입의 모든 값 xa < xb를 만족하는 것만 포함한다.
  • a(배제)에서 b(배제)까지의 구간은 동일한 숫자 타입의 모든 값 xa < x < b를 만족하는 것만 포함한다.

예를 들어, 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 언어 값은 모두 동등성을 위해 비교된다. 동등성을 비교할 때 값은 두 범주 중 하나에 속한다. 동일성이 없는 값정수의 크기나 시퀀스의 길이와 같은 모든 고유 특성이 같다면 다른 동일성이 없는 값과 같다. 동일성이 없는 값은 그 특성을 완전히 기술함으로써 사전 참조 없이도 드러낼 수 있다. 반대로 각 동일성이 있는 값은 고유하므로 오직 자기 자신과만 같다. 동일성이 있는 값은 동일성이 없는 값과 같지만, 여기에 동일성이라고 불리는 추가적인, 추측할 수 없고 변경할 수 없으며 보편적으로 유일한 특성이 더해진 것이다. 기존 동일성이 있는 값에 대한 참조는 동일성 자체를 기술할 수 없기 때문에 그것을 설명하는 것만으로는 드러낼 수 없고, 대신 이러한 값들에 대한 참조는 한 장소에서 다른 장소로 명시적으로 전달되어야 한다. 일부 동일성이 있는 값은 가변적이어서, 그 특성(동일성 제외)을 제자리에서 변경할 수 있고, 이로 인해 그 값을 보유한 모든 이가 새로운 특성을 관찰하게 된다. 동일성이 없는 값은 동일성이 있는 값과 결코 같지 않다.

이 명세서의 관점에서, “is”라는 단어는 “If bool is true, then ...”와 같이 두 값을 동등성을 위해 비교하는 데 사용되고, “contains”라는 단어는 "If list contains a Record r such that r.[[Foo]] is true, then ..."와 같이 리스트 내부에서 동등성 비교를 사용해 값을 찾는 데 사용된다. 값들의 명세 동일성이 이러한 비교의 결과를 결정하며, 이는 이 명세서에서 공리적이다.

ECMAScript 언어의 관점에서, 언어 값은 SameValue 추상 연산과 그것이 전이적으로 호출하는 추상 연산들을 사용하여 동등성을 비교한다. 이러한 비교 추상 연산의 알고리즘이 ECMAScript 언어 값의 언어 동일성을 결정한다.

명세 값의 경우, 명세 동일성이 없는 값의 예에는 다음이 포함되며 이에 국한되지 않는다: 수학적 값확장 수학적 값, ECMAScript 소스 텍스트, 서로게이트 쌍, Directive Prologue 등, UTF-16 코드 단위, 유니코드 코드 포인트, enum, 구문 지시 연산, 호스트 훅 등을 포함한 추상 연산, 그리고 순서쌍. 명세 동일성이 있는 값의 예에는 다음이 포함되며 이에 국한되지 않는다: Property Descriptor, PrivateElement 등을 포함한 모든 종류의 Record, Parse Node, List, SetRelation, Abstract Closure, Data Block, Private Name, 실행 컨텍스트 및 실행 컨텍스트 스택, 에이전트 식별자, WaiterList Record.

명세 동일성은 Symbol.for에 의해 생성된 Symbol 값을 제외한 모든 ECMAScript 언어 값에 대해 언어 동일성과 일치한다. 명세 동일성도 언어 동일성도 없는 ECMAScript 언어 값은 undefined, null, Boolean, String, Number, 그리고 BigInt이다. 명세 동일성과 언어 동일성을 모두 가지는 ECMAScript 언어 값은 SymbolSymbol.for에 의해 생성되지 않은 것과 Object이다. Symbol.for에 의해 생성된 Symbol 값은 명세 동일성은 가지지만 언어 동일성은 가지지 않는다.