🐐 DECIMATIO

This commit is contained in:
2026-04-21 15:18:39 +02:00
parent 63c35605a2
commit 861448cb04
9 changed files with 53 additions and 3 deletions

View File

@@ -248,12 +248,14 @@ Vnlike many other programming languages with modules, the modules in `CENTVRION`
### FORS ### FORS
![CVM FORS](snippets/fors.png) ![CVM FORS](snippets/fors.png)
The `FORS` module allows you to add randomness to your `CENTVRION` program. It adds 3 new built-in functions: `FORTIS_NVMERVS int int`, `FORTIS_ELECTIONIS ['a]`, and `SEMEN int`. The `FORS` module allows you to add randomness to your `CENTVRION` program. It adds 4 new built-in functions: `FORTIS_NVMERVS int int`, `FORTIS_ELECTIONIS ['a]`, `DECIMATIO ['a]`, and `SEMEN int`.
`FORTIS_NVMERVS int int` picks a random int in the (inclusive) range of the two given ints. `FORTIS_NVMERVS int int` picks a random int in the (inclusive) range of the two given ints.
`FORTIS_ELECTIONIS ['a]` picks a random element from the given array. `FORTIS_ELECTIONIS array` is identical to ```array[FORTIS_NVMERVS NVLLVS ((LONGITVDO array)-I)]```. `FORTIS_ELECTIONIS ['a]` picks a random element from the given array. `FORTIS_ELECTIONIS array` is identical to ```array[FORTIS_NVMERVS NVLLVS ((LONGITVDO array)-I)]```.
`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. `SEMEN int` seeds the random number generator for reproducibility.
### FRACTIO ### FRACTIO

View File

@@ -957,6 +957,16 @@ class BuiltIn(Node):
raise CentvrionError("SEMEN requires an integer seed") raise CentvrionError("SEMEN requires an integer seed")
random.seed(seed) random.seed(seed)
return vtable, ValNul() return vtable, ValNul()
case "DECIMATIO":
if "FORS" not in vtable["#modules"]:
raise CentvrionError("Cannot use 'DECIMATIO' without module 'FORS'")
if not isinstance(params[0], ValList):
raise CentvrionError("DECIMATIO requires an array")
arr = list(params[0].value())
to_remove = len(arr) // 10
for _ in range(to_remove):
arr.pop(random.randint(0, len(arr) - 1))
return vtable, ValList(arr)
case "LONGITVDO": case "LONGITVDO":
if isinstance(params[0], (ValList, ValStr)): if isinstance(params[0], (ValList, ValStr)):
return vtable, ValInt(len(params[0].value())) return vtable, ValInt(len(params[0].value()))

View File

@@ -186,6 +186,13 @@ def _emit_builtin(node, ctx):
else: else:
lines.append(f"CentValue {tmp} = cent_fortis_electionis({param_vars[0]});") lines.append(f"CentValue {tmp} = cent_fortis_electionis({param_vars[0]});")
case "DECIMATIO":
if not ctx.has_module("FORS"):
lines.append('cent_runtime_error("FORS module required for DECIMATIO");')
lines.append(f"CentValue {tmp} = cent_null();")
else:
lines.append(f"CentValue {tmp} = cent_decimatio({param_vars[0]});")
case "SEMEN": case "SEMEN":
if not ctx.has_module("FORS"): if not ctx.has_module("FORS"):
lines.append('cent_runtime_error("FORS module required for SEMEN");') lines.append('cent_runtime_error("FORS module required for SEMEN");')

View File

@@ -533,6 +533,25 @@ CentValue cent_fortis_electionis(CentValue lst) {
return lst.lval.items[rand() % lst.lval.len]; return lst.lval.items[rand() % lst.lval.len];
} }
CentValue cent_decimatio(CentValue lst) {
if (lst.type != CENT_LIST)
cent_type_error("'DECIMATIO' requires a list");
int len = lst.lval.len;
/* Copy the list so we can remove in-place */
CentValue result = cent_list_new(len);
for (int i = 0; i < len; i++)
cent_list_push(&result, lst.lval.items[i]);
int to_remove = result.lval.len / 10;
for (int i = 0; i < to_remove; i++) {
int idx = rand() % result.lval.len;
/* Shift remaining elements left */
for (int j = idx; j < result.lval.len - 1; j++)
result.lval.items[j] = result.lval.items[j + 1];
result.lval.len--;
}
return result;
}
void cent_semen(CentValue seed) { void cent_semen(CentValue seed) {
if (seed.type != CENT_INT) if (seed.type != CENT_INT)
cent_type_error("'SEMEN' requires an integer seed"); cent_type_error("'SEMEN' requires an integer seed");

View File

@@ -177,6 +177,7 @@ CentValue cent_avdi_numerus(void); /* AVDI_NVMERVS */
CentValue cent_longitudo(CentValue v); /* LONGITVDO */ CentValue cent_longitudo(CentValue v); /* LONGITVDO */
CentValue cent_fortis_numerus(CentValue lo, CentValue hi); /* FORTIS_NVMERVS */ CentValue cent_fortis_numerus(CentValue lo, CentValue hi); /* FORTIS_NVMERVS */
CentValue cent_fortis_electionis(CentValue lst); /* FORTIS_ELECTIONIS */ CentValue cent_fortis_electionis(CentValue lst); /* FORTIS_ELECTIONIS */
CentValue cent_decimatio(CentValue lst); /* DECIMATIO */
void cent_semen(CentValue seed); /* SEMEN */ void cent_semen(CentValue seed); /* SEMEN */
void cent_everro(void); /* EVERRO */ void cent_everro(void); /* EVERRO */

View File

@@ -39,6 +39,7 @@ keyword_tokens = [("KEYWORD_"+i, i) for i in [
builtin_tokens = [("BUILTIN", i) for i in [ builtin_tokens = [("BUILTIN", i) for i in [
"AVDI_NVMERVS", "AVDI_NVMERVS",
"AVDI", "AVDI",
"DECIMATIO",
"DICE", "DICE",
"EVERRO", "EVERRO",
"FORTIS_NVMERVS", "FORTIS_NVMERVS",

View File

@@ -57,7 +57,7 @@ contexts:
scope: constant.language.centvrion scope: constant.language.centvrion
builtins: builtins:
- match: '\b(AVDI_NVMERVS|AVDI|DICE|FORTIS_NVMERVS|FORTIS_ELECTIONIS|LONGITVDO|SEMEN)\b' - match: '\b(AVDI_NVMERVS|AVDI|DECIMATIO|DICE|FORTIS_NVMERVS|FORTIS_ELECTIONIS|LONGITVDO|SEMEN)\b'
scope: support.function.builtin.centvrion scope: support.function.builtin.centvrion
modules: modules:

View File

@@ -537,6 +537,14 @@ builtin_tests = [
('LONGITVDO("")', Program([], [ExpressionStatement(BuiltIn("LONGITVDO", [String("")]))]), ValInt(0)), ('LONGITVDO("")', Program([], [ExpressionStatement(BuiltIn("LONGITVDO", [String("")]))]), ValInt(0)),
("CVM FORS\nFORTIS_ELECTIONIS([I, II, III])", Program([ModuleCall("FORS")], [ExpressionStatement(BuiltIn("FORTIS_ELECTIONIS", [DataArray([Numeral("I"), Numeral("II"), Numeral("III")])]))]), ValInt(1)), ("CVM FORS\nFORTIS_ELECTIONIS([I, II, III])", Program([ModuleCall("FORS")], [ExpressionStatement(BuiltIn("FORTIS_ELECTIONIS", [DataArray([Numeral("I"), Numeral("II"), Numeral("III")])]))]), ValInt(1)),
("CVM FORS\nSEMEN(XLII)\nFORTIS_NVMERVS(I, C)", Program([ModuleCall("FORS")], [ExpressionStatement(BuiltIn("SEMEN", [Numeral("XLII")])), ExpressionStatement(BuiltIn("FORTIS_NVMERVS", [Numeral("I"), Numeral("C")]))]), ValInt(82)), ("CVM FORS\nSEMEN(XLII)\nFORTIS_NVMERVS(I, C)", Program([ModuleCall("FORS")], [ExpressionStatement(BuiltIn("SEMEN", [Numeral("XLII")])), ExpressionStatement(BuiltIn("FORTIS_NVMERVS", [Numeral("I"), Numeral("C")]))]), ValInt(82)),
# DECIMATIO: seed 42, 10 elements → removes 1 (element II)
("CVM FORS\nSEMEN(XLII)\nDECIMATIO([I, II, III, IV, V, VI, VII, VIII, IX, X])", Program([ModuleCall("FORS")], [ExpressionStatement(BuiltIn("SEMEN", [Numeral("XLII")])), ExpressionStatement(BuiltIn("DECIMATIO", [DataArray([Numeral("I"), Numeral("II"), Numeral("III"), Numeral("IV"), Numeral("V"), Numeral("VI"), Numeral("VII"), Numeral("VIII"), Numeral("IX"), Numeral("X")])]))]), ValList([ValInt(1), ValInt(3), ValInt(4), ValInt(5), ValInt(6), ValInt(7), ValInt(8), ValInt(9), ValInt(10)])),
# DECIMATIO: seed 1, 3 elements → 3//10=0, nothing removed
("CVM FORS\nSEMEN(I)\nDECIMATIO([I, II, III])", Program([ModuleCall("FORS")], [ExpressionStatement(BuiltIn("SEMEN", [Numeral("I")])), ExpressionStatement(BuiltIn("DECIMATIO", [DataArray([Numeral("I"), Numeral("II"), Numeral("III")])]))]), ValList([ValInt(1), ValInt(2), ValInt(3)])),
# DECIMATIO: empty array → empty array
("CVM FORS\nDECIMATIO([])", Program([ModuleCall("FORS")], [ExpressionStatement(BuiltIn("DECIMATIO", [DataArray([])]))]), ValList([])),
# DECIMATIO: seed 42, 20 elements → removes 2 (elements I and IV)
("CVM FORS\nSEMEN(XLII)\nDECIMATIO([I, II, III, IV, V, VI, VII, VIII, IX, X, XI, XII, XIII, XIV, XV, XVI, XVII, XVIII, XIX, XX])", Program([ModuleCall("FORS")], [ExpressionStatement(BuiltIn("SEMEN", [Numeral("XLII")])), ExpressionStatement(BuiltIn("DECIMATIO", [DataArray([Numeral("I"), Numeral("II"), Numeral("III"), Numeral("IV"), Numeral("V"), Numeral("VI"), Numeral("VII"), Numeral("VIII"), Numeral("IX"), Numeral("X"), Numeral("XI"), Numeral("XII"), Numeral("XIII"), Numeral("XIV"), Numeral("XV"), Numeral("XVI"), Numeral("XVII"), Numeral("XVIII"), Numeral("XIX"), Numeral("XX")])]))]), ValList([ValInt(2), ValInt(3), ValInt(5), ValInt(6), ValInt(7), ValInt(8), ValInt(9), ValInt(10), ValInt(11), ValInt(12), ValInt(13), ValInt(14), ValInt(15), ValInt(16), ValInt(17), ValInt(18), ValInt(19), ValInt(20)])),
] ]
class TestBuiltins(unittest.TestCase): class TestBuiltins(unittest.TestCase):
@@ -577,6 +585,8 @@ error_tests = [
("CVM FORS\nFORTIS_ELECTIONIS([])", CentvrionError), # FORTIS_ELECTIONIS on empty array ("CVM FORS\nFORTIS_ELECTIONIS([])", CentvrionError), # FORTIS_ELECTIONIS on empty array
("CVM FORS\nFORTIS_NVMERVS(X, I)", CentvrionError), # FORTIS_NVMERVS a > b ("CVM FORS\nFORTIS_NVMERVS(X, I)", CentvrionError), # FORTIS_NVMERVS a > b
("PER i IN I FACE { DICE(i) }", CentvrionError), # PER over non-array ("PER i IN I FACE { DICE(i) }", CentvrionError), # PER over non-array
("DECIMATIO([I, II, III])", CentvrionError), # FORS required for DECIMATIO
("CVM FORS\nDECIMATIO(I)", CentvrionError), # DECIMATIO requires an array
("LONGITVDO(I)", CentvrionError), # LONGITVDO on non-array ("LONGITVDO(I)", CentvrionError), # LONGITVDO on non-array
("DESIGNA x VT I\nINVOCA x ()", CentvrionError), # invoking a non-function ("DESIGNA x VT I\nINVOCA x ()", CentvrionError), # invoking a non-function
("SI I TVNC { DESIGNA r VT I }", CentvrionError), # non-bool SI condition: int ("SI I TVNC { DESIGNA r VT I }", CentvrionError), # non-bool SI condition: int

View File

@@ -65,7 +65,7 @@
"patterns": [ "patterns": [
{ {
"name": "support.function.builtin.cent", "name": "support.function.builtin.cent",
"match": "\\b(AVDI_NVMERVS|AVDI|DICE|EVERRO|FORTIS_NVMERVS|FORTIS_ELECTIONIS|LONGITVDO)\\b" "match": "\\b(AVDI_NVMERVS|AVDI|DECIMATIO|DICE|EVERRO|FORTIS_NVMERVS|FORTIS_ELECTIONIS|LONGITVDO|SEMEN)\\b"
} }
] ]
}, },