|
| 1 | +package tests.wurstscript.tests; |
| 2 | + |
| 3 | +import de.peeeq.wurstscript.RunArgs; |
| 4 | +import de.peeeq.wurstscript.ast.Ast; |
| 5 | +import de.peeeq.wurstscript.jassIm.*; |
| 6 | +import de.peeeq.wurstscript.translation.imtranslation.CallType; |
| 7 | +import de.peeeq.wurstscript.translation.imtranslation.Flatten; |
| 8 | +import de.peeeq.wurstscript.translation.imtranslation.Flatten.MultiResult; |
| 9 | +import de.peeeq.wurstscript.translation.imtranslation.ImTranslator; |
| 10 | +import org.testng.annotations.Test; |
| 11 | + |
| 12 | +import java.lang.reflect.Method; |
| 13 | +import java.util.Arrays; |
| 14 | +import java.util.Collections; |
| 15 | + |
| 16 | +import static org.testng.Assert.*; |
| 17 | + |
| 18 | +public class FlattenTests { |
| 19 | + |
| 20 | + @Test |
| 21 | + public void avoid_extra_temp_for_var_access() throws Exception { |
| 22 | + ImTranslator translator = new ImTranslator(Ast.WurstModel(), true, new RunArgs()); |
| 23 | + de.peeeq.wurstscript.ast.Element trace = Ast.NoExpr(); |
| 24 | + ImVar sourceVar = JassIm.ImVar(trace, JassIm.ImSimpleType("int"), "source", false); |
| 25 | + ImVar targetVar = JassIm.ImVar(trace, JassIm.ImSimpleType("int"), "target", false); |
| 26 | + |
| 27 | + ImExpr simpleAccess = JassIm.ImVarAccess(sourceVar); |
| 28 | + ImExpr expressionWithStatements = JassIm.ImStatementExpr( |
| 29 | + JassIm.ImStmts(JassIm.ImSet(trace, JassIm.ImVarAccess(targetVar), JassIm.ImIntVal(1))), |
| 30 | + JassIm.ImVarAccess(targetVar)); |
| 31 | + |
| 32 | + ImFunction function = JassIm.ImFunction(trace, "test", JassIm.ImTypeVars(), JassIm.ImVars(), JassIm.ImVoid(), |
| 33 | + JassIm.ImVars(sourceVar, targetVar), JassIm.ImStmts(), Collections.emptyList()); |
| 34 | + |
| 35 | + Method flattenExprs = Flatten.class.getDeclaredMethod("flattenExprs", ImTranslator.class, ImFunction.class, java.util.List.class); |
| 36 | + flattenExprs.setAccessible(true); |
| 37 | + |
| 38 | + MultiResult result = (MultiResult) flattenExprs.invoke(null, translator, function, Arrays.asList(simpleAccess, expressionWithStatements)); |
| 39 | + |
| 40 | + assertEquals(function.getLocals().size(), 2, "no extra locals should be introduced"); |
| 41 | + assertSame(simpleAccess, result.expr(0), "the original access should be reused"); |
| 42 | + } |
| 43 | + |
| 44 | + @Test |
| 45 | + public void add_temp_for_impure_expr_with_followup_statements() throws Exception { |
| 46 | + ImTranslator translator = new ImTranslator(Ast.WurstModel(), true, new RunArgs()); |
| 47 | + de.peeeq.wurstscript.ast.Element trace = Ast.NoExpr(); |
| 48 | + ImVar sourceVar = JassIm.ImVar(trace, JassIm.ImSimpleType("int"), "source", false); |
| 49 | + ImVar targetVar = JassIm.ImVar(trace, JassIm.ImSimpleType("int"), "target", false); |
| 50 | + |
| 51 | + ImFunction impureCallee = JassIm.ImFunction(trace, "impure", JassIm.ImTypeVars(), JassIm.ImVars(), |
| 52 | + JassIm.ImSimpleType("int"), JassIm.ImVars(), JassIm.ImStmts(), Collections.emptyList()); |
| 53 | + ImExpr impureCall = JassIm.ImFunctionCall(trace, impureCallee, JassIm.ImTypeArguments(), JassIm.ImExprs(), |
| 54 | + false, CallType.NORMAL); |
| 55 | + |
| 56 | + ImExpr expressionWithStatements = JassIm.ImStatementExpr( |
| 57 | + JassIm.ImStmts(JassIm.ImSet(trace, JassIm.ImVarAccess(targetVar), JassIm.ImIntVal(1))), |
| 58 | + JassIm.ImVarAccess(targetVar)); |
| 59 | + |
| 60 | + ImFunction function = JassIm.ImFunction(trace, "test", JassIm.ImTypeVars(), JassIm.ImVars(), JassIm.ImVoid(), |
| 61 | + JassIm.ImVars(sourceVar, targetVar), JassIm.ImStmts(), Collections.emptyList()); |
| 62 | + |
| 63 | + Method flattenExprs = Flatten.class.getDeclaredMethod("flattenExprs", ImTranslator.class, ImFunction.class, java.util.List.class); |
| 64 | + flattenExprs.setAccessible(true); |
| 65 | + |
| 66 | + MultiResult result = (MultiResult) flattenExprs.invoke(null, translator, function, Arrays.asList(impureCall, expressionWithStatements)); |
| 67 | + |
| 68 | + assertEquals(function.getLocals().size(), 3, "a temporary should be added for the impure expression"); |
| 69 | + assertEquals(result.stmts.size(), 2, "flattening should produce a temp assignment followed by the statement expr body"); |
| 70 | + |
| 71 | + ImExpr flattenedImpure = result.expr(0); |
| 72 | + assertTrue(flattenedImpure instanceof ImVarAccess, "impure call should be replaced with temp access"); |
| 73 | + ImVar tempVar = ((ImVarAccess) flattenedImpure).getVar(); |
| 74 | + assertNotSame(tempVar, sourceVar); |
| 75 | + assertNotSame(tempVar, targetVar); |
| 76 | + |
| 77 | + ImStmt tempAssignment = result.stmts.get(0); |
| 78 | + assertTrue(tempAssignment instanceof ImSet, "first statement should assign the impure result to the temp var"); |
| 79 | + ImLExpr left = ((ImSet) tempAssignment).getLeft(); |
| 80 | + assertTrue(left instanceof ImVarAccess); |
| 81 | + assertSame(((ImVarAccess) left).getVar(), tempVar); |
| 82 | + } |
| 83 | + |
| 84 | + @Test |
| 85 | + public void add_temp_when_followup_writes_accessed_var() throws Exception { |
| 86 | + ImTranslator translator = new ImTranslator(Ast.WurstModel(), true, new RunArgs()); |
| 87 | + de.peeeq.wurstscript.ast.Element trace = Ast.NoExpr(); |
| 88 | + ImVar shared = JassIm.ImVar(trace, JassIm.ImSimpleType("int"), "shared", false); |
| 89 | + |
| 90 | + ImExpr initialRead = JassIm.ImVarAccess(shared); |
| 91 | + ImExpr statementWithWrite = JassIm.ImStatementExpr( |
| 92 | + JassIm.ImStmts(JassIm.ImSet(trace, JassIm.ImVarAccess(shared), JassIm.ImIntVal(4))), |
| 93 | + JassIm.ImIntVal(2)); |
| 94 | + |
| 95 | + ImFunction function = JassIm.ImFunction(trace, "test", JassIm.ImTypeVars(), JassIm.ImVars(), JassIm.ImVoid(), |
| 96 | + JassIm.ImVars(shared), JassIm.ImStmts(), Collections.emptyList()); |
| 97 | + |
| 98 | + Method flattenExprs = Flatten.class.getDeclaredMethod("flattenExprs", ImTranslator.class, ImFunction.class, java.util.List.class); |
| 99 | + flattenExprs.setAccessible(true); |
| 100 | + |
| 101 | + MultiResult result = (MultiResult) flattenExprs.invoke(null, translator, function, Arrays.asList(initialRead, statementWithWrite)); |
| 102 | + |
| 103 | + assertEquals(function.getLocals().size(), 2, "flattening should introduce a temp for the first argument"); |
| 104 | + assertEquals(result.stmts.size(), 2, "flattening should store the first arg before executing later statements"); |
| 105 | + |
| 106 | + ImExpr firstExpr = result.expr(0); |
| 107 | + assertTrue(firstExpr instanceof ImVarAccess, "first expression should be rewritten to a temp access"); |
| 108 | + ImVar tempVar = ((ImVarAccess) firstExpr).getVar(); |
| 109 | + assertNotSame(tempVar, shared); |
| 110 | + |
| 111 | + ImStmt firstStmt = result.stmts.get(0); |
| 112 | + assertTrue(firstStmt instanceof ImSet, "first statement should capture the original value"); |
| 113 | + assertSame(((ImVarAccess) ((ImSet) firstStmt).getLeft()).getVar(), tempVar); |
| 114 | + } |
| 115 | +} |
0 commit comments