|
JavaScript 2.0
正式な記述
セマンティクス表記法
|
06/13/2003 (Fri)
JavaScript 2.0 のセマンティクス (意味) は Algol ライクな擬似コードで記述する。以下の節ではセマンティクスの概念、式、プロシジャ (手続き)、及びアクションで使用する表記を定義する。
以下の表にこのドキュメントの式で使用される演算子を要約する。演算子はグループ内で優先順位の最も高いもの (最も束縛の強いもの) から優先順位の最も低いもの (最も束縛の弱いもの) の順に並べてある。関係演算子以外の同じグループに属する演算子は同じ優先順位を持ち、結合則は全て左から右である。つまり、例えば 7–3+2–1 は 7–(3+(2–1)) や (7–(3+2))–1 とはならず ((7–3)+2)–1 となる。関係演算子は数学の慣習通りカスケードし、
a = b c < d
は以下のような意味になる。
a = b and b c and c < d
(丸) 括弧は優先順位を上書きしたり、式を明瞭にするのに使用する。
アルゴリズムの記述に使用する式は副作用を示すことができる。and 、or 、?: 以外の演算子はその全てのオペランドを左から右に計算し、いずれかのオペランドの計算が例外 e を投げると、その演算子は残りのオペランドを計算することなくすぐに e を伝播する。
| グループ | 演算子 | 説明 |
|---|---|---|
| 結合無し | (x) | x を返す。括弧は演算子の優先順位を上書きするのに使用する。 |
| {x1, x2, ... , xn} | 要素 x1, x2, ... , xn から成る集合或いは意味領域 | |
| {f(x) | x A} {f(x) | x A such that predicate(x)} |
集合の内包表記 | |
| [x0, x1, ... , xn–1] | 要素 x0, x1, ... , xn–1 から成るリスト | |
| [f(x) | x u] [f(x) | x u such that predicate(x)] |
リストの内包表記 | |
| Namelabel1: x1, ... , labeln: xn Name |
タプルコンストラクタ | |
| |x| | 数値 x の絶対値、集合 x の基数、或いはリスト x の長さ | |
| x | x の切捨て値 | |
| x | x の切上げ値 | |
| Action[nonterminali] | この表記はアクション内で左側か右側に非終端記号 nonterminal を持つ文法生成規則 に使用し、その i 番目のインスタンスについてアクション Action を実行したときの値を返す。 の右側に nonterminal のインスタンスが1つしか存在せず、i が1のときは下付き文字 i は省略可能である。 | |
| nonterminali | この表記はアクション内で左側か右側に非終端記号 nonterminal を持つ文法生成規則 に使用し、(更に、あらゆる文法非終端記号 nonterminal の完全な展開は単一の文字に展開され)、 の右側の i 番目のインスタンスを展開して得られた文字を返す。 に非終端記号 nonterminal のインスタンスが1つしか存在しない場合は添字 i は省略可能である。添字が省略されて非終端記号 nonterminal が の右側に現れた場合、この式は生成規則 全体を展開して得られる単一の文字を返す。 | |
| 添字 | ilong | 整数 i の Long への変換 |
| iulong | 整数 i の ULong への変換 | |
| xf32 | realToFloat32(x) 呼び出しによる実数 x から “最も近い” Float32 値への変換 | |
| xf64 | realToFloat64(x) 呼び出しによる実数 x から “最も近い” Float64 値への変換 | |
| xy | x の y 乗 | |
| u[i] | リスト u の i 番目の要素 | |
| u[i ... j] u[i ...] |
リスト u の切り出し | |
| u[i \ x] | リスト要素の置換 | |
| a.label | タプル、レコード a の名前 label のフィールド | |
| T{} | 要素が意味領域 T のメンバである全集合の意味領域 | |
| T[] | 要素が意味領域 T のメンバである全リストの意味領域 | |
| f(x1, ..., xn) | プロシジャ呼び出し | |
| 接頭辞 | new Namelabel1: x1, ... , labeln: xn | レコードコンストラクタ |
| –x | 実数の符号反転 | |
| min A | 集合の最小要素 | |
| max A | 集合の最大要素 | |
| 因数、因子 | x y | 実数の積 |
| x / y | 実数の商 (y は0以外でなければならない) | |
| x mod y | 実数の剰余 (y は0以外でなければならない) | |
| A B | 積集合 | |
| T1 T2 ... Tn T () T T1 T2 ... Tn () () () |
プロシジャの意味領域 | |
| 項 | x + y | 実数の和 |
| x – y | 実数の差、差集合 | |
| u v | リストの結合 | |
| A B | 和集合 | |
| 関係 | x = y x y |
タグ、実数、集合、論理値、文字、リスト、文字列、タプル、及びレコードにおいて等価性、不等価性を表す述語。種類の異なる値
(論理値 true と文字 ‘A’ など) は常に不等価とみなされる。 |
| x < y x y x > y x y |
実数、文字、文字列で順序を表す述語 | |
| x A x A |
集合のメンバであることを表す述語 | |
| A B | 部分集合を表す述語 | |
| A B | 真部分集合を表す述語 | |
| 否定 | not a | 論理否定 |
| 結合 | a and b | 短絡論理結合 |
| 分離 | a or b | 短絡論理分離 |
| a xor b | 排他的論理 or | |
| 条件 | a ? x : y | 条件 |
| some x A satisfies predicate(x) every x A satisfies predicate(x) |
集合、リストの数量詞 |
意味領域とは変数があるアルゴリズムで保持できる値を表す。正しいプログラマ、正しくないプログラマ、或いはユーザの入力やアクションに関わらずこれらの制限を常に課すことでアルゴリズムは構築される。
意味領域は直感的にはとり得る値の集合として捉えることができ、実際、このドキュメントで明示的に述べられている値の集合も意味領域である。とはいえ、領域理論において、意味領域はより正確な数学的定義を持つ ([Schmidt86] の例を参照)。領域理論では、集合 A から Integer への値マッピングを行う全関数をメンバとする集合 A を定義しようとするような矛盾に直面することなく、意味領域を再帰的に定義することが認められている。このような集合 A の通常の定義における問題は、A から Integer へのマッピングを行う全関数の集合の基数が A の基数より厳密には常に大となるという矛盾が生じるということである。領域理論は最小限の固定点構築 (least fixed point construction) を使って、意味領域 A を問題なく定義できるようにしている。
意味領域の名前には赤のキャピタライズした小さい大文字 (Capitalized Red Small Caps) を使用する。この名前は同じ名前のタグや通常の変数とは区別して扱われる。よって Undefined 、undefined 、及び undefined は3つの異なる無関係の実体である。
変数 v は以下の表記を使って制限される。
v: T
ここに T は意味領域である。この制限は v の値は常に意味領域 T のメンバであるということを示している。これらの宣言は情報を提供するだけのものだが (削除してもセマンティクスの正当性に影響は無い)、セマンティクスを理解するには有用なものである。例えばセマンティクスが x: Integer となっていれば、x が true とか +f64 という値になるとき何が起こるか考えずにすむ。
制限は静的に立証できる。JavaScript のセマンティクスは全ての制限を破らないために機械的なチェックを行っている。
タグは内部構造を持たない処理トークンである。タグは暗い赤の (dark red) フォントで記す。2つのタグが等しいのはそれらが同じ名前を持つときだけである。
タプルやレコードの名前付けを行うものでないタグは次の表記で定義する:
HTML 版では各タグの name はその定義へのリンクになっている。
タグ true と false は論理値を表す。Boolean は2つの要素を持つ意味領域 {true, false} である。
a と b を論理値、x と y を何らかの値であるとすると、= と の他に以下の操作がこれらに対して可能である:
and 、or 、及び ?: 演算子が短絡を起こすことに注意していただきたい。一部のオペランドを処理しない可能性のある演算子はこれらだけである。
集合は可能な限り無限で順序に関係無い要素の集まりである。各要素は集合内に最高でも1つ存在できる。集合内の要素の全ての組み合わせについて等価関係 = が定義されていなければならない。集合の要素はそれ自身が集合であっても良い。
集合は中括弧で囲まれたカンマ区切りの値リストで記す:
{element1, element2, ... , elementn}
空集合は {} のように書く。重複した要素は1つだけが集合に含められる。
例えば集合 {3, 0, 10, 11, 12, 13, –5} は7つの要素を持つ。
整数か文字の集合は ... 範囲演算子を使って略記することができ、整数か文字コードポイントの範囲 (各境界値を含む) となる。たとえば先の集合は {0, –5, 3 ... 3, 10 ... 13} と書くこともできる。
範囲の始点が終点と同じであれば、その範囲はただ1つの要素を示すようになる。つまり {7 ... 7} は {7} と同じである。範囲の終点が始点よりも1小さい場合は、その範囲は何も含んでいないことになる。つまり {7 ... 6} は {} と同じである。範囲の終点が始点より2つ以上小さいことはない。
{f(x) | x A}
は集合 A の全要素 x について式 f を処理した結果の集合を表す。また、述語を加えることもでき、
{f(x) | x A such that predicate(x)}
は集合 A の内、式 predicate を満たす全ての要素 x について式 f を処理した結果の集合を表す。自由変数 x と集合 A は1つでないこともあり、その場合は自由変数の値の全ての組み合わせが考えられる。例えば、
{x | x Integer such that x2 < 10} = {–3, –2, –1, 0, 1, 2, 3} 、
{x2 | x {–5, –1, 1, 2, 4}} = {1, 4, 16, 25} 、
{x10 + y | x {1, 2, 4}, y {3, 5}} = {13, 15, 23, 25, 43, 45} である。
集合と意味領域の演算には同じ表記を使用する。A と B を集合 (或いは意味領域) とし、x 、y を値とすると、以下の操作がこれらに対して可能である:
T が意味領域であれば T{} は要素が T のメンバである全集合の意味領域である。例えば T = {1,2,3} であれば T{} = {{}, {1}, {2}, {3}, {1,2}, {1,3}, {2,3}, {1,2,3}} となる。空集合 {} はあらゆる意味領域 T について T{} のメンバである。
以上に加えて、集合では数量詞 some 、 every が使用可能である (「リスト」も見よ)。次の数量詞は
some x A satisfies predicate(x)
集合 A に、predicate(x) が true を返す要素 x が1つでも存在すれば true を返す。そのような要素 x が存在しなければ some 数量詞の結果は false となる。 some 数量詞が true を返すとき、変数 x は predicate(x) が true を返す集合 A の要素に束縛されたままとなる。そのような要素 x が複数ある場合はその内任意のもの1つが選択される。例えば、
some x {3, 16, 19, 26} satisfies x mod 10 = 6
は true と評価され、x は 16 か 26 のいずれかになる。他の例も考えると:
(some x {3, 16, 19, 26} satisfies x mod 10 = 7) = false 、
(some x {} satisfies x mod 10 = 7) = false 、
(some x {“Hello”} satisfies true) = true
(x には文字列 “Hello” が設定される)、
(some x {} satisfies true) = false である。
次の数量詞は
every x A satisfies predicate(x)
集合 A に、predicate(x) が false を返す要素 x が1つも存在しなければ true を返す。そのような要素 x が1つでも存在すれば every 数量詞の結果は false となる。特殊な場合として集合 A が空集合の場合は every 数量詞は常に true である。例えば、
(every x {3, 16, 19, 26} satisfies x mod 10 = 6) = false 、
(every x {6, 26, 96, 106} satisfies x mod 10 = 6) = true 、
(every x {} satisfies x mod 10 = 6) = true である。
普通のフォントで書かれた数値はそのまま数学的実数を表す。数値は小数点あり無しのいずれの表記も可能である。先頭に “0x” の付いた整数は16進数である (基数が16である)。4294967296、4294967296.000、0x100000000、及び232は全て同じ数値である。0.1は (誤差などの無い) 1/10の正確な値である。
Integer は全整数 {... –3, –2, –1, 0, 1, 2, 3 ...} の意味領域である。3.0、3、0xFF、及び–10100は全て整数である。
Rational は全有理数の意味領域である。あらゆる整数は有理数でもある (Integer Rational)。3、1/3、7.5、–12/7、及び2–5は有理数の例である。
Real は全実数の意味領域である。あらゆる有理数は実数でもある (Rational Real)。円周率は実数の例であり、3.14よりも僅かに大きな値である。
x 、y を実数とすると、以下の操作がこれらに対して可能であり、その結果は常に正確なものである:
実数は = 、 、< 、 、> 、及び で比較することができる。結果は true か false のいずれかである。
以下に示す4つのプロシジャは整数のビット演算を行う。整数は2種類のビットで無限精度の2進数表記されているものとして扱われ、ビット1が true 、ビット0が false を表す。
より正確には、あらゆる整数 x は、添字 i の範囲が負でない全整数で常に ai {0, 1} であるビット ai の無限の並びで表現できる。この並びは慣習に従い逆順に記述する:
..., a4, a3, a2, a1, a0
整数 x に対する一意なビット並びは次の公式で与えられる:
ai = x / 2i mod 2
x が0か正であればそのビット並びは先頭から0が無限に続き、負の場合は1が無限に続く。例えば6のビット並びは ...0...0000110 であり、–6のビット並びは ...1...1111010 である。
以下に示すビット and 、or 、及び xor 演算は2つの引数 x 、y より得られるビット並び ai 、bi の対応する要素について行われる。結果はビット ci の無限の並びで、演算結果はビット並び ci を生成する一意な整数 z である。例えば6と–6から得られるビット並びの対応する要素の and は ...0...0000010 となる。これは整数2から得られるビット並びであるので、bitwiseAnd(6, –6) = 2 となる。
| プロシジャ | 説明 |
|---|---|
| bitwiseAnd(x: Integer, y: Integer): Integer | x と y のビット and |
| bitwiseOr(x: Integer, y: Integer): Integer | x と y のビット or |
| bitwiseXor(x: Integer, y: Integer): Integer | x と y のビット xor |
| bitwiseShift(x: Integer, count: Integer): Integer | x を左に count ビットシフト。count が負であれば x を右に –count ビットシフト。右側に溢れたビットは棄てられ、右端からシフトしてきたビットは0である。bitwiseShift(x, count) は x 2count と厳密に等価である。 |
‘ と ’ で囲まれた文字はコードポイントが16進数で 0000 から 10FFFF の範囲の Unicode 文字を表す。Unicode
はこれらのコードポイントの全てについて文字を定義しているわけではないが、本仕様ではこれら1114112個のあらゆるコードポイントを正しい文字として扱う。文字の例としては
‘A’ 、‘b’ 、‘«LF»’
、‘«uFFFF»’ 、‘«U00010000»’
、‘«U0010FFFF»’ がある (「非
ASCII 文字の表記法」も見よ)。
Unicode にはコードポイントの表記法がある。コードポイントは Unicode 文字テーブル内の文字の番号である。同様に Unicode にはコード単位の表記法もあり、これは特定の形式に文字を格納するのに使用する数値である。JavaScript は文字列を UTF-16 形式で表現するように設計されており、この表現の下ではコード単位は16ビットということになる (実装は文字列を UTF-8 などの他の形式で格納してもよいが、インデクシングと文字の抽出については文字列が16ビットコード単位の並びであるかのように見えるようにしなければならない)。利便性のために、本仕様では16進数で 0000 から FFFF 間での範囲についてはコードポイントとコード単位を区別しない。
Char16 は集合
{‘«u0000»’ ... ‘«uFFFF»’}
内の65536個の Unicode 文字の意味領域である。この文字群は Unicode 基本多言語面を形成し、16進数で
0000 から FFFF までの範囲のコードポイントを持つ。コード単位も Char16 意味領域内の値で表現される。
SupplementaryChar
は集合 {‘«U00010000»’ ... ‘«U0010FFFF»’}
内の1048576個の Unicode 文字の意味領域であり、これらは16進数で 10000 から 10FFFF
までの範囲のコードポイントを持つ Unicode 補助文字である。これらの文字は Char16 領域のメンバではないため、Char16
コード単位の文字列に直接格納することはできない。その代わり、セマンティックアルゴリズムは必要があれば何処でも補助文字を文字列に格納する前にサロゲートペアコード単位に変換することができる。第1サロゲートコード単位 h は集合
{‘«uD800»’ ... ‘«uDBFF»’}
、第2サロゲートコード単位 l は集合 {‘«uDC00»’ ... ‘«uDFFF»’}
にある。補助文字はコードポイント値
0x10000 + (char16ToInteger(h) – 0xD800)0x400 + char16ToInteger(l) – 0xDC00
でエンコードされる。
Char21 は1114112個の全ての Unicode 文字
{‘«u0000»’ ... ‘«U0010FFFF»’}
の意味領域である。
文字は = 、 、<
、 、> 、及び
を使って比較することができる。これらの演算子はコードポイントを比較するため、‘A’ = ‘A’
、‘A’ < ‘B’
、‘A’ < ‘a’ 、及び
‘«uFFFF»’ < ‘«U00010000»’
は全て true である。
以下のプロシジャは文字と整数の相互変換を行う:
| プロシジャ | 説明 |
|---|---|
| char16ToInteger(c: Char16): {0 ... 0xFFFF} | 文字 c の Unicode コードポイントかコード単位の数値 |
| char21ToInteger(c: Char21): {0 ... 0x10FFFF} | 文字 c の Unicode コードポイントの数値 |
| integerToChar16(i: {0 ... 0xFFFF}): Char16 | Unicode コードポイント或いは Unicode コード単位が i である文字 |
| integerToSupplementaryChar(i: {0x10000 ... 0x10FFFF}): SupplementaryChar | Unicode コードポイントが i である文字 |
| integerToChar21(i: {0 ... 0x10FFFF}): Char21 | Unicode コードポイントが i である文字 |
プロシジャ digitValue は以下のように定義されている:
0’ ... ‘9’, ‘A’ ... ‘Z’, ‘a’ ... ‘z’}): {0 ... 35}0以上の要素を持つ有限の順序付きリストは太字の角括弧内に要素を並べて書く:
[element0, element1, ... , elementn–1]
例えば次のリストは4つの文字列を持つ:
[“parsley”, “sage”, “rosemary”, “thyme”]
空のリストは [] のように書く。
集合とは異なり、リストの要素は0から始まる整数でインデックスをとることができる。リストには重複した要素があってもよい。
[f(x) | x u]
はリスト u の各要素に式 f を適用して得られる結果を要素とするリスト [f(u[0]), f(u[1]), ... , f(u[|u|–1])] を表す。x は式 f の仮引数名である。また、述語を加えることもでき、
[f(x) | x u such that predicate(x)]
はリスト u の要素の内、式 predicate を満たす全ての要素 x について式 f を処理した結果のリストを表す。この結果はリスト u の要素 x と同じ順序で並べられる。例えば、
[
[x+1 | x [–1, 1, 2, 3, 4, 5, 3, 10] such that x mod 2 = 1] = [0, 2, 4, 6, 4]
リスト u = [e0, e1, ... , en–1] 、v = [f0, f1, ... , fm–1] を考え、e を要素、i と j を整数 、x を値とすると以下の操作がリストに対して可能である。操作に意味があるのはその前提条件を満足する場合だけである (セマンティクスは前提条件を満足しない限りは以下の操作を使用しない)。
リストは機能的なものである — リスト自身を変更するための表記は存在しない。
T が意味領域であれば T[] は要素が T のメンバである全てのリストの意味領域である。空リスト [] はあらゆる T について T[] のメンバである。
上記に加えて、リストでは集合と同じく数量詞 some 、every が使用可能である:
some x u satisfies predicate(x)
every x u satisfies predicate(x)
リストにおけるこれらの数量詞の振る舞いは集合におけるものに似ている。異なるのは数量詞 some が true を返したら変数 x にはリスト u の要素の内、条件 predicate(x) を満たす最初のものが設定されるという点である。例えば、
some x [3, 36, 19, 26] satisfies x mod 10 = 6
は true と評価され、x には36が設定される。
Char16 コード単位のリストは文字列と呼ばれる。通常のリストの表記に加え、文字列には0以上の文字を二重引用符で囲った簡便記法が使用できる (「非 ASCII 文字の表記法」も見よ)。例えば、
“Wonder«LF»”
は以下と等価である:
[‘W’, ‘o’, ‘n’, ‘d’, ‘e’, ‘r’, ‘«LF»’]
空文字列は “” のように書く。
文字列が保持するのはコード単位であってコードポイントではない。Unicode 補助文字を文字列に格納するときはサロゲートペアを使って表現する。
他の全てのリスト演算に加えて、文字列では < 、 、> 、 が定義されている。文字列 x が文字列 y より小さいのは y が空文字列でなく x が空文字列の場合、x の最初のコード単位が y の最初のコード単位より小さい場合、或いは x と y の最初のコード単位が等しく x の残りの文字列が y の残りの文字列よりも小さい場合のいずれかである。
これらの関係演算ではコードポイントではなくコード単位を比較するため、サロゲートペアに展開された補助文字を含む文字列では予期せぬ効果がある可能性があるということに注意していただきたい。例えば
‘«uFFFF»’ < ‘«U00010000»’
であるが、補助文字 ‘«U00010000»’ の文字列内での表現は
“«uD800»«uDC00»” であり、上記の規則に従えば
“«uFFFF»” > “«uD800»«uDC00»”
となる。
String は全文字列の意味領域であり、String = Char16[] である。
[訳注: タプルやレコードなどの表記に使う2つの括弧 (U+2329: Left-Pointing Angle Bracket と U+232A: Right-Pointing Angle Bracket) は対応しているフォントが少なく、太字にすると正しく表示できないブラウザがあるようだ。気休めだが和訳版ではマウスカーソルを重ねると文字をポップアップするようにしたが、本文自体は変えていない]
タプルは1つの名前と0以上のラベル付けされたフィールドからなる値の変更不能な集合体である。
擬似コードは各タプルを定義し、そのフィールドを記述する。タプルの定義は次のような形式で、
各意味領域が T1 から Tn である n 個のフィールドを持つ名前 Name のタプルを定義する。HTML 版では Name はその定義へのリンクになっている。
Namelabel1: v1, ... , labeln: vn
label1 から labeln でラベル付けされた各フィールドの値がそれぞれ v1 から vn である名前 Name のタプルを表す。各値 vi は対応する意味領域 Ti のメンバである。大半のフィールドを既存のタプル a からコピーする場合、この表記は次のように短縮でき、
Namelabeli1: vi1, ... , labelik: vik, other fields from a
名前が Name で、ラベル labeli1 から labelik のフィールド値がそれぞれ vi1 から vik 、その他のフィールドを対応するラベルの a の要素からコピーしたタプルを表す。
a がタプル Namelabel1: v1, ... , labeln: vn であるとき、
a.labeli
i 番目のフィールドの値 vi を返す。タプルは機能的なものである — タプル自身を変更するための表記は存在しない。HTML 版では labeli は a の型へのリンクになっている。
等価演算子 = 、 はタプルを比較するのに使用できる。タプルが等しいのは名前が同じで、対応するフィールドの値が等しい場合である。
次の表記は
Name
名前が Name である全てのタプルの意味領域を表す。
レコードはタプルに似た値の変更可能な集合体だが、等価性の振る舞いが異なる。
レコードは名前とアドレスで構成される。アドレスは0以上のラベル付けされたフィールドで構成される変更可能なデータ構造体を指し、レコードの通し番号として機能する — new (後述) によって確保されたレコードは、同じ式で作成されたものや1つの式を2度使って作成されたものも含めて全て異なるアドレスを持つ。
擬似コードは各レコードを定義し、そのフィールドを記述する。レコードの定義は次のような形式で、
意味領域が T1 から Tn までの n 個のフィールドを持つ名前 Name のレコードを定義する。HTML 版では Name はその定義へのリンクになっている。
new Namelabel1: v1, ... , labeln: vn
名前 Name と新アドレス からなるレコードを作成する。アドレス における label1 から labeln でラベル付けされたフィールドは、それぞれ v1 から vn の値で初期化される。各値 vi は対応する意味領域 Ti のメンバである。フィールド labelk の初期値は重要ではないことを示すために、new 式の labelk: vk 対は省略してもよい。これはセマンティクスがある値を読む前に必ず明示的にその値に書き込むからである。
大半のフィールドを既存のレコード a からコピーする場合、new 式は次のように短縮でき、
new Namelabeli1: vi1, ... , labelik: vik, other fields from a
名前 Name と新アドレス からなるレコードを表現する。アドレス における labeli1 から labelik でラベル付けされたフィールドは、それぞれ vi1 から vik の値で初期化される。アドレス における他のフィールドは a のアドレスで対応するラベルのフィールド値で初期化される。
a.labeli
はアドレス における i 番目のフィールドの現在値を返す。このフィールドには代入
a.labeli w
により、新しい値 w (意味領域 Ti のメンバでなければならない) を設定することができ、以降 a.labeli は w と評価される。異なるアドレス を持つレコードには影響は無い。HTML 版では各 labeli は a の型へのリンクになっている。
レコードの比較には等価演算子 = 、 が使用できる。レコードが等しいのは同じアドレスを持つ場合だけである。
次の表記は
name
名前 Name と全てのアドレスを持つ全レコードの無限の意味領域を表す。
JavaScript は (誤差などの無い) 本当の実数を、プログラマが使用できるデータ型としてサポートしない。代わりに JavaScript の数値は有限の範囲と精度を持つ。JavaScript で表現可能なプログラマが使用する全ての数値の意味領域は GeneralNumber で、4つの基本的な数値の意味領域 Long 、ULong 、Float32 、及び Float64 の和集合として定義される。
4つの基本数値意味領域は互いに、そして意味領域 Integer 、Rational 、及び Real と共通要素を持たない。[訳注: 後述されてように4つの基本数値意味領域はタプルであり、同じ数値を保持しても共通元を持つことにはならない]
意味領域 FiniteGeneralNumber は GeneralNumber の全有限数の派生型である:
プログラマが使用する符号付き64ビット長整数は意味領域 Long により表現される。これらは意味領域 ULong 、Float32 、及び Float64 のメンバとの共通要素を持たないように1つのタプルでラップされる。
本仕様では、i が –263 以上 263 – 1 以下の整数であれば、ilong という表記は Longvalue: i の結果を示し、Long タプルにラップされた整数 i を表す。
プログラマが使用する符号無し64ビット長整数は意味領域 ULong で表現される。これらは意味領域 Long 、Float32 、及び Float64 のメンバとの共通要素を持たないように1つのタプルでラップされる。
本仕様では、i が 0 以上 264 – 1 以下の整数であれば、iulong という表記は ULongvalue: i の結果を示し、ULong タプルにラップされた整数 i を表す。
Float32 は表現可能な全ての IEEE 754 単精度浮動小数点値の意味領域で、互いに区別できる全ての非数値も含まれる。Float32 は以下の意味領域の和集合である:
0でない有限値は意味領域 Long 、ULong 、及び Float64 のメンバとの共通要素を持たないように1つのタプルでラップされる。残りの値は +zerof32 (正0)、–zerof32 (負0)、+f32 (正の無限大)、–f32 (負の無限大)、及び NaNf32 (非数) の各タグである。
正規化された値は4261412864 (232–225) ある:
m を有効数字という
また、正規化されていない値は16777214 (224–2) ある:
m を有効数字という
value が0より大きい意味領域 NonzeroFiniteFloat32 のメンバを正の有限値といい、NonzeroFiniteFloat32 の残りのメンバを負の有限値という。
浮動小数点数はタグ、或いは有理数をラップするタプルのいずれかであるので、表記
= 、 をそれらの比較に使用できる。異なるタグに対して = は
false になるので +zerof32 –zerof32
だが NaNf32 = NaNf32
となる点に注意していただきたい。isEqual と
isStrictlyEqual で定義されるとおり、JavaScript の
x == y 及び x === y 演算子は
Float32 の値に対して異なる振る舞いをする。
本仕様では、x が実数であれば、xf32 という表記は realToFloat32(x) の結果を示し、以下に定義する “最も近い” Float32 値を表す。例えば3.4はReal であるが、3.4f32 は Float32 値である (その正確な value は実際には3.400000095367431640625である)。正の有限な Float32 値の範囲は10–45f32 から (3.4028235 1038)f32 である。
このプロシジャは IEEE 754 の “四捨五入” モードの振る舞いに厳密に対応するものである。
truncateFiniteFloat32 プロシジャは FiniteFloat32 値を0方向への丸めにより整数に切り詰める:
以下の表では IEEE 754 の規則に従った Float32 値の符号反転を定義する。exprf32 が realToFloat32(expr) の結果を表していることに注意していただきたい。
| x | 結果 |
| –f32 | +f32 |
| 負の有限値 | (–x.value)f32 |
| –zerof32 | +zerof32 |
| +zerof32 | –zerof32 |
| 正の有限値 | (–x.value)f32 |
| +f32 | –f32 |
| NaNf32 | NaNf32 |
Float64 は表現可能な全ての IEEE 754 倍精度浮動小数点値の意味領域で、互いに区別できる全ての非数値も含まれる。Float64 は以下の意味領域の和集合である:
0でない有限値は意味領域 Long 、ULong 、及び Float32 のメンバとの共通要素を持たないように1つのタプルでラップされる。残りの値は +zerof64 (正0)、–zerof64 (負0)、+f64 (正の無限大)、–f64 (負の無限大)、及び NaNf64 (非数) の各タグである。
正規化された値は18428729675200069632 (264–254) ある:
m を有効数字という
また、正規化されていない値は9007199254740990 (253–2) ある:
m を有効数字という
value が0より大きい意味領域 NonzeroFiniteFloat64 のメンバを正の有限値といい、NonzeroFiniteFloat64 の残りのメンバを負の有限値という。
浮動小数点数はタグ、或いは有理数をラップするタプルのいずれかであるので、表記
= 、 をそれらの比較に使用できる。異なるタグに対して = は
false になるので +zerof64 –zerof64
だが NaNf64 = NaNf64
となる点に注意していただきたい。isEqual と
isStrictlyEqual で定義されるとおり、JavaScript の
x == y 及び x === y 演算子は
Float64 の値に対して異なる振る舞いをする。
本仕様では、x が実数であれば、xf64 という表記は realToFloat64(x) の結果を示し、以下に定義する “最も近い” Float64 値を表す。例えば3.4はReal であるが、3.4f64 は Float64 値である (その正確な value は実際には3.399999999999999911182158029987476766109466552734375である)。正の有限な Float64 値の範囲は (5 10–324)f64 から (1.7976931348623157 10308)f64 である。
realToFloat64 プロシジャは以下のように実数 x を Float64 の適切な要素に変換する:
このプロシジャは IEEE 754 の “四捨五入” モードの振る舞いに厳密に対応するものである。
float32ToFloat64 プロシジャは以下の表に示すとおり Float32 数値 x を相当する Float64 数値に変換する:
| x | 結果 |
| –f32 | –f64 |
| –zerof32 | –zerof64 |
| +zerof32 | +zerof64 |
| +f32 | +f64 |
| nanf32 | nanf64 |
| あらゆる NonzeroFiniteFloat32 値 | NonzeroFiniteFloat64value: x.value |
truncateFiniteFloat64 プロシジャは FiniteFloat64 値を0方向への丸めにより整数に切り詰める:
以下の表では IEEE 754 の規則に従った Float64 値の主要な計算を定義する。exprf64 が realToFloat64(expr) の結果を表していることに注意していただきたい。
| x | 結果 |
| –f64 | +f64 |
| 負の有限値 | (–x.value)f64 |
| –zerof64 | +zerof64 |
| +zerof64 | +zerof64 |
| 正の有限値 | x |
| +f64 | +f64 |
| NaNf64 | NaNf64 |
| x | 結果 |
| –f64 | +f64 |
| 負の有限値 | (–x.value)f64 |
| –zerof64 | +zerof64 |
| +zerof64 | –zerof64 |
| 正の有限値 | (–x.value)f64 |
| +f64 | –f64 |
| NaNf64 | NaNf64 |
| x | y | ||||||
| –f64 | 負の有限値 | –zerof64 | +zerof64 | 正の有限値 | +f64 | NaNf64 | |
| –f64 | –f64 | –f64 | –f64 | –f64 | –f64 | NaNf64 | NaNf64 |
| 負の有限値 | –f64 | (x.value + y.value)f64 | x | x | (x.value + y.value)f64 | +f64 | NaNf64 |
| –zerof64 | –f64 | y | –zerof64 | +zerof64 | y | +f64 | NaNf64 |
| +zerof64 | –f64 | y | +zerof64 | +zerof64 | y | +f64 | NaNf64 |
| 正の有限値 | –f64 | (x.value + y.value)f64 | x | x | (x.value + y.value)f64 | +f64 | NaNf64 |
| +f64 | NaNf64 | +f64 | +f64 | +f64 | +f64 | +f64 | NaNf64 |
| NaNf64 | NaNf64 | NaNf64 | NaNf64 | NaNf64 | NaNf64 | NaNf64 | NaNf64 |
| x | y | ||||||
| –f64 | 負の有限値 | –zerof64 | +zerof64 | 正の有限値 | +f64 | NaNf64 | |
| –f64 | NaNf64 | –f64 | –f64 | –f64 | –f64 | –f64 | NaNf64 |
| 負の有限値 | +f64 | (x.value – y.value)f64 | x | x | (x.value – y.value)f64 | –f64 | NaNf64 |
| –zerof64 | +f64 | (–y.value)f64 | +zerof64 | –zerof64 | (–y.value)f64 | –f64 | NaNf64 |
| +zerof64 | +f64 | (–y.value)f64 | +zerof64 | +zerof64 | (–y.value)f64 | –f64 | NaNf64 |
| 正の有限値 | +f64 | (x.value – y.value)f64 | x | x | (x.value – y.value)f64 | –f64 | NaNf64 |
| +f64 | +f64 | +f64 | +f64 | +f64 | +f64 | NaNf64 | NaNf64 |
| NaNf64 | NaNf64 | NaNf64 | NaNf64 | NaNf64 | NaNf64 | NaNf64 | NaNf64 |
| x | y | ||||||
| –f64 | 負の有限値 | –zerof64 | +zerof64 | 正の有限値 | +f64 | NaNf64 | |
| –f64 | +f64 | +f64 | NaNf64 | NaNf64 | –f64 | –f64 | NaNf64 |
| 負の有限値 | +f64 | (x.value y.value)f64 | +zerof64 | –zerof64 | (x.value y.value)f64 | –f64 | NaNf64 |
| –zerof64 | NaNf64 | +zerof64 | +zerof64 | –zerof64 | –zerof64 | NaNf64 | NaNf64 |
| +zerof64 | NaNf64 | –zerof64 | –zerof64 | +zerof64 | +zerof64 | NaNf64 | NaNf64 |
| 正の有限値 | –f64 | (x.value y.value)f64 | –zerof64 | +zerof64 | (x.value y.value)f64 | +f64 | NaNf64 |
| +f64 | –f64 | –f64 | NaNf64 | NaNf64 | +f64 | +f64 | NaNf64 |
| NaNf64 | NaNf64 | NaNf64 | NaNf64 | NaNf64 | NaNf64 | NaNf64 | NaNf64 |
| x | y | ||||||
| –f64 | 負の有限値 | –zerof64 | +zerof64 | 正の有限値 | +f64 | NaNf64 | |
| –f64 | NaNf64 | +f64 | +f64 | –f64 | –f64 | NaNf64 | NaNf64 |
| 負の有限値 | +zerof64 | (x.value / y.value)f64 | +f64 | –f64 | (x.value / y.value)f64 | –zerof64 | NaNf64 |
| –zerof64 | +zerof64 | +zerof64 | NaNf64 | NaNf64 | –zerof64 | –zerof64 | NaNf64 |
| +zerof64 | –zerof64 | –zerof64 | NaNf64 | NaNf64 | +zerof64 | +zerof64 | NaNf64 |
| 正の有限値 | –zerof64 | (x.value / y.value)f64 | –f64 | +f64 | (x.value / y.value)f64 | +zerof64 | NaNf64 |
| +f64 | NaNf64 | –f64 | –f64 | +f64 | +f64 | NaNf64 | NaNf64 |
| NaNf64 | NaNf64 | NaNf64 | NaNf64 | NaNf64 | NaNf64 | NaNf64 | NaNf64 |
| x | y | |||
| –f64, +f64 | 正、或いは負の有限値 | –zerof64, +zerof64 | NaNf64 | |
| –f64 | NaNf64 | NaNf64 | NaNf64 | NaNf64 |
| 負の有限値 | x | float64Negate(float64remainder(float64Negate(x), y)) | NaNf64 | NaNf64 |
| –zerof64 | –zerof64 | –zerof64 | NaNf64 | NaNf64 |
| +zerof64 | +zerof64 | +zerof64 | NaNf64 | NaNf64 |
| 正の有限値 | x | (x.value – |y.value|x.value/|y.value|)f64 | NaNf64 | NaNf64 |
| +f64 | NaNf64 | NaNf64 | NaNf64 | NaNf64 |
| NaNf64 | NaNf64 | NaNf64 | NaNf64 | NaNf64 |
float64remainder(float64Negate(x), y) が float64Negate(float64remainder(x, y)) と常に同じ結果を生成することに注意していただきたい。また float64remainder(x, float64Negate(y)) は float64remainder(x, y) と常に同じ結果を生成する。
プロシジャ (手続き) は0以上の (実) 引数を受け取り、処理を行い、必要があれば結果を返す関数である。プロシジャは副作用を生じてもよい。このドキュメント中のプロシジャという語は内部アルゴリズムを指すのに使用する。関数という語は
JavaScript でプログラマが使用する function 構成物を指す。
プロシジャは以下のように表記する:
プロシジャが値を返さない場合は最初の行の : T は省く。
f はプロシジャ名、param1 から paramn はプロシジャの仮引数、T1 から Tn は各引数の意味領域、T は戻り値の意味領域、そして step1 から stepm はプロシジャの処理手順を示すもので、副作用を生じたり結果を返したりする。T が省略されていればそのプロシジャは結果を返さない。プロシジャが実引数 v1, ..., vn を伴って呼び出されると、プロシジャの本体が処理され、必要に応じて結果が呼び出し側に返される。
プロシジャの本体は param1 から paramn の仮引数を参照することができ、引数 parami の各参照は相当する実引数 vi の値として評価される。プロシジャの仮引数は静的なスコープを持ち、実引数は値渡しで渡される。
プロシジャ f に対する唯一の操作は、構文 f(arg1, ..., argn) による呼び出しである。まず最初に f が処理され、次に引数式 arg1 から argn が左から右の順で処理される。f かいずれかの引数式の処理が例外 e をスローした場合、呼び出しは後続の引数式を処理することなく直ちに e を伝播する。そうでなければ与えられた引数を使って f が呼び出され、結果の値があれば呼び出し側に返される。
プロシジャは = 、 、その他比較演算子で比較することはできない。
各引数の意味領域が T1 から Tn の n 個の仮引数を持ち、結果の意味領域が T であるプロシジャの意味領域は T1 T2 ... Tn T と書く。n = 0 であればこの意味領域は () T と書き、プロシジャが結果を返さない場合は T1 T2 ... Tn () や () () と書く。
プロシジャの処理手順は英語と形式的な表記の両方で記述する。形式的な手順の幾つかは本節で説明する。複数の手順はセミコロンで区切り、それ以前の手順が return や例外の伝播により終了しない限りそのままの順序で処理される。
形式的でない手順は不変でありコメントの提示に使用される。
Informal steps state invariants and provide comments.
手順 nothing は何もしない。
手順 note は何もせず、アルゴリズムについて (有益な) コメントを示すのに使用する。Comment が式であれば、手順 note はその時点でその式を評価すると true になるという表明を行うコメントになる。
処理手順は1つの式で構成することもできる。式は評価され、その値があれば無視される。
代入手順は代入演算子 を使って表す。この手順は expression の値を計算し、その結果を一時変数か変更可能でグローバルな v に代入する。これがプロシジャ内でのその一時変数への最初の参照であれば、その変数の意味領域 T をリストに追加する。v に格納されるあらゆる値は意味領域 T のメンバであることが保証される。
この手順は v を意味領域 T の一時変数として代入無しで宣言する。他の手順が最初に値を代入するまで v が読み取られることは無い。
アクション内では、代入演算子 は他のアクション Action[nonterminali] を nonterminali の現在の展開に適用した結果の定義にも使用できる。非終端記号は現在の生成規則の左側か右側に現れなければならず、このような代入は Action[nonterminali] の値がアクションにより明示的に定義されない場合にのみ行われる。Action[nonterminali] の値が設定されるのは最高でも1回で、それ以降変更されることはない。同じ非終端記号が1つソースプログラム解析中に複数回展開される場合は、それらの展開は全て別々に扱われる。
一時変数はそれらを定義するプロシジャ (入れ子になっているものも含む) 内でローカルである。プロシジャは呼び出される毎に新しい一時変数の集合を取得する。
この形式の代入はレコード a のフィールド label の値を expression の値に設定する。
手順 if は expression1 を評価する。この式は true か false のいずれかに評価され、true であれば step の最初のリストが処理される。そうでなければ expression2 が評価、試験され、そうでなければその次へと続く。true と評価された expression が1つも無ければ else の後ろの step リストが処理される。else 節は省略可能で、その場合 true と評価された expression が1つも無ければいずれのアクションも行われない。
手順 case は expression を処理し、この式は値 v と評価される。v T1 であれば step の最初のリストが処理される。それ以外で v T2 であれば step の2番目のリストが処理される。以下同じである。v がいずれの Ti のメンバでもなければ else の後ろの step リストが処理される。else 節は省略可能で、その場合 v は必ずいずれかの Ti のメンバになる。
手順 while は expression を処理する。この式は true か false のいずれかに評価され、false であれば何のアクションも行われない。true であれば step のリストが処理され、再び expression が評価、試験される。この繰り返しは expression が true を返す限り (或いはプロシジャが return か例外の送出により終了しない限り) 続く。
手順 for each は expression を処理する。この式はセットかリスト A として評価され、変数 x を A の各要素に束縛しながら step のリストを繰り返し処理する。A がリストであれば x はリストの順序どおりに各要素に束縛され、A が集合であれば x が各要素に束縛される順序は任意である。この繰り返しは x が A の全ての要素に束縛された後 (或いはプロシジャが return か例外の送出により終了したとき) 終了する。
手順 return は expression を処理して値 v を取得し、値 v を伴って囲っているプロシジャから返る。囲っているプロシジャ内の以降の手順は処理されない。expression は省略可能であり、その場合囲っているプロシジャは結果を何も返さない。
手順 throw は expression を処理して v を得、外部に例外 v の送出を開始し、この例外が手順 catch により捕捉されるまで部分的に処理されていた手順とプロシジャ呼び出しの中止が繰り返される。囲っているプロシジャがこの例外を補足しない限りそのプロシジャ内の手順がそれ以上処理されることはない。
手順 try は1つ目の step リストを処理し、それが通常通り終了すれば (或いは何処かで return すれば) 手順 try は終了である。step のどれかが例外 e を送出した場合、e T であれば例外 e の伝播は停止し、変数 v が値 e に束縛され、2つ目の step リストが処理される。e T であれば例外 e の伝播は止まらない。
2つ目の step リストから送出された例外を手順 try が受け取ることはない。
外側の proc の内側に proc を1つの手順として入れ子にすることができる。この場合、内側のプロシジャはクロージャであり、外側のプロシジャの引数と一時変数にアクセスすることができる。
セマンティックアクションは文法とセマンティクス (意味) を結びつけるものである。セマンティックアクションはセマンティクスの意味を文法生成規則によるものと捉える。
セマンティックアクションの使用を示すために、例を見てその後セマンティックアクションの表記について解説することにする。
以下の文法と開始非終端記号 Numeral について考える:
この文法は許容できる入力の構文を定義しており、“37” 、“33#4” 、及び
“30#2” は構文的に許容できるが “1a”
はそうではない。しかしながらこの文法はこれらの入力が何を意味しているかを示していない。それはセマンティクスの仕事であり、文法規則の展開による解析木上のアクションにおいて定義される。この文法上で定義されるアクションの例と
(この例において) Value という開始 Numeral アクションを考える:
アクションの名前にはすみれ色の草書体フォント (violet cursive type) を使う。次の定義は、
アクション Value が非終端記号 Numeral
のあらゆる展開に適用可能で、その結果は Integer
であることを示す。このアクションは入力を整数にマップ、或いは例外を投げる。上記のコードは入力が “30#2”
のとき例外 syntaxError を投げる。
Numeral を展開するそれぞれの文法生成規則のために Numeral におけるアクション Value の定義は2つある:
1つのアクションのそれぞれの定義は展開の右側の終端、非終端記号においてアクションをとることが認められている。例えば、1番目の
Numeral 生成規則 (Numeral が
Digits に展開される) に適用された Value
は単純に非終端記号 Digits の展開にアクション DecimalValue
を適用し、結果を返す。一方、2番目の Numeral 生成規則
(Numeral が Digits #
Digits に展開される) に適用された Value は非終端記号
Digits の2つの展開に DecimalValue と
BaseValue を適用した結果を使って処理を行う。この場合展開の右側に同一の
Digits が2つ存在するため、DecimalValue と
BaseValue のどちらのアクションが処理するかを示すのに下付き文字を使う。
この定義はアクション BaseValue が非終端記号 Digits のあらゆる展開に適用可能で、その結果は1つの Integer 引数 base をとり、Integer を返すプロシジャであることを示す。このプロシジャの本体は Digits が何に展開されるかの場合分けになっており、プロシジャが呼び出されると非終端記号 Digits の展開に対応する場合が評価される。
Digit における Value アクションは意味式 (digitValue(Digit)) で非終端記号を直接使うことを示している。非終端記号 Digit のこのような使用は Digit 文法規則を展開して得られる文字への参照になる。
以下は幾つかの入力例でセマンティクスを完全に評価した結果である:
| 入力 | 結果 |
|---|---|
37 |
37 |
33#4 |
15 |
30#2 |
throw syntaxError |
非終端記号 N の規則についての名前 A の全てのアクションが繰り返しになっており、文法中の N の展開の右側にある非終端記号について A を呼ぶだけになることがある。このような場合はアクション A のセマンティクスは以下の例で示すように短縮される。
以下の文法規則が与えられているとき、
* Subexpression+ Subexpressionthis次の表記は
以下の短縮形である:
* Subexpression] do+ Subexpression2] dothis] do nothing以下のことに注意していただきたい:
propagates... 表記はアクションが値を返すときにも使用される。この場合、各展開はただ1つの非終端記号を持っていなければならない。例えば以下の文法規則が与えられているとき、
次の表記は
以下の短縮形である:
以下の表記は最上位意味実体を定義するのに使用する:
この表記は Name を意味領域 expression の略記として定義する。HTML 版では Name はその定義へのリンクになっている。
この表記は name を、expression の処理結果で与えられる値の定数として定義し、値は意味領域 T のメンバであることが保証される。HTML 版では name はその定義へのリンクになっている。
この表記は name を変更可能なグローバル値として定義する。その初期値は expression の処理結果であるが、後で代入により変更可能である。値は意味領域 T のメンバであることが保証される。HTML 版では name はその定義へのリンクになっている。
この表記は f をプロシジャとして定義する。
この表記はタグを定義する。
この表記はタプルを定義する。
この表記はレコードを定義する。
この表記はアクション Action が非終端記号 nonterminal について処理可能で、意味領域 T のメンバである値を返すということを示す。アクションの値は以下で述べる表記 Action[nonterminal expansion] = expression で定義されるか、或いはアクションの代入による他のアクション処理の副作用として設定される。
この表記は非終端記号 nonterminal が与えられた expansion に展開される場合にアクション Action を非終端記号 nonterminal について適用した値を規定する。expansion には0以上の終端、或いは非終端記号を含めることができる (他の表記が文法生成規則の右辺で認めているのと同じである)。更に expansion の終端、非終端記号は expression 内で明確にアクション参照、非終端参照されるように下付き文字を使うことができる。
この表記は上の2つの結合形である — 値だけではなくアクションの意味領域も規定する。
この表記はアクションの処理が1つの式で表すには複雑である場合に使用する。アクションを処理する手順は step1 から stepm のリストになっており、手順 return はアクションの値を生成する。
この表記は単一の展開 expansion が非終端記号 nonterminal に適用されて Action がプロシジャを返すときにのみ使用する。プロシジャの手順は step1 から stepm のリストになっている。
この表記は複数の展開 expansion1 から expansionn が非終端記号 nonterminal に適用されて Action がプロシジャを返すときにのみ使用する。このプロシジャの本体は各展開についての場合分けになっており、文法解析器を使用して発見された展開に対応する手順のみが評価される。
この表記は nonterminal についての Action の呼び出しが、nonterminal の適切な展開の右側の各非終端記号について同じ引数での呼び出しを表すということの短縮形である。
|
Waldemar Horwat 最終更新: 2003年6月13日 (金) |