浏览代码

Painless: Types Section Clean Up (#30283)

Clean up of types section, casting section, and a large number of examples.
Jack Conradson 7 年之前
父节点
当前提交
a96a45c6ae

+ 417 - 133
docs/painless/painless-casting.asciidoc

@@ -1,172 +1,456 @@
 [[painless-casting]]
 [[painless-casting]]
 === Casting
 === Casting
 
 
-Casting is the conversion of one type to another. Implicit casts are casts that
-occur automatically, such as during an assignment operation. Explicit casts are
-casts where you use the casting operator to explicitly convert one type to
-another. This is necessary during operations where the cast cannot be inferred.
+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.
 
 
-To cast to a new type, precede the expression by the new type enclosed in
-parentheses, for example
-`(int)x`.
+*Errors*
 
 
-The following sections specify the implicit casts that can be performed and the
-explicit casts that are allowed. The only other permitted cast is casting
-a single character `String` to a `char`.
+* If during a cast there exists no equivalent value for the target type.
+* If an implicit cast is given, but an explicit cast is required.
 
 
-*Grammar:*
+*Grammar*
 [source,ANTLR4]
 [source,ANTLR4]
 ----
 ----
 cast: '(' TYPE ')' expression
 cast: '(' TYPE ')' expression
 ----
 ----
 
 
-[[numeric-casting]]
-==== Numeric Casting
+*Examples*
 
 
-The following table shows the allowed implicit and explicit casts between
-numeric types. Read the table by row. To find out if you need to explicitly
-cast from type A to type B, find the row for type A and scan across to the
-column for type B.
+* Valid casts.
++
+[source,Painless]
+----
+<1> int i = (int)5L;
+<2> Map m = new HashMap();
+<3> HashMap hm = (HashMap)m;
+----
++
+<1> declare `int i`;
+    explicit cast `long 5` to `int 5` -> `int 5`;
+    assign `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`
+<3> declare `HashMap hm`;
+    access `m` -> `Map reference`;
+    explicit cast `Map reference` to `HashMap reference` -> `HashMap reference`;
+    assign `HashMap reference` to `hm`
+
+[[numeric-type-casting]]
+==== Numeric Type Casting
 
 
-IMPORTANT: Explicit casts between numeric types can result in some data loss. A
-smaller numeric type cannot necessarily accommodate the value from a larger
-numeric type. You might also lose precision when casting from integer types
-to floating point types.
+A <<primitive-types, numeric type>> cast converts the value of an original
+numeric type to the equivalent value of a target numeric type. A cast between
+two numeric type values results in data loss when the value of the original
+numeric type is larger than the target numeric type can accommodate. A cast
+between an integer type value and a floating point type value can result in
+precision loss.
+
+The allowed casts for values of each numeric type are shown as a row in the
+following table:
 
 
 |====
 |====
-|       | byte     | short    | char     | int      | long     | float    | double
-| byte  |          | implicit | implicit | implicit | implicit | implicit | implicit
-| short | explicit |          | explicit | implicit | implicit | implicit | implicit
-| char  | explicit | explicit |          | implicit | implicit | implicit | implicit
-| int   | explicit | explicit | explicit |          | implicit | implicit | implicit
-| long  | explicit | explicit | explicit | explicit |          | implicit | implicit
-| float | explicit | explicit | explicit | explicit | explicit |          | implicit
+|        | byte     | short    | char     | int      | long     | float    | double
+| byte   |          | implicit | implicit | implicit | implicit | implicit | implicit
+| short  | explicit |          | explicit | implicit | implicit | implicit | implicit
+| char   | explicit | explicit |          | implicit | implicit | implicit | implicit
+| int    | explicit | explicit | explicit |          | implicit | implicit | implicit
+| long   | explicit | explicit | explicit | explicit |          | implicit | implicit
+| float  | explicit | explicit | explicit | explicit | explicit |          | implicit
 | double | explicit | explicit | explicit | explicit | explicit | explicit |
 | double | explicit | explicit | explicit | explicit | explicit | explicit |
 |====
 |====
 
 
+*Examples*
+
+* Valid numeric type casts.
++
+[source,Painless]
+----
+<1> int a = 1;
+<2> long b = a;
+<3> short c = (short)b;
+<4> double e = (double)a;
+----
++
+<1> declare `int a`;
+    assign `int 1` to `a`
+<2> declare `long b`;
+    access `a` -> `int 1`;
+    implicit cast `int 1` to `long 1` -> `long 1`;
+    assign `long 1` to `b`
+<3> declare `short c`;
+    access `b` -> `long 1`;
+    explicit cast `long 1` to `short 1` -> `short 1`;
+    assign `short 1` value to `c`
+<4> declare `double e`;
+    access `a` -> `int 1`;
+    explicit cast `int 1` to `double 1.0`;
+    assign `double 1.0` to `e`;
+    (note the explicit cast is extraneous since an implicit cast is valid)
++
+* Invalid numeric type casts resulting in errors.
++
+[source,Painless]
+----
+<1> int a = 1.0; // error
+<2> int b = 2;
+<3> byte c = b;  // error
+----
++
+<1> declare `int i`;
+    *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`
+<3> declare byte `c`;
+    access `b` -> `int 2`;
+    *error* -> cannot implicit cast `int 2` to `byte 2`;
+    (note an explicit cast is valid)
+
+[[reference-type-casting]]
+==== Reference Type Casting
+
+A <<reference-types, reference type>> cast converts the value of an original
+reference type to the equivalent value of a target reference type. An implicit
+cast between two reference type values is allowed when the original reference
+type is a descendant of the target type. An explicit cast between two reference
+type values is allowed when the original type is a descendant of the target type
+or the target type is a descendant of the original type.
+
+*Examples*
+
+* Valid reference type casts.
++
+[source,Painless]
+----
+<1> List x;
+<2> ArrayList y = new ArrayList();
+<3> x = y;
+<4> y = (ArrayList)x;
+<5> x = (List)y;
+----
++
+<1> declare `List x`;
+    assign default value `null` to `x`
+<2> declare `ArrayList y`;
+    allocate `ArrayList` instance -> `ArrayList reference`;
+    assign `ArrayList reference` to `y`;
+<3> access `y` -> `ArrayList reference`;
+    implicit cast `ArrayList reference` to `List reference` -> `List reference`;
+    assign `List reference` to `x`;
+    (note `ArrayList` is a descendant of `List`)
+<4> access `x` -> `List reference`;
+    explicit cast `List reference` to `ArrayList reference`
+            -> `ArrayList reference`;
+    assign `ArrayList reference` to `y`;
+<5> access `y` -> `ArrayList reference`;
+    explicit cast `ArrayList reference` to `List reference` -> `List reference`;
+    assign `List reference` to `x`;
+    (note the explicit cast is extraneous, and an implicit cast is valid)
++
+* Invalid reference type casts resulting in errors.
++
+[source,Painless]
+----
+<1> List x = new ArrayList();
+<2> ArrayList y = x;          // error
+<3> Map m = (Map)x;           // error
+----
++
+<1> declare `List x`;
+    allocate `ArrayList` instance -> `ArrayList reference`;
+    implicit cast `ArrayList reference` to `List reference` -> `List reference`;
+    assign `List reference` to `x`
+<2> declare `ArrayList y`;
+    access `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`;
+    *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)
+
+[[dynamic-type-casting]]
+==== Dynamic Type Casting
+
+A <<dynamic-types, dynamic (`def`) type>> cast converts the value of an original
+`def` type to the equivalent value of any target type or converts the value of
+any original type to the equivalent value of a target `def` type.
+
+An implicit cast from any original type value to a `def` type value is always
+allowed. An explicit cast from any original type value to a `def` type value is
+always allowed but never necessary.
+
+An implicit or explicit cast from an original `def` type value to
+any target type value is allowed if and only if the cast is normally allowed
+based on the current type value the `def` type value represents.
+
+*Examples*
 
 
-Example(s)
-[source,Java]
-----
-int a = 1;            // Declare int variable a and set it to the literal
-                      //   value 1
-long b = a;           // Declare long variable b and set it to int variable
-                      //    a with an implicit cast to convert from int to long
-short c = (short)b;   // Declare short variable c, explicitly cast b to a
-                      //   short, and assign b to c
-byte d = a;           // ERROR: Casting an int to a byte requires an explicit
-                      //   cast
-double e = (double)a; // Explicitly cast int variable a to a double and assign
-                      //   it to the double variable e. The explicit cast is
-                      //   allowed, but it is not necessary.
-----
-
-[[reference-casting]]
-==== Reference Casting
-
-A reference type can be implicitly cast to another reference type as long as
-the type being cast _from_ is a descendant of the type being cast _to_.  A
-reference type can be explicitly cast _to_ if the type being cast to is a
-descendant of the type being cast _from_.
-
-*Examples:*
-[source,Java]
-----
-List x;                        // Declare List variable x
-ArrayList y = new ArrayList(); // Declare ArrayList variable y and assign it a
-                               //   newly allocated ArrayList [1]
-x = y;                         // Assign Arraylist y to List x using an
-                               //   implicit cast
-y = (ArrayList)x;              // Explicitly cast List x to an ArrayList and
-                               //  assign it to ArrayList y
-x = (List)y;                   // Set List x to ArrayList y using an explicit
-                               //   cast (the explicit cast is not necessary)
-y = x;                         // ERROR: List x cannot be implicitly cast to
-                               //   an ArrayList, an explicit cast is required
-Map m = y;                     // ERROR: Cannot implicitly or explicitly cast [2]
-                               //   an ArrayList to a Map, no relationship
-                               //   exists between the two types.
-----
-[1] `ArrayList` is a descendant of the `List` type.
-[2] `Map` is unrelated to the `List` and `ArrayList` types.
-
-[[def-type-casting]]
-==== def Type Casting
-All primitive and reference types can always be implicitly cast to
-`def`. While it is possible to explicitly cast to `def`, it is not necessary.
-
-However, it is not always possible to implicitly cast a `def` to other
-primitive and reference types. An explicit cast is required if an explicit
-cast would normally be required between the non-def types.
-
-
-*Examples:*
-[source,Java]
-----
-def x;          // Declare def variable x and set it to null
-x = 3;          // Set the def variable x to the literal 3 with an implicit
-                //   cast from int to def
-double a = x;   // Declare double variable a and set it to def variable x,
-                //   which contains a double
-int b = x;      // ERROR: Results in a run-time error because an explicit cast is
-                //   required to cast from a double to an int
-int c = (int)x; // Declare int variable c, explicitly cast def variable x to an
-                //   int, and assign x to c
+* Valid dynamic type casts with any original type to a target `def` type.
++
+[source,Painless]
 ----
 ----
+<1> def d0 = 3;
+<2> d0 = new ArrayList();
+<3> Object o = new HashMap();
+<4> def d1 = o;
+<5> int i = d1.size();
+----
++
+<1> declare `def d0`;
+    implicit cast `int 3` to `def`;
+    assign `int 3` to `d0`
+<2> allocate `ArrayList` instance -> `ArrayList reference`;
+    implicit cast `ArrayList reference` to `def` -> `def`;
+    assign `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`
+<4> declare `def d1`;
+    access `o` -> `Object reference`;
+    implicit cast `Object reference` to `def` -> `def`;
+    assign `def` to `d1`
+<5> declare `int i`;
+    access `d1` -> `def`;
+    implicit cast `def` to `HashMap reference` -> HashMap reference`;
+    call `size` on `HashMap reference` -> `int 0`;
+    assign `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)
++
+* Valid dynamic type casts with an original `def` type to any target type.
++
+[source,Painless]
+----
+<1> def d = 1.0;
+<2> int i = (int)d;
+<3> d = 1;
+<4> float f = d;
+<5> d = new ArrayList();
+<6> List l = d;
+----
++
+<1> declare `def d`;
+    implicit cast `double 1.0` to `def` -> `def`;
+    assign `def` to `d`
+<2> declare `int i`;
+    access `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`;
+    (note the switch in the type `d` represents from `double` to `int`)
+<4> declare `float i`;
+    access `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`
+<5> allocate `ArrayList` instance -> `ArrayList reference`;
+    assign `ArrayList reference` to `d`;
+    (note the switch in the type `d` represents from `int` to `ArrayList`)
+<6> declare `List l`;
+    access `d` -> `def`;
+    implicit cast `def` to `ArrayList reference` -> `ArrayList reference`;
+    implicit cast `ArrayList reference` to `List reference` -> `List reference`;
+    assign `List reference` to `l`
++
+* Invalid dynamic type casts resulting in errors.
++
+[source,Painless]
+----
+<1> def d = 1;
+<2> short s = d;       // error
+<3> d = new HashMap();
+<4> List l = d;        // error
+----
+<1> declare `def d`;
+    implicit cast `int 1` to `def` -> `def`;
+    assign `def` to `d`
+<2> declare `short s`;
+    access `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`
+<4> declare `List l`;
+    access `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)
+
+[[string-character-casting]]
+==== String to Character Casting
+
+Use the *cast operator* to convert a <<string-type, `String` type>> value into a
+<<primitive-types, `char` type>> value.
+
+*Errors*
+
+* If the `String` type value isn't one character in length.
+* If the `String` type value is `null`.
+
+*Examples*
+
+* Casting string literals into `char` type values.
++
+[source,Painless]
+----
+<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`
+<2> explicit cast `String 'c'` to `char c` -> `char c`;
+    assign `char c` to `c`
++
+* Casting a `String` reference into a `char` value.
++
+[source,Painless]
+----
+<1> String s = "s";
+<2> char c = (char)s;
+----
+<1> declare `String s`;
+    assign `String "s"` to `s`;
+<2> declare `char c`
+    access `s` -> `String "s"`;
+    explicit cast `String "s"` to `char s` -> `char s`;
+    assign `char s` to `c`
 
 
 [[boxing-unboxing]]
 [[boxing-unboxing]]
 ==== Boxing and Unboxing
 ==== Boxing and Unboxing
 
 
-Boxing is where a cast is used to convert a primitive type to its corresponding
-reference type. Unboxing is the reverse, converting a reference type to the
-corresponding primitive type.
+Boxing is a special type of cast used to convert a primitive type to its
+corresponding reference type. Unboxing is the reverse used to convert a
+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
+  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.
 
 
-There are two places Painless performs implicit boxing and unboxing:
+Explicit boxing/unboxing is not allowed. Use the reference type API to
+explicitly convert a primitive type value to its respective reference type
+value and vice versa.
 
 
-* When you call methods, Painless automatically boxes and unboxes arguments
-so you can specify either primitive types or their corresponding reference
-types.
-* When you use the `def` type, Painless automatically boxes and unboxes as
-needed when converting to and from `def`.
+*Errors*
 
 
-The casting operator does not support any way to explicitly box a primitive
-type or unbox a reference type.
+* If an explicit cast is made to box/unbox a primitive type.
 
 
-If a primitive type needs to be converted to a reference type, the Painless
-reference type API supports methods that can do that. However, under normal
-circumstances this should not be necessary.
+*Examples*
 
 
-*Examples:*
-[source,Java]
+* Uses of implicit boxing/unboxing.
++
+[source,Painless]
 ----
 ----
-Integer x = 1;               // ERROR: not a legal implicit cast
-Integer y = (Integer)1;      // ERROR: not a legal explicit cast
-int a = new Integer(1);      // ERROR: not a legal implicit cast
-int b = (int)new Integer(1); // ERROR: not a legal explicit cast
+<1> List l = new ArrayList();
+<2> l.add(1);
+<3> Integer I = Integer.valueOf(0);
+<4> int i = l.get(i);
 ----
 ----
++
+<1> declare `List l`;
+    allocate `ArrayList` instance -> `ArrayList reference`;
+    assign `ArrayList reference` to `l`;
+<2> access `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`;
+<4> declare `int i`;
+    access `I` -> `Integer 0`;
+    unbox `Integer 0` -> `int 0`;
+    access `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`;
+    (note internally `int 1` is unboxed from `Integer 1` when loaded from a
+            `def` type value)
++
+* Uses of invalid boxing/unboxing resulting in errors.
++
+[source,Painless]
+----
+<1> Integer x = 1;                   // error
+<2> Integer y = (Integer)1;          // error
+<3> int a = Integer.valueOf(1);      // error
+<4> int b = (int)Integer.valueOf(1); // error
+----
++
+<1> declare `Integer x`;
+    *error* -> cannot implicit box `int 1` to `Integer 1` during assignment
+<2> declare `Integer y`;
+    *error* -> cannot explicit box `int 1` to `Integer 1` during assignment
+<3> declare `int a`;
+    call `valueOf` on `Integer` with arguments of (`int 1`) -> `Integer 1`;
+    *error* -> cannot implicit unbox `Integer 1` to `int 1` during assignment
+<4> declare `int a`;
+    call `valueOf` on `Integer` with arguments of (`int 1`) -> `Integer 1`;
+    *error* -> cannot explicit unbox `Integer 1` to `int 1` during assignment
 
 
 [[promotion]]
 [[promotion]]
 ==== Promotion
 ==== Promotion
 
 
-Promotion is where certain operations require types to be either a minimum
-numerical type or for two (or more) types to be equivalent.
-The documentation for each operation that has these requirements
-includes promotion tables that describe how this is handled.
+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.
 
 
-When an operation promotes a type or types, the resultant type
-of the operation is the promoted type.  Types can be promoted to def
-at compile-time; however, at run-time, the resultant type will be the
-promotion of the types the `def` is representing.
+*Errors*
 
 
-*Examples:*
-[source,Java]
-----
-2 + 2.0     // Add the literal int 2 and the literal double 2.0. The literal
-            //   2 is promoted to a double and the resulting value is a double.
+* If a specific operation cannot find an allowed promotion type for the type(s)
+  of value(s) given.
 
 
-def x = 1;  // Declare def variable x and set it to the literal int 1 through
-            //   an implicit cast
-x + 2.0F    // Add def variable x and the literal float 2.0.
-            // At compile-time the types are promoted to def.
-            // At run-time the types are promoted to float.
+*Examples*
+
+* Uses of promotion.
++
+[source,Painless]
+----
+<1> double d = 2 + 2.0;
+<2> def x = 1;
+<3> float f = x + 2.0F;
 ----
 ----
+<1> declare `double d`;
+    promote `int 2` and `double 2.0 @0` -> `double 2.0 @0`;
+    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`
+<2> declare `def x`;
+    implicit cast `int 1` to `def` -> `def`;
+    assign `def` to `x`;
+<3> declare `float f`;
+    access `x` -> `def`;
+    implicit cast `def` to `int 1` -> `int 1`;
+    promote `int 1` and `float 2.0` -> `float 2.0`;
+    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`;
+    (note this example illustrates promotion done at run-time as promotion
+            done at compile-time would have resolved to a `def` type value)

+ 6 - 6
docs/painless/painless-comments.asciidoc

@@ -1,12 +1,12 @@
 [[painless-comments]]
 [[painless-comments]]
 === Comments
 === Comments
 
 
-Use the `//` token 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.
+Use a comment to annotate or explain code within a script. Use the `//` token
+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.
 
 
 *Grammar*
 *Grammar*
 [source,ANTLR4]
 [source,ANTLR4]

