123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432 |
- [[painless-operators-general]]
- === Operators: General
- [[precedence-operator]]
- ==== Precedence
- Use the `precedence operator '()'` to guarantee the order of evaluation for an
- expression. An expression encapsulated by the precedence operator (enclosed in
- parentheses) overrides existing precedence relationships between operators and
- is evaluated prior to other expressions in inward-to-outward order.
- *Grammar*
- [source,ANTLR4]
- ----
- precedence: '(' expression ')';
- ----
- *Examples*
- * Precedence with numeric operators.
- +
- [source,Painless]
- ----
- <1> int x = (5+4)*6;
- <2> int y = 12/(x-50);
- ----
- +
- <1> declare `int x`;
- add `int 5` and `int 4` -> `int 9`;
- multiply `int 9` and `int 6` -> `int 54`;
- store `int 54` to `x`;
- (note the add is evaluated before the multiply due to the precedence
- operator)
- <2> declare `int y`;
- load from `x` -> `int 54`;
- subtract `int 50` from `int 54` -> `int 4`;
- divide `int 12` by `int 4` -> `int 3`;
- store `int 3` to `y`;
- (note the subtract is evaluated before the divide due to the precedence
- operator)
- [[function-call-operator]]
- ==== Function Call
- Use the `function call operator ()` to call an existing function. A
- <<painless-functions, function call>> is defined within a script.
- *Grammar*
- [source,ANTLR4]
- ----
- function_call: ID '(' ( expression (',' expression)* )? ')'';
- ----
- *Examples*
- * A function call.
- +
- [source,Painless]
- ----
- <1> int add(int x, int y) {
- return x + y;
- }
- <2> int z = add(1, 2);
- ----
- +
- <1> define function `add` that returns `int` and has parameters (`int x`,
- `int y`)
- <2> declare `int z`;
- call `add` with arguments (`int 1`, `int 2`) -> `int 3`;
- store `int 3` to `z`
- [[cast-operator]]
- ==== Cast
- An explicit cast converts the value of an original type to the equivalent value
- of a target type forcefully as an operation. Use the `cast operator '()'` to
- specify an explicit cast. Refer to <<painless-casting, casting>> for more
- information.
- [[conditional-operator]]
- ==== Conditional
- A conditional consists of three expressions. The first expression is evaluated
- with an expected boolean result type. If the first expression evaluates to true
- then the second expression will be evaluated. If the first expression evaluates
- to false then the third expression will be evaluated. The second and third
- expressions will be <<promotion, promoted>> if the evaluated values are not the
- same type. Use the `conditional operator '? :'` as a shortcut to avoid the need
- for a full if/else branch in certain expressions.
- *Errors*
- * If the first expression does not evaluate to a boolean type value.
- * If the values for the second and third expressions cannot be promoted.
- *Grammar*
- [source,ANTLR4]
- ----
- conditional: expression '?' expression ':' expression;
- ----
- *Promotion*
- [cols="<1,^1,^1,^1,^1,^1,^1,^1,^1,^1"]
- |====
- | | byte | short | char | int | long | float | double | Reference | def
- | byte | int | int | int | int | long | float | double | - | def
- | short | int | int | int | int | long | float | double | - | def
- | char | int | int | int | int | long | float | double | - | def
- | int | int | int | int | int | long | float | double | - | def
- | long | long | long | long | long | long | float | double | - | def
- | float | float | float | float | float | float | float | double | - | def
- | double | double | double | double | double | double | double | double | - | def
- | Reference | - | - | - | - | - | - | - | Object @ | def
- | def | def | def | def | def | def | def | def | def | def
- |====
- @ If the two reference type values are the same then this promotion will not
- occur.
- *Examples*
- * Evaluation of conditionals.
- +
- [source,Painless]
- ----
- <1> boolean b = true;
- <2> int x = b ? 1 : 2;
- <3> List y = x > 1 ? new ArrayList() : null;
- <4> def z = x < 2 ? x : 2.0;
- ----
- +
- <1> declare `boolean b`;
- store `boolean true` to `b`
- <2> declare `int x`;
- load from `b` -> `boolean true`
- evaluate 1st expression: `int 1` -> `int 1`;
- store `int 1` to `x`
- <3> declare `List y`;
- load from `x` -> `int 1`;
- `int 1` greater than `int 1` -> `boolean false`;
- evaluate 2nd expression: `null` -> `null`;
- store `null` to `y`;
- <4> declare `def z`;
- load from `x` -> `int 1`;
- `int 1` less than `int 2` -> `boolean true`;
- evaluate 1st expression: load from `x` -> `int 1`;
- promote `int 1` and `double 2.0`: result `double`;
- implicit cast `int 1` to `double 1.0` -> `double 1.0`;
- implicit cast `double 1.0` to `def` -> `def`;
- store `def` to `z`;
- [[assignment-operator]]
- ==== Assignment
- Use the `assignment operator '='` to store a value in a variable or reference
- type member field for use in subsequent operations. Any operation that produces
- a value can be assigned to any variable/field as long as the
- <<painless-types, types>> are the same or the resultant type can be
- <<painless-casting, implicitly cast>> to the variable/field type.
- See <<variable-assignment, variable assignment>> for examples using variables.
- *Errors*
- * If the type of value is unable to match the type of variable or field.
- *Grammar*
- [source,ANTLR4]
- ----
- assignment: field '=' expression
- ----
- *Examples*
- The examples use the following reference type definition:
- [source,Painless]
- ----
- name:
- Example
- non-static member fields:
- * int x
- * def y
- * List z
- ----
- * Field assignments of different type values.
- +
- [source,Painless]
- ----
- <1> Example example = new Example();
- <2> example.x = 1;
- <3> example.y = 2.0;
- <4> example.z = new ArrayList();
- ----
- +
- <1> declare `Example example`;
- allocate `Example` instance -> `Example reference`;
- store `Example reference` to `example`
- <2> load from `example` -> `Example reference`;
- store `int 1` to `x` of `Example reference`
- <3> load from `example` -> `Example reference`;
- implicit cast `double 2.0` to `def` -> `def`;
- store `def` to `y` of `Example reference`
- <4> load from `example` -> `Example reference`;
- allocate `ArrayList` instance -> `ArrayList reference`;
- implicit cast `ArrayList reference` to `List reference` -> `List reference`;
- store `List reference` to `z` of `Example reference`
- +
- * A field assignment from a field access.
- +
- [source,Painless]
- ----
- <1> Example example = new Example();
- <2> example.x = 1;
- <3> example.y = example.x;
- ----
- +
- <1> declare `Example example`;
- allocate `Example` instance -> `Example reference`;
- store `Example reference` to `example`
- <2> load from `example` -> `Example reference`;
- store `int 1` to `x` of `Example reference`
- <3> load from `example` -> `Example reference @0`;
- load from `example` -> `Example reference @1`;
- load from `x` of `Example reference @1` -> `int 1`;
- implicit cast `int 1` to `def` -> `def`;
- store `def` to `y` of `Example reference @0`;
- (note `Example reference @0` and `Example reference @1` are the same)
- [[compound-assignment-operator]]
- ==== Compound Assignment
- Use the `compound assignment operator '$='` as a shortcut for an assignment
- where a binary operation would occur between the variable/field as the
- left-hand side expression and a separate right-hand side expression.
- A compound assignment is equivalent to the expression below where V is the
- variable/field and T is the type of variable/member.
- [source,Painless]
- ----
- V = (T)(V op expression);
- ----
- *Operators*
- The table below shows the available operators for use in a compound assignment.
- Each operator follows the casting/promotion rules according to their regular
- definition. For numeric operations there is an extra implicit cast when
- necessary to return the promoted numeric type value to the original numeric type
- value of the variable/field and can result in data loss.
- |====
- |Operator|Compound Symbol
- |Multiplication|*=
- |Division|/=
- |Remainder|%=
- |Addition|+=
- |Subtraction|-=
- |Left Shift|<<=
- |Right Shift|>>=
- |Unsigned Right Shift|>>>=
- |Bitwise And|&=
- |Boolean And|&=
- |Bitwise Xor|^=
- |Boolean Xor|^=
- |Bitwise Or|\|=
- |Boolean Or|\|=
- |String Concatenation|+=
- |====
- *Errors*
- * If the type of value is unable to match the type of variable or field.
- *Grammar*
- [source,ANTLR4]
- ----
- compound_assignment: ( ID | field ) '$=' expression;
- ----
- Note the use of the `$=` represents the use of any of the possible binary
- operators.
- *Examples*
- * Compound assignment for each numeric operator.
- +
- [source,Painless]
- ----
- <1> int i = 10;
- <2> i *= 2;
- <3> i /= 5;
- <4> i %= 3;
- <5> i += 5;
- <6> i -= 5;
- <7> i <<= 2;
- <8> i >>= 1;
- <9> i >>>= 1;
- <10> i &= 15;
- <11> i ^= 12;
- <12> i |= 2;
- ----
- +
- <1> declare `int i`;
- store `int 10` to `i`
- <2> load from `i` -> `int 10`;
- multiply `int 10` and `int 2` -> `int 20`;
- store `int 20` to `i`;
- (note this is equivalent to `i = i*2`)
- <3> load from `i` -> `int 20`;
- divide `int 20` by `int 5` -> `int 4`;
- store `int 4` to `i`;
- (note this is equivalent to `i = i/5`)
- <4> load from `i` -> `int 4`;
- remainder `int 4` by `int 3` -> `int 1`;
- store `int 1` to `i`;
- (note this is equivalent to `i = i%3`)
- <5> load from `i` -> `int 1`;
- add `int 1` and `int 5` -> `int 6`;
- store `int 6` to `i`;
- (note this is equivalent to `i = i+5`)
- <6> load from `i` -> `int 6`;
- subtract `int 5` from `int 6` -> `int 1`;
- store `int 1` to `i`;
- (note this is equivalent to `i = i-5`)
- <7> load from `i` -> `int 1`;
- left shift `int 1` by `int 2` -> `int 4`;
- store `int 4` to `i`;
- (note this is equivalent to `i = i<<2`)
- <8> load from `i` -> `int 4`;
- right shift `int 4` by `int 1` -> `int 2`;
- store `int 2` to `i`;
- (note this is equivalent to `i = i>>1`)
- <9> load from `i` -> `int 2`;
- unsigned right shift `int 2` by `int 1` -> `int 1`;
- store `int 1` to `i`;
- (note this is equivalent to `i = i>>>1`)
- <10> load from `i` -> `int 1`;
- bitwise and `int 1` and `int 15` -> `int 1`;
- store `int 1` to `i`;
- (note this is equivalent to `i = i&2`)
- <11> load from `i` -> `int 1`;
- bitwise xor `int 1` and `int 12` -> `int 13`;
- store `int 13` to `i`;
- (note this is equivalent to `i = i^2`)
- <12> load from `i` -> `int 13`;
- bitwise or `int 13` and `int 2` -> `int 15`;
- store `int 15` to `i`;
- (note this is equivalent to `i = i|2`)
- +
- * Compound assignment for each boolean operator.
- +
- [source,Painless]
- ----
- <1> boolean b = true;
- <2> b &= false;
- <3> b ^= false;
- <4> b |= true;
- ----
- +
- <1> declare `boolean b`;
- store `boolean true` in `b`;
- <2> load from `b` -> `boolean true`;
- boolean and `boolean true` and `boolean false` -> `boolean false`;
- store `boolean false` to `b`;
- (note this is equivalent to `b = b && false`)
- <3> load from `b` -> `boolean false`;
- boolean xor `boolean false` and `boolean false` -> `boolean false`;
- store `boolean false` to `b`;
- (note this is equivalent to `b = b ^ false`)
- <4> load from `b` -> `boolean true`;
- boolean or `boolean false` and `boolean true` -> `boolean true`;
- store `boolean true` to `b`;
- (note this is equivalent to `b = b || true`)
- +
- * A compound assignment with the string concatenation operator.
- +
- [source,Painless]
- ----
- <1> String s = 'compound';
- <2> s += ' assignment';
- ----
- <1> declare `String s`;
- store `String 'compound'` to `s`;
- <2> load from `s` -> `String 'compound'`;
- string concat `String 'compound'` and `String ' assignment''`
- -> `String 'compound assignment'`;
- store `String 'compound assignment'` to `s`;
- (note this is equivalent to `s = s + ' assignment'`)
- +
- * A compound assignment with the `def` type.
- +
- [source,Painless]
- ----
- <1> def x = 1;
- <2> x += 2;
- ----
- <1> declare `def x`;
- implicit cast `int 1` to `def`;
- store `def` to `x`;
- <2> load from `x` -> `def`;
- implicit cast `def` to `int 1` -> `int 1`;
- add `int 1` and `int 2` -> `int 3`;
- implicit cast `int 3` to `def` -> `def`;
- store `def` to `x`;
- (note this is equivalent to `x = x+2`)
- +
- * A compound assignment with an extra implicit cast.
- +
- [source,Painless]
- ----
- <1> byte b = 1;
- <2> b += 2;
- ----
- <1> declare `byte b`;
- store `byte 1` to `x`;
- <2> load from `x` -> `byte 1`;
- implicit cast `byte 1 to `int 1` -> `int 1`;
- add `int 1` and `int 2` -> `int 3`;
- implicit cast `int 3` to `byte 3` -> `byte 3`;
- store `byte 3` to `b`;
- (note this is equivalent to `b = b+2`)
|