演算子・式

この章では、KLでの受付可能な演算子、結果とし生じる式について説明します。一般的にKLは JavaScript、C言語と同じ演算子と式についての文法をもち、特に優先順位と結合規則は全く同一です。

演算子

KLは、JavaScriptやC言語と同様の基本的な演算子を持ちます。おおまかに分類すると 算術演算子, 論理演算子, ビット演算子 and 代入演算子 です。

算術演算子

加算・減算

+ もしくは - を2つの式の間に置くと、加算( add )、減算( subtract )2項演算子として扱います。これらの演算子は、全ての整数、浮動小数点数型に組み込みで定義され、通常の算術演算を実行します。ユーザ定義の、構造体あるいは他の型の組み合わせに対し、演算子のオーバーロードを適用することも可能です。例えば、左項にユーザ定義の Rect 、右項に Point をとるようなある演算子を定義することが可能です。

+ 加算演算子 ( - 減算演算子ではなく)は、 整数・浮動小数点数型の組み込み定義されたものに加え、文字列型にも定義されています。2つの文字列を加算すると、2つの文字列を連結します。

乗算・除算、剰余

*, /, % を2つの式の間に置くと、乗算、除算、剰余( multiply, divide and remainder )2項演算子として扱います。これらの演算子は全ての整数・浮動小数点数型について組み込み定義され、通常の算術演算を行います。ユーザ定義の、構造体あるいは他の型の組み合わせに対し、演算子のオーバーロードを適用することも可能です。例えば、左項にユーザ定義の Float32 、右項に Vec3 をとるようなある演算子を定義することが可能です。

単項のプラス・マイナス

+ または - 演算子を、整数・浮動小数点数式の直前に左辺になにも式を置かずおくと、 unary plusunary minus 演算子として扱います。単項プラス演算子は値に対して何も作用しませんが、単項マイナス演算子は、符号なし整数式の場合:0、符号付き整数および符号付き浮動小数点数の場合:符号を反転させた値、を生成します。

インクリメント・デクリメント演算子

++ (インクリメント)、 -- (デクリメント)演算子は、変数のひとつ加算、減算に用います。これらの演算子は以下の特徴があります。

  • 変数、もしくは入出力パラメータ(io parameter)のみに使用可能です。式の値を変更するため定数や入力パラメータ(input parameter)は操作できません。
  • 整数値のみ操作できます。
  • どの演算子も、変数に対し前置あるいは後置のどちらでも作用します。前置する場合、式の値は変数のインクリメント の値となります。これは prefix インクリメント(デクリメント)と呼ばれます。後置する場合、式の値は変数のインクリメント の値となります。これは postfix インクリメント(デクリメント)と呼ばれます。
  • オーバーロード不可能です。

論理演算子

等価演算子(Equality Operators)

== あるいは != を2つの式の間におくと、 equal-to あるいは not-equal-to 2項演算子として扱います。2つまとめて等価演算子( equality operators )と呼びます。

等価演算子は、全ての整数・浮動小数点数型、 BooleanString 型について組み込み定義されています。ユーザ定義の構造体や、特定のオブジェクト、型のコンビネーションに対してオーバーロードが可能です。

同一性演算子(Identity Operators)

=== あるいは !== を2つの式の間に置くと、 identical-to あるいは not-identical-to 2項演算子として扱います。2つまとめて同一性演算子 identity operators と呼びます。

同一性演算子は、 object 型interface types 型のみに事前定義されています。2つのオブジェクト(もしくはインタフェース)が同じオブジェクトを参照するか ―つまり片方への変更がもう片方にも作用するかどうかをテストします。

関係演算子(Relational Operators)

<, <=, > or >= を2つの式の間に置くと、less-than, less-than-or-equal-to, greater-than, greater-than-or-equal-to 2項演算子として扱います。まとめて関係演算子と呼びます。

関係演算子は、全ての整数・浮動小数点数、文字列型に対し事前定義されています。ユーザ定義の構造体、型のコンビネーションに対してオーバーロードが可能です。

論理 AND

