From d6a4c14e1bfe23aaa8c3ff67a6b57f695672b330 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Thu, 7 Jun 2018 17:11:56 -0700 Subject: [PATCH] Painless: Restructure/Clean Up of Spec Documentation (#31013) Full restructure of the spec into new sections for operators, statements, scripts, functions, lambdas, and regexes. Split of operators into 6 sections, a table, reference, array, numeric, boolean, and general. Clean up of all operators sections. Sporadic clean up else where. --- docs/painless/painless-casting.asciidoc | 226 +- docs/painless/painless-comments.asciidoc | 3 +- docs/painless/painless-functions.asciidoc | 24 + .../painless/painless-general-syntax.asciidoc | 81 - docs/painless/painless-identifiers.asciidoc | 8 +- docs/painless/painless-keywords.asciidoc | 10 +- docs/painless/painless-lambdas.asciidoc | 15 + docs/painless/painless-lang-spec.asciidoc | 20 +- docs/painless/painless-literals.asciidoc | 13 +- .../painless-operators-array.asciidoc | 294 +++ .../painless-operators-boolean.asciidoc | 1420 +++++++++++++ .../painless-operators-general.asciidoc | 432 ++++ .../painless-operators-numeric.asciidoc | 1339 ++++++++++++ .../painless-operators-reference.asciidoc | 774 +++++++ docs/painless/painless-operators.asciidoc | 1875 +---------------- docs/painless/painless-regexes.asciidoc | 33 + docs/painless/painless-scripts.asciidoc | 6 + docs/painless/painless-statements.asciidoc | 14 + docs/painless/painless-types.asciidoc | 233 +- docs/painless/painless-variables.asciidoc | 105 +- 20 files changed, 4775 insertions(+), 2150 deletions(-) create mode 100644 docs/painless/painless-functions.asciidoc delete mode 100644 docs/painless/painless-general-syntax.asciidoc create mode 100644 docs/painless/painless-lambdas.asciidoc create mode 100644 docs/painless/painless-operators-array.asciidoc create mode 100644 docs/painless/painless-operators-boolean.asciidoc create mode 100644 docs/painless/painless-operators-general.asciidoc create mode 100644 docs/painless/painless-operators-numeric.asciidoc create mode 100644 docs/painless/painless-operators-reference.asciidoc create mode 100644 docs/painless/painless-regexes.asciidoc create mode 100644 docs/painless/painless-scripts.asciidoc create mode 100644 docs/painless/painless-statements.asciidoc diff --git a/docs/painless/painless-casting.asciidoc b/docs/painless/painless-casting.asciidoc index a3624f90831..4bcd14cbfc6 100644 --- a/docs/painless/painless-casting.asciidoc +++ b/docs/painless/painless-casting.asciidoc @@ -4,8 +4,11 @@ A cast converts the value of an original type to the equivalent value of a target type. An implicit cast infers the target type and automatically occurs during certain <>. An explicit cast specifies -the target type and forcefully occurs as its own operation. Use the *cast -operator* to specify an explicit cast. +the target type and forcefully occurs as its own operation. Use the `cast +operator '()'` to specify an explicit cast. + +Refer to the <> for a quick reference on all +allowed casts. *Errors* @@ -13,6 +16,7 @@ operator* to specify an explicit cast. * If an implicit cast is given, but an explicit cast is required. *Grammar* + [source,ANTLR4] ---- cast: '(' TYPE ')' expression @@ -31,15 +35,15 @@ cast: '(' TYPE ')' expression + <1> declare `int i`; explicit cast `long 5` to `int 5` -> `int 5`; - assign `int 5` to `i` + store `int 5` to `i` <2> declare `Map m`; allocate `HashMap` instance -> `HashMap reference`; implicit cast `HashMap reference` to `Map reference` -> `Map reference`; - assign `Map reference` to `m` + store `Map reference` to `m` <3> declare `HashMap hm`; - access `m` -> `Map reference`; + load from `m` -> `Map reference`; explicit cast `Map reference` to `HashMap reference` -> `HashMap reference`; - assign `HashMap reference` to `hm` + store `HashMap reference` to `hm` [[numeric-type-casting]] ==== Numeric Type Casting @@ -78,19 +82,19 @@ following table: ---- + <1> declare `int a`; - assign `int 1` to `a` + store `int 1` to `a` <2> declare `long b`; - access `a` -> `int 1`; + load from `a` -> `int 1`; implicit cast `int 1` to `long 1` -> `long 1`; - assign `long 1` to `b` + store `long 1` to `b` <3> declare `short c`; - access `b` -> `long 1`; + load from `b` -> `long 1`; explicit cast `long 1` to `short 1` -> `short 1`; - assign `short 1` value to `c` + store `short 1` value to `c` <4> declare `double e`; - access `a` -> `int 1`; + load from `a` -> `int 1`; explicit cast `int 1` to `double 1.0`; - assign `double 1.0` to `e`; + store `double 1.0` to `e`; (note the explicit cast is extraneous since an implicit cast is valid) + * Invalid numeric type casts resulting in errors. @@ -106,9 +110,9 @@ following table: *error* -> cannot implicit cast `double 1.0` to `int 1`; (note an explicit cast is valid) <2> declare `int b`; - assign `int 2` to `b` + store `int 2` to `b` <3> declare byte `c`; - access `b` -> `int 2`; + load from `b` -> `int 2`; *error* -> cannot implicit cast `int 2` to `byte 2`; (note an explicit cast is valid) @@ -136,21 +140,21 @@ or the target type is a descendant of the original type. ---- + <1> declare `List x`; - assign default value `null` to `x` + store default value `null` to `x` <2> declare `ArrayList y`; allocate `ArrayList` instance -> `ArrayList reference`; - assign `ArrayList reference` to `y`; -<3> access `y` -> `ArrayList reference`; + store `ArrayList reference` to `y`; +<3> load from `y` -> `ArrayList reference`; implicit cast `ArrayList reference` to `List reference` -> `List reference`; - assign `List reference` to `x`; + store `List reference` to `x`; (note `ArrayList` is a descendant of `List`) -<4> access `x` -> `List reference`; +<4> load from `x` -> `List reference`; explicit cast `List reference` to `ArrayList reference` -> `ArrayList reference`; - assign `ArrayList reference` to `y`; -<5> access `y` -> `ArrayList reference`; + store `ArrayList reference` to `y`; +<5> load from `y` -> `ArrayList reference`; explicit cast `ArrayList reference` to `List reference` -> `List reference`; - assign `List reference` to `x`; + store `List reference` to `x`; (note the explicit cast is extraneous, and an implicit cast is valid) + * Invalid reference type casts resulting in errors. @@ -165,16 +169,16 @@ or the target type is a descendant of the original type. <1> declare `List x`; allocate `ArrayList` instance -> `ArrayList reference`; implicit cast `ArrayList reference` to `List reference` -> `List reference`; - assign `List reference` to `x` + store `List reference` to `x` <2> declare `ArrayList y`; - access `x` -> `List reference`; + load from `x` -> `List reference`; *error* -> cannot implicit cast `List reference` to `ArrayList reference`; (note an explicit cast is valid since `ArrayList` is a descendant of `List`) <3> declare `ArrayList y`; - access `x` -> `List reference`; + load from `x` -> `List reference`; *error* -> cannot explicit cast `List reference` to `Map reference`; - (note no cast would be valid since neither `List` nor `Map` is a descendant - of the other) + (note no cast is valid since neither `List` nor `Map` is a descendant of the + other) [[dynamic-type-casting]] ==== Dynamic Type Casting @@ -206,24 +210,24 @@ based on the current type value the `def` type value represents. + <1> declare `def d0`; implicit cast `int 3` to `def`; - assign `int 3` to `d0` + store `int 3` to `d0` <2> allocate `ArrayList` instance -> `ArrayList reference`; implicit cast `ArrayList reference` to `def` -> `def`; - assign `def` to `d0` + store `def` to `d0` <3> declare `Object o`; allocate `HashMap` instance -> `HashMap reference`; implicit cast `HashMap reference` to `Object reference` -> `Object reference`; - assign `Object reference` to `o` + store `Object reference` to `o` <4> declare `def d1`; - access `o` -> `Object reference`; + load from `o` -> `Object reference`; implicit cast `Object reference` to `def` -> `def`; - assign `def` to `d1` + store `def` to `d1` <5> declare `int i`; - access `d1` -> `def`; + load from `d1` -> `def`; implicit cast `def` to `HashMap reference` -> HashMap reference`; call `size` on `HashMap reference` -> `int 0`; - assign `int 0` to `i`; + store `int 0` to `i`; (note `def` was implicit cast to `HashMap reference` since `HashMap` is the child-most descendant type value that the `def` type value represents) @@ -242,29 +246,29 @@ based on the current type value the `def` type value represents. + <1> declare `def d`; implicit cast `double 1.0` to `def` -> `def`; - assign `def` to `d` + store `def` to `d` <2> declare `int i`; - access `d` -> `def`; + load from `d` -> `def`; implicit cast `def` to `double 1.0` -> `double 1.0`; explicit cast `double 1.0` to `int 1` -> `int 1`; - assign `int 1` to `i`; - (note the explicit cast is necessary since a `double` value cannot be - converted to an `int` value implicitly) -<3> assign `int 1` to `d`; + store `int 1` to `i`; + (note the explicit cast is necessary since a `double` type value is not + converted to an `int` type value implicitly) +<3> store `int 1` to `d`; (note the switch in the type `d` represents from `double` to `int`) <4> declare `float i`; - access `d` -> `def`; + load from `d` -> `def`; implicit cast `def` to `int 1` -> `int 1`; implicit cast `int 1` to `float 1.0` -> `float 1.0`; - assign `float 1.0` to `f` + store `float 1.0` to `f` <5> allocate `ArrayList` instance -> `ArrayList reference`; - assign `ArrayList reference` to `d`; + store `ArrayList reference` to `d`; (note the switch in the type `d` represents from `int` to `ArrayList`) <6> declare `List l`; - access `d` -> `def`; + load from `d` -> `def`; implicit cast `def` to `ArrayList reference` -> `ArrayList reference`; implicit cast `ArrayList reference` to `List reference` -> `List reference`; - assign `List reference` to `l` + store `List reference` to `l` + * Invalid dynamic type casts resulting in errors. + @@ -277,26 +281,26 @@ based on the current type value the `def` type value represents. ---- <1> declare `def d`; implicit cast `int 1` to `def` -> `def`; - assign `def` to `d` + store `def` to `d` <2> declare `short s`; - access `d` -> `def`; + load from `d` -> `def`; implicit cast `def` to `int 1` -> `int 1`; *error* -> cannot implicit cast `int 1` to `short 1`; (note an explicit cast is valid) <3> allocate `HashMap` instance -> `HashMap reference`; implicit cast `HashMap reference` to `def` -> `def`; - assign `def` to `d` + store `def` to `d` <4> declare `List l`; - access `d` -> `def`; + load from `d` -> `def`; implicit cast `def` to `HashMap reference`; *error* -> cannot implicit cast `HashMap reference` to `List reference`; - (note no cast would be valid since neither `HashMap` nor `List` is a - descendant of the other) + (note no cast is valid since neither `HashMap` nor `List` is a descendant of + the other) [[string-character-casting]] ==== String to Character Casting -Use the *cast operator* to convert a <> value into a +Use the cast operator to convert a <> value into a <> value. *Errors* @@ -310,17 +314,17 @@ Use the *cast operator* to convert a <> value into a + [source,Painless] ---- -<1> char c = (char)"C" -<2> c = (char)'c' +<1> char c = (char)"C"; +<2> c = (char)'c'; ---- + <1> declare `char c`; explicit cast `String "C"` to `char C` -> `char C`; - assign `char C` to `c` + store `char C` to `c` <2> explicit cast `String 'c'` to `char c` -> `char c`; - assign `char c` to `c` + store `char c` to `c` + -* Casting a `String` reference into a `char` value. +* Casting a `String` reference into a `char` type value. + [source,Painless] ---- @@ -328,11 +332,11 @@ Use the *cast operator* to convert a <> value into a <2> char c = (char)s; ---- <1> declare `String s`; - assign `String "s"` to `s`; + store `String "s"` to `s`; <2> declare `char c` - access `s` -> `String "s"`; + load from `s` -> `String "s"`; explicit cast `String "s"` to `char s` -> `char s`; - assign `char s` to `c` + store `char s` to `c` [[boxing-unboxing]] ==== Boxing and Unboxing @@ -343,12 +347,12 @@ reference type to its corresponding primitive type. Implicit boxing/unboxing occurs during the following operations: -* Conversions between a `def` type and a primitive type will be implicitly +* Conversions between a `def` type and a primitive type are implicitly boxed/unboxed as necessary, though this is referred to as an implicit cast throughout the documentation. -* Method/function call arguments will be implicitly boxed/unboxed as necessary. -* A primitive type value will be implicitly boxed when a reference type method - call is invoked on it. +* Method/function call arguments are implicitly boxed/unboxed as necessary. +* A primitive type value is implicitly boxed when a reference type method + is called on it. Explicit boxing/unboxing is not allowed. Use the reference type API to explicitly convert a primitive type value to its respective reference type @@ -372,22 +376,22 @@ value and vice versa. + <1> declare `List l`; allocate `ArrayList` instance -> `ArrayList reference`; - assign `ArrayList reference` to `l`; -<2> access `l` -> `List reference`; + store `ArrayList reference` to `l`; +<2> load from `l` -> `List reference`; implicit cast `int 1` to `def` -> `def`; call `add` on `List reference` with arguments (`def`); (note internally `int 1` is boxed to `Integer 1` to store as a `def` type value) <3> declare `Integer I`; call `valueOf` on `Integer` with arguments of (`int 0`) -> `Integer 0`; - assign `Integer 0` to `I`; + store `Integer 0` to `I`; <4> declare `int i`; - access `I` -> `Integer 0`; + load from `I` -> `Integer 0`; unbox `Integer 0` -> `int 0`; - access `l` -> `List reference`; + load from `l` -> `List reference`; call `get` on `List reference` with arguments (`int 0`) -> `def`; implicit cast `def` to `int 1` -> `int 1`; - assign `int 1` to `i`; + store `int 1` to `i`; (note internally `int 1` is unboxed from `Integer 1` when loaded from a `def` type value) + @@ -419,8 +423,8 @@ Promotion is when a single value is implicitly cast to a certain type or multiple values are implicitly cast to the same type as required for evaluation by certain operations. Each operation that requires promotion has a promotion table that shows all required implicit casts based on the type(s) of value(s). A -value can be promoted to a `def` type at compile-time; however, the promoted -type value is derived from what the `def` type value represents at run-time. +value promoted to a `def` type at compile-time is promoted again at run-time +based on the type the `def` value represents. *Errors* @@ -438,19 +442,83 @@ type value is derived from what the `def` type value represents at run-time. <3> float f = x + 2.0F; ---- <1> declare `double d`; - promote `int 2` and `double 2.0 @0` -> `double 2.0 @0`; + promote `int 2` and `double 2.0 @0`: result `double`; implicit cast `int 2` to `double 2.0 @1` -> `double 2.0 @1`; add `double 2.0 @1` and `double 2.0 @0` -> `double 4.0`; - assign `double 4.0` to `d` + store `double 4.0` to `d` <2> declare `def x`; implicit cast `int 1` to `def` -> `def`; - assign `def` to `x`; + store `def` to `x`; <3> declare `float f`; - access `x` -> `def`; + load from `x` -> `def`; implicit cast `def` to `int 1` -> `int 1`; - promote `int 1` and `float 2.0` -> `float 2.0`; + promote `int 1` and `float 2.0`: result `float`; implicit cast `int 1` to `float 1.0` -> `float `1.0`; add `float 1.0` and `float 2.0` -> `float 3.0`; - assign `float 3.0` to `f`; + store `float 3.0` to `f`; (note this example illustrates promotion done at run-time as promotion done at compile-time would have resolved to a `def` type value) + +[[allowed-casts]] +==== Allowed Casts + +The following tables show all allowed casts. Read the tables row by row, where +the original type is shown in the first column, and each subsequent column +indicates whether a cast to the specified target type is implicit (I), explicit +(E), or is not allowed (-). + +*Primitive/Reference Types* + +[cols="<3,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1"] +|==== +| | o | b | s | c | i | j | f | d | O | B | S | C | I | L | F | D | T | R | def +| boolean ( o ) | | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | I +| byte ( b ) | - | | I | I | I | I | I | I | - | - | - | - | - | - | - | - | - | - | I +| short ( s ) | - | E | | E | I | I | I | I | - | - | - | - | - | - | - | - | - | - | I +| char ( c ) | - | E | E | | I | I | I | I | - | - | - | - | - | - | - | - | E | - | I +| int ( i ) | - | E | E | E | | I | I | I | - | - | - | - | - | - | - | - | - | - | I +| long ( j ) | - | E | E | E | E | | I | I | - | - | - | - | - | - | - | - | - | - | I +| float ( f ) | - | E | E | E | E | E | | I | - | - | - | - | - | - | - | - | - | - | I +| double ( d ) | - | E | E | E | E | E | E | | - | - | - | - | - | - | - | - | - | - | I +| Boolean ( O ) | - | - | - | - | - | - | - | - | - | - | - | | - | - | - | - | - | - | I +| Byte ( B ) | - | - | - | - | - | - | - | - | - | | - | - | - | - | - | - | - | - | I +| Short ( S ) | - | - | - | - | - | - | - | - | - | - | | - | - | - | - | - | - | - | I +| Character ( C ) | - | - | - | - | - | - | - | - | - | - | - | | - | - | - | - | - | - | I +| Integer ( I ) | - | - | - | - | - | - | - | - | - | - | - | - | | - | - | - | - | - | I +| Long ( L ) | - | - | - | - | - | - | - | - | - | - | - | - | - | | - | - | - | - | I +| Float ( F ) | - | - | - | - | - | - | - | - | - | - | - | - | - | - | | - | - | - | I +| Double ( D ) | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | | - | - | I +| String ( T ) | - | - | - | E | - | - | - | - | - | - | - | - | - | - | - | - | | - | I +| Reference ( R ) | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | @ | I +|==== + +@ See <> for allowed reference + type casts. + +*`def` Type* + +[cols="<3,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1"] +|==== +| | o | b | s | c | i | j | f | d | O | B | S | C | I | L | F | D | T | R | def +| def as boolean | I | - | - | - | - | - | - | - | I | - | - | - | - | - | - | - | - | - | +| def as byte | - | I | I | I | I | I | I | I | - | I | I | I | I | I | I | I | - | - | +| def as short | - | E | I | E | I | I | I | I | - | E | I | E | I | I | I | I | - | - | +| def as char | - | E | E | I | I | I | I | I | - | E | E | I | I | I | I | I | E | - | +| def as int | - | E | E | E | I | I | I | I | - | E | E | E | I | I | I | I | - | - | +| def as long | - | E | E | E | E | I | I | I | - | E | E | E | E | I | I | I | - | - | +| def as float | - | E | E | E | E | E | I | I | - | E | E | E | E | E | I | I | - | - | +| def as double | - | E | E | E | E | E | E | I | - | E | E | E | E | E | E | I | - | - | +| def as Boolean | I | - | - | - | - | - | - | - | I | - | - | - | | - | - | - | - | - | +| def as Byte | - | I | I | I | I | I | I | I | - | I | I | I | I | I | I | I | - | - | +| def as Short | - | E | I | E | I | I | I | I | - | E | I | E | I | I | I | I | - | - | +| def as Character | - | E | E | I | I | I | I | I | - | E | E | I | I | I | I | I | - | - | +| def as Integer | - | E | E | E | I | I | I | I | - | E | E | E | I | I | I | I | - | - | +| def as Long | - | E | E | E | E | I | I | I | - | E | E | E | E | I | I | I | - | - | +| def as Float | - | E | E | E | E | E | I | I | - | E | E | E | E | E | I | I | - | - | +| def as Double | - | E | E | E | E | E | E | I | - | E | E | E | E | E | E | I | - | - | +| def as String | - | - | - | E | - | - | - | - | - | - | - | - | - | - | - | - | I | - | +| def as Reference | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | @ | +|==== + +@ See <> for allowed reference + type casts. diff --git a/docs/painless/painless-comments.asciidoc b/docs/painless/painless-comments.asciidoc index bde30e37e04..bfd3594431e 100644 --- a/docs/painless/painless-comments.asciidoc +++ b/docs/painless/painless-comments.asciidoc @@ -6,9 +6,10 @@ anywhere on a line to specify a single-line comment. All characters from the `//` token to the end of the line are ignored. Use an opening `/*` token and a closing `*/` token to specify a multi-line comment. Multi-line comments can start anywhere on a line, and all characters in between the `/*` token and `*/` -token are ignored. Comments can be included anywhere within a script. +token are ignored. A comment is included anywhere within a script. *Grammar* + [source,ANTLR4] ---- SINGLE_LINE_COMMENT: '//' .*? [\n\r]; diff --git a/docs/painless/painless-functions.asciidoc b/docs/painless/painless-functions.asciidoc new file mode 100644 index 00000000000..20f3e821f1e --- /dev/null +++ b/docs/painless/painless-functions.asciidoc @@ -0,0 +1,24 @@ +[[painless-functions]] +=== Functions + +A function is a named piece of code comprised of one-to-many statements to +perform a specific task. A function is called multiple times in a single script +to repeat its specific task. A parameter is a named type value available as a +<> within the statement(s) of a function. A +function specifies zero-to-many parameters, and when a function is called a +value is specified per parameter. An argument is a value passed into a function +at the point of call. A function specifies a return type value, though if the +type is <> then no value is returned. Any non-void type return +value is available for use within an <> or is +discarded otherwise. + +You can declare functions at the beginning of a Painless script, for example: + +[source,painless] +--------------------------------------------------------- +boolean isNegative(def x) { x < 0 } +... +if (isNegative(someVar)) { + ... +} +--------------------------------------------------------- \ No newline at end of file diff --git a/docs/painless/painless-general-syntax.asciidoc b/docs/painless/painless-general-syntax.asciidoc deleted file mode 100644 index 114bff80bfa..00000000000 --- a/docs/painless/painless-general-syntax.asciidoc +++ /dev/null @@ -1,81 +0,0 @@ -[[painless-general-syntax]] -=== General Syntax - -[[control-flow]] -==== Control flow - -Painless supports all of Java's https://docs.oracle.com/javase/tutorial/java/nutsandbolts/flow.html[ -control flow statements] except the `switch` statement. - -Painless also supports the `for in` syntax from Groovy: - -[source,painless] ---------------------------------------------------------- -for (item : list) { - ... -} ---------------------------------------------------------- - -[[functions]] -==== Functions - -You can declare functions at the beginning of a Painless script, for example: - -[source,painless] ---------------------------------------------------------- -boolean isNegative(def x) { x < 0 } -... -if (isNegative(someVar)) { - ... -} ---------------------------------------------------------- - -[[lambda-expressions]] -==== Lambda expressions -Lambda expressions and method references work the same as in https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html[Java]. - -[source,painless] ---------------------------------------------------------- -list.removeIf(item -> item == 2); -list.removeIf((int item) -> item == 2); -list.removeIf((int item) -> { item == 2 }); -list.sort((x, y) -> x - y); -list.sort(Integer::compare); ---------------------------------------------------------- - -You can make method references to functions within the script with `this`, -for example `list.sort(this::mycompare)`. - -[[patterns]] -==== Patterns - -Regular expression constants are directly supported. To ensure fast performance, -this is the only mechanism for creating patterns. Regular expressions -are always constants and compiled efficiently a single time. - -[source,painless] ---------------------------------------------------------- -Pattern p = /[aeiou]/ ---------------------------------------------------------- - -[[pattern-flags]] -===== Pattern flags - -You can define flags on patterns in Painless by adding characters after the -trailing `/` like `/foo/i` or `/foo \w #comment/iUx`. Painless exposes all of -the flags from Java's -https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html[ -Pattern class] using these characters: - -[cols="<,<,<",options="header",] -|======================================================================= -| Character | Java Constant | Example -|`c` | CANON_EQ | `'å' ==~ /å/c` (open in hex editor to see) -|`i` | CASE_INSENSITIVE | `'A' ==~ /a/i` -|`l` | LITERAL | `'[a]' ==~ /[a]/l` -|`m` | MULTILINE | `'a\nb\nc' =~ /^b$/m` -|`s` | DOTALL (aka single line) | `'a\nb\nc' =~ /.b./s` -|`U` | UNICODE_CHARACTER_CLASS | `'Ɛ' ==~ /\\w/U` -|`u` | UNICODE_CASE | `'Ɛ' ==~ /ɛ/iu` -|`x` | COMMENTS (aka extended) | `'a' ==~ /a #comment/x` -|======================================================================= diff --git a/docs/painless/painless-identifiers.asciidoc b/docs/painless/painless-identifiers.asciidoc index 7762f56cb7b..d2678b528ea 100644 --- a/docs/painless/painless-identifiers.asciidoc +++ b/docs/painless/painless-identifiers.asciidoc @@ -3,8 +3,12 @@ Use an identifier as a named token to specify a <>, <>, -<>, <>, or function. -<> cannot be used as identifiers. +<>, <>, or +<>. + +*Errors* + +If a <> is used as an identifier. *Grammar* [source,ANTLR4] diff --git a/docs/painless/painless-keywords.asciidoc b/docs/painless/painless-keywords.asciidoc index 39a2201fd2b..9463902c8d3 100644 --- a/docs/painless/painless-keywords.asciidoc +++ b/docs/painless/painless-keywords.asciidoc @@ -1,9 +1,13 @@ [[painless-keywords]] === Keywords -Keywords are reserved tokens for built-in language features and cannot be used -as <> within a script. The following are -keywords: +Keywords are reserved tokens for built-in language features. + +*Errors* + +If a keyword is used as an <>. + +*Keywords* [cols="^1,^1,^1,^1,^1"] |==== diff --git a/docs/painless/painless-lambdas.asciidoc b/docs/painless/painless-lambdas.asciidoc new file mode 100644 index 00000000000..e6694229a0c --- /dev/null +++ b/docs/painless/painless-lambdas.asciidoc @@ -0,0 +1,15 @@ +[[painless-lambdas]] +=== Lambdas +Lambda expressions and method references work the same as in https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html[Java]. + +[source,painless] +--------------------------------------------------------- +list.removeIf(item -> item == 2); +list.removeIf((int item) -> item == 2); +list.removeIf((int item) -> { item == 2 }); +list.sort((x, y) -> x - y); +list.sort(Integer::compare); +--------------------------------------------------------- + +You can make method references to functions within the script with `this`, +for example `list.sort(this::mycompare)`. \ No newline at end of file diff --git a/docs/painless/painless-lang-spec.asciidoc b/docs/painless/painless-lang-spec.asciidoc index 5e6b84d8c57..d50f3db2dc0 100644 --- a/docs/painless/painless-lang-spec.asciidoc +++ b/docs/painless/painless-lang-spec.asciidoc @@ -33,4 +33,22 @@ include::painless-casting.asciidoc[] include::painless-operators.asciidoc[] -include::painless-general-syntax.asciidoc[] +include::painless-operators-general.asciidoc[] + +include::painless-operators-numeric.asciidoc[] + +include::painless-operators-boolean.asciidoc[] + +include::painless-operators-reference.asciidoc[] + +include::painless-operators-array.asciidoc[] + +include::painless-statements.asciidoc[] + +include::painless-scripts.asciidoc[] + +include::painless-functions.asciidoc[] + +include::painless-lambdas.asciidoc[] + +include::painless-regexes.asciidoc[] diff --git a/docs/painless/painless-literals.asciidoc b/docs/painless/painless-literals.asciidoc index ebf7eaa07b6..621fc152be9 100644 --- a/docs/painless/painless-literals.asciidoc +++ b/docs/painless/painless-literals.asciidoc @@ -4,7 +4,7 @@ Use a literal to specify a value directly in an <>. -[[integers]] +[[integer-literals]] ==== Integers Use an integer literal to specify an integer type value in decimal, octal, or @@ -16,6 +16,7 @@ to specify an integer literal as octal, and use `0x` or `0X` as a prefix to specify an integer literal as hex. *Grammar* + [source,ANTLR4] ---- INTEGER: '-'? ( '0' | [1-9] [0-9]* ) [lLfFdD]?; @@ -44,7 +45,7 @@ HEX: '-'? '0' [xX] [0-9a-fA-F]+ [lL]?; <5> `int -18` in octal <6> `int 3882` in hex -[[floats]] +[[float-literals]] ==== Floats Use a floating point literal to specify a floating point type value of a @@ -53,6 +54,7 @@ single letter designations to specify the primitive type: `f` or `F` for `float` and `d` or `D` for `double`. If not specified, the type defaults to `double`. *Grammar* + [source,ANTLR4] ---- DECIMAL: '-'? ( '0' | [1-9] [0-9]* ) (DOT [0-9]+)? EXPONENT? [fFdD]?; @@ -78,7 +80,7 @@ EXPONENT: ( [eE] [+\-]? [0-9]+ ); <4> `double -126.34` <5> `float 89.9` -[[strings]] +[[string-literals]] ==== Strings Use a string literal to specify a <> value with @@ -88,6 +90,7 @@ include a single-quote as part of a single-quoted string literal. Use a `\\` token to include a backslash as part of any string literal. *Grammar* + [source,ANTLR4] ---- STRING: ( '"' ( '\\"' | '\\\\' | ~[\\"] )*? '"' ) @@ -114,9 +117,9 @@ STRING: ( '"' ( '\\"' | '\\\\' | ~[\\"] )*? '"' ) "double-quoted with non-escaped 'single-quotes'" ---- -[[characters]] +[[character-literals]] ==== Characters -A character literal cannot be specified directly. Instead, use the +Character literals are not specified directly. Instead, use the <> to convert a `String` type value into a `char` type value. diff --git a/docs/painless/painless-operators-array.asciidoc b/docs/painless/painless-operators-array.asciidoc new file mode 100644 index 00000000000..e91c07acef5 --- /dev/null +++ b/docs/painless/painless-operators-array.asciidoc @@ -0,0 +1,294 @@ +[[painless-operators-array]] +=== Operators: Array + +[[array-initialization-operator]] +==== Array Initialization + +Use the `array initialization operator '[] {}'` to allocate a single-dimensional +<> instance to the heap with a set of pre-defined +elements. Each value used to initialize an element in the array type instance is +cast to the specified element type value upon insertion. The order of specified +values is maintained. + +*Errors* + +* If a value is not castable to the specified type value. + +*Grammar* + +[source,ANTLR4] +---- +array_initialization: 'new' TYPE '[' ']' '{' expression_list '}' + | 'new' TYPE '[' ']' '{' '}'; +expression_list: expression (',' expression); +---- + +*Example:* + +* Array initialization with static values. ++ +[source,Painless] +---- +<1> int[] x = new int[] {1, 2, 3}; +---- ++ +<1> declare `int[] x`; + allocate `1-d int array` instance with `length [3]` + -> `1-d int array reference`; + store `int 1` to `index [0]` of `1-d int array reference`; + store `int 2` to `index [1]` of `1-d int array reference`; + store `int 3` to `index [2]` of `1-d int array reference`; + store `1-d int array reference` to `x`; ++ +* Array initialization with non-static values. ++ +[source,Painless] +---- +<1> int i = 1; +<2> long l = 2L; +<3> float f = 3.0F; +<4> double d = 4.0; +<5> String s = "5"; +<6> def array = new def[] {i, l, f*d, s}; +---- ++ +<1> declare `int i`; + store `int 1` to `i` +<2> declare `long l`; + store `long 2` to `l` +<3> declare `float f`; + store `float 3.0` to `f` +<4> declare `double d`; + store `double 4.0` to `d` +<5> declare `String s`; + store `String "5"` to `s` +<6> declare `def array`; + allocate `1-d def array` instance with `length [4]` + -> `1-d def array reference`; + load from `i` -> `int 1`; + implicit cast `int 1` to `def` -> `def`; + store `def` to `index [0]` of `1-d def array reference`; + load from `l` -> `long 2`; + implicit cast `long 2` to `def` -> `def`; + store `def` to `index [1]` of `1-d def array reference`; + load from `f` -> `float 3.0`; + load from `d` -> `double 4.0`; + promote `float 3.0` and `double 4.0`: result `double`; + implicit cast `float 3.0` to `double 3.0` -> `double 3.0`; + multiply `double 3.0` and `double 4.0` -> `double 12.0`; + implicit cast `double 12.0` to `def` -> `def`; + store `def` to `index [2]` of `1-d def array reference`; + load from `s` -> `String "5"`; + implicit cast `String "5"` to `def` -> `def`; + store `def` to `index [3]` of `1-d def array reference`; + implicit cast `1-d int array reference` to `def` -> `def`; + store `def` to `array` + +[[array-access-operator]] +==== Array Access + +Use the `array access operator '[]'` to store a value to or load a value from +an <> value. Each element of an array type value is +accessed with an `int` type value to specify the index to store/load. The range +of elements within an array that are accessible is `[0, size)` where size is the +number of elements specified at the time of allocation. Use a negative `int` +type value as an index to access an element in reverse from the end of an array +type value within a range of `[-size, -1]`. + +*Errors* + +* If a value other than an `int` type value or a value that is castable to an + `int` type value is provided as an index. +* If an element is accessed outside of the valid ranges. + +*Grammar* + +[source,ANTLR4] +---- +brace_access: '[' expression ']' +---- + +*Examples* + +* Array access with a single-dimensional array. ++ +[source,Painless] +---- +<1> int[] x = new int[2]; +<2> x[0] = 2; +<3> x[1] = 5; +<4> int y = x[0] + x[1]; +<5> int z = 1; +<6> int i = x[z]; +---- ++ +<1> declare `int[] x`; + allocate `1-d int array` instance with `length [2]` + -> `1-d int array reference`; + store `1-d int array reference` to `x` +<2> load from `x` -> `1-d int array reference`; + store `int 2` to `index [0]` of `1-d int array reference`; +<3> load from `x` -> `1-d int array reference`; + store `int 5` to `index [1]` of `1-d int array reference`; +<4> declare `int y`; + load from `x` -> `1-d int array reference`; + load from `index [0]` of `1-d int array reference` -> `int 2`; + load from `x` -> `1-d int array reference`; + load from `index [1]` of `1-d int array reference` -> `int 5`; + add `int 2` and `int 5` -> `int 7`; + store `int 7` to `y` +<5> declare `int z`; + store `int 1` to `z`; +<6> declare `int i`; + load from `x` -> `1-d int array reference`; + load from `z` -> `int 1`; + load from `index [1]` of `1-d int array reference` -> `int 5`; + store `int 5` to `i`; ++ +* Array access with the `def` type. ++ +[source,Painless] +---- +<1> def d = new int[2]; +<2> d[0] = 2; +<3> d[1] = 5; +<4> def x = d[0] + d[1]; +<5> def y = 1; +<6> def z = d[y]; +---- ++ +<1> declare `def d`; + allocate `1-d int array` instance with `length [2]` + -> `1-d int array reference`; + implicit cast `1-d int array reference` to `def` -> `def`; + store `def` to `d` +<2> load from `d` -> `def` + implicit cast `def` to `1-d int array reference` + -> `1-d int array reference`; + store `int 2` to `index [0]` of `1-d int array reference`; +<3> load from `d` -> `def` + implicit cast `def` to `1-d int array reference` + -> `1-d int array reference`; + store `int 5` to `index [1]` of `1-d int array reference`; +<4> declare `int x`; + load from `d` -> `def` + implicit cast `def` to `1-d int array reference` + -> `1-d int array reference`; + load from `index [0]` of `1-d int array reference` -> `int 2`; + load from `d` -> `def` + implicit cast `def` to `1-d int array reference` + -> `1-d int array reference`; + load from `index [1]` of `1-d int array reference` -> `int 5`; + add `int 2` and `int 5` -> `int 7`; + implicit cast `int 7` to `def` -> `def`; + store `def` to `x` +<5> declare `def y`; + implicit cast `int 1` to `def` -> `def`; + store `def ` to `y`; +<6> declare `int i`; + load from `d` -> `def` + implicit cast `def` to `1-d int array reference` + -> `1-d int array reference`; + load from `y` -> `def`; + implicit cast `def` to `int 1` -> `int 1`; + load from `index [1]` of `1-d int array reference` -> `int 5`; + implicit cast `int 5` to `def`; + store `def` to `z`; ++ +* Array access with a multi-dimensional array. ++ +[source,Painless] +---- +<1> int[][][] ia3 = new int[2][3][4]; +<2> ia3[1][2][3] = 99; +<3> int i = ia3[1][2][3]; +---- ++ +<1> declare `int[][][] ia`; + allocate `3-d int array` instance with length `[2, 3, 4]` + -> `3-d int array reference`; + store `3-d int array reference` to `ia3` +<2> load from `ia3` -> `3-d int array reference`; + store `int 99` to `index [1, 2, 3]` of `3-d int array reference` +<3> declare `int i`; + load from `ia3` -> `3-d int array reference`; + load from `index [1, 2, 3]` of `3-d int array reference` -> `int 99`; + store `int 99` to `i` + +[[array-length-operator]] +==== Array Length + +An array type value contains a read-only member field named `length`. The +`length` field stores the size of the array as an `int` type value where size is +the number of elements specified at the time of allocation. Use the +<> to load the field `length` +from an array type value. + +*Examples* + +* Access the `length` field. ++ +[source,Painless] +---- +<1> int[] x = new int[10]; +<2> int l = x.length; +---- +<1> declare `int[] x`; + allocate `1-d int array` instance with `length [2]` + -> `1-d int array reference`; + store `1-d int array reference` to `x` +<2> declare `int l`; + load `x` -> `1-d int array reference`; + load `length` from `1-d int array reference` -> `int 10`; + store `int 10` to `l`; + +[[new-array-operator]] +==== New Array + +Use the `new array operator 'new []'` to allocate an array type instance to +the heap. Specify the element type following the `new` token. Specify each +dimension with the `[` and `]` tokens following the element type name. The size +of each dimension is specified by an `int` type value in between each set of `[` +and `]` tokens. + +*Errors* + +* If a value other than an `int` type value or a value that is castable to an + `int` type value is specified for for a dimension's size. + +*Grammar* + +[source,ANTLR4] +---- +new_array: 'new' TYPE ('[' expression ']')+; +---- + +*Examples* + +* Allocation of different array types. ++ +[source,Painless] +---- +<1> int[] x = new int[5]; +<2> x = new int[10]; +<3> int y = 2; +<4> def z = new def[y][y*2]; +---- ++ +<1> declare `int[] x`; + allocate `1-d int array` instance with `length [5]` + -> `1-d int array reference`; + store `1-d int array reference` to `x` +<2> allocate `1-d int array` instance with `length [10]` + -> `1-d int array reference`; + store `1-d int array reference` to `x` +<3> declare `int y`; + store `int 2` to `y`; +<4> declare `def z`; + load from `y` -> `int 2 @0`; + load from `y` -> `int 2 @1`; + multiply `int 2 @1` by `int 2 @2` -> `int 4`; + allocate `2-d int array` instance with length `[2, 4]` + -> `2-d int array reference`; + implicit cast `2-d int array reference` to `def` -> `def`; + store `def` to `z`; diff --git a/docs/painless/painless-operators-boolean.asciidoc b/docs/painless/painless-operators-boolean.asciidoc new file mode 100644 index 00000000000..1223a8d56e7 --- /dev/null +++ b/docs/painless/painless-operators-boolean.asciidoc @@ -0,0 +1,1420 @@ +[[painless-operators-boolean]] +=== Operators: Boolean + +[[boolean-not-operator]] +==== Boolean Not + +Use the `boolean not operator '!'` to NOT a `boolean` type value where `true` is +flipped to `false` and `false` is flipped to `true`. + +*Errors* + +* If a value other than a `boolean` type value or a value that is castable to a + `boolean` type value is given. + +*Truth* + +[options="header",cols="<1,<1"] +|==== +| original | result +| true | false +| false | true +|==== + +*Grammar* + +[source,ANTLR4] +---- +boolean_not: '!' expression; +---- + +*Examples* + +* Boolean not with the `boolean` type. ++ +[source,Painless] +---- +<1> boolean x = !false; +<2> boolean y = !x; +---- +<1> declare `boolean x`; + boolean not `boolean false` -> `boolean true`; + store `boolean true` to `x` +<2> declare `boolean y`; + load from `x` -> `boolean true`; + boolean not `boolean true` -> `boolean false`; + store `boolean false` to `y` ++ +* Boolean not with the `def` type. ++ +[source,Painless] +---- +<1> def y = true; +<2> def z = !y; +---- ++ +<1> declare `def y`; + implicit cast `boolean true` to `def` -> `def`; + store `true` to `y` +<2> declare `def z`; + load from `y` -> `def`; + implicit cast `def` to `boolean true` -> boolean `true`; + boolean not `boolean true` -> `boolean false`; + implicit cast `boolean false` to `def` -> `def`; + store `def` to `z` + +[[greater-than-operator]] +==== Greater Than + +Use the `greater than operator '>'` to COMPARE two numeric type values where a +resultant `boolean` type value is `true` if the left-hand side value is greater +than to the right-hand side value and `false` otherwise. + +*Errors* + +* If either the evaluated left-hand side or the evaluated right-hand side is a + non-numeric value. + +*Grammar* + +[source,ANTLR4] +---- +greater_than: expression '>' expression; +---- + +*Promotion* + +[cols="<1,^1,^1,^1,^1,^1,^1,^1,^1"] +|==== +| | byte | short | char | int | long | float | double | 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 +| def | def | def | def | def | def | def | def | def +|==== + +*Examples* + +* Greater than with different numeric types. ++ +[source,Painless] +---- +<1> boolean x = 5 > 4; +<2> double y = 6.0; +<3> x = 6 > y; +---- ++ +<1> declare `boolean x`; + greater than `int 5` and `int 4` -> `boolean true`; + store `boolean true` to `x`; +<2> declare `double y`; + store `double 6.0` to `y`; +<3> load from `y` -> `double 6.0 @0`; + promote `int 6` and `double 6.0`: result `double`; + implicit cast `int 6` to `double 6.0 @1` -> `double 6.0 @1`; + greater than `double 6.0 @1` and `double 6.0 @0` -> `boolean false`; + store `boolean false` to `x` ++ +* Greater than with `def` type. ++ +[source,Painless] +---- +<1> int x = 5; +<2> def y = 7.0; +<3> def z = y > 6.5; +<4> def a = x > y; +---- ++ +<1> declare `int x`; + store `int 5` to `x` +<2> declare `def y`; + implicit cast `double 7.0` to `def` -> `def`; + store `def` to `y` +<3> declare `def z`; + load from `y` -> `def`; + implicit cast `def` to `double 7.0` -> `double 7.0`; + greater than `double 7.0` and `double 6.5` -> `boolean true`; + implicit cast `boolean true` to `def` -> `def`; + store `def` to `z` +<4> declare `def a`; + load from `y` -> `def`; + implicit cast `def` to `double 7.0` -> `double 7.0`; + load from `x` -> `int 5`; + promote `int 5` and `double 7.0`: result `double`; + implicit cast `int 5` to `double 5.0` -> `double 5.0`; + greater than `double 5.0` and `double 7.0` -> `boolean false`; + implicit cast `boolean false` to `def` -> `def`; + store `def` to `z` + +[[greater-than-or-equal-operator]] +==== Greater Than Or Equal + +Use the `greater than or equal operator '>='` to COMPARE two numeric type values +where a resultant `boolean` type value is `true` if the left-hand side value is +greater than or equal to the right-hand side value and `false` otherwise. + +*Errors* + +* If either the evaluated left-hand side or the evaluated right-hand side is a + non-numeric value. + +*Grammar* + +[source,ANTLR4] +---- +greater_than_or_equal: expression '>=' expression; +---- + +*Promotion* + +[cols="<1,^1,^1,^1,^1,^1,^1,^1,^1"] +|==== +| | byte | short | char | int | long | float | double | 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 +| def | def | def | def | def | def | def | def | def +|==== + +*Examples* + +* Greater than or equal with different numeric types. ++ +[source,Painless] +---- +<1> boolean x = 5 >= 4; +<2> double y = 6.0; +<3> x = 6 >= y; +---- ++ +<1> declare `boolean x`; + greater than or equal `int 5` and `int 4` -> `boolean true`; + store `boolean true` to `x` +<2> declare `double y`; + store `double 6.0` to `y` +<3> load from `y` -> `double 6.0 @0`; + promote `int 6` and `double 6.0`: result `double`; + implicit cast `int 6` to `double 6.0 @1` -> `double 6.0 @1`; + greater than or equal `double 6.0 @1` and `double 6.0 @0` -> `boolean true`; + store `boolean true` to `x` ++ +* Greater than or equal with the `def` type. ++ +[source,Painless] +---- +<1> int x = 5; +<2> def y = 7.0; +<3> def z = y >= 7.0; +<4> def a = x >= y; +---- ++ +<1> declare `int x`; + store `int 5` to `x`; +<2> declare `def y` + implicit cast `double 7.0` to `def` -> `def`; + store `def` to `y` +<3> declare `def z`; + load from `y` -> `def`; + implicit cast `def` to `double 7.0 @0` -> `double 7.0 @0`; + greater than or equal `double 7.0 @0` and `double 7.0 @1` -> `boolean true`; + implicit cast `boolean true` to `def` -> `def`; + store `def` to `z` +<4> declare `def a`; + load from `y` -> `def`; + implicit cast `def` to `double 7.0` -> `double 7.0`; + load from `x` -> `int 5`; + promote `int 5` and `double 7.0`: result `double`; + implicit cast `int 5` to `double 5.0` -> `double 5.0`; + greater than or equal `double 5.0` and `double 7.0` -> `boolean false`; + implicit cast `boolean false` to `def` -> `def`; + store `def` to `z` + +[[less-than-operator]] +==== Less Than + +Use the `less than operator '<'` to COMPARE two numeric type values where a +resultant `boolean` type value is `true` if the left-hand side value is less +than to the right-hand side value and `false` otherwise. + +*Errors* + +* If either the evaluated left-hand side or the evaluated right-hand side is a + non-numeric value. + +*Grammar* + +[source,ANTLR4] +---- +less_than: expression '<' expression; +---- + +*Promotion* + +[cols="<1,^1,^1,^1,^1,^1,^1,^1,^1"] +|==== +| | byte | short | char | int | long | float | double | 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 +| def | def | def | def | def | def | def | def | def +|==== + +*Examples* + +* Less than with different numeric types. ++ +[source,Painless] +---- +<1> boolean x = 5 < 4; +<2> double y = 6.0; +<3> x = 6 < y; +---- ++ +<1> declare `boolean x`; + less than `int 5` and `int 4` -> `boolean false`; + store `boolean false` to `x` +<2> declare `double y`; + store `double 6.0` to `y` +<3> load from `y` -> `double 6.0 @0`; + promote `int 6` and `double 6.0`: result `double`; + implicit cast `int 6` to `double 6.0 @1` -> `double 6.0 @1`; + less than `double 6.0 @1` and `double 6.0 @0` -> `boolean false`; + store `boolean false` to `x` ++ +* Less than with the `def` type. ++ +[source,Painless] +---- +<1> int x = 5; +<2> def y = 7.0; +<3> def z = y < 6.5; +<4> def a = x < y; +---- ++ +<1> declare `int x`; + store `int 5` to `x` +<2> declare `def y`; + implicit cast `double 7.0` to `def` -> `def`; + store `def` to `y` +<3> declare `def z`; + load from `y` -> `def`; + implicit cast `def` to `double 7.0` -> `double 7.0`; + less than `double 7.0` and `double 6.5` -> `boolean false`; + implicit cast `boolean false` to `def` -> `def`; + store `def` to `z` +<4> declare `def a`; + load from `y` -> `def`; + implicit cast `def` to `double 7.0` -> `double 7.0`; + load from `x` -> `int 5`; + promote `int 5` and `double 7.0`: result `double`; + implicit cast `int 5` to `double 5.0` -> `double 5.0`; + less than `double 5.0` and `double 7.0` -> `boolean true`; + implicit cast `boolean true` to `def` -> `def`; + store `def` to `z` + +[[less-than-or-equal-operator]] +==== Less Than Or Equal + +Use the `less than or equal operator '<='` to COMPARE two numeric type values +where a resultant `boolean` type value is `true` if the left-hand side value is +less than or equal to the right-hand side value and `false` otherwise. + +*Errors* + +* If either the evaluated left-hand side or the evaluated right-hand side is a + non-numeric value. + +*Grammar* + +[source,ANTLR4] +---- +greater_than_or_equal: expression '<=' expression; +---- + +*Promotion* + +[cols="<1,^1,^1,^1,^1,^1,^1,^1,^1"] +|==== +| | byte | short | char | int | long | float | double | 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 +| def | def | def | def | def | def | def | def | def +|==== + +*Examples* + +* Less than or equal with different numeric types. ++ +[source,Painless] +---- +<1> boolean x = 5 <= 4; +<2> double y = 6.0; +<3> x = 6 <= y; +---- ++ +<1> declare `boolean x`; + less than or equal `int 5` and `int 4` -> `boolean false`; + store `boolean true` to `x` +<2> declare `double y`; + store `double 6.0` to `y` +<3> load from `y` -> `double 6.0 @0`; + promote `int 6` and `double 6.0`: result `double`; + implicit cast `int 6` to `double 6.0 @1` -> `double 6.0 @1`; + less than or equal `double 6.0 @1` and `double 6.0 @0` -> `boolean true`; + store `boolean true` to `x` ++ +* Less than or equal with the `def` type. ++ +[source,Painless] +---- +<1> int x = 5; +<2> def y = 7.0; +<3> def z = y <= 7.0; +<4> def a = x <= y; +---- ++ +<1> declare `int x`; + store `int 5` to `x`; +<2> declare `def y`; + implicit cast `double 7.0` to `def` -> `def`; + store `def` to `y`; +<3> declare `def z`; + load from `y` -> `def`; + implicit cast `def` to `double 7.0 @0` -> `double 7.0 @0`; + less than or equal `double 7.0 @0` and `double 7.0 @1` -> `boolean true`; + implicit cast `boolean true` to `def` -> `def`; + store `def` to `z` +<4> declare `def a`; + load from `y` -> `def`; + implicit cast `def` to `double 7.0` -> `double 7.0`; + load from `x` -> `int 5`; + promote `int 5` and `double 7.0`: result `double`; + implicit cast `int 5` to `double 5.0` -> `double 5.0`; + less than or equal `double 5.0` and `double 7.0` -> `boolean true`; + implicit cast `boolean true` to `def` -> `def`; + store `def` to `z` + +[[instanceof-operator]] +==== Instanceof + +Use the `instanceof operator` to COMPARE the variable/field type to a +specified reference type using the reference type name where a resultant +`boolean` type value is `true` if the variable/field type is the same as or a +descendant of the specified reference type and false otherwise. + +*Errors* + +* If the reference type name doesn't exist as specified by the right-hand side. + +*Grammar* + +[source,ANTLR4] +---- +instance_of: ID 'instanceof' TYPE; +---- + +*Examples* + +* Instance of with different reference types. ++ +[source,Painless] +---- +<1> Map m = new HashMap(); +<2> boolean a = m instanceof HashMap; +<3> boolean b = m instanceof Map; +---- ++ +<1> declare `Map m`; + allocate `HashMap` instance -> `HashMap reference`; + implicit cast `HashMap reference` to `Map reference`; + store `Map reference` to `m` +<2> declare `boolean a`; + load from `m` -> `Map reference`; + implicit cast `Map reference` to `HashMap reference` -> `HashMap reference`; + instanceof `HashMap reference` and `HashMap` -> `boolean true`; + store `boolean true` to `a` +<3> declare `boolean b`; + load from `m` -> `Map reference`; + implicit cast `Map reference` to `HashMap reference` -> `HashMap reference`; + instanceof `HashMap reference` and `Map` -> `boolean true`; + store `true` to `b`; + (note `HashMap` is a descendant of `Map`) ++ +* Instance of with the `def` type. ++ +[source,Painless] +---- +<1> def d = new ArrayList(); +<2> boolean a = d instanceof List; +<3> boolean b = d instanceof Map; +---- ++ +<1> declare `def d`; + allocate `ArrayList` instance -> `ArrayList reference`; + implicit cast `ArrayList reference` to `def` -> `def`; + store `def` to `d` +<2> declare `boolean a`; + load from `d` -> `def`; + implicit cast `def` to `ArrayList reference` -> `ArrayList reference`; + instanceof `ArrayList reference` and `List` -> `boolean true`; + store `boolean true` to `a`; + (note `ArrayList` is a descendant of `List`) +<3> declare `boolean b`; + load from `d` -> `def`; + implicit cast `def` to `ArrayList reference` -> `ArrayList reference`; + instanceof `ArrayList reference` and `Map` -> `boolean false`; + store `boolean false` to `a`; + (note `ArrayList` is not a descendant of `Map`) + +[[equality-equals-operator]] +==== Equality Equals + +Use the `equality equals operator '=='` to COMPARE two values where a resultant +`boolean` type value is `true` if the two values are equal and `false` +otherwise. The member method, `equals`, is implicitly called when the values are +reference type values where the first value is the target of the call and the +second value is the argument. This operation is null-safe where if both values +are `null` the resultant `boolean` type value is `true`, and if only one value +is `null` the resultant `boolean` type value is `false`. A valid comparison is +between `boolean` type values, numeric type values, or reference type values. + +*Errors* + +* If a comparison is made between a `boolean` type value and numeric type value. +* If a comparison is made between a primitive type value and a reference type + value. + +*Grammar* + +[source,ANTLR4] +---- +equality_equals: expression '==' expression; +---- + +*Promotion* + +[cols="<1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1"] +|==== +| | boolean | byte | short | char | int | long | float | double | Reference | def +| boolean | boolean | - | - | - | - | - | - | - | - | 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 | def +|==== + +*Examples* + +* Equality equals with the `boolean` type. ++ +[source,Painless] +---- +<1> boolean a = true; +<2> boolean b = false; +<3> a = a == false; +<4> b = a == b; +---- ++ +<1> declare `boolean a`; + store `boolean true` to `a` +<2> declare `boolean b`; + store `boolean false` to `b` +<3> load from `a` -> `boolean true`; + equality equals `boolean true` and `boolean false` -> `boolean false`; + store `boolean false` to `a` +<4> load from `a` -> `boolean false @0`; + load from `b` -> `boolean false @1`; + equality equals `boolean false @0` and `boolean false @1` + -> `boolean false`; + store `boolean false` to `b` ++ +* Equality equals with primitive types. ++ +[source,Painless] +---- +<1> int a = 1; +<2> double b = 2.0; +<3> boolean c = a == b; +<4> c = 1 == a; +---- ++ +<1> declare `int a`; + store `int 1` to `a` +<2> declare `double b`; + store `double 1.0` to `b` +<3> declare `boolean c`; + load from `a` -> `int 1`; + load from `b` -> `double 2.0`; + promote `int 1` and `double 2.0`: result `double`; + implicit cast `int 1` to `double 1.0` -> `double `1.0`; + equality equals `double 1.0` and `double 2.0` -> `boolean false`; + store `boolean false` to `c` +<4> load from `a` -> `int 1 @1`; + equality equals `int 1 @0` and `int 1 @1` -> `boolean true`; + store `boolean true` to `c` ++ +* Equal equals with reference types. ++ +[source,Painless] +---- +<1> List a = new ArrayList(); +<2> List b = new ArrayList(); +<3> a.add(1); +<4> boolean c = a == b; +<5> b.add(1); +<6> c = a == b; +---- ++ +<1> declare `List a`; + allocate `ArrayList` instance -> `ArrayList reference`; + implicit cast `ArrayList reference` to `List reference` -> `List reference`; + store `List reference` to `a` +<2> declare `List b`; + allocate `ArrayList` instance -> `ArrayList reference`; + implicit cast `ArrayList reference` to `List reference` -> `List reference`; + store `List reference` to `b` +<3> load from `a` -> `List reference`; + call `add` on `List reference` with arguments (`int 1)` +<4> declare `boolean c`; + load from `a` -> `List reference @0`; + load from `b` -> `List reference @1`; + call `equals` on `List reference @0` with arguments (`List reference @1`) + -> `boolean false`; + store `boolean false` to `c` +<5> load from `b` -> `List reference`; + call `add` on `List reference` with arguments (`int 1`) +<6> load from `a` -> `List reference @0`; + load from `b` -> `List reference @1`; + call `equals` on `List reference @0` with arguments (`List reference @1`) + -> `boolean true`; + store `boolean true` to `c` ++ +* Equality equals with `null`. ++ +[source,Painless] +---- +<1> Object a = null; +<2> Object b = null; +<3> boolean c = a == null; +<4> c = a == b; +<5> b = new Object(); +<6> c = a == b; +---- ++ +<1> declare `Object a`; + store `null` to `a` +<2> declare `Object b`; + store `null` to `b` +<3> declare `boolean c`; + load from `a` -> `null @0`; + equality equals `null @0` and `null @1` -> `boolean true`; + store `boolean true` to `c` +<4> load from `a` -> `null @0`; + load from `b` -> `null @1`; + equality equals `null @0` and `null @1` -> `boolean true`; + store `boolean true` to `c` +<5> allocate `Object` instance -> `Object reference`; + store `Object reference` to `b` +<6> load from `a` -> `Object reference`; + load from `b` -> `null`; + call `equals` on `Object reference` with arguments (`null`) + -> `boolean false`; + store `boolean false` to `c` ++ +* Equality equals with the `def` type. ++ +[source, Painless] +---- +<1> def a = 0; +<2> def b = 1; +<3> boolean c = a == b; +<4> def d = new HashMap(); +<5> def e = new ArrayList(); +<6> c = d == e; +---- ++ +<1> declare `def a`; + implicit cast `int 0` to `def` -> `def`; + store `def` to `a`; +<2> declare `def b`; + implicit cast `int 1` to `def` -> `def`; + store `def` to `b`; +<3> declare `boolean c`; + load from `a` -> `def`; + implicit cast `a` to `int 0` -> `int 0`; + load from `b` -> `def`; + implicit cast `b` to `int 1` -> `int 1`; + equality equals `int 0` and `int 1` -> `boolean false`; + store `boolean false` to `c` +<4> declare `def d`; + allocate `HashMap` instance -> `HashMap reference`; + implicit cast `HashMap reference` to `def` -> `def` + store `def` to `d`; +<5> declare `def e`; + allocate `ArrayList` instance -> `ArrayList reference`; + implicit cast `ArrayList reference` to `def` -> `def` + store `def` to `d`; +<6> load from `d` -> `def`; + implicit cast `def` to `HashMap reference` -> `HashMap reference`; + load from `e` -> `def`; + implicit cast `def` to `ArrayList reference` -> `ArrayList reference`; + call `equals` on `HashMap reference` with arguments (`ArrayList reference`) + -> `boolean false`; + store `boolean false` to `c` + +[[equality-not-equals-operator]] +==== Equality Not Equals + +Use the `equality not equals operator '!='` to COMPARE two values where a +resultant `boolean` type value is `true` if the two values are NOT equal and +`false` otherwise. The member method, `equals`, is implicitly called when the +values are reference type values where the first value is the target of the call +and the second value is the argument with the resultant `boolean` type value +flipped. This operation is `null-safe` where if both values are `null` the +resultant `boolean` type value is `false`, and if only one value is `null` the +resultant `boolean` type value is `true`. A valid comparison is between boolean +type values, numeric type values, or reference type values. + +*Errors* + +* If a comparison is made between a `boolean` type value and numeric type value. +* If a comparison is made between a primitive type value and a reference type + value. + +*Grammar* + +[source,ANTLR4] +---- +equality_not_equals: expression '!=' expression; +---- + +*Promotion* + +[cols="<1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1"] +|==== +| | boolean | byte | short | char | int | long | float | double | Reference | def +| boolean | boolean | - | - | - | - | - | - | - | - | 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 | def +|==== + +*Examples* + +* Equality not equals with the `boolean` type. ++ +[source,Painless] +---- +<1> boolean a = true; +<2> boolean b = false; +<3> a = a != false; +<4> b = a != b; +---- ++ +<1> declare `boolean a`; + store `boolean true` to `a` +<2> declare `boolean b`; + store `boolean false` to `b` +<3> load from `a` -> `boolean true`; + equality not equals `boolean true` and `boolean false` -> `boolean true`; + store `boolean true` to `a` +<4> load from `a` -> `boolean true`; + load from `b` -> `boolean false`; + equality not equals `boolean true` and `boolean false` -> `boolean true`; + store `boolean true` to `b` ++ +* Equality not equals with primitive types. ++ +[source,Painless] +---- +<1> int a = 1; +<2> double b = 2.0; +<3> boolean c = a != b; +<4> c = 1 != a; +---- ++ +<1> declare `int a`; + store `int 1` to `a` +<2> declare `double b`; + store `double 1.0` to `b` +<3> declare `boolean c`; + load from `a` -> `int 1`; + load from `b` -> `double 2.0`; + promote `int 1` and `double 2.0`: result `double`; + implicit cast `int 1` to `double 1.0` -> `double `1.0`; + equality not equals `double 1.0` and `double 2.0` -> `boolean true`; + store `boolean true` to `c` +<4> load from `a` -> `int 1 @1`; + equality not equals `int 1 @0` and `int 1 @1` -> `boolean false`; + store `boolean false` to `c` ++ +* Equality not equals with reference types. ++ +[source,Painless] +---- +<1> List a = new ArrayList(); +<2> List b = new ArrayList(); +<3> a.add(1); +<4> boolean c = a == b; +<5> b.add(1); +<6> c = a == b; +---- ++ +<1> declare `List a`; + allocate `ArrayList` instance -> `ArrayList reference`; + implicit cast `ArrayList reference` to `List reference` -> `List reference`; + store `List reference` to `a` +<2> declare `List b`; + allocate `ArrayList` instance -> `ArrayList reference`; + implicit cast `ArrayList reference` to `List reference` -> `List reference`; + store `List reference` to `b` +<3> load from `a` -> `List reference`; + call `add` on `List reference` with arguments (`int 1)` +<4> declare `boolean c`; + load from `a` -> `List reference @0`; + load from `b` -> `List reference @1`; + call `equals` on `List reference @0` with arguments (`List reference @1`) + -> `boolean false`; + boolean not `boolean false` -> `boolean true` + store `boolean true` to `c` +<5> load from `b` -> `List reference`; + call `add` on `List reference` with arguments (`int 1`) +<6> load from `a` -> `List reference @0`; + load from `b` -> `List reference @1`; + call `equals` on `List reference @0` with arguments (`List reference @1`) + -> `boolean true`; + boolean not `boolean true` -> `boolean false`; + store `boolean false` to `c` ++ +* Equality not equals with `null`. ++ +[source,Painless] +---- +<1> Object a = null; +<2> Object b = null; +<3> boolean c = a == null; +<4> c = a == b; +<5> b = new Object(); +<6> c = a == b; +---- ++ +<1> declare `Object a`; + store `null` to `a` +<2> declare `Object b`; + store `null` to `b` +<3> declare `boolean c`; + load from `a` -> `null @0`; + equality not equals `null @0` and `null @1` -> `boolean false`; + store `boolean false` to `c` +<4> load from `a` -> `null @0`; + load from `b` -> `null @1`; + equality not equals `null @0` and `null @1` -> `boolean false`; + store `boolean false` to `c` +<5> allocate `Object` instance -> `Object reference`; + store `Object reference` to `b` +<6> load from `a` -> `Object reference`; + load from `b` -> `null`; + call `equals` on `Object reference` with arguments (`null`) + -> `boolean false`; + boolean not `boolean false` -> `boolean true`; + store `boolean true` to `c` ++ +* Equality not equals with the `def` type. ++ +[source, Painless] +---- +<1> def a = 0; +<2> def b = 1; +<3> boolean c = a == b; +<4> def d = new HashMap(); +<5> def e = new ArrayList(); +<6> c = d == e; +---- ++ +<1> declare `def a`; + implicit cast `int 0` to `def` -> `def`; + store `def` to `a`; +<2> declare `def b`; + implicit cast `int 1` to `def` -> `def`; + store `def` to `b`; +<3> declare `boolean c`; + load from `a` -> `def`; + implicit cast `a` to `int 0` -> `int 0`; + load from `b` -> `def`; + implicit cast `b` to `int 1` -> `int 1`; + equality equals `int 0` and `int 1` -> `boolean false`; + store `boolean false` to `c` +<4> declare `def d`; + allocate `HashMap` instance -> `HashMap reference`; + implicit cast `HashMap reference` to `def` -> `def` + store `def` to `d`; +<5> declare `def e`; + allocate `ArrayList` instance -> `ArrayList reference`; + implicit cast `ArrayList reference` to `def` -> `def` + store `def` to `d`; +<6> load from `d` -> `def`; + implicit cast `def` to `HashMap reference` -> `HashMap reference`; + load from `e` -> `def`; + implicit cast `def` to `ArrayList reference` -> `ArrayList reference`; + call `equals` on `HashMap reference` with arguments (`ArrayList reference`) + -> `boolean false`; + store `boolean false` to `c` + +[[identity-equals-operator]] +==== Identity Equals + +Use the `identity equals operator '==='` to COMPARE two values where a resultant +`boolean` type value is `true` if the two values are equal and `false` +otherwise. A reference type value is equal to another reference type value if +both values refer to same instance on the heap or if both values are `null`. A +valid comparison is between `boolean` type values, numeric type values, or +reference type values. + +*Errors* + +* If a comparison is made between a `boolean` type value and numeric type value. +* If a comparison is made between a primitive type value and a reference type + value. + +*Grammar* + +[source,ANTLR4] +---- +identity_equals: expression '===' expression; +---- + +*Promotion* + +[cols="<1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1"] +|==== +| | boolean | byte | short | char | int | long | float | double | Reference | def +| boolean | boolean | - | - | - | - | - | - | - | - | 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 | def +|==== + +*Examples* + +* Identity equals with reference types. ++ +[source,Painless] +---- +<1> List a = new ArrayList(); +<2> List b = new ArrayList(); +<3> List c = a; +<4> boolean c = a === b; +<5> c = a === c; +---- ++ +<1> declare `List a`; + allocate `ArrayList` instance -> `ArrayList reference`; + implicit cast `ArrayList reference` to `List reference` -> `List reference`; + store `List reference` to `a` +<2> declare `List b`; + allocate `ArrayList` instance -> `ArrayList reference`; + implicit cast `ArrayList reference` to `List reference` -> `List reference`; + store `List reference` to `b` +<3> load from `a` -> `List reference`; + store `List reference` to `c` +<4> declare `boolean c`; + load from `a` -> `List reference @0`; + load from `b` -> `List reference @1`; + identity equals `List reference @0` and `List reference @1` + -> `boolean false` + store `boolean false` to `c` +<5> load from `a` -> `List reference @0`; + load from `c` -> `List reference @1`; + identity equals `List reference @0` and `List reference @1` + -> `boolean true` + store `boolean true` to `c` + (note `List reference @0` and `List reference @1` refer to the same + instance) ++ +* Identity equals with `null`. ++ +[source,Painless] +---- +<1> Object a = null; +<2> Object b = null; +<3> boolean c = a === null; +<4> c = a === b; +<5> b = new Object(); +<6> c = a === b; +---- ++ +<1> declare `Object a`; + store `null` to `a` +<2> declare `Object b`; + store `null` to `b` +<3> declare `boolean c`; + load from `a` -> `null @0`; + identity equals `null @0` and `null @1` -> `boolean true`; + store `boolean true` to `c` +<4> load from `a` -> `null @0`; + load from `b` -> `null @1`; + identity equals `null @0` and `null @1` -> `boolean true`; + store `boolean true` to `c` +<5> allocate `Object` instance -> `Object reference`; + store `Object reference` to `b` +<6> load from `a` -> `Object reference`; + load from `b` -> `null`; + identity equals `Object reference` and `null` -> `boolean false`; + store `boolean false` to `c` ++ +* Identity equals with the `def` type. ++ +[source, Painless] +---- +<1> def a = new HashMap(); +<2> def b = new ArrayList(); +<3> boolean c = a === b; +<4> b = a; +<5> c = a === b; +---- ++ +<1> declare `def d`; + allocate `HashMap` instance -> `HashMap reference`; + implicit cast `HashMap reference` to `def` -> `def` + store `def` to `d` +<2> declare `def e`; + allocate `ArrayList` instance -> `ArrayList reference`; + implicit cast `ArrayList reference` to `def` -> `def` + store `def` to `d` +<3> declare `boolean c`; + load from `a` -> `def`; + implicit cast `def` to `HashMap reference` -> `HashMap reference`; + load from `b` -> `def`; + implicit cast `def` to `ArrayList reference` -> `ArrayList reference`; + identity equals `HashMap reference` and `ArrayList reference` + -> `boolean false`; + store `boolean false` to `c` +<4> load from `a` -> `def`; + store `def` to `b` +<5> load from `a` -> `def`; + implicit cast `def` to `HashMap reference @0` -> `HashMap reference @0`; + load from `b` -> `def`; + implicit cast `def` to `HashMap reference @1` -> `HashMap reference @1`; + identity equals `HashMap reference @0` and `HashMap reference @1` + -> `boolean true`; + store `boolean true` to `b`; + (note `HashMap reference @0` and `HashMap reference @1` refer to the same + instance) + +[[identity-not-equals-operator]] +==== Identity Not Equals + +Use the `identity not equals operator '!=='` to COMPARE two values where a +resultant `boolean` type value is `true` if the two values are NOT equal and +`false` otherwise. A reference type value is not equal to another reference type +value if both values refer to different instances on the heap or if one value is +`null` and the other is not. A valid comparison is between `boolean` type +values, numeric type values, or reference type values. + +*Errors* + +* If a comparison is made between a `boolean` type value and numeric type value. +* If a comparison is made between a primitive type value and a reference type + value. + +*Grammar* + +[source,ANTLR4] +---- +identity_not_equals: expression '!==' expression; +---- + +*Promotion* + +[cols="<1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1"] +|==== +| | boolean | byte | short | char | int | long | float | double | Reference | def +| boolean | boolean | - | - | - | - | - | - | - | - | 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 | def +|==== + +*Examples* + +* Identity not equals with reference type values. ++ +[source,Painless] +---- +<1> List a = new ArrayList(); +<2> List b = new ArrayList(); +<3> List c = a; +<4> boolean c = a !== b; +<5> c = a !== c; +---- ++ +<1> declare `List a`; + allocate `ArrayList` instance -> `ArrayList reference`; + implicit cast `ArrayList reference` to `List reference` -> `List reference`; + store `List reference` to `a` +<2> declare `List b`; + allocate `ArrayList` instance -> `ArrayList reference`; + implicit cast `ArrayList reference` to `List reference` -> `List reference`; + store `List reference` to `b` +<3> load from `a` -> `List reference`; + store `List reference` to `c` +<4> declare `boolean c`; + load from `a` -> `List reference @0`; + load from `b` -> `List reference @1`; + identity not equals `List reference @0` and `List reference @1` + -> `boolean true` + store `boolean true` to `c` +<5> load from `a` -> `List reference @0`; + load from `c` -> `List reference @1`; + identity not equals `List reference @0` and `List reference @1` + -> `boolean false` + store `boolean false` to `c` + (note `List reference @0` and `List reference @1` refer to the same + instance) ++ +* Identity not equals with `null`. ++ +[source,Painless] +---- +<1> Object a = null; +<2> Object b = null; +<3> boolean c = a !== null; +<4> c = a !== b; +<5> b = new Object(); +<6> c = a !== b; +---- ++ +<1> declare `Object a`; + store `null` to `a` +<2> declare `Object b`; + store `null` to `b` +<3> declare `boolean c`; + load from `a` -> `null @0`; + identity not equals `null @0` and `null @1` -> `boolean false`; + store `boolean false` to `c` +<4> load from `a` -> `null @0`; + load from `b` -> `null @1`; + identity not equals `null @0` and `null @1` -> `boolean false`; + store `boolean false` to `c` +<5> allocate `Object` instance -> `Object reference`; + store `Object reference` to `b` +<6> load from `a` -> `Object reference`; + load from `b` -> `null`; + identity not equals `Object reference` and `null` -> `boolean true`; + store `boolean true` to `c` ++ +* Identity not equals with the `def` type. ++ +[source, Painless] +---- +<1> def a = new HashMap(); +<2> def b = new ArrayList(); +<3> boolean c = a !== b; +<4> b = a; +<5> c = a !== b; +---- ++ +<1> declare `def d`; + allocate `HashMap` instance -> `HashMap reference`; + implicit cast `HashMap reference` to `def` -> `def` + store `def` to `d` +<2> declare `def e`; + allocate `ArrayList` instance -> `ArrayList reference`; + implicit cast `ArrayList reference` to `def` -> `def` + store `def` to `d` +<3> declare `boolean c`; + load from `a` -> `def`; + implicit cast `def` to `HashMap reference` -> `HashMap reference`; + load from `b` -> `def`; + implicit cast `def` to `ArrayList reference` -> `ArrayList reference`; + identity not equals `HashMap reference` and `ArrayList reference` + -> `boolean true`; + store `boolean true` to `c` +<4> load from `a` -> `def`; + store `def` to `b` +<5> load from `a` -> `def`; + implicit cast `def` to `HashMap reference @0` -> `HashMap reference @0`; + load from `b` -> `def`; + implicit cast `def` to `HashMap reference @1` -> `HashMap reference @1`; + identity not equals `HashMap reference @0` and `HashMap reference @1` + -> `boolean false`; + store `boolean false` to `b`; + (note `HashMap reference @0` and `HashMap reference @1` refer to the same + instance) + +[[boolean-xor-operator]] +==== Boolean Xor + +Use the `boolean xor operator '^'` to XOR together two `boolean` type values +where if one `boolean` type value is `true` and the other is `false` the +resultant `boolean` type value is `true` and `false` otherwise. + +*Errors* + +* If either evaluated value is a value other than a `boolean` type value or + a value that is castable to a `boolean` type value. + +*Truth* + +[cols="^1,^1,^1"] +|==== +| | true | false +| true | false | true +| false | true | false +|==== + +*Grammar* + +[source,ANTLR4] +---- +boolean_xor: expression '^' expression; +---- + +*Examples* + +* Boolean xor with the `boolean` type. ++ +[source,Painless] +---- +<1> boolean x = false; +<2> boolean y = x ^ true; +<3> y = y ^ x; +---- ++ +<1> declare `boolean x`; + store `boolean false` to `x` +<2> declare `boolean y`; + load from `x` -> `boolean false` + boolean xor `boolean false` and `boolean true` -> `boolean true`; + store `boolean true` to `y` +<3> load from `y` -> `boolean true @0`; + load from `x` -> `boolean true @1`; + boolean xor `boolean true @0` and `boolean true @1` -> `boolean false`; + store `boolean false` to `y` ++ +* Boolean xor with the `def` type. ++ +[source,Painless] +---- +<1> def x = false; +<2> def y = x ^ true; +<3> y = y ^ x; +---- ++ +<1> declare `def x`; + implicit cast `boolean false` to `def` -> `def`; + store `def` to `x` +<2> declare `def y`; + load from `x` -> `def`; + implicit cast `def` to `boolean false` -> `boolean false`; + boolean xor `boolean false` and `boolean true` -> `boolean true`; + implicit cast `boolean true` to `def` -> `def`; + store `def` to `y` +<3> load from `y` -> `def`; + implicit cast `def` to `boolean true @0` -> `boolean true @0`; + load from `x` -> `def`; + implicit cast `def` to `boolean true @1` -> `boolean true @1`; + boolean xor `boolean true @0` and `boolean true @1` -> `boolean false`; + implicit cast `boolean false` -> `def`; + store `def` to `y` + +[[boolean-and-operator]] +==== Boolean And + +Use the `boolean and operator '&&'` to AND together two `boolean` type values +where if both `boolean` type values are `true` the resultant `boolean` type +value is `true` and `false` otherwise. + +*Errors* + +* If either evaluated value is a value other than a `boolean` type value or + a value that is castable to a `boolean` type value. + +*Truth* + +[cols="^1,^1,^1"] +|==== +| | true | false +| true | true | false +| false | false | false +|==== + +*Grammar* + +[source,ANTLR4] +---- +boolean_and: expression '&&' expression; +---- + +*Examples* + +* Boolean and with the `boolean` type. ++ +[source,Painless] +---- +<1> boolean x = true; +<2> boolean y = x && true; +<3> x = false; +<4> y = y && x; +---- ++ +<1> declare `boolean x`; + store `boolean true` to `x` +<2> declare `boolean y`; + load from `x` -> `boolean true @0`; + boolean and `boolean true @0` and `boolean true @1` -> `boolean true`; + store `boolean true` to `y` +<3> store `boolean false` to `x` +<4> load from `y` -> `boolean true`; + load from `x` -> `boolean false`; + boolean and `boolean true` and `boolean false` -> `boolean false`; + store `boolean false` to `y` ++ +* Boolean and with the `def` type. ++ +[source,Painless] +---- +<1> def x = true; +<2> def y = x && true; +<3> x = false; +<4> y = y && x; +---- ++ +<1> declare `def x`; + implicit cast `boolean true` to `def` -> `def`; + store `def` to `x` +<2> declare `def y`; + load from `x` -> `def`; + implicit cast `def` to `boolean true @0` -> `boolean true @0`; + boolean and `boolean true @0` and `boolean true @1` -> `boolean true`; + implicit cast `boolean true` to `def` -> `def`; + store `def` to `y` +<3> implicit cast `boolean false` to `def` -> `def`; + store `def` to `x`; +<4> load from `y` -> `def`; + implicit cast `def` to `boolean true` -> `boolean true`; + load from `x` -> `def`; + implicit cast `def` to `boolean false` -> `boolean false`; + boolean and `boolean true` and `boolean false` -> `boolean false`; + implicit cast `boolean false` -> `def`; + store `def` to `y` + +[[boolean-or-operator]] +==== Boolean Or + +Use the `boolean or operator '||'` to OR together two `boolean` type values +where if either one of the `boolean` type values is `true` the resultant +`boolean` type value is `true` and `false` otherwise. + +*Errors* + +* If either evaluated value is a value other than a `boolean` type value or + a value that is castable to a `boolean` type value. + +*Truth* + +[cols="^1,^1,^1"] +|==== +| | true | false +| true | true | true +| false | true | false +|==== + +*Grammar:* +[source,ANTLR4] +---- +boolean_and: expression '||' expression; +---- + +*Examples* + +* Boolean or with the `boolean` type. ++ +[source,Painless] +---- +<1> boolean x = false; +<2> boolean y = x || true; +<3> y = false; +<4> y = y || x; +---- ++ +<1> declare `boolean x`; + store `boolean false` to `x` +<2> declare `boolean y`; + load from `x` -> `boolean false`; + boolean or `boolean false` and `boolean true` -> `boolean true`; + store `boolean true` to `y` +<3> store `boolean false` to `y` +<4> load from `y` -> `boolean false @0`; + load from `x` -> `boolean false @1`; + boolean or `boolean false @0` and `boolean false @1` -> `boolean false`; + store `boolean false` to `y` ++ +* Boolean or with the `def` type. ++ +[source,Painless] +---- +<1> def x = false; +<2> def y = x || true; +<3> y = false; +<4> y = y || x; +---- ++ +<1> declare `def x`; + implicit cast `boolean false` to `def` -> `def`; + store `def` to `x` +<2> declare `def y`; + load from `x` -> `def`; + implicit cast `def` to `boolean false` -> `boolean true`; + boolean or `boolean false` and `boolean true` -> `boolean true`; + implicit cast `boolean true` to `def` -> `def`; + store `def` to `y` +<3> implicit cast `boolean false` to `def` -> `def`; + store `def` to `y`; +<4> load from `y` -> `def`; + implicit cast `def` to `boolean false @0` -> `boolean false @0`; + load from `x` -> `def`; + implicit cast `def` to `boolean false @1` -> `boolean false @1`; + boolean or `boolean false @0` and `boolean false @1` -> `boolean false`; + implicit cast `boolean false` -> `def`; + store `def` to `y` diff --git a/docs/painless/painless-operators-general.asciidoc b/docs/painless/painless-operators-general.asciidoc new file mode 100644 index 00000000000..9bd057432fb --- /dev/null +++ b/docs/painless/painless-operators-general.asciidoc @@ -0,0 +1,432 @@ +[[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 +<> 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 <> 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 <> 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 +<> are the same or the resultant type can be +<> to the variable/field type. + +See <> 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`) diff --git a/docs/painless/painless-operators-numeric.asciidoc b/docs/painless/painless-operators-numeric.asciidoc new file mode 100644 index 00000000000..d39b895908f --- /dev/null +++ b/docs/painless/painless-operators-numeric.asciidoc @@ -0,0 +1,1339 @@ +[[painless-operators-numeric]] +=== Operators: Numeric + +[[post-increment-operator]] +==== Post Increment + +Use the `post increment operator '++'` to INCREASE the value of a numeric type +variable/field by `1`. An extra implicit cast is necessary to return the +promoted numeric type value to the original numeric type value of the +variable/field for the following types: `byte`, `short`, and `char`. If a +variable/field is read as part of an expression the value is loaded prior to the +increment. + +*Errors* + +* If the variable/field is a non-numeric type. + +*Grammar* + +[source,ANTLR4] +---- +post_increment: ( variable | field ) '++'; +---- + +*Promotion* + +[options="header",cols="<1,<1,<1"] +|==== +| original | promoted | implicit +| byte | int | byte +| short | int | short +| char | int | char +| int | int | +| long | long | +| float | float | +| double | double | +| def | def | +|==== + +*Examples* + +* Post increment with different numeric types. ++ +[source,Painless] +---- +<1> short i = 0; +<2> i++; +<3> long j = 1; +<4> long k; +<5> k = j++; +---- ++ +<1> declare `short i`; + store `short 0` to `i` +<2> load from `i` -> `short 0`; + promote `short 0`: result `int`; + add `int 0` and `int 1` -> `int 1`; + implicit cast `int 1` to `short 1`; + store `short 1` to `i` +<3> declare `long j`; + implicit cast `int 1` to `long 1` -> `long 1`; + store `long 1` to `j` +<4> declare `long k`; + store default `long 0` to `k` +<5> load from `j` -> `long 1`; + store `long 1` to `k`; + add `long 1` and `long 1` -> `long 2`; + store `long 2` to `j` ++ +* Post increment with the `def` type. ++ +[source,Painless] +---- +<1> def x = 1; +<2> x++; +---- ++ +<1> declare `def x`; + implicit cast `int 1` to `def` -> `def`; + store `def` to `x` +<2> load from `x` -> `def`; + implicit cast `def` to `int 1`; + add `int 1` and `int 1` -> `int 2`; + implicit cast `int 2` to `def`; + store `def` to `x` + +[[post-decrement-operator]] +==== Post Decrement + +Use the `post decrement operator '--'` to DECREASE the value of a numeric type +variable/field by `1`. An extra implicit cast is necessary to return the +promoted numeric type value to the original numeric type value of the +variable/field for the following types: `byte`, `short`, and `char`. If a +variable/field is read as part of an expression the value is loaded prior to +the decrement. + +*Errors* + +* If the variable/field is a non-numeric type. + +*Grammar* + +[source,ANTLR4] +---- +post_decrement: ( variable | field ) '--'; +---- + +*Promotion* + +[options="header",cols="<1,<1,<1"] +|==== +| original | promoted | implicit +| byte | int | byte +| short | int | short +| char | int | char +| int | int | +| long | long | +| float | float | +| double | double | +| def | def | +|==== + +*Examples* + +* Post decrement with different numeric types. ++ +[source,Painless] +---- +<1> short i = 0; +<2> i--; +<3> long j = 1; +<4> long k; +<5> k = j--; +---- ++ +<1> declare `short i`; + store `short 0` to `i` +<2> load from `i` -> `short 0`; + promote `short 0`: result `int`; + subtract `int 1` from `int 0` -> `int -1`; + implicit cast `int -1` to `short -1`; + store `short -1` to `i` +<3> declare `long j`; + implicit cast `int 1` to `long 1` -> `long 1`; + store `long 1` to `j` +<4> declare `long k`; + store default `long 0` to `k` +<5> load from `j` -> `long 1`; + store `long 1` to `k`; + subtract `long 1` from `long 1` -> `long 0`; + store `long 0` to `j` ++ +* Post decrement with the `def` type. ++ +[source,Painless] +---- +<1> def x = 1; +<2> x--; +---- ++ +<1> declare `def x`; + implicit cast `int 1` to `def` -> `def`; + store `def` to `x` +<2> load from `x` -> `def`; + implicit cast `def` to `int 1`; + subtract `int 1` from `int 1` -> `int 0`; + implicit cast `int 0` to `def`; + store `def` to `x` + +[[pre-increment-operator]] +==== Pre Increment + +Use the `pre increment operator '++'` to INCREASE the value of a numeric type +variable/field by `1`. An extra implicit cast is necessary to return the +promoted numeric type value to the original numeric type value of the +variable/field for the following types: `byte`, `short`, and `char`. If a +variable/field is read as part of an expression the value is loaded after the +increment. + +*Errors* + +* If the variable/field is a non-numeric type. + +*Grammar* + +[source,ANTLR4] +---- +pre_increment: '++' ( variable | field ); +---- + +*Promotion* + +[options="header",cols="<1,<1,<1"] +|==== +| original | promoted | implicit +| byte | int | byte +| short | int | short +| char | int | char +| int | int | +| long | long | +| float | float | +| double | double | +| def | def | +|==== + +*Examples* + +* Pre increment with different numeric types. ++ +[source,Painless] +---- +<1> short i = 0; +<2> ++i; +<3> long j = 1; +<4> long k; +<5> k = ++j; +---- ++ +<1> declare `short i`; + store `short 0` to `i` +<2> load from `i` -> `short 0`; + promote `short 0`: result `int`; + add `int 0` and `int 1` -> `int 1`; + implicit cast `int 1` to `short 1`; + store `short 1` to `i` +<3> declare `long j`; + implicit cast `int 1` to `long 1` -> `long 1`; + store `long 1` to `j` +<4> declare `long k`; + store default `long 0` to `k` +<5> load from `j` -> `long 1`; + add `long 1` and `long 1` -> `long 2`; + store `long 2` to `j`; + store `long 2` to `k` ++ +* Pre increment with the `def` type. ++ +[source,Painless] +---- +<1> def x = 1; +<2> ++x; +---- ++ +<1> declare `def x`; + implicit cast `int 1` to `def` -> `def`; + store `def` to `x` +<2> load from `x` -> `def`; + implicit cast `def` to `int 1`; + add `int 1` and `int 1` -> `int 2`; + implicit cast `int 2` to `def`; + store `def` to `x` + +[[pre-decrement-operator]] +==== Pre Decrement + +Use the `pre decrement operator '--'` to DECREASE the value of a numeric type +variable/field by `1`. An extra implicit cast is necessary to return the +promoted numeric type value to the original numeric type value of the +variable/field for the following types: `byte`, `short`, and `char`. If a +variable/field is read as part of an expression the value is loaded after the +decrement. + +*Errors* + +* If the variable/field is a non-numeric type. + +*Grammar* + +[source,ANTLR4] +---- +pre_increment: '--' ( variable | field ); +---- + +*Promotion* + +[options="header",cols="<1,<1,<1"] +|==== +| original | promoted | implicit +| byte | int | byte +| short | int | short +| char | int | char +| int | int | +| long | long | +| float | float | +| double | double | +| def | def | +|==== + +*Examples* + +* Pre decrement with different numeric types. ++ +[source,Painless] +---- +<1> short i = 0; +<2> --i; +<3> long j = 1; +<4> long k; +<5> k = --j; +---- ++ +<1> declare `short i`; + store `short 0` to `i` +<2> load from `i` -> `short 0`; + promote `short 0`: result `int`; + subtract `int 1` from `int 0` -> `int -1`; + implicit cast `int -1` to `short -1`; + store `short -1` to `i` +<3> declare `long j`; + implicit cast `int 1` to `long 1` -> `long 1`; + store `long 1` to `j` +<4> declare `long k`; + store default `long 0` to `k` +<5> load from `j` -> `long 1`; + subtract `long 1` from `long 1` -> `long 0`; + store `long 0` to `j` + store `long 0` to `k`; ++ +* Pre decrement operator with the `def` type. ++ +[source,Painless] +---- +<1> def x = 1; +<2> --x; +---- ++ +<1> declare `def x`; + implicit cast `int 1` to `def` -> `def`; + store `def` to `x` +<2> load from `x` -> `def`; + implicit cast `def` to `int 1`; + subtract `int 1` from `int 1` -> `int 0`; + implicit cast `int 0` to `def`; + store `def` to `x` + +[[unary-positive-operator]] +==== Unary Positive + +Use the `unary positive operator '+'` to the preserve the IDENTITY of a +numeric type value. + +*Errors* + +* If the value is a non-numeric type. + +*Grammar* + +[source,ANTLR4] +---- +unary_positive: '+' expression; +---- + +*Examples* + +* Unary positive with different numeric types. ++ +[source,Painless] +---- +<1> int x = +1; +<2> long y = +x; +---- ++ +<1> declare `int x`; + identity `int 1` -> `int 1`; + store `int 1` to `x` +<2> declare `long y`; + load from `x` -> `int 1`; + identity `int 1` -> `int 1`; + implicit cast `int 1` to `long 1` -> `long 1`; + store `long 1` to `y` ++ +* Unary positive with the `def` type. ++ +[source,Painless] +---- +<1> def z = +1; +<2> int i = +z; +---- +<1> declare `def z`; + identity `int 1` -> `int 1`; + implicit cast `int 1` to `def`; + store `def` to `z` +<2> declare `int i`; + load from `z` -> `def`; + implicit cast `def` to `int 1`; + identity `int 1` -> `int 1`; + store `int 1` to `i`; + +[[unary-negative-operator]] +==== Unary Negative + +Use the `unary negative operator '-'` to NEGATE a numeric type value. + +*Errors* + +* If the value is a non-numeric type. + +*Grammar* + +[source,ANTLR4] +---- +unary_negative: '-' expression; +---- + +*Examples* + +* Unary negative with different numeric types. ++ +[source,Painless] +---- +<1> int x = -1; +<2> long y = -x; +---- ++ +<1> declare `int x`; + negate `int 1` -> `int -1`; + store `int -1` to `x` +<2> declare `long y`; + load from `x` -> `int 1`; + negate `int -1` -> `int 1`; + implicit cast `int 1` to `long 1` -> `long 1`; + store `long 1` to `y` ++ +* Unary negative with the `def` type. ++ +[source,Painless] +---- +<1> def z = -1; +<2> int i = -z; +---- +<1> declare `def z`; + negate `int 1` -> `int -1`; + implicit cast `int -1` to `def`; + store `def` to `z` +<2> declare `int i`; + load from `z` -> `def`; + implicit cast `def` to `int -1`; + negate `int -1` -> `int 1`; + store `int 1` to `i`; + +[[bitwise-not-operator]] +==== Bitwise Not + +Use the `bitwise not operator '~'` to NOT each bit in an integer type value +where a `1-bit` is flipped to a resultant `0-bit` and a `0-bit` is flipped to a +resultant `1-bit`. + +*Errors* + +* If the value is a non-integer type. + +*Bits* + +[options="header",cols="<1,<1"] +|==== +| original | result +| 1 | 0 +| 0 | 1 +|==== + +*Grammar* + +[source,ANTLR4] +---- +bitwise_not: '~' expression; +---- + +*Promotion* + +[options="header",cols="<1,<1"] +|==== +| original | promoted +| byte | int +| short | int +| char | int +| int | int +| long | long +| def | def +|==== + +*Examples* + +* Bitwise not with different numeric types. ++ +[source,Painless] +---- +<1> byte b = 1; +<2> int i = ~b; +<3> long l = ~i; +---- ++ +<1> declare `byte x`; + store `byte 1` to b +<2> declare `int i`; + load from `b` -> `byte 1`; + implicit cast `byte 1` to `int 1` -> `int 1`; + bitwise not `int 1` -> `int -2`; + store `int -2` to `i` +<3> declare `long l`; + load from `i` -> `int -2`; + implicit cast `int -2` to `long -2` -> `long -2`; + bitwise not `long -2` -> `long 1`; + store `long 1` to `l` ++ +* Bitwise not with the `def` type. ++ +[source,Painless] +---- +<1> def d = 1; +<2> def e = ~d; +---- ++ +<1> declare `def d`; + implicit cast `int 1` to `def` -> `def`; + store `def` to `d`; +<2> declare `def e`; + load from `d` -> `def`; + implicit cast `def` to `int 1` -> `int 1`; + bitwise not `int 1` -> `int -2`; + implicit cast `int 1` to `def` -> `def`; + store `def` to `e` + +[[multiplication-operator]] +==== Multiplication + +Use the `multiplication operator '*'` to MULTIPLY together two numeric type +values. Rules for resultant overflow and NaN values follow the JVM +specification. + +*Errors* + +* If either of the values is a non-numeric type. + +*Grammar* + +[source,ANTLR4] +---- +multiplication: expression '*' expression; +---- + +*Promotion* + +[cols="<1,^1,^1,^1,^1,^1,^1,^1,^1"] +|==== +| | byte | short | char | int | long | float | double | 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 +| def | def | def | def | def | def | def | def | def +|==== + +*Examples* + +* Multiplication with different numeric types. ++ +[source,Painless] +---- +<1> int i = 5*4; +<2> double d = i*7.0; +---- ++ +<1> declare `int i`; + multiply `int 4` by `int 5` -> `int 20`; + store `int 20` in `i` +<2> declare `double d`; + load from `int i` -> `int 20`; + promote `int 20` and `double 7.0`: result `double`; + implicit cast `int 20` to `double 20.0` -> `double 20.0`; + multiply `double 20.0` by `double 7.0` -> `double 140.0`; + store `double 140.0` to `d` ++ +* Multiplication with the `def` type. ++ +[source,Painless] +---- +<1> def x = 5*4; +<2> def y = x*2; +---- +<1> declare `def x`; + multiply `int 5` by `int 4` -> `int 20`; + implicit cast `int 20` to `def` -> `def`; + store `def` in `x` +<2> declare `def y`; + load from `x` -> `def`; + implicit cast `def` to `int 20`; + multiply `int 20` by `int 2` -> `int 40`; + implicit cast `int 40` to `def` -> `def`; + store `def` to `y` + +[[division-operator]] +==== Division + +Use the `division operator '/'` to DIVIDE one numeric type value by another. +Rules for NaN values and division by zero follow the JVM specification. Division +with integer values drops the remainder of the resultant value. + +*Errors* + +* If either of the values is a non-numeric type. +* If a left-hand side integer type value is divided by a right-hand side integer + type value of `0`. + +*Grammar* + +[source,ANTLR4] +---- +division: expression '/' expression; +---- + +*Promotion* + +[cols="<1,^1,^1,^1,^1,^1,^1,^1,^1"] +|==== +| | byte | short | char | int | long | float | double | 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 +| def | def | def | def | def | def | def | def | def +|==== + +*Examples* + +* Division with different numeric types. ++ +[source,Painless] +---- +<1> int i = 29/4; +<2> double d = i/7.0; +---- ++ +<1> declare `int i`; + divide `int 29` by `int 4` -> `int 7`; + store `int 7` in `i` +<2> declare `double d`; + load from `int i` -> `int 7`; + promote `int 7` and `double 7.0`: result `double`; + implicit cast `int 7` to `double 7.0` -> `double 7.0`; + divide `double 7.0` by `double 7.0` -> `double 1.0`; + store `double 1.0` to `d` ++ +* Division with the `def` type. ++ +[source,Painless] +---- +<1> def x = 5/4; +<2> def y = x/2; +---- +<1> declare `def x`; + divide `int 5` by `int 4` -> `int 1`; + implicit cast `int 1` to `def` -> `def`; + store `def` in `x` +<2> declare `def y`; + load from `x` -> `def`; + implicit cast `def` to `int 1`; + divide `int 1` by `int 2` -> `int 0`; + implicit cast `int 0` to `def` -> `def`; + store `def` to `y` + +[[remainder-operator]] +==== Remainder + +Use the `remainder operator '%'` to calculate the REMAINDER for division +between two numeric type values. Rules for NaN values and division by zero follow the JVM +specification. + +*Errors* + +* If either of the values is a non-numeric type. + +*Grammar* + +[source,ANTLR4] +---- +remainder: expression '%' expression; +---- + +*Promotion* + +[cols="<1,^1,^1,^1,^1,^1,^1,^1,^1"] +|==== +| | byte | short | char | int | long | float | double | 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 +| def | def | def | def | def | def | def | def | def +|==== + +*Examples* + +* Remainder with different numeric types. ++ +[source,Painless] +---- +<1> int i = 29%4; +<2> double d = i%7.0; +---- ++ +<1> declare `int i`; + remainder `int 29` by `int 4` -> `int 1`; + store `int 7` in `i` +<2> declare `double d`; + load from `int i` -> `int 1`; + promote `int 1` and `double 7.0`: result `double`; + implicit cast `int 1` to `double 1.0` -> `double 1.0`; + remainder `double 1.0` by `double 7.0` -> `double 1.0`; + store `double 1.0` to `d` ++ +* Remainder with the `def` type. ++ +[source,Painless] +---- +<1> def x = 5%4; +<2> def y = x%2; +---- +<1> declare `def x`; + remainder `int 5` by `int 4` -> `int 1`; + implicit cast `int 1` to `def` -> `def`; + store `def` in `x` +<2> declare `def y`; + load from `x` -> `def`; + implicit cast `def` to `int 1`; + remainder `int 1` by `int 2` -> `int 1`; + implicit cast `int 1` to `def` -> `def`; + store `def` to `y` + +[[addition-operator]] +==== Addition + +Use the `addition operator '+'` to ADD together two numeric type values. Rules +for resultant overflow and NaN values follow the JVM specification. + +*Errors* + +* If either of the values is a non-numeric type. + +*Grammar* + +[source,ANTLR4] +---- +addition: expression '+' expression; +---- + +*Promotion* + +[cols="<1,^1,^1,^1,^1,^1,^1,^1,^1"] +|==== +| | byte | short | char | int | long | float | double | 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 +| def | def | def | def | def | def | def | def | def +|==== + +*Examples* + +* Addition operator with different numeric types. ++ +[source,Painless] +---- +<1> int i = 29+4; +<2> double d = i+7.0; +---- ++ +<1> declare `int i`; + add `int 29` and `int 4` -> `int 33`; + store `int 33` in `i` +<2> declare `double d`; + load from `int i` -> `int 33`; + promote `int 33` and `double 7.0`: result `double`; + implicit cast `int 33` to `double 33.0` -> `double 33.0`; + add `double 33.0` and `double 7.0` -> `double 40.0`; + store `double 40.0` to `d` ++ +* Addition with the `def` type. ++ +[source,Painless] +---- +<1> def x = 5+4; +<2> def y = x+2; +---- +<1> declare `def x`; + add `int 5` and `int 4` -> `int 9`; + implicit cast `int 9` to `def` -> `def`; + store `def` in `x` +<2> declare `def y`; + load from `x` -> `def`; + implicit cast `def` to `int 9`; + add `int 9` and `int 2` -> `int 11`; + implicit cast `int 11` to `def` -> `def`; + store `def` to `y` + +[[subtraction-operator]] +==== Subtraction + +Use the `subtraction operator '-'` to SUBTRACT a right-hand side numeric type +value from a left-hand side numeric type value. Rules for resultant overflow +and NaN values follow the JVM specification. + +*Errors* + +* If either of the values is a non-numeric type. + +*Grammar* + +[source,ANTLR4] +---- +subtraction: expression '-' expression; +---- + +*Promotion* + +[cols="<1,^1,^1,^1,^1,^1,^1,^1,^1"] +|==== +| | byte | short | char | int | long | float | double | 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 +| def | def | def | def | def | def | def | def | def +|==== + +*Examples* + +* Subtraction with different numeric types. ++ +[source,Painless] +---- +<1> int i = 29-4; +<2> double d = i-7.5; +---- ++ +<1> declare `int i`; + subtract `int 4` from `int 29` -> `int 25`; + store `int 25` in `i` +<2> declare `double d` + load from `int i` -> `int 25`; + promote `int 25` and `double 7.5`: result `double`; + implicit cast `int 25` to `double 25.0` -> `double 25.0`; + subtract `double 33.0` by `double 7.5` -> `double 25.5`; + store `double 25.5` to `d` ++ +* Subtraction with the `def` type. ++ +[source,Painless] +---- +<1> def x = 5-4; +<2> def y = x-2; +---- +<1> declare `def x`; + subtract `int 4` and `int 5` -> `int 1`; + implicit cast `int 1` to `def` -> `def`; + store `def` in `x` +<2> declare `def y`; + load from `x` -> `def`; + implicit cast `def` to `int 1`; + subtract `int 2` from `int 1` -> `int -1`; + implicit cast `int -1` to `def` -> `def`; + store `def` to `y` + +[[left-shift-operator]] +==== Left Shift + +Use the `left shift operator '<<'` to SHIFT lower order bits to higher order +bits in a left-hand side integer type value by the distance specified in a +right-hand side integer type value. + +*Errors* + +* If either of the values is a non-integer type. +* If the right-hand side value cannot be cast to an int type. + +*Grammar* + +[source,ANTLR4] +---- +left_shift: expression '<<' expression; +---- + +*Promotion* + +The left-hand side integer type value is promoted as specified in the table +below. The right-hand side integer type value is always implicitly cast to an +`int` type value and truncated to the number of bits of the promoted type value. + +[options="header",cols="<1,<1"] +|==== +| original | promoted +| byte | int +| short | int +| char | int +| int | int +| long | long +| def | def +|==== + +*Examples* + +* Left shift with different integer types. ++ +[source,Painless] +---- +<1> int i = 4 << 1; +<2> long l = i << 2L; +---- ++ +<1> declare `int i`; + left shift `int 4` by `int 1` -> `int 8`; + store `int 8` in `i` +<2> declare `long l` + load from `int i` -> `int 8`; + implicit cast `long 2` to `int 2` -> `int 2`; + left shift `int 8` by `int 2` -> `int 32`; + implicit cast `int 32` to `long 32` -> `long 32`; + store `long 32` to `l` ++ +* Left shift with the `def` type. ++ +[source,Painless] +---- +<1> def x = 4 << 2; +<2> def y = x << 1; +---- +<1> declare `def x`; + left shift `int 4` by `int 2` -> `int 16`; + implicit cast `int 16` to `def` -> `def`; + store `def` in `x` +<2> declare `def y`; + load from `x` -> `def`; + implicit cast `def` to `int 16`; + left shift `int 16` by `int 1` -> `int 32`; + implicit cast `int 32` to `def` -> `def`; + store `def` to `y` + +[[right-shift-operator]] +==== Right Shift + +Use the `right shift operator '>>'` to SHIFT higher order bits to lower order +bits in a left-hand side integer type value by the distance specified in a +right-hand side integer type value. The highest order bit of the left-hand side +integer type value is preserved. + +*Errors* + +* If either of the values is a non-integer type. +* If the right-hand side value cannot be cast to an int type. + +*Grammar* + +[source,ANTLR4] +---- +right_shift: expression '>>' expression; +---- + +*Promotion* + +The left-hand side integer type value is promoted as specified in the table +below. The right-hand side integer type value is always implicitly cast to an +`int` type value and truncated to the number of bits of the promoted type value. + +[options="header",cols="<1,<1"] +|==== +| original | promoted +| byte | int +| short | int +| char | int +| int | int +| long | long +| def | def +|==== + +*Examples* + +* Right shift with different integer types. ++ +[source,Painless] +---- +<1> int i = 32 >> 1; +<2> long l = i >> 2L; +---- ++ +<1> declare `int i`; + right shift `int 32` by `int 1` -> `int 16`; + store `int 16` in `i` +<2> declare `long l` + load from `int i` -> `int 16`; + implicit cast `long 2` to `int 2` -> `int 2`; + right shift `int 16` by `int 2` -> `int 4`; + implicit cast `int 4` to `long 4` -> `long 4`; + store `long 4` to `l` ++ +* Right shift with the `def` type. ++ +[source,Painless] +---- +<1> def x = 16 >> 2; +<2> def y = x >> 1; +---- +<1> declare `def x`; + right shift `int 16` by `int 2` -> `int 4`; + implicit cast `int 4` to `def` -> `def`; + store `def` in `x` +<2> declare `def y`; + load from `x` -> `def`; + implicit cast `def` to `int 4`; + right shift `int 4` by `int 1` -> `int 2`; + implicit cast `int 2` to `def` -> `def`; + store `def` to `y` + +[[unsigned-right-shift-operator]] +==== Unsigned Right Shift + +Use the `unsigned right shift operator '>>>'` to SHIFT higher order bits to +lower order bits in a left-hand side integer type value by the distance +specified in a right-hand side type integer value. The highest order bit of the +left-hand side integer type value is *not* preserved. + +*Errors* + +* If either of the values is a non-integer type. +* If the right-hand side value cannot be cast to an int type. + +*Grammar* + +[source,ANTLR4] +---- +unsigned_right_shift: expression '>>>' expression; +---- + +*Promotion* + +The left-hand side integer type value is promoted as specified in the table +below. The right-hand side integer type value is always implicitly cast to an +`int` type value and truncated to the number of bits of the promoted type value. + +[options="header",cols="<1,<1"] +|==== +| original | promoted +| byte | int +| short | int +| char | int +| int | int +| long | long +| def | def +|==== + +*Examples* + +* Unsigned right shift with different integer types. ++ +[source,Painless] +---- +<1> int i = -1 >>> 29; +<2> long l = i >>> 2L; +---- ++ +<1> declare `int i`; + unsigned right shift `int -1` by `int 29` -> `int 7`; + store `int 7` in `i` +<2> declare `long l` + load from `int i` -> `int 7`; + implicit cast `long 2` to `int 2` -> `int 2`; + unsigned right shift `int 7` by `int 2` -> `int 3`; + implicit cast `int 3` to `long 3` -> `long 3`; + store `long 3` to `l` ++ +* Unsigned right shift with the `def` type. ++ +[source,Painless] +---- +<1> def x = 16 >>> 2; +<2> def y = x >>> 1; +---- +<1> declare `def x`; + unsigned right shift `int 16` by `int 2` -> `int 4`; + implicit cast `int 4` to `def` -> `def`; + store `def` in `x` +<2> declare `def y`; + load from `x` -> `def`; + implicit cast `def` to `int 4`; + unsigned right shift `int 4` by `int 1` -> `int 2`; + implicit cast `int 2` to `def` -> `def`; + store `def` to `y` + +[[bitwise-and-operator]] +==== Bitwise And + +Use the `bitwise and operator '&'` to AND together each bit within two +integer type values where if both bits at the same index are `1` the resultant +bit is `1` and `0` otherwise. + +*Errors* + +* If either of the values is a non-integer type. + +*Bits* + +[cols="^1,^1,^1"] +|==== +| | 1 | 0 +| 1 | 1 | 0 +| 0 | 0 | 0 +|==== + +*Grammar* + +[source,ANTLR4] +---- +bitwise_and: expression '&' expression; +---- + +*Promotion* + +[cols="<1,^1,^1,^1,^1,^1,^1"] +|==== +| | byte | short | char | int | long | def +| byte | int | int | int | int | long | def +| short | int | int | int | int | long | def +| char | int | int | int | int | long | def +| int | int | int | int | int | long | def +| long | long | long | long | long | long | def +| def | def | def | def | def | def | def +|==== + +*Examples* + +* Bitwise and with different integer types. ++ +[source,Painless] +---- +<1> int i = 5 & 6; +<2> long l = i & 5L; +---- ++ +<1> declare `int i`; + bitwise and `int 5` and `int 6` -> `int 4`; + store `int 4` in `i` +<2> declare `long l` + load from `int i` -> `int 4`; + promote `int 4` and `long 5`: result `long`; + implicit cast `int 4` to `long 4` -> `long 4`; + bitwise and `long 4` and `long 5` -> `long 4`; + store `long 4` to `l` ++ +* Bitwise and with the `def` type. ++ +[source,Painless] +---- +<1> def x = 15 & 6; +<2> def y = x & 5; +---- +<1> declare `def x`; + bitwise and `int 15` and `int 6` -> `int 6`; + implicit cast `int 6` to `def` -> `def`; + store `def` in `x` +<2> declare `def y`; + load from `x` -> `def`; + implicit cast `def` to `int 6`; + bitwise and `int 6` and `int 5` -> `int 4`; + implicit cast `int 4` to `def` -> `def`; + store `def` to `y` + +[[bitwise-xor-operator]] +==== Bitwise Xor + +Use the `bitwise xor operator '^'` to XOR together each bit within two integer +type values where if one bit is a `1` and the other bit is a `0` at the same +index the resultant bit is `1` otherwise the resultant bit is `0`. + +*Errors* + +* If either of the values is a non-integer type. + +*Bits* + +The following table illustrates the resultant bit from the xoring of two bits. + +[cols="^1,^1,^1"] +|==== +| | 1 | 0 +| 1 | 0 | 1 +| 0 | 1 | 0 +|==== + +*Grammar* + +[source,ANTLR4] +---- +bitwise_and: expression '^' expression; +---- + +*Promotion* + +[cols="<1,^1,^1,^1,^1,^1,^1"] +|==== +| | byte | short | char | int | long | def +| byte | int | int | int | int | long | def +| short | int | int | int | int | long | def +| char | int | int | int | int | long | def +| int | int | int | int | int | long | def +| long | long | long | long | long | long | def +| def | def | def | def | def | def | def +|==== + +*Examples* + +* Bitwise xor with different integer types. ++ +[source,Painless] +---- +<1> int i = 5 ^ 6; +<2> long l = i ^ 5L; +---- ++ +<1> declare `int i`; + bitwise xor `int 5` and `int 6` -> `int 3`; + store `int 3` in `i` +<2> declare `long l` + load from `int i` -> `int 4`; + promote `int 3` and `long 5`: result `long`; + implicit cast `int 3` to `long 3` -> `long 3`; + bitwise xor `long 3` and `long 5` -> `long 6`; + store `long 6` to `l` ++ +* Bitwise xor with the `def` type. ++ +[source,Painless] +---- +<1> def x = 15 ^ 6; +<2> def y = x ^ 5; +---- +<1> declare `def x`; + bitwise xor `int 15` and `int 6` -> `int 9`; + implicit cast `int 9` to `def` -> `def`; + store `def` in `x` +<2> declare `def y`; + load from `x` -> `def`; + implicit cast `def` to `int 9`; + bitwise xor `int 9` and `int 5` -> `int 12`; + implicit cast `int 12` to `def` -> `def`; + store `def` to `y` + +[[bitwise-or-operator]] +==== Bitwise Or + +Use the `bitwise or operator '|'` to OR together each bit within two integer +type values where if at least one bit is a `1` at the same index the resultant +bit is `1` otherwise the resultant bit is `0`. + +*Errors* + +* If either of the values is a non-integer type. + +*Bits* + +The following table illustrates the resultant bit from the oring of two bits. + +[cols="^1,^1,^1"] +|==== +| | 1 | 0 +| 1 | 1 | 1 +| 0 | 1 | 0 +|==== + +*Grammar* + +[source,ANTLR4] +---- +bitwise_and: expression '|' expression; +---- + +*Promotion* + +[cols="<1,^1,^1,^1,^1,^1,^1"] +|==== +| | byte | short | char | int | long | def +| byte | int | int | int | int | long | def +| short | int | int | int | int | long | def +| char | int | int | int | int | long | def +| int | int | int | int | int | long | def +| long | long | long | long | long | long | def +| def | def | def | def | def | def | def +|==== + +*Examples* + +* Bitwise or with different integer types. ++ +[source,Painless] +---- +<1> int i = 5 | 6; +<2> long l = i | 8L; +---- ++ +<1> declare `int i`; + bitwise or `int 5` and `int 6` -> `int 7`; + store `int 7` in `i` +<2> declare `long l` + load from `int i` -> `int 7`; + promote `int 7` and `long 8`: result `long`; + implicit cast `int 7` to `long 7` -> `long 7`; + bitwise or `long 7` and `long 8` -> `long 15`; + store `long 15` to `l` ++ +* Bitwise or with the `def` type. ++ +[source,Painless] +---- +<1> def x = 5 ^ 6; +<2> def y = x ^ 8; +---- +<1> declare `def x`; + bitwise or `int 5` and `int 6` -> `int 7`; + implicit cast `int 7` to `def` -> `def`; + store `def` in `x` +<2> declare `def y`; + load from `x` -> `def`; + implicit cast `def` to `int 7`; + bitwise or `int 7` and `int 8` -> `int 15`; + implicit cast `int 15` to `def` -> `def`; + store `def` to `y` \ No newline at end of file diff --git a/docs/painless/painless-operators-reference.asciidoc b/docs/painless/painless-operators-reference.asciidoc new file mode 100644 index 00000000000..487fcce15f3 --- /dev/null +++ b/docs/painless/painless-operators-reference.asciidoc @@ -0,0 +1,774 @@ +[[painless-operators-reference]] +=== Operators: Reference + +[[method-call-operator]] +==== Method Call + +Use the `method call operator '()'` to call a member method on a +<> value. Implicit +<> is evaluated as necessary per argument +during the method call. When a method call is made on a target `def` type value, +the parameters and return type value are considered to also be of the `def` type +and are evaluated at run-time. + +An overloaded method is one that shares the same name with two or more methods. +A method is overloaded based on arity where the same name is re-used for +multiple methods as long as the number of parameters differs. + +*Errors* + +* If the reference type value is `null`. +* If the member method name doesn't exist for a given reference type value. +* If the number of arguments passed in is different from the number of specified + parameters. +* If the arguments cannot be implicitly cast or implicitly boxed/unboxed to the + correct type values for the parameters. + +*Grammar* + +[source,ANTLR4] +---- +method_call: '.' ID arguments; +arguments: '(' (expression (',' expression)*)? ')'; +---- + +*Examples* + +* Method calls on different reference types. ++ +[source,Painless] +---- +<1> Map m = new HashMap(); +<2> m.put(1, 2); +<3> int z = m.get(1); +<4> def d = new ArrayList(); +<5> d.add(1); +<6> int i = Integer.parseInt(d.get(0).toString()); +---- ++ +<1> declare `Map m`; + allocate `HashMap` instance -> `HashMap reference`; + store `HashMap reference` to `m` +<2> load from `m` -> `Map reference`; + implicit cast `int 1` to `def` -> `def`; + implicit cast `int 2` to `def` -> `def`; + call `put` on `Map reference` with arguments (`int 1`, `int 2`) +<3> declare `int z`; + load from `m` -> `Map reference`; + call `get` on `Map reference` with arguments (`int 1`) -> `def`; + implicit cast `def` to `int 2` -> `int 2`; + store `int 2` to `z` +<4> declare `def d`; + allocate `ArrayList` instance -> `ArrayList reference`; + implicit cast `ArrayList` to `def` -> `def`; + store `def` to `d` +<5> load from `d` -> `def`; + implicit cast `def` to `ArrayList reference` -> `ArrayList reference` + call `add` on `ArrayList reference` with arguments (`int 1`); +<6> declare `int i`; + load from `d` -> `def`; + implicit cast `def` to `ArrayList reference` -> `ArrayList reference` + call `get` on `ArrayList reference` with arguments (`int 1`) -> `def`; + implicit cast `def` to `Integer 1 reference` -> `Integer 1 reference`; + call `toString` on `Integer 1 reference` -> `String '1'`; + call `parseInt` on `Integer` with arguments (`String '1'`) -> `int 1`; + store `int 1` in `i`; + +[[field-access-operator]] +==== Field Access + +Use the `field access operator '.'` to store a value to or load a value from a +<> member field. + +*Errors* + +* If the reference type value is `null`. +* If the member field name doesn't exist for a given reference type value. + +*Grammar* + +[source,ANTLR4] +---- +field_access: '.' ID; +---- + +*Examples* + +The examples use the following reference type definition: + +[source,Painless] +---- +name: + Example + +non-static member fields: + * int x + * def y + * List z +---- + +* Field access with the `Example` type. ++ +[source,Painless] +---- +<1> Example example = new Example(); +<2> example.x = 1; +<3> example.y = example.x; +<4> example.z = new ArrayList(); +<5> example.z.add(1); +<6> example.x = example.z.get(0); +---- ++ +<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) +<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` +<5> load from `example` -> `Example reference`; + load from `z` of `Example reference` -> `List reference`; + call `add` on `List reference` with arguments (`int 1`) +<6> load from `example` -> `Example reference @0`; + load from `example` -> `Example reference @1`; + load from `z` of `Example reference @1` -> `List reference`; + call `get` on `List reference` with arguments (`int 0`) -> `int 1`; + store `int 1` in `x` of `List reference @0`; + (note `Example reference @0` and `Example reference @1` are the same) + +[[null-safe-operator]] +==== Null Safe + +Use the `null safe operator '?.'` instead of the method call operator or field +access operator to ensure a reference type value is `non-null` before +a method call or field access. A `null` value will be returned if the reference +type value is `null`, otherwise the method call or field access is evaluated. + +*Errors* + +* If the method call return type value or the field access type value is not + a reference type value and is not implicitly castable to a reference type + value. + +*Grammar* + +[source,ANTLR4] +---- +null_safe: null_safe_method_call + | null_safe_field_access + ; + +null_safe_method_call: '?.' ID arguments; +arguments: '(' (expression (',' expression)*)? ')'; + +null_safe_field_access: '?.' ID; +---- + +*Examples* + +The examples use the following reference type definition: + +[source,Painless] +---- +name: + Example + +non-static member methods: + * List factory() + +non-static member fields: + * List x +---- + +* Null safe without a `null` value. ++ +[source,Painless] +---- +<1> Example example = new Example(); +<2> List x = example?.factory(); +---- ++ +<1> declare `Example example`; + allocate `Example` instance -> `Example reference`; + store `Example reference` to `example` +<2> declare `List x`; + load from `example` -> `Example reference`; + null safe call `factory` on `Example reference` -> `List reference`; + store `List reference` to `x`; ++ +* Null safe with a `null` value; ++ +[source,Painless] +---- +<1> Example example = null; +<2> List x = example?.x; +---- +<1> declare `Example example`; + store `null` to `example` +<2> declare `List x`; + load from `example` -> `Example reference`; + null safe access `x` on `Example reference` -> `null`; + store `null` to `x`; + (note the *null safe operator* returned `null` because `example` is `null`) + +[[list-initialization-operator]] +==== List Initialization + +Use the `list initialization operator '[]'` to allocate an `List` type instance +to the heap with a set of pre-defined values. Each value used to initialize the +`List` type instance is cast to a `def` type value upon insertion into the +`List` type instance using the `add` method. The order of the specified values +is maintained. + +*Grammar* + +[source,ANTLR4] +---- +list_initialization: '[' expression (',' expression)* ']' + | '[' ']'; +---- + +*Examples* + +* List initialization of an empty `List` type value. ++ +[source,Painless] +---- +<1> List empty = []; +---- ++ +<1> declare `List empty`; + allocate `ArrayList` instance -> `ArrayList reference`; + implicit cast `ArrayList reference` to `List reference` -> `List reference`; + store `List reference` to `empty` ++ +* List initialization with static values. ++ +[source,Painless] +---- +<1> List list = [1, 2, 3]; +---- ++ +<1> declare `List list`; + allocate `ArrayList` instance -> `ArrayList reference`; + call `add` on `ArrayList reference` with arguments(`int 1`); + call `add` on `ArrayList reference` with arguments(`int 2`); + call `add` on `ArrayList reference` with arguments(`int 3`); + implicit cast `ArrayList reference` to `List reference` -> `List reference`; + store `List reference` to `list` ++ +* List initialization with non-static values. ++ +[source,Painless] +---- +<1> int i = 1; +<2> long l = 2L; +<3> float f = 3.0F; +<4> double d = 4.0; +<5> String s = "5"; +<6> List list = [i, l, f*d, s]; +---- ++ +<1> declare `int i`; + store `int 1` to `i` +<2> declare `long l`; + store `long 2` to `l` +<3> declare `float f`; + store `float 3.0` to `f` +<4> declare `double d`; + store `double 4.0` to `d` +<5> declare `String s`; + store `String "5"` to `s` +<6> declare `List list`; + allocate `ArrayList` instance -> `ArrayList reference`; + load from `i` -> `int 1`; + call `add` on `ArrayList reference` with arguments(`int 1`); + load from `l` -> `long 2`; + call `add` on `ArrayList reference` with arguments(`long 2`); + load from `f` -> `float 3.0`; + load from `d` -> `double 4.0`; + promote `float 3.0` and `double 4.0`: result `double`; + implicit cast `float 3.0` to `double 3.0` -> `double 3.0`; + multiply `double 3.0` and `double 4.0` -> `double 12.0`; + call `add` on `ArrayList reference` with arguments(`double 12.0`); + load from `s` -> `String "5"`; + call `add` on `ArrayList reference` with arguments(`String "5"`); + implicit cast `ArrayList reference` to `List reference` -> `List reference`; + store `List reference` to `list` + +[[list-access-operator]] +==== List Access + +Use the `list access operator '[]'` as a shortcut for a `set` method call or +`get` method call made on a `List` type value. + +*Errors* + +* If a value other than a `List` type value is accessed. +* If a non-integer type value is used as an index for a `set` method call or + `get` method call. + +*Grammar* + +[source,ANTLR4] +---- +list_access: '[' expression ']' +---- + +*Examples* + +* List access with the `List` type. ++ +[source,Painless] +---- +<1> List list = new ArrayList(); +<2> list.add(1); +<3> list.add(2); +<4> list.add(3); +<5> list[0] = 2; +<6> list[1] = 5; +<7> int x = list[0] + list[1]; +<8> int y = 1; +<9> int z = list[y]; +---- ++ +<1> declare `List list`; + allocate `ArrayList` instance -> `ArrayList reference`; + implicit cast `ArrayList reference` to `List reference` -> `List reference`; + store `List reference` to `list` +<2> load from `list` -> `List reference`; + call `add` on `List reference` with arguments(`int 1`) +<3> load from `list` -> `List reference`; + call `add` on `List reference` with arguments(`int 2`) +<4> load from `list` -> `List reference`; + call `add` on `List reference` with arguments(`int 3`) +<5> load from `list` -> `List reference`; + call `set` on `List reference` with arguments(`int 0`, `int 2`) +<6> load from `list` -> `List reference`; + call `set` on `List reference` with arguments(`int 1`, `int 5`) +<7> declare `int x`; + load from `list` -> `List reference`; + call `get` on `List reference` with arguments(`int 0`) -> `def`; + implicit cast `def` to `int 2` -> `int 2`; + load from `list` -> `List reference`; + call `get` on `List reference` with arguments(`int 1`) -> `def`; + implicit cast `def` to `int 5` -> `int 5`; + add `int 2` and `int 5` -> `int 7`; + store `int 7` to `x` +<8> declare `int y`; + store `int 1` int `y` +<9> declare `int z`; + load from `list` -> `List reference`; + load from `y` -> `int 1`; + call `get` on `List reference` with arguments(`int 1`) -> `def`; + implicit cast `def` to `int 5` -> `int 5`; + store `int 5` to `z` ++ +* List access with the `def` type. ++ +[source,Painless] +---- +<1> def d = new ArrayList(); +<2> d.add(1); +<3> d.add(2); +<4> d.add(3); +<5> d[0] = 2; +<6> d[1] = 5; +<7> def x = d[0] + d[1]; +<8> def y = 1; +<9> def z = d[y]; +---- ++ +<1> declare `List d`; + allocate `ArrayList` instance -> `ArrayList reference`; + implicit cast `ArrayList reference` to `def` -> `def`; + store `def` to `d` +<2> load from `d` -> `def`; + implicit cast `def` to `ArrayList reference` -> `ArrayList reference`; + call `add` on `ArrayList reference` with arguments(`int 1`) +<3> load from `d` -> `def`; + implicit cast `def` to `ArrayList reference` -> `ArrayList reference`; + call `add` on `ArrayList reference` with arguments(`int 2`) +<4> load from `d` -> `def`; + implicit cast `def` to `ArrayList reference` -> `ArrayList reference`; + call `add` on `ArrayList reference` with arguments(`int 3`) +<5> load from `d` -> `def`; + implicit cast `def` to `ArrayList reference` -> `ArrayList reference`; + call `set` on `ArrayList reference` with arguments(`int 0`, `int 2`) +<6> load from `d` -> `def`; + implicit cast `def` to `ArrayList reference` -> `ArrayList reference`; + call `set` on `ArrayList reference` with arguments(`int 1`, `int 5`) +<7> declare `def x`; + load from `d` -> `def`; + implicit cast `def` to `ArrayList reference` -> `ArrayList reference`; + call `get` on `ArrayList reference` with arguments(`int 0`) -> `def`; + implicit cast `def` to `int 2` -> `int 2`; + load from `d` -> `def`; + implicit cast `def` to `ArrayList reference` -> `ArrayList reference`; + call `get` on `ArrayList reference` with arguments(`int 1`) -> `def`; + implicit cast `def` to `int 2` -> `int 2`; + add `int 2` and `int 5` -> `int 7`; + store `int 7` to `x` +<8> declare `int y`; + store `int 1` int `y` +<9> declare `int z`; + load from `d` -> `ArrayList reference`; + load from `y` -> `def`; + implicit cast `def` to `int 1` -> `int 1`; + call `get` on `ArrayList reference` with arguments(`int 1`) -> `def`; + store `def` to `z` + +[[map-initialization-operator]] +==== Map Initialization + +Use the `map initialization operator '[:]'` to allocate a `Map` type instance to +the heap with a set of pre-defined values. Each pair of values used to +initialize the `Map` type instance are cast to `def` type values upon insertion +into the `Map` type instance using the `put` method. + +*Grammar* + +[source,ANTLR4] +---- +map_initialization: '[' key_pair (',' key_pair)* ']' + | '[' ':' ']'; +key_pair: expression ':' expression +---- + +*Examples* + +* Map initialization of an empty `Map` type value. ++ +[source,Painless] +---- +<1> Map empty = [:]; +---- ++ +<1> declare `Map empty`; + allocate `HashMap` instance -> `HashMap reference`; + implicit cast `HashMap reference` to `Map reference` -> `Map reference`; + store `Map reference` to `empty` ++ +* Map initialization with static values. ++ +[source,Painless] +---- +<1> Map map = [1:2, 3:4, 5:6]; +---- ++ +<1> declare `Map map`; + allocate `HashMap` instance -> `HashMap reference`; + call `put` on `HashMap reference` with arguments(`int 1`, `int 2`); + call `put` on `HashMap reference` with arguments(`int 3`, `int 4`); + call `put` on `HashMap reference` with arguments(`int 5`, `int 6`); + implicit cast `HashMap reference` to `Map reference` -> `Map reference`; + store `Map reference` to `map` ++ +* Map initialization with non-static values. ++ +[source,Painless] +---- +<1> byte b = 0; +<2> int i = 1; +<3> long l = 2L; +<4> float f = 3.0F; +<5> double d = 4.0; +<6> String s = "5"; +<7> Map map = [b:i, l:f*d, d:s]; +---- ++ +<1> declare `byte b`; + store `byte 0` to `b` +<2> declare `int i`; + store `int 1` to `i` +<3> declare `long l`; + store `long 2` to `l` +<4> declare `float f`; + store `float 3.0` to `f` +<5> declare `double d`; + store `double 4.0` to `d` +<6> declare `String s`; + store `String "5"` to `s` +<7> declare `Map map`; + allocate `HashMap` instance -> `HashMap reference`; + load from `b` -> `byte 0`; + load from `i` -> `int 1`; + call `put` on `HashMap reference` with arguments(`byte 0`, `int 1`); + load from `l` -> `long 2`; + load from `f` -> `float 3.0`; + load from `d` -> `double 4.0`; + promote `float 3.0` and `double 4.0`: result `double`; + implicit cast `float 3.0` to `double 3.0` -> `double 3.0`; + multiply `double 3.0` and `double 4.0` -> `double 12.0`; + call `put` on `HashMap reference` with arguments(`long 2`, `double 12.0`); + load from `d` -> `double 4.0`; + load from `s` -> `String "5"`; + call `put` on `HashMap reference` with + arguments(`double 4.0`, `String "5"`); + implicit cast `HashMap reference` to `Map reference` -> `Map reference`; + store `Map reference` to `map` + +[[map-access-operator]] +==== Map Access + +Use the `map access operator '[]'` as a shortcut for a `put` method call or +`get` method call made on a `Map` type value. + +*Errors* + +* If a value other than a `Map` type value is accessed. + +*Grammar* +[source,ANTLR4] +---- +map_access: '[' expression ']' +---- + +*Examples* + +* Map access with the `Map` type. ++ +[source,Painless] +---- +<1> Map map = new HashMap(); +<2> map['value2'] = 2; +<3> map['value5'] = 5; +<4> int x = map['value2'] + map['value5']; +<5> String y = 'value5'; +<6> int z = x[z]; +---- ++ +<1> declare `Map map`; + allocate `HashMap` instance -> `HashMap reference`; + implicit cast `HashMap reference` to `Map reference` -> `Map reference`; + store `Map reference` to `map` +<2> load from `map` -> `Map reference`; + call `put` on `Map reference` with arguments(`String 'value2'`, `int 2`) +<3> load from `map` -> `Map reference`; + call `put` on `Map reference` with arguments(`String 'value5'`, `int 5`) +<4> declare `int x`; + load from `map` -> `Map reference`; + call `get` on `Map reference` with arguments(`String 'value2'`) -> `def`; + implicit cast `def` to `int 2` -> `int 2`; + load from `map` -> `Map reference`; + call `get` on `Map reference` with arguments(`String 'value5'`) -> `def`; + implicit cast `def` to `int 5` -> `int 5`; + add `int 2` and `int 5` -> `int 7`; + store `int 7` to `x` +<5> declare `String y`; + store `String 'value5'` to `y` +<6> declare `int z`; + load from `map` -> `Map reference`; + load from `y` -> `String 'value5'`; + call `get` on `Map reference` with arguments(`String 'value5'`) -> `def`; + implicit cast `def` to `int 5` -> `int 5`; + store `int 5` to `z` ++ +* Map access with the `def` type. ++ +[source,Painless] +---- +<1> def d = new HashMap(); +<2> d['value2'] = 2; +<3> d['value5'] = 5; +<4> int x = d['value2'] + d['value5']; +<5> String y = 'value5'; +<6> def z = d[y]; +---- ++ +<1> declare `def d`; + allocate `HashMap` instance -> `HashMap reference`; + implicit cast `HashMap reference` to `def` -> `def`; + store `def` to `d` +<2> load from `d` -> `def`; + implicit cast `def` to `HashMap reference` -> `HashMap reference`; + call `put` on `HashMap reference` with arguments(`String 'value2'`, `int 2`) +<3> load from `d` -> `def`; + implicit cast `def` to `HashMap reference` -> `HashMap reference`; + call `put` on `HashMap reference` with arguments(`String 'value5'`, `int 5`) +<4> declare `int x`; + load from `d` -> `def`; + implicit cast `def` to `HashMap reference` -> `HashMap reference`; + call `get` on `HashMap reference` with arguments(`String 'value2'`) + -> `def`; + implicit cast `def` to `int 2` -> `int 2`; + load from `d` -> `def`; + call `get` on `HashMap reference` with arguments(`String 'value5'`) + -> `def`; + implicit cast `def` to `int 5` -> `int 5`; + add `int 2` and `int 5` -> `int 7`; + store `int 7` to `x` +<5> declare `String y`; + store `String 'value5'` to `y` +<6> declare `def z`; + load from `d` -> `def`; + load from `y` -> `String 'value5'`; + call `get` on `HashMap reference` with arguments(`String 'value5'`) + -> `def`; + store `def` to `z` + +[[new-instance-operator]] +==== New Instance + +Use the `new instance operator 'new ()'` to allocate a +<> instance to the heap and call a specified +constructor. Implicit <> is evaluated as +necessary per argument during the constructor call. + +An overloaded constructor is one that shares the same name with two or more +constructors. A constructor is overloaded based on arity where the same +reference type name is re-used for multiple constructors as long as the number +of parameters differs. + +*Errors* + +* If the reference type name doesn't exist for instance allocation. +* If the number of arguments passed in is different from the number of specified + parameters. +* If the arguments cannot be implicitly cast or implicitly boxed/unboxed to the + correct type values for the parameters. + +*Grammar* + +[source,ANTLR4] +---- +new_instance: 'new' TYPE '(' (expression (',' expression)*)? ')'; +---- + +*Examples* + +* Allocation of new instances with different types. + +[source,Painless] +---- +<1> Map m = new HashMap(); +<2> def d = new ArrayList(); +<3> def e = new HashMap(m); +---- +<1> declare `Map m`; + allocate `HashMap` instance -> `HashMap reference`; + implicit cast `HashMap reference` to `Map reference` -> `Map reference`; + store `Map reference` to `m`; +<2> declare `def d`; + allocate `ArrayList` instance -> `ArrayList reference`; + implicit cast `ArrayList reference` to `def` -> `def`; + store `def` to `d`; +<3> declare `def e`; + load from `m` -> `Map reference`; + allocate `HashMap` instance with arguments (`Map reference`) + -> `HashMap reference`; + implicit cast `HashMap reference` to `def` -> `def`; + store `def` to `e`; + +[[string-concatenation-operator]] +==== String Concatenation + +Use the `string concatenation operator '+'` to concatenate two values together +where at least one of the values is a <>. + +*Grammar* + +[source,ANTLR4] +---- +concatenate: expression '+' expression; +---- + +*Examples* + +* String concatenation with different primitive types. ++ +[source,Painless] +---- +<1> String x = "con"; +<2> String y = x + "cat"; +<3> String z = 4 + 5 + x; +---- ++ +<1> declare `String x`; + store `String "con"` to `x`; +<2> declare `String y`; + load from `x` -> `String "con"`; + concat `String "con"` and `String "cat"` -> `String "concat"`; + store `String "concat"` to `y` +<3> declare `String z`; + add `int 4` and `int 5` -> `int 9`; + concat `int 9` and `String "9concat"`; + store `String "9concat"` to `z`; + (note the addition is done prior to the concatenation due to precedence and + associativity of the specific operations) ++ +* String concatenation with the `def` type. ++ +[source,Painless] +---- +<1> def d = 2; +<2> d = "con" + d + "cat"; +---- ++ +<1> declare `def`; + implicit cast `int 2` to `def` -> `def`; + store `def` in `d`; +<2> concat `String "con"` and `int 9` -> `String "con9"`; + concat `String "con9"` and `String "con"` -> `String "con9cat"` + implicit cast `String "con9cat"` to `def` -> `def`; + store `def` to `d`; + (note the switch in type of `d` from `int` to `String`) + +[[elvis-operator]] +==== Elvis + +An elvis consists of two expressions. The first expression is evaluated +with to check for a `null` value. If the first expression evaluates to +`null` then the second expression is evaluated and its value used. If the first +expression evaluates to `non-null` then the resultant value of the first +expression is used. Use the `elvis operator '?:'` as a shortcut for the +conditional operator. + +*Errors* + +* If the first expression or second expression cannot produce a `null` value. + +*Grammar* + +[source,ANTLR4] +---- +elvis: expression '?:' expression; +---- + +*Examples* + +* Elvis with different reference types. ++ +[source,Painless] +---- +<1> List x = new ArrayList(); +<2> List y = x ?: new ArrayList(); +<3> y = null; +<4> List z = y ?: new ArrayList(); +---- ++ +<1> declare `List x`; + allocate `ArrayList` instance -> `ArrayList reference`; + implicit cast `ArrayList reference` to `List reference` -> `List reference`; + store `List reference` to `x`; +<2> declare `List y`; + load `x` -> `List reference`; + `List reference` equals `null` -> `false`; + evaluate 1st expression: `List reference` -> `List reference`; + store `List reference` to `y` +<3> store `null` to `y`; +<4> declare `List z`; + load `y` -> `List reference`; + `List reference` equals `null` -> `true`; + evaluate 2nd expression: + allocate `ArrayList` instance -> `ArrayList reference`; + implicit cast `ArrayList reference` to `List reference` -> `List reference`; + store `List reference` to `z`; diff --git a/docs/painless/painless-operators.asciidoc b/docs/painless/painless-operators.asciidoc index 8329686f663..b51e94088a6 100644 --- a/docs/painless/painless-operators.asciidoc +++ b/docs/painless/painless-operators.asciidoc @@ -1,1819 +1,64 @@ [[painless-operators]] === Operators -The following is a table of the available operators in Painless. Each operator will have further information and examples outside of the table. Many operators will have a promotion table as described by the documentation on promotion [MARK]. - -[options="header",cols="6,3,2,4"] -|==== -|Operator|Symbol(s)|Precedence|Associativity -|Precedence|()|0|left-to-right -|Field Access|.|1|left-to-right -|Method Call|. ()|1|left-to-right -|Null Safe|?.|1|left-to-right -|Function Call|()|1|left-to-right -|Array Initialization|[] {}|1|left-to-right -|Array Access|[]|1|left-to-right -|Array Length|.|1|left-to-right -|List Initialization|[]|1|left-to-right -|List Access|[]|1|left-to-right -|Map Initialization|[:]|1|left-to-right -|Map Access|[]|1|left-to-right -|Post Increment|++|1|left-to-right -|Post Decrement|--|1|left-to-right -|Pre Increment|++|2|right-to-left -|Pre Decrement|--|2|right-to-left -|Unary Positive|+|2|right-to-left -|Unary Negative|-|2|right-to-left -|Boolean Not|!|2|right-to-left -|Bitwise Not|~|2|right-to-left -|Cast|()|3|right-to-left -|Constructor Call|new ()|3|right-to-left -|New Array|new|3|right-to-left -|Multiplication|*|4|left-to-right -|Division|/|4|left-to-right -|Remainder|%|4|left-to-right -|String Concatenation|+|5|left-to-right -|Addition|+|5|left-to-right -|Subtraction|-|5|left-to-right -|Left Shift|<<|6|left-to-right -|Right Shift|>>|6|left-to-right -|Unsigned Right Shift|>>>|6|left-to-right -|Greater Than|>|7|left-to-right -|Greater Than Or Equal|>=|7|left-to-right -|Less Than|<|7|left-to-right -|Less Than Or Equal|<=|7|left-to-right -|Instance Of|instanceof|8|left-to-right -|Equality Equals|==|9|left-to-right -|Equality Not Equals|!=|9|left-to-right -|Identity Equals|===|9|left-to-right -|Identity Not Equals|!==|9|left-to-right -|Bitwise And|&|10|left-to-right -|Boolean Xor|^|11|left-to-right -|Bitwise Xor|^|11|left-to-right -|Bitwise Or|\||12|left-to-right -|Boolean And|&&|13|left-to-right -|Boolean Or|\|\||14|left-to-right -|Conditional|? :|15|right-to-left -|Elvis|?:|16|right-to-left -|Assignment|=|17|right-to-left -|Compound Assignment|$=|17|right-to-left +An operator is the most basic action that can be taken to evaluate values in a +script. An expression is one-to-many consecutive operations. Precedence is the +order in which an operator will be evaluated relative to another operator. +Associativity is the direction within an expression in which a specific operator +is evaluated. The following table lists all available operators: + +[cols="<6,<3,^3,^2,^4"] +|==== +| *Operator* | *Category* | *Symbol(s)* | *Precedence* | *Associativity* +| <> | <> | () | 0 | left -> right +| <> | <> | . () | 1 | left -> right +| <> | <> | . | 1 | left -> right +| <> | <> | ?. | 1 | left -> right +| <> | <> | () | 1 | left -> right +| <> | <> | [] {} | 1 | left -> right +| <> | <> | [] | 1 | left -> right +| <> | <> | . | 1 | left -> right +| <> | <> | [] | 1 | left -> right +| <> | <> | [] | 1 | left -> right +| <> | <> | [:] | 1 | left -> right +| <> | <> | [] | 1 | left -> right +| <> | <> | ++ | 1 | left -> right +| <> | <> | -- | 1 | left -> right +| <> | <> | ++ | 2 | right -> left +| <> | <> | -- | 2 | right -> left +| <> | <> | + | 2 | right -> left +| <> | <> | - | 2 | right -> left +| <> | <> | ! | 2 | right -> left +| <> | <> | ~ | 2 | right -> left +| <> | <> | () | 3 | right -> left +| <> | <> | new () | 3 | right -> left +| <> | <> | new [] | 3 | right -> left +| <> | <> | * | 4 | left -> right +| <> | <> | / | 4 | left -> right +| <> | <> | % | 4 | left -> right +| <> | <> | + | 5 | left -> right +| <> | <> | + | 5 | left -> right +| <> | <> | - | 5 | left -> right +| <> | <> | << | 6 | left -> right +| <> | <> | >> | 6 | left -> right +| <> | <> | >>> | 6 | left -> right +| <> | <> | > | 7 | left -> right +| <> | <> | >= | 7 | left -> right +| <> | <> | < | 7 | left -> right +| <> | <> | <= | 7 | left -> right +| <> | <> | instanceof | 8 | left -> right +| <> | <> | == | 9 | left -> right +| <> | <> | != | 9 | left -> right +| <> | <> | === | 9 | left -> right +| <> | <> | !== | 9 | left -> right +| <> | <> | & | 10 | left -> right +| <> | <> | ^ | 11 | left -> right +| <> | <> | ^ | 11 | left -> right +| <> | <> | \| | 12 | left -> right +| <> | <> | && | 13 | left -> right +| <> | <> | \|\| | 14 | left -> right +| <> | <> | ? : | 15 | right -> left +| <> | <> | ?: | 16 | right -> left +| <> | <> | = | 17 | right -> left +| <> | <> | $= | 17 | right -> left |==== - -[[precedence-operator]] -==== Precedence - -You group expressions using the precedence operator to guarantee -the order of evaluation and override existing precedence relationships between operators. The format is an opening parenthesis, one or more expressions, and -a closing parenthesis. For example, `(20+1)*2`. - -*Grammar:* -[source,ANTLR4] ----- -precedence: '(' expression ')'; ----- - -*Examples:* -[source,Java] ----- -int x = (5+4)*6; // declares the variable int x and sets it to (5+4)*6 - // where 5+4 is evaluated first due to the precedence operator -int y = 2*(x-4); // declares the variable int y and sets it to 2*(x-4) - // where x-4 is evaluated first due to the precedence operator ----- - - -[[dot-operator]] -==== Dot -You use the dot operator `.` to access a type's <> and <>. - -[[field-access]] -===== Accessing Fields -You access primitive and reference type members in a reference type using the -dot operator '.' followed by the id of the member. The accessed member behaves -the same way as the type it represents with one exception: if the reference -type is of type `def`, the member is also considered to be of type `def` and -resolved at runtime. - -*Grammar:* -[source,ANTLR4] ----- -field_access: ID '.' ID; ----- - -*Examples:* -[source,Java] ----- -FeatureTest ft = new FeatureTest(); // Declare FeatureTest variable ft and - // set it to a newly allocated FeatureTest -ft.x = 5; // Access int member x from ft and assign - // it the literal int value 5 -ft.y = ft.x; // Access int member y from ft and assign - // it the value of ft member x -int value = ft.x + ft.y; // Declare variable value as an int, - // add ft members x and y together, - // assign the sum to the variable value ----- - -[[method-access]] -===== Calling Methods - -You call reference type methods using the dot operator and the method id: -`.method_id(arg1,...,argn)`. The parentheses are required even if there are no -arguments. - -If the reference type is not type `def`, the argument types for the method -can be resolved at compile time. An error occurs if appropriate type -conversions (casting) cannot be performed. If the reference type is type `def`, the argument types for the method are all considered to be the type `def`. The -appropriate type conversions are performed at run-time. - -Automatic <> is performed when you pass in -arguments to a method. - -Method calls can be overloaded based on arity in Painless. The same method -name can be re-used for different methods as long as the number of arguments -differs. This differs from Java method overloading, where only the types must -differ. This has an effect on some of the provided reference type methods in -the <>. Where there are overloaded methods with -the same arity for a reference type in Java, Painless chooses a single method -to be provided. - -*Grammar:* -[source,ANTLR4] ----- -method_call: ID '.' ID '(' (expression (',' expression)*)? ')'; ----- - -*Examples:* -[source,Java] ----- -Map m = new HashMap(); // Declare Map variable m and set it a newly - // allocated HashMap -x.put(1, 2); // Call the put method on variable x to add key 1 - // with the value 2 to the Map -int z = x.get(1); // Declare int variable z, call the get method to - // retrieve the value of key 1, and assign the - // return value of the method call to variable z -def d = new ArrayList(); // Declare def variable m and set it a newly - // allocated ArrayList -d.add(1); // Call the add method on variable d and add the - // literal int 1 to the ArrayList. Note that - // the argument type is considered to be of - // type def since the reference type is also def -int i = Integer.parseInt('2'); // Declare int variable i and set it to the - // value returned by the static method parseInt ----- - -************************** -Painless describes the Map method arguments using the `def` type: - -[source,Java] ----- -put(def, def) -get(def) ----- - -When you call `x.put(1, 2)`, the key and value are implicitly converted from -the int type to the def type. - -Assume for a minute that the Map method arguments were described as Integers: - -[source,Java] ----- -put(Integer, Integer) -get(Integer) ----- - -In this case, the key and value would implicitly be _boxed_ from the primitive -int type to the Integer reference type. For more information about how Painless -casts between primitive types and reference types, see <>. -************************** - -==== Null Safe - -The null safe operator `?.` can be used in place of the dot operator -to check if a reference type instance is `null` before attempting to access -a field or make a method call against it. When using the null safe operator, -if the instance is `null`, the returned value is `null`. If the reference -type instance is non-null, it returns the value of the field or result of -the method call normally. - -// REVIEWER NOTE: The following paragraph doesn't make sense to me. Do you -All resultant types must be a reference type or be able to be implicitly cast -to a reference type or an error will occur. - -*Grammar:* -[source,ANTLR4] ----- -null_safe: null_safe_field_access - | null_safe_method_call; -null_safe_field_access: ID '?.' ID; -null_safe_method_call: ID '?.' ID '(' (expression (',' expression)*)? ')'; ----- - -*Examples:* -[source,Java] ----- -Map x = new HashMap(); // Declare the Map variable x and set it to a newly - // allocated HashMap -Map y = null; // Declare the Map variable y and set it to null -def z = new HashMap(); // Declares the def variable z and set it to a newly - // allocated HashMap - -x.put(1, 2); // Put the key-value pair 1 and 2 into x -z.put(5, 6); // Put the key-value pair 5 and 6 into z - -def value = x?.get(1); // Declare the def variable value and set it to the - // result of .get(1) since x is not null -value = y?.get(3); // Sets value to null since y is null -value = z?.get(5); // Sets value to the result of .get(5) since z is not null ----- - -==== Parenthesis - -User-defined function calls can be made in Painless using the parenthesis -operator. See Function Calls [MARK] for more information. - -==== Brackets and Braces - -The brackets operator `[]` is used to create and access arrays, lists, and maps. -The braces operator `{}` is used to intialize arrays. - -[[array-initialization]] -===== Creating and Initializing Arrays - -You create and initialize arrays using the brackets `[]` and braces `{}` -operators. Each set of brackets represents a dimension. The values you want to -initialize each dimension with are specified as a comma-separated list enclosed -in braces. For example, `new int[] {1, 2, 3}` creates a one dimensional `int` -array with a size of 3 and the values 1, 2, and 3. - -To allocate an array, you use the `new` keyword followed by the type and a -set of brackets for each dimension. You can explicitly define the size of each dimension by specifying an expression within the brackets, or initialize each -dimension with the desired number of values. The allocated size of each -dimension is its permanent size. - -To initialize an array, specify the values you want to initialize -each dimension with as a comma-separated list of expressions enclosed in braces. -For example, `new int[] {1, 2, 3}` creates a one-dimensional `int` array with a -size of 3 and the values 1, 2, and 3. - -When you initialize an array, the order of the expressions is maintained. Each expression used as part of the initialization is converted to the -array's type. An error occurs if the types do not match. - -*Grammar:* -[source,ANTLR4] ----- -declare_array: TYPE ('[' ']')+; - -array_initialization: 'new' TYPE '[' ']' '{' expression (',' expression) '}' - | 'new' TYPE '[' ']' '{' '}'; ----- - -*Examples:* -[source,Java] ----- -int[] x = new int[5]; // Declare int array x and assign it a newly - // allocated int array with a size of 5 -def[][] y = new def[5][5]; // Declare the 2-dimensional def array y and - // assign it a newly allocated 2-dimensional - // array where both dimensions have a size of 5 -int[] x = new int[] {1, 2, 3}; // Declare int array x and set it to an int - // array with values 1, 2, 3 and a size of 3 -int i = 1; -long l = 2L; -float f = 3.0F; -double d = 4.0; -String s = "5"; -def[] da = new def[] {i, l, f*d, s}; // Declare def array da and set it to - // a def array with a size of 4 and the - // values i, l, f*d, and s ----- - -[[array-access]] -===== Accessing Array Elements - -Elements in an array are stored and accessed using the brackets `[]` operator. -Elements are referenced by an expression enclosed in brackets. An error -occurs if the expression used to reference an element cannot be implicitly -cast to an `int`. - -The range of elements within an array that can be accessed is `[0, size)` where -size is the originally allocated size of the array. To access elements relative -to the last element in an array, you can use a negative numeric value from -`[-size, -1]`. An error occurs if you attempt to reference an element outside -of the array's range. - -*Grammar:* -[source,ANTLR4] ----- -brace_access: '[' expression ']' ----- - -*Examples:* -[source,Java] ----- - -int[] x = new int[2]; // Declare int array x and set it to a newly allocated - // array with a size of 2 -x[0] = 2; // Set the 0th element of array x to 2 -x[1] = 5; // Set the 1st element of array x to 5 -int y = x[0] + x[1]; // Declare the int variable y and set it to the sum - // of the first two elements of array x -int z = 1; // Declare the int variable z and set it to 1 -return x[z]; // Access the 1st element of array x using the - // variable z as an expression and return the value - -def d = new int[2]; // Declare def variable d and set it to a newly - // allocated array with a size of 2 -d[0] = 2; // Set the 0th element of array d to 2 -d[1] = 5; // Set the 1st element of array d to 2 -def y = d[0] + d[1]; // Declare def variable y and set it to the sum - // of the first two elements of array d -def z = 1; // Declare def variable z and set it to 1 -return d[z]; // Access the 1st element of array d using the - // variable z as an expression and return the value ----- - -NOTE: The use of the `def` type in the second example means that the types -cannot be resolved until runtime. - -[[array-length]] -===== Array Length - -Arrays contain a special member known as 'length' that is a read-only value that contains the size of the array. This member can be accessed from an array using the dot operator. - -*Examples:* -[source,Java] ----- -int[] x = new int[10]; // declares an int array variable x and sets it to a newly allocated array with a size of 10 -int l = x.length; // declares and int variable l and sets it to the field length of variable x ----- - -===== Creating and Initializing Lists - -You create and initialize lists using the brackets `[]` operator. The values -you want to initialize the list with are specified as a comma-separated list -of expressions enclosed in brackets. For example, `List l = [1, 2, 3]` creates -a new three item list. Each expression used to initialize the list is converted -a `def` type when the value is inserted into the list. The order of the -expressions is maintained. - -*Grammar:* -[source,ANTLR4] ----- -list_initialization: '[' expression (',' expression)* ']' - | '[' ']'; ----- - -*Examples:* -[source,Java] ----- -List empty = []; // declares the List variable empty and sets it to a newly initialized empty List -List l0 = [1, 2, 3]; // declares the List variable l0 and sets it to a newly initialized List with the values 1, 2, and 3 - -int i = 1; -long l = 2L; -float f = 3.0F; -double d = 4.0; -String s = "5"; -List l1 = [i, l, f*d, s]; // declares the List variable l1 and sets it to a newly initialized List with the values of i, l, and f*d and s ----- - -===== Accessing List Elements - -Elements in a List are stored or accessed using the brackets operator. The format begins with an opening bracket, followed by an expression, and finishes with a closing bracket. Storing elements in a List is equivalent to invoking a List's set method. Accessing elements in a List is equivalent to invoking a List's get method. Using this operator is strictly a shortcut for the previously mentioned methods. The range of elements within a List that can be accessed is [0, size) where size is the number of elements currently in the List. Elements may also be accessed from the last element in a List using a negative numeric value from [-size, -1]. The expression used to determine which element is accessed must be able to be implicitly cast to an int. An error will occur if the expression is outside of the legal range or is not of type int. - -*Grammar:* -[source,ANTLR4] ----- -list_access: '[' expression ']' ----- - -*Examples:* -[source,Java] ----- -List x = new ArrayList(); // declares a List variable x and sets it to a newly allocated ArrayList -x.add(1); // invokes the add method on the variable x and adds the constant int 1 to the List -x.add(2); // invokes the add method on the variable x and adds the constant int 2 to the List -x.add(3); // invokes the add method on the variable x and adds the constant int 3 to the List -x[0] = 2; // sets the 0th element of the variable x to the constant int 2 -x[1] = 5; // sets the 1st element of the variable x to the constant int 2 -int y = x[0] + x[1]; // declares the int variable y and sets it to the sum of the first two elements of the variable x -int z = 1; // declares the int variable z and sets it to the constant int 1 -return x[z]; // accesses the 1st element of the variable x using the variable z as an expression and returns the value - -def d = new ArrayList(); // declares a def variable d and sets it to a newly allocated ArrayList -d.add(1); // invokes the add method on the variable d and adds the constant int 1 to the List -d.add(2); // invokes the add method on the variable d and adds the constant int 2 to the List -d.add(3); // invokes the add method on the variable d and adds the constant int 3 to the List -d[0] = 2; // sets the 0th element of the variable d to the constant int 2 -d[1] = 5; // sets the 1st element of the variable d to the constant int 2 -def y = d[0] + d[1]; // declares the def variable y and sets it to the sum of the first two elements of the variable d -def z = 1; // declares the def variable z and sets it to the constant int 1 -return d[z]; // accesses the 1st element of the variable d using the variable z as an expression and returns the value ----- - -Note in the first example above all types can be resolved at compile-time, while in the second example all types must wait to be resolved until run-time. - -===== Creating and Initializing Maps - -A Map can be created and initialized using the brackets operator. The format begins with a bracket, followed by an arbitrary number of key-value pairs delimited with commas (except the last), and ends with a closing bracket. Each key-value pair is a set of two expressions separate by a colon. If there is only a single colon with no expressions, a new empty Map is created. - -*Grammar:* -[source,ANTLR4] ----- -map_initialization: '[' key_pair (',' key_pair)* ']' - | '[' ':' ']'; -key_pair: expression ':' expression ----- - -Each expression used as part of the initialization is converted to a `def` type -for insertion into the map. - -*Examples:* -[source,Java] ----- -Map empty = [:]; // declares the Map variable empty and sets it to a newly initialized empty Map -Map m0 = [1:2, 3:4, 5:6]; // declares the Map variable m0 and sets it to a newly initialized Map with the keys 1, 3, 5 and values 2, 4, 6, respectively - -byte b = 0; -int i = 1; -long l = 2L; -float f = 3.0F; -double d = 4.0; -String s = "5"; -Map m1 = [b:i, l:f*d, d:s]; // declares the Map variable m1 and sets it to a newly initialized Map with the keys b, l, d and values i, f*d, s, respectively ----- - -===== Accessing Map Elements - -Elements in a Map can be stored or accessed using the brackets operator. The format begins with an opening bracket, followed by an expression, and finishes with a closing bracket. Storing values in a Map is equivalent to invoking a Map's put method. Accessing values in a Map is equivalent to invoking a Map's get method. Using this operator is strictly a shortcut for the previously mentioned methods. Any element from a Map can be stored/accessed where the expression is the key. If a key has no corresponding value when accessing a Map then the value will be null. - -*Grammar:* -[source,ANTLR4] ----- -map_access: '[' expression ']' ----- - -*Examples:* -[source,Java] ----- -Map x = new HashMap(); // declares a Map variable x and sets it to a newly allocated HashMap -x['value2'] = 2; // puts the value of the key constant String value2 of the variable x to the constant int 2 -x['value5'] = 5; // puts the value of the key constant String value5 of the variable x to the constant int 5 -int y = x['value2'] + x['value5']; // declares the int variable y and sets it to the sum of the two values of the variable x -String z = 'value5'; // declares the String variable z and sets it to the constant String value5 -return x[z]; // accesses the value for the key value5 of the variable x using the variable z as an expression and returns the value - -def d = new HashMap(); // declares a def variable d and sets it to a newly allocated HashMap -d['value2'] = 2; // puts the value of the key constant String value2 of the variable d to the constant int 2 -d['value5'] = 5; // puts the value of the key constant String value5 of the variable d to the constant int 5 -int y = d['value2'] + d['value5']; // declares the int variable y and sets it to the sum of the two values of the variable d -String z = 'value5'; // declares the String variable z and sets it to the constant String value5 -return d[z]; // accesses the value for the key value5 of the variable x using the variable z as an expression and returns the value ----- - -Note in the first example above all types can be resolved at compile-time, while in the second example all types must wait to be resolved until run-time. - -==== Post Increment - -A variable/field representing a numerical value can be possibly evaluated as part of an expression, and then increased by 1 for its respective type. The format starts with a variable name followed by a plus and ends with a plus. - -*Grammar:* -[source,ANTLR4] ----- -post_increment: ( variable | member ) '++' ----- - -A numeric promotion may occur during a post-increment followed by a downcast if necessary. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. A downcast may be required after the type promotion to assign the appropriate value back into the variable/field. Non-numeric variables/members will result in an error. - -Promotion Table: - -|==== -|from|to|downcast -|byte|int|byte -|short|int|short -|char|int|char -|int|int| -|long|long| -|float|float| -|double|double| -|def|def| -|==== - -Examples(s): -[source,Java] ----- -int i = 0; // declares the int variable i and sets it to the constant 0 -i++; // increments the int variable i by 1 to a value of 1 -long l = 1; // declares the long variable l and set it the constant 1 -long k; // declares the long variable k -k = l++; // sets the long variable k to the value of l (1), and then increments the long variable l by 1 to a value of 2 ----- - -==== Post Decrement - -A variable/field representing a numerical value can be possibly evaluated as part of an expression, and then increased by 1 for its respective type. The format starts with a variable name followed by a minus and ends with a minus. - -*Grammar:* -[source,ANTLR4] ----- -post_increment: ( variable | member ) '--' ----- - -A numeric promotion may occur during a post-decrement followed by a downcast if necessary. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. A downcast may be required after the type promotion to assign the appropriate value back into the variable/field. Non-numeric variables/members will result in an error. - -Promotion Table: - -|==== -|from|to|downcast -|byte|int|byte -|short|int|short -|char|int|char -|int|int| -|long|long| -|float|float| -|double|double| -|def|def| -|==== - -Examples(s): -[source,Java] ----- -short i = 0; // declares the short variable i and sets it to the constant short 0 -i--; // decrements the short variable i by 1 to a value of -1 (promoted to int and downcast to short) -float l = 1.0f; // declares the float variable l and sets it the constant float 1.0f -float k; // declares the float variable k -k = l--; // sets the float variable k to the value of l (1.0f), and then decrements the float variable l by 1.0 to a value of 0.0 ----- - -==== Pre Increment - -A variable/field representing a numerical value can be increased by 1 for its respective type, and then possibly evaluated as part of an expression. The format starts with a plus followed by a plus and ends with a variable name. - -*Grammar:* -[source,ANTLR4] ----- -pre_increment: '++' ( variable | member ) ----- - -A numeric promotion may occur during a pre-increment followed by a downcast if necessary. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. A downcast may be required after the type promotion to assign the appropriate value back into the variable/field. Non-numeric variables/members will result in an error. - -Promotion Table: - -|==== -|from|to|downcast -|byte|int|byte -|short|int|short -|char|int|char -|int|int| -|long|long| -|float|float| -|double|double| -|def|def| -|==== - -Examples(s): -[source,Java] ----- -int i = 0; // declares the int variable i and sets it to the constant int 0 -++i; // increments the int variable i by 1 to a value of 1 -long l = 1; // declares the long variable l and sets it to the constant long 1 -long k; // declares the long variable k -k = ++l; // increments the long variable l by 1 to a value of 2, and then sets the long variable k to the value of l (2) ----- - -==== Pre Decrement - -A variable/field representing a numerical value can be decreased by 1 for its respective type, and then possibly evaluated as part of an expression. The format starts with a minus followed by a minus and ends with a variable name. - -*Grammar:* -[source,ANTLR4] ----- -pre_decrement: '--' ( variable | member ) ----- - -A numeric promotion may occur during a pre-decrement followed by a downcast if necessary. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. A downcast may be required after the type promotion to assign the appropriate value back into the variable/field. Non-numeric variables/members will result in an error. - -Promotion Table: -|==== -|from|to|downcast -|byte|int|byte -|short|int|short -|char|int|char -|int|int| -|long|long| -|float|float| -|double|double| -|def|def| -|==== - -Examples(s): -[source,Java] ----- -byte i = 1; // declares the byte variable i and sets it to the constant int 1 ---i; // decrements the byte variable i by 1 to a value of 0 (promoted to int and downcast to byte) -double l = 1.0; // declares the double variable l and sets it to the constant double 1.0 -double k; // declares the double variable k -k = --l; // decrements the double variable l by 1.0 to a value of 0.0, and then sets the double variable k to the value of l (0.0) ----- - -==== Unary Positive - -Unary positive gives the identity of a numerical value using the plus operator. In practice this is usually a no-op, but will cause some numeric types to be promoted. Format starts with a plus operator followed by a numerical expression. - -*Grammar:* -[source,ANTLR4] ----- -unary_positive: '+' expression ----- - -A numeric promotion may occur during a unary positive operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric expressions will result in an error. - -Promotion Table: -|==== -|from|to -|byte|int -|short|int -|char|int -|int|int -|long|long -|float|float -|double|double -|def|def -|==== - -*Examples:* -[source,Java] ----- -int x = +1; // declares the int variable x and sets it to positive 1 -long y = +x; // declares the long variable y and sets it to positive x (promoted to long from int) -def z = +y; // declares the def variable z and sets it to positive y -byte z = +2; //ERROR: cannot implicitly downcast an int to a byte ----- - -==== Unary Negative - -Unary negative negates a numeric value using the minus operator. Format starts with a minus followed by a numerical expression. - -*Grammar:* -[source,ANTLR4] ----- -unary_negative: '-' expression ----- - -A numeric promotion may occur during a unary negative operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric expressions will result in an error. - -Promotion Table: -|==== -|from|to -|byte|int -|short|int -|char|int -|int|int -|long|long -|float|float -|double|double -|def|def -|==== - -*Examples:* -[source,Java] ----- -int x = -1; // declares the int variable x and sets it to negative 1 -long y = -x; // declares the long variable y and sets it to negative x (promoted to long from int) -def z = -y; // declares the def variable z and sets it to negative y -byte z = -2; //ERROR: cannot implicitly downcast an int to a byte ----- - -==== Boolean Not - -Boolean not will flip a boolean value from true to false or false to true using the bang operator. The format is a bang operator followed by an expression. - -*Grammar:* -[source,ANTLR4] ----- -boolean_not: '!' expression; ----- - -Note that def types will be assumed to be of the boolean type. Any def type evaluated at run-time that does not represent a boolean will result in an error. Non-boolean expressions will result in an error. - -*Examples:* -[source,Java] ----- -boolean x = !false; // declares the boolean variable x and sets it to the opposite of the false value -boolean y = !x; // declares the boolean variable y and sets it to the opposite of the boolean variable x -def z = !y; // declares the def variable z and sets it to the opposite of the boolean variable y ----- - -==== Bitwise Not - -Bitwise not will flip each bit of an integer type expression. The format is the tilde operator followed by an expression. - -*Grammar:* -[source,ANTLR4] ----- -bitwise_not: '~' expression; ----- - -A numeric promotion may occur during unary positive operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-integer expressions will result in an error. - -Promotion Table: -|==== -|from|to -|byte|int -|short|int -|char|int -|int|int -|long|long -|def|def -|==== - -*Examples:* -[source,Java] ----- -byte x = 1; // declares the byte variable x and sets it to a constant int 1 -int y = ~x; // declares the int variable y and sets it to the negation of x -long z = ~y; // declares the long variable z and sets it the negation of y -def d = ~z; // declares the def variable d and sets it the negation of z -def e; // declares the def variable e -e = ~d; // sets e the negation of d ----- - -==== Cast - -The cast operator can be used to explicitly convert one type to another. See casting [MARK] for more information. - -[[constructor-call]] -==== Constructor Call - -A constructor call is a special type of method call [MARK] used to allocate a reference type instance using the new operator. The format is the new operator followed by a type, an opening parenthesis, arguments if any, and a closing parenthesis. Arguments are a series of zero-to-many expressions delimited by commas. Auto-boxing and auto-unboxing will be applied automatically for arguments passed into a constructor call. See boxing and unboxing [MARK] for more information on this topic. Constructor argument types can always be resolved at run-time; if appropriate type conversions (casting) cannot be applied an error will occur. Once a reference type instance has been allocated, its members may be used as part of other expressions. - -Constructor calls may be overloaded based on arity in Painless. This means the same reference type may have multiple constructors as long as the number of arguments differs for each one. This does have an effect on some of the provided reference type constructors in the Painless API [MARK]. When there are overloaded constructors with the same arity for a reference type in Java a single constructor must be chosen to be provided in Painless. - -*Grammar:* -[source,ANTLR4] ----- -constructor_call: 'new' TYPE '(' (expression (',' expression)*)? ')'; ----- - -*Examples:* -[source,Java] ----- -Map m = new HashMap(); // declares the Map variable m and sets it to a newly allocated HashMap using an empty constructor -m.put(3, 3); // invokes the method call member put and adds the key-value pair of 3 to Map variable m -def d = new ArrayList(); // declares the def variable d and sets it to a newly allocated ArrayList using an empty constructor -def e; // declares the def variable e -e = new HashMap(m); // sets e to a newly allocated HashMap using the constructor with a single argument m ----- - -[[new-array]] -==== New Array - -An array type instance can be allocated using the new operator. The format starts with the new operator followed by the type followed by a series of opening and closing braces each containing an expression for the size of the dimension. - -*Grammar:* -[source,ANTLR4] ----- -new_array: 'new' TYPE ('[' expression ']')+; ----- - -*Examples:* -[source,Java] ----- -int[] x = new int[5]; // declares an int array variable x and sets it to a newly allocated array with a size of 5 -x = new int[10]; // sets the int array variable x to a newly allocated array with a size of 10 -def[][] y = new def[5][5]; // declares a 2-dimensional def array variable y and set it to a newly - // allocated 2-dimensional array where both dimensions have a size of 5 ----- - -==== Multiplication - -Multiplies two numerical expressions. Rules for resultant overflow and NaN values follow the Java specification. The format is an expression, followed by the star operator, and a closing expression. - -*Grammar:* -[source,ANTLR4] ----- -multiplication: expression '*' expression; ----- - -A numeric promotion may occur during a multiplication operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric numbers will result in an error. - -Promotion Table: -|==== -||byte|short|char|int|long|float|double|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 -|def|def|def|def|def|def|def|def|def -|==== - -*Examples:* -[source,Java] ----- -int x = 5*4; // declares the int variable x and sets it to the result of 5 multiplied by 4 -double y = x*7.0; // declares the double variable y and sets it to the result of x multiplied by 7.0 (x is promoted to a double) -def z = x*y; // declares the def variable z and sets it to the result of x multiplied by y (x is promoted to a double) -def a = z*x; // declares the def variable a and sets it to the result of z multiplied by x (x is promoted to def at compile-time and double at run-time) ----- - -==== Division - -Divides two numerical expressions. Rules for NaN values and division by zero follow the Java specification. Integer division will drop the remainder of the resultant value. The format is an expression, followed by the slash operator, and a closing expression. - -*Grammar:* -[source,ANTLR4] ----- -division: expression '/' expression; ----- - -A numeric promotion may occur during a division operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric expressions will result in an error. - -Promotion Table: -|==== -||byte|short|char|int|long|float|double|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 -|def|def|def|def|def|def|def|def|def -|==== - -*Examples:* -[source,Java] ----- -int x = 5/4; // declares the int variable x and sets it to the result of 5 divided by 4 -double y = x/7.0; // declares the double variable y and sets it to the result of x divided by 7.0 (x is promoted to a double) -def z = x/y; // declares the def variable z and sets it to the result of x divided by y (x is promoted to a double) -def a = z/x; // declares the def variable a and sets it to the result of z divided by x (x is promoted to def at compile-time and double at run-time) ----- - -==== Remainder - -Calculates the remainder for division between two numerical expressions. Rules for NaN values and division by zero follow the Java specification. The format is an expression, followed by the percent operator, and a closing expression. - -*Grammar:* -[source,ANTLR4] ----- -remainder: expression '%' expression; ----- - -A numeric promotion may occur during a remainder operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric expressions will result in an error. - -Promotion Table: -|==== -||byte|short|char|int|long|float|double|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 -|def|def|def|def|def|def|def|def|def -|==== - -*Examples:* -[source,Java] ----- -int x = 5%4; // declares the int variable x and sets it to the remainder of 5 divided by 4 -double y = x%7.0; // declares the double variable y and sets it to the remainder of x divided by 7.0 (x is promoted to a double) -def z = x%y; // declares the def variable z and sets it to the remainder of x divided by y (x is promoted to a double) -def a = z%x; // declares the def variable a and sets it to the remainder of z divided by x (x is promoted to def at compile-time and double at run-time) ----- - -==== String Concatenation - -Concatenates two expressions together as a single String where at least of one of the expressions is a String to begin with. The format is an expression, followed by a plus operator, and a closing expression. - -*Grammar:* -[source,ANTLR4] ----- -concatenate: expression '+' expression; ----- - -*Examples:* -[source,Java] ----- -String x = "con"; // declares the String variable x and sets it to the String constant "con" -String y = x + "cat"; // declares the String variable y and sets it to the concatenation of the String variable x and the String constant "cat" -String z = 4 + x; // declares the String variable z and sets it to the concatenation of the int constant 4 and the String variable x (4 is implicitly cast to a String) -def d = 2; // declares the def variable d and sets it to the int constant 2 -z = z + d; // sets the String variable z to the concatenation of the String variable z -d = "con" + x + y + "cat"; // sets the def variable d to the concatenation of String constant "con", x, y, and the String constant "cat" ----- - -==== Addition - -Adds two numerical expressions. Rules for resultant overflow and NaN values follow the Java specification. The format is an expression, followed by the plus operator, and a closing expression. - -*Grammar:* -[source,ANTLR4] ----- -addition: expression '+' expression; ----- - -A numeric promotion may occur during a addition operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric expressions will result in an error, except in the case of String which then implies the operation is string concatenation [MARK] rather than addition. - -Promotion Table: -|==== -||byte|short|char|int|long|float|double|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 -|def|def|def|def|def|def|def|def|def -|==== - -*Examples:* -[source,Java] ----- -int x = 5 + 4; // declares the int variable x and sets it to the result of 5 added to 4 -double y = x + 7.0; // declares the double variable y and sets it to the result of x added to 7.0 (x is promoted to a double) -def z = x + y; // declares the def variable z and sets it to the result of x added to y (x is promoted to a double) -def a = z + x; // declares the def variable a and sets it to the result of z added to x (x is promoted to def at compile-time and double at run-time) ----- - -==== Subtraction - -Subtracts two numerical expressions. Rules for resultant overflow and NaN values follow the Java specification. The format is an expression, followed by the minus operator, and a closing expression. - -*Grammar:* -[source,ANTLR4] ----- -subtraction: expression '-' expression; ----- - -A numeric promotion may occur during a subtraction operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric expressions will result in an error. - -Promotion Table: -|==== -||byte|short|char|int|long|float|double|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 -|def|def|def|def|def|def|def|def|def -|==== - -*Examples:* -[source,Java] ----- -int x = 5-4; // declares the int variable x and sets it to the result of 4 subtracted from 5 -double y = x-7.0; // declares the double variable y and sets it to the result of 7.0 subtracted from x (x is promoted to a double) -def z = x-y; // declares the def variable z and sets it to the result of y subtracted from x (x is promoted to a double) -def a = z-x; // declares the def variable a and sets it to the result of x subtracted from z (x is promoted to def at compile-time and double at run-time) ----- - -==== Left Shift - -Shifts lower order bits to higher order bits in the left-side expression by the distance specified in the right-side expression. The format is an expression followed by two left-carrots, and a closing expression. - -*Grammar:* -[source,ANTLR4] ----- -left_shift: expression '<<' expression; ----- - -A numeric promotion may occur during a left shift operation to the left-side expression. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric and floating point expressions will result in an error. - -Promotion Table: -|==== -|from|to -|byte|int -|short|int -|char|int -|int|int -|long|long -|def|def -|==== - -The right-side expression will be explicitly cast to an int value and truncated based on the promoted type of the left-side expression. If the left-side expression is of type int then the lowest order 5-bits will be taken as the distance to shift from the right-side expression (0-31). If the left-side expression is of type long then the lowest order 6-bits will be taken as the distance to shift from the right-side expression (0-63). Non-numeric and floating point expressions will result in an error. - -*Examples:* -[source,Java] ----- -int x = 5 << 4; // declares the int variable x and sets it to the result of 5 left shifted by 4 -long y = x << 7; // declares the long variable y and sets it to the result of x left shifted by 7 (x is promoted to a long) -def z = x << y; // declares the def variable z and sets it to the result of x left shifted by y -def a = z << x; // declares the def variable a and sets it to the result of z left shifted by x ----- - -==== Right Shift - -Shifts higher order bits to lower order bits in the left-side expression by the distance specified in the right-side expression. Right shift will preserve the signed bit (highest order bit) as part of the result. The format is an expression followed by two right-carrots, and a closing expression. - -*Grammar:* -[source,ANTLR4] ----- -right_shift: expression '>>' expression; ----- - -A numeric promotion may occur during a right shift operation to the left-side expression. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric and floating point expressions will result in an error. - -Promotion Table: -|==== -|from|to -|byte|int -|short|int -|char|int -|int|int -|long|long -|def|def -|==== - -The right-side expression will be explicitly cast to an int value and truncated based on the promoted type of the left-side expression. If the left-side expression is of type int then the lowest order 5-bits will be taken as the distance to shift from the right-side expression (0-31). If the left-side expression is of type long then the lowest order 6-bits will be taken as the distance to shift from the right-side expression (0-63). Non-numeric and floating point expressions will result in an error. - -*Examples:* -[source,Java] ----- -int x = 5 >> 4; // declares the int variable x and sets it to the result of 5 right shifted by 4 -long y = x >> 7; // declares the long variable y and sets it to the result of x right shifted by 7 (x is promoted to a long) -def z = x >> y; // declares the def variable z and sets it to the result of x right shifted by y -def a = z >> x; // declares the def variable a and sets it to the result of z right shifted by x ----- - -==== Unsigned Right Shift - -Shifts higher order bits to lower order bits in the left-side expression by the distance specified in the right-side expression. Unsigned right shift will not preserve the signed bit (highest order bit) as part of the result. The format is an expression followed by three right-carrots, and a closing expression. - -*Grammar:* -[source,ANTLR4] ----- -unsigned_right_shift: expression '>>>' expression; ----- - -A numeric promotion may occur during an unsigned right shift operation to the left-side expression. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric and floating point expressions will result in an error. - -Promotion Table: -|==== -|from|to -|byte|int -|short|int -|char|int -|int|int -|long|long -|def|def -|==== - -The right-side expression will be explicitly cast to an int value and truncated based on the promoted type of the left-side expression. If the left-side expression is of type int then the lowest order 5-bits will be taken as the distance to shift from the right-side expression (0-31). If the left-side expression is of type long then the lowest order 6-bits will be taken as the distance to shift from the right-side expression (0-63). Non-numeric and floating point expressions will result in an error. - -*Examples:* -[source,Java] ----- -int x = 5 >> 4; // declares the int variable x and sets it to the result of 5 unsigned right shifted by 4 -long y = x >> 7; // declares the long variable y and sets it to the result of x unsigned right shifted by 7 (x is promoted to a long) -def z = x >> y; // declares the def variable z and sets it to the result of x unsigned right shifted by y -def a = z >> x; // declares the def variable a and sets it to the result of z unsigned right shifted by x ----- - -==== Greater Than - -Greater than compares two numerical expressions where a resultant boolean value will be true if the left-side expression is a larger value than the right-side expression otherwise false. The format is an expression, followed by the right angle operator, and a closing expression. - -*Grammar:* -[source,ANTLR4] ----- -greater_than: expression '>' expression; ----- - -A numeric promotion may occur during a greater than operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric expressions will result in an error. - -Promotion Table: -|==== -||byte|short|char|int|long|float|double|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 -|def|def|def|def|def|def|def|def|def -|==== - -*Examples:* -[source,Java] ----- -boolean x = 5 > 4; // declares the int variable x and sets it to the result of 5 greater than 4 -double y = 7.0; // declares the double variable y and sets it to the double constant 7.0 -def z = y > 6.5; // declares the def variable z and sets it to the result of y greater than 6.5 -def a = y > x; // declares the def variable a and sets it to the result of y greater than z (x is promoted to double at compile-time) ----- - -==== Greater Than Or Equal - -Greater than or equal compares two numerical expressions where a resultant boolean value will be true if the left-side expression is a larger value than or equal to the right-side expression otherwise false. The format is an expression, followed by the right angle and equals operator, and a closing expression. - -*Grammar:* -[source,ANTLR4] ----- -greater_than_or_equal: expression '>=' expression; ----- - -A numeric promotion may occur during a greater than or equal operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric expressions will result in an error. - -Promotion Table: -|==== -||byte|short|char|int|long|float|double|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 -|def|def|def|def|def|def|def|def|def -|==== - -*Examples:* -[source,Java] ----- -boolean x = 5 >= 4; // declares the int variable x and sets it to the result of 5 greater than or equal to 4 -double y = 7.0; // declares the double variable y and sets it to the double constant 7.0 -def z = y >= 6.5; // declares the def variable z and sets it to the result of y greater than or equal to 6.5 -def a = y >= x; // declares the def variable a and sets it to the result of y greater than or equal to z (x is promoted to double at compile-time) ----- - -==== Less Than - -Less than compares two numerical expressions where a resultant boolean value will be true if the left-side expression is a smaller value than the right-side expression otherwise false. The format is an expression, followed by the left angle operator, and a closing expression. - -*Grammar:* -[source,ANTLR4] ----- -less_than: expression '<' expression; ----- - -A numeric promotion may occur during a less than operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric expressions will result in an error. - -Promotion Table: -|==== -||byte|short|char|int|long|float|double|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 -|def|def|def|def|def|def|def|def|def -|==== - -*Examples:* -[source,Java] ----- -boolean x = 5 < 4; // declares the int variable x and sets it to the result of 5 less than 4 -double y = 7.0; // declares the double variable y and sets it to the double constant 7.0 -def z = y < 6.5; // declares the def variable z and sets it to the result of y less than 6.5 -def a = y < x; // declares the def variable a and sets it to the result of y less than z (x is promoted to double at compile-time) ----- - -==== Less Than Or Equal - -Less than or equal compares two numerical expressions where a resultant boolean value will be true if the left-side expression is a larger value than or equal to the right-side expression otherwise false. The format is an expression, followed by the left angle and equals operator, and a closing expression. - -*Grammar:* -[source,ANTLR4] ----- -less_than_or_equal: expression '<=' expression; ----- - -A numeric promotion may occur during a less than or equal operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric expressions will result in an error. - -Promotion Table: -|==== -||byte|short|char|int|long|float|double|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 -|def|def|def|def|def|def|def|def|def -|==== - -*Examples:* -[source,Java] ----- -boolean x = 5 <= 4; // declares the int variable x and sets it to the result of 5 less than or equal to 4 -double y = 7.0; // declares the double variable y and sets it to the double constant 7.0 -def z = y <= 6.5; // declares the def variable z and sets it to the result of y less than or equal to 6.5 -def a = y <= x; // declares the def variable a and sets it to the result of y less than or equal to z (x is promoted to double at compile-time) ----- - -==== Instance Of - -The instanceof operator can be used to compare a variable's type to a specified reference type where a resultant boolean value is true if the variable type is the same as or a descendant of the specified reference type and false otherwise. The format is an id, followed by the instanceof operator, and finished with a type. - -*Grammar:* -[source,ANTLR4] ----- -instance_of: ID 'instanceof' TYPE; ----- - -*Examples:* -[source,Java] ----- -Map x = new HashMap(); // declares the Map variable x and sets it to a newly allocated HashMap -List y = new ArrayList(); // declares the List variable y and sets it to a newly allocated ArrayList -def z = y; // declares the def variable z and sets it to y -boolean a = x instanceof HashMap; // declares the boolean variable a and sets it to true since x's type is the same type as HashMap -boolean b = y instanceof Map; // declares the boolean variable b and sets it to false since y's type is not the same type as Map or a descendant of Map -boolean c = z instanceof List; // declares the boolean variable c and sets it to true since z's type is a descendant of the type List ----- - -==== Equality Equals - -Equality equals compares two expressions where a resultant boolean value is true if the two expressions are equal and false otherwise. When reference types are compared using this operator the equivalent of the equals member method will be called against the first expression, where the second expression is the argument. Though the equals member method is used for reference types, this operation will always be null-safe. Valid comparisons are between boolean types, primitive numeric types, and reference types. If a comparison is made that is not listed as one of the valid comparisons an error will occur. The format is an expression, followed by the equals-equals operator, and finished with an expression. - -*Grammar:* -[source,ANTLR4] ----- -equality_equals: expression '==' expression; ----- - -A numeric type promotion may occur during a primitive numeric comparison. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. - -Promotion Table: -|==== -||byte|short|char|int|long|float|double|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 -|def|def|def|def|def|def|def|def|def -|==== - -*Examples:* -[source,Java] ----- -boolean b0 = true; // declares the boolean variable b0 and sets it the constant boolean true -boolean b1 = false; // declares the boolean variable b1 and sets it the constant boolean false -int i = 2; // declares the int variable i and sets it the constant int 2 -float f = 2.0f; // declares the float variable f and sets it the constant float 2.0 -List l0 = new ArrayList(); // declares the List variable l0 and sets it to a newly allocated ArrayList -ArrayList l1 = new ArrayList(); // declares the ArrayList variable l1 and sets it to a newly allocated ArrayList -def di0 = 2; // declares the def variable di0 and sets it the constant int 2 -def di1 = 3; // declares the def variable di1 and sets it the constant int 3 -def dl = new ArrayList(); // declares the def variable dl and sets it to a newly allocated ArrayList -boolean result; // declares the boolean variable result - -result = b0 == b1; // compares b0 to b1 and has a boolean result of false -result = i == f; // compares i to f where i is promoted to float and has a boolean result of true -result = b0 == i; // ERROR: a comparison between a boolean and a primitive numeric type is illegal -result = i == l0; // ERROR: a comparison between a primitive numeric type and a reference type is illegal - -l0.add(1); // adds a constant int 1 to the List l0 -l1.add(1); // adds a constant int 1 to the ArrayList l1 -result = l0 == l1; // compares l0 to l1 using l0.equals(l1) and has a boolean result of true -l0.add(1); // adds a constant int 1 to the List l0 -result = l0 == l1; // compares l0 to l1 using l0.equals(l1) and has a boolean result of false - -result = di0 == di1; // compares di0 to di1 and has a boolean result of false -result = di0 == i; // compares di0 to i where i is promoted to def and has a boolean result of true - -dl.add(1); // adds a constant int 1 to the def ArrayList dl -result = dl == l0; // compares dl to l0 using dl.equals(l0) with a boolean result of true - -result = null == dl; // compares null to dl with a boolean result of false -result = l1 == null; // compares l1 to null with a boolean result of false ----- - -==== Equality Not Equals - -Equality not equals compares two expressions where a resultant boolean value is true if the two expressions are not equal and false otherwise. When reference types are compared using this operator the equivalent of the equals member method will be called against the first expression, where the second expression is the argument, with the resultant boolean being reversed. Though the equals member method is used for reference types, this operation will always be null-safe. Valid comparisons are between boolean types, primitive numeric types, and reference types. If a comparison is made that is not listed as one of the valid comparisons an error will occur. The format is an expression, followed by the bang-equals operator, and finished with an expression. - -*Grammar:* -[source,ANTLR4] ----- -equality_not_equals: expression '!=' expression; ----- - -A numeric type promotion may occur during a primitive numeric comparison. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. - -Promotion Table: -|==== -||byte|short|char|int|long|float|double|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 -|def|def|def|def|def|def|def|def|def -|==== - -*Examples:* -[source,Java] ----- -boolean b0 = true; // declares the boolean variable b0 and sets it the constant boolean true -boolean b1 = false; // declares the boolean variable b1 and sets it the constant boolean false -int i = 2; // declares the int variable i and sets it the constant int 2 -float f = 2.0f; // declares the float variable f and sets it the constant float 2.0 -List l0 = new ArrayList(); // declares the List variable l0 and sets it to a newly allocated ArrayList -ArrayList l1 = new ArrayList(); // declares the ArrayList variable l1 and sets it to a newly allocated ArrayList -def di0 = 2; // declares the def variable di0 and sets it the constant int 2 -def di1 = 3; // declares the def variable di1 and sets it the constant int 3 -def dl = new ArrayList(); // declares the def variable dl and sets it to a newly allocated ArrayList -boolean result; // declares the boolean variable result - -result = b0 != b1; // compares b0 to b1 and has a boolean result of true -result = i != f; // compares i to f where i is promoted to float and has a boolean result of false -result = b0 != i; // ERROR: a comparison between a boolean and a primitive numeric type is illegal -result = i != l0; // ERROR: a comparison between a primitive numeric type and a reference type is illegal - -l0.add(1); // adds a constant int 1 to the List l0 -l1.add(1); // adds a constant int 1 to the ArrayList l1 -result = l0 != l1; // compares l0 to l1 using l0.equals(l1) and has a boolean result of false -l0.add(1); // adds a constant int 1 to the List l0 -result = l0 != l1; // compares l0 to l1 using l0.equals(l1) and has a boolean result of true - -result = di0 != di1; // compares di0 to di1 and has a boolean result of true -result = di0 != i; // compares di0 to i where i is promoted to def and has a boolean result of false - -dl.add(1); // adds a constant int 1 to the def ArrayList dl -result = dl != l0; // compares dl to l0 using dl.equals(l0) with a boolean result of false - -result = null != dl; // compares null to dl with a boolean result of true -result = l1 != null; // compares null to l1 with a boolean result of true ----- - -==== Identity Equals - -Identity equals compares two expressions where a resultant boolean value is true if the two expressions are equal and false otherwise. Two primitive types are considered to be equal if they have the same value. Two reference types are considered to be equal if they refer to the exact same instance in memory or are both null. Valid comparisons are between boolean types, primitive numeric types, and reference types. If a comparison is made that is not listed as one of the valid comparisons an error will occur. The format is an expression, followed by the equals-equals-equals operator, and finished with an expression. - -*Grammar:* -[source,ANTLR4] ----- -identity_equals: expression '===' expression; ----- - -A numeric type promotion may occur during a primitive numeric comparison. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. - -Promotion Table: -|==== -||byte|short|char|int|long|float|double|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 -|def|def|def|def|def|def|def|def|def -|==== - -*Examples:* -[source,Java] ----- -boolean b0 = true; // declares the boolean variable b0 and sets it the constant boolean true -boolean b1 = false; // declares the boolean variable b1 and sets it the constant boolean false -int i = 2; // declares the int variable i and sets it the constant int 2 -float f = 2.0f; // declares the float variable f and sets it the constant float 2.0 -List l0 = new ArrayList(); // declares the List variable l0 and sets it to a newly allocated ArrayList -ArrayList l1 = new ArrayList(); // declares the ArrayList variable l1 and sets it to a newly allocated ArrayList -List l2 = l1; // declares the List variable l2 and sets it to l1 -def di0 = 2; // declares the def variable di0 and sets it the constant int 2 -def di1 = 3; // declares the def variable di1 and sets it the constant int 3 -def dl = l0; // declares the def variable dl and sets it to l0 -boolean result; // declares the boolean variable result - -result = b0 === b1; // compares b0 to b1 and has a boolean result of false -result = i === f; // compares i to f where i is promoted to float and has a boolean result of true -result = b0 === i; // ERROR: a comparison between a boolean and a primitive numeric type is illegal -result = i === l0; // ERROR: a comparison between a primitive numeric type and a reference type is illegal - -l0.add(1); // adds a constant int 1 to the List l0 -l1.add(1); // adds a constant int 1 to the ArrayList l1 -result = l0 === l1; // compares l0 to l1 and has a boolean result of false -l0.add(1); // adds a constant int 1 to the List l0 -result = l0 === l1; // compares l0 to l1 and has a boolean result of false -result = l1 === l2; // compares l1 to l2 and has a boolean result of true - -result = di0 === di1; // compares di0 to di1 and has a boolean result of false -result = di0 === i; // compares di0 to i where i is promoted to def and has a boolean result of true - -result = dl === l0; // compares dl to l0 with a boolean result of true - -result = null === dl; // compares null to dl with a boolean result of false -result = l1 === null; // compares null to l1 with a boolean result of false ----- - -==== Identity Not Equals - -Identity not equals compares two expressions where a resultant boolean value is true if the two expressions are not equal and false otherwise. Two primitive types are considered to be not equal if they have different values. Two reference types are considered to be not equal if they refer to the different instances in memory or one is null and the other is not. Valid comparisons are between boolean types, primitive numeric types, and reference types. If a comparison is made that is not listed as one of the valid comparisons an error will occur. The format is an expression, followed by the bang-equals-equals operator, and finished with an expression. - -*Grammar:* -[source,ANTLR4] ----- -identity_not_equals: expression '!==' expression; ----- - -A numeric type promotion may occur during a primitive numeric comparison. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. - -Promotion Table: -|==== -||byte|short|char|int|long|float|double|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 -|def|def|def|def|def|def|def|def|def -|==== - -*Examples:* -[source,Java] ----- -boolean b0 = true; // declares the boolean variable b0 and sets it the constant boolean true -boolean b1 = false; // declares the boolean variable b1 and sets it the constant boolean false -int i = 2; // declares the int variable i and sets it the constant int 2 -float f = 2.0f; // declares the float variable f and sets it the constant float 2.0 -List l0 = new ArrayList(); // declares the List variable l0 and sets it to a newly allocated ArrayList -ArrayList l1 = new ArrayList(); // declares the ArrayList variable l1 and sets it to a newly allocated ArrayList -List l2 = l1; // declares the List variable l2 and sets it to l1 -def di0 = 2; // declares the def variable di0 and sets it the constant int 2 -def di1 = 3; // declares the def variable di1 and sets it the constant int 3 -def dl = l0; // declares the def variable dl and sets it to l0 -boolean result; // declares the boolean variable result - -result = b0 !== b1; // compares b0 to b1 and has a boolean result of true -result = i !== f; // compares i to f where i is promoted to float and has a boolean result of false -result = b0 !== i; // ERROR: a comparison between a boolean and a primitive numeric type is illegal -result = i !== l0; // ERROR: a comparison between a primitive numeric type and a reference type is illegal - -l0.add(1); // adds a constant int 1 to the List l0 -l1.add(1); // adds a constant int 1 to the ArrayList l1 -result = l0 !== l1; // compares l0 to l1 and has a boolean result of true -l0.add(1); // adds a constant int 1 to the List l0 -result = l0 !== l1; // compares l0 to l1 and has a boolean result of true -result = l1 !== l2; // compares l1 to l2 and has a boolean result of false - -result = di0 !== di1; // compares di0 to di1 and has a boolean result of true -result = di0 !== i; // compares di0 to i where i is promoted to def and has a boolean result of false - -result = dl !== l0; // compares dl to l0 with a boolean result of false - -result = null !== dl; // compares null to dl with a boolean result of true -result = l1 !== null; // compares null to l1 with a boolean result of true ----- - -==== Bitwise And - -Bitwise and will and together two integer type expressions. The table below shows what each resultant bit will in the resultant integer type value be based on the corresponding bit in each integer type expression. - -|==== -||1|0 -|1|1|0 -|0|0|0 -|==== - -The format starts with an expression, follows with the ampersand operator, and finishes with an expression. - -*Grammar:* -[source,ANTLR4] ----- -bitwise_and: expression '&' expression; ----- - -A numeric promotion may occur during a bitwise and operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-integer expressions will result in an error. - -Promotion Table: -|==== -||byte|short|char|int|long|def -|byte|int|int|int|int|long|def -|short|int|int|int|int|long|def -|char|int|int|int|int|long|def -|int|int|int|int|int|long|def -|long|long|long|long|long|long|def -|def|def|def|def|def|def|def|def|def -|==== - -*Examples:* -[source,Java] ----- -byte x = 16; // declares the byte variable x and sets it to a constant int 1 -int y = x & 4; // declares the int variable y and sets it to the result of x and 4 -long z = y & x; // declares the long variable z and sets it the result of y and x -def d = z & 2; // declares the def variable d and sets it the result of z and 2 -def e; // declares the def variable e -e = d & z; // sets e to the result of d and z ----- - -==== Boolean Xor - -Boolean xor will xor together two boolean expressions. The table below shows what the resultant boolean value will be based on the two boolean expressions. - -|==== -||true|false -|true|false|true -|false|true|false -|==== - -The format starts with an expression, follows with the carrot operator, and finishes with an expression. - -*Grammar:* -[source,ANTLR4] ----- -boolean_xor: expression '^' expression; ----- - -Note that def types will be assumed to be of the boolean type. Any def type evaluated at run-time that does not represent a boolean will result in an error. Non-boolean expressions will result in an error. - -*Examples:* -[source,Java] ----- -boolean x = false; // declares the boolean variable x and sets the constant boolean false -boolean y = x ^ true; // declares the boolean variable y and sets it the result of x xor true -def z = y ^ x; // declares the def variable z and sets it to the result of y xor x ----- - -==== Bitwise Xor - -Bitwise xor will xor together two integer type expressions. The table below shows what each resultant bit will in the resultant integer type value be based on the corresponding bit in each integer type expression. - -|==== -||1|0 -|1|0|1 -|0|1|0 -|==== - -The format starts with an expression, follows with the carrot operator, and finishes with an expression. - -*Grammar:* -[source,ANTLR4] ----- -bitwise_xor: expression '^' expression; ----- - -A numeric promotion may occur during a bitwise xor operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-integer expressions will result in an error. - -Promotion Table: -|==== -||byte|short|char|int|long|def -|byte|int|int|int|int|long|def -|short|int|int|int|int|long|def -|char|int|int|int|int|long|def -|int|int|int|int|int|long|def -|long|long|long|long|long|long|def -|def|def|def|def|def|def|def|def|def -|==== - -*Examples:* -[source,Java] ----- -byte x = 16; // declares the byte variable x and sets it to a constant int 1 -int y = x ^ 4; // declares the int variable y and sets it to the result of x xor 4 -long z = y ^ x; // declares the long variable z and sets it the result of y xor x -def d = z ^ 2; // declares the def variable d and sets it the result of z xor 2 -def e; // declares the def variable e -e = d ^ z; // sets e to the result of d xor z ----- - -==== Bitwise Or - -Bitwise or will or together two integer type expressions. The table below shows what each resultant bit will in the resultant integer type value be based on the corresponding bit in each integer type expression. - -|==== -||1|0 -|1|1|1 -|0|1|0 -|==== - -The format starts with an expression, follows with the pipe operator, and finishes with an expression. - -*Grammar:* -[source,ANTLR4] ----- -bitwise_or: expression '|' expression; ----- - -A numeric promotion may occur during a bitwise xor operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-integer expressions will result in an error. - -Promotion Table: -|==== -||byte|short|char|int|long|def -|byte|int|int|int|int|long|def -|short|int|int|int|int|long|def -|char|int|int|int|int|long|def -|int|int|int|int|int|long|def -|long|long|long|long|long|long|def -|def|def|def|def|def|def|def|def|def -|==== - -*Examples:* -[source,Java] ----- -byte x = 16; // declares the byte variable x and sets it to a constant int 1 -int y = x | 4; // declares the int variable y and sets it to the result of x or 4 -long z = y | x; // declares the long variable z and sets it the result of y or x -def d = z | 2; // declares the def variable d and sets it the result of z or 2 -def e; // declares the def variable e -e = d | z; // sets e to the result of d or z ----- - -==== Boolean And - -Boolean and will and together two boolean expressions. If the first expression is found to be false then it is known that the result will also be false, so evaluation of the second expression will be skipped. The table below shows what the resultant boolean value will be based on the two boolean expressions. - -||true|false -|true|true|false -|false|false|false - -The format starts with an expression, follows with the ampersand-ampersand operator, and finishes with an expression. - -*Grammar:* -[source,ANTLR4] ----- -boolean_and: expression '&&' expression; ----- - -Note that def types will be assumed to be of the boolean type. Any def type evaluated at run-time that does not represent a boolean will result in an error. Non-boolean expressions will result in an error. - -*Examples:* -[source,Java] ----- -boolean x = false; // declares the boolean variable x and sets the constant boolean false -boolean y = x && true; // declares the boolean variable y and sets it the result of x and true -def z = y && x; // declares the def variable z and sets it to the result of y and x ----- - -==== Boolean Or - -Boolean or will or together two boolean expressions. If the first expression is found to be true then it is known that the result will also be true, so evaluation of the second expression will be skipped. The table below shows what the resultant boolean value will be based on the two boolean expressions. - -|==== -||true|false -|true|true|true -|false|true|false -|==== - -The format starts with an expression, follows with the pipe-pipe operator, and finishes with an expression. - -*Grammar:* -[source,ANTLR4] ----- -boolean_and: expression '||' expression; ----- - -Note that def types will be assumed to be of the boolean type. Any def type evaluated at run-time that does not represent a boolean will result in an error. Non-boolean expressions will result in an error. - -*Examples:* -[source,Java] ----- -boolean x = false; // declares the boolean variable x and sets the constant boolean false -boolean y = x || true; // declares the boolean variable y and sets it the result of x or true -def z = y || x; // declares the def variable z and sets it to the result of y or x ----- - -==== Conditional - -A conditional operation 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. This can be used as a shortcut many different operations without requiring a full if/else branch. Errors will occur if the first expression does not evaluate to a boolean type or if one of the second or third expression cannot be converted to a type appropriate for the expected result. The format is an expression followed by a question-mark operator, another expression, a colon operator, and finishes with a final expression. - -*Grammar:* -[source,ANTLR4] ----- -conditional: expression '?' expression ':' expression; ----- - -A numeric type promotion may occur during the evaluation of a conditional with the second and third expressions if the expected result is a numeric type. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. - -Promotion Table: -|==== -||byte|short|char|int|long|float|double|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 -|def|def|def|def|def|def|def|def|def -|==== - -*Examples:* -[source,Java] ----- -boolean b = true; // declares the boolean variable b and sets it the constant boolean true - -int x = b ? 1 : 2; // declares the int variable x and sets it to the int constant 1 - // since the first expression of the conditional evaluates to true - // so the second expression is evaluated for a result - -List y = x > 1 ? new ArrayList() : null; // declares the List variable y and sets it to null - // since the first expression of the conditional evaluates to false - // so the third expression is evaluated for a result - -def z = x < 2 ? true : false; // declares the def variable z and sets it to the boolean constant true - // since the first expression of the conditional evaluates to true - // so the second expression is evaluated for a result ----- - -==== Elvis - -The elvis operator consists of two expressions. If the first expression is a non-null value then the resultant value will be the evaluated first expression otherwise the resultant value will be the evaluated second expression. This is typically used as a shortcut for a null check in a conditional. An error will occur if the expected result is a primitive type. The format is an expression, followed by the question-mark-colon operator, and finishes with an expression. - -*Grammar:* -[source,ANTLR4] ----- -elvis: expression '?:' expression; ----- - -*Examples:* -[source,Java] ----- -List l = new ArrayList(); // declares the List variable l and sets it to a newly allocated ArrayList -List y = l ?: new ArrayList(); // declares the List variable y and sets it to l since l is not null -y = null; // sets y to null -def z = y ?: new HashMap(); // declares the def variable z and sets it to a newly allocated HashMap since y is null ----- - -==== Assignment - -Assignment can be used to assign a value to a variable. See Variable Assignment [MARK] for more information. - -==== Compound Assignment - -Compound assignment can be used as a shortcut for an assignment where a binary operation would occur between the variable/field as the left-side expression and a separate right-side expression. The variable/field and right-side expression must be of appropriate types for the specific operation or an error will occur. A downcast may be necessary for certain operations to be able to assign the result back into the variable/field and will happen implicitly. The format is a variable/field, followed by one of the compound assignment operators, finished with an expression. - -*Grammar:* -[source,ANTLR4] ----- -compund_assignment: ID (. ID)? '$=' expression; // $ is a placeholder for the operation symbol ----- - -A compound assignment is equivalent to the expression below where V is the variable/field and T is the type of variable/member. - -[source,Java] ----- -V = (T)(V op expression); ----- - -The table below shows all available operators for compound assignment. All operators follow any casting/promotion rules according to their regular definition. - -|==== -|Operator|Compound Symbol -|Multiplication|*= -|Division|/= -|Remainder|%= -|String Concatenation|+= -|Addition|+= -|Subtraction|-= -|Left Shift|<<= -|Right Shift|>>= -|Unsigned Right Shift|>>>= -|Bitwise And|&= -|Boolean And|&= -|Bitwise Xor|^= -|Boolean Xor|^= -|Bitwise Or|\|= -|Boolean Or|\|= -|==== - -*Examples:* -[source,Java] ----- -int i = 10; // declares the variable i and sets it to constant int 10 -i *= 2; // multiplies i by 2 -- i = (int)(i * 2) -i /= 5; // divides i by 5 -- i = (int)(i / 5) -i %= 3; // gives the remainder for i/3 -- i = (int)(i % 3) -i += 5; // adds 5 to i -- i = (int)(i + 5) -i -= 5; // subtracts 5 from i -- i = (int)(i - 5) -i <<= 2; // left shifts i by 2 -- i = (int)(i << 2) -i >>= 1; // right shifts i by 1 -- i = (int)(i >> 1) -i >>>= 1; // unsigned right shifts i by 1 -- i = (int)(i >>> 1) -i &= 15; // ands i with 15 -- i = (int)(i & 15) -i ^= 12; // xors i with 12 -- i = (int)(i ^ 2) -i |= 4; // ors i with 4 -- i = (int)(i | 4) - -boolean b = true; // declares the boolean variable b and sets it to the constant boolean true -b &= false; // ands b with false -- b = (boolean)(b & false) -b ^= false; // xors b with false -- b = (boolean)(b & false) -b |= true; // ors be with true -- b = (boolean)(b & false) - -def x = 'compound'; // declares the def variable x and sets it to the constant String 'compound' -x += ' assignment'; // string concatenates ' assignment' to x -- x = (String)(x + ' assignment') ----- diff --git a/docs/painless/painless-regexes.asciidoc b/docs/painless/painless-regexes.asciidoc new file mode 100644 index 00000000000..b4434208ab0 --- /dev/null +++ b/docs/painless/painless-regexes.asciidoc @@ -0,0 +1,33 @@ +[[painless-regexes]] +=== Regexes + +Regular expression constants are directly supported. To ensure fast performance, +this is the only mechanism for creating patterns. Regular expressions +are always constants and compiled efficiently a single time. + +[source,painless] +--------------------------------------------------------- +Pattern p = /[aeiou]/ +--------------------------------------------------------- + +[[pattern-flags]] +==== Pattern flags + +You can define flags on patterns in Painless by adding characters after the +trailing `/` like `/foo/i` or `/foo \w #comment/iUx`. Painless exposes all of +the flags from Java's +https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html[ +Pattern class] using these characters: + +[cols="<,<,<",options="header",] +|======================================================================= +| Character | Java Constant | Example +|`c` | CANON_EQ | `'å' ==~ /å/c` (open in hex editor to see) +|`i` | CASE_INSENSITIVE | `'A' ==~ /a/i` +|`l` | LITERAL | `'[a]' ==~ /[a]/l` +|`m` | MULTILINE | `'a\nb\nc' =~ /^b$/m` +|`s` | DOTALL (aka single line) | `'a\nb\nc' =~ /.b./s` +|`U` | UNICODE_CHARACTER_CLASS | `'Ɛ' ==~ /\\w/U` +|`u` | UNICODE_CASE | `'Ɛ' ==~ /ɛ/iu` +|`x` | COMMENTS (aka extended) | `'a' ==~ /a #comment/x` +|======================================================================= \ No newline at end of file diff --git a/docs/painless/painless-scripts.asciidoc b/docs/painless/painless-scripts.asciidoc new file mode 100644 index 00000000000..87e5b601590 --- /dev/null +++ b/docs/painless/painless-scripts.asciidoc @@ -0,0 +1,6 @@ +[[painless-scripts]] +=== Scripts + +Scripts are composed of one-to-many <> and are +run in a sandbox that determines what local variables are immediately available +along with what APIs are whitelisted for use. \ No newline at end of file diff --git a/docs/painless/painless-statements.asciidoc b/docs/painless/painless-statements.asciidoc new file mode 100644 index 00000000000..3bc4513baa7 --- /dev/null +++ b/docs/painless/painless-statements.asciidoc @@ -0,0 +1,14 @@ +[[painless-statements]] +=== Statements + +Painless supports all of Java's https://docs.oracle.com/javase/tutorial/java/nutsandbolts/flow.html[ +control flow statements] except the `switch` statement. + +Painless also supports the `for in` syntax from Groovy: + +[source,painless] +--------------------------------------------------------- +for (item : list) { + ... +} +--------------------------------------------------------- \ No newline at end of file diff --git a/docs/painless/painless-types.asciidoc b/docs/painless/painless-types.asciidoc index a897b8e8a04..65ae9b3f703 100644 --- a/docs/painless/painless-types.asciidoc +++ b/docs/painless/painless-types.asciidoc @@ -12,16 +12,16 @@ belongs to one of the following categories: <>, A primitive type represents basic data built natively into the JVM and is allocated to non-heap memory. Declare a primitive type -<>, and assign it a primitive type value for -evaluation during later operations. The default value for a newly-declared -primitive type variable is listed as part of the definitions below. A primitive -type value is copied during an assignment or as an argument for a -method/function call. +<> or access a primitive type member field (from +a reference type instance), and assign it a primitive type value for evaluation +during later operations. The default value for a newly-declared primitive type +variable is listed as part of the definitions below. A primitive type value is +copied during an assignment or as an argument for a method/function call. A primitive type has a corresponding reference type (also known as a boxed -type). Use the <> or -<> on a primitive type value to force -evaluation as its corresponding reference type value. +type). Use the <> or +<> on a primitive type value to +force evaluation as its corresponding reference type value. The following primitive types are available: @@ -83,11 +83,11 @@ logical quantity with two possible values of `true` and `false` ---- + <1> declare `int i`; - assign `int 1` to `i` + store `int 1` to `i` <2> declare `double d`; - assign default `double 0.0` to `d` + store default `double 0.0` to `d` <3> declare `boolean b`; - assign `boolean true` to `b` + store `boolean true` to `b` + * Method call on a primitive type using the corresponding reference type. + @@ -98,8 +98,8 @@ logical quantity with two possible values of `true` and `false` ---- + <1> declare `int i`; - assign `int 1` to `i` -<2> access `i` -> `int 1`; + store `int 1` to `i` +<2> load from `i` -> `int 1`; box `int 1` -> `Integer 1 reference`; call `toString` on `Integer 1 reference` -> `String '1'` @@ -113,7 +113,7 @@ multiple pieces of data (member fields) and logic to manipulate that data A reference type instance is a single set of data for one reference type object allocated to the heap. Use the -<> to allocate a reference type +<> to allocate a reference type instance. Use a reference type instance to load from, store to, and manipulate complex data. @@ -122,10 +122,11 @@ reference type values may refer to the same reference type instance. A change to a reference type instance will affect all reference type values referring to that specific instance. -Declare a reference type <>, and assign it a -reference type value for evaluation during later operations. The default value -for a newly-declared reference type variable is `null`. A reference type value -is shallow-copied during an assignment or as an argument for a method/function +Declare a reference type <> or access a reference +type member field (from a reference type instance), and assign it a reference +type value for evaluation during later operations. The default value for a +newly-declared reference type variable is `null`. A reference type value is +shallow-copied during an assignment or as an argument for a method/function call. Assign `null` to a reference type variable to indicate the reference type value refers to no reference type instance. The JVM will garbage collect a reference type instance when it is no longer referred to by any reference type @@ -138,8 +139,8 @@ static member field:: A static member field is a named and typed piece of data. Each reference type *object* contains one set of data representative of its static member fields. -Use the <> in correspondence with the -reference type object name to access a static member field for loading and +Use the <> in correspondence with +the reference type object name to access a static member field for loading and storing to a specific reference type *object*. No reference type instance allocation is necessary to use a static member field. @@ -148,32 +149,34 @@ non-static member field:: A non-static member field is a named and typed piece of data. Each reference type *instance* contains one set of data representative of its reference type object's non-static member fields. Use the -<> for loading and storing to a non-static -member field of a specific reference type *instance*. An allocated reference -type instance is required to use a non-static member field. +<> for loading and storing to a +non-static member field of a specific reference type *instance*. An allocated +reference type instance is required to use a non-static member field. static member method:: -A static member method is a function called on a reference type *object*. Use -the <> in correspondence with the reference -type object name to call a static member method. No reference type instance -allocation is necessary to use a static member method. +A static member method is a <> called on a +reference type *object*. Use the <> +in correspondence with the reference type object name to call a static member +method. No reference type instance allocation is necessary to use a static +member method. non-static member method:: -A non-static member method is a function called on a reference type *instance*. -A non-static member method called on a reference type instance can load from and -store to non-static member fields of that specific reference type instance. Use -the <> in correspondence with a specific -reference type instance to call a non-static member method. An allocated -reference type instance is required to use a non-static member method. +A non-static member method is a <> called on a +reference type *instance*. A non-static member method called on a reference type +instance can load from and store to non-static member fields of that specific +reference type instance. Use the <> +in correspondence with a specific reference type instance to call a non-static +member method. An allocated reference type instance is required to use a +non-static member method. constructor:: -A constructor is a special type of function used to allocate a reference type -*instance* defined by a specific reference type *object*. Use the -<> to allocate a reference type -instance. +A constructor is a special type of <> used to +allocate a reference type *instance* defined by a specific reference type +*object*. Use the <> to allocate +a reference type instance. A reference type object follows a basic inheritance model. Consider types A and B. Type A is considered to be a parent of B, and B a child of A, if B inherits @@ -198,16 +201,16 @@ relationships. <1> declare `List l`; allocate `ArrayList` instance -> `ArrayList reference`; implicit cast `ArrayList reference` to `List reference` -> `List reference`; - assign `List reference` to `l` -<2> access `l` -> `List reference`; + store `List reference` to `l` +<2> load from `l` -> `List reference`; implicit cast `int 1` to `def` -> `def` call `add` on `List reference` with arguments (`def`) <3> declare `int i`; - access `l` -> `List reference`; + load from `l` -> `List reference`; call `get` on `List reference` with arguments (`int 0`) -> `def`; implicit cast `def` to `int 1` -> `int 1`; add `int 1` and `int 2` -> `int 3`; - assign `int 3` to `i` + store `int 3` to `i` + * Sharing a reference type instance. + @@ -223,26 +226,26 @@ relationships. <1> declare `List l0`; allocate `ArrayList` instance -> `ArrayList reference`; implicit cast `ArrayList reference` to `List reference` -> `List reference`; - assign `List reference` to `l0` + store `List reference` to `l0` <2> declare `List l1`; - access `l0` -> `List reference`; - assign `List reference` to `l1` + load from `l0` -> `List reference`; + store `List reference` to `l1` (note `l0` and `l1` refer to the same instance known as a shallow-copy) -<3> access `l0` -> `List reference`; +<3> load from `l0` -> `List reference`; implicit cast `int 1` to `def` -> `def` call `add` on `List reference` with arguments (`def`) -<4> access `l1` -> `List reference`; +<4> load from `l1` -> `List reference`; implicit cast `int 2` to `def` -> `def` call `add` on `List reference` with arguments (`def`) <5> declare `int i`; - access `l0` -> `List reference`; + load from `l0` -> `List reference`; call `get` on `List reference` with arguments (`int 0`) -> `def @0`; implicit cast `def @0` to `int 1` -> `int 1`; - access `l1` -> `List reference`; + load from `l1` -> `List reference`; call `get` on `List reference` with arguments (`int 1`) -> `def @1`; implicit cast `def @1` to `int 2` -> `int 2`; add `int 1` and `int 2` -> `int 3`; - assign `int 3` to `i`; + store `int 3` to `i`; + * Using the static members of a reference type. + @@ -253,11 +256,11 @@ relationships. ---- + <1> declare `int i`; - access `MAX_VALUE` on `Integer` -> `int 2147483647`; - assign `int 2147483647` to `i` + load from `MAX_VALUE` on `Integer` -> `int 2147483647`; + store `int 2147483647` to `i` <2> declare `long l`; call `parseLong` on `Long` with arguments (`long 123`) -> `long 123`; - assign `long 123` to `l` + store `long 123` to `l` [[dynamic-types]] ==== Dynamic Types @@ -268,11 +271,12 @@ the behavior of whatever value it represents at run-time and will always represent the child-most descendant type value of any type value when evaluated during operations. -Declare a `def` type <>, and assign it -any type of value for evaluation during later operations. The default value -for a newly-declared `def` type variable is `null`. A `def` type variable or -method/function parameter can change the type it represents during the -compilation and evaluation of a script. +Declare a `def` type <> or access a `def` type +member field (from a reference type instance), and assign it any type of value +for evaluation during later operations. The default value for a newly-declared +`def` type variable is `null`. A `def` type variable or method/function +parameter can change the type it represents during the compilation and +evaluation of a script. Using the `def` type can have a slight impact on performance. Use only primitive types and reference types directly when performance is critical. @@ -295,13 +299,13 @@ types and reference types directly when performance is critical. + <1> declare `def dp`; implicit cast `int 1` to `def` -> `def`; - assign `def` to `dp` + store `def` to `dp` <2> declare `def dr`; allocate `ArrayList` instance -> `ArrayList reference`; implicit cast `ArrayList reference` to `def` -> `def`; - assign `def` to `dr` -<3> access `dp` -> `def`; - assign `def` to `dr`; + store `def` to `dr` +<3> load from `dp` -> `def`; + store `def` to `dr`; (note the switch in the type `dr` represents from `ArrayList` to `int`) + * A `def` type value representing the child-most descendant of a value. @@ -317,12 +321,12 @@ types and reference types directly when performance is critical. allocate `ArrayList` instance -> `ArrayList reference`; implicit cast `ArrayList reference` to `Object reference` -> `Object reference`; - assign `Object reference` to `l` + store `Object reference` to `l` <2> declare `def d`; - access `l` -> `Object reference`; + load from `l` -> `Object reference`; implicit cast `Object reference` to `def` -> `def`; - assign `def` to `d`; -<3> access `d` -> `def`; + store `def` to `d`; +<3> load from `d` -> `def`; implicit cast `def` to `ArrayList reference` -> `ArrayList reference`; call `ensureCapacity` on `ArrayList reference` with arguments (`int 10`); (note `def` was implicit cast to `ArrayList reference` @@ -333,9 +337,9 @@ types and reference types directly when performance is critical. ==== String Type The `String` type is a specialized reference type that does not require -explicit allocation. Use a <> to directly evaluate a -`String` type value. While not required, the -<> can allocate `String` type +explicit allocation. Use a <> to directly +evaluate a `String` type value. While not required, the +<> can allocate `String` type instances. *Examples* @@ -351,15 +355,15 @@ instances. ---- + <1> declare `String r`; - assign `String "some text"` to `r` + store `String "some text"` to `r` <2> declare `String s`; - assign `String 'some text'` to `s` + store `String 'some text'` to `s` <3> declare `String t`; allocate `String` instance with arguments (`String "some text"`) -> `String "some text"`; - assign `String "some text"` to `t` + store `String "some text"` to `t` <4> declare `String u`; - assign default `null` to `u` + store default `null` to `u` [[void-type]] ==== void Type @@ -382,35 +386,38 @@ void addToList(List l, def d) { ==== Array Type An array type is a specialized reference type where an array type instance -represents a series of values allocated to the heap. All values in an array -type instance are of the same type. Each value is assigned an index from within -the range `[0, length)` where length is the total number of values allocated for -the array type instance. +contains a series of values allocated to the heap. Each value in an array type +instance is defined as an element. All elements in an array type instance are of +the same type (element type) specified as part of declaration. Each element is +assigned an index within the range `[0, length)` where length is the total +number of elements allocated for an array type instance. -Use the <> or the -<> to allocate an array -type instance. Declare an array type <>, and -assign it an array type value for evaluation during later operations. The -default value for a newly-declared array type variable is `null`. An array type -value is shallow-copied during an assignment or as an argument for a -method/function call. Assign `null` to an array type variable to indicate the -array type value refers to no array type instance. The JVM will garbage collect -an array type instance when it is no longer referred to by any array type -values. Pass `null` as an argument to a method/function call to indicate the -argument refers to no array type instance. +Use the <> or the +<> to allocate an +array type instance. Declare an array type <> or +access an array type member field (from a reference type instance), and assign +it an array type value for evaluation during later operations. The default value +for a newly-declared array type variable is `null`. An array type value is +shallow-copied during an assignment or as an argument for a method/function +call. Assign `null` to an array type variable to indicate the array type value +refers to no array type instance. The JVM will garbage collect an array type +instance when it is no longer referred to by any array type values. Pass `null` +as an argument to a method/function call to indicate the argument refers to no +array type instance. -Use the <> to retrieve the length of an -array type value as an int type value. Use the -<> to load from and store to individual -values within an array type value. +Use the <> to retrieve the length +of an array type value as an `int` type value. Use the +<> to load from and store to +an individual element within an array type instance. When an array type instance is allocated with multiple dimensions using the -range `[2, d]` where `d >= 2`, each dimension in the range `[1, d-1]` is also -an array type. The array type of each dimension, `n`, is an array type with the -number of dimensions equal to `d-n`. For example, consider `int[][][]` with 3 -dimensions. The 3rd dimension, `d-3`, is the primitive type `int`. The 2nd -dimension, `d-2`, is the array type `int[]`. And the 1st dimension, `d-1` is -the array type `int[][]`. +range `[2, d]` where `d >= 2`, each element within each dimension in the range +`[1, d-1]` is also an array type. The element type of each dimension, `n`, is an +array type with the number of dimensions equal to `d-n`. For example, consider +`int[][][]` with 3 dimensions. Each element in the 3rd dimension, `d-3`, is the +primitive type `int`. Each element in the 2nd dimension, `d-2`, is the array +type `int[]`. And each element in the 1st dimension, `d-1` is the array type +`int[][]`. *Examples* @@ -426,26 +433,26 @@ the array type `int[][]`. ---- + <1> declare `int[] x`; - assign default `null` to `x` + store default `null` to `x` <2> declare `float[] y`; allocate `1-d float array` instance with `length [10]` -> `1-d float array reference`; - assign `1-d float array reference` to `y` + store `1-d float array reference` to `y` <3> declare `def z`; allocate `1-d float array` instance with `length [5]` -> `1-d float array reference`; implicit cast `1-d float array reference` to `def` -> `def`; - assign `def` to `z` -<4> access `y` -> `1-d float array reference`; - assign `float 1.0` to `index [9]` of `1-d float array reference` -<5> access `y` -> `1-d float array reference @0`; - access `index [9]` of `1-d float array reference @0` -> `float 1.0`; - access `z` -> `def`; + store `def` to `z` +<4> load from `y` -> `1-d float array reference`; + store `float 1.0` to `index [9]` of `1-d float array reference` +<5> load from `y` -> `1-d float array reference @0`; + load from `index [9]` of `1-d float array reference @0` -> `float 1.0`; + load from `z` -> `def`; implicit cast `def` to `1-d float array reference @1` -> `1-d float array reference @1`; - assign `float 1.0` to `index [0]` of `1-d float array reference @1` + store `float 1.0` to `index [0]` of `1-d float array reference @1` + -* Use of a multi-dimensional array. +* General use of a multi-dimensional array. + [source,Painless] ---- @@ -457,10 +464,10 @@ the array type `int[][]`. <1> declare `int[][][] ia`; allocate `3-d int array` instance with length `[2, 3, 4]` -> `3-d int array reference`; - assign `3-d int array reference` to `ia3` -<2> access `ia3` -> `3-d int array reference`; - assign `int 99` to `index [1, 2, 3]` of `3-d int array reference` + store `3-d int array reference` to `ia3` +<2> load from `ia3` -> `3-d int array reference`; + store `int 99` to `index [1, 2, 3]` of `3-d int array reference` <3> declare `int i`; - access `ia3` -> `3-d int array reference`; - access `index [1, 2, 3]` of `3-d int array reference` -> `int 99`; - assign `int 99` to `i` + load from `ia3` -> `3-d int array reference`; + load from `index [1, 2, 3]` of `3-d int array reference` -> `int 99`; + store `int 99` to `i` diff --git a/docs/painless/painless-variables.asciidoc b/docs/painless/painless-variables.asciidoc index 8b8782b1511..8f83b9e2b57 100644 --- a/docs/painless/painless-variables.asciidoc +++ b/docs/painless/painless-variables.asciidoc @@ -4,7 +4,7 @@ A variable loads and stores a value for evaluation during <>. -[[declaration]] +[[variable-declaration]] ==== Declaration Declare a variable before use with the format of <> @@ -12,16 +12,17 @@ followed by <>. Declare an <> variable using an opening `[` token and a closing `]` token for each dimension directly after the identifier. Specify a comma-separated list of identifiers following the type to declare multiple -variables in a single statement. Use an <> -combined with a declaration to immediately assign a value to a variable. -A variable not immediately assigned a value will have a default value assigned -implicitly based on the type. +variables in a single statement. Use an +<> combined with a declaration to +immediately assign a value to a variable. A variable not immediately assigned a +value will have a default value assigned implicitly based on the type. *Errors* * If a variable is used prior to or without declaration. *Grammar* + [source,ANTLR4] ---- declaration : type ID assignment? (',' ID assignment?)*; @@ -45,37 +46,39 @@ assignment: '=' expression; ---- + <1> declare `int x`; - assign default `null` to `x` + store default `null` to `x` <2> declare `List y`; - assign default `null` to `y` + store default `null` to `y` <3> declare `int x`; - assign default `int 0` to `x`; + store default `int 0` to `x`; declare `int y`; - assign `int 5` to `y`; + store `int 5` to `y`; declare `int z`; - assign default `int 0` to `z`; + store default `int 0` to `z`; <4> declare `def d`; - assign default `null` to `d` + store default `null` to `d` <5> declare `int i`; - assign `int 10` to `i` + store `int 10` to `i` <6> declare `float[] f`; - assign default `null` to `f` + store default `null` to `f` <7> declare `Map[][] m`; - assign default `null` to `m` + store default `null` to `m` -[[assignment]] +[[variable-assignment]] ==== Assignment -Use the *assignment operator* to store a value in a variable. Any operation -that produces a value can be assigned to any variable as long as the -<> are the same or the resultant type can be -<> to the variable type. +Use the `assignment operator '='` to store a value in a variable for use in +subsequent operations. Any operation that produces a value can be assigned to +any variable as long as the <> are the same or the +resultant type can be <> to the variable +type. *Errors* * If the type of value is unable to match the type of variable. *Grammar* + [source,ANTLR4] ---- assignment: ID '=' expression @@ -92,8 +95,8 @@ assignment: ID '=' expression ---- + <1> declare `int i`; - assign default `int 0` to `i` -<2> assign `int 10` to `i` + store default `int 0` to `i` +<2> store `int 10` to `i` + * Declaration combined with immediate assignment. + @@ -104,11 +107,11 @@ assignment: ID '=' expression ---- + <1> declare `int i`; - assign `int 10` to `i` + store `int 10` to `i` <2> declare `double j`; - assign `double 2.0` to `j` + store `double 2.0` to `j` + -* Assignment of one variable to another using primitive types. +* Assignment of one variable to another using primitive type values. + [source,Painless] ---- @@ -117,12 +120,13 @@ assignment: ID '=' expression ---- + <1> declare `int i`; - assign `int 10` to `i` + store `int 10` to `i` <2> declare `int j`; - access `i` -> `int 10`; - assign `int 10` to `j` + load from `i` -> `int 10`; + store `int 10` to `j` + -* Assignment with reference types using the *new instance operator*. +* Assignment with reference types using the + <>. + [source,Painless] ---- @@ -132,13 +136,13 @@ assignment: ID '=' expression + <1> declare `ArrayList l`; allocate `ArrayList` instance -> `ArrayList reference`; - assign `ArrayList reference` to `l` + store `ArrayList reference` to `l` <2> declare `Map m`; allocate `HashMap` instance -> `HashMap reference`; implicit cast `HashMap reference` to `Map reference` -> `Map reference`; - assign `Map reference` to `m` + store `Map reference` to `m` + -* Assignment of one variable to another using reference types. +* Assignment of one variable to another using reference type values. + [source,Painless] ---- @@ -151,18 +155,19 @@ assignment: ID '=' expression <1> declare `List l`; allocate `ArrayList` instance -> `ArrayList reference`; implicit cast `ArrayList reference` to `List reference` -> `List reference`; - assign `List reference` to `l` + store `List reference` to `l` <2> declare `List k`; - access `l` -> `List reference`; - assign `List reference` to `k`; + load from `l` -> `List reference`; + store `List reference` to `k`; (note `l` and `k` refer to the same instance known as a shallow-copy) <3> declare `List m`; - assign default `null` to `m` -<4> access `k` -> `List reference`; - assign `List reference` to `m`; + store default `null` to `m` +<4> load from `k` -> `List reference`; + store `List reference` to `m`; (note `l`, `k`, and `m` refer to the same instance) + -* Assignment with an array type variable using the *new array operator*. +* Assignment with array type variables using the + <>. + [source,Painless] ---- @@ -176,24 +181,24 @@ assignment: ID '=' expression ---- + <1> declare `int[] ia1`; - assign default `null` to `ia1` + store default `null` to `ia1` <2> allocate `1-d int array` instance with `length [2]` -> `1-d int array reference`; - assign `1-d int array reference` to `ia1` -<3> access `ia1` -> `1-d int array reference`; - assign `int 1` to `index [0]` of `1-d int array reference` + store `1-d int array reference` to `ia1` +<3> load from `ia1` -> `1-d int array reference`; + store `int 1` to `index [0]` of `1-d int array reference` <4> declare `int[] ib1`; - access `ia1` -> `1-d int array reference`; - assign `1-d int array reference` to `ib1`; + load from `ia1` -> `1-d int array reference`; + store `1-d int array reference` to `ib1`; (note `ia1` and `ib1` refer to the same instance known as a shallow copy) <5> declare `int[][] ic2`; allocate `2-d int array` instance with `length [2, 5]` -> `2-d int array reference`; - assign `2-d int array reference` to `ic2` -<6> access `ic2` -> `2-d int array reference`; - assign `int 2` to `index [1, 3]` of `2-d int array reference` -<7> access `ia1` -> `1-d int array reference`; - access `ic2` -> `2-d int array reference`; - assign `1-d int array reference` to + store `2-d int array reference` to `ic2` +<6> load from `ic2` -> `2-d int array reference`; + store `int 2` to `index [1, 3]` of `2-d int array reference` +<7> load from `ia1` -> `1-d int array reference`; + load from `ic2` -> `2-d int array reference`; + store `1-d int array reference` to `index [0]` of `2-d int array reference`; (note `ia1`, `ib1`, and `index [0]` of `ia2` refer to the same instance)