+ 4 - 4
docs/painless/painless-identifiers.asciidoc

@@ -1,10 +1,10 @@
 [[painless-identifiers]]
 [[painless-identifiers]]
 === Identifiers
 === Identifiers
 
 
-Specify identifiers to <<declaration, declare>>, <<assignment, assign>>, and
-<<painless-operators, use>> variables, <<dot-operator, access fields>>, and
-<<dot-operator, call methods>>. <<painless-keywords, Keywords>> and
-<<painless-types, types>> cannot be used as identifiers.
+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.
 
 
 *Grammar*
 *Grammar*
 [source,ANTLR4]
 [source,ANTLR4]

+ 3 - 3
docs/painless/painless-keywords.asciidoc

@@ -1,9 +1,9 @@
 [[painless-keywords]]
 [[painless-keywords]]
 === Keywords
 === Keywords
 
 
-The keywords in the table below are reserved for built-in language
-features. These keywords cannot be used as
-<<painless-identifiers, identifiers>> or <<painless-types, types>>.
+Keywords are reserved tokens for built-in language features and cannot be used
+as <<painless-identifiers, identifiers>> within a script. The following are
+keywords:
 
 
 [cols="^1,^1,^1,^1,^1"]
 [cols="^1,^1,^1,^1,^1"]
 |====
 |====

