Painless Spec Documentation Clean Up (#29441)
Created a flatter structure for the different sections. Cleaned up comments, keywords, and literals. Used callouts for examples where it made sense.
This commit is contained in:
parent
7969eb7db7
commit
c833167d84
|
@ -5,39 +5,6 @@ include::../Versions.asciidoc[]
|
|||
|
||||
include::painless-getting-started.asciidoc[]
|
||||
|
||||
// include::painless-examples.asciidoc[]
|
||||
|
||||
// include::painless-design.asciidoc[]
|
||||
|
||||
include::painless-lang-spec.asciidoc[]
|
||||
|
||||
include::painless-syntax.asciidoc[]
|
||||
|
||||
include::painless-api-reference.asciidoc[]
|
||||
|
||||
////
|
||||
Proposed Outline (WIP)
|
||||
Getting Started with Painless
|
||||
Accessing Doc Values
|
||||
Updating Fields
|
||||
Working with Dates
|
||||
Using Regular Expressions
|
||||
Debugging Painless Scripts
|
||||
|
||||
Example Scripts
|
||||
Using Painless in Script Fields
|
||||
Using Painless in Watches
|
||||
Using Painless in Function Score Queries
|
||||
Using Painless in Script Queries
|
||||
Using Painless When Updating Docs
|
||||
Using Painless When Reindexing
|
||||
|
||||
How Painless Works
|
||||
Painless Architecture
|
||||
Dispatching Functions
|
||||
|
||||
Painless Language Specification
|
||||
Painless API
|
||||
////
|
||||
|
||||
Painless API Reference
|
||||
|
|
|
@ -1,17 +1,13 @@
|
|||
["appendix",id="painless-api-reference"]
|
||||
= Painless API Reference
|
||||
[[painless-api-reference]]
|
||||
== Painless API Reference
|
||||
|
||||
Painless has a strict whitelist for methods and
|
||||
classes to make sure that all painless scripts are secure and fast. Most of
|
||||
these methods are exposed directly from the JRE while others are part of
|
||||
Elasticsearch or Painless itself. Below is a list of all available methods
|
||||
grouped under the classes on which you can call them. Clicking on the method
|
||||
name takes you to the documentation for the method.
|
||||
|
||||
NOTE: Methods defined in the JRE also have a `(java 9)` link which can be used
|
||||
to see the method's documentation in Java 9 while clicking on the method's name
|
||||
goes to the Java 8 documentation. Usually these aren't different but it is
|
||||
worth going to the version that matches the version of Java you are using to
|
||||
run Elasticsearch just in case.
|
||||
Painless has a strict whitelist for methods and classes to ensure all
|
||||
painless scripts are secure. Most of these methods are exposed directly
|
||||
from the Java Runtime Enviroment (JRE) while others are part of
|
||||
Elasticsearch or Painless itself. Below is a list of all available
|
||||
classes grouped with their respected methods. Clicking on the method
|
||||
name takes you to the documentation for that specific method. Methods
|
||||
defined in the JRE also have a `(java 9)` link which can be used to see
|
||||
the method's documentation in Java 9.
|
||||
|
||||
include::painless-api-reference/index.asciidoc[]
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
[[painless-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.
|
||||
|
||||
To cast to a new type, precede the expression by the new type enclosed in
|
||||
parentheses, for example
|
||||
`(int)x`.
|
||||
|
||||
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`.
|
||||
|
||||
*Grammar:*
|
||||
[source,ANTLR4]
|
||||
----
|
||||
cast: '(' TYPE ')' expression
|
||||
----
|
||||
|
||||
[[numeric-casting]]
|
||||
==== Numeric Casting
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
|====
|
||||
| | 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 |
|
||||
|====
|
||||
|
||||
|
||||
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
|
||||
----
|
||||
|
||||
[[boxing-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.
|
||||
|
||||
There are two places Painless performs implicit boxing and unboxing:
|
||||
|
||||
* 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`.
|
||||
|
||||
The casting operator does not support any way to explicitly box a primitive
|
||||
type or unbox a reference 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:*
|
||||
[source,Java]
|
||||
----
|
||||
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
|
||||
----
|
||||
|
||||
[[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.
|
||||
|
||||
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.
|
||||
|
||||
*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.
|
||||
|
||||
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.
|
||||
----
|
|
@ -0,0 +1,51 @@
|
|||
[[painless-comments]]
|
||||
=== Comments
|
||||
|
||||
Painless supports both single-line and multi-line comments. Comments can be
|
||||
included anywhere 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.
|
||||
|
||||
*Grammar*
|
||||
[source,ANTLR4]
|
||||
----
|
||||
SINGLE_LINE_COMMENT: '//' .*? [\n\r];
|
||||
MULTI_LINE_COMMENT: '/*' .*? '*/';
|
||||
----
|
||||
|
||||
*Examples*
|
||||
|
||||
Single-line comments.
|
||||
|
||||
[source,Painless]
|
||||
----
|
||||
// single-line comment
|
||||
|
||||
int value; // single-line comment
|
||||
----
|
||||
|
||||
Multi-line comments.
|
||||
|
||||
[source,Painless]
|
||||
----
|
||||
/* multi-
|
||||
line
|
||||
comment */
|
||||
|
||||
int value; /* multi-
|
||||
line
|
||||
comment */ value = 0;
|
||||
|
||||
int value; /* multi-line
|
||||
comment */
|
||||
|
||||
/* multi-line
|
||||
comment */ int value;
|
||||
|
||||
int value; /* multi-line
|
||||
comment */ value = 0;
|
||||
|
||||
int value; /* multi-line comment */ value = 0;
|
||||
----
|
|
@ -2,7 +2,7 @@ _Painless_ is a simple, secure scripting language designed specifically for use
|
|||
with Elasticsearch. It is the default scripting language for Elasticsearch and
|
||||
can safely be used for inline and stored scripts. For a detailed description of
|
||||
the Painless syntax and language features, see the
|
||||
{painless}/painless-specification.html[Painless Language Specification].
|
||||
{painless}/painless-lang-spec.html[Painless Language Specification].
|
||||
|
||||
[[painless-features]]
|
||||
You can use Painless anywhere scripts can be used in Elasticsearch. Painless
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
[[painless-syntax]]
|
||||
=== Painless Syntax
|
||||
[[painless-general-syntax]]
|
||||
=== General Syntax
|
||||
|
||||
[float]
|
||||
[[control-flow]]
|
||||
==== Control flow
|
||||
|
||||
|
@ -17,7 +16,6 @@ for (item : list) {
|
|||
}
|
||||
---------------------------------------------------------
|
||||
|
||||
[float]
|
||||
[[functions]]
|
||||
==== Functions
|
||||
|
||||
|
@ -32,7 +30,6 @@ if (isNegative(someVar)) {
|
|||
}
|
||||
---------------------------------------------------------
|
||||
|
||||
[float]
|
||||
[[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].
|
||||
|
@ -49,7 +46,6 @@ list.sort(Integer::compare);
|
|||
You can make method references to functions within the script with `this`,
|
||||
for example `list.sort(this::mycompare)`.
|
||||
|
||||
[float]
|
||||
[[patterns]]
|
||||
==== Patterns
|
||||
|
||||
|
@ -62,7 +58,6 @@ are always constants and compiled efficiently a single time.
|
|||
Pattern p = /[aeiou]/
|
||||
---------------------------------------------------------
|
||||
|
||||
[float]
|
||||
[[pattern-flags]]
|
||||
===== Pattern flags
|
||||
|
||||
|
@ -84,34 +79,3 @@ Pattern class] using these characters:
|
|||
|`u` | UNICODE_CASE | `'Ɛ' ==~ /ɛ/iu`
|
||||
|`x` | COMMENTS (aka extended) | `'a' ==~ /a #comment/x`
|
||||
|=======================================================================
|
||||
|
||||
[float]
|
||||
[[painless-deref]]
|
||||
==== Dereferences
|
||||
|
||||
Like lots of languages, Painless uses `.` to reference fields and call methods:
|
||||
|
||||
[source,painless]
|
||||
---------------------------------------------------------
|
||||
String foo = 'foo';
|
||||
TypeWithGetterOrPublicField bar = new TypeWithGetterOrPublicField()
|
||||
return foo.length() + bar.x
|
||||
---------------------------------------------------------
|
||||
|
||||
Like Groovy, Painless uses `?.` to perform null-safe references, with the
|
||||
result being `null` if the left hand side is `null`:
|
||||
|
||||
[source,painless]
|
||||
---------------------------------------------------------
|
||||
String foo = null;
|
||||
return foo?.length() // Returns null
|
||||
---------------------------------------------------------
|
||||
|
||||
Unlike Groovy, Painless doesn't support writing to `null` values with this
|
||||
operator:
|
||||
|
||||
[source,painless]
|
||||
---------------------------------------------------------
|
||||
TypeWithSetterOrPublicField foo = null;
|
||||
foo?.x = 'bar' // Compile error
|
||||
---------------------------------------------------------
|
|
@ -0,0 +1,13 @@
|
|||
[[painless-keywords]]
|
||||
=== Keywords
|
||||
|
||||
The keywords in the table below are reserved for built-in language
|
||||
features. These keywords cannot be used as <<identifiers, identifiers>> or
|
||||
<<painless-types, types>>.
|
||||
|
||||
[cols="^1,^1,^1,^1,^1"]
|
||||
|====
|
||||
| if | else | while | do | for
|
||||
| in | continue | break | return | new
|
||||
| try | catch | throw | this | instanceof
|
||||
|====
|
|
@ -1,73 +1,34 @@
|
|||
[[painless-specification]]
|
||||
[[painless-lang-spec]]
|
||||
== Painless Language Specification
|
||||
|
||||
Painless uses a Java-style syntax that is similar to Groovy. In fact, most
|
||||
Painless scripts are also valid Groovy, and simple Groovy scripts are typically
|
||||
valid Painless. This specification assumes you have at least a passing
|
||||
familiarity with Java and related languages.
|
||||
|
||||
Painless is essentially a subset of Java with some additional scripting
|
||||
language features that make scripts easier to write. However, there are some
|
||||
important differences, particularly with the casting model. For more detailed
|
||||
Painless is a scripting language designed for security and performance.
|
||||
Painless syntax is similar to Java syntax along with some additional
|
||||
features such as dynamic typing, Map and List accessor shortcuts, and array
|
||||
initializers. As a direct comparison to Java, there are some important
|
||||
differences, especially related to the casting model. For more detailed
|
||||
conceptual information about the basic constructs that Java and Painless share,
|
||||
refer to the corresponding topics in the
|
||||
https://docs.oracle.com/javase/specs/jls/se8/html/index.html[Java Language
|
||||
Specification].
|
||||
|
||||
Painless scripts are parsed and compiled using the http://www.antlr.org/[ANTLR4]
|
||||
and http://asm.ow2.org/[ASM] libraries. Painless scripts are compiled directly
|
||||
into Java byte code and executed against a standard Java Virtual Machine. This
|
||||
specification uses ANTLR4 grammar notation to describe the allowed syntax.
|
||||
and http://asm.ow2.org/[ASM] libraries. Scripts are compiled directly
|
||||
into Java Virtual Machine (JVM) byte code and executed against a standard JVM.
|
||||
This specification uses ANTLR4 grammar notation to describe the allowed syntax.
|
||||
However, the actual Painless grammar is more compact than what is shown here.
|
||||
|
||||
[float]
|
||||
[[comments]]
|
||||
==== Comments
|
||||
include::painless-comments.asciidoc[]
|
||||
|
||||
Painless supports both single-line and multi-line comments. You can include
|
||||
comments anywhere within a script.
|
||||
|
||||
Single-line comments are preceded by two slashes: `// comment`. They can be
|
||||
placed anywhere on a line. All characters from the two slashes to the end of
|
||||
the line are ignored.
|
||||
|
||||
Multi-line comments are preceded by a slash-star `/*` and closed by
|
||||
star-slash `*/`. Multi-line comments can start anywhere on a line. All
|
||||
characters from the opening `/*` to the closing `*/` are ignored.
|
||||
|
||||
*Examples:*
|
||||
|
||||
[source,Java]
|
||||
----
|
||||
// single-line comment
|
||||
|
||||
<code> // single-line comment
|
||||
|
||||
/* multi-
|
||||
line
|
||||
comment */
|
||||
|
||||
<code> /* multi-line
|
||||
comment */ <code>
|
||||
|
||||
<code> /* multi-line comment */ <code>
|
||||
----
|
||||
|
||||
[float]
|
||||
[[keywords]]
|
||||
==== Keywords
|
||||
|
||||
Painless reserves the following keywords for built-in language features.
|
||||
These keywords cannot be used in other contexts, such as identifiers.
|
||||
|
||||
[cols="^1,^1,^1,^1,^1"]
|
||||
|====
|
||||
| if | else | while | do | for
|
||||
| in | continue | break | return | new
|
||||
| try | catch | throw | this | instanceof
|
||||
|====
|
||||
include::painless-keywords.asciidoc[]
|
||||
|
||||
include::painless-literals.asciidoc[]
|
||||
|
||||
include::painless-variables.asciidoc[]
|
||||
|
||||
include::painless-types.asciidoc[]
|
||||
|
||||
include::painless-casting.asciidoc[]
|
||||
|
||||
include::painless-operators.asciidoc[]
|
||||
|
||||
include::painless-general-syntax.asciidoc[]
|
||||
|
|
|
@ -1,94 +1,143 @@
|
|||
[[literals]]
|
||||
[[painless-literals]]
|
||||
=== Literals
|
||||
|
||||
Literals are values that you can specify directly in Painless scripts.
|
||||
Use literals to specify different types of values directly in a script.
|
||||
|
||||
[[integers]]
|
||||
==== Integers
|
||||
|
||||
Specify integer literals in decimal, octal, or hex notation. Use the following
|
||||
single letter designations to specify the primitive type: `l` for `long`, `f`
|
||||
for `float`, and `d` for `double`. If not specified, the type defaults to
|
||||
`int` (with the exception of certain assignments described later).
|
||||
Use integer literals to specify an integer value in decimal, octal, or hex
|
||||
notation of the <<primitive-types, primitive types>> `int`, `long`, `float`,
|
||||
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.
|
||||
|
||||
*Grammar:*
|
||||
*Grammar*
|
||||
[source,ANTLR4]
|
||||
----
|
||||
INTEGER: '-'? ( '0' | [1-9] [0-9]* ) [lLfFdD]?;
|
||||
OCTAL: '-'? '0' [0-7]+ [lL]?;
|
||||
HEX: '-'? '0' [xX] [0-9a-fA-F]+ [lL]?;
|
||||
OCTAL: '-'? '0' [0-7]+ [lL]?;
|
||||
HEX: '-'? '0' [xX] [0-9a-fA-F]+ [lL]?;
|
||||
----
|
||||
|
||||
*Examples:*
|
||||
[source,Java]
|
||||
*Examples*
|
||||
|
||||
Integer literals.
|
||||
|
||||
[source,Painless]
|
||||
----
|
||||
0 // integer literal of 0
|
||||
0D // double literal of 0.0
|
||||
1234L // long literal of 1234
|
||||
-90F // float literal of -90.0
|
||||
-022 // integer literal of -18 specified in octal
|
||||
0xF2A // integer literal of 3882
|
||||
0 <1>
|
||||
0D <2>
|
||||
1234L <3>
|
||||
-90f <4>
|
||||
-022 <5>
|
||||
0xF2A <6>
|
||||
----
|
||||
|
||||
[[floating-point-values]]
|
||||
==== Floating Point Values
|
||||
<1> `int 0`
|
||||
<2> `double 0.0`
|
||||
<3> `long 1234`
|
||||
<4> `float -90.0`
|
||||
<5> `int -18` in octal
|
||||
<6> `int 3882` in hex
|
||||
|
||||
Specify floating point literals using the following single letter designations
|
||||
for the primitive type: `f` for `float` and `d` for `double`.
|
||||
If not specified, the type defaults to `double`.
|
||||
[[floats]]
|
||||
==== Floats
|
||||
|
||||
*Grammar:*
|
||||
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`.
|
||||
|
||||
*Grammar*
|
||||
[source,ANTLR4]
|
||||
----
|
||||
DECIMAL: '-'? ( '0' | [1-9] [0-9]* ) (DOT [0-9]+)? ( [eE] [+\-]? [0-9]+ )? [fFdD]?;
|
||||
DECIMAL: '-'? ( '0' | [1-9] [0-9]* ) (DOT [0-9]+)? EXPONENT? [fFdD]?;
|
||||
EXPONENT: ( [eE] [+\-]? [0-9]+ );
|
||||
----
|
||||
|
||||
*Examples:*
|
||||
[source,Java]
|
||||
*Examples*
|
||||
|
||||
Floating point literals.
|
||||
|
||||
[source,Painless]
|
||||
----
|
||||
0.0 // double value of 0.0
|
||||
1E6 // double value of 1000000
|
||||
0.977777 // double value of 0.97777
|
||||
-126.34 // double value of -126.34
|
||||
89.9F // float value of 89.9
|
||||
0.0 <1>
|
||||
1E6 <2>
|
||||
0.977777 <3>
|
||||
-126.34 <4>
|
||||
89.9F <5>
|
||||
----
|
||||
|
||||
<1> `double 0.0`
|
||||
<2> `double 1000000.0` in exponent notation
|
||||
<3> `double 0.977777`
|
||||
<4> `double -126.34`
|
||||
<5> `float 89.9`
|
||||
|
||||
[[strings]]
|
||||
==== Strings
|
||||
|
||||
Specify literal string with either single or double quotes. In double-quoted
|
||||
literal strings, you can escape double-quotes with a backslash to include them
|
||||
in the string. Similarly, you escape single quotes with a backslash in
|
||||
single-quoted literal strings. Backslashes themselves also need to be
|
||||
escaped with a backslash.
|
||||
Use string literals to specify string values of the
|
||||
<<string-type, String type>> with 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 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:*
|
||||
*Grammar*
|
||||
[source,ANTLR4]
|
||||
----
|
||||
STRING: ( '"' ( '\\"' | '\\\\' | ~[\\"] )*? '"' ) | ( '\'' ( '\\\'' | '\\\\' | ~[\\'] )*? '\'' );
|
||||
STRING: ( '"' ( '\\"' | '\\\\' | ~[\\"] )*? '"' )
|
||||
| ( '\'' ( '\\\'' | '\\\\' | ~[\\'] )*? '\'' );
|
||||
----
|
||||
|
||||
*Examples:*
|
||||
[source,Java]
|
||||
*Examples*
|
||||
|
||||
String literals using single-quotes.
|
||||
|
||||
[source,Painless]
|
||||
----
|
||||
"double-quoted String literal"
|
||||
'single-quoted String literal'
|
||||
"\"double-quoted String with escaped double-quotes\" and backslash: \\"
|
||||
'\'single-quoted String with escaped single-quotes\' and backslash \\'
|
||||
"double-quoted String with non-escaped 'single-quotes'"
|
||||
'single-quoted String with non-escaped "double-quotes"'
|
||||
'single-quoted string literal'
|
||||
'\'single-quoted string with escaped single-quotes\' and backslash \\'
|
||||
'single-quoted string with non-escaped "double-quotes"'
|
||||
----
|
||||
|
||||
[[char]]
|
||||
===== Char
|
||||
String literals using double-quotes.
|
||||
|
||||
You cannot directly specify character literals in Painless. However, you can
|
||||
cast single-character strings to char. Attempting to cast a multi-character
|
||||
string to a char throws an error.
|
||||
[source,Painless]
|
||||
----
|
||||
"double-quoted string literal"
|
||||
"\"double-quoted string with escaped double-quotes\" and backslash: \\"
|
||||
"double-quoted string with non-escaped 'single-quotes'"
|
||||
----
|
||||
|
||||
*Examples:*
|
||||
[source,Java]
|
||||
[[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;
|
||||
----
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
[[painless-operators]]
|
||||
=== Operators
|
||||
|
||||
The following is a table of the available operators in Painless. Each operator will have further information and examples outside of the table. Many operators will have a promotion table as described by the documentation on promotion [MARK].
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[[types]]
|
||||
=== Data Types
|
||||
[[painless-types]]
|
||||
=== Types
|
||||
|
||||
Painless supports both dynamic and static types. Static types are split into
|
||||
_primitive types_ and _reference types_.
|
||||
|
@ -267,176 +267,3 @@ 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
|
||||
----
|
||||
|
||||
[[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.
|
||||
|
||||
To cast to a new type, precede the expression by the new type enclosed in
|
||||
parentheses, for example
|
||||
`(int)x`.
|
||||
|
||||
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`.
|
||||
|
||||
*Grammar:*
|
||||
[source,ANTLR4]
|
||||
----
|
||||
cast: '(' TYPE ')' expression
|
||||
----
|
||||
|
||||
[[numeric-casting]]
|
||||
==== Numeric Casting
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
|====
|
||||
| | 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 |
|
||||
|====
|
||||
|
||||
|
||||
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
|
||||
----
|
||||
|
||||
[[boxing-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.
|
||||
|
||||
There are two places Painless performs implicit boxing and unboxing:
|
||||
|
||||
* 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`.
|
||||
|
||||
The casting operator does not support any way to explicitly box a primitive
|
||||
type or unbox a reference 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:*
|
||||
[source,Java]
|
||||
----
|
||||
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
|
||||
----
|
||||
|
||||
[[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.
|
||||
|
||||
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.
|
||||
|
||||
*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.
|
||||
|
||||
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.
|
||||
----
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
[[variables]]
|
||||
[[painless-variables]]
|
||||
=== Variables
|
||||
|
||||
Variables in Painless must be declared and can be statically or <<dynamic-types,
|
||||
dynamically typed>>.
|
||||
Variables in Painless must be declared and can be
|
||||
statically or <<dynamic-types, dynamically typed>>.
|
||||
|
||||
[[variable-identifiers]]
|
||||
==== Variable Identifiers
|
||||
[[identifiers]]
|
||||
==== Identifiers
|
||||
|
||||
Specify variable identifiers using the following grammar. Variable identifiers
|
||||
must start with a letter or underscore. You cannot use <<keywords, keywords>> or
|
||||
<<types, types>> as identifiers.
|
||||
must start with a letter or underscore. You cannot use
|
||||
<<painless-keywords, keywords>> or <<painless-types, types>> as identifiers.
|
||||
|
||||
*Grammar:*
|
||||
[source,ANTLR4]
|
||||
|
@ -20,7 +20,6 @@ ID: [_a-zA-Z] [_a-zA-Z-0-9]*;
|
|||
*Examples:*
|
||||
[source,Java]
|
||||
----
|
||||
_
|
||||
a
|
||||
Z
|
||||
id
|
||||
|
@ -30,8 +29,8 @@ MAP25
|
|||
_map25
|
||||
----
|
||||
|
||||
[[variable-declaration]]
|
||||
==== Variable Declaration
|
||||
[[declaration]]
|
||||
==== Declaration
|
||||
|
||||
Variables must be declared before you use them. The format is `type-name
|
||||
identifier-name`. To declare multiple variables of the same type, specify a
|
||||
|
@ -56,7 +55,7 @@ int i = 10; // Declare the int variable i and set it to the int literal 10
|
|||
----
|
||||
|
||||
[[variable-assignment]]
|
||||
==== Variable Assignment
|
||||
==== Assignment
|
||||
|
||||
Use the equals operator (`=`) to assign a value to a variable. The format is
|
||||
`identifier-name = value`. Any value expression can be assigned to any variable
|
||||
|
@ -80,7 +79,7 @@ int i; // Declare an int i
|
|||
i = 10; // Set the int i to the int literal 10
|
||||
----
|
||||
|
||||
Immediately assigning a value when declaring a variable.
|
||||
Immediately assigning a value when declaring a variable.
|
||||
|
||||
[source,Java]
|
||||
----
|
||||
|
|
|
@ -489,7 +489,7 @@ Using `_index` in scripts has been replaced with writing `ScriptEngine` backends
|
|||
=== Painless Syntax
|
||||
|
||||
See the
|
||||
{painless}/painless-specification.html[Painless Language Specification]
|
||||
{painless}/painless-lang-spec.html[Painless Language Specification]
|
||||
in the guide to the {painless}/index.html[Painless Scripting Language].
|
||||
|
||||
[role="exclude",id="modules-scripting-painless-debugging"]
|
||||
|
|
Loading…
Reference in New Issue