🐐 Better arrays
This commit is contained in:
10
README.md
10
README.md
@@ -96,7 +96,13 @@ The base `CENTVRION` syntax does not allow for floats. However, the `FRACTIO` mo
|
|||||||
Booleans are denoted with the keywords `VERITAS` for true and `FALSITAS` for false.
|
Booleans are denoted with the keywords `VERITAS` for true and `FALSITAS` for false.
|
||||||
|
|
||||||
### Arrays
|
### Arrays
|
||||||
Arrays are defined using square brackets (`[]`) and commas (`,`). An array of integers can also be initialized with the `VSQVE` keyword:
|
Arrays are defined using square brackets (`[]`) and commas (`,`):
|
||||||
|
|
||||||
|
```
|
||||||
|
DESIGNA x VT [I, II, III]
|
||||||
|
```
|
||||||
|
|
||||||
|
An array of integers can also be initialized with the `VSQVE` keyword:
|
||||||
|
|
||||||
```
|
```
|
||||||
DESIGNA x VT [I VSQVE X]
|
DESIGNA x VT [I VSQVE X]
|
||||||
@@ -105,7 +111,7 @@ 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:
|
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)]
|
DESIGNA x VT [I, II, III]
|
||||||
DICE(x[I])
|
DICE(x[I])
|
||||||
|
|
||||||
> I
|
> I
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ class DataArray(Node):
|
|||||||
|
|
||||||
def print(self):
|
def print(self):
|
||||||
items = ", ".join(i.print() for i in self.content)
|
items = ", ".join(i.print() for i in self.content)
|
||||||
return f"[({items})]"
|
return f"[{items}]"
|
||||||
|
|
||||||
def _eval(self, vtable):
|
def _eval(self, vtable):
|
||||||
vals = []
|
vals = []
|
||||||
|
|||||||
@@ -138,6 +138,17 @@ class Parser():
|
|||||||
else:
|
else:
|
||||||
return [calls[0]] + calls[2]
|
return [calls[0]] + calls[2]
|
||||||
|
|
||||||
|
@self.pg.production('array_items : ')
|
||||||
|
@self.pg.production('array_items : expression')
|
||||||
|
@self.pg.production('array_items : expression SYMBOL_COMMA array_items')
|
||||||
|
def array_items(calls):
|
||||||
|
if len(calls) == 0:
|
||||||
|
return []
|
||||||
|
elif len(calls) == 1:
|
||||||
|
return [calls[0]]
|
||||||
|
else:
|
||||||
|
return [calls[0]] + calls[2]
|
||||||
|
|
||||||
@self.pg.production('expression : id')
|
@self.pg.production('expression : id')
|
||||||
def expression_id(tokens):
|
def expression_id(tokens):
|
||||||
return tokens[0]
|
return tokens[0]
|
||||||
@@ -187,7 +198,7 @@ class Parser():
|
|||||||
def parens(tokens):
|
def parens(tokens):
|
||||||
return tokens[1]
|
return tokens[1]
|
||||||
|
|
||||||
@self.pg.production('expression : SYMBOL_LBRACKET expressions SYMBOL_RBRACKET')
|
@self.pg.production('expression : SYMBOL_LBRACKET array_items SYMBOL_RBRACKET')
|
||||||
def array(tokens):
|
def array(tokens):
|
||||||
return ast_nodes.DataArray(tokens[1])
|
return ast_nodes.DataArray(tokens[1])
|
||||||
|
|
||||||
@@ -221,7 +232,7 @@ class Parser():
|
|||||||
|
|
||||||
@self.pg.error
|
@self.pg.error
|
||||||
def error_handle(token):
|
def error_handle(token):
|
||||||
raise SyntaxError(token.name, token.value, token.source_pos)
|
raise SyntaxError(f"{token.name}, {token.value}, {token.source_pos}")
|
||||||
|
|
||||||
parser = self.pg.build()
|
parser = self.pg.build()
|
||||||
return parser.parse(tokens_input) # type: ignore
|
return parser.parse(tokens_input) # type: ignore
|
||||||
|
|||||||
40
tests.py
40
tests.py
@@ -157,11 +157,11 @@ precedence_tests = [
|
|||||||
Program([], [ExpressionStatement(BinOp(UnaryMinus(Numeral("II")), Numeral("III"), "SYMBOL_PLUS"))]),
|
Program([], [ExpressionStatement(BinOp(UnaryMinus(Numeral("II")), Numeral("III"), "SYMBOL_PLUS"))]),
|
||||||
ValInt(1)),
|
ValInt(1)),
|
||||||
# INDEX binds tighter than UMINUS: -(arr[I]) = -1
|
# INDEX binds tighter than UMINUS: -(arr[I]) = -1
|
||||||
("- [(I, II, III)][I]",
|
("- [I, II, III][I]",
|
||||||
Program([], [ExpressionStatement(UnaryMinus(ArrayIndex(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("I"))))]),
|
Program([], [ExpressionStatement(UnaryMinus(ArrayIndex(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("I"))))]),
|
||||||
ValInt(-1)),
|
ValInt(-1)),
|
||||||
# INDEX binds tighter than +: (arr[II]) + X = 2 + 10 = 12
|
# INDEX binds tighter than +: (arr[II]) + X = 2 + 10 = 12
|
||||||
("[(I, II, III)][II] + X",
|
("[I, II, III][II] + X",
|
||||||
Program([], [ExpressionStatement(BinOp(ArrayIndex(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("II")), Numeral("X"), "SYMBOL_PLUS"))]),
|
Program([], [ExpressionStatement(BinOp(ArrayIndex(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("II")), Numeral("X"), "SYMBOL_PLUS"))]),
|
||||||
ValInt(12)),
|
ValInt(12)),
|
||||||
# left-associativity of -: (10-3)-2 = 5, not 10-(3-2) = 9
|
# left-associativity of -: (10-3)-2 = 5, not 10-(3-2) = 9
|
||||||
@@ -283,7 +283,7 @@ control_tests = [
|
|||||||
]),
|
]),
|
||||||
ValStr("I"), "I\n"),
|
ValStr("I"), "I\n"),
|
||||||
# PER foreach
|
# PER foreach
|
||||||
("PER i IN [(I, II, III)] FACE { DICE(i) }",
|
("PER i IN [I, II, III] FACE { DICE(i) }",
|
||||||
Program([], [PerStatement(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), ID("i"), [ExpressionStatement(BuiltIn("DICE", [ID("i")]))])]),
|
Program([], [PerStatement(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), ID("i"), [ExpressionStatement(BuiltIn("DICE", [ID("i")]))])]),
|
||||||
ValStr("III"), "I\nII\nIII\n"),
|
ValStr("III"), "I\nII\nIII\n"),
|
||||||
# DONICVM range loop
|
# DONICVM range loop
|
||||||
@@ -351,8 +351,8 @@ builtin_tests = [
|
|||||||
("AVDI_NVMERVS()", Program([], [ExpressionStatement(BuiltIn("AVDI_NVMERVS", []))]), ValInt(10), "", ["X"]),
|
("AVDI_NVMERVS()", Program([], [ExpressionStatement(BuiltIn("AVDI_NVMERVS", []))]), ValInt(10), "", ["X"]),
|
||||||
("CVM FORS\nFORTIS_NVMERVS(I, X)", Program([ModuleCall("FORS")], [ExpressionStatement(BuiltIn("FORTIS_NVMERVS", [Numeral("I"), Numeral("X")]))]), ValInt(3)),
|
("CVM FORS\nFORTIS_NVMERVS(I, X)", Program([ModuleCall("FORS")], [ExpressionStatement(BuiltIn("FORTIS_NVMERVS", [Numeral("I"), Numeral("X")]))]), ValInt(3)),
|
||||||
("AVDI()", Program([], [ExpressionStatement(BuiltIn("AVDI", []))]), ValStr("hello"), "", ["hello"]),
|
("AVDI()", Program([], [ExpressionStatement(BuiltIn("AVDI", []))]), ValStr("hello"), "", ["hello"]),
|
||||||
("LONGITVDO([(I, II, III)])", Program([], [ExpressionStatement(BuiltIn("LONGITVDO", [DataArray([Numeral("I"), Numeral("II"), Numeral("III")])]))]), ValInt(3)),
|
("LONGITVDO([I, II, III])", Program([], [ExpressionStatement(BuiltIn("LONGITVDO", [DataArray([Numeral("I"), Numeral("II"), Numeral("III")])]))]), ValInt(3)),
|
||||||
("CVM FORS\nFORTIS_ELECTIONIS([(I, II, III)])", Program([ModuleCall("FORS")], [ExpressionStatement(BuiltIn("FORTIS_ELECTIONIS", [DataArray([Numeral("I"), Numeral("II"), Numeral("III")])]))]), ValInt(1)),
|
("CVM FORS\nFORTIS_ELECTIONIS([I, II, III])", Program([ModuleCall("FORS")], [ExpressionStatement(BuiltIn("FORTIS_ELECTIONIS", [DataArray([Numeral("I"), Numeral("II"), Numeral("III")])]))]), ValInt(1)),
|
||||||
]
|
]
|
||||||
|
|
||||||
class TestBuiltins(unittest.TestCase):
|
class TestBuiltins(unittest.TestCase):
|
||||||
@@ -375,8 +375,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][III]", IndexError), # index too high
|
||||||
("[(I, II)][-I]", IndexError), # negative index
|
("[I, II][-I]", IndexError), # negative index
|
||||||
]
|
]
|
||||||
|
|
||||||
class TestErrors(unittest.TestCase):
|
class TestErrors(unittest.TestCase):
|
||||||
@@ -511,7 +511,7 @@ dice_type_tests = [
|
|||||||
("DICE(VERITAS)", Program([], [ExpressionStatement(BuiltIn("DICE", [Bool(True)]))]), ValStr("VERVS"), "VERVS\n"),
|
("DICE(VERITAS)", Program([], [ExpressionStatement(BuiltIn("DICE", [Bool(True)]))]), ValStr("VERVS"), "VERVS\n"),
|
||||||
("DICE(FALSITAS)", Program([], [ExpressionStatement(BuiltIn("DICE", [Bool(False)]))]), ValStr("FALSVS"), "FALSVS\n"),
|
("DICE(FALSITAS)", Program([], [ExpressionStatement(BuiltIn("DICE", [Bool(False)]))]), ValStr("FALSVS"), "FALSVS\n"),
|
||||||
("DICE(NVLLVS)", Program([], [ExpressionStatement(BuiltIn("DICE", [Nullus()]))]), ValStr("NVLLVS"), "NVLLVS\n"),
|
("DICE(NVLLVS)", Program([], [ExpressionStatement(BuiltIn("DICE", [Nullus()]))]), ValStr("NVLLVS"), "NVLLVS\n"),
|
||||||
('DICE([(I, II)])', Program([], [ExpressionStatement(BuiltIn("DICE", [DataArray([Numeral("I"), Numeral("II")])]))]), ValStr("[I II]"), "[I II]\n"),
|
('DICE([I, II])', Program([], [ExpressionStatement(BuiltIn("DICE", [DataArray([Numeral("I"), Numeral("II")])]))]), ValStr("[I II]"), "[I II]\n"),
|
||||||
('DICE("")', Program([], [ExpressionStatement(BuiltIn("DICE", [String("")]))]), ValStr(""), "\n"),
|
('DICE("")', Program([], [ExpressionStatement(BuiltIn("DICE", [String("")]))]), ValStr(""), "\n"),
|
||||||
# arithmetic result printed as numeral
|
# arithmetic result printed as numeral
|
||||||
("DICE(II + III)", Program([], [ExpressionStatement(BuiltIn("DICE", [BinOp(Numeral("II"), Numeral("III"), "SYMBOL_PLUS")]))]), ValStr("V"), "V\n"),
|
("DICE(II + III)", Program([], [ExpressionStatement(BuiltIn("DICE", [BinOp(Numeral("II"), Numeral("III"), "SYMBOL_PLUS")]))]), ValStr("V"), "V\n"),
|
||||||
@@ -541,11 +541,11 @@ truthiness_tests = [
|
|||||||
]),
|
]),
|
||||||
ValInt(2)),
|
ValInt(2)),
|
||||||
# non-empty list is truthy
|
# non-empty list is truthy
|
||||||
("SI [(I)] TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr",
|
("SI [I] TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr",
|
||||||
Program([], [SiStatement(DataArray([Numeral("I")]), [Designa(ID("r"), Numeral("I"))], [Designa(ID("r"), Numeral("II"))]), ExpressionStatement(ID("r"))]),
|
Program([], [SiStatement(DataArray([Numeral("I")]), [Designa(ID("r"), Numeral("I"))], [Designa(ID("r"), Numeral("II"))]), ExpressionStatement(ID("r"))]),
|
||||||
ValInt(1)),
|
ValInt(1)),
|
||||||
# empty list is falsy
|
# empty list is falsy
|
||||||
("SI [()] TVNC { DESIGNA r VT II } ALVID { DESIGNA r VT I }\nr",
|
("SI [] TVNC { DESIGNA r VT II } ALVID { DESIGNA r VT I }\nr",
|
||||||
Program([], [SiStatement(DataArray([]), [Designa(ID("r"), Numeral("II"))], [Designa(ID("r"), Numeral("I"))]), ExpressionStatement(ID("r"))]),
|
Program([], [SiStatement(DataArray([]), [Designa(ID("r"), Numeral("II"))], [Designa(ID("r"), Numeral("I"))]), ExpressionStatement(ID("r"))]),
|
||||||
ValInt(1)),
|
ValInt(1)),
|
||||||
# DVM exits when condition becomes truthy
|
# DVM exits when condition becomes truthy
|
||||||
@@ -697,11 +697,11 @@ loop_edge_tests = [
|
|||||||
Program([], [PerStatement(DataRangeArray(Numeral("III"), Numeral("III")), ID("i"), [ExpressionStatement(BuiltIn("DICE", [ID("i")]))])]),
|
Program([], [PerStatement(DataRangeArray(Numeral("III"), Numeral("III")), ID("i"), [ExpressionStatement(BuiltIn("DICE", [ID("i")]))])]),
|
||||||
ValNul(), ""),
|
ValNul(), ""),
|
||||||
# empty array — body never runs
|
# empty array — body never runs
|
||||||
("PER i IN [()] FACE { DICE(i) }",
|
("PER i IN [] FACE { DICE(i) }",
|
||||||
Program([], [PerStatement(DataArray([]), ID("i"), [ExpressionStatement(BuiltIn("DICE", [ID("i")]))])]),
|
Program([], [PerStatement(DataArray([]), ID("i"), [ExpressionStatement(BuiltIn("DICE", [ID("i")]))])]),
|
||||||
ValNul(), ""),
|
ValNul(), ""),
|
||||||
# PER breaks on element 2 — last assigned i is 2
|
# PER breaks on element 2 — last assigned i is 2
|
||||||
("PER i IN [(I, II, III)] FACE { SI i EST II TVNC { ERVMPE } }\ni",
|
("PER i IN [I, II, III] FACE { SI i EST II TVNC { ERVMPE } }\ni",
|
||||||
Program([], [
|
Program([], [
|
||||||
PerStatement(
|
PerStatement(
|
||||||
DataArray([Numeral("I"), Numeral("II"), Numeral("III")]),
|
DataArray([Numeral("I"), Numeral("II"), Numeral("III")]),
|
||||||
@@ -724,7 +724,7 @@ loop_edge_tests = [
|
|||||||
ValInt(3), ""),
|
ValInt(3), ""),
|
||||||
# nested PER: inner always breaks on first element; outer completes both iterations
|
# nested PER: inner always breaks on first element; outer completes both iterations
|
||||||
# cnt starts at 1, increments twice → 3
|
# cnt starts at 1, increments twice → 3
|
||||||
("DESIGNA cnt VT I\nPER i IN [(I, II)] FACE {\nPER k IN [(I, II)] FACE {\nERVMPE\n}\nDESIGNA cnt VT cnt + I\n}\ncnt",
|
("DESIGNA cnt VT I\nPER i IN [I, II] FACE {\nPER k IN [I, II] FACE {\nERVMPE\n}\nDESIGNA cnt VT cnt + I\n}\ncnt",
|
||||||
Program([], [
|
Program([], [
|
||||||
Designa(ID("cnt"), Numeral("I")),
|
Designa(ID("cnt"), Numeral("I")),
|
||||||
PerStatement(
|
PerStatement(
|
||||||
@@ -864,11 +864,11 @@ class TestEtAvt(unittest.TestCase):
|
|||||||
|
|
||||||
array_index_tests = [
|
array_index_tests = [
|
||||||
# basic indexing
|
# 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][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][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
|
("[I, II, III][III]", Program([], [ExpressionStatement(ArrayIndex(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("III")))]), ValInt(3)), # third element
|
||||||
# index into a variable
|
# index into a variable
|
||||||
("DESIGNA a VT [(X, XX, XXX)]\na[II]",
|
("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")))]),
|
Program([], [Designa(ID("a"), DataArray([Numeral("X"), Numeral("XX"), Numeral("XXX")])), ExpressionStatement(ArrayIndex(ID("a"), Numeral("II")))]),
|
||||||
ValInt(20)), # second element
|
ValInt(20)), # second element
|
||||||
# index into range array
|
# index into range array
|
||||||
@@ -944,7 +944,7 @@ scope_tests = [
|
|||||||
]),
|
]),
|
||||||
ValInt(5)),
|
ValInt(5)),
|
||||||
# PER: loop variable holds last array element after loop (no ERVMPE)
|
# PER: loop variable holds last array element after loop (no ERVMPE)
|
||||||
("PER i IN [(I, II, III)] FACE { DESIGNA nop VT I }\ni",
|
("PER i IN [I, II, III] FACE { DESIGNA nop VT I }\ni",
|
||||||
Program([], [
|
Program([], [
|
||||||
PerStatement(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), ID("i"), [Designa(ID("nop"), Numeral("I"))]),
|
PerStatement(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), ID("i"), [Designa(ID("nop"), Numeral("I"))]),
|
||||||
ExpressionStatement(ID("i")),
|
ExpressionStatement(ID("i")),
|
||||||
@@ -952,7 +952,7 @@ scope_tests = [
|
|||||||
ValInt(3)),
|
ValInt(3)),
|
||||||
# PER: reassigning loop var in body doesn't prevent remaining iterations from running
|
# PER: reassigning loop var in body doesn't prevent remaining iterations from running
|
||||||
# cnt increments once per iteration (all 3); C=100 doesn't replace next element assignment
|
# cnt increments once per iteration (all 3); C=100 doesn't replace next element assignment
|
||||||
("DESIGNA cnt VT I\nPER i IN [(I, II, III)] FACE { DESIGNA i VT C\nDESIGNA cnt VT cnt + I }\ncnt",
|
("DESIGNA cnt VT I\nPER i IN [I, II, III] FACE { DESIGNA i VT C\nDESIGNA cnt VT cnt + I }\ncnt",
|
||||||
Program([], [
|
Program([], [
|
||||||
Designa(ID("cnt"), Numeral("I")),
|
Designa(ID("cnt"), Numeral("I")),
|
||||||
PerStatement(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), ID("i"), [
|
PerStatement(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), ID("i"), [
|
||||||
@@ -964,7 +964,7 @@ scope_tests = [
|
|||||||
ValInt(4)),
|
ValInt(4)),
|
||||||
# PER: loop var after loop reflects the last body assignment, not the last array element
|
# PER: loop var after loop reflects the last body assignment, not the last array element
|
||||||
# body sets i=C=100 on every iteration; after loop ends, i stays at 100
|
# body sets i=C=100 on every iteration; after loop ends, i stays at 100
|
||||||
("PER i IN [(I, II, III)] FACE { DESIGNA i VT C }\ni",
|
("PER i IN [I, II, III] FACE { DESIGNA i VT C }\ni",
|
||||||
Program([], [
|
Program([], [
|
||||||
PerStatement(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), ID("i"), [Designa(ID("i"), Numeral("C"))]),
|
PerStatement(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), ID("i"), [Designa(ID("i"), Numeral("C"))]),
|
||||||
ExpressionStatement(ID("i")),
|
ExpressionStatement(ID("i")),
|
||||||
|
|||||||
Reference in New Issue
Block a user