+ 1 - 1
docs/painless/painless-lang-spec.asciidoc

@@ -6,7 +6,7 @@ Painless syntax is similar to Java syntax along with some additional
 features such as dynamic typing, Map and List accessor shortcuts, and array
 features such as dynamic typing, Map and List accessor shortcuts, and array
 initializers. As a direct comparison to Java, there are some important
 initializers. As a direct comparison to Java, there are some important
 differences, especially related to the casting model. For more detailed
 differences, especially related to the casting model. For more detailed
-conceptual information about the basic constructs that Java and Painless share,
+conceptual information about the basic constructs that Painless and Java share,
 refer to the corresponding topics in the
 refer to the corresponding topics in the
 https://docs.oracle.com/javase/specs/jls/se8/html/index.html[Java Language
 https://docs.oracle.com/javase/specs/jls/se8/html/index.html[Java Language
 Specification].
 Specification].

+ 16 - 36
docs/painless/painless-literals.asciidoc

@@ -1,18 +1,19 @@
 [[painless-literals]]
 [[painless-literals]]
 === Literals
 === Literals
 
 
-Use literals to specify different types of values directly in a script.
+Use a literal to specify a value directly in an
+<<painless-operators, operation>>.
 
 
 [[integers]]
 [[integers]]
 ==== Integers
 ==== Integers
 
 
