2022-06-03 19:54:31 +02:00
|
|
|
# μScript
|
2022-11-24 19:05:51 +01:00
|
|
|
|
2022-06-13 13:31:54 +02:00
|
|
|
μScript was created to allow respackopts pack authors to specify conditions for loading resources
|
2022-06-03 19:54:31 +02:00
|
|
|
in a more human-friendly manner than the previous json tree-based system.
|
|
|
|
It is intended to be vaguely like java in its syntax, though it deviates in some aspects.
|
|
|
|
The language is parsed into an AST representation which is executed in-place, no compilation is performed.
|
2022-06-13 13:31:54 +02:00
|
|
|
μScript supports outputting data using various types, not just strings or booleans
|
2022-06-03 19:54:31 +02:00
|
|
|
|
|
|
|
## Value types
|
2022-11-24 19:05:51 +01:00
|
|
|
|
2022-06-03 19:54:31 +02:00
|
|
|
This DSL supports numbers (double), booleans, strings, objects, lists and functions.
|
|
|
|
The topmost operator of a condition must always return a boolean for it to be valid in the context of respackopts.
|
|
|
|
The values of input data are according to the pack config.
|
|
|
|
String literals may be written with quotation marks as follows: `"some text"` or `'some text'`
|
|
|
|
Numbers may be written as follows: `103` or `10.15`
|
|
|
|
Booleans may be written either as `true` or `false`
|
2023-01-24 13:43:46 +01:00
|
|
|
Lists may be created with the `listOf` function (part of StandardLib): `listOf(1, 2, 3, 4)`
|
|
|
|
Functions may be created with the syntax explained below (--> Closures).
|
|
|
|
You may assign any of these to a variable, including closures.
|
|
|
|
Objects cannot be created manually but may be provided to the script as parameters or from functions defined in Java.
|
2022-06-03 19:54:31 +02:00
|
|
|
|
|
|
|
Please ensure you use proper whitespace, as this might behave unexpectedly otherwise.
|
|
|
|
|
|
|
|
## Operators
|
2022-11-24 19:05:51 +01:00
|
|
|
|
2022-06-03 19:54:31 +02:00
|
|
|
Numbers support the following operators (x and y are numbers):
|
2022-11-24 19:05:51 +01:00
|
|
|
|
2022-06-03 19:54:31 +02:00
|
|
|
- Addition: `x + y`
|
|
|
|
- Subtraction: `x - y`
|
|
|
|
- Multiplication: `x * y`
|
|
|
|
- Division: `x / y`
|
|
|
|
- Modulo: `x % y`
|
|
|
|
- Power: `x ^ y`
|
|
|
|
- Inversion: `-x`
|
|
|
|
- Greater than: `x > y`
|
|
|
|
- Greater than or equal: `x >= y`
|
|
|
|
- Less than: `x < y`
|
|
|
|
- Less than or equal: `x <= y`
|
|
|
|
- Equality: `x == y`
|
|
|
|
- Inequality: `x != y`
|
|
|
|
|
|
|
|
Strings support the following operators (x and y are strings, a is any value):
|
2022-11-24 19:05:51 +01:00
|
|
|
|
2022-06-03 19:54:31 +02:00
|
|
|
- Equality: `x == y`
|
|
|
|
- Inequality: `x != y`
|
|
|
|
- Concatenation: `x || a` or `a || x`
|
|
|
|
|
|
|
|
Booleans support the following operators (x and y are booleans, a and b are values of the same type):
|
2022-11-24 19:05:51 +01:00
|
|
|
|
2022-06-03 19:54:31 +02:00
|
|
|
- Conditional: `x ? a : b`
|
|
|
|
- Inversion: `!x`
|
|
|
|
- And: `x & y`
|
|
|
|
- Or: `x | y`
|
|
|
|
- Equality (=XNOR): `x == y`
|
|
|
|
- Inequality (=XOR): `x != y`
|
|
|
|
|
|
|
|
Objects support the following operators (x is an object with an entry called `entry`):
|
2022-11-24 19:05:51 +01:00
|
|
|
|
2022-06-03 19:54:31 +02:00
|
|
|
- Value access via `.`: `x.entry`
|
2023-01-24 13:43:46 +01:00
|
|
|
- Value access via square brackets: `x["entry"]`
|
|
|
|
|
|
|
|
Lists support the following operators (x is a list, someFunc is a method taking variadic arguments):
|
|
|
|
|
|
|
|
- Value access via square brackets: `x[0]`
|
|
|
|
- Expanding via `...` (only in calls): `someFunc(x...)`
|
2022-06-03 19:54:31 +02:00
|
|
|
|
2023-01-20 21:52:25 +01:00
|
|
|
Parentheses (`()`) may be used to indicate order of operation.
|
2022-06-03 19:54:31 +02:00
|
|
|
|
2023-01-20 21:52:25 +01:00
|
|
|
## Closures (functions)
|
|
|
|
One may define a closure as follows: `{list, of, arguments -> body}`.
|
|
|
|
The body of a closure may contain multiple expressions, which can be (but don't have to be) seperated by semicolons.
|
|
|
|
In that case, the return value of the last expression will be the return value of the closure.
|
|
|
|
The arrow (`->`) must always be present, even if the closure takes no arguments.
|
|
|
|
The amount of arguments is checked at runtime, so the amount used to call the function MUST be correct.
|
2023-01-24 13:43:46 +01:00
|
|
|
If you don't know the amount of arguments upfront, you may declare a variadic closure with `...`: `{some, arguments... -> body}`
|
|
|
|
where `arguments` would be the variadic argument, which is always a list of excess parameters.
|
2023-01-20 21:52:25 +01:00
|
|
|
In closures (or multi-expression scripts for that matter), you may assign variables as follows: `name = value`.
|
|
|
|
Please note that you cannot assign values to fields of objects.
|
|
|
|
You may also assign a closure to a variable to use it like a named function.
|
|
|
|
This could look as follows: `someFunction = {arg -> arg * arg}`
|
|
|
|
Please also be aware that μScript does NOT allow you to modify variables of outer scopes from inner scopes.
|
2022-06-13 13:31:54 +02:00
|
|
|
|
|
|
|
## Embedding μScript
|
2022-11-24 19:05:51 +01:00
|
|
|
|
2023-01-20 21:52:25 +01:00
|
|
|
μScript is available as a [maven package](https://maven.frohnmeyer-wds.de/#/artifacts/io/gitlab/jfronny/muscript) which you can add to your
|
2022-11-24 19:05:51 +01:00
|
|
|
project.
|
2023-01-20 21:52:25 +01:00
|
|
|
To use it, first parse an expression via `Parser.parse(String script)` and convert the returned generic expression to a typed
|
|
|
|
one by calling `as(Bool|String|Number|Dynamic)Expr`.
|
2022-06-13 13:31:54 +02:00
|
|
|
This process may throw a ParseException.
|
2023-01-20 21:52:25 +01:00
|
|
|
You may also use `Parser.parseScript(String script)` for multi-expression scripts.
|
2023-01-20 22:05:18 +01:00
|
|
|
You can call `get(Dynamic<?> dataRoot)` on the result to execute the script on the provided data, which should be a
|
2023-01-24 14:05:04 +01:00
|
|
|
`Scope` which you created with `StandardLib.createScope()` to add standard methods.
|
2022-06-13 13:31:54 +02:00
|
|
|
This is also where you can add custom data to be accessed by your script.
|
|
|
|
The execution of a script can throw a LocationalException which may be converted to a LocationalError for printing
|
|
|
|
using the source of the expression if available.
|
|
|
|
You may also call `StarScriptIngester.starScriptToMu()` to generate μScript code from StarScript code.
|
|
|
|
|
|
|
|
A full example could look as follows:
|
2022-11-24 19:05:51 +01:00
|
|
|
|
2022-06-13 13:31:54 +02:00
|
|
|
```java
|
2023-01-24 14:05:04 +01:00
|
|
|
public class Example {
|
|
|
|
public static void main(String[] args) {
|
|
|
|
String source = String.join(" ", args);
|
|
|
|
Expr<?> parsed;
|
|
|
|
try {
|
|
|
|
parsed = Parser.parse(source); // or Parser.parse(StarScriptIngester.starScriptToMu(source))
|
|
|
|
} catch (Parser.ParseException e) { // Could not parse
|
|
|
|
System.err.println(e.error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
BoolExpr typed;
|
|
|
|
try {
|
|
|
|
typed = parsed.asBoolExpr();
|
|
|
|
} catch (LocationalException e) {
|
|
|
|
System.err.println(e.asPrintable(source));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Scope scope = StandardLib.createScope()
|
|
|
|
.set("someValue", 15)
|
|
|
|
.set("someOther", Map.of(
|
|
|
|
"subValue", DFinal.of(true)
|
|
|
|
));
|
|
|
|
boolean result;
|
|
|
|
try {
|
2023-01-24 14:10:42 +01:00
|
|
|
result = typed.get(scope);
|
2023-01-24 14:05:04 +01:00
|
|
|
} catch (LocationalException e) {
|
|
|
|
System.err.println(e.asPrintable(source));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
System.out.println("Result: " + result);
|
|
|
|
}
|
2022-06-13 13:31:54 +02:00
|
|
|
}
|
|
|
|
```
|