🐐 Dict

This commit is contained in:
2026-04-21 17:37:12 +02:00
parent 264ea84dfc
commit db5b7bf144
12 changed files with 456 additions and 25 deletions

View File

@@ -5,7 +5,7 @@ from fractions import Fraction
from rply.token import BaseBox
from centvrion.errors import CentvrionError
from centvrion.values import Val, ValInt, ValStr, ValBool, ValList, ValNul, ValFunc, ValFrac
from centvrion.values import Val, ValInt, ValStr, ValBool, ValList, ValDict, ValNul, ValFunc, ValFrac
NUMERALS = {
"I": 1,
@@ -136,6 +136,14 @@ def make_string(val, magnvm=False, svbnvlla=False) -> str:
elif isinstance(val, ValList):
inner = ' '.join(make_string(i, magnvm, svbnvlla) for i in val.value())
return f"[{inner}]"
elif isinstance(val, ValDict):
def _key_val(k):
return ValStr(k) if isinstance(k, str) else ValInt(k)
inner = ', '.join(
f"{make_string(_key_val(k), magnvm, svbnvlla)} VT {make_string(v, magnvm, svbnvlla)}"
for k, v in val.value().items()
)
return "{" + inner + "}"
else:
raise CentvrionError(f"Cannot display {val!r}")
@@ -272,6 +280,32 @@ class DataRangeArray(Node):
return vtable, ValList([ValInt(i) for i in range(from_int, to_int)])
class DataDict(Node):
def __init__(self, pairs) -> None:
self.pairs = pairs
def __eq__(self, other):
return type(self) == type(other) and self.pairs == other.pairs
def __repr__(self) -> str:
pair_strs = ', '.join(f"({k!r}, {v!r})" for k, v in self.pairs)
return f"Dict([{pair_strs}])"
def print(self):
items = ", ".join(f"{k.print()} VT {v.print()}" for k, v in self.pairs)
return "TABVLA {" + items + "}"
def _eval(self, vtable):
d = {}
for key_node, val_node in self.pairs:
vtable, key = key_node.eval(vtable)
vtable, val = val_node.eval(vtable)
if not isinstance(key, (ValStr, ValInt)):
raise CentvrionError("Dict keys must be strings or integers")
d[key.value()] = val
return vtable, ValDict(d)
class String(Node):
def __init__(self, value) -> None:
self.value = value
@@ -469,8 +503,15 @@ class DesignaIndex(Node):
if self.id.name not in vtable:
raise CentvrionError(f"Undefined variable: {self.id.name}")
target = vtable[self.id.name]
if isinstance(target, ValDict):
if not isinstance(index, (ValStr, ValInt)):
raise CentvrionError("Dict key must be a string or integer")
d = dict(target.value())
d[index.value()] = val
vtable[self.id.name] = ValDict(d)
return vtable, ValNul()
if not isinstance(target, ValList):
raise CentvrionError(f"{self.id.name} is not an array")
raise CentvrionError(f"{self.id.name} is not an array or dict")
i = index.value()
lst = list(target.value())
if i < 1 or i > len(lst):
@@ -756,6 +797,14 @@ class ArrayIndex(Node):
def _eval(self, vtable):
vtable, array = self.array.eval(vtable)
vtable, index = self.index.eval(vtable)
if isinstance(array, ValDict):
if not isinstance(index, (ValStr, ValInt)):
raise CentvrionError("Dict key must be a string or integer")
k = index.value()
d = array.value()
if k not in d:
raise CentvrionError(f"Key not found in dict")
return vtable, d[k]
if not isinstance(array, ValList):
raise CentvrionError("Cannot index a non-array value")
if isinstance(index, ValInt):
@@ -879,8 +928,11 @@ class PerStatement(Node):
def _eval(self, vtable):
vtable, array = self.data_list.eval(vtable)
if isinstance(array, ValDict):
keys = [ValStr(k) if isinstance(k, str) else ValInt(k) for k in array.value().keys()]
array = ValList(keys)
if not isinstance(array, ValList):
raise CentvrionError("PER requires an array")
raise CentvrionError("PER requires an array or dict")
variable_name = self.variable_name.name
last_val = ValNul()
for item in array:
@@ -1027,9 +1079,14 @@ class BuiltIn(Node):
true_count = sum(1 for p in items if p.value())
return vtable, ValBool(true_count > len(items) / 2)
case "LONGITVDO":
if isinstance(params[0], (ValList, ValStr)):
if isinstance(params[0], (ValList, ValStr, ValDict)):
return vtable, ValInt(len(params[0].value()))
raise CentvrionError("LONGITVDO requires an array or string")
raise CentvrionError("LONGITVDO requires an array, string, or dict")
case "CLAVES":
if not isinstance(params[0], ValDict):
raise CentvrionError("CLAVES requires a dict")
keys = [ValStr(k) if isinstance(k, str) else ValInt(k) for k in params[0].value().keys()]
return vtable, ValList(keys)
case "EVERRO":
print("\033[2J\033[H", end="", flush=True)
return vtable, ValNul()