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:
Jack Conradson 2018-06-07 17:11:56 -07:00 committed by GitHub
parent 972dcbc0ad
commit d6a4c14e1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 4775 additions and 2150 deletions

View File

@ -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.

View File

@ -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];

View File

@ -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)) {
...
}
---------------------------------------------------------

View File

@ -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`
|=======================================================================

View File

@ -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]

View File

@ -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"]
|====

View File

@ -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)`.

View File

@ -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[]

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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`
|=======================================================================

View File

@ -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.

View File

@ -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) {
...
}
---------------------------------------------------------

View File

@ -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`

View File

@ -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)