OpenSearch/docs/painless/painless-operators.asciidoc

1775 lines
81 KiB
Plaintext

=== 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].
[options="header",cols="6,3,2,4"]
|====
|Operator|Symbol(s)|Precedence|Associativity
|Precedence|()|0|left-to-right
|Field Access|.|1|left-to-right
|Method Call|. ()|1|left-to-right
|Null Safe|?.|1|left-to-right
|Function Call|()|1|left-to-right
|Array Initialization|[] {}|1|left-to-right
|Array Access|[]|1|left-to-right
|Array Length|.|1|left-to-right
|List Initialization|[]|1|left-to-right
|List Access|[]|1|left-to-right
|Map Initialization|[:]|1|left-to-right
|Map Access|[]|1|left-to-right
|Post Increment|++|1|left-to-right
|Post Decrement|--|1|left-to-right
|Pre Increment|++|2|right-to-left
|Pre Decrement|--|2|right-to-left
|Unary Positive|+|2|right-to-left
|Unary Negative|-|2|right-to-left
|Boolean Not|!|2|right-to-left
|Bitwise Not|~|2|right-to-left
|Cast|()|3|right-to-left
|Constructor Call|new ()|3|right-to-left
|New Array|new|3|right-to-left
|Multiplication|*|4|left-to-right
|Division|/|4|left-to-right
|Remainder|%|4|left-to-right
|String Concatenation|+|5|left-to-right
|Addition|+|5|left-to-right
|Subtraction|-|5|left-to-right
|Left Shift|<<|6|left-to-right
|Right Shift|>>|6|left-to-right
|Unsigned Right Shift|>>>|6|left-to-right
|Greater Than|>|7|left-to-right
|Greater Than Or Equal|>=|7|left-to-right
|Less Than|<|7|left-to-right
|Less Than Or Equal|<=|7|left-to-right
|Instance Of|instanceof|8|left-to-right
|Equality Equals|==|9|left-to-right
|Equality Not Equals|!=|9|left-to-right
|Identity Equals|===|9|left-to-right
|Identity Not Equals|!==|9|left-to-right
|Bitwise And|&|10|left-to-right
|Boolean Xor|^|11|left-to-right
|Bitwise Xor|^|11|left-to-right
|Bitwise Or|\||12|left-to-right
|Boolean And|&&|13|left-to-right
|Boolean Or|\|\||14|left-to-right
|Conditional|? :|15|right-to-left
|Elvis|?:|16|right-to-left
|Assignment|=|17|right-to-left
|Compound Assignment|$=|17|right-to-left
|====
[[precedence-operator]]
==== Precedence
You group expressions using the precedence operator to guarantee
the order of evaluation and override existing precedence relationships between operators. The format is an opening parenthesis, one or more expressions, and
a closing parenthesis. For example, `(20+1)*2`.
*Grammar:*
[source,ANTLR4]
----
precedence: '(' expression ')';
----
*Examples:*
[source,Java]
----
int x = (5+4)*6; // declares the variable int x and sets it to (5+4)*6
// where 5+4 is evaluated first due to the precedence operator
int y = 2*(x-4); // declares the variable int y and sets it to 2*(x-4)
// where x-4 is evaluated first due to the precedence operator
----
[[dot-operator]]
==== Dot
You use the dot operator `.` to access a type's <<field-access,
fields>> and <<method-access, methods>>.
[[field-access]]
===== Accessing Fields
You access primitive and reference type members in a reference type using the
dot operator '.' followed by the id of the member. The accessed member behaves
the same way as the type it represents with one exception: if the reference
type is of type `def`, the member is also considered to be of type `def` and
resolved at runtime.
*Grammar:*
[source,ANTLR4]
----
field_access: ID '.' ID;
----
*Examples:*
[source,Java]
----
FeatureTest ft = new FeatureTest(); // Declare FeatureTest variable ft and
// set it to a newly allocated FeatureTest
ft.x = 5; // Access int member x from ft and assign
// it the literal int value 5
ft.y = ft.x; // Access int member y from ft and assign
// it the value of ft member x
int value = ft.x + ft.y; // Declare variable value as an int,
// add ft members x and y together,
// assign the sum to the variable value
----
[[method-access]]
===== Calling Methods
You call reference type methods using the dot operator and the method id:
`.method_id(arg1,...,argn)`. The parentheses are required even if there are no
arguments.
If the reference type is not type `def`, the argument types for the method
can be resolved at compile time. An error occurs if appropriate type
conversions (casting) cannot be performed. If the reference type is type `def`, the argument types for the method are all considered to be the type `def`. The
appropriate type conversions are performed at run-time.
Automatic <<boxing-unboxing,boxing and unboxing>> is performed when you pass in
arguments to a method.
Method calls can be overloaded based on arity in Painless. The same method
name can be re-used for different methods as long as the number of arguments
differs. This differs from Java method overloading, where only the types must
differ. This has an effect on some of the provided reference type methods in
the <<painless-api-reference,Painless API>>. Where there are overloaded methods with
the same arity for a reference type in Java, Painless chooses a single method
to be provided.
*Grammar:*
[source,ANTLR4]
----
method_call: ID '.' ID '(' (expression (',' expression)*)? ')';
----
*Examples:*
[source,Java]
----
Map m = new HashMap(); // Declare Map variable m and set it a newly
// allocated HashMap
x.put(1, 2); // Call the put method on variable x to add key 1
// with the value 2 to the Map
int z = x.get(1); // Declare int variable z, call the get method to
// retrieve the value of key 1, and assign the
// return value of the method call to variable z
def d = new ArrayList(); // Declare def variable m and set it a newly
// allocated ArrayList
d.add(1); // Call the add method on variable d and add the
// literal int 1 to the ArrayList. Note that
// the argument type is considered to be of
// type def since the reference type is also def
int i = Integer.parseInt('2'); // Declare int variable i and set it to the
// value returned by the static method parseInt
----
**************************
Painless describes the Map method arguments using the `def` type:
[source,Java]
----
put(def, def)
get(def)
----
When you call `x.put(1, 2)`, the key and value are implicitly converted from
the int type to the def type.
Assume for a minute that the Map method arguments were described as Integers:
[source,Java]
----
put(Integer, Integer)
get(Integer)
----
In this case, the key and value would implicitly be _boxed_ from the primitive
int type to the Integer reference type. For more information about how Painless
casts between primitive types and reference types, see <<boxing-unboxing, Boxing
and Unboxing>>.
**************************
==== Null Safe
The null safe operator `?.` can be used in place of the dot operator
to check if a reference type instance is `null` before attempting to access
a field or make a method call against it. When using the null safe operator,
if the instance is `null`, the returned value is `null`. If the reference
type instance is non-null, it returns the value of the field or result of
the method call normally.
// REVIEWER NOTE: The following paragraph doesn't make sense to me. Do you
All resultant types must be a reference type or be able to be implicitly cast
to a reference type or an error will occur.
*Grammar:*
[source,ANTLR4]
----
null_safe: null_safe_field_access
| null_safe_method_call;
null_safe_field_access: ID '?.' ID;
null_safe_method_call: ID '?.' ID '(' (expression (',' expression)*)? ')';
----
*Examples:*
[source,Java]
----
Map x = new HashMap(); // Declare the Map variable x and set it to a newly
// allocated HashMap
Map y = null; // Declare the Map variable y and set it to null
def z = new HashMap(); // Declares the def variable z and set it to a newly
// allocated HashMap
x.put(1, 2); // Put the key-value pair 1 and 2 into x
z.put(5, 6); // Put the key-value pair 5 and 6 into z
def value = x?.get(1); // Declare the def variable value and set it to the
// result of .get(1) since x is not null
value = y?.get(3); // Sets value to null since y is null
value = z?.get(5); // Sets value to the result of .get(5) since z is not null
----
==== Parenthesis
User-defined function calls can be made in Painless using the parenthesis
operator. See Function Calls [MARK] for more information.
==== Brackets and Braces
The brackets operator `[]` is used to create and access arrays, lists, and maps.
The braces operator `{}` is used to intialize arrays.
===== Creating and Initializing Arrays
You create and initialize arrays using the brackets `[]` and braces `{}`
operators. Each set of brackets represents a dimension. The values you want to
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`
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>>.
===== Accessing Array Elements
Elements in an array are stored and accessed using the brackets `[]` operator.
Elements are referenced by an expression enclosed in brackets. An error
occurs if the expression used to reference an element cannot be implicitly
cast to an `int`.
The range of elements within an array that can be accessed is `[0, size)` where
size is the originally allocated size of the array. To access elements relative
to the last element in an array, you can use a negative numeric value from
`[-size, -1]`. An error occurs if you attempt to reference an element outside
of the array's range.
*Grammar:*
[source,ANTLR4]
----
brace_access: '[' expression ']'
----
*Examples:*
[source,Java]
----
int[] x = new int[2]; // Declare int array x and set it to a newly allocated
// array with a size of 2
x[0] = 2; // Set the 0th element of array x to 2
x[1] = 5; // Set the 1st element of array x to 5
int y = x[0] + x[1]; // Declare the int variable y and set it to the sum
// of the first two elements of array x
int z = 1; // Declare the int variable z and set it to 1
return x[z]; // Access the 1st element of array x using the
// variable z as an expression and return the value
def d = new int[2]; // Declare def variable d and set it to a newly
// allocated array with a size of 2
d[0] = 2; // Set the 0th element of array d to 2
d[1] = 5; // Set the 1st element of array d to 2
def y = d[0] + d[1]; // Declare def variable y and set it to the sum
// of the first two elements of array d
def z = 1; // Declare def variable z and set it to 1
return d[z]; // Access the 1st element of array d using the
// variable z as an expression and return the value
----
NOTE: The use of the `def` type in the second example means that the types
cannot be resolved until runtime.
===== 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.
*Examples:*
[source,Java]
----
int[] x = new int[10]; // declares an int array variable x and sets it to a newly allocated array with a size of 10
int l = x.length; // declares and int variable l and sets it to the field length of variable x
----
===== Creating and Initializing Lists
You create and initialize lists using the brackets `[]` operator. The values
you want to initialize the list with are specified as a comma-separated list
of expressions enclosed in brackets. For example, `List l = [1, 2, 3]` creates
a new three item list. Each expression used to initialize the list is converted
a `def` type when the value is inserted into the list. The order of the
expressions is maintained.
*Grammar:*
[source,ANTLR4]
----
list_initialization: '[' expression (',' expression)* ']'
| '[' ']';
----
*Examples:*
[source,Java]
----
List empty = []; // declares the List variable empty and sets it to a newly initialized empty List
List l0 = [1, 2, 3]; // declares the List variable l0 and sets it to a newly initialized List with the values 1, 2, and 3
int i = 1;
long l = 2L;
float f = 3.0F;
double d = 4.0;
String s = "5";
List l1 = [i, l, f*d, s]; // declares the List variable l1 and sets it to a newly initialized List with the values of i, l, and f*d and s
----
===== Accessing List Elements
Elements in a List are stored or accessed using the brackets operator. The format begins with an opening bracket, followed by an expression, and finishes with a closing bracket. Storing elements in a List is equivalent to invoking a List's set method. Accessing elements in a List is equivalent to invoking a List's get method. Using this operator is strictly a shortcut for the previously mentioned methods. The range of elements within a List that can be accessed is [0, size) where size is the number of elements currently in the List. Elements may also be accessed from the last element in a List using a negative numeric value from [-size, -1]. The expression used to determine which element is accessed must be able to be implicitly cast to an int. An error will occur if the expression is outside of the legal range or is not of type int.
*Grammar:*
[source,ANTLR4]
----
list_access: '[' expression ']'
----
*Examples:*
[source,Java]
----
List x = new ArrayList(); // declares a List variable x and sets it to a newly allocated ArrayList
x.add(1); // invokes the add method on the variable x and adds the constant int 1 to the List
x.add(2); // invokes the add method on the variable x and adds the constant int 2 to the List
x.add(3); // invokes the add method on the variable x and adds the constant int 3 to the List
x[0] = 2; // sets the 0th element of the variable x to the constant int 2
x[1] = 5; // sets the 1st element of the variable x to the constant int 2
int y = x[0] + x[1]; // declares the int variable y and sets it to the sum of the first two elements of the variable x
int z = 1; // declares the int variable z and sets it to the constant int 1
return x[z]; // accesses the 1st element of the variable x using the variable z as an expression and returns the value
def d = new ArrayList(); // declares a def variable d and sets it to a newly allocated ArrayList
d.add(1); // invokes the add method on the variable d and adds the constant int 1 to the List
d.add(2); // invokes the add method on the variable d and adds the constant int 2 to the List
d.add(3); // invokes the add method on the variable d and adds the constant int 3 to the List
d[0] = 2; // sets the 0th element of the variable d to the constant int 2
d[1] = 5; // sets the 1st element of the variable d to the constant int 2
def y = d[0] + d[1]; // declares the def variable y and sets it to the sum of the first two elements of the variable d
def z = 1; // declares the def variable z and sets it to the constant int 1
return d[z]; // accesses the 1st element of the variable d using the variable z as an expression and returns the value
----
Note in the first example above all types can be resolved at compile-time, while in the second example all types must wait to be resolved until run-time.
===== Creating and Initializing Maps
A Map can be created and initialized using the brackets operator. The format begins with a bracket, followed by an arbitrary number of key-value pairs delimited with commas (except the last), and ends with a closing bracket. Each key-value pair is a set of two expressions separate by a colon. If there is only a single colon with no expressions, a new empty Map is created.
*Grammar:*
[source,ANTLR4]
----
map_initialization: '[' key_pair (',' key_pair)* ']'
| '[' ':' ']';
key_pair: expression ':' expression
----
Each expression used as part of the initialization is converted to a `def` type
for insertion into the map.
*Examples:*
[source,Java]
----
Map empty = [:]; // declares the Map variable empty and sets it to a newly initialized empty Map
Map m0 = [1:2, 3:4, 5:6]; // declares the Map variable m0 and sets it to a newly initialized Map with the keys 1, 3, 5 and values 2, 4, 6, respectively
byte b = 0;
int i = 1;
long l = 2L;
float f = 3.0F;
double d = 4.0;
String s = "5";
Map m1 = [b:i, l:f*d, d:s]; // declares the Map variable m1 and sets it to a newly initialized Map with the keys b, l, d and values i, f*d, s, respectively
----
===== Accessing Map Elements
Elements in a Map can be stored or accessed using the brackets operator. The format begins with an opening bracket, followed by an expression, and finishes with a closing bracket. Storing values in a Map is equivalent to invoking a Map's put method. Accessing values in a Map is equivalent to invoking a Map's get method. Using this operator is strictly a shortcut for the previously mentioned methods. Any element from a Map can be stored/accessed where the expression is the key. If a key has no corresponding value when accessing a Map then the value will be null.
*Grammar:*
[source,ANTLR4]
----
map_access: '[' expression ']'
----
*Examples:*
[source,Java]
----
Map x = new HashMap(); // declares a Map variable x and sets it to a newly allocated HashMap
x['value2'] = 2; // puts the value of the key constant String value2 of the variable x to the constant int 2
x['value5'] = 5; // puts the value of the key constant String value5 of the variable x to the constant int 5
int y = x['value2'] + x['value5']; // declares the int variable y and sets it to the sum of the two values of the variable x
String z = 'value5'; // declares the String variable z and sets it to the constant String value5
return x[z]; // accesses the value for the key value5 of the variable x using the variable z as an expression and returns the value
def d = new HashMap(); // declares a def variable d and sets it to a newly allocated HashMap
d['value2'] = 2; // puts the value of the key constant String value2 of the variable d to the constant int 2
d['value5'] = 5; // puts the value of the key constant String value5 of the variable d to the constant int 5
int y = d['value2'] + d['value5']; // declares the int variable y and sets it to the sum of the two values of the variable d
String z = 'value5'; // declares the String variable z and sets it to the constant String value5
return d[z]; // accesses the value for the key value5 of the variable x using the variable z as an expression and returns the value
----
Note in the first example above all types can be resolved at compile-time, while in the second example all types must wait to be resolved until run-time.
==== Post Increment
A variable/field representing a numerical value can be possibly evaluated as part of an expression, and then increased by 1 for its respective type. The format starts with a variable name followed by a plus and ends with a plus.
*Grammar:*
[source,ANTLR4]
----
post_increment: ( variable | member ) '++'
----
A numeric promotion may occur during a post-increment followed by a downcast if necessary. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. A downcast may be required after the type promotion to assign the appropriate value back into the variable/field. Non-numeric variables/members will result in an error.
Promotion Table:
|====
|from|to|downcast
|byte|int|byte
|short|int|short
|char|int|char
|int|int|
|long|long|
|float|float|
|double|double|
|def|def|
|====
Examples(s):
[source,Java]
----
int i = 0; // declares the int variable i and sets it to the constant 0
i++; // increments the int variable i by 1 to a value of 1
long l = 1; // declares the long variable l and set it the constant 1
long k; // declares the long variable k
k = l++; // sets the long variable k to the value of l (1), and then increments the long variable l by 1 to a value of 2
----
==== Post Decrement
A variable/field representing a numerical value can be possibly evaluated as part of an expression, and then increased by 1 for its respective type. The format starts with a variable name followed by a minus and ends with a minus.
*Grammar:*
[source,ANTLR4]
----
post_increment: ( variable | member ) '--'
----
A numeric promotion may occur during a post-decrement followed by a downcast if necessary. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. A downcast may be required after the type promotion to assign the appropriate value back into the variable/field. Non-numeric variables/members will result in an error.
Promotion Table:
|====
|from|to|downcast
|byte|int|byte
|short|int|short
|char|int|char
|int|int|
|long|long|
|float|float|
|double|double|
|def|def|
|====
Examples(s):
[source,Java]
----
short i = 0; // declares the short variable i and sets it to the constant short 0
i--; // decrements the short variable i by 1 to a value of -1 (promoted to int and downcast to short)
float l = 1.0f; // declares the float variable l and sets it the constant float 1.0f
float k; // declares the float variable k
k = l--; // sets the float variable k to the value of l (1.0f), and then decrements the float variable l by 1.0 to a value of 0.0
----
==== Pre Increment
A variable/field representing a numerical value can be increased by 1 for its respective type, and then possibly evaluated as part of an expression. The format starts with a plus followed by a plus and ends with a variable name.
*Grammar:*
[source,ANTLR4]
----
pre_increment: '++' ( variable | member )
----
A numeric promotion may occur during a pre-increment followed by a downcast if necessary. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. A downcast may be required after the type promotion to assign the appropriate value back into the variable/field. Non-numeric variables/members will result in an error.
Promotion Table:
|====
|from|to|downcast
|byte|int|byte
|short|int|short
|char|int|char
|int|int|
|long|long|
|float|float|
|double|double|
|def|def|
|====
Examples(s):
[source,Java]
----
int i = 0; // declares the int variable i and sets it to the constant int 0
++i; // increments the int variable i by 1 to a value of 1
long l = 1; // declares the long variable l and sets it to the constant long 1
long k; // declares the long variable k
k = ++l; // increments the long variable l by 1 to a value of 2, and then sets the long variable k to the value of l (2)
----
==== Pre Decrement
A variable/field representing a numerical value can be decreased by 1 for its respective type, and then possibly evaluated as part of an expression. The format starts with a minus followed by a minus and ends with a variable name.
*Grammar:*
[source,ANTLR4]
----
pre_decrement: '--' ( variable | member )
----
A numeric promotion may occur during a pre-decrement followed by a downcast if necessary. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. A downcast may be required after the type promotion to assign the appropriate value back into the variable/field. Non-numeric variables/members will result in an error.
Promotion Table:
|====
|from|to|downcast
|byte|int|byte
|short|int|short
|char|int|char
|int|int|
|long|long|
|float|float|
|double|double|
|def|def|
|====
Examples(s):
[source,Java]
----
byte i = 1; // declares the byte variable i and sets it to the constant int 1
--i; // decrements the byte variable i by 1 to a value of 0 (promoted to int and downcast to byte)
double l = 1.0; // declares the double variable l and sets it to the constant double 1.0
double k; // declares the double variable k
k = --l; // decrements the double variable l by 1.0 to a value of 0.0, and then sets the double variable k to the value of l (0.0)
----
==== Unary Positive
Unary positive gives the identity of a numerical value using the plus operator. In practice this is usually a no-op, but will cause some numeric types to be promoted. Format starts with a plus operator followed by a numerical expression.
*Grammar:*
[source,ANTLR4]
----
unary_positive: '+' expression
----
A numeric promotion may occur during a unary positive operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric expressions will result in an error.
Promotion Table:
|====
|from|to
|byte|int
|short|int
|char|int
|int|int
|long|long
|float|float
|double|double
|def|def
|====
*Examples:*
[source,Java]
----
int x = +1; // declares the int variable x and sets it to positive 1
long y = +x; // declares the long variable y and sets it to positive x (promoted to long from int)
def z = +y; // declares the def variable z and sets it to positive y
byte z = +2; //ERROR: cannot implicitly downcast an int to a byte
----
==== Unary Negative
Unary negative negates a numeric value using the minus operator. Format starts with a minus followed by a numerical expression.
*Grammar:*
[source,ANTLR4]
----
unary_negative: '-' expression
----
A numeric promotion may occur during a unary negative operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric expressions will result in an error.
Promotion Table:
|====
|from|to
|byte|int
|short|int
|char|int
|int|int
|long|long
|float|float
|double|double
|def|def
|====
*Examples:*
[source,Java]
----
int x = -1; // declares the int variable x and sets it to negative 1
long y = -x; // declares the long variable y and sets it to negative x (promoted to long from int)
def z = -y; // declares the def variable z and sets it to negative y
byte z = -2; //ERROR: cannot implicitly downcast an int to a byte
----
==== Boolean Not
Boolean not will flip a boolean value from true to false or false to true using the bang operator. The format is a bang operator followed by an expression.
*Grammar:*
[source,ANTLR4]
----
boolean_not: '!' expression;
----
Note that def types will be assumed to be of the boolean type. Any def type evaluated at run-time that does not represent a boolean will result in an error. Non-boolean expressions will result in an error.
*Examples:*
[source,Java]
----
boolean x = !false; // declares the boolean variable x and sets it to the the opposite of the false value
boolean y = !x; // declares the boolean variable y and sets it to the opposite of the boolean variable x
def z = !y; // declares the def variable z and sets it to the opposite of the boolean variable y
----
==== Bitwise Not
Bitwise not will flip each bit of an integer type expression. The format is the tilde operator followed by an expression.
*Grammar:*
[source,ANTLR4]
----
bitwise_not: '~' expression;
----
A numeric promotion may occur during unary positive operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-integer expressions will result in an error.
Promotion Table:
|====
|from|to
|byte|int
|short|int
|char|int
|int|int
|long|long
|def|def
|====
*Examples:*
[source,Java]
----
byte x = 1; // declares the byte variable x and sets it to a constant int 1
int y = ~x; // declares the int variable y and sets it to the negation of x
long z = ~y; // declares the long variable z and sets it the negation of y
def d = ~z; // declares the def variable d and sets it the negation of z
def e; // declares the def variable e
e = ~d; // sets e the negation of d
----
==== Cast
The cast operator can be used to explicitly convert one type to another. See casting [MARK] for more information.
==== Constructor Call
A constructor call is a special type of method call [MARK] used to allocate a reference type instance using the new operator. The format is the new operator followed by a type, an opening parenthesis, arguments if any, and a closing parenthesis. Arguments are a series of zero-to-many expressions delimited by commas. Auto-boxing and auto-unboxing will be applied automatically for arguments passed into a constructor call. See boxing and unboxing [MARK] for more information on this topic. Constructor argument types can always be resolved at run-time; if appropriate type conversions (casting) cannot be applied an error will occur. Once a reference type instance has been allocated, its members may be used as part of other expressions.
Constructor calls may be overloaded based on arity in Painless. This means the same reference type may have multiple constructors as long as the number of arguments differs for each one. This does have an effect on some of the provided reference type constructors in the Painless API [MARK]. When there are overloaded constructors with the same arity for a reference type in Java a single constructor must be chosen to be provided in Painless.
*Grammar:*
[source,ANTLR4]
----
constructor_call: 'new' TYPE '(' (expression (',' expression)*)? ')';
----
*Examples:*
[source,Java]
----
Map m = new HashMap(); // declares the Map variable m and sets it to a newly allocated HashMap using an empty constructor
m.put(3, 3); // invokes the method call member put and adds the key-value pair of 3 to Map variable m
def d = new ArrayList(); // declares the def variable d and sets it to a newly allocated ArrayList using an empty constructor
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
----
==== 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.
*Grammar:*
[source,ANTLR4]
----
new_array: 'new' TYPE ('[' expression ']')+;
----
*Examples:*
[source,Java]
----
int[] x = new int[5]; // declares an int array variable x and sets it to a newly allocated array with a size of 5
x = new int[10]; // sets the int array variable x to a newly allocated array with a size of 10
def[][] y = new def[5][5]; // declares a 2-dimensional def array variable y and set it to a newly
// allocated 2-dimensional array where both dimensions have a size of 5
----
==== Multiplication
Multiplies two numerical expressions. Rules for resultant overflow and NaN values follow the Java specification. The format is an expression, followed by the star operator, and a closing expression.
*Grammar:*
[source,ANTLR4]
----
multiplication: expression '*' expression;
----
A numeric promotion may occur during a multiplication operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric numbers will result in an error.
Promotion Table:
|====
||byte|short|char|int|long|float|double|def
|byte|int|int|int|int|long|float|double|def
|short|int|int|int|int|long|float|double|def
|char|int|int|int|int|long|float|double|def
|int|int|int|int|int|long|float|double|def
|long|long|long|long|long|long|float|double|def
|float|float|float|float|float|float|float|double|def
|double|double|double|double|double|double|double|double|def
|def|def|def|def|def|def|def|def|def
|====
*Examples:*
[source,Java]
----
int x = 5*4; // declares the int variable x and sets it to the result of 5 multiplied by 4
double y = x*7.0; // declares the double variable y and sets it to the result of x multiplied by 7.0 (x is promoted to a double)
def z = x*y; // declares the def variable z and sets it to the result of x multiplied by y (x is promoted to a double)
def a = z*x; // declares the def variable a and sets it to the result of z multiplied by x (x is promoted to def at compile-time and double at run-time)
----
==== Division
Divides two numerical expressions. Rules for NaN values and division by zero follow the Java specification. Integer division will drop the remainder of the resultant value. The format is an expression, followed by the slash operator, and a closing expression.
*Grammar:*
[source,ANTLR4]
----
division: expression '/' expression;
----
A numeric promotion may occur during a division operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric expressions will result in an error.
Promotion Table:
|====
||byte|short|char|int|long|float|double|def
|byte|int|int|int|int|long|float|double|def
|short|int|int|int|int|long|float|double|def
|char|int|int|int|int|long|float|double|def
|int|int|int|int|int|long|float|double|def
|long|long|long|long|long|long|float|double|def
|float|float|float|float|float|float|float|double|def
|double|double|double|double|double|double|double|double|def
|def|def|def|def|def|def|def|def|def
|====
*Examples:*
[source,Java]
----
int x = 5/4; // declares the int variable x and sets it to the result of 5 divided by 4
double y = x/7.0; // declares the double variable y and sets it to the result of x divided by 7.0 (x is promoted to a double)
def z = x/y; // declares the def variable z and sets it to the result of x divided by y (x is promoted to a double)
def a = z/x; // declares the def variable a and sets it to the result of z divided by x (x is promoted to def at compile-time and double at run-time)
----
==== Remainder
Calculates the remainder for division between two numerical expressions. Rules for NaN values and division by zero follow the Java specification. The format is an expression, followed by the percent operator, and a closing expression.
*Grammar:*
[source,ANTLR4]
----
remainder: expression '%' expression;
----
A numeric promotion may occur during a remainder operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric expressions will result in an error.
Promotion Table:
|====
||byte|short|char|int|long|float|double|def
|byte|int|int|int|int|long|float|double|def
|short|int|int|int|int|long|float|double|def
|char|int|int|int|int|long|float|double|def
|int|int|int|int|int|long|float|double|def
|long|long|long|long|long|long|float|double|def
|float|float|float|float|float|float|float|double|def
|double|double|double|double|double|double|double|double|def
|def|def|def|def|def|def|def|def|def
|====
*Examples:*
[source,Java]
----
int x = 5%4; // declares the int variable x and sets it to the remainder of 5 divided by 4
double y = x%7.0; // declares the double variable y and sets it to the remainder of x divided by 7.0 (x is promoted to a double)
def z = x%y; // declares the def variable z and sets it to the remainder of x divided by y (x is promoted to a double)
def a = z%x; // declares the def variable a and sets it to the remainder of z divided by x (x is promoted to def at compile-time and double at run-time)
----
==== String Concatenation
Concatenates two expressions together as a single String where at least of one of the expressions is a String to begin with. The format is an expression, followed by a plus operator, and a closing expression.
*Grammar:*
[source,ANTLR4]
----
concatenate: expression '+' expression;
----
*Examples:*
[source,Java]
----
String x = "con"; // declares the String variable x and sets it to the String constant "con"
String y = x + "cat"; // declares the String variable y and sets it to the concatenation of the String variable x and the String constant "cat"
String z = 4 + x; // declares the String variable z and sets it to the concatenation of the int constant 4 and the String variable x (4 is implicitly cast to a String)
def d = 2; // declares the def variable d and sets it to the int constant 2
z = z + d; // sets the String variable z to the concatenation of the String variable z
d = "con" + x + y + "cat"; // sets the def variable d to the concatenation of String constant "con", x, y, and the String constant "cat"
----
==== Addition
Adds two numerical expressions. Rules for resultant overflow and NaN values follow the Java specification. The format is an expression, followed by the plus operator, and a closing expression.
*Grammar:*
[source,ANTLR4]
----
addition: expression '+' expression;
----
A numeric promotion may occur during a addition operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric expressions will result in an error, except in the case of String which then implies the operation is string concatenation [MARK] rather than addition.
Promotion Table:
|====
||byte|short|char|int|long|float|double|def
|byte|int|int|int|int|long|float|double|def
|short|int|int|int|int|long|float|double|def
|char|int|int|int|int|long|float|double|def
|int|int|int|int|int|long|float|double|def
|long|long|long|long|long|long|float|double|def
|float|float|float|float|float|float|float|double|def
|double|double|double|double|double|double|double|double|def
|def|def|def|def|def|def|def|def|def
|====
*Examples:*
[source,Java]
----
int x = 5 + 4; // declares the int variable x and sets it to the result of 5 added to 4
double y = x + 7.0; // declares the double variable y and sets it to the result of x added to 7.0 (x is promoted to a double)
def z = x + y; // declares the def variable z and sets it to the result of x added to y (x is promoted to a double)
def a = z + x; // declares the def variable a and sets it to the result of z added to x (x is promoted to def at compile-time and double at run-time)
----
==== Subtraction
Subtracts two numerical expressions. Rules for resultant overflow and NaN values follow the Java specification. The format is an expression, followed by the minus operator, and a closing expression.
*Grammar:*
[source,ANTLR4]
----
subtraction: expression '-' expression;
----
A numeric promotion may occur during a subtraction operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric expressions will result in an error.
Promotion Table:
|====
||byte|short|char|int|long|float|double|def
|byte|int|int|int|int|long|float|double|def
|short|int|int|int|int|long|float|double|def
|char|int|int|int|int|long|float|double|def
|int|int|int|int|int|long|float|double|def
|long|long|long|long|long|long|float|double|def
|float|float|float|float|float|float|float|double|def
|double|double|double|double|double|double|double|double|def
|def|def|def|def|def|def|def|def|def
|====
*Examples:*
[source,Java]
----
int x = 5-4; // declares the int variable x and sets it to the result of 4 subtracted from 5
double y = x-7.0; // declares the double variable y and sets it to the result of 7.0 subtracted from x (x is promoted to a double)
def z = x-y; // declares the def variable z and sets it to the result of y subtracted from x (x is promoted to a double)
def a = z-x; // declares the def variable a and sets it to the result of x subtracted from z (x is promoted to def at compile-time and double at run-time)
----
==== Left Shift
Shifts lower order bits to higher order bits in the left-side expression by the distance specified in the right-side expression. The format is an expression followed by two left-carrots, and a closing expression.
*Grammar:*
[source,ANTLR4]
----
left_shift: expression '<<' expression;
----
A numeric promotion may occur during a left shift operation to the left-side expression. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric and floating point expressions will result in an error.
Promotion Table:
|====
|from|to
|byte|int
|short|int
|char|int
|int|int
|long|long
|def|def
|====
The right-side expression will be explicitly cast to an int value and truncated based on the promoted type of the left-side expression. If the left-side expression is of type int then the lowest order 5-bits will be taken as the distance to shift from the right-side expression (0-31). If the left-side expression is of type long then the lowest order 6-bits will be taken as the distance to shift from the right-side expression (0-63). Non-numeric and floating point expressions will result in an error.
*Examples:*
[source,Java]
----
int x = 5 << 4; // declares the int variable x and sets it to the result of 5 left shifted by 4
long y = x << 7; // declares the long variable y and sets it to the result of x left shifted by 7 (x is promoted to a long)
def z = x << y; // declares the def variable z and sets it to the result of x left shifted by y
def a = z << x; // declares the def variable a and sets it to the result of z left shifted by x
----
==== Right Shift
Shifts higher order bits to lower order bits in the left-side expression by the distance specified in the right-side expression. Right shift will preserve the signed bit (highest order bit) as part of the result. The format is an expression followed by two right-carrots, and a closing expression.
*Grammar:*
[source,ANTLR4]
----
right_shift: expression '>>' expression;
----
A numeric promotion may occur during a right shift operation to the left-side expression. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric and floating point expressions will result in an error.
Promotion Table:
|====
|from|to
|byte|int
|short|int
|char|int
|int|int
|long|long
|def|def
|====
The right-side expression will be explicitly cast to an int value and truncated based on the promoted type of the left-side expression. If the left-side expression is of type int then the lowest order 5-bits will be taken as the distance to shift from the right-side expression (0-31). If the left-side expression is of type long then the lowest order 6-bits will be taken as the distance to shift from the right-side expression (0-63). Non-numeric and floating point expressions will result in an error.
*Examples:*
[source,Java]
----
int x = 5 >> 4; // declares the int variable x and sets it to the result of 5 right shifted by 4
long y = x >> 7; // declares the long variable y and sets it to the result of x right shifted by 7 (x is promoted to a long)
def z = x >> y; // declares the def variable z and sets it to the result of x right shifted by y
def a = z >> x; // declares the def variable a and sets it to the result of z right shifted by x
----
==== Unsigned Right Shift
Shifts higher order bits to lower order bits in the left-side expression by the distance specified in the right-side expression. Unsigned right shift will not preserve the signed bit (highest order bit) as part of the result. The format is an expression followed by three right-carrots, and a closing expression.
*Grammar:*
[source,ANTLR4]
----
unsigned_right_shift: expression '>>>' expression;
----
A numeric promotion may occur during an unsigned right shift operation to the left-side expression. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric and floating point expressions will result in an error.
Promotion Table:
|====
|from|to
|byte|int
|short|int
|char|int
|int|int
|long|long
|def|def
|====
The right-side expression will be explicitly cast to an int value and truncated based on the promoted type of the left-side expression. If the left-side expression is of type int then the lowest order 5-bits will be taken as the distance to shift from the right-side expression (0-31). If the left-side expression is of type long then the lowest order 6-bits will be taken as the distance to shift from the right-side expression (0-63). Non-numeric and floating point expressions will result in an error.
*Examples:*
[source,Java]
----
int x = 5 >> 4; // declares the int variable x and sets it to the result of 5 unsigned right shifted by 4
long y = x >> 7; // declares the long variable y and sets it to the result of x unsigned right shifted by 7 (x is promoted to a long)
def z = x >> y; // declares the def variable z and sets it to the result of x unsigned right shifted by y
def a = z >> x; // declares the def variable a and sets it to the result of z unsigned right shifted by x
----
==== Greater Than
Greater than compares two numerical expressions where a resultant boolean value will be true if the left-side expression is a larger value than the right-side expression otherwise false. The format is an expression, followed by the right angle operator, and a closing expression.
*Grammar:*
[source,ANTLR4]
----
greater_than: expression '>' expression;
----
A numeric promotion may occur during a greater than operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric expressions will result in an error.
Promotion Table:
|====
||byte|short|char|int|long|float|double|def
|byte|int|int|int|int|long|float|double|def
|short|int|int|int|int|long|float|double|def
|char|int|int|int|int|long|float|double|def
|int|int|int|int|int|long|float|double|def
|long|long|long|long|long|long|float|double|def
|float|float|float|float|float|float|float|double|def
|double|double|double|double|double|double|double|double|def
|def|def|def|def|def|def|def|def|def
|====
*Examples:*
[source,Java]
----
boolean x = 5 > 4; // declares the int variable x and sets it to the result of 5 greater than 4
double y = 7.0; // declares the double variable y and sets it to the double constant 7.0
def z = y > 6.5; // declares the def variable z and sets it to the result of y greater than 6.5
def a = y > x; // declares the def variable a and sets it to the result of y greater than z (x is promoted to double at compile-time)
----
==== Greater Than Or Equal
Greater than or equal compares two numerical expressions where a resultant boolean value will be true if the left-side expression is a larger value than or equal to the right-side expression otherwise false. The format is an expression, followed by the right angle and equals operator, and a closing expression.
*Grammar:*
[source,ANTLR4]
----
greater_than_or_equal: expression '>=' expression;
----
A numeric promotion may occur during a greater than or equal operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric expressions will result in an error.
Promotion Table:
|====
||byte|short|char|int|long|float|double|def
|byte|int|int|int|int|long|float|double|def
|short|int|int|int|int|long|float|double|def
|char|int|int|int|int|long|float|double|def
|int|int|int|int|int|long|float|double|def
|long|long|long|long|long|long|float|double|def
|float|float|float|float|float|float|float|double|def
|double|double|double|double|double|double|double|double|def
|def|def|def|def|def|def|def|def|def
|====
*Examples:*
[source,Java]
----
boolean x = 5 >= 4; // declares the int variable x and sets it to the result of 5 greater than or equal to 4
double y = 7.0; // declares the double variable y and sets it to the double constant 7.0
def z = y >= 6.5; // declares the def variable z and sets it to the result of y greater than or equal to 6.5
def a = y >= x; // declares the def variable a and sets it to the result of y greater than or equal to z (x is promoted to double at compile-time)
----
==== Less Than
Less than compares two numerical expressions where a resultant boolean value will be true if the left-side expression is a smaller value than the right-side expression otherwise false. The format is an expression, followed by the left angle operator, and a closing expression.
*Grammar:*
[source,ANTLR4]
----
less_than: expression '<' expression;
----
A numeric promotion may occur during a less than operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric expressions will result in an error.
Promotion Table:
|====
||byte|short|char|int|long|float|double|def
|byte|int|int|int|int|long|float|double|def
|short|int|int|int|int|long|float|double|def
|char|int|int|int|int|long|float|double|def
|int|int|int|int|int|long|float|double|def
|long|long|long|long|long|long|float|double|def
|float|float|float|float|float|float|float|double|def
|double|double|double|double|double|double|double|double|def
|def|def|def|def|def|def|def|def|def
|====
*Examples:*
[source,Java]
----
boolean x = 5 < 4; // declares the int variable x and sets it to the result of 5 less than 4
double y = 7.0; // declares the double variable y and sets it to the double constant 7.0
def z = y < 6.5; // declares the def variable z and sets it to the result of y less than 6.5
def a = y < x; // declares the def variable a and sets it to the result of y less than z (x is promoted to double at compile-time)
----
==== Less Than Or Equal
Less than or equal compares two numerical expressions where a resultant boolean value will be true if the left-side expression is a larger value than or equal to the right-side expression otherwise false. The format is an expression, followed by the left angle and equals operator, and a closing expression.
*Grammar:*
[source,ANTLR4]
----
less_than_or_equal: expression '<=' expression;
----
A numeric promotion may occur during a less than or equal operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-numeric expressions will result in an error.
Promotion Table:
|====
||byte|short|char|int|long|float|double|def
|byte|int|int|int|int|long|float|double|def
|short|int|int|int|int|long|float|double|def
|char|int|int|int|int|long|float|double|def
|int|int|int|int|int|long|float|double|def
|long|long|long|long|long|long|float|double|def
|float|float|float|float|float|float|float|double|def
|double|double|double|double|double|double|double|double|def
|def|def|def|def|def|def|def|def|def
|====
*Examples:*
[source,Java]
----
boolean x = 5 <= 4; // declares the int variable x and sets it to the result of 5 less than or equal to 4
double y = 7.0; // declares the double variable y and sets it to the double constant 7.0
def z = y <= 6.5; // declares the def variable z and sets it to the result of y less than or equal to 6.5
def a = y <= x; // declares the def variable a and sets it to the result of y less than or equal to z (x is promoted to double at compile-time)
----
==== Instance Of
The instanceof operator can be used to compare a variable's type to a specified reference type where a resultant boolean value is true if the variable type is the same as or a descendant of the specified reference type and false otherwise. The format is an id, followed by the instanceof operator, and finished with a type.
*Grammar:*
[source,ANTLR4]
----
instance_of: ID 'instanceof' TYPE;
----
*Examples:*
[source,Java]
----
Map x = new HashMap(); // declares the Map variable x and sets it to a newly allocated HashMap
List y = new ArrayList(); // declares the List variable y and sets it to a newly allocated ArrayList
def z = y; // declares the def variable z and sets it to y
boolean a = x instanceof HashMap; // declares the boolean variable a and sets it to true since x's type is the same type as HashMap
boolean b = y instanceof Map; // declares the boolean variable b and sets it to false since y's type is not the same type as Map or a descendant of Map
boolean c = z instanceof List; // declares the boolean variable c and sets it to true since z's type is a descendant of the type List
----
==== Equality Equals
Equality equals compares two expressions where a resultant boolean value is true if the two expressions are equal and false otherwise. When reference types are compared using this operator the equivalent of the equals member method will be called against the first expression, where the second expression is the argument. Though the equals member method is used for reference types, this operation will always be null-safe. Valid comparisons are between boolean types, primitive numeric types, and reference types. If a comparison is made that is not listed as one of the valid comparisons an error will occur. The format is an expression, followed by the equals-equals operator, and finished with an expression.
*Grammar:*
[source,ANTLR4]
----
equality_equals: expression '==' expression;
----
A numeric type promotion may occur during a primitive numeric comparison. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents.
Promotion Table:
|====
||byte|short|char|int|long|float|double|def
|byte|int|int|int|int|long|float|double|def
|short|int|int|int|int|long|float|double|def
|char|int|int|int|int|long|float|double|def
|int|int|int|int|int|long|float|double|def
|long|long|long|long|long|long|float|double|def
|float|float|float|float|float|float|float|double|def
|double|double|double|double|double|double|double|double|def
|def|def|def|def|def|def|def|def|def
|====
*Examples:*
[source,Java]
----
boolean b0 = true; // declares the boolean variable b0 and sets it the constant boolean true
boolean b1 = false; // declares the boolean variable b1 and sets it the constant boolean false
int i = 2; // declares the int variable i and sets it the constant int 2
float f = 2.0f; // declares the float variable f and sets it the constant float 2.0
List l0 = new ArrayList(); // declares the List variable l0 and sets it to a newly allocated ArrayList
ArrayList l1 = new ArrayList(); // declares the ArrayList variable l1 and sets it to a newly allocated ArrayList
def di0 = 2; // declares the def variable di0 and sets it the constant int 2
def di1 = 3; // declares the def variable di1 and sets it the constant int 3
def dl = new ArrayList(); // declares the def variable dl and sets it to a newly allocated ArrayList
boolean result; // declares the boolean variable result
result = b0 == b1; // compares b0 to b1 and has a boolean result of false
result = i == f; // compares i to f where i is promoted to float and has a boolean result of true
result = b0 == i; // ERROR: a comparison between a boolean and a primitive numeric type is illegal
result = i == l0; // ERROR: a comparison between a primitive numeric type and a reference type is illegal
l0.add(1); // adds a constant int 1 to the List l0
l1.add(1); // adds a constant int 1 to the ArrayList l1
result = l0 == l1; // compares l0 to l1 using l0.equals(l1) and has a boolean result of true
l0.add(1); // adds a constant int 1 to the List l0
result = l0 == l1; // compares l0 to l1 using l0.equals(l1) and has a boolean result of false
result = di0 == di1; // compares di0 to di1 and has a boolean result of false
result = di0 == i; // compares di0 to i where i is promoted to def and has a boolean result of true
dl.add(1); // adds a constant int 1 to the def ArrayList dl
result = dl == l0; // compares dl to l0 using dl.equals(l0) with a boolean result of true
result = null == dl; // compares null to dl with a boolean result of false
result = l1 == null; // compares l1 to null with a boolean result of false
----
==== Equality Not Equals
Equality not equals compares two expressions where a resultant boolean value is true if the two expressions are not equal and false otherwise. When reference types are compared using this operator the equivalent of the equals member method will be called against the first expression, where the second expression is the argument, with the resultant boolean being reversed. Though the equals member method is used for reference types, this operation will always be null-safe. Valid comparisons are between boolean types, primitive numeric types, and reference types. If a comparison is made that is not listed as one of the valid comparisons an error will occur. The format is an expression, followed by the bang-equals operator, and finished with an expression.
*Grammar:*
[source,ANTLR4]
----
equality_not_equals: expression '!=' expression;
----
A numeric type promotion may occur during a primitive numeric comparison. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents.
Promotion Table:
|====
||byte|short|char|int|long|float|double|def
|byte|int|int|int|int|long|float|double|def
|short|int|int|int|int|long|float|double|def
|char|int|int|int|int|long|float|double|def
|int|int|int|int|int|long|float|double|def
|long|long|long|long|long|long|float|double|def
|float|float|float|float|float|float|float|double|def
|double|double|double|double|double|double|double|double|def
|def|def|def|def|def|def|def|def|def
|====
*Examples:*
[source,Java]
----
boolean b0 = true; // declares the boolean variable b0 and sets it the constant boolean true
boolean b1 = false; // declares the boolean variable b1 and sets it the constant boolean false
int i = 2; // declares the int variable i and sets it the constant int 2
float f = 2.0f; // declares the float variable f and sets it the constant float 2.0
List l0 = new ArrayList(); // declares the List variable l0 and sets it to a newly allocated ArrayList
ArrayList l1 = new ArrayList(); // declares the ArrayList variable l1 and sets it to a newly allocated ArrayList
def di0 = 2; // declares the def variable di0 and sets it the constant int 2
def di1 = 3; // declares the def variable di1 and sets it the constant int 3
def dl = new ArrayList(); // declares the def variable dl and sets it to a newly allocated ArrayList
boolean result; // declares the boolean variable result
result = b0 != b1; // compares b0 to b1 and has a boolean result of true
result = i != f; // compares i to f where i is promoted to float and has a boolean result of false
result = b0 != i; // ERROR: a comparison between a boolean and a primitive numeric type is illegal
result = i != l0; // ERROR: a comparison between a primitive numeric type and a reference type is illegal
l0.add(1); // adds a constant int 1 to the List l0
l1.add(1); // adds a constant int 1 to the ArrayList l1
result = l0 != l1; // compares l0 to l1 using l0.equals(l1) and has a boolean result of false
l0.add(1); // adds a constant int 1 to the List l0
result = l0 != l1; // compares l0 to l1 using l0.equals(l1) and has a boolean result of true
result = di0 != di1; // compares di0 to di1 and has a boolean result of true
result = di0 != i; // compares di0 to i where i is promoted to def and has a boolean result of false
dl.add(1); // adds a constant int 1 to the def ArrayList dl
result = dl != l0; // compares dl to l0 using dl.equals(l0) with a boolean result of false
result = null != dl; // compares null to dl with a boolean result of true
result = l1 != null; // compares null to l1 with a boolean result of true
----
==== Identity Equals
Identity equals compares two expressions where a resultant boolean value is true if the two expressions are equal and false otherwise. Two primitive types are considered to be equal if they have the same value. Two reference types are considered to be equal if they refer to the exact same instance in memory or are both null. Valid comparisons are between boolean types, primitive numeric types, and reference types. If a comparison is made that is not listed as one of the valid comparisons an error will occur. The format is an expression, followed by the equals-equals-equals operator, and finished with an expression.
*Grammar:*
[source,ANTLR4]
----
identity_equals: expression '===' expression;
----
A numeric type promotion may occur during a primitive numeric comparison. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents.
Promotion Table:
|====
||byte|short|char|int|long|float|double|def
|byte|int|int|int|int|long|float|double|def
|short|int|int|int|int|long|float|double|def
|char|int|int|int|int|long|float|double|def
|int|int|int|int|int|long|float|double|def
|long|long|long|long|long|long|float|double|def
|float|float|float|float|float|float|float|double|def
|double|double|double|double|double|double|double|double|def
|def|def|def|def|def|def|def|def|def
|====
*Examples:*
[source,Java]
----
boolean b0 = true; // declares the boolean variable b0 and sets it the constant boolean true
boolean b1 = false; // declares the boolean variable b1 and sets it the constant boolean false
int i = 2; // declares the int variable i and sets it the constant int 2
float f = 2.0f; // declares the float variable f and sets it the constant float 2.0
List l0 = new ArrayList(); // declares the List variable l0 and sets it to a newly allocated ArrayList
ArrayList l1 = new ArrayList(); // declares the ArrayList variable l1 and sets it to a newly allocated ArrayList
List l2 = l1; // declares the List variable l2 and sets it to l1
def di0 = 2; // declares the def variable di0 and sets it the constant int 2
def di1 = 3; // declares the def variable di1 and sets it the constant int 3
def dl = l0; // declares the def variable dl and sets it to l0
boolean result; // declares the boolean variable result
result = b0 === b1; // compares b0 to b1 and has a boolean result of false
result = i === f; // compares i to f where i is promoted to float and has a boolean result of true
result = b0 === i; // ERROR: a comparison between a boolean and a primitive numeric type is illegal
result = i === l0; // ERROR: a comparison between a primitive numeric type and a reference type is illegal
l0.add(1); // adds a constant int 1 to the List l0
l1.add(1); // adds a constant int 1 to the ArrayList l1
result = l0 === l1; // compares l0 to l1 and has a boolean result of false
l0.add(1); // adds a constant int 1 to the List l0
result = l0 === l1; // compares l0 to l1 and has a boolean result of false
result = l1 === l2; // compares l1 to l2 and has a boolean result of true
result = di0 === di1; // compares di0 to di1 and has a boolean result of false
result = di0 === i; // compares di0 to i where i is promoted to def and has a boolean result of true
result = dl === l0; // compares dl to l0 with a boolean result of true
result = null === dl; // compares null to dl with a boolean result of false
result = l1 === null; // compares null to l1 with a boolean result of false
----
==== Identity Not Equals
Identity not equals compares two expressions where a resultant boolean value is true if the two expressions are not equal and false otherwise. Two primitive types are considered to be not equal if they have different values. Two reference types are considered to be not equal if they refer to the different instances in memory or one is null and the other is not. Valid comparisons are between boolean types, primitive numeric types, and reference types. If a comparison is made that is not listed as one of the valid comparisons an error will occur. The format is an expression, followed by the bang-equals-equals operator, and finished with an expression.
*Grammar:*
[source,ANTLR4]
----
identity_not_equals: expression '!==' expression;
----
A numeric type promotion may occur during a primitive numeric comparison. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents.
Promotion Table:
|====
||byte|short|char|int|long|float|double|def
|byte|int|int|int|int|long|float|double|def
|short|int|int|int|int|long|float|double|def
|char|int|int|int|int|long|float|double|def
|int|int|int|int|int|long|float|double|def
|long|long|long|long|long|long|float|double|def
|float|float|float|float|float|float|float|double|def
|double|double|double|double|double|double|double|double|def
|def|def|def|def|def|def|def|def|def
|====
*Examples:*
[source,Java]
----
boolean b0 = true; // declares the boolean variable b0 and sets it the constant boolean true
boolean b1 = false; // declares the boolean variable b1 and sets it the constant boolean false
int i = 2; // declares the int variable i and sets it the constant int 2
float f = 2.0f; // declares the float variable f and sets it the constant float 2.0
List l0 = new ArrayList(); // declares the List variable l0 and sets it to a newly allocated ArrayList
ArrayList l1 = new ArrayList(); // declares the ArrayList variable l1 and sets it to a newly allocated ArrayList
List l2 = l1; // declares the List variable l2 and sets it to l1
def di0 = 2; // declares the def variable di0 and sets it the constant int 2
def di1 = 3; // declares the def variable di1 and sets it the constant int 3
def dl = l0; // declares the def variable dl and sets it to l0
boolean result; // declares the boolean variable result
result = b0 !== b1; // compares b0 to b1 and has a boolean result of true
result = i !== f; // compares i to f where i is promoted to float and has a boolean result of false
result = b0 !== i; // ERROR: a comparison between a boolean and a primitive numeric type is illegal
result = i !== l0; // ERROR: a comparison between a primitive numeric type and a reference type is illegal
l0.add(1); // adds a constant int 1 to the List l0
l1.add(1); // adds a constant int 1 to the ArrayList l1
result = l0 !== l1; // compares l0 to l1 and has a boolean result of true
l0.add(1); // adds a constant int 1 to the List l0
result = l0 !== l1; // compares l0 to l1 and has a boolean result of true
result = l1 !== l2; // compares l1 to l2 and has a boolean result of false
result = di0 !== di1; // compares di0 to di1 and has a boolean result of true
result = di0 !== i; // compares di0 to i where i is promoted to def and has a boolean result of false
result = dl !== l0; // compares dl to l0 with a boolean result of false
result = null !== dl; // compares null to dl with a boolean result of true
result = l1 !== null; // compares null to l1 with a boolean result of true
----
==== Bitwise And
Bitwise and will and together two integer type expressions. The table below shows what each resultant bit will in the resultant integer type value be based on the corresponding bit in each integer type expression.
|====
||1|0
|1|1|0
|0|0|0
|====
The format starts with an expression, follows with the ampersand operator, and finishes with an expression.
*Grammar:*
[source,ANTLR4]
----
bitwise_and: expression '&' expression;
----
A numeric promotion may occur during a bitwise and operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-integer expressions will result in an error.
Promotion Table:
|====
||byte|short|char|int|long|def
|byte|int|int|int|int|long|def
|short|int|int|int|int|long|def
|char|int|int|int|int|long|def
|int|int|int|int|int|long|def
|long|long|long|long|long|long|def
|def|def|def|def|def|def|def|def|def
|====
*Examples:*
[source,Java]
----
byte x = 16; // declares the byte variable x and sets it to a constant int 1
int y = x & 4; // declares the int variable y and sets it to the result of x and 4
long z = y & x; // declares the long variable z and sets it the result of y and x
def d = z & 2; // declares the def variable d and sets it the result of z and 2
def e; // declares the def variable e
e = d & z; // sets e to the result of d and z
----
==== Boolean Xor
Boolean xor will xor together two boolean expressions. The table below shows what the resultant boolean value will be based on the two boolean expressions.
|====
||true|false
|true|false|true
|false|true|false
|====
The format starts with an expression, follows with the carrot operator, and finishes with an expression.
*Grammar:*
[source,ANTLR4]
----
boolean_xor: expression '^' expression;
----
Note that def types will be assumed to be of the boolean type. Any def type evaluated at run-time that does not represent a boolean will result in an error. Non-boolean expressions will result in an error.
*Examples:*
[source,Java]
----
boolean x = false; // declares the boolean variable x and sets the constant boolean false
boolean y = x ^ true; // declares the boolean variable y and sets it the result of x xor true
def z = y ^ x; // declares the def variable z and sets it to the result of y xor x
----
==== Bitwise Xor
Bitwise xor will xor together two integer type expressions. The table below shows what each resultant bit will in the resultant integer type value be based on the corresponding bit in each integer type expression.
|====
||1|0
|1|0|1
|0|1|0
|====
The format starts with an expression, follows with the carrot operator, and finishes with an expression.
*Grammar:*
[source,ANTLR4]
----
bitwise_xor: expression '^' expression;
----
A numeric promotion may occur during a bitwise xor operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-integer expressions will result in an error.
Promotion Table:
|====
||byte|short|char|int|long|def
|byte|int|int|int|int|long|def
|short|int|int|int|int|long|def
|char|int|int|int|int|long|def
|int|int|int|int|int|long|def
|long|long|long|long|long|long|def
|def|def|def|def|def|def|def|def|def
|====
*Examples:*
[source,Java]
----
byte x = 16; // declares the byte variable x and sets it to a constant int 1
int y = x ^ 4; // declares the int variable y and sets it to the result of x xor 4
long z = y ^ x; // declares the long variable z and sets it the result of y xor x
def d = z ^ 2; // declares the def variable d and sets it the result of z xor 2
def e; // declares the def variable e
e = d ^ z; // sets e to the result of d xor z
----
==== Bitwise Or
Bitwise or will or together two integer type expressions. The table below shows what each resultant bit will in the resultant integer type value be based on the corresponding bit in each integer type expression.
|====
||1|0
|1|1|1
|0|1|0
|====
The format starts with an expression, follows with the pipe operator, and finishes with an expression.
*Grammar:*
[source,ANTLR4]
----
bitwise_or: expression '|' expression;
----
A numeric promotion may occur during a bitwise xor operation. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents. Non-integer expressions will result in an error.
Promotion Table:
|====
||byte|short|char|int|long|def
|byte|int|int|int|int|long|def
|short|int|int|int|int|long|def
|char|int|int|int|int|long|def
|int|int|int|int|int|long|def
|long|long|long|long|long|long|def
|def|def|def|def|def|def|def|def|def
|====
*Examples:*
[source,Java]
----
byte x = 16; // declares the byte variable x and sets it to a constant int 1
int y = x | 4; // declares the int variable y and sets it to the result of x or 4
long z = y | x; // declares the long variable z and sets it the result of y or x
def d = z | 2; // declares the def variable d and sets it the result of z or 2
def e; // declares the def variable e
e = d | z; // sets e to the result of d or z
----
==== Boolean And
Boolean and will and together two boolean expressions. If the first expression is found to be false then it is known that the result will also be false, so evaluation of the second expression will be skipped. The table below shows what the resultant boolean value will be based on the two boolean expressions.
||true|false
|true|true|false
|false|false|false
The format starts with an expression, follows with the ampersand-ampersand operator, and finishes with an expression.
*Grammar:*
[source,ANTLR4]
----
boolean_and: expression '&&' expression;
----
Note that def types will be assumed to be of the boolean type. Any def type evaluated at run-time that does not represent a boolean will result in an error. Non-boolean expressions will result in an error.
*Examples:*
[source,Java]
----
boolean x = false; // declares the boolean variable x and sets the constant boolean false
boolean y = x && true; // declares the boolean variable y and sets it the result of x and true
def z = y && x; // declares the def variable z and sets it to the result of y and x
----
==== Boolean Or
Boolean or will or together two boolean expressions. If the first expression is found to be true then it is known that the result will also be true, so evaluation of the second expression will be skipped. The table below shows what the resultant boolean value will be based on the two boolean expressions.
|====
||true|false
|true|true|true
|false|true|false
|====
The format starts with an expression, follows with the pipe-pipe operator, and finishes with an expression.
*Grammar:*
[source,ANTLR4]
----
boolean_and: expression '||' expression;
----
Note that def types will be assumed to be of the boolean type. Any def type evaluated at run-time that does not represent a boolean will result in an error. Non-boolean expressions will result in an error.
*Examples:*
[source,Java]
----
boolean x = false; // declares the boolean variable x and sets the constant boolean false
boolean y = x || true; // declares the boolean variable y and sets it the result of x or true
def z = y || x; // declares the def variable z and sets it to the result of y or x
----
==== Conditional
A conditional operation consists of three expressions. The first expression is evaluated with an expected boolean result type. If the first expression evaluates to true then the second expression will be evaluated. If the first expression evaluates to false then the third expression will be evaluated. This can be used as a shortcut many different operations without requiring a full if/else branch. Errors will occur if the first expression does not evaluate to a boolean type or if one of the second or third expression cannot be converted to a type appropriate for the expected result. The format is an expression followed by a question-mark operator, another expression, a colon operator, and finishes with a final expression.
*Grammar:*
[source,ANTLR4]
----
conditional: expression '?' expression ':' expression;
----
A numeric type promotion may occur during the evaluation of a conditional with the second and third expressions if the expected result is a numeric type. A def type evaluated at run-time will follow the same promotion table at run-time following whatever type def represents.
Promotion Table:
|====
||byte|short|char|int|long|float|double|def
|byte|int|int|int|int|long|float|double|def
|short|int|int|int|int|long|float|double|def
|char|int|int|int|int|long|float|double|def
|int|int|int|int|int|long|float|double|def
|long|long|long|long|long|long|float|double|def
|float|float|float|float|float|float|float|double|def
|double|double|double|double|double|double|double|double|def
|def|def|def|def|def|def|def|def|def
|====
*Examples:*
[source,Java]
----
boolean b = true; // declares the boolean variable b and sets it the constant boolean true
int x = b ? 1 : 2; // declares the int variable x and sets it to the int constant 1
// since the first expression of the conditional evaluates to true
// so the second expression is evaluated for a result
List y = x > 1 ? new ArrayList() : null; // declares the List variable y and sets it to null
// since the first expression of the conditional evaluates to false
// so the third expression is evaluated for a result
def z = x < 2 ? true : false; // declares the def variable z and sets it to the boolean constant true
// since the first expression of the conditional evaluates to true
// so the second expression is evaluated for a result
----
==== Elvis
The elvis operator consists of two expressions. If the first expression is a non-null value then the resultant value will be the evaluated first expression otherwise the resultant value will be the evaluated second expression. This is typically used as a shortcut for a null check in a conditional. An error will occur if the expected result is a primitive type. The format is an expression, followed by the question-mark-colon operator, and finishes with an expression.
*Grammar:*
[source,ANTLR4]
----
elvis: expression '?:' expression;
----
*Examples:*
[source,Java]
----
List l = new ArrayList(); // declares the List variable l and sets it to a newly allocated ArrayList
List y = l ?: new ArrayList(); // declares the List variable y and sets it to l since l is not null
y = null; // sets y to null
def z = y ?: new HashMap(); // declares the def variable z and sets it to a newly allocated HashMap since y is null
----
==== Assignment
Assignment can be used to assign a value to a variable. See Variable Assignment [MARK] for more information.
==== Compound Assignment
Compound assignment can be used as a shortcut for an assignment where a binary operation would occur between the variable/field as the left-side expression and a separate right-side expression. The variable/field and right-side expression must be of appropriate types for the specific operation or an error will occur. A downcast may be necessary for certain operations to be able to assign the result back into the variable/field and will happen implicitly. The format is a variable/field, followed by one of the compound assignment operators, finished with an expression.
*Grammar:*
[source,ANTLR4]
----
compund_assignment: ID (. ID)? '$=' expression; // $ is a placeholder for the operation symbol
----
A compound assignment is equivalent to the expression below where V is the variable/field and T is the type of variable/member.
[source,Java]
----
V = (T)(V op expression);
----
The table below shows all available operators for compound assignment. All operators follow any casting/promotion rules according to their regular definition.
|====
|Operator|Compound Symbol
|Multiplication|*=
|Division|/=
|Remainder|%=
|String Concatenation|+=
|Addition|+=
|Subtraction|-=
|Left Shift|<<=
|Right Shift|>>=
|Unsigned Right Shift|>>>=
|Bitwise And|&=
|Boolean And|&=
|Bitwise Xor|^=
|Boolean Xor|^=
|Bitwise Or|\|=
|Boolean Or|\|=
|====
*Examples:*
[source,Java]
----
int i = 10; // declares the variable i and sets it to constant int 10
i *= 2; // multiplies i by 2 -- i = (int)(i * 2)
i /= 5; // divides i by 5 -- i = (int)(i / 5)
i %= 3; // gives the remainder for i/3 -- i = (int)(i % 3)
i += 5; // adds 5 to i -- i = (int)(i + 5)
i -= 5; // subtracts 5 from i -- i = (int)(i - 5)
i <<= 2; // left shifts i by 2 -- i = (int)(i << 2)
i >>= 1; // right shifts i by 1 -- i = (int)(i >> 1)
i >>>= 1; // unsigned right shifts i by 1 -- i = (int)(i >>> 1)
i &= 15; // ands i with 15 -- i = (int)(i & 15)
i ^= 12; // xors i with 12 -- i = (int)(i ^ 2)
i |= 4; // ors i with 4 -- i = (int)(i | 4)
boolean b = true; // declares the boolean variable b and sets it to the constant boolean true
b &= false; // ands b with false -- b = (boolean)(b & false)
b ^= false; // xors b with false -- b = (boolean)(b & false)
b |= true; // ors be with true -- b = (boolean)(b & false)
def x = 'compound'; // declares the def variable x and sets it to the constant String 'compound'
x += ' assignment'; // string concatenates ' assignment' to x -- x = (String)(x + ' assignment')
----