🐐 SENATVS

This commit is contained in:
2026-04-21 15:49:53 +02:00
parent 861448cb04
commit f62a7dda1c
7 changed files with 66 additions and 1 deletions

View File

@@ -236,6 +236,11 @@ Breaks out of the current loop (`DVM` or `PER`). Has no meaningful return value.
Returns the length of `array` (element count) or `string` (character count) as an integer. Returns the length of `array` (element count) or `string` (character count) as an integer.
### 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 (even split) return FALSITAS.
## Modules ## Modules
Modules are additions to the base `CENTVRION` syntax. They add or change certain features. Modules are included in your code by having Modules are additions to the base `CENTVRION` syntax. They add or change certain features. Modules are included in your code by having

View File

@@ -967,6 +967,16 @@ class BuiltIn(Node):
for _ in range(to_remove): for _ in range(to_remove):
arr.pop(random.randint(0, len(arr) - 1)) arr.pop(random.randint(0, len(arr) - 1))
return vtable, ValList(arr) return vtable, ValList(arr)
case "SENATVS":
if len(params) == 1 and isinstance(params[0], ValList):
items = params[0].value()
else:
items = params
for p in items:
if not isinstance(p, ValBool):
raise CentvrionError("SENATVS requires boolean arguments")
true_count = sum(1 for p in items if p.value())
return vtable, ValBool(true_count > len(items) / 2)
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

@@ -201,6 +201,14 @@ def _emit_builtin(node, ctx):
lines.append(f"cent_semen({param_vars[0]});") lines.append(f"cent_semen({param_vars[0]});")
lines.append(f"CentValue {tmp} = cent_null();") lines.append(f"CentValue {tmp} = cent_null();")
case "SENATVS":
if param_vars:
arr_tmp = ctx.fresh_tmp() + "_arr"
lines.append(f"CentValue {arr_tmp}[] = {{{', '.join(param_vars)}}};")
lines.append(f"CentValue {tmp} = cent_senatus({arr_tmp}, {len(param_vars)});")
else:
lines.append(f"CentValue {tmp} = cent_senatus(NULL, 0);")
case "ERVMPE": case "ERVMPE":
# break as expression (side-effecting; result is unused) # break as expression (side-effecting; result is unused)
lines.append("break;") lines.append("break;")

View File