&& を2つの式の間におくと、 logical AND として扱います。論理AND 演算子は以下のように振る舞います。左オペランドを Boolean にキャストし true であれば、 演算子の結果は右オペランド、 false であれば結果は左オペランド。(左オペランドをキャストするということはつまり、左オペラントより Boolean の値がコンストラクトされるということです)

警告

論理AND の動作はJavaScriptと同じですが、C言語とは異なります。Cでは、論理ANDの結果は常に整数です。(C++ では bool)

論理AND 演算子のオーバロードは不可能です。ただし、カスタム型(構造体)に対し、 Boolean コンストラクタを作成し、そのコンストラクタを左オペラントの型と同じ型をパラメータを1つとるように定義することで、論理AND を有効にすることはできます。

論理 OR

|| を2つの式の間におくと、 logical OR として扱います。論理 OR 演算子は以下のように振る舞います。左オペランドを Boolean にキャストし true であれば、 演算子の結果は左オペランド、 false であれば結果は右オペランド。(左オペランドをキャストするということはつまり、左オペラントより Boolean の値がコンストラクトされるということです)

警告

論理OR の動作はJavaScriptと同じですが、C言語とは異なります。Cでは、論理ORの結果は常に整数です。(C++ では bool)

論理OR 演算子のオーバロードは不可能です。ただし、カスタム型(構造体)に対し、 Boolean コンストラクタを作成し、そのコンストラクタを左オペラントの型と同じ型をパラメータを1つとるように定義することで、論理OR を有効にすることはできます。

論理 NOT

! (エクスクラメーションびっくりマーク)を式の前につけると、論理NOT logical NOT 単項演算子として扱います。論理NOTは式の論理値を反転させます。具体的な挙動は、まず式から新たな Boolean 値をコンストラクトし、その論理値を反転します。したがって論理NOTは、式の型がそのパラメータの型と同じ、単一のパラメータをとる Boolean コンストラクタを持つどのような式にも使用可能です。

論理NOT 演算子のオーバロードは不可能です。ただし、カスタム型(構造体)に対し、 Boolean コンストラクタを作成し、そのコンストラクタを左オペラントの型と同じ型をパラメータを1つとるように定義することで、論理NOT を有効にすることはできます。

条件演算子

3つの式を、 ? (感嘆符)と : (コロン) により分割すると、条件演算子 conditional operator (あるいは3項演算子 ternary operator) として扱います。3項演算子は1つめのオペランドより Boolean をコンストラクト、その値が true であれば2番めのオペランド、 false であれば3番めのオペランドが結果となります。

3項演算子をオーバーロードすることはできません。

コンマ演算子

, (コンマ)により2つの式を分割すると、コンマ演算子 comma operator として扱います。コンマ演算子は、最初に左側の式を評価し、結果を捨て、右側の式を評価します。右側の式の値がこの演算子の式の値となります。

コンマ演算子をオーバーロードすることはできません。

ビット演算子

ビット AND・OR・XOR

&, |, ^ を2つの式の間に置くと、それぞれ bitwise AND, bitwise OR, bitwise XOR として扱います。

ビット AND・OR・XOR は全ての整数型に事前定義されています。2つの値における通常のビット演算を行います。 Boolean 型にも事前定義されています。どちらも単一ビット 1 (true) あるいは 0 (false)であるかのように扱われます。

ビット AND・OR・XOR はユーザ定義の構造体、型のコンビネーションに対しオーバーロード不可能です。

ビットNOT

~ (チルダ)を式の前に置くと、ビット NOT bitwise NOT 単項演算子として扱います。

ビット NOTは、全ての整数型に事前定義されています。。値のビット状態を反転させます。 Boolean 型にも事前定義されています。どちらも単一ビット 1 (true) あるいは 0 (false)であるかのように扱われます。

左・右シフト

<< もしくは >> を2つの式の間に置くと、 left shift もしくは right shift 2項演算子として扱います。全ての整数型に事前定義されています。左側のオペランドを右側のオペランドに与えられたビット数によって、左・右ビットシフト行います。

