🐐 Array functions

This commit is contained in:
2026-04-25 18:18:13 +02:00
parent d03af56e67
commit 3a80c4e941
9 changed files with 132 additions and 2 deletions

View File

@@ -361,6 +361,21 @@ Returns the keys of `dict` as an 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.
### 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`.
### SENATVS
`SENATVS(bool, ...)` or `SENATVS([bool])`

View File

@@ -1496,6 +1496,32 @@ class BuiltIn(Node):
case "EVERRE":
print("\033[2J\033[H", end="", flush=True)
return vtable, ValNul()
case "ADDE":
if len(params) != 2:
raise CentvrionError("ADDE takes exactly II arguments")
if not isinstance(params[0], ValList):
raise CentvrionError("ADDE requires an array")
return vtable, ValList(list(params[0].value()) + [params[1]])
case "TOLLE":
if len(params) != 2:
raise CentvrionError("TOLLE takes exactly II arguments")
if not isinstance(params[0], ValList):
raise CentvrionError("TOLLE requires an array")
items = list(params[0].value())
idx = _to_index_int(params[1])
if idx < 1 or idx > len(items):
raise CentvrionError(f"Index {idx} out of range for array of length {len(items)}")
return vtable, ValList(items[:idx - 1] + items[idx:])
case "INSERE":
if len(params) != 3:
raise CentvrionError("INSERE takes exactly III arguments")
if not isinstance(params[0], ValList):
raise CentvrionError("INSERE requires an array")
items = list(params[0].value())
idx = _to_index_int(params[1])
if idx < 1 or idx > len(items) + 1:
raise CentvrionError(f"Index {idx} out of range for array of length {len(items)}")
return vtable, ValList(items[:idx - 1] + [params[2]] + items[idx - 1:])
case "ORDINA":
if not isinstance(params[0], ValList):
raise CentvrionError("ORDINA requires an array")

View File

@@ -313,6 +313,15 @@ def _emit_builtin(node, ctx):
case "ORDINA":
lines.append(f"CentValue {tmp} = cent_ordina({param_vars[0]});")
case "ADDE":
lines.append(f"CentValue {tmp} = cent_adde({param_vars[0]}, {param_vars[1]});")
case "TOLLE":
lines.append(f"CentValue {tmp} = cent_tolle({param_vars[0]}, {param_vars[1]});")
case "INSERE":
lines.append(f"CentValue {tmp} = cent_insere({param_vars[0]}, {param_vars[1]}, {param_vars[2]});")
case "EVERRE":
lines.append("cent_everre();")
lines.append(f"CentValue {tmp} = cent_null();")

View File

@@ -848,6 +848,56 @@ CentValue cent_ordina(CentValue lst) {
return result;
}
static long _index_arg(CentValue idx, const char *name) {
if (idx.type == CENT_INT)
return idx.ival;
if (idx.type == CENT_FRAC && idx.fval.den == 1)
return idx.fval.num;
cent_type_error(name);
return 0;
}
CentValue cent_adde(CentValue lst, CentValue v) {
if (lst.type != CENT_LIST)
cent_type_error("'ADDE' requires a list");
int len = lst.lval.len;
CentValue result = cent_list_new(len + 1);
for (int i = 0; i < len; i++)
cent_list_push(&result, lst.lval.items[i]);
cent_list_push(&result, v);
return result;
}
CentValue cent_tolle(CentValue lst, CentValue idx) {
if (lst.type != CENT_LIST)
cent_type_error("'TOLLE' requires a list");
long i = _index_arg(idx, "'TOLLE' index must be an integer");
int len = lst.lval.len;
if (i < 1 || i > len)
cent_runtime_error("'TOLLE' index out of range");
CentValue result = cent_list_new(len - 1);
for (int j = 0; j < len; j++)
if (j != i - 1)
cent_list_push(&result, lst.lval.items[j]);
return result;
}
CentValue cent_insere(CentValue lst, CentValue idx, CentValue v) {
if (lst.type != CENT_LIST)
cent_type_error("'INSERE' requires a list");
long i = _index_arg(idx, "'INSERE' index must be an integer");
int len = lst.lval.len;
if (i < 1 || i > len + 1)
cent_runtime_error("'INSERE' index out of range");
CentValue result = cent_list_new(len + 1);
for (int j = 0; j < i - 1; j++)
cent_list_push(&result, lst.lval.items[j]);
cent_list_push(&result, v);
for (int j = i - 1; j < len; j++)
cent_list_push(&result, lst.lval.items[j]);
return result;
}
/* ------------------------------------------------------------------ */
/* Array helpers */
/* ------------------------------------------------------------------ */

