🐐 Zipping
This commit is contained in:
10
README.md
10
README.md
@@ -376,6 +376,16 @@ Returns a new array with the element at 1-based position `idx` removed. The inde
|
||||
|
||||
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])`
|
||||
|
||||
|
||||
@@ -1522,6 +1522,29 @@ class BuiltIn(Node):
|
||||
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 "NECTE":
|
||||
if len(params) != 2:
|
||||
raise CentvrionError("NECTE takes exactly II arguments")
|
||||
if not isinstance(params[0], ValList) or not isinstance(params[1], ValList):
|
||||
raise CentvrionError("NECTE requires two arrays")
|
||||
a, b = list(params[0].value()), list(params[1].value())
|
||||
if len(a) != len(b):
|
||||
raise CentvrionError("NECTE requires arrays of equal length")
|
||||
return vtable, ValList([ValList([x, y]) for x, y in zip(a, b)])
|
||||
case "IVNGE":
|
||||
if len(params) != 2:
|
||||
raise CentvrionError("IVNGE takes exactly II arguments")
|
||||
if not isinstance(params[0], ValList) or not isinstance(params[1], ValList):
|
||||
raise CentvrionError("IVNGE requires two arrays")
|
||||
keys, vals = list(params[0].value()), list(params[1].value())
|
||||
if len(keys) != len(vals):
|
||||
raise CentvrionError("IVNGE requires arrays of equal length")
|
||||
d = {}
|
||||
for k, v in zip(keys, vals):
|
||||
if not isinstance(k, (ValStr, ValInt)):
|
||||
raise CentvrionError("Dict keys must be strings or integers")
|
||||
d[k.value()] = v
|
||||
return vtable, ValDict(d)
|
||||
case "ORDINA":
|
||||
if not isinstance(params[0], ValList):
|
||||
raise CentvrionError("ORDINA requires an array")
|
||||
|
||||
@@ -322,6 +322,12 @@ def _emit_builtin(node, ctx):
|
||||
case "INSERE":
|
||||
lines.append(f"CentValue {tmp} = cent_insere({param_vars[0]}, {param_vars[1]}, {param_vars[2]});")
|
||||
|
||||
case "NECTE":
|
||||
lines.append(f"CentValue {tmp} = cent_necte({param_vars[0]}, {param_vars[1]});")
|
||||
|
||||
case "IVNGE":
|
||||
lines.append(f"CentValue {tmp} = cent_ivnge({param_vars[0]}, {param_vars[1]});")
|
||||
|
||||
case "EVERRE":
|
||||
lines.append("cent_everre();")
|
||||
lines.append(f"CentValue {tmp} = cent_null();")
|
||||
|
||||
@@ -898,6 +898,38 @@ CentValue cent_insere(CentValue lst, CentValue idx, CentValue v) {
|
||||
return result;
|
||||
}
|
||||
|
||||
CentValue cent_necte(CentValue a, CentValue b) {
|
||||
if (a.type != CENT_LIST || b.type != CENT_LIST)
|
||||
cent_type_error("'NECTE' requires two arrays");
|
||||
if (a.lval.len != b.lval.len)
|
||||
cent_runtime_error("'NECTE' requires arrays of equal length");
|
||||
int len = a.lval.len;
|
||||
CentValue result = cent_list_new(len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
CentValue pair = cent_list_new(2);
|
||||
cent_list_push(&pair, a.lval.items[i]);
|
||||
cent_list_push(&pair, b.lval.items[i]);
|
||||
cent_list_push(&result, pair);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
CentValue cent_ivnge(CentValue keys, CentValue vals) {
|
||||
if (keys.type != CENT_LIST || vals.type != CENT_LIST)
|
||||
cent_type_error("'IVNGE' requires two arrays");
|
||||
if (keys.lval.len != vals.lval.len)
|
||||
cent_runtime_error("'IVNGE' requires arrays of equal length");
|
||||
int len = keys.lval.len;
|
||||
CentValue result = cent_dict_new(len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
CentValue k = keys.lval.items[i];
|
||||
if (k.type != CENT_INT && k.type != CENT_STR)
|
||||
cent_runtime_error("Dict keys must be strings or integers");
|
||||
cent_dict_set(&result, k, vals.lval.items[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Array helpers */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
@@ -242,6 +242,8 @@ 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_necte(CentValue a, CentValue b); /* NECTE */
|
||||
CentValue cent_ivnge(CentValue keys, CentValue vals); /* IVNGE */
|
||||
CentValue cent_lege(CentValue path); /* LEGE */
|
||||
void cent_scribe(CentValue path, CentValue content); /* SCRIBE */
|
||||
void cent_adivnge(CentValue path, CentValue content); /* ADIVNGE */
|
||||
|
||||
@@ -57,10 +57,12 @@ builtin_tokens = [("BUILTIN", i) for i in [
|
||||
"FORTVITVS_NVMERVS",
|
||||
"FORTVITA_ELECTIO",
|
||||
"INSERE",
|
||||
"IVNGE",
|
||||
"LITTERA",
|
||||
"LONGITVDO",
|
||||
"MAIVSCVLA",
|
||||
"MINVSCVLA",
|
||||
"NECTE",
|
||||
"NVMERVS",
|
||||
"ORDINA",
|
||||
"SEMEN",
|
||||
|
||||
@@ -70,7 +70,7 @@ contexts:
|
||||
scope: constant.language.centvrion
|
||||
|
||||
builtins:
|
||||
- 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'
|
||||
- match: '\b(ADDE|ADIVNGE|AVDI_NVMERVS|AVDI|AVSCVLTA|CLAVES|DECIMATIO|DIC|DORMI|EVERRE|FORTVITVS_NVMERVS|FORTVITA_ELECTIO|INSERE|IVNGE|LEGE|LITTERA|LONGITVDO|MAIVSCVLA|MINVSCVLA|NECTE|NVMERVS|ORDINA|PETE|PETITVR|QVAERE|SCINDE|SCRIBE|SEMEN|SENATVS|SVBSTITVE|TOLLE|TYPVS)\b'
|
||||
scope: support.function.builtin.centvrion
|
||||
|
||||
modules:
|
||||
|
||||
@@ -242,6 +242,30 @@ builtin_tests = [
|
||||
('MINVSCVLA("A,B!1")', Program([], [ExpressionStatement(BuiltIn("MINVSCVLA", [String("A,B!1")]))]), ValStr("a,b!1")),
|
||||
# MINVSCVLA round-trips MAIVSCVLA on lowercase input
|
||||
('MINVSCVLA(MAIVSCVLA("hi"))', Program([], [ExpressionStatement(BuiltIn("MINVSCVLA", [BuiltIn("MAIVSCVLA", [String("hi")])]))]), ValStr("hi")),
|
||||
# NECTE: zip two integer arrays
|
||||
("NECTE([I, II, III], [IV, V, VI])", Program([], [ExpressionStatement(BuiltIn("NECTE", [DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), DataArray([Numeral("IV"), Numeral("V"), Numeral("VI")])]))]), ValList([ValList([ValInt(1), ValInt(4)]), ValList([ValInt(2), ValInt(5)]), ValList([ValInt(3), ValInt(6)])])),
|
||||
# NECTE: empty + empty
|
||||
("NECTE([], [])", Program([], [ExpressionStatement(BuiltIn("NECTE", [DataArray([]), DataArray([])]))]), ValList([])),
|
||||
# NECTE: single element
|
||||
("NECTE([I], [II])", Program([], [ExpressionStatement(BuiltIn("NECTE", [DataArray([Numeral("I")]), DataArray([Numeral("II")])]))]), ValList([ValList([ValInt(1), ValInt(2)])])),
|
||||
# NECTE: mixed types (numerals paired with strings)
|
||||
('NECTE([I, II], ["a", "b"])', Program([], [ExpressionStatement(BuiltIn("NECTE", [DataArray([Numeral("I"), Numeral("II")]), DataArray([String("a"), String("b")])]))]), ValList([ValList([ValInt(1), ValStr("a")]), ValList([ValInt(2), ValStr("b")])])),
|
||||
# NECTE: print form
|
||||
('DIC(NECTE([I, II], [III, IV]))', Program([], [ExpressionStatement(BuiltIn("DIC", [BuiltIn("NECTE", [DataArray([Numeral("I"), Numeral("II")]), DataArray([Numeral("III"), Numeral("IV")])])]))]), ValStr("[[I III] [II IV]]"), "[[I III] [II IV]]\n"),
|
||||
# NECTE: via variables
|
||||
("DESIGNA a VT [I, II]\nDESIGNA b VT [III, IV]\nNECTE(a, b)", Program([], [Designa(ID("a"), DataArray([Numeral("I"), Numeral("II")])), Designa(ID("b"), DataArray([Numeral("III"), Numeral("IV")])), ExpressionStatement(BuiltIn("NECTE", [ID("a"), ID("b")]))]), ValList([ValList([ValInt(1), ValInt(3)]), ValList([ValInt(2), ValInt(4)])])),
|
||||
# IVNGE: string keys
|
||||
('IVNGE(["a", "b"], [I, II])', Program([], [ExpressionStatement(BuiltIn("IVNGE", [DataArray([String("a"), String("b")]), DataArray([Numeral("I"), Numeral("II")])]))]), ValDict({"a": ValInt(1), "b": ValInt(2)})),
|
||||
# IVNGE: integer keys
|
||||
('IVNGE([I, II], ["one", "two"])', Program([], [ExpressionStatement(BuiltIn("IVNGE", [DataArray([Numeral("I"), Numeral("II")]), DataArray([String("one"), String("two")])]))]), ValDict({1: ValStr("one"), 2: ValStr("two")})),
|
||||
# IVNGE: empty + empty
|
||||
("IVNGE([], [])", Program([], [ExpressionStatement(BuiltIn("IVNGE", [DataArray([]), DataArray([])]))]), ValDict({})),
|
||||
# IVNGE: duplicate keys → last wins
|
||||
('IVNGE(["a", "a"], [I, II])', Program([], [ExpressionStatement(BuiltIn("IVNGE", [DataArray([String("a"), String("a")]), DataArray([Numeral("I"), Numeral("II")])]))]), ValDict({"a": ValInt(2)})),
|
||||
# IVNGE: print form
|
||||
('DIC(IVNGE(["a", "b"], [I, II]))', Program([], [ExpressionStatement(BuiltIn("DIC", [BuiltIn("IVNGE", [DataArray([String("a"), String("b")]), DataArray([Numeral("I"), Numeral("II")])])]))]), ValStr("{a VT I, b VT II}"), "{a VT I, b VT II}\n"),
|
||||
# IVNGE composes with CLAVES (round-trip keys)
|
||||
('CLAVES(IVNGE(["a", "b"], [I, II]))', Program([], [ExpressionStatement(BuiltIn("CLAVES", [BuiltIn("IVNGE", [DataArray([String("a"), String("b")]), DataArray([Numeral("I"), Numeral("II")])])]))]), ValList([ValStr("a"), ValStr("b")])),
|
||||
]
|
||||
|
||||
class TestBuiltins(unittest.TestCase):
|
||||
|
||||
@@ -132,6 +132,14 @@ error_tests = [
|
||||
('CVM RETE\nPETITVR("/", FVNCTIO (r) VT {\nREDI("hi")\n})\nAVSCVLTA("text")', CentvrionError), # AVSCVLTA port must be integer
|
||||
("DONICVM i VT I VSQVE X GRADV I - I FAC { DIC(i) }", CentvrionError), # GRADV zero step
|
||||
('DONICVM i VT I VSQVE X GRADV "foo" FAC { DIC(i) }', CentvrionError), # GRADV non-integer step
|
||||
("NECTE([I, II], [III])", CentvrionError), # NECTE length mismatch
|
||||
('NECTE(I, [II])', CentvrionError), # NECTE first arg not a list
|
||||
('NECTE([I], II)', CentvrionError), # NECTE second arg not a list
|
||||
("IVNGE([I, II], [III])", CentvrionError), # IVNGE length mismatch
|
||||
('IVNGE(I, [II])', CentvrionError), # IVNGE first arg not a list
|
||||
('IVNGE(["a"], II)', CentvrionError), # IVNGE second arg not a list
|
||||
("IVNGE([VERITAS], [I])", CentvrionError), # IVNGE invalid key type (bool)
|
||||
("IVNGE([[I]], [II])", CentvrionError), # IVNGE invalid key type (list)
|
||||
]
|
||||
|
||||
class TestErrors(unittest.TestCase):
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
"patterns": [
|
||||
{
|
||||
"name": "support.function.builtin.cent",
|
||||
"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"
|
||||
"match": "\\b(ADDE|ADIVNGE|AVDI_NVMERVS|AVDI|AVSCVLTA|CLAVES|DECIMATIO|DIC|DORMI|EVERRE|FORTVITVS_NVMERVS|FORTVITA_ELECTIO|INSERE|IVNGE|LEGE|LITTERA|LONGITVDO|MAIVSCVLA|MINVSCVLA|NECTE|NVMERVS|ORDINA|PETE|PETITVR|QVAERE|SCINDE|SCRIBE|SEMEN|SENATVS|SVBSTITVE|TOLLE|TYPVS)\\b"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user