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.
This commit is contained in:
parent
972dcbc0ad
commit
d6a4c14e1b
|
@ -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 <<painless-operators, operations>>. 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 <<allowed-casts, cast table>> 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 <<string-type, `String` type>> value into a
|
||||
Use the cast operator to convert a <<string-type, `String` type>> value into a
|
||||
<<primitive-types, `char` type>> value.
|
||||
|
||||
*Errors*
|
||||
|
@ -310,17 +314,17 @@ Use the *cast operator* to convert a <<string-type, `String` type>> 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 <<string-type, `String` type>> 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 <<reference-type-casting, reference type casting>> 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 <<reference-type-casting, reference type casting>> for allowed reference
|
||||
type casts.
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
<<painless-variables, variable>> 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 <<void-type, void>> then no value is returned. Any non-void type return
|
||||
value is available for use within an <<painless-operators, operation>> 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)) {
|
||||
...
|
||||
}
|
||||
---------------------------------------------------------
|
|
@ -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`
|
||||
|=======================================================================
|
|
@ -3,8 +3,12 @@
|
|||
|
||||
Use an identifier as a named token to specify a
|
||||
<<painless-variables, variable>>, <<painless-types, type>>,
|
||||
<<dot-operator, field>>, <<dot-operator, method>>, or function.
|
||||
<<painless-keywords, Keywords>> cannot be used as identifiers.
|
||||
<<field-access-operator, field>>, <<method-call-operator, method>>, or
|
||||
<<painless-functions, function>>.
|
||||
|
||||
*Errors*
|
||||
|
||||
If a <<painless-keywords, keyword>> is used as an identifier.
|
||||
|
||||
*Grammar*
|
||||
[source,ANTLR4]
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
[[painless-keywords]]
|
||||
=== Keywords
|
||||
|
||||
Keywords are reserved tokens for built-in language features and cannot be used
|
||||
as <<painless-identifiers, identifiers>> within a script. The following are
|
||||
keywords:
|
||||
Keywords are reserved tokens for built-in language features.
|
||||
|
||||
*Errors*
|
||||
|
||||
If a keyword is used as an <<painless-identifiers, identifier>>.
|
||||
|
||||
*Keywords*
|
||||
|
||||
[cols="^1,^1,^1,^1,^1"]
|
||||
|====
|
||||
|
|
|
@ -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)`.
|
|
@ -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[]
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
Use a literal to specify a value directly in an
|
||||
<<painless-operators, operation>>.
|
||||
|
||||
[[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 <<string-type, `String` type>> 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
|
||||
<<string-character-casting, cast operator>> to convert a `String` type value
|
||||
into a `char` type value.
|
||||
|
|
|
@ -0,0 +1,294 @@
|
|||
[[painless-operators-array]]
|
||||
=== Operators: Array
|
||||
|
||||
[[array-initialization-operator]]
|
||||
==== Array Initialization
|
||||
|
||||
Use the `array initialization operator '[] {}'` to allocate a single-dimensional
|
||||
<<array-type, array type>> 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 <<array-type, array type>> 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
|
||||
<<field-access-operator, field access operator>> 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`;
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
<<painless-functions, function call>> is defined within a script.
|
||||
|
||||
*Grammar*
|
||||
|
||||
[source,ANTLR4]
|
||||
----
|
||||
function_call: ID '(' ( expression (',' expression)* )? ')'';
|
||||
----
|
||||
|
||||
*Examples*
|
||||
|
||||
* A function call.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
<1> int add(int x, int y) {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
<2> int z = add(1, 2);
|
||||
----
|
||||
+
|
||||
<1> define function `add` that returns `int` and has parameters (`int x`,
|
||||
`int y`)
|
||||
<2> declare `int z`;
|
||||
call `add` with arguments (`int 1`, `int 2`) -> `int 3`;
|
||||
store `int 3` to `z`
|
||||
|
||||
[[cast-operator]]
|
||||
==== Cast
|
||||
|
||||
An explicit cast converts the value of an original type to the equivalent value
|
||||
of a target type forcefully as an operation. Use the `cast operator '()'` to
|
||||
specify an explicit cast. Refer to <<painless-casting, casting>> for more
|
||||
information.
|
||||
|
||||
[[conditional-operator]]
|
||||
==== Conditional
|
||||
|
||||
A conditional consists of three expressions. The first expression is evaluated
|
||||
with an expected boolean result type. If the first expression evaluates to true
|
||||
then the second expression will be evaluated. If the first expression evaluates
|
||||
to false then the third expression will be evaluated. The second and third
|
||||
expressions will be <<promotion, promoted>> if the evaluated values are not the
|
||||
same type. Use the `conditional operator '? :'` as a shortcut to avoid the need
|
||||
for a full if/else branch in certain expressions.
|
||||
|
||||
*Errors*
|
||||
|
||||
* If the first expression does not evaluate to a boolean type value.
|
||||
* If the values for the second and third expressions cannot be promoted.
|
||||
|
||||
*Grammar*
|
||||
|
||||
[source,ANTLR4]
|
||||
----
|
||||
conditional: expression '?' expression ':' expression;
|
||||
----
|
||||
|
||||
*Promotion*
|
||||
|
||||
[cols="<1,^1,^1,^1,^1,^1,^1,^1,^1,^1"]
|
||||
|====
|
||||
| | byte | short | char | int | long | float | double | Reference | def
|
||||
| byte | int | int | int | int | long | float | double | - | def
|
||||
| short | int | int | int | int | long | float | double | - | def
|
||||
| char | int | int | int | int | long | float | double | - | def
|
||||
| int | int | int | int | int | long | float | double | - | def
|
||||
| long | long | long | long | long | long | float | double | - | def
|
||||
| float | float | float | float | float | float | float | double | - | def
|
||||
| double | double | double | double | double | double | double | double | - | def
|
||||
| Reference | - | - | - | - | - | - | - | Object @ | def
|
||||
| def | def | def | def | def | def | def | def | def | def
|
||||
|====
|
||||
|
||||
@ If the two reference type values are the same then this promotion will not
|
||||
occur.
|
||||
|
||||
*Examples*
|
||||
|
||||
* Evaluation of conditionals.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
<1> boolean b = true;
|
||||
<2> int x = b ? 1 : 2;
|
||||
<3> List y = x > 1 ? new ArrayList() : null;
|
||||
<4> def z = x < 2 ? x : 2.0;
|
||||
----
|
||||
+
|
||||
<1> declare `boolean b`;
|
||||
store `boolean true` to `b`
|
||||
<2> declare `int x`;
|
||||
load from `b` -> `boolean true`
|
||||
evaluate 1st expression: `int 1` -> `int 1`;
|
||||
store `int 1` to `x`
|
||||
<3> declare `List y`;
|
||||
load from `x` -> `int 1`;
|
||||
`int 1` greater than `int 1` -> `boolean false`;
|
||||
evaluate 2nd expression: `null` -> `null`;
|
||||
store `null` to `y`;
|
||||
<4> declare `def z`;
|
||||
load from `x` -> `int 1`;
|
||||
`int 1` less than `int 2` -> `boolean true`;
|
||||
evaluate 1st expression: load from `x` -> `int 1`;
|
||||
promote `int 1` and `double 2.0`: result `double`;
|
||||
implicit cast `int 1` to `double 1.0` -> `double 1.0`;
|
||||
implicit cast `double 1.0` to `def` -> `def`;
|
||||
store `def` to `z`;
|
||||
|
||||
[[assignment-operator]]
|
||||
==== Assignment
|
||||
|
||||
Use the `assignment operator '='` to store a value in a variable or reference
|
||||
type member field for use in subsequent operations. Any operation that produces
|
||||
a value can be assigned to any variable/field as long as the
|
||||
<<painless-types, types>> are the same or the resultant type can be
|
||||
<<painless-casting, implicitly cast>> to the variable/field type.
|
||||
|
||||
See <<variable-assignment, variable assignment>> for examples using variables.
|
||||
|
||||
*Errors*
|
||||
|
||||
* If the type of value is unable to match the type of variable or field.
|
||||
|
||||
*Grammar*
|
||||
|
||||
[source,ANTLR4]
|
||||
----
|
||||
assignment: field '=' expression
|
||||
----
|
||||
|
||||
*Examples*
|
||||
|
||||
The examples use the following reference type definition:
|
||||
|
||||
[source,Painless]
|
||||
----
|
||||
name:
|
||||
Example
|
||||
|
||||
non-static member fields:
|
||||
* int x
|
||||
* def y
|
||||
* List z
|
||||
----
|
||||
|
||||
* Field assignments of different type values.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
<1> Example example = new Example();
|
||||
<2> example.x = 1;
|
||||
<3> example.y = 2.0;
|
||||
<4> example.z = new ArrayList();
|
||||
----
|
||||
+
|
||||
<1> declare `Example example`;
|
||||
allocate `Example` instance -> `Example reference`;
|
||||
store `Example reference` to `example`
|
||||
<2> load from `example` -> `Example reference`;
|
||||
store `int 1` to `x` of `Example reference`
|
||||
<3> load from `example` -> `Example reference`;
|
||||
implicit cast `double 2.0` to `def` -> `def`;
|
||||
store `def` to `y` of `Example reference`
|
||||
<4> load from `example` -> `Example reference`;
|
||||
allocate `ArrayList` instance -> `ArrayList reference`;
|
||||
implicit cast `ArrayList reference` to `List reference` -> `List reference`;
|
||||
store `List reference` to `z` of `Example reference`
|
||||
+
|
||||
* A field assignment from a field access.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
<1> Example example = new Example();
|
||||
<2> example.x = 1;
|
||||
<3> example.y = example.x;
|
||||
----
|
||||
+
|
||||
<1> declare `Example example`;
|
||||
allocate `Example` instance -> `Example reference`;
|
||||
store `Example reference` to `example`
|
||||
<2> load from `example` -> `Example reference`;
|
||||
store `int 1` to `x` of `Example reference`
|
||||
<3> load from `example` -> `Example reference @0`;
|
||||
load from `example` -> `Example reference @1`;
|
||||
load from `x` of `Example reference @1` -> `int 1`;
|
||||
implicit cast `int 1` to `def` -> `def`;
|
||||
store `def` to `y` of `Example reference @0`;
|
||||
(note `Example reference @0` and `Example reference @1` are the same)
|
||||
|
||||
[[compound-assignment-operator]]
|
||||
==== Compound Assignment
|
||||
|
||||
Use the `compound assignment operator '$='` as a shortcut for an assignment
|
||||
where a binary operation would occur between the variable/field as the
|
||||
left-hand side expression and a separate right-hand side expression.
|
||||
|
||||
A compound assignment is equivalent to the expression below where V is the
|
||||
variable/field and T is the type of variable/member.
|
||||
|
||||
[source,Painless]
|
||||
----
|
||||
V = (T)(V op expression);
|
||||
----
|
||||
|
||||
*Operators*
|
||||
|
||||
The table below shows the available operators for use in a compound assignment.
|
||||
Each operator follows the casting/promotion rules according to their regular
|
||||
definition. For numeric operations there is an extra implicit cast when
|
||||
necessary to return the promoted numeric type value to the original numeric type
|
||||
value of the variable/field and can result in data loss.
|
||||
|
||||
|====
|
||||
|Operator|Compound Symbol
|
||||
|Multiplication|*=
|
||||
|Division|/=
|
||||
|Remainder|%=
|
||||
|Addition|+=
|
||||
|Subtraction|-=
|
||||
|Left Shift|<<=
|
||||
|Right Shift|>>=
|
||||
|Unsigned Right Shift|>>>=
|
||||
|Bitwise And|&=
|
||||
|Boolean And|&=
|
||||
|Bitwise Xor|^=
|
||||
|Boolean Xor|^=
|
||||
|Bitwise Or|\|=
|
||||
|Boolean Or|\|=
|
||||
|String Concatenation|+=
|
||||
|====
|
||||
|
||||
*Errors*
|
||||
|
||||
* If the type of value is unable to match the type of variable or field.
|
||||
|
||||
*Grammar*
|
||||
|
||||
[source,ANTLR4]
|
||||
----
|
||||
compound_assignment: ( ID | field ) '$=' expression;
|
||||
----
|
||||
|
||||
Note the use of the `$=` represents the use of any of the possible binary
|
||||
operators.
|
||||
|
||||
*Examples*
|
||||
|
||||
* Compound assignment for each numeric operator.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
<1> int i = 10;
|
||||
<2> i *= 2;
|
||||
<3> i /= 5;
|
||||
<4> i %= 3;
|
||||
<5> i += 5;
|
||||
<6> i -= 5;
|
||||
<7> i <<= 2;
|
||||
<8> i >>= 1;
|
||||
<9> i >>>= 1;
|
||||
<10> i &= 15;
|
||||
<11> i ^= 12;
|
||||
<12> i |= 2;
|
||||
----
|
||||
+
|
||||
<1> declare `int i`;
|
||||
store `int 10` to `i`
|
||||
<2> load from `i` -> `int 10`;
|
||||
multiply `int 10` and `int 2` -> `int 20`;
|
||||
store `int 20` to `i`;
|
||||
(note this is equivalent to `i = i*2`)
|
||||
<3> load from `i` -> `int 20`;
|
||||
divide `int 20` by `int 5` -> `int 4`;
|
||||
store `int 4` to `i`;
|
||||
(note this is equivalent to `i = i/5`)
|
||||
<4> load from `i` -> `int 4`;
|
||||
remainder `int 4` by `int 3` -> `int 1`;
|
||||
store `int 1` to `i`;
|
||||
(note this is equivalent to `i = i%3`)
|
||||
<5> load from `i` -> `int 1`;
|
||||
add `int 1` and `int 5` -> `int 6`;
|
||||
store `int 6` to `i`;
|
||||
(note this is equivalent to `i = i+5`)
|
||||
<6> load from `i` -> `int 6`;
|
||||
subtract `int 5` from `int 6` -> `int 1`;
|
||||
store `int 1` to `i`;
|
||||
(note this is equivalent to `i = i-5`)
|
||||
<7> load from `i` -> `int 1`;
|
||||
left shift `int 1` by `int 2` -> `int 4`;
|
||||
store `int 4` to `i`;
|
||||
(note this is equivalent to `i = i<<2`)
|
||||
<8> load from `i` -> `int 4`;
|
||||
right shift `int 4` by `int 1` -> `int 2`;
|
||||
store `int 2` to `i`;
|
||||
(note this is equivalent to `i = i>>1`)
|
||||
<9> load from `i` -> `int 2`;
|
||||
unsigned right shift `int 2` by `int 1` -> `int 1`;
|
||||
store `int 1` to `i`;
|
||||
(note this is equivalent to `i = i>>>1`)
|
||||
<10> load from `i` -> `int 1`;
|
||||
bitwise and `int 1` and `int 15` -> `int 1`;
|
||||
store `int 1` to `i`;
|
||||
(note this is equivalent to `i = i&2`)
|
||||
<11> load from `i` -> `int 1`;
|
||||
bitwise xor `int 1` and `int 12` -> `int 13`;
|
||||
store `int 13` to `i`;
|
||||
(note this is equivalent to `i = i^2`)
|
||||
<12> load from `i` -> `int 13`;
|
||||
bitwise or `int 13` and `int 2` -> `int 15`;
|
||||
store `int 15` to `i`;
|
||||
(note this is equivalent to `i = i|2`)
|
||||
+
|
||||
* Compound assignment for each boolean operator.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
<1> boolean b = true;
|
||||
<2> b &= false;
|
||||
<3> b ^= false;
|
||||
<4> b |= true;
|
||||
----
|
||||
+
|
||||
<1> declare `boolean b`;
|
||||
store `boolean true` in `b`;
|
||||
<2> load from `b` -> `boolean true`;
|
||||
boolean and `boolean true` and `boolean false` -> `boolean false`;
|
||||
store `boolean false` to `b`;
|
||||
(note this is equivalent to `b = b && false`)
|
||||
<3> load from `b` -> `boolean false`;
|
||||
boolean xor `boolean false` and `boolean false` -> `boolean false`;
|
||||
store `boolean false` to `b`;
|
||||
(note this is equivalent to `b = b ^ false`)
|
||||
<4> load from `b` -> `boolean true`;
|
||||
boolean or `boolean false` and `boolean true` -> `boolean true`;
|
||||
store `boolean true` to `b`;
|
||||
(note this is equivalent to `b = b || true`)
|
||||
+
|
||||
* A compound assignment with the string concatenation operator.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
<1> String s = 'compound';
|
||||
<2> s += ' assignment';
|
||||
----
|
||||
<1> declare `String s`;
|
||||
store `String 'compound'` to `s`;
|
||||
<2> load from `s` -> `String 'compound'`;
|
||||
string concat `String 'compound'` and `String ' assignment''`
|
||||
-> `String 'compound assignment'`;
|
||||
store `String 'compound assignment'` to `s`;
|
||||
(note this is equivalent to `s = s + ' assignment'`)
|
||||
+
|
||||
* A compound assignment with the `def` type.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
<1> def x = 1;
|
||||
<2> x += 2;
|
||||
----
|
||||
<1> declare `def x`;
|
||||
implicit cast `int 1` to `def`;
|
||||
store `def` to `x`;
|
||||
<2> load from `x` -> `def`;
|
||||
implicit cast `def` to `int 1` -> `int 1`;
|
||||
add `int 1` and `int 2` -> `int 3`;
|
||||
implicit cast `int 3` to `def` -> `def`;
|
||||
store `def` to `x`;
|
||||
(note this is equivalent to `x = x+2`)
|
||||
+
|
||||
* A compound assignment with an extra implicit cast.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
<1> byte b = 1;
|
||||
<2> b += 2;
|
||||
----
|
||||
<1> declare `byte b`;
|
||||
store `byte 1` to `x`;
|
||||
<2> load from `x` -> `byte 1`;
|
||||
implicit cast `byte 1 to `int 1` -> `int 1`;
|
||||
add `int 1` and `int 2` -> `int 3`;
|
||||
implicit cast `int 3` to `byte 3` -> `byte 3`;
|
||||
store `byte 3` to `b`;
|
||||
(note this is equivalent to `b = b+2`)
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
<<reference-types, reference type>> value. Implicit
|
||||
<<boxing-unboxing, boxing/unboxing>> 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
|
||||
<<reference-types, reference type>> 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
|
||||
<<reference-types, reference type>> instance to the heap and call a specified
|
||||
constructor. Implicit <<boxing-unboxing, boxing/unboxing>> 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 <<string-type, `String` type>>.
|
||||
|
||||
*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`;
|
File diff suppressed because it is too large
Load Diff
|
@ -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`
|
||||
|=======================================================================
|
|
@ -0,0 +1,6 @@
|
|||
[[painless-scripts]]
|
||||
=== Scripts
|
||||
|
||||
Scripts are composed of one-to-many <<painless-statements, statements>> and are
|
||||
run in a sandbox that determines what local variables are immediately available
|
||||
along with what APIs are whitelisted for use.
|
|
@ -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) {
|
||||
...
|
||||
}
|
||||
---------------------------------------------------------
|
|
@ -12,16 +12,16 @@ belongs to one of the following categories: <<primitive-types, primitive>>,
|
|||
|
||||
A primitive type represents basic data built natively into the JVM and is
|
||||
allocated to non-heap memory. Declare a primitive type
|
||||
<<painless-variables, variable>>, 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.
|
||||
<<painless-variables, variable>> 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 <<field-access, field access operator>> or
|
||||
<<method-access, method call operator>> on a primitive type value to force
|
||||
evaluation as its corresponding reference type value.
|
||||
type). Use the <<field-access-operator, field access operator>> or
|
||||
<<method-call-operator, method call operator>> 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
|
||||
<<constructor-call, new instance operator>> to allocate a reference type
|
||||
<<new-instance-operator, new instance operator>> 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 <<painless-variables, variable>>, 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 <<painless-variables, variable>> 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 <<field-access, field access operator>> in correspondence with the
|
||||
reference type object name to access a static member field for loading and
|
||||
Use the <<field-access-operator, field access operator>> 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
|
||||
<<field-access, field access operator>> 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.
|
||||
<<field-access-operator, field access operator>> 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 <<method-access, method call operator>> 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 <<painless-functions, function>> called on a
|
||||
reference type *object*. Use the <<method-call-operator, method call operator>>
|
||||
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 <<method-access, method call operator>> 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 <<painless-functions, 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 <<method-call-operator, method call operator>>
|
||||
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
|
||||
<<constructor-call, new instance operator>> to allocate a reference type
|
||||
instance.
|
||||
A constructor is a special type of <<painless-functions, function>> used to
|
||||
allocate a reference type *instance* defined by a specific reference type
|
||||
*object*. Use the <<new-instance-operator, new instance operator>> 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 <<painless-variables, variable>>, 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 <<painless-variables, variable>> 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 <<strings, string literal>> to directly evaluate a
|
||||
`String` type value. While not required, the
|
||||
<<constructor-call, new instance operator>> can allocate `String` type
|
||||
explicit allocation. Use a <<string-literals, string literal>> to directly
|
||||
evaluate a `String` type value. While not required, the
|
||||
<<new-instance-operator, new instance operator>> 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 <<new-array, new array operator>> or the
|
||||
<<array-initialization, array initialization operator>> to allocate an array
|
||||
type instance. Declare an array type <<painless-variables, variable>>, 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 <<new-array-operator, new array operator>> or the
|
||||
<<array-initialization-operator, array initialization operator>> to allocate an
|
||||
array type instance. Declare an array type <<painless-variables, variable>> 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 <<array-length, array length operator>> to retrieve the length of an
|
||||
array type value as an int type value. Use the
|
||||
<<array-access, array access operator>> to load from and store to individual
|
||||
values within an array type value.
|
||||
Use the <<array-length-operator, array length operator>> to retrieve the length
|
||||
of an array type value as an `int` type value. Use the
|
||||
<<array-access-operator, array access operator>> 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`
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
A variable loads and stores a value for evaluation during
|
||||
<<painless-operators, operations>>.
|
||||
|
||||
[[declaration]]
|
||||
[[variable-declaration]]
|
||||
==== Declaration
|
||||
|
||||
Declare a variable before use with the format of <<painless-types, type>>
|
||||
|
@ -12,16 +12,17 @@ followed by <<painless-identifiers, identifier>>. Declare an
|
|||
<<array-type, array type>> 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 <<assignment, assignment operator>>
|
||||
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
|
||||
<<variable-assignment, assignment operator>> 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
|
||||
<<painless-types, types>> are the same or the resultant type can be
|
||||
<<painless-casting, implicitly cast>> 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 <<painless-types, types>> are the same or the
|
||||
resultant type can be <<painless-casting, implicitly cast>> 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
|
||||
<<new-instance-operator, new instance operator>>.
|
||||
+
|
||||
[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
|
||||
<<new-array-operator, new array operator>>.
|
||||
+
|
||||
[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)
|
||||
|
|
Loading…
Reference in New Issue