🐐 Array indexing

This commit is contained in:
2026-03-31 22:10:55 +02:00
parent cdad648f58
commit 58149b5f65
4 changed files with 41 additions and 7 deletions

View File

@@ -102,6 +102,15 @@ Arrays are defined using square brackets (`[]`) and commas (`,`). An array of in
DESIGNA x VT [I VSQVE X] DESIGNA x VT [I VSQVE X]
``` ```
Individual elements can be accessed by index using square brackets. Indexing is 1-based, so `I` refers to the first element:
```
DESIGNA x VT [(I, II, III)]
DICE(x[I])
> I
```
## Conditionals ## Conditionals
### SI/TVNC ### SI/TVNC
If-then statements are denoted with the keywords `SI` (if) and `TVNC` (then). Thus, the code If-then statements are denoted with the keywords `SI` (if) and `TVNC` (then). Thus, the code

View File

@@ -342,6 +342,24 @@ class UnaryMinus(Node):
return vtable, ValInt(-val.value()) return vtable, ValInt(-val.value())
class ArrayIndex(Node):
def __init__(self, array, index) -> None:
self.array = array
self.index = index
def __repr__(self) -> str:
return f"ArrayIndex({self.array!r}, {self.index!r})"
def _eval(self, vtable):
vtable, array = self.array.eval(vtable)
vtable, index = self.index.eval(vtable)
i = index.value()
lst = array.value()
if i < 1 or i > len(lst):
raise IndexError(f"Index {i} out of range for array of length {len(lst)}")
return vtable, lst[i - 1]
class SiStatement(Node): class SiStatement(Node):
def __init__(self, test, statements, else_part) -> None: def __init__(self, test, statements, else_part) -> None:
self.test = test self.test = test

View File

@@ -16,6 +16,7 @@ class Parser():
('left', ["SYMBOL_PLUS", "SYMBOL_MINUS"]), ('left', ["SYMBOL_PLUS", "SYMBOL_MINUS"]),
('left', ["SYMBOL_TIMES", "SYMBOL_DIVIDE"]), ('left', ["SYMBOL_TIMES", "SYMBOL_DIVIDE"]),
('right', ["UMINUS"]), ('right', ["UMINUS"]),
('left', ["INDEX"]),
] ]
) )
@@ -194,6 +195,10 @@ class Parser():
def range_array(tokens): def range_array(tokens):
return ast_nodes.DataRangeArray(tokens[1], tokens[3]) return ast_nodes.DataRangeArray(tokens[1], tokens[3])
@self.pg.production('expression : expression SYMBOL_LBRACKET expression SYMBOL_RBRACKET', precedence='INDEX')
def array_index(tokens):
return ast_nodes.ArrayIndex(tokens[0], tokens[2])
# ids # ids
@self.pg.production('ids : SYMBOL_LPARENS id_list') @self.pg.production('ids : SYMBOL_LPARENS id_list')
def ids(tokens): def ids(tokens):

View File

@@ -5,7 +5,7 @@ from unittest.mock import patch
from parameterized import parameterized from parameterized import parameterized
from centvrion.ast_nodes import ( from centvrion.ast_nodes import (
Bool, BinOp, BuiltIn, DataArray, DataRangeArray, Defini, ArrayIndex, Bool, BinOp, BuiltIn, DataArray, DataRangeArray, Defini,
Designa, DumStatement, Erumpe, ExpressionStatement, ID, Designa, DumStatement, Erumpe, ExpressionStatement, ID,
Invoca, ModuleCall, Nullus, Numeral, PerStatement, Invoca, ModuleCall, Nullus, Numeral, PerStatement,
Program, Redi, SiStatement, String, UnaryMinus, Program, Redi, SiStatement, String, UnaryMinus,
@@ -231,6 +231,8 @@ error_tests = [
("DEFINI f (x, y) VT { REDI(x) }\nINVOCA f (I)", TypeError), # too few args ("DEFINI f (x, y) VT { REDI(x) }\nINVOCA f (I)", TypeError), # too few args
("DEFINI f () VT { REDI(I) }\nINVOCA f (I)", TypeError), # args to zero-param function ("DEFINI f () VT { REDI(I) }\nINVOCA f (I)", TypeError), # args to zero-param function
("SI NVLLVS TVNC { DESIGNA r VT I }", TypeError), # NVLLVS cannot be used as boolean ("SI NVLLVS TVNC { DESIGNA r VT I }", TypeError), # NVLLVS cannot be used as boolean
("[(I, II)][III]", IndexError), # index too high
("[(I, II)][-I]", IndexError), # negative index
] ]
class TestErrors(unittest.TestCase): class TestErrors(unittest.TestCase):
@@ -604,17 +606,17 @@ class TestEtAvt(unittest.TestCase):
# --- Array indexing --- # --- Array indexing ---
# Indexing is 0-based; NVLLVS serves as index 0 # Indexing is 1-based; I is the first element
array_index_tests = [ array_index_tests = [
# basic indexing # basic indexing
("[(I, II, III)][NVLLVS]", None, ValInt(1)), # index 0 → first element ("[(I, II, III)][I]", None, ValInt(1)), # first element
("[(I, II, III)][I]", None, ValInt(2)), # index 1 → second element ("[(I, II, III)][II]", None, ValInt(2)), # second element
("[(I, II, III)][II]", None, ValInt(3)), # index 2 → third element ("[(I, II, III)][III]", None, ValInt(3)), # third element
# index into a variable # index into a variable
("DESIGNA a VT [(X, XX, XXX)]\na[I]", None, ValInt(20)), ("DESIGNA a VT [(X, XX, XXX)]\na[II]", None, ValInt(20)), # second element
# index into range array # index into range array
("[I VSQVE V][II]", None, ValInt(3)), ("[I VSQVE V][II]", None, ValInt(2)), # second element of [1,2,3,4]
] ]
class TestArrayIndex(unittest.TestCase): class TestArrayIndex(unittest.TestCase):