Files
centvrion/tests/07_test_arrays__.py
2026-04-24 19:13:48 +02:00

274 lines
12 KiB
Python

from tests._helpers import (
unittest, parameterized, Fraction, time,
run_test, run_compiler_error_test,
ArrayIndex, ArraySlice, Bool, BinOp, BuiltIn, DataArray, DataDict, DataRangeArray,
Defini, Continva, Designa, DesignaDestructure, DesignaIndex, DumStatement,
Erumpe, ExpressionStatement, Fvnctio, ID, InterpolatedString, Invoca,
ModuleCall, Nullus, Numeral, PerStatement, Program, Redi, SiStatement,
String, TemptaStatement, UnaryMinus, UnaryNot, Fractio, frac_to_fraction,
fraction_to_frac, num_to_int, int_to_num, make_string,
ValInt, ValStr, ValBool, ValList, ValDict, ValNul, ValFunc, ValFrac,
CentvrionError, _RUNTIME_C, _cent_rng,
Lexer, Parser, compile_program,
os, subprocess, tempfile, StringIO, patch,
)
# --- Array concatenation ---
array_concat_tests = [
("[I, II] @ [III, IV]",
Program([], [ExpressionStatement(BinOp(DataArray([Numeral("I"), Numeral("II")]), DataArray([Numeral("III"), Numeral("IV")]), "SYMBOL_AT"))]),
ValList([ValInt(1), ValInt(2), ValInt(3), ValInt(4)])),
("[] @ [I]",
Program([], [ExpressionStatement(BinOp(DataArray([]), DataArray([Numeral("I")]), "SYMBOL_AT"))]),
ValList([ValInt(1)])),
("[I] @ []",
Program([], [ExpressionStatement(BinOp(DataArray([Numeral("I")]), DataArray([]), "SYMBOL_AT"))]),
ValList([ValInt(1)])),
("[] @ []",
Program([], [ExpressionStatement(BinOp(DataArray([]), DataArray([]), "SYMBOL_AT"))]),
ValList([])),
('["a"] @ [I]',
Program([], [ExpressionStatement(BinOp(DataArray([String("a")]), DataArray([Numeral("I")]), "SYMBOL_AT"))]),
ValList([ValStr("a"), ValInt(1)])),
# left-associative chaining
("[I] @ [II] @ [III]",
Program([], [ExpressionStatement(BinOp(BinOp(DataArray([Numeral("I")]), DataArray([Numeral("II")]), "SYMBOL_AT"), DataArray([Numeral("III")]), "SYMBOL_AT"))]),
ValList([ValInt(1), ValInt(2), ValInt(3)])),
# concat with variable
("DESIGNA a VT [I, II]\nDESIGNA b VT [III]\na @ b",
Program([], [Designa(ID("a"), DataArray([Numeral("I"), Numeral("II")])), Designa(ID("b"), DataArray([Numeral("III")])), ExpressionStatement(BinOp(ID("a"), ID("b"), "SYMBOL_AT"))]),
ValList([ValInt(1), ValInt(2), ValInt(3)])),
]
class TestArrayConcat(unittest.TestCase):
@parameterized.expand(array_concat_tests)
def test_array_concat(self, source, nodes, value):
run_test(self, source, nodes, value)
# --- Array indexing ---
# Indexing is 1-based; I is the first element
array_index_tests = [
# basic indexing
("[I, II, III][I]", Program([], [ExpressionStatement(ArrayIndex(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("I")))]), ValInt(1)), # first element
("[I, II, III][II]", Program([], [ExpressionStatement(ArrayIndex(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("II")))]), ValInt(2)), # second element
("[I, II, III][III]", Program([], [ExpressionStatement(ArrayIndex(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("III")))]), ValInt(3)), # third element
# index into a variable
("DESIGNA a VT [X, XX, XXX]\na[II]",
Program([], [Designa(ID("a"), DataArray([Numeral("X"), Numeral("XX"), Numeral("XXX")])), ExpressionStatement(ArrayIndex(ID("a"), Numeral("II")))]),
ValInt(20)), # second element
# index into range array
("[I VSQVE V][II]", Program([], [ExpressionStatement(ArrayIndex(DataRangeArray(Numeral("I"), Numeral("V")), Numeral("II")))]), ValInt(2)), # second element of [1,2,3,4,5]
# expression as index
("[I, II, III][I + I]",
Program([], [ExpressionStatement(ArrayIndex(
DataArray([Numeral("I"), Numeral("II"), Numeral("III")]),
BinOp(Numeral("I"), Numeral("I"), "SYMBOL_PLUS")))]),
ValInt(2)),
# division result as index (no FRACTIO): IV / II = 2
("[X, XX, XXX][IV / II]",
Program([], [ExpressionStatement(ArrayIndex(
DataArray([Numeral("X"), Numeral("XX"), Numeral("XXX")]),
BinOp(Numeral("IV"), Numeral("II"), "SYMBOL_DIVIDE")))]),
ValInt(20)),
# whole-number fraction (from division) as index, with FRACTIO imported
("CVM FRACTIO\n[X, XX, XXX][IV / II]",
Program([ModuleCall("FRACTIO")], [ExpressionStatement(ArrayIndex(
DataArray([Numeral("X"), Numeral("XX"), Numeral("XXX")]),
BinOp(Numeral("IV"), Numeral("II"), "SYMBOL_DIVIDE")))]),
ValInt(20)),
]
class TestArrayIndex(unittest.TestCase):
@parameterized.expand(array_index_tests)
def test_array_index(self, source, nodes, value):
run_test(self, source, nodes, value)
# --- Array index assignment ---
array_index_assign_tests = [
# assign to middle element
("DESIGNA a VT [I, II, III]\nDESIGNA a[II] VT X\na[II]",
Program([], [
Designa(ID("a"), DataArray([Numeral("I"), Numeral("II"), Numeral("III")])),
DesignaIndex(ID("a"), [Numeral("II")], Numeral("X")),
ExpressionStatement(ArrayIndex(ID("a"), Numeral("II"))),
]),
ValInt(10)),
# assign to first element
("DESIGNA a VT [I, II, III]\nDESIGNA a[I] VT V\na[I]",
Program([], [
Designa(ID("a"), DataArray([Numeral("I"), Numeral("II"), Numeral("III")])),
DesignaIndex(ID("a"), [Numeral("I")], Numeral("V")),
ExpressionStatement(ArrayIndex(ID("a"), Numeral("I"))),
]),
ValInt(5)),
# assign to last element
("DESIGNA a VT [I, II, III]\nDESIGNA a[III] VT L\na[III]",
Program([], [
Designa(ID("a"), DataArray([Numeral("I"), Numeral("II"), Numeral("III")])),
DesignaIndex(ID("a"), [Numeral("III")], Numeral("L")),
ExpressionStatement(ArrayIndex(ID("a"), Numeral("III"))),
]),
ValInt(50)),
# other elements unaffected
("DESIGNA a VT [I, II, III]\nDESIGNA a[II] VT X\na[I]",
Program([], [
Designa(ID("a"), DataArray([Numeral("I"), Numeral("II"), Numeral("III")])),
DesignaIndex(ID("a"), [Numeral("II")], Numeral("X")),
ExpressionStatement(ArrayIndex(ID("a"), Numeral("I"))),
]),
ValInt(1)),
# expression as index
("DESIGNA a VT [I, II, III]\nDESIGNA i VT II\nDESIGNA a[i] VT X\na[II]",
Program([], [
Designa(ID("a"), DataArray([Numeral("I"), Numeral("II"), Numeral("III")])),
Designa(ID("i"), Numeral("II")),
DesignaIndex(ID("a"), [ID("i")], Numeral("X")),
ExpressionStatement(ArrayIndex(ID("a"), Numeral("II"))),
]),
ValInt(10)),
]
class TestArrayIndexAssign(unittest.TestCase):
@parameterized.expand(array_index_assign_tests)
def test_array_index_assign(self, source, nodes, value):
run_test(self, source, nodes, value)
# --- Multi-dimensional array index assignment ---
multidim_assign_tests = [
# 2D array assignment
("DESIGNA a VT [[I, II], [III, IV]]\nDESIGNA a[I][II] VT X\na[I][II]",
Program([], [
Designa(ID("a"), DataArray([DataArray([Numeral("I"), Numeral("II")]), DataArray([Numeral("III"), Numeral("IV")])])),
DesignaIndex(ID("a"), [Numeral("I"), Numeral("II")], Numeral("X")),
ExpressionStatement(ArrayIndex(ArrayIndex(ID("a"), Numeral("I")), Numeral("II"))),
]),
ValInt(10)),
# other elements unaffected
("DESIGNA a VT [[I, II], [III, IV]]\nDESIGNA a[I][II] VT X\na[II][I]",
Program([], [
Designa(ID("a"), DataArray([DataArray([Numeral("I"), Numeral("II")]), DataArray([Numeral("III"), Numeral("IV")])])),
DesignaIndex(ID("a"), [Numeral("I"), Numeral("II")], Numeral("X")),
ExpressionStatement(ArrayIndex(ArrayIndex(ID("a"), Numeral("II")), Numeral("I"))),
]),
ValInt(3)),
# dict inside array
('DESIGNA a VT [TABVLA {"x" VT I}]\nDESIGNA a[I]["x"] VT X\na[I]["x"]',
Program([], [
Designa(ID("a"), DataArray([DataDict([(String("x"), Numeral("I"))])])),
DesignaIndex(ID("a"), [Numeral("I"), String("x")], Numeral("X")),
ExpressionStatement(ArrayIndex(ArrayIndex(ID("a"), Numeral("I")), String("x"))),
]),
ValInt(10)),
# array inside dict
('DESIGNA d VT TABVLA {"a" VT [I, II]}\nDESIGNA d["a"][I] VT X\nd["a"][I]',
Program([], [
Designa(ID("d"), DataDict([(String("a"), DataArray([Numeral("I"), Numeral("II")]))])),
DesignaIndex(ID("d"), [String("a"), Numeral("I")], Numeral("X")),
ExpressionStatement(ArrayIndex(ArrayIndex(ID("d"), String("a")), Numeral("I"))),
]),
ValInt(10)),
# 3 levels deep
("DESIGNA a VT [[[I]]]\nDESIGNA a[I][I][I] VT X\na[I][I][I]",
Program([], [
Designa(ID("a"), DataArray([DataArray([DataArray([Numeral("I")])])])),
DesignaIndex(ID("a"), [Numeral("I"), Numeral("I"), Numeral("I")], Numeral("X")),
ExpressionStatement(ArrayIndex(ArrayIndex(ArrayIndex(ID("a"), Numeral("I")), Numeral("I")), Numeral("I"))),
]),
ValInt(10)),
]
class TestMultidimAssign(unittest.TestCase):
@parameterized.expand(multidim_assign_tests)
def test_multidim_assign(self, source, nodes, value):
run_test(self, source, nodes, value)
# --- Array slicing ---
array_slice_tests = [
# basic slice from middle
("[X, XX, XXX, XL, L][II VSQVE IV]",
Program([], [ExpressionStatement(ArraySlice(
DataArray([Numeral("X"), Numeral("XX"), Numeral("XXX"), Numeral("XL"), Numeral("L")]),
Numeral("II"), Numeral("IV")))]),
ValList([ValInt(20), ValInt(30), ValInt(40)])),
# slice of length 1
("[I, II, III][II VSQVE II]",
Program([], [ExpressionStatement(ArraySlice(
DataArray([Numeral("I"), Numeral("II"), Numeral("III")]),
Numeral("II"), Numeral("II")))]),
ValList([ValInt(2)])),
# full array slice
("[I, II, III][I VSQVE III]",
Program([], [ExpressionStatement(ArraySlice(
DataArray([Numeral("I"), Numeral("II"), Numeral("III")]),
Numeral("I"), Numeral("III")))]),
ValList([ValInt(1), ValInt(2), ValInt(3)])),
# slice on variable
("DESIGNA a VT [I, II, III, IV, V]\na[II VSQVE IV]",
Program([], [
Designa(ID("a"), DataArray([Numeral("I"), Numeral("II"), Numeral("III"), Numeral("IV"), Numeral("V")])),
ExpressionStatement(ArraySlice(ID("a"), Numeral("II"), Numeral("IV"))),
]),
ValList([ValInt(2), ValInt(3), ValInt(4)])),
# slice then index (chained)
("[I, II, III, IV][I VSQVE III][II]",
Program([], [ExpressionStatement(ArrayIndex(
ArraySlice(
DataArray([Numeral("I"), Numeral("II"), Numeral("III"), Numeral("IV")]),
Numeral("I"), Numeral("III")),
Numeral("II")))]),
ValInt(2)),
# slice on range array
("[I VSQVE X][III VSQVE VII]",
Program([], [ExpressionStatement(ArraySlice(
DataRangeArray(Numeral("I"), Numeral("X")),
Numeral("III"), Numeral("VII")))]),
ValList([ValInt(3), ValInt(4), ValInt(5), ValInt(6), ValInt(7)])),
# expression as slice bounds
("[I, II, III, IV, V][I + I VSQVE II + II]",
Program([], [ExpressionStatement(ArraySlice(
DataArray([Numeral("I"), Numeral("II"), Numeral("III"), Numeral("IV"), Numeral("V")]),
BinOp(Numeral("I"), Numeral("I"), "SYMBOL_PLUS"),
BinOp(Numeral("II"), Numeral("II"), "SYMBOL_PLUS")))]),
ValList([ValInt(2), ValInt(3), ValInt(4)])),
]
class TestArraySlice(unittest.TestCase):
@parameterized.expand(array_slice_tests)
def test_array_slice(self, source, nodes, value):
run_test(self, source, nodes, value)
# --- Multiline arrays ---
multiline_array_tests = [
# newlines after commas
("[I,\nII,\nIII]",
Program([], [ExpressionStatement(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]))]),
ValList([ValInt(1), ValInt(2), ValInt(3)])),
# single newline after comma
("[I, II,\nIII]",
Program([], [ExpressionStatement(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]))]),
ValList([ValInt(1), ValInt(2), ValInt(3)])),
# empty array still works
("[]",
Program([], [ExpressionStatement(DataArray([]))]),
ValList([])),
# nested arrays with newlines
("[I,\n[II, III],\nIV]",
Program([], [ExpressionStatement(DataArray([
Numeral("I"),
DataArray([Numeral("II"), Numeral("III")]),
Numeral("IV")]))]),
ValList([ValInt(1), ValList([ValInt(2), ValInt(3)]), ValInt(4)])),
]
class TestMultilineArray(unittest.TestCase):
@parameterized.expand(multiline_array_tests)
def test_multiline_array(self, source, nodes, value):
run_test(self, source, nodes, value)