Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Documentation for built-in functions in Jenny #2258

Merged
merged 12 commits into from
Jan 8, 2023
2 changes: 1 addition & 1 deletion doc/_sphinx/theme/flames.css
Original file line number Diff line number Diff line change
Expand Up @@ -815,7 +815,7 @@ div.admonition.seealso {
--admonition-border-color: #54d452;
--admonition-icon: '\f064';
--admonition-icon-color: #acfab6;
--admonition-title-background-color: #285131;
--admonition-title-background-color: #28513140;
}

div.admonition.admonition-deprecated {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,55 @@
# Functions

TODO

An expression may also contain function calls, which are indicated by the name of the function,
followed by its arguments in parentheses. The parentheses are required, even when there are no
arguments:
A **function** in YarnSpinner is the same notion as in any other programming language, or in math:
it takes a certain number of arguments, and then computes and returns the result. A function call
is indicated by the name of the function, followed by its arguments in parentheses. The parentheses
are required, even when there are no arguments:

```yarn
<<set $roll_2d6 = dice(6) + dice(6)>>
<<set $random = random()>>
```

There are around 20 built-in functions in Jenny, listed below; and it is also possible to add
[user-defined functions] as well.


## Built-in functions

- **Random functions**
- [`dice(n)`](random.md#dicen)
- [`random()`](random.md#random)
- [`random_range(a, b)`](random.md#random_rangea-b)

- **Numeric functions**
- [`ceil(x)`](numeric.md#ceilx)
- [`dec(x)`](numeric.md#decx)
- [`decimal(x)`](numeric.md#decimalx)
- [`floor(x)`](numeric.md#floorx)
- [`inc(x)`](numeric.md#incx)
- [`int(x)`](numeric.md#intx)
- [`round(x)`](numeric.md#roundx)
- [`round_places(x, n)`](numeric.md#round_placesx-n)

- **Type conversion functions**
- [`bool(x)`](type.md#boolx)
- [`number(x)`](type.md#numberx)
- [`string(x)`](type.md#stringx)

- **Other functions**
- [`plural(x, ...)`](misc.md#pluralx-words)
- [`visit_count(node)`](misc.md#visit_countnode)
- [`visited(node)`](misc.md#visitednode)


```{toctree}
:hidden:

Random functions <random.md>
Numeric functions <numeric.md>
Type conversion functions <type.md>
Miscellaneous functions <misc.md>
User-defined functions <user_defined_functions.md>
```

[user-defined functions]: user_defined_functions.md
115 changes: 115 additions & 0 deletions doc/other_modules/jenny/language/expressions/functions/misc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Miscellaneous functions


## plural(x, words...)

Returns the correct plural form depending on the value of variable `x`.

This function is locale-dependent, and its implementation and signature changes depending on the
`locale` property in the `YarnProject`. In all cases, the first argument `x` must be numeric,
while all other arguments should be strings.

The purpose of this function is to form correct plural phrases, according to the rules of the
current language. For example, suppose you need to say `{$n} items`, where `$n` is a variable. If
you simply plug in the value of the variable like that, you'll end up getting phrases like
"23 items", or "1 items" -- which is not what you want. So instead, the `plural()` function can be
used, which will select the correct plural form of the word "item":

```yarn
I have {plural($n, "% item")}.
```

In English locale (`en`), the function `plural()` takes either 1 or 2 `word`s after the numeral
`$x`. The first word is the singular form, and the second is the plural. The second word can be
omitted if the singular form is simple enough that its plural form can be obtained by adding either
`-s` or `-es`. For example:

```yarn
// Here "foot" is an irregular noun, so its plural form must be specified
// explicitly. At the same time, "inch" is regular, and the function
// plural() will know to add "es" to make its plural form.
The distance is {plural($ft, "% foot", "% feet")} and {plural($in, "% inch")}.
```

In locales other than English, the number of plural words can be anywhere from 1 to 3. Usually,
the first word is the singular form, while others are different plurals -- their meaning would
depend on a particular language. For example, in Ukrainian locale (`uk`) the function `plural()`
requires 3 words: the singular form, the "few" plural form, and the "many" plural form:

```yarn
// Assuming locale == 'uk'
У мене є {plural($coins, "% монета", "% монети", "% монет")}.

// Produces phrases like this:
// У мене є 21 монета
// У мене є 23 монети
// У мене є 25 монет
```

Note that in all examples above the words contain the `%` sign. This is used as a placeholder where
the numeral itself should be placed. It is allowed for some (or all) of the `words` to not contain
the `%` sign.


## visit_count(node)

Returns the number of times that the `node` was visited.

A node is considered "visited" if the dialogue enters and then exits that node. The node can be
exited either through the normal dialogue flow, or via the [\<\<stop\>\>] command. However, if a
runtime exception occurs while running the node, then the visit will not count.

The `node` argument must be a string, and it must contain a valid node name. If a node with the
given name does not exist in the project, an exception will be thrown.

```yarn
title: LuckyWheel
---
<<if visit_count("LuckyWheel") < 5>>
Clown: Would you like to speen a wheel and get fabulous prizes?
-> I sure do!
<<jump SpinLuckyWheel>>
-> I don't talk to strangers...
<<stop>>
<<else>>
Clown: Sorry kid, we're all out of prizes for now.
<<endif>>
===
```

```{seealso}
- [`visited(node)`](#visitednode)
```


## visited(node)

Returns `true` if the node with the given title was visited, and `false` otherwise.

For a node to be considered "visited", the dialogue must enter and then exit the node at least
once. For example, within a node "X" the expression `visited("X")` will return `false` during the
first run of this node, and `true` upon all subsequent runs.

The `node` argument must be a string, and it must contain a valid node name. If a node with the
given name does not exist in the project, an exception will be thrown.

```yarn
title: MerchantDialogue
---
<<if not visited("MerchantDialogue")>>
// This part of the dialogue will run only during the first interaction
// with the merchant.
Merchant: Greetings! My name is Hazeem
Merchant: I offer exquisute wares for the most fastidious customers!
Player: Hi. I'm Bob. I like stuff.
<<endif>>
...
===
```

```{seealso}
- [`visit_count(node)`](#visit_countnode)
```


[\<\<stop\>\>]: ../../commands/stop.md
197 changes: 197 additions & 0 deletions doc/other_modules/jenny/language/expressions/functions/numeric.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
# Numeric functions

These functions are used to manipulate numeric values. Most of them take a single numeric argument
and produce a numeric result.


## `ceil(x)`

Returns the value `x` rounded up towards positive infinity. In other words, this returns the
smallest integer value greater than or equal to `x`.

```yarn
title: ceil
---
{ ceil(0) } // 0
{ ceil(0.3) } // 1
{ ceil(5) } // 5
{ ceil(5.001) } // 6
{ ceil(5.999) } // 6
{ ceil(-2.07) } // -2
===
```

```{seealso}
- [`floor(x)`](#floorx)
- [`int(x)`](#intx)
```


## `dec(x)`

Returns the value `x` reduced towards the previous integer. Thus, if `x` is already an integer
this returns `x - 1`, but if `x` is not an integer then this returns `floor(x)`.

```yarn
title: dec
---
{ dec(0) } // -1
{ dec(0.3) } // 0
{ dec(5.0) } // 4
{ dec(5.001) } // 5
{ dec(5.999) } // 5
{ dec(-2.07) } // -3
===
```

```{seealso}
- [`inc(x)`](#incx)
```


## `decimal(x)`

Returns a fractional part of `x`.

If `x` is positive, then the returned value will be between `0` (inclusive) and `1` (exclusive).
If `x` is negative, then the returned value will be between `0` and `-1`. In all cases it should
hold that `x == int(x) + decimal(x)`.

```yarn
title: decimal
---
{ decimal(0) } // 0
{ decimal(0.3) } // 0.3
{ decimal(5.0) } // 0
{ decimal(5.001) } // 0.001
{ decimal(5.999) } // 0.999
{ decimal(-2.07) } // -0.07
===
```

```{seealso}
- [`int(x)`](#intx)
```


## `floor(x)`

Returns the value `x` rounded down towards negative infinity. In other words, this returns the
largest integer value less than or equal to `x`.

```yarn
title: floor
---
{ floor(0) } // 0
{ floor(0.3) } // 0
{ floor(5) } // 5
{ floor(5.001) } // 5
{ floor(5.999) } // 5
{ floor(-2.07) } // -3
===
```

```{seealso}
- [`ceil(x)`](#ceilx)
- [`int(x)`](#intx)
```


## `inc(x)`

Returns the value `x` increased towards the next integer. Thus, if `x` is already an integer
this returns `x + 1`, but if `x` is not an integer then this returns `ceil(x)`.

```yarn
title: inc
---
{ inc(0) } // 1
{ inc(0.3) } // 1
{ inc(5.0) } // 6
{ inc(5.001) } // 6
{ inc(5.999) } // 6
{ inc(-2.07) } // -2
===
```

```{seealso}
- [`dec(x)`](#decx)
```


## `int(x)`

Truncates the fractional part of `x`, rounding it towards zero, and returns just the integer part
of the argument `x`.

```yarn
title: int
---
{ int(0) } // 0
{ int(0.3) } // 0
{ int(5.0) } // 5
{ int(5.001) } // 5
{ int(5.999) } // 5
{ int(-2.07) } // -2
===
```

```{seealso}
- [`decimal(x)`](#decimalx)
- [`round(x)`](#roundx)
```


## `round(x)`

Rounds the value `x` towards a nearest integer.

The values that end with `.5` are rounded up if `x` is positive, and down if `x` is negative.

```yarn
title: round
---
{ round(0) } // 0
{ round(0.3) } // 0
{ round(5.0) } // 5
{ round(5.001) } // 5
{ round(5.5) } // 6
{ round(5.999) } // 6
{ round(-2.07) } // -2
{ round(-2.5) } // -3
===
```

```{seealso}
- [`round_places(x, n)`](#round_placesx-n)
```


## `round_places(x, n)`

Rounds the value `x` to `n` decimal places.

The value `x` can be either positive, negative, or zero, but it must be an integer. Rounding to
`0` decimal places is equivalent to the regular `round(x)` function. If `n` is positive, then the
function will attempt to keep that many digits after the decimal point in `x`. If `n` is negative,
then `round_places()` will round `x` to nearest tens, hundreds, thousands, etc:

```yarn
title: round_places
---
{ round_places(0, 1) } // 0
{ round_places(0.3, 1) } // 0.3
{ round_places(5.001, 1) } // 5.0
{ round_places(5.001, 2) } // 5.0
{ round_places(5.001, 3) } // 5.001
{ round_places(5.5, 1) } // 5.5
{ round_places(5.999, 1) } // 6.0
{ round_places(-2.07, 1) } // -2.1
{ round_places(13, -1) } // 10
{ round_places(252, -2) } // 200
===
```

```{seealso}
- [`round(x)`](#roundx)
```
Loading