符号付き整数の値の右シフトは、左端のビットを符号ビットで埋めます。0ではありません。符号なし整数の値の右シフト、そして符号ありなし両方の整数の左シフトは、常に0で埋まります。

シフト演算子はユーザ定義の型、さらに整数型以外のものでも、右側オペランドとしてオーバロードが可能です。

代入演算子

直接代入演算子

= 演算子を2つの式の間に置くと、直接代入演算子 direct assignment operator として扱います。直接代入演算子は全ての型で事前定義されています。 KLの型システム により詳しい代入の仕組みを参照してください。どのような型でもこの演算子のオーバロードが可能です。 直接代入のオーバロード 参照

複合代入演算子

どのような算術、ビット(論理演算子は含めない)2項演算子も、 = と組み合わせて複合代入演算子 compound assignment operator とすることができます。具体的には +=, -=, *=, /=, %=, <<=, >>=, &=, ^= and |=

複合代入演算子は、その型に対して事前定義されている2項演算子であれば、事前定義されています。複号代入演算子はオーバーロード可能です。左オペランドと右オペランドの型が違う場合でも可能です。 複合代入演算子のオーバロード を参照してください。

演算子と多態性(Operators and Polymorphism)

演算子・オペレータの呼び出しは多態性に関して、関数呼び出しにおけるそれと同じルールが適用されます。あるオペレータが以下の条件 ―そのオペレータのパラメータの型とオペランドの型が厳密に一致しない場合、KLはそのオペレータの既存の実装の中から最適なものを探します。これにより例えば、整数と文字列を加算える事ができます。つまり、まず整数が文字列へとキャストされます。その文字列と文字列が連結されます。

多態についてと、最適なもの探索ルールについてのさらなる情報は ポリモーフィズム を参照してください。

式(Expressions)

KLには2種の式があります。単純式と複合式です。

単純式

単純式 Simple expressions とはより複雑な式を導出するためのものです。単純式とは:

  • 変数を参照するシンボルであり、関数の引数であり、あるいは定数であります。単純式の型は、参照するデータの実態(entity)の型となります。例:: foo, myParam, mathPI. シンボルがどのように解決されるかは Scoping Rules を参照してください。
  • Boolean, integer, floating-point, string 定数。この単純式の方は、すなわち定数の型です。例:: true, 42, 3.14159, FILE, LINE. 定数 を参照してください。

複雑式

複雑式 Compound expressionssimple expressions と(もしくは) operators を使用した複雑式により構成されます。

以下のテーブルリストにすべての異なる複雑式を列挙します。複雑式は type によりグループ分けされます。つまり、同じタイプに属するすべての式は、同じ順序であり同じ結合性を持ちます。以下のリストでは複雑式のタイプを優先順位の高いもの順に記載します。

タイプ 結合規則 式(複数可)
後置 左から右 functionName(args)
expr[expr]
expr.member
expr.method(args)
expr++
expr--
前置 右から左 +expr
-expr
++expr
--expr
!expr
~expr
乗法 左から右 expr * expr
expr / expr
expr % expr
加法 左から右 expr + expr
expr - expr
シフト 左から右 expr << expr
expr >> expr
関係 左から右 expr < expr
expr <= expr
expr > expr
expr >= expr
等価 左から右 expr == expr
expr != expr
expr === expr
expr !== expr
ビット AND 左から右 expr & expr
ビット XOR 左から右 expr ^ expr
ビット OR 左から右 expr | expr
論理 AND 左から右 expr && expr
論理 OR 左から右 expr || expr
条件 右から左 expr? expr: expr
代入 右から左 expr = expr
expr += expr
expr -= expr
expr *= expr
expr /= expr
expr %= expr
expr <<= expr
expr >>= expr
expr &= expr
expr ^= expr
expr |= expr
コンマ 左から右 expr , expr

操作順の制御

操作の順序を明示的に制御することが可能です。式を () (括弧)で包みます。

/*
** Example: Order of Operations
*/

operator entry() {
  report( (2 * 3) + 5 );
  report( 2 * (3 + 5) );
}

/*
** Output:

11
16

*/