295 lines
9.1 KiB
Plaintext
295 lines
9.1 KiB
Plaintext
[[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]
|
|
----
|
|
int[] x = new int[] {1, 2, 3}; <1>
|
|
----
|
|
+
|
|
<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]
|
|
----
|
|
int i = 1; <1>
|
|
long l = 2L; <2>
|
|
float f = 3.0F; <3>
|
|
double d = 4.0; <4>
|
|
String s = "5"; <5>
|
|
def array = new def[] {i, l, f*d, s}; <6>
|
|
----
|
|
+
|
|
<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]
|
|
----
|
|
int[] x = new int[2]; <1>
|
|
x[0] = 2; <2>
|
|
x[1] = 5; <3>
|
|
int y = x[0] + x[1]; <4>
|
|
int z = 1; <5>
|
|
int i = x[z]; <6>
|
|
----
|
|
+
|
|
<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]
|
|
----
|
|
def d = new int[2]; <1>
|
|
d[0] = 2; <2>
|
|
d[1] = 5; <3>
|
|
def x = d[0] + d[1]; <4>
|
|
def y = 1; <5>
|
|
def z = d[y]; <6>
|
|
----
|
|
+
|
|
<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]
|
|
----
|
|
int[][][] ia3 = new int[2][3][4]; <1>
|
|
ia3[1][2][3] = 99; <2>
|
|
int i = ia3[1][2][3]; <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]
|
|
----
|
|
int[] x = new int[10]; <1>
|
|
int l = x.length; <2>
|
|
----
|
|
<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 a dimension's size.
|
|
|
|
*Grammar*
|
|
|
|
[source,ANTLR4]
|
|
----
|
|
new_array: 'new' TYPE ('[' expression ']')+;
|
|
----
|
|
|
|
*Examples*
|
|
|
|
* Allocation of different array types.
|
|
+
|
|
[source,Painless]
|
|
----
|
|
int[] x = new int[5]; <1>
|
|
x = new int[10]; <2>
|
|
int y = 2; <3>
|
|
def z = new def[y][y*2]; <4>
|
|
----
|
|
+
|
|
<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`;
|