Merge branch 'master' into 1.16
This commit is contained in:
commit
b2ff11b9e5
5 files changed
+126
-63
No files matched your search
+65
-25
@@ -272,6 +272,18 @@ check_foo_not_zero();
|
||||
check_foo_not_zero() -> if(global_foo == 0, global_foo = 1)
|
||||
</pre>
|
||||
|
||||
## Scarpet preprocessor
|
||||
|
||||
There are several preprocessing operations applied to the source of your program to clean it up and prepare for
|
||||
execution. Some of them will affect your code as it is reported via stack traces and function definition, and some
|
||||
are applied only on the surface.
|
||||
- stripping `//` comments (in file mode)
|
||||
- replacing `$` with newlines (in command mode, modifies submitted code)
|
||||
- removing extra semicolons that don't follow `;` use as a binary operator, allowing for lenient use of semicolons
|
||||
- translating `{` into `m(`, `[` into `l(`, and `]` and `}` into `)`
|
||||
|
||||
No further optimizations are currently applied to your code.
|
||||
|
||||
## Mentions
|
||||
|
||||
LR1 parser, tokenizer, and several built-in functions are built based on the EvalEx project.
|
||||
@@ -1233,6 +1245,8 @@ a() -> global_list+=1; global_list = l(1,2,3); a(); a(); global_list // => [1,2
|
||||
|
||||
### `Operator ->`
|
||||
|
||||
`->` operator has two uses - as a function definition operator and key-value initializer for maps.
|
||||
|
||||
To organize code better than a flat sequence of operations, one can define functions. Definition is correct
|
||||
if has the following form
|
||||
|
||||
@@ -1257,7 +1271,17 @@ a(lst) -> lst+=1; list = l(1,2,3); a(list); a(list); list // => [1,2,3]
|
||||
</pre>
|
||||
|
||||
In case the inner function wants to operate and modify larger objects, lists from the outer scope, but not global,
|
||||
it needs to use `outer` function in function signature
|
||||
it needs to use `outer` function in function signature.
|
||||
|
||||
in map construction context (directly in `m()` or `{}`), the `->` operator has a different function by converting its
|
||||
arguments to a tuple which is used by map constructor as a key-value pair:
|
||||
|
||||
<pre>
|
||||
{ 'foo' -> 'bar' } => {l('foo', 'bar')}
|
||||
</pre>
|
||||
|
||||
This means that it is not possible to define literally a set of inline function, however a set of functions can still
|
||||
be created by adding elements to an empty set, and building it this way.
|
||||
|
||||
### `outer(arg)`
|
||||
|
||||
@@ -1473,26 +1497,31 @@ tag = nbt('{a:[{lvl:[1,2,3]},{lvl:[3,2,1]},{lvl:[4,5,6]}]}'); put(tag, 'a[].lvl[
|
||||
|
||||
## List operations
|
||||
|
||||
### `l(values ...), l(iterator)`
|
||||
### `[value, ...?]`,`[iterator]`,`l(value, ...?)`, `l(iterator)`
|
||||
|
||||
Creates a list of values of the expressions passed as parameters. It can be used as an L-value and if all
|
||||
elements are variables, you coujld use it to return multiple results from one function call, if that
|
||||
function returns a list of results with the same size as the `l` call uses. In case there is only one
|
||||
function returns a list of results with the same size as the `[]` call uses. In case there is only one
|
||||
argument and it is an iterator (vanilla expression specification has `range`, but Minecraft API implements
|
||||
a bunch of them, like `diamond`), it will convert it to a proper list. Iterators can only be used in high order
|
||||
functions, and are treated as empty lists, unless unrolled with `l`
|
||||
functions, and are treated as empty lists, unless unrolled with `[]`.
|
||||
|
||||
Internally, `[elem, ...]`(list syntax) and `l(elem, ...)`(function syntax) are equivalent. `[]` is simply translated to
|
||||
`l()` in the scarpet preprocessing stage. This means that internally the code has always expression syntax despite `[]`
|
||||
not using different kinds of brackets and not being proper operators. This means that `l(]` and `[)` are also valid
|
||||
although not recommended as they will make your code far less readable.
|
||||
|
||||
<pre>
|
||||
l(1,2,'foo') => [1, 2, foo]
|
||||
l() => [] (empty list)
|
||||
l(range(10)) => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
l(1, 2) = l(3, 4) => Error: l is not a variable
|
||||
l(foo, bar) = l(3,4); foo==3 && bar==4 => 1
|
||||
l(foo, bar, baz) = l(2, 4, 6); l(min(foo, bar), baz) = l(3, 5); l(foo, bar, baz) => [3, 4, 5]
|
||||
l(1,2,'foo') <=> [1, 2, 'foo']
|
||||
l() <=> [] (empty list)
|
||||
[range(10)] => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
[1, 2] = [3, 4] => Error: l is not a variable
|
||||
[foo, bar] = [3, 4]; foo==3 && bar==4 => 1
|
||||
[foo, bar, baz] = [2, 4, 6]; [min(foo, bar), baz] = [3, 5]; [foo, bar, baz] => [3, 4, 5]
|
||||
</pre>
|
||||
|
||||
In the last example `l(min(foo, bar), baz)` creates a valid L-value, as min(foo, bar) finds the lower of the
|
||||
variables (in this case `foo`) creating a valid assignable L-list of [foo, baz], and these values
|
||||
In the last example `[min(foo, bar), baz]` creates a valid L-value, as `min(foo, bar)` finds the lower of the
|
||||
variables (in this case `foo`) creating a valid assignable L-list of `[foo, baz]`, and these values
|
||||
will be assigned new values
|
||||
|
||||
### `join(delim, list), join(delim, values ...)`
|
||||
@@ -1566,29 +1595,37 @@ range(5,10) => [5, 6, 7, 8, 9]
|
||||
range(20, 10, -2) => [20, 18, 16, 14, 12]
|
||||
</pre>
|
||||
|
||||
### `element(list, index)(deprecated)`
|
||||
|
||||
Legacy support for older method that worked only on lists. Please use `get(...)` for equivalent support, or `.`
|
||||
operator. Also previous unique behaviours with `put` on lists has been removed to support all type of
|
||||
container types.
|
||||
|
||||
## Map operations
|
||||
|
||||
Scarpet supports map structures, aka hashmaps, dicts etc. Map structure can also be used, with `null` values as sets.
|
||||
Apart from container access functions, (`. , get, put, has, delete`), the following functions:
|
||||
|
||||
### `m(values ...), m(iterator), m(key_value_pairs)`
|
||||
### `{values, ...}`,`{iterator}`,`{key -> value, ...}`,`m(values, ...)`, `m(iterator)`, `m(l(key, value), ...))`
|
||||
|
||||
creates and initializes a map with supplied keys, and values. If the arguments contains a flat list, these are all
|
||||
treated as keys with no value, same goes with the iterator - creates a map that behaves like a set. If the
|
||||
arguments is a list of lists, they have to have two elements each, and then first is a key, and second, a value
|
||||
|
||||
In map creation context (directly inside `{}` or `m{}` call), `->` operator acts like a pair constructor for simpler
|
||||
syntax providing key value pairs, so the invocation to `{foo -> bar, baz -> quux}` is equivalent to
|
||||
`{l(foo, bar), l(baz, quux)}`, which is equivalent to somewhat older, but more traditional functional form of
|
||||
`m(l(foo, bar),l(baz, quuz))`.
|
||||
|
||||
Internally, `{?}`(list syntax) and `m(?)`(function syntax) are equivalent. `{}` is simply translated to
|
||||
`m()` in the scarpet preprocessing stage. This means that internally the code has always expression syntax despite `{}`
|
||||
not using different kinds of brackets and not being proper operators. This means that `m(}` and `{)` are also valid
|
||||
although not recommended as they will make your code far less readable.
|
||||
|
||||
When converting map value to string, `':'` is used as a key-value separator due to tentative compatibility with NBT
|
||||
notation, meaning in simpler cases maps can be converted to NBT parsable string by calling `str()`. This however
|
||||
does not guarantee a parsable output. To properly convert to NBT value, use `encode_nbt()`.
|
||||
|
||||
<pre>
|
||||
m(1,2,'foo') => {1: null, 2: null, foo: null}
|
||||
m() => {} (empty map)
|
||||
m(range(10)) => {0: null, 1: null, 2: null, 3: null, 4: null, 5: null, 6: null, 7: null, 8: null, 9: null}
|
||||
m(l(1, 2), l(3, 4)) => {1: 2, 3: 4}
|
||||
reduce(range(10), put(_a, _, _*_); _a, m())
|
||||
{1, 2, 'foo'} => {1: null, 2: null, foo: null}
|
||||
m() <=> {} (empty map)
|
||||
{range(10)} => {0: null, 1: null, 2: null, 3: null, 4: null, 5: null, 6: null, 7: null, 8: null, 9: null}
|
||||
m(l(1, 2), l(3, 4)) <=> {1 -> 2, 3 -> 4} => {1: 2, 3: 4}
|
||||
reduce(range(10), put(_a, _, _*_); _a, {})
|
||||
=> {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
|
||||
</pre>
|
||||
|
||||
@@ -1681,7 +1718,10 @@ set(x,y,z,'hopper', l('facing', 'north'), nbt('{Items:[{Slot:1b,id:"minecraft:sl
|
||||
|
||||
### `without_updates(expr)`
|
||||
|
||||
Evaluates subexpression without causing updates when blocks change in the world
|
||||
Evaluates subexpression without causing updates when blocks change in the world.
|
||||
|
||||
For synchronization sake, as well as from the fact that suppressed update can only happen within a tick,
|
||||
the call to the `expr` is docked on the main server task.
|
||||
|
||||
Consider following scenario: We would like to generate a bunch of terrain in a flat world following a perlin noise
|
||||
generator. The following code causes a cascading effect as blocks placed on chunk borders will cause other chunks to get
|
||||
|
||||
@@ -117,26 +117,31 @@ tag = nbt('{a:[{lvl:[1,2,3]},{lvl:[3,2,1]},{lvl:[4,5,6]}]}'); put(tag, 'a[].lvl[
|
||||
|
||||
## List operations
|
||||
|
||||
### `l(values ...), l(iterator)`
|
||||
### `[value, ...?]`,`[iterator]`,`l(value, ...?)`, `l(iterator)`
|
||||
|
||||
Creates a list of values of the expressions passed as parameters. It can be used as an L-value and if all
|
||||
elements are variables, you coujld use it to return multiple results from one function call, if that
|
||||
function returns a list of results with the same size as the `l` call uses. In case there is only one
|
||||
function returns a list of results with the same size as the `[]` call uses. In case there is only one
|
||||
argument and it is an iterator (vanilla expression specification has `range`, but Minecraft API implements
|
||||
a bunch of them, like `diamond`), it will convert it to a proper list. Iterators can only be used in high order
|
||||
functions, and are treated as empty lists, unless unrolled with `l`
|
||||
functions, and are treated as empty lists, unless unrolled with `[]`.
|
||||
|
||||
Internally, `[elem, ...]`(list syntax) and `l(elem, ...)`(function syntax) are equivalent. `[]` is simply translated to
|
||||
`l()` in the scarpet preprocessing stage. This means that internally the code has always expression syntax despite `[]`
|
||||
not using different kinds of brackets and not being proper operators. This means that `l(]` and `[)` are also valid
|
||||
although not recommended as they will make your code far less readable.
|
||||
|
||||
<pre>
|
||||
l(1,2,'foo') => [1, 2, foo]
|
||||
l() => [] (empty list)
|
||||
l(range(10)) => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
l(1, 2) = l(3, 4) => Error: l is not a variable
|
||||
l(foo, bar) = l(3,4); foo==3 && bar==4 => 1
|
||||
l(foo, bar, baz) = l(2, 4, 6); l(min(foo, bar), baz) = l(3, 5); l(foo, bar, baz) => [3, 4, 5]
|
||||
l(1,2,'foo') <=> [1, 2, 'foo']
|
||||
l() <=> [] (empty list)
|
||||
[range(10)] => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
[1, 2] = [3, 4] => Error: l is not a variable
|
||||
[foo, bar] = [3, 4]; foo==3 && bar==4 => 1
|
||||
[foo, bar, baz] = [2, 4, 6]; [min(foo, bar), baz] = [3, 5]; [foo, bar, baz] => [3, 4, 5]
|
||||
</pre>
|
||||
|
||||
In the last example `l(min(foo, bar), baz)` creates a valid L-value, as min(foo, bar) finds the lower of the
|
||||
variables (in this case `foo`) creating a valid assignable L-list of [foo, baz], and these values
|
||||
In the last example `[min(foo, bar), baz]` creates a valid L-value, as `min(foo, bar)` finds the lower of the
|
||||
variables (in this case `foo`) creating a valid assignable L-list of `[foo, baz]`, and these values
|
||||
will be assigned new values
|
||||
|
||||
### `join(delim, list), join(delim, values ...)`
|
||||
@@ -210,29 +215,37 @@ range(5,10) => [5, 6, 7, 8, 9]
|
||||
range(20, 10, -2) => [20, 18, 16, 14, 12]
|
||||
</pre>
|
||||
|
||||
### `element(list, index)(deprecated)`
|
||||
|
||||
Legacy support for older method that worked only on lists. Please use `get(...)` for equivalent support, or `.`
|
||||
operator. Also previous unique behaviours with `put` on lists has been removed to support all type of
|
||||
container types.
|
||||
|
||||
## Map operations
|
||||
|
||||
Scarpet supports map structures, aka hashmaps, dicts etc. Map structure can also be used, with `null` values as sets.
|
||||
Apart from container access functions, (`. , get, put, has, delete`), the following functions:
|
||||
|
||||
### `m(values ...), m(iterator), m(key_value_pairs)`
|
||||
### `{values, ...}`,`{iterator}`,`{key -> value, ...}`,`m(values, ...)`, `m(iterator)`, `m(l(key, value), ...))`
|
||||
|
||||
creates and initializes a map with supplied keys, and values. If the arguments contains a flat list, these are all
|
||||
treated as keys with no value, same goes with the iterator - creates a map that behaves like a set. If the
|
||||
arguments is a list of lists, they have to have two elements each, and then first is a key, and second, a value
|
||||
|
||||
In map creation context (directly inside `{}` or `m{}` call), `->` operator acts like a pair constructor for simpler
|
||||
syntax providing key value pairs, so the invocation to `{foo -> bar, baz -> quux}` is equivalent to
|
||||
`{l(foo, bar), l(baz, quux)}`, which is equivalent to somewhat older, but more traditional functional form of
|
||||
`m(l(foo, bar),l(baz, quuz))`.
|
||||
|
||||
Internally, `{?}`(list syntax) and `m(?)`(function syntax) are equivalent. `{}` is simply translated to
|
||||
`m()` in the scarpet preprocessing stage. This means that internally the code has always expression syntax despite `{}`
|
||||
not using different kinds of brackets and not being proper operators. This means that `m(}` and `{)` are also valid
|
||||
although not recommended as they will make your code far less readable.
|
||||
|
||||
When converting map value to string, `':'` is used as a key-value separator due to tentative compatibility with NBT
|
||||
notation, meaning in simpler cases maps can be converted to NBT parsable string by calling `str()`. This however
|
||||
does not guarantee a parsable output. To properly convert to NBT value, use `encode_nbt()`.
|
||||
|
||||
<pre>
|
||||
m(1,2,'foo') => {1: null, 2: null, foo: null}
|
||||
m() => {} (empty map)
|
||||
m(range(10)) => {0: null, 1: null, 2: null, 3: null, 4: null, 5: null, 6: null, 7: null, 8: null, 9: null}
|
||||
m(l(1, 2), l(3, 4)) => {1: 2, 3: 4}
|
||||
reduce(range(10), put(_a, _, _*_); _a, m())
|
||||
{1, 2, 'foo'} => {1: null, 2: null, foo: null}
|
||||
m() <=> {} (empty map)
|
||||
{range(10)} => {0: null, 1: null, 2: null, 3: null, 4: null, 5: null, 6: null, 7: null, 8: null, 9: null}
|
||||
m(l(1, 2), l(3, 4)) <=> {1 -> 2, 3 -> 4} => {1: 2, 3: 4}
|
||||
reduce(range(10), put(_a, _, _*_); _a, {})
|
||||
=> {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
|
||||
</pre>
|
||||
|
||||
|
||||
@@ -47,6 +47,8 @@ a() -> global_list+=1; global_list = l(1,2,3); a(); a(); global_list // => [1,2
|
||||
|
||||
### `Operator ->`
|
||||
|
||||
`->` operator has two uses - as a function definition operator and key-value initializer for maps.
|
||||
|
||||
To organize code better than a flat sequence of operations, one can define functions. Definition is correct
|
||||
if has the following form
|
||||
|
||||
@@ -71,7 +73,17 @@ a(lst) -> lst+=1; list = l(1,2,3); a(list); a(list); list // => [1,2,3]
|
||||
</pre>
|
||||
|
||||
In case the inner function wants to operate and modify larger objects, lists from the outer scope, but not global,
|
||||
it needs to use `outer` function in function signature
|
||||
it needs to use `outer` function in function signature.
|
||||
|
||||
in map construction context (directly in `m()` or `{}`), the `->` operator has a different function by converting its
|
||||
arguments to a tuple which is used by map constructor as a key-value pair:
|
||||
|
||||
<pre>
|
||||
{ 'foo' -> 'bar' } => {l('foo', 'bar')}
|
||||
</pre>
|
||||
|
||||
This means that it is not possible to define literally a set of inline function, however a set of functions can still
|
||||
be created by adding elements to an empty set, and building it this way.
|
||||
|
||||
### `outer(arg)`
|
||||
|
||||
|
||||
@@ -272,6 +272,18 @@ check_foo_not_zero();
|
||||
check_foo_not_zero() -> if(global_foo == 0, global_foo = 1)
|
||||
</pre>
|
||||
|
||||
## Scarpet preprocessor
|
||||
|
||||
There are several preprocessing operations applied to the source of your program to clean it up and prepare for
|
||||
execution. Some of them will affect your code as it is reported via stack traces and function definition, and some
|
||||
are applied only on the surface.
|
||||
- stripping `//` comments (in file mode)
|
||||
- replacing `$` with newlines (in command mode, modifies submitted code)
|
||||
- removing extra semicolons that don't follow `;` use as a binary operator, allowing for lenient use of semicolons
|
||||
- translating `{` into `m(`, `[` into `l(`, and `]` and `}` into `)`
|
||||
|
||||
No further optimizations are currently applied to your code.
|
||||
|
||||
## Mentions
|
||||
|
||||
LR1 parser, tokenizer, and several built-in functions are built based on the EvalEx project.
|
||||
|
||||
@@ -1463,20 +1463,6 @@ public class Expression
|
||||
return (cc, tt) -> ret;
|
||||
});
|
||||
|
||||
//Deprecated, use "get" instead, or . operator
|
||||
addBinaryFunction("element", (v1, v2) ->
|
||||
{
|
||||
if (!(v1 instanceof ListValue))
|
||||
throw new InternalExpressionException("First argument of 'get' should be a list");
|
||||
List<Value> items = ((ListValue)v1).getItems();
|
||||
long index = NumericValue.asNumber(v2).getLong();
|
||||
int numitems = items.size();
|
||||
long range = abs(index)/numitems;
|
||||
index += (range+2)*numitems;
|
||||
index = index % numitems;
|
||||
return items.get((int)index);
|
||||
});
|
||||
|
||||
addLazyFunction("put", -1, (c, t, lv) ->
|
||||
{
|
||||
if(lv.size()<2)
|
||||
|
||||
Reference in new issue
Block a user