-Use integer literals to specify an integer value in decimal, octal, or hex
-notation of the <<primitive-types, primitive types>> `int`, `long`, `float`,
+Use an integer literal to specify an integer type value in decimal, octal, or
+hex notation of a <<primitive-types, primitive type>> `int`, `long`, `float`,
 or `double`. Use the following single letter designations to specify the
 or `double`. Use the following single letter designations to specify the
-<<primitive-types, primitive type>>: `l` or `L` for `long`, `f` or `F` for
-`float`, and `d` or `D` for `double`. If not specified, the type defaults to
-`int`.  Use `0` as a prefix to specify an integer literal as octal, and use
-`0x` or `0X` as a prefix to specify an integer literal as hex.
+primitive type: `l` or `L` for `long`, `f` or `F` for `float`, and `d` or `D`
+for `double`. If not specified, the type defaults to `int`.  Use `0` as a prefix
+to specify an integer literal as octal, and use `0x` or `0X` as a prefix to
+specify an integer literal as hex.
 
 
 *Grammar*
 *Grammar*
 [source,ANTLR4]
 [source,ANTLR4]
@@ -46,11 +47,10 @@ HEX:     '-'? '0' [xX] [0-9a-fA-F]+ [lL]?;
 [[floats]]
 [[floats]]
 ==== Floats
 ==== Floats
 
 
-Use floating point literals to specify a floating point value of the
-<<primitive-types, primitive types>> `float` or `double`. Use the following
-single letter designations to specify the <<primitive-types, primitive type>>:
-`f` or `F` for `float` and `d` or `D` for `double`. If not specified, the type defaults
-to `double`.
+Use a floating point literal to specify a floating point type value of a
+<<primitive-types, primitive type>> `float` or `double`. Use the following
+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*
 *Grammar*
 [source,ANTLR4]
 [source,ANTLR4]
@@ -81,7 +81,7 @@ EXPONENT: ( [eE] [+\-]? [0-9]+ );
 [[strings]]
 [[strings]]
 ==== Strings
 ==== Strings
 
 
-Use string literals to specify <<string-type, String>> values with
+Use a string literal to specify a <<string-type, `String` type>> value with
 either single-quotes or double-quotes. Use a `\"` token to include a
 either single-quotes or double-quotes. Use a `\"` token to include a
 double-quote as part of a double-quoted string literal. Use a `\'` token to
 double-quote as part of a double-quoted string literal. Use a `\'` token to
 include a single-quote as part of a single-quoted string literal.  Use a `\\`
 include a single-quote as part of a single-quoted string literal.  Use a `\\`
