Skip to content

Commit d893610

Browse files
committed
bunch of fixes and prevent nil comparisons
1 parent d92077a commit d893610

4 files changed

Lines changed: 130 additions & 22 deletions

File tree

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/lua/translation/ExprTranslation.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,13 @@ public static LuaExpr translate(ImOperatorCall e, LuaTranslator tr) {
152152
LuaExpr leftExpr = left.translateToLua(tr);
153153
LuaExpr rightExpr = right.translateToLua(tr);
154154
LuaOpBinary op;
155+
if (isIntNumericOperator(e.getOp())) {
156+
leftExpr = ensureInt(leftExpr, tr);
157+
rightExpr = ensureInt(rightExpr, tr);
158+
} else if (isRealNumericOperator(e.getOp())) {
159+
leftExpr = ensureReal(leftExpr, tr);
160+
rightExpr = ensureReal(rightExpr, tr);
161+
}
155162
if (e.getOp() == WurstOperator.MOD_INT) {
156163
op = LuaAst.LuaOpMod();
157164

@@ -176,6 +183,7 @@ public static LuaExpr translate(ImOperatorCall e, LuaTranslator tr) {
176183
break;
177184
case UNARY_MINUS:
178185
op = LuaAst.LuaOpMinus();
186+
argT = ensureReal(argT, tr);
179187
break;
180188
default:
181189
throw new Error("not implemented: unary operator " + e.getOp());
@@ -186,6 +194,29 @@ public static LuaExpr translate(ImOperatorCall e, LuaTranslator tr) {
186194
throw new Error("not implemented: " + e);
187195
}
188196

197+
private static boolean isIntNumericOperator(WurstOperator op) {
198+
return op == WurstOperator.DIV_INT || op == WurstOperator.MOD_INT;
199+
}
200+
201+
private static boolean isRealNumericOperator(WurstOperator op) {
202+
return op == WurstOperator.LESS
203+
|| op == WurstOperator.LESS_EQ
204+
|| op == WurstOperator.GREATER
205+
|| op == WurstOperator.GREATER_EQ
206+
|| op == WurstOperator.MINUS
207+
|| op == WurstOperator.MULT
208+
|| op == WurstOperator.DIV_REAL
209+
|| op == WurstOperator.MOD_REAL;
210+
}
211+
212+
private static LuaExpr ensureInt(LuaExpr expr, LuaTranslator tr) {
213+
return LuaAst.LuaExprFunctionCall(tr.ensureIntFunction, LuaAst.LuaExprlist(expr));
214+
}
215+
216+
private static LuaExpr ensureReal(LuaExpr expr, LuaTranslator tr) {
217+
return LuaAst.LuaExprFunctionCall(tr.ensureRealFunction, LuaAst.LuaExprlist(expr));
218+
}
219+
189220
static class TupleFunc {
190221
final ImTupleType tupleType;
191222
final LuaFunction func;

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/lua/translation/LuaNatives.java

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,13 +115,42 @@ public class LuaNatives {
115115
f.getBody().add(LuaAst.LuaLiteral("if not h[p] then h[p] = {} end h[p][c] = i"));
116116
});
117117

118-
addNative(Arrays.asList(
119-
"LoadInteger", "LoadBoolean", "LoadReal", "LoadStr",
120-
"__wurst_LoadInteger", "__wurst_LoadBoolean", "__wurst_LoadReal", "__wurst_LoadStr"), f -> {
118+
addNative(Arrays.asList("LoadInteger", "__wurst_LoadInteger"), f -> {
119+
f.getParams().add(LuaAst.LuaVariable("h", LuaAst.LuaNoExpr()));
120+
f.getParams().add(LuaAst.LuaVariable("p", LuaAst.LuaNoExpr()));
121+
f.getParams().add(LuaAst.LuaVariable("c", LuaAst.LuaNoExpr()));
122+
f.getBody().add(LuaAst.LuaLiteral("if not h[p] then return 0 end"));
123+
f.getBody().add(LuaAst.LuaLiteral("local v = h[p][c]"));
124+
f.getBody().add(LuaAst.LuaLiteral("if v == nil then return 0 end"));
125+
f.getBody().add(LuaAst.LuaLiteral("return v"));
126+
});
127+
128+
addNative(Arrays.asList("LoadBoolean", "__wurst_LoadBoolean"), f -> {
129+
f.getParams().add(LuaAst.LuaVariable("h", LuaAst.LuaNoExpr()));
130+
f.getParams().add(LuaAst.LuaVariable("p", LuaAst.LuaNoExpr()));
131+
f.getParams().add(LuaAst.LuaVariable("c", LuaAst.LuaNoExpr()));
132+
f.getBody().add(LuaAst.LuaLiteral("if not h[p] then return false end"));
133+
f.getBody().add(LuaAst.LuaLiteral("local v = h[p][c]"));
134+
f.getBody().add(LuaAst.LuaLiteral("if v == nil then return false end"));
135+
f.getBody().add(LuaAst.LuaLiteral("return v"));
136+
});
137+
138+
addNative(Arrays.asList("LoadReal", "__wurst_LoadReal"), f -> {
139+
f.getParams().add(LuaAst.LuaVariable("h", LuaAst.LuaNoExpr()));
140+
f.getParams().add(LuaAst.LuaVariable("p", LuaAst.LuaNoExpr()));
141+
f.getParams().add(LuaAst.LuaVariable("c", LuaAst.LuaNoExpr()));
142+
f.getBody().add(LuaAst.LuaLiteral("if not h[p] then return 0.0 end"));
143+
f.getBody().add(LuaAst.LuaLiteral("local v = h[p][c]"));
144+
f.getBody().add(LuaAst.LuaLiteral("if v == nil then return 0.0 end"));
145+
f.getBody().add(LuaAst.LuaLiteral("return v"));
146+
});
147+
148+
addNative(Arrays.asList("LoadStr", "__wurst_LoadStr"), f -> {
121149
f.getParams().add(LuaAst.LuaVariable("h", LuaAst.LuaNoExpr()));
122150
f.getParams().add(LuaAst.LuaVariable("p", LuaAst.LuaNoExpr()));
123151
f.getParams().add(LuaAst.LuaVariable("c", LuaAst.LuaNoExpr()));
124-
f.getBody().add(LuaAst.LuaLiteral("if not h[p] then return nil end return h[p][c]"));
152+
f.getBody().add(LuaAst.LuaLiteral("if not h[p] then return nil end"));
153+
f.getBody().add(LuaAst.LuaLiteral("return h[p][c]"));
125154
});
126155

127156
addNative(Arrays.asList(

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/lua/translation/LuaTranslator.java

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@
2222

2323
public class LuaTranslator {
2424
private static final int LUA_LOCALS_LIMIT = 200;
25+
private static final List<String> REQUIRED_WURST_HASHTABLE_HELPERS = Arrays.asList(
26+
"__wurst_InitHashtable",
27+
"__wurst_SaveInteger", "__wurst_SaveBoolean", "__wurst_SaveReal", "__wurst_SaveStr",
28+
"__wurst_LoadInteger", "__wurst_LoadBoolean", "__wurst_LoadReal", "__wurst_LoadStr",
29+
"__wurst_HaveSavedInteger", "__wurst_HaveSavedBoolean", "__wurst_HaveSavedReal", "__wurst_HaveSavedString",
30+
"__wurst_FlushChildHashtable", "__wurst_FlushParentHashtable",
31+
"__wurst_RemoveSavedInteger", "__wurst_RemoveSavedBoolean", "__wurst_RemoveSavedReal", "__wurst_RemoveSavedString"
32+
);
2533
private static final Set<String> HASHTABLE_NATIVE_NAMES = new HashSet<>(Arrays.asList(
2634
"InitHashtable",
2735
"SaveInteger", "SaveBoolean", "SaveReal", "SaveStr",
@@ -202,6 +210,7 @@ public LuaCompilationUnit translate() {
202210
createInstanceOfFunction();
203211
createObjectIndexFunctions();
204212
createEnsureTypeFunctions();
213+
ensureWurstHashtableHelpers();
205214

206215
for (ImVar v : prog.getGlobals()) {
207216
translateGlobal(v);
@@ -230,6 +239,19 @@ public LuaCompilationUnit translate() {
230239
return luaModel;
231240
}
232241

242+
/**
243+
* Always emit internal hashtable helper functions used by Lua lowering.
244+
* This keeps compiletime migration data loading robust even if the
245+
* corresponding Warcraft natives are unavailable or filtered out.
246+
*/
247+
private void ensureWurstHashtableHelpers() {
248+
for (String helper : REQUIRED_WURST_HASHTABLE_HELPERS) {
249+
LuaFunction f = LuaAst.LuaFunction(helper, LuaAst.LuaParams(), LuaAst.LuaStatements());
250+
LuaNatives.get(f);
251+
luaModel.add(f);
252+
}
253+
}
254+
233255
private boolean isFixedEntryPoint(ImFunction function) {
234256
return function == imTr.getMainFunc() || function == imTr.getConfFunc();
235257
}
@@ -444,24 +466,29 @@ function defaultArray(d)
444466
}
445467

446468
private void createEnsureTypeFunctions() {
447-
LuaFunction[] ensureTypeFunctions = {ensureIntFunction, ensureBoolFunction, ensureRealFunction, ensureStrFunction};
448-
String[] defaultValue = {"0", "false", "0.0", "\"\""};
449-
for(int i = 0; i < ensureTypeFunctions.length; ++i) {
450-
LuaFunction ensureTypeFunction = ensureTypeFunctions[i];
451-
String[] code = {
452-
"if x == nil then",
453-
" return " + defaultValue[i],
454-
"else",
455-
" return " + (ensureTypeFunction == ensureIntFunction ? "math.tointeger(x)" : "x"),
456-
"end"
457-
};
458-
459-
ensureTypeFunction.getParams().add(LuaAst.LuaVariable("x", LuaAst.LuaNoExpr()));
460-
for (String c : code) {
461-
ensureTypeFunction.getBody().add(LuaAst.LuaLiteral(c));
462-
}
463-
luaModel.add(ensureTypeFunction);
464-
}
469+
ensureIntFunction.getParams().add(LuaAst.LuaVariable("x", LuaAst.LuaNoExpr()));
470+
ensureIntFunction.getBody().add(LuaAst.LuaLiteral("local n = tonumber(x)"));
471+
ensureIntFunction.getBody().add(LuaAst.LuaLiteral("if n == nil then return 0 end"));
472+
ensureIntFunction.getBody().add(LuaAst.LuaLiteral("local i = math.tointeger(n)"));
473+
ensureIntFunction.getBody().add(LuaAst.LuaLiteral("if i == nil then return 0 end"));
474+
ensureIntFunction.getBody().add(LuaAst.LuaLiteral("return i"));
475+
luaModel.add(ensureIntFunction);
476+
477+
ensureBoolFunction.getParams().add(LuaAst.LuaVariable("x", LuaAst.LuaNoExpr()));
478+
ensureBoolFunction.getBody().add(LuaAst.LuaLiteral("if x == nil then return false end"));
479+
ensureBoolFunction.getBody().add(LuaAst.LuaLiteral("return x"));
480+
luaModel.add(ensureBoolFunction);
481+
482+
ensureRealFunction.getParams().add(LuaAst.LuaVariable("x", LuaAst.LuaNoExpr()));
483+
ensureRealFunction.getBody().add(LuaAst.LuaLiteral("local n = tonumber(x)"));
484+
ensureRealFunction.getBody().add(LuaAst.LuaLiteral("if n == nil then return 0.0 end"));
485+
ensureRealFunction.getBody().add(LuaAst.LuaLiteral("return n"));
486+
luaModel.add(ensureRealFunction);
487+
488+
ensureStrFunction.getParams().add(LuaAst.LuaVariable("x", LuaAst.LuaNoExpr()));
489+
ensureStrFunction.getBody().add(LuaAst.LuaLiteral("if x == nil then return \"\" end"));
490+
ensureStrFunction.getBody().add(LuaAst.LuaLiteral("return tostring(x)"));
491+
luaModel.add(ensureStrFunction);
465492
}
466493

467494
private void cleanStatements() {

de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/LuaTranslationTests.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ public void testStdLib() throws IOException {
7575
);
7676
String compiled = Files.toString(new File("test-output/lua/LuaTranslationTests_testStdLib.lua"), Charsets.UTF_8);
7777
assertTrue(compiled.contains("MagicFunctions_compiletime"));
78+
assertTrue(compiled.contains("function __wurst_InitHashtable("));
79+
assertTrue(compiled.contains("function __wurst_SaveInteger("));
80+
assertTrue(compiled.contains("function __wurst_LoadInteger("));
81+
assertFunctionBodyContains(compiled, "__wurst_LoadInteger", "return 0", true);
7882
}
7983

8084
@Ignore
@@ -202,6 +206,23 @@ public void stringConcatenation() throws IOException {
202206
assertFunctionBodyContains(compiled, "test", "stringConcat", true);
203207
}
204208

209+
@Test
210+
public void numericOpsAreGuardedWithEnsure() throws IOException {
211+
test().testLua(true).lines(
212+
"package Test",
213+
"function cmp(int a, int b) returns boolean",
214+
" return a < b",
215+
"function divi(int a, int b) returns int",
216+
" return a div b",
217+
"init",
218+
" cmp(1, 2)",
219+
" divi(2, 1)"
220+
);
221+
String compiled = Files.toString(new File("test-output/lua/LuaTranslationTests_numericOpsAreGuardedWithEnsure.lua"), Charsets.UTF_8);
222+
assertFunctionBodyContains(compiled, "cmp", "realEnsure", true);
223+
assertFunctionBodyContains(compiled, "divi", "intEnsure", true);
224+
}
225+
205226
@Test
206227
public void methodFieldNameCollision() throws IOException {
207228
test().testLua(true).lines(

0 commit comments

Comments
 (0)