[[modules-scripting-painless-syntax]]
=== Painless Syntax

experimental[The Painless scripting language is new and is still marked as experimental. The syntax or API may be changed in the future in non-backwards compatible ways if required.]

[float]
[[painless-types]]
=== Variable types

Painless supports all of https://docs.oracle.com/javase/tutorial/java/nutsandbolts/variables.html[Java's types],
including array types, but adds some additional built-in types.

[float]
[[painless-def]]
==== Def

The dynamic type `def` serves as a placeholder for any other type. It adopts the behavior
of whatever runtime type it represents.

[float]
[[painless-strings]]
==== String

String constants can be declared with single quotes, to avoid escaping horrors with JSON:

[source,painless]
---------------------------------------------------------
def mystring = 'foo';
---------------------------------------------------------

[float]
[[painless-lists]]
==== List

Lists can be created explicitly (e.g. `new ArrayList()`) or initialized similar to Groovy:

[source,painless]
---------------------------------------------------------
def list = [1,2,3];
---------------------------------------------------------

Lists can also be accessed similar to arrays: they support subscript and `.length`:

[source,painless]
---------------------------------------------------------
def list = [1,2,3];
return list[0]
---------------------------------------------------------

[float]
[[painless-maps]]
==== Map

Maps can be created explicitly (e.g. `new HashMap()`) or initialized similar to Groovy:

[source,painless]
---------------------------------------------------------
def person = ['name': 'Joe', 'age': 63];
---------------------------------------------------------

Map keys can also be accessed as properties.

[source,painless]
---------------------------------------------------------
def person = ['name': 'Joe', 'age': 63];
person.retired = true;
return person.name
---------------------------------------------------------

Map keys can also be accessed via subscript (for keys containing special characters):

[source,painless]
---------------------------------------------------------
return map['something-absurd!']
---------------------------------------------------------

[float]
[[painless-pattern]]
==== Pattern

Regular expression constants are directly supported:

[source,painless]
---------------------------------------------------------
Pattern p = /[aeiou]/
---------------------------------------------------------

Patterns can only be created via this mechanism. This ensures fast performance, regular expressions
are always constants and compiled efficiently a single time.

[float]
[[modules-scripting-painless-regex-flags]]
==== Pattern flags

You can define flags on patterns in Painless by adding characters after the
trailing `/` like `/foo/i` or `/foo \w #comment/iUx`. Painless exposes all the
flags from
https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html[Java's Pattern class]
using these characters:

[cols="<,<,<",options="header",]
|=======================================================================
| Character | Java Constant | Example
|`c` | CANON_EQ                  | `'å' ==~ /å/c` (open in hex editor to see)
|`i` | CASE_INSENSITIVE          | `'A' ==~ /a/i`
|`l` | LITERAL                   | `'[a]' ==~ /[a]/l`
|`m` | MULTILINE                 | `'a\nb\nc' =~ /^b$/m`
|`s` | DOTALL (aka single line)  | `'a\nb\nc' =~ /.b./s`
|`U` | UNICODE_CHARACTER_CLASS   | `'Ɛ' ==~ /\\w/U`
|`u` | UNICODE_CASE              | `'Ɛ' ==~ /ɛ/iu`
|`x` | COMMENTS (aka extended)   | `'a' ==~ /a #comment/x`
|=======================================================================

[float]
[[painless-operators]]
=== Operators

All of Java's https://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html[operators] are
supported with the same precedence, promotion, and semantics.

There are only a few minor differences and add-ons:

* `==` behaves as Java's for numeric types, but for non-numeric types acts as https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#equals-java.lang.Object-[`Object.equals()`]
* `===` and `!==` support exact reference comparison (e.g. `x === y`)
* `=~` true if a portion of the text matches a pattern (e.g. `x =~ /b/`)
* `==~` true if the entire text matches a pattern (e.g. `x ==~ /[Bb]ob/`)

[float]
[[painless-control-flow]]
=== Control flow

Java's https://docs.oracle.com/javase/tutorial/java/nutsandbolts/flow.html[control flow statements] are supported, with the exception
of the `switch` statement.

In addition to Java's `enhanced for` loop, the `for in` syntax from groovy can also be used:

[source,painless]
---------------------------------------------------------
for (item : list) {
  ...
}
---------------------------------------------------------

[float]
[[painless-functions]]
=== Functions

Functions can be declared at the beginning of the script, for example:

[source,painless]
---------------------------------------------------------
boolean isNegative(def x) { x < 0 }
...
if (isNegative(someVar)) {
  ...
}
---------------------------------------------------------

[float]
[[painless-lambda-expressions]]
=== Lambda expressions
Lambda expressions and method references work the same as https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html[Java's].

[source,painless]
---------------------------------------------------------
list.removeIf(item -> item == 2);
list.removeIf((int item) -> item == 2);
list.removeIf((int item) -> { item == 2 });
list.sort((x, y) -> x - y);
list.sort(Integer::compare);
---------------------------------------------------------

Method references to functions within the script can be accomplished using `this`, e.g. `list.sort(this::mycompare)`.
