🐐 NON operator
This commit is contained in:
@@ -462,6 +462,24 @@ class UnaryMinus(Node):
|
||||
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):
|
||||
def __init__(self, array, index) -> None:
|
||||
self.array = array
|
||||
|
||||
@@ -17,6 +17,7 @@ keyword_tokens = [("KEYWORD_"+i, i) for i in [
|
||||
"INVOCA",
|
||||
"IN",
|
||||
"MINVS",
|
||||
"NON",
|
||||
"NVLLVS",
|
||||
"PER",
|
||||
"PLVS",
|
||||
|
||||
@@ -15,7 +15,7 @@ class Parser():
|
||||
('left', ["KEYWORD_PLVS", "KEYWORD_MINVS", "KEYWORD_EST"]),
|
||||
('left', ["SYMBOL_COLON", "SYMBOL_PLUS", "SYMBOL_MINUS"]),
|
||||
('left', ["SYMBOL_TIMES", "SYMBOL_DIVIDE"]),
|
||||
('right', ["UMINUS"]),
|
||||
('right', ["UMINUS", "UNOT"]),
|
||||
('left', ["INDEX"]),
|
||||
]
|
||||
)
|
||||
@@ -191,6 +191,10 @@ class Parser():
|
||||
def unary_minus(tokens):
|
||||
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')
|
||||
def invoca(tokens):
|
||||
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,
|
||||
Designa, DumStatement, Erumpe, ExpressionStatement, ID,
|
||||
Invoca, ModuleCall, Nullus, Numeral, PerStatement,
|
||||
Program, Redi, SiStatement, String, UnaryMinus,
|
||||
Program, Redi, SiStatement, String, UnaryMinus, UnaryNot,
|
||||
num_to_int, int_to_num, make_string,
|
||||
)
|
||||
from centvrion.lexer import Lexer
|
||||
@@ -160,6 +160,10 @@ precedence_tests = [
|
||||
("CVM SVBNVLLA\n- [I, II, III][I]",
|
||||
Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(UnaryMinus(ArrayIndex(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("I"))))]),
|
||||
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
|
||||
("[I, II, III][II] + X",
|
||||
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)
|
||||
|
||||
|
||||
# --- 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__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user