View File

@@ -239,6 +239,9 @@ CentValue cent_senatus(CentValue *args, int n); /* SENATVS */
CentValue cent_typvs(CentValue v); /* TYPVS */
void cent_dormi(CentValue n); /* DORMI */
CentValue cent_ordina(CentValue lst); /* ORDINA */
CentValue cent_adde(CentValue lst, CentValue v); /* ADDE */
CentValue cent_tolle(CentValue lst, CentValue idx); /* TOLLE */
CentValue cent_insere(CentValue lst, CentValue idx, CentValue v); /* INSERE */
CentValue cent_lege(CentValue path); /* LEGE */
void cent_scribe(CentValue path, CentValue content); /* SCRIBE */
void cent_adivnge(CentValue path, CentValue content); /* ADIVNGE */

View File

@@ -46,6 +46,7 @@ keyword_tokens = [("KEYWORD_"+i, i) for i in [
]]
builtin_tokens = [("BUILTIN", i) for i in [
"ADDE",
"AVDI_NVMERVS",
"AVDI",
"CLAVES",
@@ -55,6 +56,7 @@ builtin_tokens = [("BUILTIN", i) for i in [
"EVERRE",
"FORTVITVS_NVMERVS",
"FORTVITA_ELECTIO",
"INSERE",
"LITTERA",
"LONGITVDO",
"MAIVSCVLA",
@@ -63,6 +65,7 @@ builtin_tokens = [("BUILTIN", i) for i in [
"ORDINA",
"SEMEN",
"SENATVS",
"TOLLE",
"TYPVS",
"LEGE",
"SCRIBE",

View File

@@ -70,7 +70,7 @@ contexts:
scope: constant.language.centvrion
builtins:
- match: '\b(ADIVNGE|AVDI_NVMERVS|AVDI|AVSCVLTA|CLAVES|DECIMATIO|DIC|DORMI|EVERRE|FORTVITVS_NVMERVS|FORTVITA_ELECTIO|LEGE|LITTERA|LONGITVDO|MAIVSCVLA|MINVSCVLA|NVMERVS|ORDINA|PETE|PETITVR|QVAERE|SCINDE|SCRIBE|SEMEN|SENATVS|SVBSTITVE|TYPVS)\b'
- match: '\b(ADDE|ADIVNGE|AVDI_NVMERVS|AVDI|AVSCVLTA|CLAVES|DECIMATIO|DIC|DORMI|EVERRE|FORTVITVS_NVMERVS|FORTVITA_ELECTIO|INSERE|LEGE|LITTERA|LONGITVDO|MAIVSCVLA|MINVSCVLA|NVMERVS|ORDINA|PETE|PETITVR|QVAERE|SCINDE|SCRIBE|SEMEN|SENATVS|SVBSTITVE|TOLLE|TYPVS)\b'
scope: support.function.builtin.centvrion
modules:

View File

@@ -76,6 +76,30 @@ builtin_tests = [
("CVM FRACTIO\nORDINA([III, S, II])", Program([ModuleCall("FRACTIO")], [ExpressionStatement(BuiltIn("ORDINA", [DataArray([Numeral("III"), Fractio("S"), Numeral("II")])]))]), ValList([ValFrac(Fraction(1, 2)), ValInt(2), ValInt(3)])),
# ORDINA: array passed via variable
("DESIGNA x VT [III, I, II]\nORDINA(x)", Program([], [Designa(ID("x"), DataArray([Numeral("III"), Numeral("I"), Numeral("II")])), ExpressionStatement(BuiltIn("ORDINA", [ID("x")]))]), ValList([ValInt(1), ValInt(2), ValInt(3)])),
# ADDE: append to non-empty
("ADDE([I, II], III)", Program([], [ExpressionStatement(BuiltIn("ADDE", [DataArray([Numeral("I"), Numeral("II")]), Numeral("III")]))]), ValList([ValInt(1), ValInt(2), ValInt(3)])),
# ADDE: append to empty
("ADDE([], V)", Program([], [ExpressionStatement(BuiltIn("ADDE", [DataArray([]), Numeral("V")]))]), ValList([ValInt(5)])),
# ADDE: heterogeneous types are allowed
('ADDE([I, II], "x")', Program([], [ExpressionStatement(BuiltIn("ADDE", [DataArray([Numeral("I"), Numeral("II")]), String("x")]))]), ValList([ValInt(1), ValInt(2), ValStr("x")])),
# ADDE: print form to confirm output rendering
("DIC(ADDE([I, II], III))", Program([], [ExpressionStatement(BuiltIn("DIC", [BuiltIn("ADDE", [DataArray([Numeral("I"), Numeral("II")]), Numeral("III")])]))]), ValStr("[I II III]"), "[I II III]\n"),
# TOLLE: remove middle element
("TOLLE([I, II, III], II)", Program([], [ExpressionStatement(BuiltIn("TOLLE", [DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("II")]))]), ValList([ValInt(1), ValInt(3)])),
# TOLLE: remove first element
("TOLLE([I, II, III], I)", Program([], [ExpressionStatement(BuiltIn("TOLLE", [DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("I")]))]), ValList([ValInt(2), ValInt(3)])),
# TOLLE: remove last element
("TOLLE([I, II, III], III)", Program([], [ExpressionStatement(BuiltIn("TOLLE", [DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("III")]))]), ValList([ValInt(1), ValInt(2)])),
# TOLLE: single-element array → empty
("TOLLE([V], I)", Program([], [ExpressionStatement(BuiltIn("TOLLE", [DataArray([Numeral("V")]), Numeral("I")]))]), ValList([])),
# INSERE: insert into middle
("INSERE([I, III], II, II)", Program([], [ExpressionStatement(BuiltIn("INSERE", [DataArray([Numeral("I"), Numeral("III")]), Numeral("II"), Numeral("II")]))]), ValList([ValInt(1), ValInt(2), ValInt(3)])),
# INSERE: insert at front
("INSERE([II, III], I, I)", Program([], [ExpressionStatement(BuiltIn("INSERE", [DataArray([Numeral("II"), Numeral("III")]), Numeral("I"), Numeral("I")]))]), ValList([ValInt(1), ValInt(2), ValInt(3)])),
# INSERE: insert at len+1 (== append)
("INSERE([I, II], III, III)", Program([], [ExpressionStatement(BuiltIn("INSERE", [DataArray([Numeral("I"), Numeral("II")]), Numeral("III"), Numeral("III")]))]), ValList([ValInt(1), ValInt(2), ValInt(3)])),
# INSERE: into empty array at idx 1
("INSERE([], I, V)", Program([], [ExpressionStatement(BuiltIn("INSERE", [DataArray([]), Numeral("I"), Numeral("V")]))]), ValList([ValInt(5)])),
# TYPVS: integer
("TYPVS(V)", Program([], [ExpressionStatement(BuiltIn("TYPVS", [Numeral("V")]))]), ValStr("NVMERVS")),
# TYPVS: string

View File

@@ -65,7 +65,7 @@
"patterns": [
{
"name": "support.function.builtin.cent",
"match": "\\b(ADIVNGE|AVDI_NVMERVS|AVDI|AVSCVLTA|CLAVES|DECIMATIO|DIC|DORMI|EVERRE|FORTVITVS_NVMERVS|FORTVITA_ELECTIO|LEGE|LITTERA|LONGITVDO|MAIVSCVLA|MINVSCVLA|NVMERVS|ORDINA|PETE|PETITVR|QVAERE|SCINDE|SCRIBE|SEMEN|SENATVS|SVBSTITVE|TYPVS)\\b"
"match": "\\b(ADDE|ADIVNGE|AVDI_NVMERVS|AVDI|AVSCVLTA|CLAVES|DECIMATIO|DIC|DORMI|EVERRE|FORTVITVS_NVMERVS|FORTVITA_ELECTIO|INSERE|LEGE|LITTERA|LONGITVDO|MAIVSCVLA|MINVSCVLA|NVMERVS|ORDINA|PETE|PETITVR|QVAERE|SCINDE|SCRIBE|SEMEN|SENATVS|SVBSTITVE|TOLLE|TYPVS)\\b"
}
]
},