🐐 NON operator
This commit is contained in:
@@ -462,6 +462,24 @@ class UnaryMinus(Node):
|
|||||||
return vtable, ValInt(-val.value())
|
return vtable, ValInt(-val.value())
|
||||||
|
|
||||||
|
|
||||||
|
class UnaryNot(Node):
|
||||||
|
def __init__(self, expr):
|
||||||
|
self.expr = expr
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other) and self.expr == other.expr
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"UnaryNot({self.expr!r})"
|
||||||
|
|
||||||
|
def print(self):
|
||||||
|
return f"(NON {self.expr.print()})"
|
||||||
|
|
||||||
|
def _eval(self, vtable):
|
||||||
|
vtable, val = self.expr.eval(vtable)
|
||||||
|
return vtable, ValBool(not bool(val))
|
||||||
|
|
||||||
|
|
||||||
class ArrayIndex(Node):
|
class ArrayIndex(Node):
|
||||||
def __init__(self, array, index) -> None:
|
def __init__(self, array, index) -> None:
|
||||||
self.array = array
|
self.array = array
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ keyword_tokens = [("KEYWORD_"+i, i) for i in [
|
|||||||
"INVOCA",
|
"INVOCA",
|
||||||
"IN",
|
"IN",
|
||||||
"MINVS",
|
"MINVS",
|
||||||
|
"NON",
|
||||||
"NVLLVS",
|
"NVLLVS",
|
||||||
"PER",
|
"PER",
|
||||||
"PLVS",
|
"PLVS",
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class Parser():
|
|||||||
('left', ["KEYWORD_PLVS", "KEYWORD_MINVS", "KEYWORD_EST"]),
|
('left', ["KEYWORD_PLVS", "KEYWORD_MINVS", "KEYWORD_EST"]),
|
||||||
('left', ["SYMBOL_COLON", "SYMBOL_PLUS", "SYMBOL_MINUS"]),
|
('left', ["SYMBOL_COLON", "SYMBOL_PLUS", "SYMBOL_MINUS"]),
|
||||||
('left', ["SYMBOL_TIMES", "SYMBOL_DIVIDE"]),
|
('left', ["SYMBOL_TIMES", "SYMBOL_DIVIDE"]),
|
||||||
('right', ["UMINUS"]),
|
('right', ["UMINUS", "UNOT"]),
|
||||||
('left', ["INDEX"]),
|
('left', ["INDEX"]),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@@ -191,6 +191,10 @@ class Parser():
|
|||||||
def unary_minus(tokens):
|
def unary_minus(tokens):
|
||||||
return ast_nodes.UnaryMinus(tokens[1])
|
return ast_nodes.UnaryMinus(tokens[1])
|
||||||
|
|
||||||
|
@self.pg.production('expression : KEYWORD_NON expression', precedence='UNOT')
|
||||||
|
def unary_not(tokens):
|
||||||
|
return ast_nodes.UnaryNot(tokens[1])
|
||||||
|
|
||||||
@self.pg.production('expression : KEYWORD_INVOCA id expressions')
|
@self.pg.production('expression : KEYWORD_INVOCA id expressions')
|
||||||
def invoca(tokens):
|
def invoca(tokens):
|
||||||
return ast_nodes.Invoca(tokens[1], tokens[2])
|
return ast_nodes.Invoca(tokens[1], tokens[2])
|
||||||
|
|||||||
41
tests.py
41
tests.py
@@ -8,7 +8,7 @@ from centvrion.ast_nodes import (
|
|||||||
ArrayIndex, 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, UnaryNot,
|
||||||
num_to_int, int_to_num, make_string,
|
num_to_int, int_to_num, make_string,
|
||||||
)
|
)
|
||||||
from centvrion.lexer import Lexer
|
from centvrion.lexer import Lexer
|
||||||
@@ -160,6 +160,10 @@ precedence_tests = [
|
|||||||
("CVM SVBNVLLA\n- [I, II, III][I]",
|
("CVM SVBNVLLA\n- [I, II, III][I]",
|
||||||
Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(UnaryMinus(ArrayIndex(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("I"))))]),
|
Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(UnaryMinus(ArrayIndex(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("I"))))]),
|
||||||
ValInt(-1)),
|
ValInt(-1)),
|
||||||
|
# INDEX binds tighter than NON: NON (arr[I]) = NON VERITAS = False
|
||||||
|
("NON [VERITAS, FALSITAS][I]",
|
||||||
|
Program([], [ExpressionStatement(UnaryNot(ArrayIndex(DataArray([Bool(True), Bool(False)]), Numeral("I"))))]),
|
||||||
|
ValBool(False)),
|
||||||
# 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"))]),
|
||||||
@@ -1080,5 +1084,40 @@ class TestScope(unittest.TestCase):
|
|||||||
run_test(self, source, nodes, value)
|
run_test(self, source, nodes, value)
|
||||||
|
|
||||||
|
|
||||||
|
# --- NON (boolean not) ---
|
||||||
|
|
||||||
|
non_tests = [
|
||||||
|
("NON VERITAS",
|
||||||
|
Program([], [ExpressionStatement(UnaryNot(Bool(True)))]),
|
||||||
|
ValBool(False)),
|
||||||
|
("NON FALSITAS",
|
||||||
|
Program([], [ExpressionStatement(UnaryNot(Bool(False)))]),
|
||||||
|
ValBool(True)),
|
||||||
|
("NON NON VERITAS",
|
||||||
|
Program([], [ExpressionStatement(UnaryNot(UnaryNot(Bool(True))))]),
|
||||||
|
ValBool(True)),
|
||||||
|
("NON I",
|
||||||
|
Program([], [ExpressionStatement(UnaryNot(Numeral("I")))]),
|
||||||
|
ValBool(False)),
|
||||||
|
# zero int is falsy, so NON gives True
|
||||||
|
("DESIGNA z VT I - I\nNON z",
|
||||||
|
Program([], [Designa(ID("z"), BinOp(Numeral("I"), Numeral("I"), "SYMBOL_MINUS")), ExpressionStatement(UnaryNot(ID("z")))]),
|
||||||
|
ValBool(True)),
|
||||||
|
# NON binds tighter than AVT: (NON VERITAS) AVT FALSITAS → FALSITAS AVT FALSITAS → False
|
||||||
|
("NON VERITAS AVT FALSITAS",
|
||||||
|
Program([], [ExpressionStatement(BinOp(UnaryNot(Bool(True)), Bool(False), "KEYWORD_AVT"))]),
|
||||||
|
ValBool(False)),
|
||||||
|
# NON binds tighter than EST: (NON I) EST I → FALSITAS EST I → False
|
||||||
|
("NON I EST I",
|
||||||
|
Program([], [ExpressionStatement(BinOp(UnaryNot(Numeral("I")), Numeral("I"), "KEYWORD_EST"))]),
|
||||||
|
ValBool(False)),
|
||||||
|
]
|
||||||
|
|
||||||
|
class TestNon(unittest.TestCase):
|
||||||
|
@parameterized.expand(non_tests)
|
||||||
|
def test_non(self, source, nodes, value):
|
||||||
|
run_test(self, source, nodes, value)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user