2023-03-11 17:03:17 +01:00
|
|
|
# μScript
|
|
|
|
|
|
|
|
The purpose of this document is to be a guide to using the μScript language.
|
|
|
|
It is not intended to explain any history of the language, implementation details or details on how to embed μScript in programs.
|
|
|
|
For information on that, look [here](../../../README.md).
|
|
|
|
|
|
|
|
## Types
|
|
|
|
μScript supports a couple of basic types, namely:
|
|
|
|
- [Numbers](#numbers) (double-precision floating-point)
|
|
|
|
- [Booleans](#booleans)
|
|
|
|
- [Strings](#strings)
|
|
|
|
- [Objects](#objects)
|
|
|
|
- [Lists](#lists)
|
|
|
|
- [Functions](#functions)
|
|
|
|
|
|
|
|
Numbers, booleans and strings can be created just like in java.
|
|
|
|
|
|
|
|
## Numbers
|
|
|
|
|
|
|
|
You can use the most common math operations on numbers.
|
|
|
|
That includes addition, subtraction, multiplication, division, modulo, pow, and your standard comparison operators.
|
|
|
|
|
|
|
|
Order of operation is also supported.
|
|
|
|
|
|
|
|
The StdLib comes with additional constants and functions, namely: `PI`, `E`, `round`, `floor`, `ceil`, `abs`, `random`
|
|
|
|
|
2023-03-11 17:10:56 +01:00
|
|
|
<details>
|
|
|
|
<summary>Example</summary>
|
|
|
|
<br>
|
2023-03-11 17:03:17 +01:00
|
|
|
|
|
|
|
```mu
|
|
|
|
listOf(
|
|
|
|
2 + 5,
|
|
|
|
2 - 5,
|
|
|
|
0.5 * 4,
|
|
|
|
2 + 2 * 3,
|
|
|
|
(2 + 2) * 3,
|
|
|
|
4 / 2,
|
|
|
|
5 % 3, // this is modulo
|
|
|
|
2 ^ 10, // two to the power of ten
|
|
|
|
12 > 4,
|
|
|
|
5 < 3,
|
|
|
|
4 >= 4,
|
|
|
|
5 != 2,
|
|
|
|
8 == 8,
|
|
|
|
round(PI, 2) + floor(E) // round also accepts a second argument: precision, but it can be ommitted to round to a whole number
|
|
|
|
)
|
|
|
|
```
|
2023-03-11 17:10:56 +01:00
|
|
|
Result:
|
2023-03-11 17:03:17 +01:00
|
|
|
```
|
|
|
|
[7, -3, 2, 8, 12, 2, 2, 1024, true, false, true, true, true, 5.1400]
|
|
|
|
```
|
|
|
|
</details>
|
|
|
|
|
|
|
|
## Booleans
|
|
|
|
|
|
|
|
Your standard logic operators are supported.
|
|
|
|
XOR/XNOR are just your normal `!=`/`==` operators.
|
|
|
|
Make sure not to use `||`, as that is the string concatenation operator, not OR.
|
|
|
|
You can also use ternary conditional operators as you would in java.
|
|
|
|
|
2023-03-11 17:10:56 +01:00
|
|
|
<details>
|
|
|
|
<summary>Example</summary>
|
|
|
|
<br>
|
|
|
|
|
2023-03-11 17:03:17 +01:00
|
|
|
```mu
|
|
|
|
listOf(
|
|
|
|
1 < 3 ? "this is correct" : "it is not", // if the condition is true, do the first thing. Else, do the second
|
|
|
|
!true, // not
|
|
|
|
true & false, // and
|
|
|
|
true & true,
|
|
|
|
true | false, // or
|
|
|
|
false | false
|
|
|
|
)
|
|
|
|
```
|
2023-03-11 17:10:56 +01:00
|
|
|
Result:
|
2023-03-11 17:03:17 +01:00
|
|
|
```
|
|
|
|
[this is correct, false, false, true, true, false]
|
|
|
|
```
|
|
|
|
</details>
|
|
|
|
|
|
|
|
## Strings
|
|
|
|
|
|
|
|
Strings only support concatenation via `||`.
|
|
|
|
You can also concatenate other things to a string.
|
|
|
|
Values of all other types can also be coerced into strings.
|
|
|
|
|
|
|
|
Equality operations are supported.
|
|
|
|
|
|
|
|
The StdLib comes with some additional functions, namely: `toUpper`, `toLower`, `contains` and `replace`
|
|
|
|
|
|
|
|
<details>
|
2023-03-11 17:10:56 +01:00
|
|
|
<summary>Example</summary>
|
2023-03-11 17:03:17 +01:00
|
|
|
<br>
|
|
|
|
|
2023-03-11 17:10:56 +01:00
|
|
|
```mu
|
|
|
|
15 || "string one"::toUpper() || 'string Two'::toLower() || "example"::contains("thing") || "yxamply"::replace("y", "e")
|
|
|
|
```
|
|
|
|
Result:
|
2023-03-11 17:03:17 +01:00
|
|
|
```
|
|
|
|
15STRING ONEstring twofalseexample
|
|
|
|
```
|
|
|
|
</details>
|
|
|
|
|
|
|
|
## Objects
|
|
|
|
|
|
|
|
You cannot create your own objects, but objects may be passed to your script from functions or as parameters.
|
|
|
|
You can read (but not write) their fields via `.` or `[]`.
|
|
|
|
|
|
|
|
In the following example, the objects `object` and `object2` is passed to the script.
|
|
|
|
|
|
|
|
The StdLib also contains two objects, namely `date` and `time` which allow reading the current date and time.
|
|
|
|
They also allow creating date/time objects and comparing them.
|
|
|
|
|
2023-03-11 17:10:56 +01:00
|
|
|
<details>
|
|
|
|
<summary>Example</summary>
|
|
|
|
<br>
|
|
|
|
|
2023-03-11 17:03:17 +01:00
|
|
|
```mu
|
|
|
|
listOf(
|
|
|
|
object2.valuename, // This is how you would normally do this
|
|
|
|
object2['valuename'], // You can also use []
|
|
|
|
this['object2']['valuename'], // 'this' is always an object representing the current scope
|
|
|
|
object2['value' || 'name'], // [] can contain any expression
|
|
|
|
object[object2['sub'].val / 10], // [] even references to other field
|
|
|
|
object2.sub['val'] * 2, // You can do anything with the value of a field
|
|
|
|
object.subvalue / (object2.sub.val + 6),
|
|
|
|
object2.stringfunc("some parameter"), // Objects can also contain functions
|
|
|
|
date(2023, 5, 13),
|
|
|
|
time(23, 55, 10),
|
|
|
|
date(2020, 5, 10) > date.today
|
|
|
|
)
|
|
|
|
```
|
2023-03-11 17:10:56 +01:00
|
|
|
Result:
|
2023-03-11 17:03:17 +01:00
|
|
|
```
|
|
|
|
[subvalue, subvalue, subvalue, subvalue, One, 20, 64, some parameter, 2023-05-13, 23:55:10, false]
|
|
|
|
```
|
|
|
|
</details>
|
|
|
|
|
|
|
|
## Lists
|
|
|
|
|
|
|
|
Lists can be created with the stdlib function `listOf` (as seen in other examples).
|
|
|
|
You can access their entries with `[]`, just like you would access fields for objects.
|
|
|
|
In function calls, you can use the spread operator (`...`) to use all elements of the list as parameters.
|
|
|
|
The StdLib also comes with some additional functions, namely `len`, `isEmpty`, `concat`, `filter`, `map`, `flatMap`, `fold` and `forEach`.
|
|
|
|
|
2023-03-11 17:10:56 +01:00
|
|
|
<details>
|
|
|
|
<summary>Example</summary>
|
|
|
|
<br>
|
|
|
|
|
2023-03-11 17:03:17 +01:00
|
|
|
```mu
|
|
|
|
listOf(
|
|
|
|
len(listOf(1, 2, 3)),
|
|
|
|
isEmpty(listOf()),
|
|
|
|
concat(listOf(1, 2), listOf(3, 4)),
|
|
|
|
listOf(1, 2)::concat(listOf(3, 4))::len(), // Don't forget using the bind operator for readability in longer chains
|
|
|
|
time(listOf(23, 55)..., 10), // You can use the spread operator in any call, not just variadic ones
|
|
|
|
listOf(1, 2, 3)[1], // Lists are 0-indexed
|
|
|
|
listOf(1, 2, 3, 4)::filter({n->n%2==0})::map({n->n/2}) // you can chain the additional functions for proper functional programming
|
|
|
|
)
|
|
|
|
```
|
2023-03-11 17:10:56 +01:00
|
|
|
Result:
|
2023-03-11 17:03:17 +01:00
|
|
|
```
|
|
|
|
[3, true, [1, 2, 3, 4], 4, 23:55:10, 2, [1, 2]]
|
|
|
|
```
|
|
|
|
</details>
|
|
|
|
|
|
|
|
## Functions
|
|
|
|
|
|
|
|
μScript is functional as in functions being treated like any other data type.
|
|
|
|
This means you can pass them to methods as arguments, store them in variables or do whatever else you feel like.
|
|
|
|
A closure consists of a list of arguments (of which the last may be variadic) and some instructions.
|
|
|
|
|
2023-03-11 17:10:56 +01:00
|
|
|
<details>
|
|
|
|
<summary>Example</summary>
|
|
|
|
<br>
|
|
|
|
|
2023-03-11 17:03:17 +01:00
|
|
|
```mu
|
|
|
|
someFunction = {n -> n * 2} // By assigning a closure to a variable, you get an equivalent to a normal java function
|
|
|
|
|
|
|
|
someVal = 1
|
|
|
|
$someVal = 1
|
|
|
|
|
|
|
|
{->someVal = 12}() // If you try to change a variable from inside a closure, you create a copy of it. The outer scope doesn't change
|
|
|
|
{->$someVal = 12}() // The only exception to that are variables prefixed with a dollar sign
|
|
|
|
// These work like mutable variables in other languages
|
|
|
|
/*
|
|
|
|
Use `...` to mark the last argument of a closure as variadic
|
|
|
|
All arguments that don't fit in the previous parameters will be packed in it as a list
|
|
|
|
Note that the length of that list may be 0
|
|
|
|
*/
|
|
|
|
someFunction2 = { a, b... ->
|
|
|
|
isEmpty(b) ? a : a * someFunction2(b...) // you can use the spread operator on that list like any other
|
|
|
|
}
|
|
|
|
|
|
|
|
listOf(
|
|
|
|
someFunction(1), // Closures are ran with parentheses
|
|
|
|
{->"some expression(s)"}(), // You don't have to store them to call them once...
|
|
|
|
{f1, f2 -> f1(f2(5))}(someFunction, {n->n}), // ... or to pass them to a higher order function
|
|
|
|
{->
|
|
|
|
12 + 3
|
|
|
|
10 + 2
|
|
|
|
5 + 2 // The last expression in a closure is its result. This is the same behavior as scripts (like the one this runs in)
|
|
|
|
}(),
|
|
|
|
{->
|
|
|
|
12 + 3; // You can (and probably should) use semicolons to seperate expressions
|
|
|
|
10 + 2;
|
|
|
|
5 + 2;
|
|
|
|
}(),
|
|
|
|
1::someFunction(), // You can use the bind operator '::' to create a new closure using the value to the left as the first argument
|
|
|
|
// In this case, this new closure is executed immediately using the parentheses, but doing that isn't necessary
|
|
|
|
1::({n->n})(), // Instead of a name, you can also use any expression as the right part of a bind operator (if it is in parentheses)
|
|
|
|
someVal,
|
|
|
|
$someVal,
|
|
|
|
someFunction2(1, 2, 3, 4)
|
|
|
|
)
|
|
|
|
```
|
2023-03-11 17:10:56 +01:00
|
|
|
Result:
|
2023-03-11 17:03:17 +01:00
|
|
|
```
|
|
|
|
[2, some expression(s), 10, 7, 7, 2, 1, 1, 12, 24]
|
|
|
|
```
|
|
|
|
</details>
|