259 lines
9.7 KiB
Markdown
259 lines
9.7 KiB
Markdown
# Operators
|
|
|
|
There is a number of operators you can use inside the expressions. Those could be considered generic type operators
|
|
that apply to most data types. They also follow standard operator precedence, i.e. `2+2*2` is understood
|
|
as `2+(2*2)`, not `(2+2)*2`, otherwise they are applied from left to right, i.e. `2+4-3` is interpreted
|
|
as `(2+4)-3`, which in case of numbers doesn't matter, but since `scarpet` allows for mixing all value types
|
|
the associativity would matter, and may lead to unintended effects:
|
|
|
|
Important operator is function definition `->` operator. It will be covered
|
|
in [User Defined Functions and Program Control Flow](docs/scarpet/language/FunctionsAndControlFlow.md)
|
|
|
|
<pre>
|
|
'123'+4-2 => ('123'+4)-2 => '1234'-2 => '134'
|
|
'123'+(4-2) => '123'+2 => '1232'
|
|
3*'foo' => 'foofoofoo'
|
|
1357-5 => 1352
|
|
1357-'5' => 137
|
|
3*'foo'-'o' => 'fff'
|
|
[1,3,5]+7 => [8,10,12]
|
|
</pre>
|
|
|
|
As you can see, values can behave differently when mixed with other types in the same expression.
|
|
In case values are of the same types, the result tends to be obvious, but `Scarpet` tries to make sense of whatever
|
|
it has to deal with
|
|
|
|
## Operator Precedence
|
|
|
|
Here is the complete list of operators in `scarpet` including control flow operators. Note, that commas and brackets
|
|
are not technically operators, but part of the language, even if they look like them:
|
|
|
|
* Match, Get `~ :`
|
|
* Unary `+ - ! ...`
|
|
* Exponent `^`
|
|
* Multiplication `* / %`
|
|
* Addition `+ -`
|
|
* Comparison `> >= <= <`
|
|
* Equality `== !=`
|
|
* Logical And`&&`
|
|
* Logical Or `||`
|
|
* Assignment `= += <>`
|
|
* Definition `->`
|
|
* Next statement`;`
|
|
* Comma `,`
|
|
* Bracket `( )`
|
|
|
|
### `Get, Accessor Operator :`
|
|
|
|
Operator version of the `get(...)` function to access elements of lists, maps, and potentially other containers
|
|
(i.e. NBTs). It is important to distinguish from `~` operator, which is a matching operator, which is expected to
|
|
perform some extra computations to retrieve the result, while `:` should be straightforward and immediate, and
|
|
the source object should behave like a container and support full container API,
|
|
meaning `get(...)`, `put(...)`, `delete(...)`, and `has(...)` functions
|
|
|
|
For certain operators and functions (get, put, delete, has, =, +=) objects can use `:` annotated fields as l-values,
|
|
meaning construct like `foo:0 = 5`, would act like `put(foo, 0, 5)`, rather than `get(foo, 0) = 5`,
|
|
which would result in an error.
|
|
|
|
TODO: add more information about l-value behaviour.
|
|
|
|
### `Matching Operator ~`
|
|
|
|
This operator should be understood as 'matches', 'contains', 'is_in', or 'find me some stuff about something else.
|
|
For strings it matches the right operand as a regular expression to the left, returning:
|
|
- `null` if there is no match
|
|
- matched phrase if no grouping is applied
|
|
- matched element if one group is applied
|
|
- list of matches if more than one grouping is applied
|
|
|
|
This can be used to extract information from unparsed nbt's in a more convoluted way (use `get(...)` for
|
|
more appropriate way of doing it). For lists it checks if an element is in the list, and returns the
|
|
index of that element, or `null` if no such element was found, especially that the use of `first(...)`
|
|
function will not return the index. Currently it doesn't have any special behaviour for numbers - it checks for
|
|
existence of characters in string representation of the left operand with respect of the regular expression on
|
|
the right hand side.
|
|
|
|
In Minecraft API portion `entity ~ feature` is a shortcode for `query(entity,feature)` for queries that do not take
|
|
any extra arguments.
|
|
|
|
<pre>
|
|
[1,2,3] ~ 2 => 1
|
|
[1,2,3] ~ 4 => null
|
|
|
|
'foobar' ~ 'baz' => null
|
|
'foobar' ~ '.b' => 'ob'
|
|
'foobar' ~ '(.)b' => 'o'
|
|
'foobar' ~ '((.)b)' => ['ob', 'o']
|
|
'foobar' ~ '((.)(b))' => ['ob', 'o', 'b']
|
|
'foobar' ~ '(?:(.)(?:b))' => 'o'
|
|
|
|
player('*') ~ 'gnembon' // null unless player gnembon is logged in (better to use player('gnembon') instead
|
|
p ~ 'sneaking' // if p is an entity returns whether p is sneaking
|
|
</pre>
|
|
|
|
Or a longer example of an ineffective way to searching for a squid
|
|
|
|
<pre>
|
|
entities = entities_area('all',x,y,z,100,10,100);
|
|
sid = entities ~ 'Squid';
|
|
if(sid != null, run('execute as '+query(get(entities,sid),'id')+' run say I am here '+query(get(entities,sid),'pos') ) )
|
|
</pre>
|
|
|
|
Or an example to find if a player has specific enchantment on a held axe (either hand) and get its level
|
|
(not using proper NBTs query support via `get(...)`):
|
|
|
|
<pre>
|
|
global_get_enchantment(p, ench) -> (
|
|
$ for(['main','offhand'],
|
|
$ holds = query(p, 'holds', _);
|
|
$ if( holds,
|
|
$ [what, count, nbt] = holds;
|
|
$ if( what ~ '_axe' && nbt ~ ench,
|
|
$ lvl = max(lvl, number(nbt ~ '(?<=lvl:)\\d') )
|
|
$ )
|
|
$ )
|
|
$ );
|
|
$ lvl
|
|
$);
|
|
/script run global_get_enchantment(player(), 'sharpness')
|
|
</pre>
|
|
|
|
### `Basic Arithmetic Operators + - * /`
|
|
|
|
Allows to add the results of two expressions. If the operands resolve to numbers, the result is arithmetic operation.
|
|
In case of strings, adding or subtracting from a string results in string concatenation and removal of substrings
|
|
from that string. Multiplication of strings and numbers results in repeating the string N times and division results
|
|
in taking the first k'th part of the string, so that `str*n/n ~ str`
|
|
|
|
In case first operand is a list, either it
|
|
results in a new list with all elements modified one by one with the other operand, or if the operand is a list
|
|
with the same number of items - element-wise addition/subtraction. This prioritize treating lists as value containers
|
|
to lists treated as vectors.
|
|
|
|
Addition with maps (`{}` or `m()`) results in a new map with keys from both maps added, if both operands are maps,
|
|
adding elements of the right argument to the keys, of left map, or just adding the right value as a new key
|
|
in the output map.
|
|
|
|
Examples:
|
|
|
|
<pre>
|
|
2+3 => 5
|
|
'foo'+3+2 => 'foo32'
|
|
'foo'+(3+2) => 'foo5'
|
|
3+2+'bar' => '5bar'
|
|
'foo'*3 => 'foofoofoo'
|
|
'foofoofoo' / 3 => 'foo'
|
|
'foofoofoo'-'o' => 'fff'
|
|
[1,2,3]+1 => [2,3,4]
|
|
b = [100,63,100]; b+[10,0,10] => [110,63,110]
|
|
{'a' -> 1} + {'b' -> 2} => {'a' -> 1, 'b' -> 2}
|
|
</pre>
|
|
|
|
### `Just Operators % ^`
|
|
|
|
The modulo and exponent (power) operators work only if both operands are numbers
|
|
|
|
<pre>pi^pi%euler => 1.124....
|
|
-9 % 4 => -1
|
|
9 % -4 => 0 ¯\_(ツ)_/¯ Java
|
|
-3 ^ 2 => 9
|
|
-3 ^ pi => // Error
|
|
</pre>
|
|
|
|
### `Comparison Operators == != < > <= >=`
|
|
|
|
Allows to compare the results of two expressions. For numbers it is considers arithmetic order of numbers, for
|
|
strings - lexicographical, nulls are always 'less' than everything else, and lists check their elements -
|
|
if the sizes are different, the size matters, otherwise, pairwise comparisons for each elements are performed.
|
|
The same order rules than with all these operators are used with the default sortographical order as used by `sort`
|
|
function. All of these are true:
|
|
|
|
<pre>
|
|
null == null
|
|
null != false
|
|
0 == false
|
|
1 == true
|
|
null < 0
|
|
null < -1000
|
|
1000 < 'a'
|
|
'bar' < 'foo'
|
|
3 == 3.0
|
|
</pre>
|
|
|
|
### `Logical Operators && ||`
|
|
|
|
These operator compute respective boolean operation on the operands. What it important is that if calculating of the
|
|
second operand is not necessary, it won't be evaluated, which means one can use them as conditional statements. In
|
|
case of success returns first positive operand (`||`) or last one (`&&`).
|
|
|
|
<pre>
|
|
true || false => true
|
|
null || false => false
|
|
false || null => null
|
|
null != false || run('kill gnembon') // gnembon survives
|
|
null != false && run('kill gnembon') // when cheats not allowed
|
|
null != false && run('kill gnembon') // gnembon dies, cheats allowed
|
|
</pre>
|
|
|
|
### `Assignment Operators = <> +=`
|
|
|
|
A set of assignment operators. All require bounded variable on the LHS, `<>` requires bounded arguments on the
|
|
right hand side as well (bounded, meaning being variables). Additionally they can also handle list constructors
|
|
with all bounded variables, and work then as list assignment operators. When `+=` is used on a list, it extends
|
|
that list of that element, and returns the list (old == new). `scarpet` doesn't support currently removal of items.
|
|
Removal of items can be obtaine via `filter` command, and reassigning it fo the same variable. Both operations would
|
|
require rewriting of the array anyways.
|
|
|
|
<pre>
|
|
a = 5 => a == 5
|
|
[a,b,c] = [3,4,5] => a==3, b==4, c==5
|
|
[minx,maxx] = sort(xi,xj); // minx assumes min(xi, xj) and maxx, max(xi, xj)
|
|
[a,b,c,d,e,f] = [range(6)]; [a,b,c] <> [d,e,f]; [a,b,c,d,e,f] => [3,4,5,0,1,2]
|
|
a = [1,2,3]; a += 4 => [1,2,3,4]
|
|
a = [1,2,3,4]; a = filter(a,_!=2) => [1,3,4]
|
|
</pre>
|
|
|
|
### `Unary Operators - +`
|
|
|
|
Require a number, flips the sign. One way to assert it's a number is by crashing the script. gg.
|
|
|
|
<pre>
|
|
-4 => -4
|
|
+4 => 4
|
|
+'4' // Error message
|
|
</pre>
|
|
|
|
### `Negation Operator !`
|
|
|
|
flips boolean condition of the expression. Equivalent of `bool(expr)==false`
|
|
|
|
<pre>
|
|
!true => false
|
|
!false => true
|
|
!null => true
|
|
!5 => false
|
|
!l() => true
|
|
!l(null) => false
|
|
</pre>
|
|
|
|
### `Unpacking Operator ...`
|
|
|
|
Unpacks elements of a list of an iterator into a sequence of arguments in a function making so that `fun(...[1, 2, 3])` is
|
|
identical with `fun(1, 2, 3)`. For maps, it unpacks them to a list of key-value pairs.
|
|
|
|
In function signatures it identifies a vararg parameter.
|
|
|
|
`fun(a, b, ... rest) -> [a, b, rest]; fun(1, 2, 3, 4)` => `[1, 2, [3, 4]]`
|
|
|
|
Effects of `...` can be surprisingly lasting. It is kept through the use of variables and function calls.
|
|
|
|
`fun(a, b, ... rest) -> [a, b, ... rest]; fun(1, 2, 3, 4)` => `[1, 2, 3, 4]`
|
|
`args() -> ... [1, 2, 3]; sum(a, b, c) -> a+b+c; sum(args())` => `6`
|
|
`a = ... [1, 2, 3]; sum(a, b, c) -> a+b+c; sum(a)` => `6`
|
|
|
|
Unpacking mechanics can be used for list and map constriction, not just for function calls.
|
|
|
|
`[...range(5), pi, ...range(5,-1,-1)]` => `[0, 1, 2, 3, 4, 3.14159265359, 5, 4, 3, 2, 1, 0]`
|
|
`{ ... map(range(5), _ -> _*_ )}` => `{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}`
|
|
`{...{1 -> 2, 3 -> 4}, ...{5 -> 6, 7 -> 8}}` => `{1: 2, 3: 4, 5: 6, 7: 8}`
|