# 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` (+=), `MINVE` (-=), `MVLTIPLICA` (*=) and `DIVIDE` (/=) are shorthand for updating a variable with an arithmetic operation: ![Compound assignment](snippets/compound.png) ``` > VIII ``` `x AVGE III` is equivalent to `DESIGNA x VT x + III`; `MINVE`, `MVLTIPLICA` and `DIVIDE` expand the same way with subtraction, multiplication and division. ### 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: ![String indexing](snippets/string_index.png) ``` > S > L ``` Slicing uses `VSQVE` with inclusive bounds, returning a substring: ![String slicing](snippets/string_slice.png) ``` > 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 `@`: ![Array concatenation](snippets/array_concat.png) ``` > [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` (<), `PLVS` (>), `HAVD_PLVS` (≤), and `HAVD_MINVS` (≥) 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 ``` Variables can be unpacked in `PER` loops, similar to `DESIGNA` destructuring: ![PER destructuring](snippets/per_destructure.png) ``` > III > VII ``` ## 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 / CAPE](snippets/tempta_cape.png) ``` > 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). ### LITTERA `LITTERA(value)` Returns `value` formatted as the same display string `DIC` would print. Integers become Roman numerals (zero becomes `NVLLVS`), fractions use the `S`/`:`/`.`/`|` notation, booleans become `VERITAS`/`FALSITAS`, arrays are space-separated in brackets, and dicts use the `{ key VT value, ... }` form. Strings pass through unchanged. Respects `MAGNVM` and `SVBNVLLA` for large and negative numbers. Inverse of `NVMERVS` for integers: `NVMERVS(LITTERA(n)) == n`. ### 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 2–5, `{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`.