@@ -117,26 +117,6 @@ STRING: ( '"'  ( '\\"'  | '\\\\' | ~[\\"] )*? '"'  )
 [[characters]]
 [[characters]]
 ==== Characters
 ==== Characters
 
 
-Use the <<painless-casting, casting operator>> to convert string literals or
-<<string-type, String>> values into <<primitive-types, char>> values.
-<<string-type, String>> values converted into
-<<primitive-types, char>> values must be exactly one character in length
-or an error will occur.
-
-*Examples*
-
-* Casting string literals into <<primitive-types, char>> values.
-+
-[source,Painless]
-----
-(char)"C"
-(char)'c'
-----
-+
-* Casting a <<string-type, String>> value into a <<primitive-types, char>> value.
-+
-[source,Painless]
-----
-String s = "s";
-char c = (char)s;
-----
+A character literal cannot be specified directly. Instead, use the
+<<string-character-casting, cast operator>> to convert a `String` type value
+into a `char` type value.

+ 45 - 2
docs/painless/painless-operators.asciidoc

@@ -240,6 +240,7 @@ operator.  See Function Calls [MARK] for more information.
 The brackets operator `[]` is used to create and access arrays, lists, and maps.
 The brackets operator `[]` is used to create and access arrays, lists, and maps.
 The braces operator `{}` is used to intialize arrays.
 The braces operator `{}` is used to intialize arrays.
 
 
+[[array-initialization]]
 ===== Creating and Initializing Arrays
 ===== Creating and Initializing Arrays
 
 
 You create and initialize arrays using the brackets `[]` and braces `{}`
 You create and initialize arrays using the brackets `[]` and braces `{}`
@@ -248,9 +249,49 @@ initialize each dimension with are specified as a comma-separated list enclosed
 in braces. For example, `new int[] {1, 2, 3}` creates a one dimensional `int`
 in braces. For example, `new int[] {1, 2, 3}` creates a one dimensional `int`
 array with a size of 3 and the values 1, 2, and 3.
 array with a size of 3 and the values 1, 2, and 3.
 
 
-For more information about allocating and initializing arrays, see <<array-type,
-Array Type>>.
+To allocate an array, you use the `new` keyword followed by the type and a
+set of brackets for each dimension. You can explicitly define the size of each dimension by specifying an expression within the brackets, or initialize each
+dimension with the desired number of values. The allocated size of each
+dimension is its permanent size.
 
 
+To initialize an array, specify the values you want to initialize
+each dimension with as a comma-separated list of expressions enclosed in braces.
+For example, `new int[] {1, 2, 3}` creates a one-dimensional `int` array with a
+size of 3 and the values 1, 2, and 3.
+
+When you initialize an array, the order of the expressions is maintained. Each expression used as part of the initialization is converted to the
+array's type. An error occurs if the types do not match.
+
+*Grammar:*
+[source,ANTLR4]
+----
+declare_array: TYPE ('[' ']')+;
+
+array_initialization: 'new' TYPE '[' ']' '{' expression (',' expression) '}'
+                    | 'new' TYPE '[' ']' '{' '}';
+----
+
+*Examples:*
+[source,Java]
+----
+int[] x = new int[5];          // Declare int array x and assign it a newly
+                               //   allocated int array with a size of 5
+def[][] y = new def[5][5];     // Declare the 2-dimensional def array y and
+                               //   assign it a newly allocated 2-dimensional
+                               //   array where both dimensions have a size of 5
+int[] x = new int[] {1, 2, 3}; // Declare int array x and set it to an int
+                               //   array with values 1, 2, 3 and a size of 3
+int i = 1;
+long l = 2L;
+float f = 3.0F;
+double d = 4.0;
+String s = "5";
+def[] da = new def[] {i, l, f*d, s}; // Declare def array da and set it to
+                                     // a def array with a size of 4 and the
+                                     // values i, l, f*d, and s
+----
+
+[[array-access]]
 ===== Accessing Array Elements
 ===== Accessing Array Elements
 
 
 Elements in an array are stored and accessed using the brackets `[]` operator.
 Elements in an array are stored and accessed using the brackets `[]` operator.
@@ -298,6 +339,7 @@ return d[z];              // Access the 1st element of array d using the
 NOTE: The use of the `def` type in the second example means that the types
 NOTE: The use of the `def` type in the second example means that the types
 cannot be resolved until runtime.
 cannot be resolved until runtime.
 
 
+[[array-length]]
 ===== Array Length
 ===== Array Length
 
 
 Arrays contain a special member known as 'length' that is a read-only value that contains the size of the array.  This member can be accessed from an array using the dot operator.
 Arrays contain a special member known as 'length' that is a read-only value that contains the size of the array.  This member can be accessed from an array using the dot operator.
@@ -727,6 +769,7 @@ def e;                   // declares the def variable e
 e = new HashMap(m);      // sets e to a newly allocated HashMap using the constructor with a single argument m
 e = new HashMap(m);      // sets e to a newly allocated HashMap using the constructor with a single argument m
 ----
 ----
 
 
+[[new-array]]
 ==== New Array
 ==== New Array
 
 
 An array type instance can be allocated using the new operator. The format starts with the new operator followed by the type followed by a series of opening and closing braces each containing an expression for the size of the dimension.
 An array type instance can be allocated using the new operator. The format starts with the new operator followed by the type followed by a series of opening and closing braces each containing an expression for the size of the dimension.

+ 421 - 224
docs/painless/painless-types.asciidoc

@@ -1,269 +1,466 @@
 [[painless-types]]
 [[painless-types]]
 === Types
 === Types
 
 
-Painless supports both dynamic and static types. Static types are split into
-_primitive types_ and _reference types_.
-
-[[dynamic-types]]
-==== Dynamic Types
-
-Painless supports one dynamic type: `def`.  The `def` type can represent any
-primitive or reference type. When you use the `def` type, it mimics the exact
-behavior of whatever type it represents at runtime. The default value for the
-def type is `null.`
-
-Internally, if the `def` type represents a primitive type, it is converted to the
-corresponding reference type. It still behaves like the primitive type, however,
-including within the casting model. The `def` type can be assigned to different
-types during the course of script execution.
-
-IMPORTANT: Because a `def` type variable can be assigned to different types
-during execution, type conversion errors that occur when using the `def` type
-happen at runtime.
-
-Using the `def` type can have a slight impact on performance. If performance is
-critical, it's better to declare static types.
-
-*Examples:*
-[source,Java]
-----
-def x = 1;               // Declare def variable x and set it to the
-                         //   literal int 1
-def l = new ArrayList(); // Declare def variable l and set it a newly 
-                         //   allocated ArrayList
-----
+A type is a classification of data used to define the properties of a value.
+These properties specify what data a value represents and the rules for how a
+value is evaluated during an <<painless-operators, operation>>. Each type
+belongs to one of the following categories: <<primitive-types, primitive>>,
+<<reference-types, reference>>, or <<dynamic-types, dynamic>>.
 
 
 [[primitive-types]]
 [[primitive-types]]
 ==== Primitive Types
 ==== Primitive Types
 
 
-Primitive types are allocated directly onto the stack according to the standard
-Java memory model.
-
-Primitive types can behave as their corresponding (<<boxing-unboxing, boxed>>)
-reference type. This means any piece of a reference type can be accessed or
-called through the primitive type. Operations performed in this manner convert
-the primitive type to its corresponding reference type at runtime and perform
-the field access  or method call without needing to perform any other
-operations.
-
-Painless supports the following primitive types.
-
-byte::
-An 8-bit, signed, two's complement integer.
-Range: [-128, 127].
-Default value: 0.
-Reference type: Byte.
-
-short:: 
-A 16-bit, signed, two's complement integer.
-Range: [-32768, 32767].
-Default value: 0.
-Reference type: Short.
-
-char::
-A 16-bit Unicode character.
-Range: [0, 65535].
-Default value: 0 or `\u0000`.
-Reference type: Character.
-
-int::
-A 32-bit, signed, two's complement integer.
-Range: [-2^32, 2^32-1].
-Default value: 0.
-Reference type: Integer.
-
-long::
-A 64-bit, signed, two's complement integer.
-Range: [-2^64, 2^64-1].
-Default value: 0.
-Reference type: Long.
-
-float::
-A 32-bit, single-precision, IEEE 754 floating point number.
-Range:  Depends on multiple factors.
-Default value: 0.0.
-Reference type: Float.
-
-double::
-A 64-bit, double-precision, IEEE 754 floating point number.
-Range: Depends on multiple factors.
-Default value: 0.0.
-Reference type: Double.
-
-boolean::
-A logical quanity with two possible values: true and false.
-Range: true/false.
-Default value: false.
-Reference type: Boolean.
-
-
-*Examples:*
-[source,Java]
+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.
+
+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.
+
+The following primitive types are available:
+
+[horizontal]
+`byte`::
+8-bit, signed, two's complement integer
+* range: [`-128`, `127`]
+* default value: `0`
+* reference type: `Byte`
+
+`short`::
+16-bit, signed, two's complement integer
+* range: [`-32768`, `32767`]
+* default value: `0`
+* reference type: `Short`
+
+`char`::
+16-bit, unsigned, Unicode character
+* range: [`0`, `65535`]
+* default value: `0` or `\u0000`
+* reference type: `Character`
+
+`int`::
+32-bit, signed, two's complement integer
+* range: [`-2^32`, `2^32-1`]
+* default value: `0`
+* reference type: `Integer`
+
+`long`::
+64-bit, signed, two's complement integer
+* range: [`-2^64`, `2^64-1`]
+* default value: `0`
+* reference type: `Long`
+
+`float`::
+32-bit, signed, single-precision, IEEE 754 floating point number
+* default value: `0.0`
+* reference type: `Float`
+
+`double`::
+64-bit, signed, double-precision, IEEE 754 floating point number
+* default value: `0.0`
+* reference type: `Double`
+
+`boolean`::
+logical quantity with two possible values of `true` and `false`
+* default value: `false`
+* reference type: `Boolean`
+
+*Examples*
+
+* Primitive types used in declaration, declaration and assignment.
++
+[source,Painless]
 ----
 ----
-int i = 1;        // Declare variable i as an int and set it to the
-                  //   literal 1
-double d;         // Declare variable d as a double and set it to the
-                  //   default value of 0.0
-boolean b = true; // Declare variable b as a boolean and set it to true
+<1> int i = 1;
+<2> double d;
+<3> boolean b = true;
 ----
 ----
-
-Using methods from the corresponding reference type on a primitive type.
-
-[source,Java]
++
+<1> declare `int i`;
+    assign `int 1` to `i`
+<2> declare `double d`;
+    assign default `double 0.0` to `d`
+<3> declare `boolean b`;
+    assign `boolean true` to `b`
++
+* Method call on a primitive type using the corresponding reference type.
++
+[source,Painless]
 ----
 ----
-int i = 1;    // Declare variable i as an int and set it to the
-              //   literal 1
-i.toString(); // Invokes the Integer method toString on variable i
+<1> int i = 1;
+<2> i.toString();
 ----
 ----
++
+<1> declare `int i`;
+    assign `int 1` to `i`
+<2> access `i` -> `int 1`;
+    box `int 1` -> `Integer 1 reference`;
+    call `toString` on `Integer 1 reference` -> `String '1'`
 
 
 [[reference-types]]
 [[reference-types]]
 ==== Reference Types
 ==== Reference Types
 
 
-Reference types are similar to Java classes and can contain multiple pieces
-known as _members_. However, reference types do not support access modifiers.
-You allocate reference type instances on the heap using the `new` operator.
-
-Reference types can have both static and non-static members:
-
-* Static members are shared by all instances of the same reference type and
-can be accessed without allocating an instance of the reference type. For
-example `Integer.MAX_VALUE`.
-* Non-static members are specific to an instance of the reference type
-and can only be accessed through the allocated instance.
-
-The default value for a reference type is `null`, indicating that no memory has
-been allocated for it. When you assign `null` to a reference type, its previous
-value is discarded and garbage collected in accordance with the Java memory
-model as long as there are no other references to that value.
-
-A reference type can contain:
-
-* Zero to many primitive types. Primitive type members can be static or
-non-static and read-only or read-write.
-* Zero to many reference types. Reference type members can be static or
-non-static and read-only or read-write.
-* Methods that call an internal function to return a value and/or manipulate
-the primitive or reference type members. Method members can be static or
-non-static.
-* Constructors that call an internal function to return a newly-allocated
-reference type instance. Constructors are non-static methods that can
-optionally manipulate the primitive and reference type members.
-
-Reference types support a Java-style 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
-(is able to access as its own) all of A's fields and methods. Type B is
+A reference type is a named construct (object), potentially representing
+multiple pieces of data (member fields) and logic to manipulate that data
+(member methods), defined as part of the application programming interface
+(API) for scripts.
+
+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
+instance. Use a reference type instance to load from, store to, and manipulate
+complex data.
+
+A reference type value refers to a reference type instance, and multiple
+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
+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
+values. Pass `null` as an argument to a method/function call to indicate the
+argument refers to no reference type instance.
+
+A reference type object defines zero-to-many of each of the following:
+
+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
+storing to a specific reference type *object*. No reference type instance
+allocation is necessary to use a static member field.
+
+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.
+
+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.
+
+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.
+
+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 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
+(is able to access as its own) all of A's non-static members. Type B is
 considered a descendant of A if there exists a recursive parent-child
 considered a descendant of A if there exists a recursive parent-child
 relationship from B to A with none to many types in between. In this case, B
 relationship from B to A with none to many types in between. In this case, B
-inherits all of A's fields and methods along with all of the fields and
-methods of the types in between. Type B is also considered to be a type A
-in both relationships.
-
-For the complete list of Painless reference types and their supported methods,
-see the https://www.elastic.co/guide/en/elasticsearch/reference/current/painless-api-reference.html[Painless API Reference].
+inherits all of A's non-static members along with all of the non-static members
+of the types in between. Type B is also considered to be a type A in both
+relationships.
 
 
-For more information about working with reference types, see
-<<field-access, Accessing Fields>> and <<method-access, Calling Methods>>.
+*Examples*
 
 
-*Examples:*
-[source,Java]
+* Reference types evaluated in several different operations.
++
+[source,Painless]
+----
+<1> List l = new ArrayList();
+<2> l.add(1);
+<3> int i = l.get(0) + 2;
+----
++
+<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`;
+    implicit cast `int 1` to `def` -> `def`
+    call `add` on `List reference` with arguments (`def`)
+<3> declare `int i`;
+    access `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`
++
+* Sharing a reference type instance.
++
+[source,Painless]
 ----
 ----
-ArrayList al = new ArrayList();  // Declare variable al as an ArrayList and
-                                 //   set it to a newly allocated ArrayList
-List l = new ArrayList();        // Declare variable l as a List and set
-                                 //   it to a newly allocated ArrayList, which is
-                                 //   allowed because ArrayList inherits from List
-Map m;                           // Declare variable m as a Map and set it
-                                 //   to the default value of null
+<1> List l0 = new ArrayList();
+<2> List l1 = l0;
+<3> l0.add(1);
+<4> l1.add(2);
+<5> int i = l1.get(0) + l0.get(1);
 ----
 ----
++
+<1> declare `List l0`;
+    allocate `ArrayList` instance -> `ArrayList reference`;
+    implicit cast `ArrayList reference` to `List reference` -> `List reference`;
+    assign `List reference` to `l0`
+<2> declare `List l1`;
+    access `l0` -> `List reference`;
+    assign `List reference` to `l1`
+    (note `l0` and `l1` refer to the same instance known as a shallow-copy)
+<3> access `l0` -> `List reference`;
+    implicit cast `int 1` to `def` -> `def`
+    call `add` on `List reference` with arguments (`def`)
+<4> access `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`;
+    call `get` on `List reference` with arguments (`int 0`) -> `def @0`;
+    implicit cast `def @0` to `int 1` -> `int 1`;
+    access `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`;
++
+* Using the static members of a reference type.
++
+[source,Painless]
+----
+<1> int i = Integer.MAX_VALUE;
+<2> long l = Long.parseLong("123L");
+----
++
+<1> declare `int i`;
+    access `MAX_VALUE` on `Integer` -> `int 2147483647`;
+    assign `int 2147483647` to `i`
+<2> declare `long l`;
+    call `parseLong` on `Long` with arguments (`long 123`) -> `long 123`;
+    assign `long 123` to `l`
+
+[[dynamic-types]]
+==== Dynamic Types
+
+A dynamic type value can represent the value of any primitive type or
+reference type using a single type name `def`. A `def` type value mimics
+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.
+
+Using the `def` type can have a slight impact on performance. Use only primitive
+types and reference types directly when performance is critical.
+
+*Errors*
 
 
-Directly accessing static pieces of a reference type.
+* If a `def` type value represents an inappropriate type for evaluation of an
+  operation at run-time.
 
 
-[source,Java]
+*Examples*
+
+* General uses of the `def` type.
++
+[source,Painless]
+----
+<1> def dp = 1;
+<2> def dr = new ArrayList();
+<3> dr = dp;
+----
++
+<1> declare `def dp`;
+    implicit cast `int 1` to `def` -> `def`;
+    assign `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`;
+    (note the switch in the type `dr` represents from `ArrayList` to `int`)
++
+* A `def` type value representing the child-most descendant of a value.
++
+[source,Painless]
 ----
 ----
-Integer.MAX_VALUE      // a static field access
-Long.parseLong("123L") // a static function call
+<1> Object l = new ArrayList();
+<2> def d = l;
+<3> d.ensureCapacity(10);
 ----
 ----
++
+<1> declare `Object l`;
+    allocate `ArrayList` instance -> `ArrayList reference`;
+    implicit cast `ArrayList reference` to `Object reference`
+            -> `Object reference`;
+    assign `Object reference` to `l`
+<2> declare `def d`;
+    access `l` -> `Object reference`;
+    implicit cast `Object reference` to `def` -> `def`;
+    assign `def` to `d`;
+<3> access `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`
+            since ArrayList` is the child-most descendant type value that the
+            `def` type value represents)
 
 
 [[string-type]]
 [[string-type]]
 ==== String Type
 ==== String Type
 
 
-A `String` is a specialized reference type that is immutable and does not have
-to be explicitly allocated. You can directly assign to a `String` without first
-allocating it with the `new` keyword. (Strings can be allocated with the `new`
-keyword, but it's not required.)
+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
+instances.
 
 
-When assigning a value to a `String`, you must enclose the text in single or
-double quotes. Strings are allocated according to the standard Java Memory Model.
-The default value for a `String` is `null.`
+*Examples*
 
 
-*Examples:*
-[source,Java]
+* General use of the `String` type.
++
+[source,Painless]
 ----
 ----
-String r = "some text";             // Declare String r and set it to the
-                                    //   String "some text"
-String s = 'some text';             // Declare String s and set it to the
-                                    //   String 'some text'
-String t = new String("some text"); // Declare String t and set it to the
-                                    //   String "some text"
-String u;                           // Declare String u and set it to the
-                                    //   default value null
+<1> String r = "some text";
+<2> String s = 'some text';
+<3> String t = new String("some text");
+<4> String u;
 ----
 ----
++
+<1> declare `String r`;
+    assign `String "some text"` to `r`
+<2> declare `String s`;
+    assign `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`
+<4> declare `String u`;
+    assign default `null` to `u`
 
 
 [[void-type]]
 [[void-type]]
 ==== void Type
 ==== void Type
 
 
-The `void` type represents the concept of no type. In Painless, `void` declares
-that a function has no return value.
+The `void` type represents the concept of a lack of type. Use the `void` type to
+indicate a function returns no value.
 
 
-[[array-type]]
-==== Array Type
+*Examples*
 
 
-Arrays contain a series of elements of the same type that can be allocated
-simultaneously. Painless supports both single and multi-dimensional arrays for
-all types except void (including `def`).
-
-You declare an array by specifying a type followed by a series of empty brackets,
-where each set of brackets represents a dimension. Declared arrays have a default
-value of `null` and are themselves a reference type.
-
-To allocate an array, you use the `new` keyword followed by the type and a
-set of brackets for each dimension. You can explicitly define the size of each dimension by specifying an expression within the brackets, or initialize each
-dimension with the desired number of values. The allocated size of each
-dimension is its permanent size.
-
-To initialize an array, specify the values you want to initialize
-each dimension with as a comma-separated list of expressions enclosed in braces.
-For example, `new int[] {1, 2, 3}` creates a one-dimensional `int` array with a
-size of 3 and the values 1, 2, and 3.
+* Use of the `void` type in a function.
++
+[source,Painless]
+----
+void addToList(List l, def d) {
+    l.add(d);
+}
+----
 
 
-When you initialize an array, the order of the expressions is maintained. Each expression used as part of the initialization is converted to the
-array's type. An error occurs if the types do not match.
+[[array-type]]
+==== Array Type
 
 
-*Grammar:*
-[source,ANTLR4]
+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.
+
+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 <<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.
+
+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[][]`.
+
+*Examples*
+
+* General use of single-dimensional arrays.
++
+[source,Painless]
 ----
 ----
-declare_array: TYPE ('[' ']')+;
-
-array_initialization: 'new' TYPE '[' ']' '{' expression (',' expression) '}'
-                    | 'new' TYPE '[' ']' '{' '}';
+<1> int[] x;
+<2> float[] y = new float[10];
+<3> def z = new float[5];
+<4> y[9] = 1.0F;
+<5> z[0] = y[9];
 ----
 ----
-
-*Examples:*
-[source,Java]
++
+<1> declare `int[] x`;
+    assign 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`
+<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`;
+    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`
++
+* Use of a multi-dimensional array.
++
+[source,Painless]
 ----
 ----
-int[] x = new int[5];          // Declare int array x and assign it a newly
-                               //   allocated int array with a size of 5
-def[][] y = new def[5][5];     // Declare the 2-dimensional def array y and
-                               //   assign it a newly allocated 2-dimensional
-                               //   array where both dimensions have a size of 5
-int[] x = new int[] {1, 2, 3}; // Declare int array x and set it to an int
-                               //   array with values 1, 2, 3 and a size of 3
-int i = 1;
-long l = 2L;
-float f = 3.0F;
-double d = 4.0;
-String s = "5";
-def[] da = new def[] {i, l, f*d, s}; // Declare def array da and set it to
-                                     // a def array with a size of 4 and the
-                                     // values i, l, f*d, and s
+<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`;
+    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`
+<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`

+ 119 - 50
docs/painless/painless-variables.asciidoc

@@ -1,29 +1,31 @@
 [[painless-variables]]
 [[painless-variables]]
 === Variables
 === Variables
 
 
-<<declaration, Declare>> variables to <<assignment, assign>> values for
-<<painless-operators, use>> in expressions.  Specify variables as a
-<<primitive-types, primitive type>>, <<reference-types, reference type>>, or
-<<dynamic-types, dynamic type>>.  Variable operations follow the structure of a
-standard JVM in relation to instruction execution and memory usage.
+A variable loads and stores a value for evaluation during
+<<painless-operators, operations>>.
 
 
 [[declaration]]
 [[declaration]]
 ==== Declaration
 ==== Declaration
 
 
-Declare variables before use with the format of <<painless-types, type>>
-<<painless-identifiers, identifier>>. Specify a comma-separated list of
-<<painless-identifiers, identifiers>> following the <<painless-types, type>>
-to declare multiple variables in a single statement.  Use an
-<<assignment, assignment>> statement combined with a declaration statement to
-immediately assign a value to a variable. Variables not immediately assigned a
-value will have a default value assigned implicitly based on the
-<<painless-types, type>>.
+Declare a variable before use with the format of <<painless-types, type>>
+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.
+
+*Errors*
+
+* If a variable is used prior to or without declaration.
 
 
 *Grammar*
 *Grammar*
 [source,ANTLR4]
 [source,ANTLR4]
 ----
 ----
 declaration : type ID assignment? (',' ID assignment?)*;
 declaration : type ID assignment? (',' ID assignment?)*;
-type: ID ('[' ']')*;
+type: ID ('.' ID)* ('[' ']')*;
 assignment: '=' expression;
 assignment: '=' expression;
 ----
 ----
 
 
@@ -35,27 +37,43 @@ assignment: '=' expression;
 ----
 ----
 <1> int x;
 <1> int x;
 <2> List y;
 <2> List y;
-<3> int x, y, z;
-<4> def[] d;
+<3> int x, y = 5, z;
+<4> def d;
 <5> int i = 10;
 <5> int i = 10;
-----
-+
-<1> declare a variable of type `int` and identifier `x`
-<2> declare a variable of type `List` and identifier `y`
-<3> declare three variables of type `int` and identifiers `x`, `y`, `z`
-<4> declare a variable of type `def[]` and identifier `d`
-<5> declare a variable of type `int` and identifier `i`;
-    assign the integer literal `10` to `i`
+<6> float[] f;
+<7> Map[][] m;
+----
++
+<1> declare `int x`;
+    assign default `null` to `x`
+<2> declare `List y`;
+    assign default `null` to `y`
+<3> declare `int x`;
+    assign default `int 0` to `x`;
+    declare `int y`;
+    assign `int 5` to `y`;
+    declare `int z`;
+    assign default `int 0` to `z`;
+<4> declare `def d`;
+    assign default `null` to `d`
+<5> declare `int i`;
+    assign `int 10` to `i`
+<6> declare `float[] f`;
+    assign default `null` to `f`
+<7> declare `Map[][] m`;
+    assign default `null` to `m`
 
 
 [[assignment]]
 [[assignment]]
 ==== Assignment
 ==== Assignment
 
 
-Use the `equals` operator (`=`) to assign a value to a variable. Any expression
+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
 that produces a value can be assigned to any variable as long as the
-<<painless-types, types>> are the same or the resultant
-<<painless-types, type>> can be implicitly <<painless-casting, cast>> to
-the variable <<painless-types, type>>.  Otherwise, an error will occur.
-<<reference-types, Reference type>> values are shallow-copied when assigned.
+<<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*
 *Grammar*
 [source,ANTLR4]
 [source,ANTLR4]
@@ -65,7 +83,7 @@ assignment: ID '=' expression
 
 
 *Examples*
 *Examples*
 
 
-* Variable assignment with an <<integers, integer literal>>.
+* Variable assignment with an integer literal.
 +
 +
 [source,Painless]
 [source,Painless]
 ----
 ----
@@ -73,10 +91,11 @@ assignment: ID '=' expression
 <2> i = 10;
 <2> i = 10;
 ----
 ----
 +
 +
-<1> declare `int i`
-<2> assign `10` to `i`
+<1> declare `int i`;
+    assign default `int 0` to `i`
+<2> assign `int 10` to `i`
 +
 +
-* <<declaration, Declaration>> combined with immediate variable assignment.
+* Declaration combined with immediate assignment.
 +
 +
 [source,Painless]
 [source,Painless]
 ----
 ----
@@ -84,11 +103,12 @@ assignment: ID '=' expression
 <2> double j = 2.0;
 <2> double j = 2.0;
 ----
 ----
 +
 +
-<1> declare `int i`; assign `10` to `i`
-<2> declare `double j`; assign `2.0` to `j`
+<1> declare `int i`;
+    assign `int 10` to `i`
+<2> declare `double j`;
+    assign `double 2.0` to `j`
 +
 +
-* Assignment of one variable to another using
-<<primitive-types, primitive types>>.
+* Assignment of one variable to another using primitive types.
 +
 +
 [source,Painless]
 [source,Painless]
 ----
 ----
@@ -96,11 +116,13 @@ assignment: ID '=' expression
 <2> int j = i;
 <2> int j = i;
 ----
 ----
 +
 +
-<1> declare `int i`; assign `10` to `i`
-<2> declare `int j`; assign `j` to `i`
+<1> declare `int i`;
+    assign `int 10` to `i`
+<2> declare `int j`;
+    access `i` -> `int 10`;
+    assign `int 10` to `j`
 +
 +
-* Assignment with <<reference-types, reference types>> using the
-<<constructor-call, new operator>>.
+* Assignment with reference types using the *new instance operator*.
 +
 +
 [source,Painless]
 [source,Painless]
 ----
 ----
@@ -108,12 +130,15 @@ assignment: ID '=' expression
 <2> Map m = new HashMap();
 <2> Map m = new HashMap();
 ----
 ----
 +
 +
-<1> declare `ArrayList l`; assign a newly-allocated `Arraylist` to `l`
-<2> declare `Map m`; assign a newly-allocated `HashMap` to `m`
-    with an implicit cast to `Map`
+<1> declare `ArrayList l`;
+    allocate `ArrayList` instance -> `ArrayList reference`;
+    assign `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`
 +
 +
-* Assignment of one variable to another using
-<<reference-types, reference types>>.
+* Assignment of one variable to another using reference types.
 +
 +
 [source,Painless]
 [source,Painless]
 ----
 ----
@@ -123,8 +148,52 @@ assignment: ID '=' expression
 <4> m = k;
 <4> m = k;
 ----
 ----
 +
 +
-<1> declare `List l`; assign a newly-allocated `Arraylist` to `l`
-    with an implicit cast to `List`
-<2> declare `List k`; assign a shallow-copy of `l` to `k`
+<1> declare `List l`;
+    allocate `ArrayList` instance -> `ArrayList reference`;
+    implicit cast `ArrayList reference` to `List reference` -> `List reference`;
+    assign `List reference` to `l`
+<2> declare `List k`;
+    access `l` -> `List reference`;
+    assign `List reference` to `k`;
+    (note `l` and `k` refer to the same instance known as a shallow-copy)
 <3> declare `List m`;
 <3> declare `List m`;
-<4> assign a shallow-copy of `k` to `m`
+    assign default `null` to `m`
+<4> access `k` -> `List reference`;
+    assign `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*.
++
+[source,Painless]
+----
+<1> int[] ia1;
+<2> ia1 = new int[2];
+<3> ia1[0] = 1;
+<4> int[] ib1 = ia1;
+<5> int[][] ic2 = new int[2][5];
+<6> ic2[1][3] = 2;
+<7> ic2[0] = ia1;
+----
++
+<1> declare `int[] ia1`;
+    assign 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`
+<4> declare `int[] ib1`;
+    access `ia1` -> `1-d int array reference`;
+    assign `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
+            `index [0]` of `2-d int array reference`;
+    (note `ia1`, `ib1`, and `index [0]` of `ia2` refer to the same instance)