Skip to content

Commit 244b1d5

Browse files
authored
Fix plain Jass modulo semantics (#1209)
1 parent f525296 commit 244b1d5

17 files changed

Lines changed: 103 additions & 8 deletions

File tree

‎de.peeeq.wurstscript/parserspec/jass.parseq‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ JassOpBinary =
7575
| JassOpMinus()
7676
| JassOpMult()
7777
| JassOpDiv()
78+
| JassOpMod()
7879

7980
JassOpUnary =
8081
JassOpNot()

‎de.peeeq.wurstscript/src/main/antlr/de/peeeq/wurstscript/antlr/Jass.g4‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ PLUS: '+';
163163
MINUS: '-';
164164
MULT: '*';
165165
DIV_REAL: '/';
166-
MOD_REAL: '%';
166+
MOD_INT: '%';
167167
PAREN_LEFT: '(';
168168
PAREN_RIGHT: ')';
169169
BRACKET_LEFT: '[';

‎de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/JassInterpreter.java‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.google.common.collect.Maps;
44
import de.peeeq.wurstscript.WLogger;
5+
import de.peeeq.wurstscript.WurstOperator;
56
import de.peeeq.wurstscript.intermediatelang.*;
67
import de.peeeq.wurstscript.intermediatelang.interpreter.AbstractInterpreter;
78
import de.peeeq.wurstscript.intermediatelang.interpreter.TimerMockHandler;
@@ -310,6 +311,12 @@ public ILconst case_JassOpDiv(JassOpDiv jassOpDiv) {
310311
return getLeftNum().div(getRightNum());
311312
}
312313

314+
@Override
315+
public ILconst case_JassOpMod(JassOpMod jassOpMod) {
316+
return new ILconstInt(WurstOperator.jassModuloInteger(
317+
((ILconstInt) getLeft()).getVal(), ((ILconstInt) getRight()).getVal()));
318+
}
319+
313320
@Override
314321
public ILconst case_JassOpLess(JassOpLess jassOpLess) {
315322
return getLeftNum().less(getRightNum());

‎de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/LuaEnsureTypeProvider.java‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package de.peeeq.wurstio.jassinterpreter.providers;
22

3+
import de.peeeq.wurstscript.WurstOperator;
34
import de.peeeq.wurstscript.intermediatelang.ILconstInt;
45
import de.peeeq.wurstscript.intermediatelang.ILconstReal;
56
import de.peeeq.wurstscript.intermediatelang.ILconstString;
@@ -50,7 +51,7 @@ public ILconstInt __wurst_rawFloorDivInt(ILconstInt a, ILconstInt b) {
5051
}
5152

5253
public ILconstInt __wurst_rawFmodInt(ILconstInt a, ILconstInt b) {
53-
return ILconstInt.create(a.getVal() % b.getVal());
54+
return ILconstInt.create(WurstOperator.jassModuloInteger(a.getVal(), b.getVal()));
5455
}
5556

5657
public ILconstReal __wurst_rawFmodReal(ILconstReal a, ILconstReal b) {

‎de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/WurstOperator.java‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public enum WurstOperator {
2727
DIV_INT("div", 2),
2828
MOD_REAL("%", 2),
2929
MOD_INT("mod", 2),
30+
JASS_MOD_INT("%", 2),
3031
NOT("not", 1),
3132
UNARY_MINUS("-", 1);
3233

@@ -75,6 +76,8 @@ public JassOpBinary jassTranslateBinary() {
7576
case MOD_INT:
7677
case MOD_REAL:
7778
throw new Error("Cannot translate modulo");
79+
case JASS_MOD_INT:
80+
return JassAst.JassOpMod();
7881
case MULT:
7982
return JassAst.JassOpMult();
8083
case NOTEQ:
@@ -110,6 +113,7 @@ public LuaOpBinary luaTranslateBinary() {
110113
case MOD_REAL:
111114
return LuaAst.LuaOpMod();
112115
case MOD_INT:
116+
case JASS_MOD_INT:
113117
throw new Error("Cannot translate modulo int");
114118
case MULT:
115119
return LuaAst.LuaOpMult();
@@ -150,6 +154,8 @@ public ILconst evaluateBinaryOperator(ILconst left,
150154
return ((ILconstNum) left).sub((ILconstNum) right.get());
151155
case MOD_INT:
152156
return new ILconstInt(moduloInteger(((ILconstInt) left).getVal(), ((ILconstInt) right.get()).getVal()));
157+
case JASS_MOD_INT:
158+
return new ILconstInt(jassModuloInteger(((ILconstInt) left).getVal(), ((ILconstInt) right.get()).getVal()));
153159
case MOD_REAL:
154160
return new ILconstReal(moduloReal(getReal(left), getReal(right.get())));
155161
case MULT:
@@ -180,6 +186,11 @@ public static int moduloInteger(int a, int b) {
180186
return r;
181187
}
182188

189+
/** Native Jass {@code %}: integer-only remainder truncated toward zero. */
190+
public static int jassModuloInteger(int a, int b) {
191+
return a % b;
192+
}
193+
183194
/** Reference semantics for Wurst's real {@code mod}; see {@link #moduloInteger}. */
184195
public static float moduloReal(float a, float b) {
185196
float r = a % b;

‎de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/attributes/AttrExprType.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ public static WurstType calculate(final ExprBinary term) {
315315
"operands " + leftType + " and " + rightType);
316316
return WurstTypeUnknown.instance();
317317
case MOD_INT:
318+
case JASS_MOD_INT:
318319
case DIV_INT:
319320
if (leftType.isSubtypeOf(WurstTypeInt.instance(), term) && rightType.isSubtypeOf(WurstTypeInt.instance(), term)) {
320321
return leftType;

‎de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/attributes/prettyPrint/PrettyPrinter.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ public static int precedence(WurstOperator op) {
236236
case DIV_REAL:
237237
case MOD_INT:
238238
case MOD_REAL:
239+
case JASS_MOD_INT:
239240
return 4;
240241

241242
case PLUS:

‎de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/ConstantAndCopyPropagation.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,7 @@ private void analyzeComponent(List<Node> scc, Map<Node, Knowledge> knowledge) {
486486
case MULT: return JassIm.ImIntVal(l * r);
487487
case DIV_INT: if (r != 0) return JassIm.ImIntVal(l / r); break;
488488
case MOD_INT: if (r != 0) return JassIm.ImIntVal(WurstOperator.moduloInteger(l, r)); break;
489+
case JASS_MOD_INT: if (r != 0) return JassIm.ImIntVal(WurstOperator.jassModuloInteger(l, r)); break;
489490
// IMPORTANT: Return ImBoolVal for comparisons, not ImIntVal!
490491
case EQ: return JassIm.ImBoolVal(l == r);
491492
case NOTEQ: return JassIm.ImBoolVal(l != r);

‎de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/SimpleRewrites.java‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,12 @@ private boolean optimizeIntInt(ImOperatorCall opc, boolean wasViable, ImIntVal l
551551
isArithmetic = true;
552552
}
553553
break;
554+
case JASS_MOD_INT:
555+
if (i2 != 0) {
556+
resultVal = WurstOperator.jassModuloInteger(i1, i2);
557+
isArithmetic = true;
558+
}
559+
break;
554560
case MOD_REAL: {
555561
float f1 = i1;
556562
float f2 = i2;

‎de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/jass/AntlrJassParseTreeTransformer.java‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,8 @@ private WurstOperator transformOp(Token op) {
368368
return WurstOperator.MULT;
369369
case JassParser.DIV_REAL:
370370
return WurstOperator.DIV_REAL;
371-
case JassParser.MOD_REAL:
372-
return WurstOperator.MOD_REAL;
371+
case JassParser.MOD_INT:
372+
return WurstOperator.JASS_MOD_INT;
373373
case JassParser.NOT:
374374
return WurstOperator.NOT;
375375
}

0 commit comments

Comments
 (0)