@@ -533,6 +533,21 @@ CentValue cent_fortis_electionis(CentValue lst) {
return lst.lval.items[rand() % lst.lval.len]; return lst.lval.items[rand() % lst.lval.len];
} }
CentValue cent_senatus(CentValue *args, int n) {
/* Single array argument: unpack it */
if (n == 1 && args[0].type == CENT_LIST) {
n = args[0].lval.len;
args = args[0].lval.items;
}
int true_count = 0;
for (int i = 0; i < n; i++) {
if (args[i].type != CENT_BOOL)
cent_type_error("'SENATVS' requires boolean arguments");
if (args[i].bval) true_count++;
}
return cent_bool(true_count * 2 > n);
}
CentValue cent_decimatio(CentValue lst) { CentValue cent_decimatio(CentValue lst) {
if (lst.type != CENT_LIST) if (lst.type != CENT_LIST)
cent_type_error("'DECIMATIO' requires a list"); cent_type_error("'DECIMATIO' requires a list");

View File

@@ -180,6 +180,7 @@ CentValue cent_fortis_electionis(CentValue lst); /* FORTIS_ELECTIONIS *
CentValue cent_decimatio(CentValue lst); /* DECIMATIO */ 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 */
CentValue cent_senatus(CentValue *args, int n); /* SENATVS */
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
/* Array helpers */ /* Array helpers */

View File

@@ -45,7 +45,8 @@ builtin_tokens = [("BUILTIN", i) for i in [
"FORTIS_NVMERVS", "FORTIS_NVMERVS",
"FORTIS_ELECTIONIS", "FORTIS_ELECTIONIS",
"LONGITVDO", "LONGITVDO",
"SEMEN" "SEMEN",
"SENATVS"
]] ]]
data_tokens = [ data_tokens = [

View File

@@ -545,6 +545,28 @@ builtin_tests = [
("CVM FORS\nDECIMATIO([])", Program([ModuleCall("FORS")], [ExpressionStatement(BuiltIn("DECIMATIO", [DataArray([])]))]), ValList([])), ("CVM FORS\nDECIMATIO([])", Program([ModuleCall("FORS")], [ExpressionStatement(BuiltIn("DECIMATIO", [DataArray([])]))]), ValList([])),
# DECIMATIO: seed 42, 20 elements → removes 2 (elements I and IV) # 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)])), ("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)])),
# SENATVS: majority true → VERITAS
("SENATVS(VERITAS, VERITAS, FALSITAS)", Program([], [ExpressionStatement(BuiltIn("SENATVS", [Bool(True), Bool(True), Bool(False)]))]), ValBool(True)),
# SENATVS: majority false → FALSITAS
("SENATVS(FALSITAS, FALSITAS, VERITAS)", Program([], [ExpressionStatement(BuiltIn("SENATVS", [Bool(False), Bool(False), Bool(True)]))]), ValBool(False)),
# SENATVS: tie → FALSITAS
("SENATVS(VERITAS, FALSITAS)", Program([], [ExpressionStatement(BuiltIn("SENATVS", [Bool(True), Bool(False)]))]), ValBool(False)),
# SENATVS: 4-arg tie → FALSITAS
("SENATVS(VERITAS, VERITAS, FALSITAS, FALSITAS)", Program([], [ExpressionStatement(BuiltIn("SENATVS", [Bool(True), Bool(True), Bool(False), Bool(False)]))]), ValBool(False)),
# SENATVS: single true → VERITAS
("SENATVS(VERITAS)", Program([], [ExpressionStatement(BuiltIn("SENATVS", [Bool(True)]))]), ValBool(True)),
# SENATVS: single false → FALSITAS
("SENATVS(FALSITAS)", Program([], [ExpressionStatement(BuiltIn("SENATVS", [Bool(False)]))]), ValBool(False)),
# SENATVS: empty → FALSITAS (vacuous)
("SENATVS()", Program([], [ExpressionStatement(BuiltIn("SENATVS", []))]), ValBool(False)),
# SENATVS: all true <20><> VERITAS
("SENATVS(VERITAS, VERITAS, VERITAS, VERITAS, VERITAS)", Program([], [ExpressionStatement(BuiltIn("SENATVS", [Bool(True), Bool(True), Bool(True), Bool(True), Bool(True)]))]), ValBool(True)),
# SENATVS: array input, majority true → VERITAS
("SENATVS([VERITAS, VERITAS, FALSITAS])", Program([], [ExpressionStatement(BuiltIn("SENATVS", [DataArray([Bool(True), Bool(True), Bool(False)])]))]), ValBool(True)),
# SENATVS: array input, majority false → FALSITAS
("SENATVS([FALSITAS, FALSITAS, VERITAS])", Program([], [ExpressionStatement(BuiltIn("SENATVS", [DataArray([Bool(False), Bool(False), Bool(True)])]))]), ValBool(False)),
# SENATVS: array input, empty → FALSITAS
("SENATVS([])", Program([], [ExpressionStatement(BuiltIn("SENATVS", [DataArray([])]))]), ValBool(False)),
] ]
class TestBuiltins(unittest.TestCase): class TestBuiltins(unittest.TestCase):
@@ -588,6 +610,9 @@ error_tests = [
("DECIMATIO([I, II, III])", CentvrionError), # FORS required for DECIMATIO ("DECIMATIO([I, II, III])", CentvrionError), # FORS required for DECIMATIO
("CVM FORS\nDECIMATIO(I)", CentvrionError), # DECIMATIO requires an array ("CVM FORS\nDECIMATIO(I)", CentvrionError), # DECIMATIO requires an array
("LONGITVDO(I)", CentvrionError), # LONGITVDO on non-array ("LONGITVDO(I)", CentvrionError), # LONGITVDO on non-array
("SENATVS(I)", CentvrionError), # SENATVS requires booleans
("SENATVS(VERITAS, I)", CentvrionError), # SENATVS mixed types
("SENATVS([I, II, III])", CentvrionError), # SENATVS array of non-bools
("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
("IIIS", CentvrionError), # fraction without FRACTIO module ("IIIS", CentvrionError), # fraction without FRACTIO module