From 559b1b100ef2b90be33f87fc496257e5bf658e7d Mon Sep 17 00:00:00 2001 From: NikolajDanger Date: Tue, 21 Apr 2026 22:35:22 +0200 Subject: [PATCH] :goat: VSQVE change --- README.md | 8 ++++-- centvrion/ast_nodes.py | 2 +- centvrion/compiler/emit_expr.py | 4 +-- examples/bubble_sort.cent | 4 +-- examples/connect_iv.cent | 44 +++++++++++++++--------------- examples/multiplication_table.cent | 4 +-- examples/sieve.cent | 4 +-- language/main.tex | 2 +- tests.py | 37 ++++++++++++++++--------- 9 files changed, 62 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 8ad2b08..5e71828 100644 --- a/README.md +++ b/README.md @@ -105,10 +105,14 @@ Arrays are defined using square brackets (`[]`) and commas (`,`): ![Array literal](snippets/array_literal.png) -An array of integers can also be initialized with the `VSQVE` keyword: +An array of integers can also be initialized with the `VSQVE` keyword. The range is inclusive on both ends: ![Array with VSQVE](snippets/array_vsqve.png) +``` +> [I, II, III, IV, V, VI, VII, VIII, IX, X] +``` + Individual elements can be accessed by index using square brackets. Indexing is 1-based, so `I` refers to the first element: ![Array indexing](snippets/array_index.png) @@ -178,7 +182,7 @@ The keyword `ET` can be used as a boolean "and". The keyword `AVT` can be used a ![DONICVM loop](snippets/donicvm.png) ``` -> XLV +> LV ``` ### DVM loops diff --git a/centvrion/ast_nodes.py b/centvrion/ast_nodes.py index 296fcd1..0559386 100644 --- a/centvrion/ast_nodes.py +++ b/centvrion/ast_nodes.py @@ -280,7 +280,7 @@ class DataRangeArray(Node): raise CentvrionError("Range bounds must be numbers") from_int = from_val.value() or 0 to_int = to_val.value() or 0 - return vtable, ValList([ValInt(i) for i in range(from_int, to_int)]) + return vtable, ValList([ValInt(i) for i in range(from_int, to_int + 1)]) class DataDict(Node): diff --git a/centvrion/compiler/emit_expr.py b/centvrion/compiler/emit_expr.py index 84473bd..3c29c52 100644 --- a/centvrion/compiler/emit_expr.py +++ b/centvrion/compiler/emit_expr.py @@ -135,10 +135,10 @@ def emit_expr(node, ctx): hi_lines, hi_var = emit_expr(node.to_value, ctx) tmp = ctx.fresh_tmp() i_var = ctx.fresh_tmp() - cap = f"({hi_var}.ival > {lo_var}.ival ? (int)({hi_var}.ival - {lo_var}.ival) : 0)" + cap = f"({hi_var}.ival >= {lo_var}.ival ? (int)({hi_var}.ival - {lo_var}.ival + 1) : 0)" lines = lo_lines + hi_lines + [ f"CentValue {tmp} = cent_list_new({cap});", - f"for (long {i_var} = {lo_var}.ival; {i_var} < {hi_var}.ival; {i_var}++) {{", + f"for (long {i_var} = {lo_var}.ival; {i_var} <= {hi_var}.ival; {i_var}++) {{", f" cent_list_push(&{tmp}, cent_int({i_var}));", "}", ] diff --git a/examples/bubble_sort.cent b/examples/bubble_sort.cent index 2f9d5a5..b1470e4 100644 --- a/examples/bubble_sort.cent +++ b/examples/bubble_sort.cent @@ -3,8 +3,8 @@ DESIGNA arr VT [V, III, VIII, I, IX, II, VII, IV, VI, X] DESIGNA n VT LONGITVDO(arr) -DONICVM i VT I VSQVE n FACE { - DONICVM k VT I VSQVE n - i + I FACE { +DONICVM i VT I VSQVE n - I FACE { + DONICVM k VT I VSQVE n - i FACE { SI arr[k] PLVS arr[k + I] TVNC { DESIGNA temp VT arr[k] DESIGNA arr[k] VT arr[k + I] diff --git a/examples/connect_iv.cent b/examples/connect_iv.cent index d7fb03c..6b0942c 100644 --- a/examples/connect_iv.cent +++ b/examples/connect_iv.cent @@ -6,7 +6,7 @@ // Returns the bottommost empty row in col, or NVLLVS if full DEFINI find_slot(b, col) VT { DESIGNA ans VT NVLLVS - DONICVM r VT I VSQVE VII FACE { + DONICVM r VT I VSQVE VI FACE { SI b[(r - I) * VII + col] EST NVLLVS TVNC { DESIGNA ans VT r } @@ -16,32 +16,32 @@ DEFINI find_slot(b, col) VT { // Returns VERITAS if player has four in a row DEFINI est_victor(b, player) VT { - DONICVM r VT I VSQVE VII FACE { - DONICVM c VT I VSQVE V FACE { + DONICVM r VT I VSQVE VI FACE { + DONICVM c VT I VSQVE IV FACE { DESIGNA idx VT (r - I) * VII + c SI b[idx] EST player ET b[idx + I] EST player ET b[idx + II] EST player ET b[idx + III] EST player TVNC { REDI(VERITAS) } } } - DONICVM r VT I VSQVE IV FACE { - DONICVM c VT I VSQVE VIII FACE { + DONICVM r VT I VSQVE III FACE { + DONICVM c VT I VSQVE VII FACE { DESIGNA idx VT (r - I) * VII + c SI b[idx] EST player ET b[idx + VII] EST player ET b[idx + XIV] EST player ET b[idx + XXI] EST player TVNC { REDI(VERITAS) } } } - DONICVM r VT I VSQVE IV FACE { - DONICVM c VT I VSQVE V FACE { + DONICVM r VT I VSQVE III FACE { + DONICVM c VT I VSQVE IV FACE { DESIGNA idx VT (r - I) * VII + c SI b[idx] EST player ET b[idx + VIII] EST player ET b[idx + XVI] EST player ET b[idx + XXIV] EST player TVNC { REDI(VERITAS) } } } - DONICVM r VT I VSQVE IV FACE { - DONICVM c VT IV VSQVE VIII FACE { + DONICVM r VT I VSQVE III FACE { + DONICVM c VT IV VSQVE VII FACE { DESIGNA idx VT (r - I) * VII + c SI b[idx] EST player ET b[idx + VI] EST player ET b[idx + XII] EST player ET b[idx + XVIII] EST player TVNC { REDI(VERITAS) @@ -53,9 +53,9 @@ DEFINI est_victor(b, player) VT { DEFINI print_board(b) VT { DICE("+---+---+---+---+---+---+---+") - DONICVM r VT I VSQVE VII FACE { + DONICVM r VT I VSQVE VI FACE { DESIGNA line VT "| " - DONICVM c VT I VSQVE VIII FACE { + DONICVM c VT I VSQVE VII FACE { DESIGNA cell VT b[(r - I) * VII + c] SI cell EST I TVNC { DESIGNA line VT line & "X | " @@ -101,35 +101,35 @@ DEFINI score_fenestram(a, b, c, d) VT { DEFINI aestima(b) VT { DESIGNA score VT NVLLVS // Center column preference: each AI piece in column IV is worth +1 - DONICVM r VT I VSQVE VII FACE { + DONICVM r VT I VSQVE VI FACE { SI b[(r - I) * VII + IV] EST II TVNC { DESIGNA score VT score + I } } // Horizontal windows (6 rows x 4 starting columns = 24) - DONICVM r VT I VSQVE VII FACE { - DONICVM c VT I VSQVE V FACE { + DONICVM r VT I VSQVE VI FACE { + DONICVM c VT I VSQVE IV FACE { DESIGNA idx VT (r - I) * VII + c DESIGNA score VT score + INVOCA score_fenestram(b[idx], b[idx + I], b[idx + II], b[idx + III]) } } // Vertical windows (3 starting rows x 7 columns = 21) - DONICVM r VT I VSQVE IV FACE { - DONICVM c VT I VSQVE VIII FACE { + DONICVM r VT I VSQVE III FACE { + DONICVM c VT I VSQVE VII FACE { DESIGNA idx VT (r - I) * VII + c DESIGNA score VT score + INVOCA score_fenestram(b[idx], b[idx + VII], b[idx + XIV], b[idx + XXI]) } } // Diagonal up-right windows (3 starting rows x 4 starting columns = 12) - DONICVM r VT I VSQVE IV FACE { - DONICVM c VT I VSQVE V FACE { + DONICVM r VT I VSQVE III FACE { + DONICVM c VT I VSQVE IV FACE { DESIGNA idx VT (r - I) * VII + c DESIGNA score VT score + INVOCA score_fenestram(b[idx], b[idx + VIII], b[idx + XVI], b[idx + XXIV]) } } // Diagonal up-left windows (3 starting rows x 4 starting columns = 12) - DONICVM r VT I VSQVE IV FACE { - DONICVM c VT IV VSQVE VIII FACE { + DONICVM r VT I VSQVE III FACE { + DONICVM c VT IV VSQVE VII FACE { DESIGNA idx VT (r - I) * VII + c DESIGNA score VT score + INVOCA score_fenestram(b[idx], b[idx + VI], b[idx + XII], b[idx + XVIII]) } @@ -219,8 +219,8 @@ DEFINI ai_move(b) VT { } // --- Board setup --- -DESIGNA board VT [I VSQVE XLIII] -DONICVM i VT I VSQVE XLIII FACE { +DESIGNA board VT [I VSQVE XLII] +DONICVM i VT I VSQVE XLII FACE { DESIGNA board[i] VT NVLLVS } diff --git a/examples/multiplication_table.cent b/examples/multiplication_table.cent index f73a92d..a4f2ee9 100644 --- a/examples/multiplication_table.cent +++ b/examples/multiplication_table.cent @@ -1,9 +1,9 @@ // Prints an X×X multiplication table DESIGNA n VT X -DONICVM i VT I VSQVE n + I FACE { +DONICVM i VT I VSQVE n FACE { DESIGNA line VT "" - DONICVM k VT I VSQVE n + I FACE { + DONICVM k VT I VSQVE n FACE { DESIGNA line VT line & i * k & " " } DICE(line) diff --git a/examples/sieve.cent b/examples/sieve.cent index f7c40e0..0f56fda 100644 --- a/examples/sieve.cent +++ b/examples/sieve.cent @@ -2,9 +2,9 @@ DESIGNA n VT L -DONICVM i VT II VSQVE n + I FACE { +DONICVM i VT II VSQVE n FACE { DESIGNA is_prime VT VERITAS - DONICVM k VT II VSQVE i FACE { + DONICVM k VT II VSQVE i - I FACE { SI (i / k) * k EST i TVNC { DESIGNA is_prime VT FALSITAS } diff --git a/language/main.tex b/language/main.tex index 0ee241d..347f017 100644 --- a/language/main.tex +++ b/language/main.tex @@ -66,7 +66,7 @@ \languageline{literal}{\textbf{numeral}} \\ \languageline{literal}{\textbf{bool}} \\ \languageline{literal}{\texttt{[} \textit{optional-expressions} \texttt{]}} \\ - \languageline{literal}{\texttt{[} \textit{expression} \texttt{VSQVE} \textit{expression} \texttt{]}} \\ + \languageline{literal}{\texttt{[} \textit{expression} \texttt{VSQVE} \textit{expression} \texttt{]} \textnormal{\small\ (inclusive on both ends)}} \\ \languageline{literal}{\texttt{TABVLA} \texttt{\{} \textit{optional-dict-items} \texttt{\}}} \\ \hline \languageline{optional-dict-items}{\textit{dict-items}} \\ diff --git a/tests.py b/tests.py index 66d0944..f25c4b1 100644 --- a/tests.py +++ b/tests.py @@ -284,13 +284,13 @@ assignment_tests = [ Designa(ID("x"), BinOp(ID("x"), BinOp(Numeral("II"), Numeral("III"), "SYMBOL_PLUS"), "SYMBOL_PLUS")), ExpressionStatement(ID("x"))]), ValInt(6)), - # AVGE inside a loop (DONICVM range is exclusive of upper bound: I VSQVE III = [1, 2]) + # AVGE inside a loop (DONICVM range is inclusive: I VSQVE III = [1, 2, 3]) ("DESIGNA s VT NVLLVS\nDONICVM i VT I VSQVE III FACE {\ns AVGE i\n}\ns", Program([], [Designa(ID("s"), Nullus()), PerStatement(DataRangeArray(Numeral("I"), Numeral("III")), ID("i"), [Designa(ID("s"), BinOp(ID("s"), ID("i"), "SYMBOL_PLUS"))]), ExpressionStatement(ID("s"))]), - ValInt(3)), + ValInt(6)), ] class TestAssignment(unittest.TestCase): @@ -470,7 +470,7 @@ control_tests = [ # DONICVM range loop ("DONICVM i VT I VSQVE V FACE { DICE(i) }", Program([], [PerStatement(DataRangeArray(Numeral("I"), Numeral("V")), ID("i"), [ExpressionStatement(BuiltIn("DICE", [ID("i")]))])]), - ValStr("IV"), "I\nII\nIII\nIV\n"), + ValStr("V"), "I\nII\nIII\nIV\nV\n"), ] class TestControl(unittest.TestCase): @@ -1191,10 +1191,10 @@ class TestFunctionEdge(unittest.TestCase): # --- Loop edge cases --- loop_edge_tests = [ - # range(3, 3) is empty — body never runs, program returns ValNul + # [III VSQVE III] = [3] — single iteration ("DONICVM i VT III VSQVE III FACE { DICE(i) }", Program([], [PerStatement(DataRangeArray(Numeral("III"), Numeral("III")), ID("i"), [ExpressionStatement(BuiltIn("DICE", [ID("i")]))])]), - ValNul(), ""), + ValStr("III"), "III\n"), # empty array — body never runs ("PER i IN [] FACE { DICE(i) }", Program([], [PerStatement(DataArray([]), ID("i"), [ExpressionStatement(BuiltIn("DICE", [ID("i")]))])]), @@ -1278,7 +1278,7 @@ loop_edge_tests = [ ExpressionStatement(ID("cnt")), ]), ValInt(3), ""), - # DONICVM with CONTINVA: skip value III, count remaining + # DONICVM with CONTINVA: skip value III, count remaining (I VSQVE IV = [1,2,3,4], skip 3 → 3 increments) ("DESIGNA cnt VT I\nDONICVM i VT I VSQVE IV FACE {\nSI i EST III TVNC { CONTINVA }\nDESIGNA cnt VT cnt + I\n}\ncnt", Program([], [ Designa(ID("cnt"), Numeral("I")), @@ -1290,7 +1290,7 @@ loop_edge_tests = [ ), ExpressionStatement(ID("cnt")), ]), - ValInt(3)), + ValInt(4)), # DVM condition true from start — body never runs ("DESIGNA x VT I\nDVM VERITAS FACE {\nDESIGNA x VT x + I\n}\nx", Program([], [ @@ -1299,10 +1299,21 @@ loop_edge_tests = [ ExpressionStatement(ID("x")), ]), ValInt(1), ""), - # single iteration: [I VSQVE II] = [1] + # two iterations: [I VSQVE II] = [1, 2] ("DONICVM i VT I VSQVE II FACE { DICE(i) }", Program([], [PerStatement(DataRangeArray(Numeral("I"), Numeral("II")), ID("i"), [ExpressionStatement(BuiltIn("DICE", [ID("i")]))])]), + ValStr("II"), "I\nII\n"), + # single iteration: [I VSQVE I] = [1] + ("DONICVM i VT I VSQVE I FACE { DICE(i) }", + Program([], [PerStatement(DataRangeArray(Numeral("I"), Numeral("I")), ID("i"), [ExpressionStatement(BuiltIn("DICE", [ID("i")]))])]), ValStr("I"), "I\n"), + # empty range: [V VSQVE I] = [] + ("DESIGNA x VT NVLLVS\nDONICVM i VT V VSQVE I FACE { DESIGNA x VT x + i }\nx", + Program([], [Designa(ID("x"), Nullus()), + PerStatement(DataRangeArray(Numeral("V"), Numeral("I")), ID("i"), + [Designa(ID("x"), BinOp(ID("x"), ID("i"), "SYMBOL_PLUS"))]), + ExpressionStatement(ID("x"))]), + ValNul(), ""), ] class TestLoopEdge(unittest.TestCase): @@ -1427,7 +1438,7 @@ array_index_tests = [ 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] + ("[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( @@ -1596,15 +1607,15 @@ scope_tests = [ ]), ValInt(100)), # DONICVM: counter holds last range value after loop ends - # [I VSQVE IV] = [1,2,3]; last value assigned by loop is III=3 + # [I VSQVE IV] = [1,2,3,4]; last value assigned by loop is IV=4 ("DONICVM i VT I VSQVE IV FACE { DESIGNA nop VT I }\ni", Program([], [ PerStatement(DataRangeArray(Numeral("I"), Numeral("IV")), ID("i"), [Designa(ID("nop"), Numeral("I"))]), ExpressionStatement(ID("i")), ]), - ValInt(3)), + ValInt(4)), # DONICVM: reassigning counter inside body doesn't reduce the number of iterations - # range [I VSQVE IV] evaluated once; i reset each time; cnt still increments 3 times → 4 + # range [I VSQVE IV] evaluated once; i reset each time; cnt still increments 4 times → 5 ("DESIGNA cnt VT I\nDONICVM i VT I VSQVE IV FACE { DESIGNA cnt VT cnt + I\nDESIGNA i VT C }\ncnt", Program([], [ Designa(ID("cnt"), Numeral("I")), @@ -1614,7 +1625,7 @@ scope_tests = [ ]), ExpressionStatement(ID("cnt")), ]), - ValInt(4)), + ValInt(5)), # DONICVM: ERVMPE exits loop early; counter persists at break value ("DONICVM i VT I VSQVE X FACE {\nSI i EST III TVNC { ERVMPE }\n}\ni", Program([], [