🐐 Modulo
This commit is contained in:
@@ -37,7 +37,9 @@ OP_STR = {
|
||||
"SYMBOL_PLUS": "+", "SYMBOL_MINUS": "-",
|
||||
"SYMBOL_TIMES": "*", "SYMBOL_DIVIDE": "/",
|
||||
"SYMBOL_AMPERSAND": "&",
|
||||
"KEYWORD_EST": "EST", "KEYWORD_MINVS": "MINVS",
|
||||
"KEYWORD_RELIQVVM": "RELIQVVM",
|
||||
"KEYWORD_EST": "EST", "KEYWORD_DISPAR": "DISPAR",
|
||||
"KEYWORD_MINVS": "MINVS",
|
||||
"KEYWORD_PLVS": "PLVS", "KEYWORD_ET": "ET", "KEYWORD_AVT": "AVT",
|
||||
}
|
||||
|
||||
@@ -586,6 +588,14 @@ class BinOp(Node):
|
||||
if isinstance(lv, Fraction) or isinstance(rv, Fraction) or "FRACTIO" in vtable["#modules"]:
|
||||
return vtable, ValFrac(Fraction(lv or 0) / Fraction(rv or 0))
|
||||
return vtable, ValInt((lv or 0) // (rv or 0))
|
||||
case "KEYWORD_RELIQVVM":
|
||||
if isinstance(lv, (str, list)) or isinstance(rv, (str, list)):
|
||||
raise CentvrionError("Cannot use RELIQVVM on strings or arrays")
|
||||
if (rv or 0) == 0:
|
||||
raise CentvrionError("Modulo by zero")
|
||||
if isinstance(lv, Fraction) or isinstance(rv, Fraction) or "FRACTIO" in vtable["#modules"]:
|
||||
return vtable, ValFrac(Fraction(lv or 0) % Fraction(rv or 0))
|
||||
return vtable, ValInt((lv or 0) % (rv or 0))
|
||||
case "KEYWORD_MINVS":
|
||||
if isinstance(lv, (str, list)) or isinstance(rv, (str, list)):
|
||||
raise CentvrionError("Cannot compare strings or arrays with MINVS")
|
||||
@@ -596,6 +606,8 @@ class BinOp(Node):
|
||||
return vtable, ValBool((lv or 0) > (rv or 0))
|
||||
case "KEYWORD_EST":
|
||||
return vtable, ValBool(lv == rv)
|
||||
case "KEYWORD_DISPAR":
|
||||
return vtable, ValBool(lv != rv)
|
||||
case "KEYWORD_ET":
|
||||
return vtable, ValBool(bool(left) and bool(right))
|
||||
case "KEYWORD_AVT":
|
||||
|
||||
@@ -13,7 +13,9 @@ _BINOP_FN = {
|
||||
"SYMBOL_TIMES": "cent_mul",
|
||||
"SYMBOL_DIVIDE": "cent_div",
|
||||
"SYMBOL_AMPERSAND": "cent_concat",
|
||||
"KEYWORD_RELIQVVM": "cent_mod",
|
||||
"KEYWORD_EST": "cent_eq",
|
||||
"KEYWORD_DISPAR": "cent_neq",
|
||||
"KEYWORD_MINVS": "cent_lt",
|
||||
"KEYWORD_PLVS": "cent_gt",
|
||||
"KEYWORD_ET": "cent_and",
|
||||
@@ -77,6 +79,8 @@ def emit_expr(node, ctx):
|
||||
tmp = ctx.fresh_tmp()
|
||||
if node.op == "SYMBOL_DIVIDE" and ctx.has_module("FRACTIO"):
|
||||
fn = "cent_div_frac"
|
||||
elif node.op == "KEYWORD_RELIQVVM" and ctx.has_module("FRACTIO"):
|
||||
fn = "cent_mod_frac"
|
||||
else:
|
||||
fn = _BINOP_FN[node.op]
|
||||
return l_lines + r_lines + [f"CentValue {tmp} = {fn}({l_var}, {r_var});"], tmp
|
||||
|
||||
@@ -396,6 +396,30 @@ CentValue cent_div_frac(CentValue a, CentValue b) {
|
||||
return frac_reduce(an * bd, ad * bn);
|
||||
}
|
||||
|
||||
CentValue cent_mod(CentValue a, CentValue b) {
|
||||
if (a.type != CENT_INT || b.type != CENT_INT)
|
||||
cent_type_error("'RELIQVVM' requires two integers");
|
||||
if (b.ival == 0)
|
||||
cent_runtime_error("modulo by zero");
|
||||
return cent_int(a.ival % b.ival);
|
||||
}
|
||||
|
||||
CentValue cent_mod_frac(CentValue a, CentValue b) {
|
||||
long an, ad, bn, bd;
|
||||
to_frac(a, &an, &ad); to_frac(b, &bn, &bd);
|
||||
if (bn == 0) cent_runtime_error("modulo by zero");
|
||||
/* a/b mod c/d over a common denominator ad*bd:
|
||||
num_a = an*bd, num_b = bn*ad
|
||||
result = (num_a - floor(num_a/num_b) * num_b) / (ad*bd)
|
||||
Use floored division so the result matches Python's Fraction.__mod__. */
|
||||
long num_a = an * bd;
|
||||
long num_b = bn * ad;
|
||||
long q = num_a / num_b;
|
||||
if ((num_a % num_b != 0) && ((num_a < 0) != (num_b < 0))) q -= 1;
|
||||
long new_num = num_a - q * num_b;
|
||||
return frac_reduce(new_num, ad * bd);
|
||||
}
|
||||
|
||||
CentValue cent_eq(CentValue a, CentValue b) {
|
||||
if ((a.type == CENT_INT || a.type == CENT_FRAC) &&
|
||||
(b.type == CENT_INT || b.type == CENT_FRAC)) {
|
||||
@@ -414,6 +438,11 @@ CentValue cent_eq(CentValue a, CentValue b) {
|
||||
}
|
||||
}
|
||||
|
||||
CentValue cent_neq(CentValue a, CentValue b) {
|
||||
CentValue r = cent_eq(a, b);
|
||||
return cent_bool(!r.bval);
|
||||
}
|
||||
|
||||
CentValue cent_lt(CentValue a, CentValue b) {
|
||||
if ((a.type == CENT_INT || a.type == CENT_FRAC || a.type == CENT_NULL) &&
|
||||
(b.type == CENT_INT || b.type == CENT_FRAC || b.type == CENT_NULL)) {
|
||||
|
||||
@@ -158,7 +158,10 @@ CentValue cent_sub(CentValue a, CentValue b); /* INT-INT or FRAC-FRAC/INT */
|
||||
CentValue cent_mul(CentValue a, CentValue b); /* INT*INT or FRAC*FRAC/INT */
|
||||
CentValue cent_div(CentValue a, CentValue b); /* INT/INT integer div */
|
||||
CentValue cent_div_frac(CentValue a, CentValue b); /* FRACTIO: exact div → FRAC */
|
||||
CentValue cent_mod(CentValue a, CentValue b); /* INT%INT integer modulo */
|
||||
CentValue cent_mod_frac(CentValue a, CentValue b); /* FRACTIO: floored mod → FRAC */
|
||||
CentValue cent_eq (CentValue a, CentValue b); /* EST → BOOL */
|
||||
CentValue cent_neq(CentValue a, CentValue b); /* DISPAR → BOOL */
|
||||
CentValue cent_lt (CentValue a, CentValue b); /* MINVS → BOOL */
|
||||
CentValue cent_gt (CentValue a, CentValue b); /* PLVS → BOOL */
|
||||
CentValue cent_and(CentValue a, CentValue b); /* ET → BOOL */
|
||||
|
||||
@@ -7,6 +7,7 @@ keyword_tokens = [("KEYWORD_"+i, i) for i in [
|
||||
"AVT",
|
||||
"DEFINI",
|
||||
"DESIGNA",
|
||||
"DISPAR",
|
||||
"DONICVM",
|
||||
"DVM",
|
||||
"CONTINVA",
|
||||
@@ -23,6 +24,7 @@ keyword_tokens = [("KEYWORD_"+i, i) for i in [
|
||||
"PER",
|
||||
"PLVS",
|
||||
"REDI",
|
||||
"RELIQVVM",
|
||||
"SI",
|
||||
"TVNC",
|
||||
"VSQVE",
|
||||
|
||||
@@ -12,9 +12,9 @@ class Parser():
|
||||
precedence=[
|
||||
('left', ["KEYWORD_AVT"]),
|
||||
('left', ["KEYWORD_ET"]),
|
||||
('left', ["KEYWORD_PLVS", "KEYWORD_MINVS", "KEYWORD_EST"]),
|
||||
('left', ["KEYWORD_PLVS", "KEYWORD_MINVS", "KEYWORD_EST", "KEYWORD_DISPAR"]),
|
||||
('left', ["SYMBOL_AMPERSAND", "SYMBOL_PLUS", "SYMBOL_MINUS"]),
|
||||
('left', ["SYMBOL_TIMES", "SYMBOL_DIVIDE"]),
|
||||
('left', ["SYMBOL_TIMES", "SYMBOL_DIVIDE", "KEYWORD_RELIQVVM"]),
|
||||
('right', ["UMINUS", "UNOT"]),
|
||||
('left', ["SYMBOL_LBRACKET", "INDEX"]),
|
||||
]
|
||||
@@ -191,7 +191,9 @@ class Parser():
|
||||
@self.pg.production('expression : expression SYMBOL_PLUS expression')
|
||||
@self.pg.production('expression : expression SYMBOL_TIMES expression')
|
||||
@self.pg.production('expression : expression SYMBOL_DIVIDE expression')
|
||||
@self.pg.production('expression : expression KEYWORD_RELIQVVM expression')
|
||||
@self.pg.production('expression : expression KEYWORD_EST expression')
|
||||
@self.pg.production('expression : expression KEYWORD_DISPAR expression')
|
||||
@self.pg.production('expression : expression KEYWORD_MINVS expression')
|
||||
@self.pg.production('expression : expression KEYWORD_PLVS expression')
|
||||
@self.pg.production('expression : expression KEYWORD_ET expression')
|
||||
|
||||
Reference in New Issue
Block a user