java-commons/muscript/src/test/resources/example.md

223 lines
6.9 KiB
Markdown

# μ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`
<details>
<summary>Example</summary>
<br>
```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
)
```
Result:
```
[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.
<details>
<summary>Example</summary>
<br>
```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
)
```
Result:
```
['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>
<summary>Example</summary>
<br>
```mu
15 || "string one"::toUpper() || 'string Two'::toLower() || "example"::contains("thing") || "yxamply"::replace("y", "e")
```
Result:
```
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.
<details>
<summary>Example</summary>
<br>
```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
)
```
Result:
```
['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`.
<details>
<summary>Example</summary>
<br>
```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
)
```
Result:
```
[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.
<details>
<summary>Example</summary>
<br>
```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)
)
```
Result:
```
[2, 'some expression(s)', 10, 7, 7, 2, 1, 1, 12, 24]
```
</details>