Files
centvrion/README.md
2026-04-22 15:35:51 +02:00

455 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# About
`CENTVRION` is the programming language for the modern roman.
# Documentation
## Example code
### Hello World
![Hello World](snippets/hello_world.png)
### Recursive Fibonacci number function
![Fibonacci](snippets/fibonacci.png)
### Number guessing game
![Number guessing game](snippets/guessing.png)
## Variables
Variables are set with the `DESIGNA` and `VT` keywords. Type is inferred.
![Variable assignment](snippets/variable.png)
Variable can consist of lower-case letters, numbers, as well as `_`.
### Compound assignment
`AVGE` (+=) and `MINVE` (-=) are shorthand for incrementing or decrementing a variable:
![Compound assignment](snippets/compound.png)
```
> VIII
```
`x AVGE III` is equivalent to `DESIGNA x VT x + III`.
### Destructuring
Multiple variables can be assigned at once by unpacking an array or multi-return function:
![Destructuring function](snippets/destructure_fn.png)
The number of targets must match the length of the array. This also works with array literals:
![Destructuring array](snippets/destructure_array.png)
## Data types
### NVLLVS
`NVLLVS` is a special kind of data type in `CENTVRION`, similar to the `null` value in many other languages. `NVLLVS` can be 0 if evaluated as an int or float, or an empty string if evaluated as a string. `NVLLVS` cannot be evaluated as a boolean.
### Strings
Strings are written as text in quotes (`'` or `"`).
![String literal](snippets/string_literal.png)
Strings are concatenated with `&`:
![String concatenation](snippets/string_concat.png)
`NVLLVS` coerces to an empty string when used with `&`. Note: `+` is for arithmetic only — using it on strings raises an error.
#### String Interpolation
Double-quoted strings support interpolation with `{expression}`:
![String interpolation](snippets/string_interp.png)
Any expression can appear inside `{}`. Values are coerced to strings the same way as with `&` (integers become Roman numerals, booleans become `VERITAS`/`FALSITAS`, etc.).
Single-quoted strings do **not** interpolate — `'{nomen}'` is the literal text `{nomen}`. Use `{{` and `}}` for literal braces in double-quoted strings: `"use {{braces}}"``use {braces}`.
#### String Indexing and Slicing
Strings support the same indexing and slicing syntax as arrays. Indexing is 1-based and returns a single-character string:
```
"SALVTE"[I] @> "S"
"SALVTE"[III] @> "L"
```
Slicing uses `VSQVE` with inclusive bounds, returning a substring:
```
"SALVTE"[II VSQVE IV] @> "ALV"
```
Integer modulo is `RELIQVVM`: `VII RELIQVVM III` evaluates to `I`. Under the `FRACTIO` module it returns a fraction, so `IIIS RELIQVVM IS` is `S` (i.e. 1/2).
### Integers
Integers must be written in roman numerals using the following symbols:
|Symbol|Value|
|------|-----|
|`I`|1|
|`V`|5|
|`X`|10|
|`L`|50|
|`C`|100|
|`D`|500|
|`M`|1000|
Each of the symbols written by themself is equal to the value of the symbol. Different symbols written from largest to smallest are equal to the sum of the symbols. Two to three of the same symbol written consecutively is equal to the sum of those symbols (only true for `I`s, `X`s, `C`s or `M`s ). A single `I` written before a `V` or `X` is equal to 1 less than the value of the second symbol. Similarly, an `X` written before a `L` or `C` is 10 less than the second symbol, and a `C` written before a `D` or `M` is 100 less than the second symbol.
Because of the restrictions of roman numerals, numbers above 3.999 are impossible to write in the base `CENTVRION` syntax. If numbers of that size are required, see the `MAGNVM` module.
The number 0 can be expressed with the keyword `NVLLVS`.
#### Negative numbers
Negative numbers can be expressed as `NVLLVS` minus the value. For an explicit definition of negative numbers, see the `SVBNVLLA` module.
### Floats
The base `CENTVRION` syntax does not allow for floats. However, the `FRACTIO` module adds a syntax for fractions.
### Booleans
Booleans are denoted with the keywords `VERITAS` for true and `FALSITAS` for false.
### Arrays
Arrays are defined using square brackets (`[]`) and commas (`,`):
![Array literal](snippets/array_literal.png)
An array of integers can also be initialized with the `VSQVE` keyword. The range is inclusive on both ends:
![Array with VSQVE](snippets/array_vsqve.png)
```
> [I, II, III, IV, V, VI, VII, VIII, IX, X]
```
Individual elements can be accessed by index using square brackets. Indexing is 1-based, so `I` refers to the first element:
![Array indexing](snippets/array_index.png)
```
> I
```
Arrays are concatenated with `@`:
```
DESIGNA x VT [I, II, III] @ [IV, V]
DIC x
```
```
> [I, II, III, IV, V]
```
Both operands must be arrays — using `@` on non-arrays raises an error.
A sub-array can be extracted with `VSQVE` inside the index brackets. Both bounds are inclusive and 1-based:
![Array slicing](snippets/array_slice.png)
```
> [XX, XXX, XL]
```
### Dicts (TABVLA)
Dicts are key-value maps created with the `TABVLA` keyword and curly braces:
![Dict creation](snippets/dict_create.png)
Keys must be strings or integers. Values are accessed and assigned with square brackets:
![Dict access](snippets/dict_access.png)
Iterating over a dict with `PER` loops over its keys:
![Dict iteration](snippets/dict_per.png)
`LONGITVDO(dict)` returns the number of entries. `CLAVES(dict)` returns the keys as an array.
## Conditionals
### SI/TVNC
If-then statements are denoted with the keywords `SI` (if) and `TVNC` (then). Thus, the code
![SI/TVNC](snippets/si_tvnc.png)
Will return `I` (1), as the conditional evaluates `x` to be true.
### Boolean expressions
In conditionals, `EST` functions as an equality evaluation, `DISPAR` as not-equal, and `MINVS` (<) and `PLVS` (>) function as inequality evaluation.
### ALIVD
When using `SI`/`TVNC` statements, you can also use `ALIVD` as an "else".
![ALIVD](snippets/alivd.png)
```
> I
```
`SI` statements may follow immediately after `ALIVD`.
![ALIVD SI](snippets/alivd_si.png)
```
> II
```
### Boolean operators
The keyword `ET` can be used as a boolean "and". The keyword `AVT` can be used as a boolean "or".
![Boolean operators](snippets/boolean_ops.png)
```
> II
```
## Loops
### DONICVM loops
![DONICVM loop](snippets/donicvm.png)
```
> LV
```
### DVM loops
![DVM loop](snippets/dvm.png)
```
> XI
```
### AETERNVM loops
`AETERNVM FAC { ... }` is shorthand for an infinite loop — equivalent
to `DVM FALSITAS FAC { ... }` but without relying on `DVM`'s inverted
condition. Exit the loop with `ERVMPE` (or `REDI` from inside a function).
![AETERNVM loop](snippets/aeternvm.png)
```
> X
```
### PER loops
![PER loop](snippets/per.png)
```
> I
> II
> III
> IV
> V
```
## Error handling
Errors can be caught using `TEMPTA` (temptare = to try) and `CAPE` (capere = to catch). The `CAPE` block binds the error message to a variable as a string.
```
TEMPTA {
DESIGNA x VT I / NVLLVS
} CAPE error {
DIC(error)
}
```
```
> Division by zero
```
If the try block succeeds, the catch block is skipped. If an error occurs in the catch block, it propagates up. `TEMPTA`/`CAPE` blocks can be nested.
## Functions
Functions are defined with the `DEFINI` and `VT` keywords. The `REDI` keyword is used to return. `REDI` can also be used to end the program, if used outside of a function.
Calling a function is done with the `INVOCA` keyword.
![Function definition](snippets/function.png)
```
> CXXI
```
## First-class functions
Functions are first-class values in CENTVRION. They can be assigned to variables, passed as arguments, returned from functions, and stored in arrays or dicts.
Anonymous functions are created with the `FVNCTIO` keyword:
![FVNCTIO](snippets/fvnctio.png)
```
> XIV
```
`INVOCA` accepts any expression as the callee, not just a name:
![INVOCA expressions](snippets/invoca_expr.png)
```
> VI
> VI
> XVI
```
Note: CENTVRION does **not** have closures. When a function is called, it receives a copy of the *caller's* scope, not the scope where it was defined. Variables from a function's definition site are only available if they also exist in the caller's scope at call time.
## Built-ins
### DIC
`DIC(value, ...)`
Prints one or more values to stdout, space-separated, with integers rendered as Roman numerals. Returns the printed string.
![DIC](snippets/dic.png)
### AVDI
`AVDI()`
Reads one line from stdin and returns it as a string.
### AVDI_NVMERVS
`AVDI_NVMERVS()`
Reads one line from stdin, parses it as a Roman numeral, and returns it as an integer. Raises an error if the input is not a valid numeral.
### CONTINVA
`CONTINVA`
Skips the rest of the current loop body and continues to the next iteration (`DVM` or `PER`). Has no meaningful return value.
### ERVMPE
`ERVMPE`
Breaks out of the current loop (`DVM` or `PER`). Has no meaningful return value.
### LONGITVDO
`LONGITVDO(array)`, `LONGITVDO(string)`, or `LONGITVDO(dict)`
Returns the length of `array` (element count), `string` (character count), or `dict` (entry count) as an integer.
### CLAVES
`CLAVES(dict)`
Returns the keys of `dict` as an array.
### ORDINA
`ORDINA(array)`
Sorts an array in ascending order. Returns a new sorted array. All elements must be the same type — integers, fractions, or strings. Integers and fractions sort numerically; strings sort lexicographically.
### SENATVS
`SENATVS(bool, ...)` or `SENATVS([bool])`
Returns VERITAS if a strict majority of the arguments are VERITAS, FALSITAS otherwise. Also accepts a single array of booleans. All values must be booleans. Ties return FALSITAS.
### NVMERVS
`NVMERVS(string)`
Parses a Roman numeral string and returns its integer value. The argument must be a string containing a valid Roman numeral. Respects the `MAGNVM` and `SVBNVLLA` modules for large and negative numbers respectively.
### TYPVS
`TYPVS(value)`
Returns the type of `value` as a string: `NVMERVS` (integer), `LITTERA` (string), `VERAX` (boolean), `CATALOGVS` (list), `FRACTIO` (fraction), `TABVLA` (dict), `FVNCTIO` (function), or `NVLLVS` (null).
### DORMI
`DORMI(n)`
Sleeps for `n` seconds, where `n` is an integer, fraction, or NVLLVS (treated as 0). Returns nothing meaningful.
### QVAERE
`QVAERE(pattern, string)`
Returns an array of all non-overlapping matches of the regex `pattern` in `string`. Both arguments must be strings. Patterns use extended regular expression syntax with Roman numeral quantifiers (`{III}` for exactly 3, `{II,V}` for 25, `{III,}` for 3 or more). Returns an empty array if there are no matches. Raises an error if the pattern is invalid.
### SVBSTITVE
`SVBSTITVE(pattern, replacement, string)`
Replaces all non-overlapping matches of the regex `pattern` in `string` with `replacement`. All three arguments must be strings. The replacement string supports backreferences (`\I`, `\II`, etc.) to captured groups. Returns the resulting string. Raises an error if the pattern is invalid.
### SCINDE
`SCINDE(string, delimiter)`
Splits `string` by `delimiter` and returns an array of substrings. Both arguments must be strings. If the delimiter is not found, returns a single-element array containing the original string. If the delimiter is an empty string, splits into individual characters.
## Modules
Modules are additions to the base `CENTVRION` syntax. They add or change certain features. Modules are included in your code by having
![Module declaration](snippets/module_decl.png)
In the beginning of your source file.
Vnlike many other programming languages with modules, the modules in `CENTVRION` are not libraries that can be "imported" from other scripts written in the language. They are features of the compiler, disabled by default.
### FORS
![CVM FORS](snippets/fors.png)
The `FORS` module allows you to add randomness to your `CENTVRION` program. It adds 4 new built-in functions: `FORTVITVS_NVMERVS(int, int)`, `FORTVITA_ELECTIO(['a])`, `DECIMATIO(['a])`, and `SEMEN(int)`.
`FORTVITVS_NVMERVS(int, int)` picks a random int in the (inclusive) range of the two given ints.
`FORTVITA_ELECTIO(['a])` picks a random element from the given array. `FORTVITA_ELECTIO(array)` is identical to ```array[FORTVITVS_NVMERVS(I, LONGITVDO(array))]```.
`DECIMATIO(['a])` returns a copy of the given array with a random tenth of its elements removed. Arrays with fewer than 10 elements are returned unchanged.
`SEMEN(int)` seeds the random number generator for reproducibility.
### FRACTIO
![CVM FRACTIO](snippets/fractio.png)
The `FRACTIO` module adds floats, in the form of base 12 fractions.
In the `FRACTIO` module, `.` represents 1/12, `:` represents 1/6 and `S` represents 1/2. The symbols must be written from highest to lowest. So 3/4 would be written as "`S:.`".
Fractions can be written as an extension of integers. So 3.5 would be "`IIIS`".
The symbol `|` can be used to denote that the following fraction symbols are 1 "level down" in base 12. So after the first `|`, the fraction symbols denote 144ths instead of 12ths. So 7 and 100/144 would be "`VIIS:|::`", as "7 + 100/144" is also "7+8/12+4/144".
A single "set" of fraction symbols can only represent up to 11/12, as 12/12 can be written as 1.
### MAGNVM
![CVM MAGNVM](snippets/magnvm.png)
`MAGNVM` adds the ability to write integers larger than `MMMCMXCIX` (3.999) in your code, by adding the thousands operator, "`_`".
When `_` is added _after_ a numeric symbol, the symbol becomes 1.000 times larger. The operator can be added to the same symbol multiple times. So "`V_`" is 5.000, and "`V__`" is 5.000.000. The strict rules for integers still apply, so 4.999 cannot be written as "`IV_`", but must instead be written as "`MV_CMXCIX`".
All integer symbols except `I` may be given a `_`.
### SCRIPTA
![CVM SCRIPTA](snippets/scripta.png)
The `SCRIPTA` module adds file I/O to your `CENTVRION` program. It adds 3 new built-in functions: `LEGE`, `SCRIBE`, and `ADIVNGE`.
`LEGE(string)` reads the contents of the file at the given path and returns them as a string.
`SCRIBE(string, string)` writes the second argument to the file at the path given by the first argument, overwriting any existing content.
`ADIVNGE(string, string)` appends the second argument to the file at the path given by the first argument.
### RETE
![CVM RETE](snippets/rete.png)
The `RETE` module adds networking to your `CENTVRION` program.
`PETE(string)` performs an HTTP GET request to the given URL and returns the response body as a string.
`PETITVR(string, function)` registers a GET handler for the given path. The handler function receives a single argument: a dictionary with keys `"via"` (the request path), `"quaestio"` (query string), and `"methodus"` (HTTP method). The handler's return value becomes the response body (200 OK). Unmatched paths return a 404.
`AVSCVLTA(integer)` starts an HTTP server on the given port. This call blocks indefinitely, serving registered routes. Routes must be registered with `PETITVR` before calling `AVSCVLTA`. Ports above 3999 require the `MAGNVM` module.
### SVBNVLLA
![CVM SVBNVLLA](snippets/svbnvlla.png)
The `SVBNVLLA` module adds the ability to write negative numbers as `-II` instead of `NVLLVS-II`.