19 KiB
CENTVRION Language Reference
Full syntax documentation for the CENTVRION language. For the formal grammar, see language/main.pdf. For installation and a minimal example, see README.md.
Example code
Hello World
Recursive Fibonacci number function
Number guessing game
Variables
Variables are set with the DESIGNA and VT keywords. Type is inferred.
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:
> 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:
The number of targets must match the length of the array. This also works with array literals:
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 ").
Strings are concatenated with &:
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}:
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:
> S
> L
Slicing uses VSQVE with inclusive bounds, returning a substring:
> 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 Is, Xs, Cs or Ms ). 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 (,):
An array of integers can also be initialized with the VSQVE keyword. The range is inclusive on both ends:
> [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:
> I
Arrays are concatenated with @:
> [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:
> [XX, XXX, XL]
Dicts (TABVLA)
Dicts are key-value maps created with the TABVLA keyword and curly braces:
Keys must be strings or integers. Values are accessed and assigned with square brackets:
Iterating over a dict with PER loops over its keys:
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
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".
> I
SI statements may follow immediately after ALIVD.
> II
Boolean operators
The keyword ET can be used as a boolean "and". The keyword AVT can be used as a boolean "or".
> II
Loops
DONICVM loops
> LV
An optional GRADV clause sets the stride. The step must be a nonzero
integer expression; positive values ascend, negative values descend, and
the endpoint is included only when the stride lands on it exactly.
> XXV
DVM loops
> 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).
> X
PER loops
> I
> II
> III
> IV
> V
Variables can be unpacked in PER loops, similar to DESIGNA destructuring:
> 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.
> 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.
> 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:
> XIV
INVOCA accepts any expression as the callee, not just a name:
> 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.
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) or ORDINA(array, comparator)
Sorts an array. Returns a new sorted array; the original is unchanged.
Without a comparator, sorts in ascending order. All elements must be the same type — integers, fractions, or strings. Integers and fractions sort numerically; strings sort lexicographically.
With a comparator, the type-uniformity rule is dropped — the comparator decides ordering. The comparator must be a function of exactly two parameters and must return VERAX. comparator(a, b) returns VERITAS iff a should come before b; two elements are treated as equal when both comparator(a, b) and comparator(b, a) are FALSITAS.
> [V III II I]
MVTA
MVTA(array, fn)
Returns a new array obtained by applying fn to every element of array. The original array is unchanged. fn must be a function of exactly one parameter; its return value is unrestricted, so MVTA may produce an array of a different element type than its input.
> [II IV VI VIII]
CRIBRA
CRIBRA(array, predicate)
Returns a new array containing the elements of array for which predicate returns VERITAS, in their original order. The original array is unchanged. predicate must be a function of exactly one parameter and must return VERAX.
> [I II III]
CONFLA
CONFLA(array, initial, fn)
Left fold: starts with initial as the accumulator, then for each element e of array updates the accumulator to fn(acc, e), and returns the final accumulator. The original array is unchanged. fn must be a function of exactly two parameters. If array is empty, initial is returned unchanged.
> XVI
ADDE
ADDE(array, value)
Returns a new array with value appended at the end. The original array is unchanged.
TOLLE
TOLLE(array, idx)
Returns a new array with the element at 1-based position idx removed. The index must be an integer in the range [I, LONGITVDO(array)]; out-of-range indices raise an error.
INSERE
INSERE(array, idx, value)
Returns a new array with value inserted at 1-based position idx, shifting later elements one position to the right. The index must be an integer in the range [I, LONGITVDO(array) + I]; passing LONGITVDO(array) + I is equivalent to ADDE.
NECTE
NECTE(array1, array2)
Weaves two arrays together into a new array of two-element pair arrays. The two inputs must have equal length; mismatched lengths raise an error.
IVNGE
IVNGE(keys, values)
Builds a dict by yoking two parallel arrays — the i-th element of keys becomes the key for the i-th element of values. The two arrays must have equal length. Keys must be strings or integers. If keys contains duplicates, the later value wins.
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.
MAIVSCVLA
MAIVSCVLA(string)
Returns a new string with every ASCII letter a–z replaced by its uppercase counterpart A–Z. All other bytes (digits, punctuation, non-ASCII) pass through unchanged.
MINVSCVLA
MINVSCVLA(string)
Returns a new string with every ASCII letter A–Z replaced by its lowercase counterpart a–z. All other bytes (digits, punctuation, non-ASCII) pass through unchanged.
Modules
Modules are additions to the base CENTVRION syntax. They add or change certain features. Modules are included in your code by having
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
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
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
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
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
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
The SVBNVLLA module adds the ability to write negative numbers as -II instead of NVLLVS-II.













































