diff --git a/de.peeeq.wurstscript/parserspec/jass_im.parseq b/de.peeeq.wurstscript/parserspec/jass_im.parseq index e748e3f49..a76887af1 100644 --- a/de.peeeq.wurstscript/parserspec/jass_im.parseq +++ b/de.peeeq.wurstscript/parserspec/jass_im.parseq @@ -16,10 +16,9 @@ ImVar(@ignoreForEquality de.peeeq.wurstscript.ast.Element trace, ref ImType type ImType = ImSimpleType(String typename) - | ImArrayType(String typename) - | ImArrayTypeMulti(String typename, java.util.List arraySize) + | ImArrayType(ref ImType entryType) + | ImArrayTypeMulti(ref ImType entryType, java.util.List arraySize) | ImTupleType(java.util.List types, java.util.List names) - | ImTupleArrayType(java.util.List types, java.util.List names) | ImVoid() ImFunction(@ignoreForEquality de.peeeq.wurstscript.ast.Element trace, @@ -52,11 +51,7 @@ ImStmt = | ImLoop(@ignoreForEquality de.peeeq.wurstscript.ast.Element trace, ImStmts body) | ImExitwhen(@ignoreForEquality de.peeeq.wurstscript.ast.Element trace, ImExpr condition) | ImReturn(@ignoreForEquality de.peeeq.wurstscript.ast.Element trace, ImExprOpt returnValue) - | ImSet(@ignoreForEquality de.peeeq.wurstscript.ast.Element trace, ref ImVar left, ImExpr right) - | ImSetTuple(@ignoreForEquality de.peeeq.wurstscript.ast.Element trace, ref ImVar left, int tupleIndex, ImExpr right) - | ImSetArray(@ignoreForEquality de.peeeq.wurstscript.ast.Element trace, ref ImVar left, ImExpr index, ImExpr right) - | ImSetArrayMulti(@ignoreForEquality de.peeeq.wurstscript.ast.Element trace, ref ImVar left, ImExprs indices, ImExpr right) - | ImSetArrayTuple(@ignoreForEquality de.peeeq.wurstscript.ast.Element trace, ref ImVar left, ImExpr index, int tupleIndex, ImExpr right) + | ImSet(@ignoreForEquality de.peeeq.wurstscript.ast.Element trace, ImLExpr left, ImExpr right) | ImExpr | ImVarargLoop(@ignoreForEquality de.peeeq.wurstscript.ast.Element trace, ImStmts body, ref ImVar loopVar) @@ -72,26 +67,29 @@ ImFlatExprOpt = ImExprs * ImExpr ImExpr = - ImStatementExpr(ImStmts statements, ImExpr expr) - | ImFlatExpr - -ImFlatExpr = ImCall - | ImVarAccess(ref ImVar var) - | ImVarArrayAccess(ref ImVar var, ImExpr index) - | ImVarArrayMultiAccess(ref ImVar var, ImExpr index1, ImExpr index2) - | ImTupleExpr(ImExprs exprs) - | ImTupleSelection(ImExpr tupleExpr, int tupleIndex) | ImClassRelatedExpr | ImConst | ImGetStackTrace() | ImCompiletimeExpr(@ignoreForEquality de.peeeq.wurstscript.ast.Element trace, ImExpr expr, int executionOrderIndex) - + | ImLExpr + +// an expression which can be used on the left hand side of an assignment +ImLExpr = + ImVarAccess(ref ImVar var) + | ImVarArrayAccess(@ignoreForEquality de.peeeq.wurstscript.ast.Element trace, ref ImVar var, ImExprs indexes) + | ImTupleSelection(ImExpr tupleExpr, int tupleIndex) // can only be used as L-value if tupleExpr is l-exprs + | ImMemberAccess + | ImTupleExpr(ImExprs exprs) // can only be used as L-value if exprs only contains l-exprs + | ImStatementExpr(ImStmts statements, ImExpr expr) // can only be used as L-value if expr only contains l-exprs + + + ImClassRelatedExpr = ImMethodCall(@ignoreForEquality de.peeeq.wurstscript.ast.Element trace, ref ImMethod method, ImExpr receiver, ImExprs arguments, boolean tuplesEliminated) | ImAlloc(ref ImClass clazz) | ImDealloc(ref ImClass clazz, ImExpr obj) - | ImMemberAccess(ImExpr receiver, ref ImVar var) + | ImMemberAccess(@ignoreForEquality de.peeeq.wurstscript.ast.Element trace, ImExpr receiver, ref ImVar var) | ImInstanceof(ImExpr obj, ref ImClass clazz) | ImTypeIdOfObj(ImExpr obj, ref ImClass clazz) | ImTypeIdOfClass(ref ImClass clazz) @@ -117,12 +115,10 @@ JassImElementWithName = ImVar | ImFunction | ImClass | ImMethod ElementWithTrace = ImVar | ImFunction | ImClass | ImMethod | ImIf | ImLoop | ImExitwhen | ImReturn | ImSet | ImSetTuple | ImSetArray | ImSetArrayMulti | ImSetArrayTuple - | ImMethodCall | ImFunctionCall | ImCompiletimeExpr + | ImMethodCall | ImFunctionCall | ImCompiletimeExpr | ImVarArrayAccess | ImMemberAccess ElementWithTypes = ImTupleType | ImTupleArrayType -ElementWithLeft = ImSet| ImSetTuple| ImSetArray| ImSetArrayMulti| ImSetArrayTuple - ElementWithVar = ImVarAccess | ImVarArrayAccess | ImVarArrayMultiAccess | ImMemberAccess @@ -160,41 +156,18 @@ ImStmt.flatten( ) returns de.peeeq.wurstscript.translation.imtranslation.Flatten.Result implemented by de.peeeq.wurstscript.translation.imtranslation.Flatten.flatten - -ImStmt.attrPurity + +ImLExpr.flattenL( + de.peeeq.wurstscript.translation.imtranslation.ImTranslator translator, + de.peeeq.wurstscript.jassIm.ImFunction f + ) + returns de.peeeq.wurstscript.translation.imtranslation.Flatten.ResultL + implemented by de.peeeq.wurstscript.translation.imtranslation.Flatten.flattenL + +ImStmt.attrPurity() returns de.peeeq.wurstscript.translation.imtranslation.purity.PurityLevel implemented by de.peeeq.wurstscript.translation.imtranslation.purity.PurityLevels.calculate -ImProg.eliminateTuples(de.peeeq.wurstscript.translation.imtranslation.ImTranslator translator) - returns void - implemented by de.peeeq.wurstscript.translation.imtranslation.EliminateTuples.eliminateTuplesProg - -ImFunction.eliminateTuples(de.peeeq.wurstscript.translation.imtranslation.ImTranslator translator) - returns void - implemented by de.peeeq.wurstscript.translation.imtranslation.EliminateTuples.eliminateTuplesFunc - -ImStmt.eliminateTuples( - de.peeeq.wurstscript.translation.imtranslation.ImTranslator translator, - de.peeeq.wurstscript.jassIm.ImFunction f - ) - returns ImStmt - implemented by de.peeeq.wurstscript.translation.imtranslation.EliminateTuples.eliminateTuples - -ImExpr.eliminateTuplesExpr( - de.peeeq.wurstscript.translation.imtranslation.ImTranslator translator, - de.peeeq.wurstscript.jassIm.ImFunction f - ) - returns ImExpr - implemented by de.peeeq.wurstscript.translation.imtranslation.EliminateTuples.eliminateTuplesExpr - -ImExprOpt.eliminateTuplesExprOpt( - de.peeeq.wurstscript.translation.imtranslation.ImTranslator translator, - de.peeeq.wurstscript.jassIm.ImFunction f - ) - returns ImExprOpt - implemented by de.peeeq.wurstscript.translation.imtranslation.EliminateTuples.eliminateTuplesExpr - - ImStmts.translate( java.util.List stmts, de.peeeq.wurstscript.jassAst.JassFunction f, @@ -221,7 +194,7 @@ ImConst.equalValue(ImConst other) returns boolean implemented by de.peeeq.wurstscript.translation.imtojass.Equality.equalValue -ImExpr.attrTyp +ImExpr.attrTyp() returns ImType implemented by de.peeeq.wurstscript.translation.imtojass.ImAttrType.getType @@ -237,7 +210,7 @@ ImType.translateType() returns String implemented by de.peeeq.wurstscript.translation.imtojass.ImAttributes.translateType -ImVar.isGlobal +ImVar.isGlobal() returns boolean implemented by de.peeeq.wurstscript.translation.imtojass.ImAttributes.isGlobal @@ -267,6 +240,13 @@ ImExpr.evaluate(de.peeeq.wurstscript.intermediatelang.interpreter.ProgramState g returns de.peeeq.wurstscript.intermediatelang.ILconst implemented by de.peeeq.wurstscript.intermediatelang.interpreter.EvaluateExpr.eval +ImLExpr.evaluateLvalue(de.peeeq.wurstscript.intermediatelang.interpreter.ProgramState globalState + , de.peeeq.wurstscript.intermediatelang.interpreter.LocalState localState) + returns de.peeeq.wurstscript.intermediatelang.ILaddress + implemented by de.peeeq.wurstscript.intermediatelang.interpreter.EvaluateExpr.evaluateLvalue + + + ImCompiletimeExpr.evaluationResult returns java.util.concurrent.atomic.AtomicReference implemented by de.peeeq.wurstscript.intermediatelang.interpreter.EvaluateExpr.compiletimeEvaluationResult @@ -352,5 +332,7 @@ ImProg.attrSubclasses returns com.google.common.collect.Multimap implemented by de.peeeq.wurstscript.translation.imtranslation.Subclasses.calculate - +ImLExpr.isUsedAsLValue() + returns boolean + implemented by de.peeeq.wurstscript.translation.imtranslation.LValues.isUsedAsLValue \ No newline at end of file diff --git a/de.peeeq.wurstscript/parserspec/wurstscript.parseq b/de.peeeq.wurstscript/parserspec/wurstscript.parseq index 504f165b2..9d4580952 100644 --- a/de.peeeq.wurstscript/parserspec/wurstscript.parseq +++ b/de.peeeq.wurstscript/parserspec/wurstscript.parseq @@ -129,7 +129,7 @@ WStatement = ActionStatement | ControlflowStatement | EndFunctionStatement(de.pe ActionStatement = StmtSkip(de.peeeq.wurstscript.parser.WPos source) | LocalVarDef - | StmtSet(de.peeeq.wurstscript.parser.WPos source, NameRef updatedExpr, Expr right) + | StmtSet(de.peeeq.wurstscript.parser.WPos source, LExpr updatedExpr, Expr right) | StmtCall | StmtErr(de.peeeq.wurstscript.parser.WPos source) | ExprMemberVar @@ -166,7 +166,7 @@ StmtForRange = | StmtForRangeDown(de.peeeq.wurstscript.parser.WPos source, LocalVarDef loopVar, Expr to, Expr step, WStatements body) Expr = - NameRef + LExpr | FunctionCall | ExprBinary(de.peeeq.wurstscript.parser.WPos source, Expr left, de.peeeq.wurstscript.WurstOperator op, Expr right) | ExprUnary(de.peeeq.wurstscript.parser.WPos source, de.peeeq.wurstscript.WurstOperator opU, Expr right) @@ -232,6 +232,9 @@ IdentifierWithTypeParamDefs(de.peeeq.wurstscript.parser.WPos source, Identifier // a reference to a variable, needs a varName:String attribute NameRef = ExprVarArrayAccess | ExprVarAccess | ExprMemberVar | ExprMemberArrayVar +// an expression that can be used on the left-hand side of an assignment +LExpr = NameRef + VarDef = GlobalOrLocalVarDef | WParameter @@ -433,7 +436,7 @@ FunctionCall.attrImplicitParameter returns OptExpr implemented by de.peeeq.wurstscript.attributes.AttrImplicitParameter.getImplicitParameter -NameRef.attrImplicitParameter +LExpr.attrImplicitParameter returns OptExpr implemented by de.peeeq.wurstscript.attributes.AttrImplicitParameter.getImplicitParameter @@ -712,6 +715,13 @@ StmtForEach.attrCloseFunc returns void implemented by de.peeeq.wurstscript.translation.imtranslation.TLDTranslation.translate + LExpr.imTranslateExprLvalue( + de.peeeq.wurstscript.translation.imtranslation.ImTranslator translator, + de.peeeq.wurstscript.jassIm.ImFunction f + ) + returns de.peeeq.wurstscript.jassIm.ImLExpr + implemented by de.peeeq.wurstscript.translation.imtranslation.ExprTranslation.translateLvalue + Expr.imTranslateExpr( de.peeeq.wurstscript.translation.imtranslation.ImTranslator translator, de.peeeq.wurstscript.jassIm.ImFunction f @@ -763,11 +773,11 @@ FunctionLike.attrHasEmptyBody() // Naming: -NameRef.attrNameLink +LExpr.attrNameLink returns de.peeeq.wurstscript.attributes.names.NameLink implemented by de.peeeq.wurstscript.attributes.AttrNameDef.calculate -NameRef.attrNameDef +LExpr.attrNameDef returns NameDef implemented by de.peeeq.wurstscript.attributes.AttrNameDef.calculateDef @@ -1017,7 +1027,7 @@ ExprNewObject.getTypeName() returns String implemented by de.peeeq.wurstscript.attributes.SmallHelpers.getTypeName -NameRef.getVarName() +LExpr.getVarName() returns String implemented by de.peeeq.wurstscript.attributes.SmallHelpers.getVarName diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/CompiletimeFunctionRunner.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/CompiletimeFunctionRunner.java index 8583f9b5d..1aef345cf 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/CompiletimeFunctionRunner.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/CompiletimeFunctionRunner.java @@ -255,7 +255,7 @@ private ImExpr constantToExprHashtable(ImCompiletimeExpr cte, Element trace, Arr WPos errorPos = trace.attrErrorPos(); ImFunction initHashtable = findNative("InitHashtable", errorPos); ImStmts stmts = JassIm.ImStmts( - JassIm.ImSet(trace, htVar, JassIm.ImFunctionCall(trace, initHashtable, JassIm.ImExprs(), false, CallType.NORMAL)) + JassIm.ImSet(trace, JassIm.ImVarAccess(htVar), JassIm.ImFunctionCall(trace, initHashtable, JassIm.ImExprs(), false, CallType.NORMAL)) ); // we have to collect all values after all compiletime functions have run, so use delayedActions diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/WurstCompilerJassImpl.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/WurstCompilerJassImpl.java index a62801d08..919d366b0 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/WurstCompilerJassImpl.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/WurstCompilerJassImpl.java @@ -394,8 +394,6 @@ public void checkProg(WurstModel model, List toCheck) { new EliminateClasses(imTranslator2, imProg2, !runArgs.isUncheckedDispatch()).eliminateClasses(); imTranslator2.assertProperties(); printDebugImProg("./test-output/im " + stage++ + "_classesEliminated.im"); - new MultiArrayEliminator(imProg2, imTranslator2).run(); - imTranslator2.assertProperties(); new VarargEliminator(imProg2).run(); printDebugImProg("./test-output/im " + stage++ + "_varargEliminated.im"); @@ -426,11 +424,15 @@ public void checkProg(WurstModel model, List toCheck) { // eliminate tuples beginPhase(6, "eliminate tuples"); getImProg().flatten(imTranslator2); - getImProg().eliminateTuples(imTranslator2); + EliminateTuples.eliminateTuplesProg(getImProg(), imTranslator2); getImTranslator().assertProperties(AssertProperty.NOTUPLES); printDebugImProg("./test-output/im " + stage++ + "_withouttuples.im"); + new MultiArrayEliminator(imProg2, imTranslator2).run(); + printDebugImProg("./test-output/im " + stage++ + "_withoutmultiarrays.im"); + imTranslator2.assertProperties(); + beginPhase(7, "remove func refs"); new FuncRefRemover(imProg2, imTranslator2).run(); @@ -469,10 +471,12 @@ public void checkProg(WurstModel model, List toCheck) { beginPhase(12, "froptimize"); optimizer.optimize(); + optimizer.removeGarbage(); + imProg.flatten(imTranslator); printDebugImProg("./test-output/im " + stage++ + "_afteroptimize.im"); } - optimizer.removeGarbage(); + // translate flattened intermediate lang to jass: diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/ILaddress.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/ILaddress.java new file mode 100644 index 000000000..2aa0ec192 --- /dev/null +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/ILaddress.java @@ -0,0 +1,9 @@ +package de.peeeq.wurstscript.intermediatelang; + +/** + * + */ +public interface ILaddress { + void set(ILconst value); + ILconst get(); +} diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/ILconstArray.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/ILconstArray.java new file mode 100644 index 000000000..91f00a91c --- /dev/null +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/ILconstArray.java @@ -0,0 +1,49 @@ +package de.peeeq.wurstscript.intermediatelang; + +import de.peeeq.wurstscript.types.WurstType; +import de.peeeq.wurstscript.types.WurstTypeString; + +import java.util.Map; +import java.util.TreeMap; +import java.util.function.Supplier; + +public class ILconstArray extends ILconstAbstract { + + private final Map values = new TreeMap<>(); // including the quotes + private final Supplier defaultValue; + + public ILconstArray(Supplier defaultValue) { + this.defaultValue = defaultValue; + } + + @Override + public String print() { + StringBuilder s = new StringBuilder(); + s.append("["); + for (Map.Entry e : values.entrySet()) { + if (s.length() > 1) { + s.append(", "); + } + s.append(e.getKey()); + s.append(": "); + s.append(e.getValue()); + } + s.append("]"); + return s.toString(); + } + + + @Override + public boolean isEqualTo(ILconst other) { + return other == this; + } + + public void set(int index, ILconst value) { + values.put(index, value); + } + + public ILconst get(int index) { + return values.computeIfAbsent(index, i -> defaultValue.get()); + } + +} diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/ILconstTuple.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/ILconstTuple.java index cc9fa9746..36a237397 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/ILconstTuple.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/ILconstTuple.java @@ -13,14 +13,7 @@ public class ILconstTuple extends ILconstAbstract { private final ILconst[] values; public ILconstTuple(ILconst... values) { - this.values = Arrays.stream(values) - .flatMap(c -> { - if (c instanceof ILconstTuple) { - return Arrays.stream(((ILconstTuple) c).values); - } else { - return Stream.of(c); - } - }).toArray(ILconst[]::new); + this.values = values; } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/interpreter/EvaluateExpr.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/interpreter/EvaluateExpr.java index 08b804d4c..35904afcb 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/interpreter/EvaluateExpr.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/interpreter/EvaluateExpr.java @@ -1,7 +1,6 @@ package de.peeeq.wurstscript.intermediatelang.interpreter; import com.google.common.collect.Lists; -import de.peeeq.datastructures.IntTuple; import de.peeeq.wurstio.jassinterpreter.InterpreterException; import de.peeeq.wurstscript.WLogger; import de.peeeq.wurstscript.WurstOperator; @@ -10,11 +9,14 @@ import de.peeeq.wurstscript.ast.WPackage; import de.peeeq.wurstscript.intermediatelang.*; import de.peeeq.wurstscript.jassIm.*; +import de.peeeq.wurstscript.translation.imtranslation.ImPrinter; import org.eclipse.jdt.annotation.Nullable; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; public class EvaluateExpr { @@ -71,6 +73,11 @@ public static ILconst eval(ImStatementExpr e, ProgramState globalState, LocalSta return e.getExpr().evaluate(globalState, localState); } + public static ILaddress evaluateLvalue(ImStatementExpr e, ProgramState globalState, LocalState localState) { + e.getStatements().runStatements(globalState, localState); + return ((ImLExpr) e.getExpr()).evaluateLvalue(globalState, localState); + } + public static ILconst eval(ImStringVal e, ProgramState globalState, LocalState localState) { return new ILconstString(e.getValS()); } @@ -111,7 +118,7 @@ public static ILconst eval(ImVarAccess e, ProgramState globalState, LocalState l } return r; } else { - return notNull(localState.getVal(var), var.getType(), "Local variable " + var.getName() + " is null.", true); + return notNull(localState.getVal(var), var.getType(), "Local variable " + var + " is null.", true); } } @@ -144,11 +151,14 @@ private static ILconst notNull(@Nullable ILconst val, ImType imType, String msg, } public static ILconst eval(ImVarArrayAccess e, ProgramState globalState, LocalState localState) { - ILconstInt index = (ILconstInt) e.getIndex().evaluate(globalState, localState); + List indexes = e.getIndexes().stream() + .map(ie -> ((ILconstInt) ie.evaluate(globalState, localState)).getVal()) + .collect(Collectors.toList()); + if (e.getVar().isGlobal()) { - return notNull(globalState.getArrayVal(e.getVar(), index.getVal()), e.getVar().getType(), "Variable " + e.getVar().getName() + " is null.", false); + return notNull(globalState.getArrayVal(e.getVar(), indexes), e.getVar().getType(), "Variable " + e.getVar().getName() + " is null.", false); } else { - return notNull(localState.getArrayVal(e.getVar(), index.getVal()), e.getVar().getType(), "Variable " + e.getVar().getName() + " is null.", false); + return notNull(localState.getArrayVal(e.getVar(), indexes), e.getVar().getType(), "Variable " + e.getVar().getName() + " is null.", false); } } @@ -184,7 +194,7 @@ public static ILconst eval(ImMemberAccess ma, ProgramState globalState, LocalSta if (receiver.getVal() == 0) { throw new RuntimeException("Null pointer dereference"); } - return notNull(globalState.getArrayVal(ma.getVar(), receiver.getVal()), ma.getVar().getType(), "Variable " + ma.getVar().getName() + " is null.", false); + return notNull(globalState.getArrayVal(ma.getVar(), Collections.singletonList(receiver.getVal())), ma.getVar().getType(), "Variable " + ma.getVar().getName() + " is null.", false); } public static ILconst eval(ImAlloc imAlloc, ProgramState globalState, @@ -216,31 +226,6 @@ public static ILconst eval(ImTypeIdOfObj e, return new ILconstInt(globalState.getTypeId(obj.getVal(), e.attrTrace())); } - public static ILconst eval(ImVarArrayMultiAccess s, - ProgramState globalState, LocalState localState) { - ImVar v = s.getVar(); - int[] indices = { - ((ILconstInt) s.getIndex1().evaluate(globalState, localState)).getVal(), - ((ILconstInt) s.getIndex2().evaluate(globalState, localState)).getVal() - }; - - IntTuple indicesT = IntTuple.of(indices); - ILconstMultiArray ar; - if (v.isGlobal()) { - ar = (ILconstMultiArray) globalState.getArrayVal(v, indicesT.head()); - if (ar == null) { - ar = new ILconstMultiArray(); - globalState.setArrayVal(v, indicesT.head(), ar); - } - } else { - ar = (ILconstMultiArray) localState.getArrayVal(v, indicesT.head()); - if (ar == null) { - ar = new ILconstMultiArray(); - globalState.setArrayVal(v, indicesT.head(), ar); - } - } - return ar.get(indicesT.tail()); - } public static ILconst eval(ImGetStackTrace e, ProgramState globalState, LocalState localState) { @@ -262,4 +247,112 @@ public static ILconst eval(ImCompiletimeExpr expr, ProgramState globalState, Loc public static AtomicReference compiletimeEvaluationResult(ImCompiletimeExpr imCompiletimeExpr) { return new AtomicReference<>(); } + + public static ILaddress evaluateLvalue(ImVarAccess va, ProgramState globalState, LocalState localState) { + ImVar v = va.getVar(); + State state; + state = v.isGlobal() ? globalState : localState; + return new ILaddress() { + @Override + public void set(ILconst value) { + state.setVal(v, value); + } + + @Override + public ILconst get() { + return state.getVal(v); + } + }; + } + + + public static ILaddress evaluateLvalue(ImVarArrayAccess va, ProgramState globalState, LocalState localState) { + ImVar v = va.getVar(); + State state; + state = v.isGlobal() ? globalState : localState; + List indexes = va.getIndexes().stream() + .map(ie -> ((ILconstInt) ie.evaluate(globalState, localState)).getVal()) + .collect(Collectors.toList()); + return new ILaddress() { + @Override + public void set(ILconst value) { + state.setArrayVal(v, indexes, value); + } + + @Override + public ILconst get() { + return state.getArrayVal(v, indexes); + } + }; + } + + public static ILaddress evaluateLvalue(ImTupleSelection ts, ProgramState globalState, LocalState localState) { + ImExpr tupleExpr = ts.getTupleExpr(); + int tupleIndex = ts.getTupleIndex(); + if (tupleExpr instanceof ImLExpr) { + ILaddress addr = ((ImLExpr) tupleExpr).evaluateLvalue(globalState, localState); + return new ILaddress() { + @Override + public void set(ILconst value) { + ILconst val = addr.get(); + ILconstTuple tuple = (ILconstTuple) val; + ILconstTuple updated = tuple.updated(tupleIndex, value); + addr.set(updated); + } + + @Override + public ILconst get() { + ILconstTuple tuple = (ILconstTuple) addr.get(); + return tuple.getValue(tupleIndex); + } + }; + } else { + ILconstTuple tupleValue = (ILconstTuple) tupleExpr.evaluate(globalState, localState); + return new ILaddress() { + @Override + public void set(ILconst value) { + throw new InterpreterException(ts.attrTrace(), "Not a valid L-value in tuple-selection"); + } + + @Override + public ILconst get() { + return tupleValue.getValue(tupleIndex); + } + }; + } + } + + public static ILaddress evaluateLvalue(ImMemberAccess e, ProgramState globalState, LocalState localState) { + ILconst r = e.getReceiver().evaluate(globalState, localState); + throw new InterpreterException(e.attrTrace(), "Cannot evaluate " + r); + } + + + public static ILaddress evaluateLvalue(ImTupleExpr e, ProgramState globalState, LocalState localState) { + List addresses = new ArrayList<>(); + for (ImExpr lexpr : e.getExprs()) { + ILaddress addr = ((ImLExpr) lexpr).evaluateLvalue(globalState, localState); + addresses.add(addr); + } + return new ILaddress() { + @Override + public void set(ILconst value) { + if (value instanceof ILconstTuple) { + ILconstTuple te = (ILconstTuple) value; + for (int i = 0; i < addresses.size(); i++) { + addresses.get(i).set(te.getValue(i)); + } + } + } + + @Override + public ILconst get() { + return new ILconstTuple(addresses.stream() + .map(ILaddress::get) + .toArray(ILconst[]::new)); + } + }; + } + + } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/interpreter/ProgramState.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/interpreter/ProgramState.java index 470d8b3fc..91d2371ea 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/interpreter/ProgramState.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/interpreter/ProgramState.java @@ -8,11 +8,11 @@ import de.peeeq.wurstscript.attributes.CompileError; import de.peeeq.wurstscript.gui.WurstGui; import de.peeeq.wurstscript.intermediatelang.ILconst; +import de.peeeq.wurstscript.intermediatelang.ILconstArray; import de.peeeq.wurstscript.jassIm.*; import de.peeeq.wurstscript.parser.WPos; import de.peeeq.wurstscript.utils.LineOffsets; import de.peeeq.wurstscript.utils.Utils; -import org.eclipse.jdt.annotation.Nullable; import java.io.PrintStream; import java.util.*; @@ -234,17 +234,17 @@ public boolean isCompiletime() { return isCompiletime; } - protected Map getArray(ImVar v) { - Map r = arrayValues.get(v); + protected ILconstArray getArray(ImVar v) { + ILconstArray r = arrayValues.get(v); if (r == null) { - r = Maps.newLinkedHashMap(); + r = new ILconstArray(v.getType()::defaultValue); arrayValues.put(v, r); List e = prog.getGlobalInits().get(v); if (e != null) { LocalState ls = new LocalState(); for (int i = 0; i < e.size(); i++) { ILconst val = e.get(i).evaluate(this, ls); - r.put(i, val); + r.set(i, val); } } } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/interpreter/RunStatement.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/interpreter/RunStatement.java index 6ac6ad427..73ebdb506 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/interpreter/RunStatement.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/interpreter/RunStatement.java @@ -8,6 +8,7 @@ import de.peeeq.wurstscript.jassIm.*; import de.peeeq.wurstscript.jassinterpreter.ExitwhenException; import de.peeeq.wurstscript.jassinterpreter.ReturnException; +import de.peeeq.wurstscript.translation.imtojass.DefaultValue; public class RunStatement { @@ -56,94 +57,11 @@ public static void run(ImReturn s, ProgramState globalState, LocalState localSta } public static void run(ImSet s, ProgramState globalState, LocalState localState) { - ImVar v = s.getLeft(); + ILaddress v = s.getLeft().evaluateLvalue(globalState, localState); ILconst right = s.getRight().evaluate(globalState, localState); - if (v.isGlobal()) { - globalState.setVal(v, right); - } else { - localState.setVal(v, right); - } - } - - public static void run(ImSetArray s, ProgramState globalState, LocalState localState) { - ImVar v = s.getLeft(); - ILconstInt index = (ILconstInt) s.getIndex().evaluate(globalState, localState); - ILconst right = s.getRight().evaluate(globalState, localState); - if (v.isGlobal()) { - globalState.setArrayVal(v, index.getVal(), right); - } else { - localState.setArrayVal(v, index.getVal(), right); - } - } - - public static void run(ImSetArrayTuple s, ProgramState globalState, LocalState localState) { - ImVar v = s.getLeft(); - ILconstInt index = (ILconstInt) s.getIndex().evaluate(globalState, localState); - ILconst right = s.getRight().evaluate(globalState, localState); - if (v.isGlobal()) { - ILconstTuple oldVal = (ILconstTuple) globalState.getArrayVal(v, index.getVal()); - if (oldVal == null) { - throw new Error("Tuple not initialized"); - } - ILconstTuple newVal = oldVal.updated(s.getTupleIndex(), right); - globalState.setArrayVal(v, index.getVal(), newVal); - } else { - ILconstTuple oldVal = (ILconstTuple) localState.getArrayVal(v, index.getVal()); - if (oldVal == null) { - throw new Error("Tuple not initialized"); - } - ILconstTuple newVal = oldVal.updated(s.getTupleIndex(), right); - localState.setArrayVal(v, index.getVal(), newVal); - } - } - - public static void run(ImSetArrayMulti s, ProgramState globalState, LocalState localState) { - ImVar v = s.getLeft(); - int[] indices = new int[s.getIndices().size()]; - - for (int i = 0; i < indices.length; i++) { - ILconstInt index = (ILconstInt) s.getIndices().get(i).evaluate(globalState, localState); - indices[i] = index.getVal(); - } - IntTuple indicesT = IntTuple.of(indices); - ILconst right = s.getRight().evaluate(globalState, localState); - ILconstMultiArray ar; - if (v.isGlobal()) { - ar = (ILconstMultiArray) globalState.getArrayVal(v, indicesT.head()); - if (ar == null) { - ar = new ILconstMultiArray(); - globalState.setArrayVal(v, indicesT.head(), ar); - } - } else { - ar = (ILconstMultiArray) localState.getArrayVal(v, indicesT.head()); - if (ar == null) { - ar = new ILconstMultiArray(); - globalState.setArrayVal(v, indicesT.head(), ar); - } - } - ar.set(indicesT.tail(), right); + v.set(right); } - public static void run(ImSetTuple s, ProgramState globalState, LocalState localState) { - ImVar v = s.getLeft(); - ILconst right = s.getRight().evaluate(globalState, localState); - if (v.isGlobal()) { - ILconstTuple oldVal = (ILconstTuple) globalState.getVal(v); - if (oldVal == null) { - throw new Error("Tuple not initialized"); - } - ILconstTuple newVal = oldVal.updated(s.getTupleIndex(), right); - globalState.setVal(v, newVal); - } else { - ILconstTuple oldVal = (ILconstTuple) localState.getVal(v); - if (oldVal == null) { - throw new Error("Tuple not initialized"); - } - ILconstTuple newVal = oldVal.updated(s.getTupleIndex(), right); - localState.setVal(v, newVal); - } - - } public static void run(ImStmts stmts, ProgramState globalState, LocalState localState) { for (ImStmt s : stmts) { diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/interpreter/State.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/interpreter/State.java index ca9af0ca2..404f294c3 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/interpreter/State.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/interpreter/State.java @@ -2,16 +2,18 @@ import com.google.common.collect.Maps; import de.peeeq.wurstscript.intermediatelang.ILconst; +import de.peeeq.wurstscript.intermediatelang.ILconstArray; import de.peeeq.wurstscript.jassIm.ImVar; import org.eclipse.jdt.annotation.Nullable; +import java.util.List; import java.util.Map; import java.util.Map.Entry; public abstract class State { private Map values = Maps.newLinkedHashMap(); - protected Map> arrayValues = Maps.newLinkedHashMap(); + protected Map arrayValues = Maps.newLinkedHashMap(); public void setVal(ImVar v, ILconst val) { @@ -22,16 +24,24 @@ public void setVal(ImVar v, ILconst val) { return values.get(v); } - protected Map getArray(ImVar v) { - return arrayValues.computeIfAbsent(v, k -> Maps.newLinkedHashMap()); + protected ILconstArray getArray(ImVar v) { + return arrayValues.computeIfAbsent(v, k -> new ILconstArray(() -> v.getType().defaultValue())); } - public void setArrayVal(ImVar v, int index, ILconst val) { - getArray(v).put(index, val); + public void setArrayVal(ImVar v, List indexes, ILconst val) { + ILconstArray ar = getArray(v); + for (int i = 0; i < indexes.size() - 1; i++) { + ar = (ILconstArray) ar.get(indexes.get(i)); + } + ar.set(indexes.get(indexes.size() - 1), val); } - public @Nullable ILconst getArrayVal(ImVar v, int index) { - return getArray(v).get(index); + public @Nullable ILconst getArrayVal(ImVar v, List indexes) { + ILconstArray ar = getArray(v); + for (int i = 0; i < indexes.size() - 1; i++) { + ar = (ILconstArray) ar.get(indexes.get(i)); + } + return ar.get(indexes.get(indexes.size() - 1)); } public @Nullable ILconst getVarValue(String varName) { diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/ConstantAndCopyPropagation.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/ConstantAndCopyPropagation.java index f26494565..dc0ee6435 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/ConstantAndCopyPropagation.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/ConstantAndCopyPropagation.java @@ -100,9 +100,27 @@ private void rewriteCode(ControlFlowGraph cfg, Map knowledge) { } Knowledge kn = knowledge.get(node); stmt.accept(new ImStmt.DefaultVisitor() { + + @Override + public void visit(ImSet imSet) { + ImLExpr e = imSet.getLeft(); + if (e instanceof ImMemberAccess) { + ImMemberAccess ma = (ImMemberAccess) e; + ma.accept(this); + } else if (e instanceof ImVarArrayAccess) { + ImVarArrayAccess vaa = (ImVarArrayAccess) e; + for (ImExpr ie : vaa.getIndexes()) { + ie.accept(this); + } + } + imSet.getRight().accept(this); + } + @Override public void visit(ImVarAccess va) { - super.visit(va); + if (va.isUsedAsLValue()) { + return; + } Value val = kn.varKnowledge.get(va.getVar()); if (val == null) { return; @@ -119,6 +137,7 @@ public void visit(ImVarAccess va) { }); } + } private Map calculateKnowledge(ControlFlowGraph cfg) { @@ -165,30 +184,32 @@ private Map calculateKnowledge(ControlFlowGraph cfg) { ImStmt stmt = n.getStmt(); if (stmt instanceof ImSet) { ImSet imSet = (ImSet) stmt; - ImVar var = imSet.getLeft(); - if (!var.isGlobal()) { - Value newValue = null; - if (imSet.getRight() instanceof ImConst) { - ImConst imConst = (ImConst) imSet.getRight(); - newValue = new Value(imConst); - } else if (imSet.getRight() instanceof ImVarAccess) { - ImVarAccess imVarAccess = (ImVarAccess) imSet.getRight(); - if (!imVarAccess.getVar().isGlobal()) { - newValue = new Value(imVarAccess.getVar()); + if (imSet.getLeft() instanceof ImVarAccess) { + ImVar var = ((ImVarAccess) imSet.getLeft()).getVar(); + if (!var.isGlobal()) { + Value newValue = null; + if (imSet.getRight() instanceof ImConst) { + ImConst imConst = (ImConst) imSet.getRight(); + newValue = new Value(imConst); + } else if (imSet.getRight() instanceof ImVarAccess) { + ImVarAccess imVarAccess = (ImVarAccess) imSet.getRight(); + if (!imVarAccess.getVar().isGlobal()) { + newValue = new Value(imVarAccess.getVar()); + } } + if (newValue == null) { + // invalidate old value + newOut.remove(var); + } else { + newOut.put(var, newValue); + } + // invalidate copies of the lhs + // for example: + // x = a; [x->a] + // y = b; [x->a, y->b] + // a = 5; [y->b, a->5] // here [x->a] has been invalidated + newOut.entrySet().removeIf(entry -> entry.getValue().equalValue(new Value(var))); } - if (newValue == null) { - // invalidate old value - newOut.remove(var); - } else { - newOut.put(var, newValue); - } - // invalidate copies of the lhs - // for example: - // x = a; [x->a] - // y = b; [x->a, y->b] - // a = 5; [y->b, a->5] // here [x->a] has been invalidated - newOut.entrySet().removeIf(entry -> entry.getValue().equalValue(new Value(var))); } } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/LocalMerger.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/LocalMerger.java index 8b3f9cdf4..d4a2a4749 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/LocalMerger.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/LocalMerger.java @@ -96,9 +96,11 @@ public void visit(ImVarAccess va) { @Override public void visit(ImSet set) { super.visit(set); - ImVar v = set.getLeft(); - if (merges.containsKey(v)) { - set.setLeft(merges.get(v)); + if (set.getLeft() instanceof ImVarAccess) { + ImVar v = ((ImVarAccess) set.getLeft()).getVar(); + if (merges.containsKey(v)) { + set.setLeft(JassIm.ImVarAccess(merges.get(v))); + } } } }); @@ -123,10 +125,16 @@ private void eliminateDeadCode(Map> livenessInfo) { for (ImStmt s : livenessInfo.keySet()) { if (s instanceof ImSet) { ImSet imSet = (ImSet) s; - if (imSet.getLeft().isGlobal()) { + if (!(imSet.getLeft() instanceof ImVarAccess)) { continue; } - if (!livenessInfo.get(s).contains(imSet.getLeft())) { + ImVarAccess va = (ImVarAccess) imSet.getLeft(); + ImVar v = va.getVar(); + if (v.isGlobal()) { + continue; + } + + if (!livenessInfo.get(s).contains(v)) { // write to a variable which is not live // --> only keep side effects ImExpr right = imSet.getRight(); @@ -227,8 +235,11 @@ private Multimap calculateDefs(List nodes) { ImStmt stmt = node.getStmt(); if (stmt instanceof ImSet) { ImSet imSet = (ImSet) stmt; - if (!imSet.getLeft().isGlobal()) { - result.put(node, imSet.getLeft()); + if (imSet.getLeft() instanceof ImVarAccess) { + ImVar v = ((ImVarAccess) imSet.getLeft()).getVar(); + if (!v.isGlobal()) { + result.put(node, v); + } } } } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/SideEffectAnalyzer.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/SideEffectAnalyzer.java index 21a8a5ff3..03a2f7941 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/SideEffectAnalyzer.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/SideEffectAnalyzer.java @@ -6,6 +6,7 @@ import de.peeeq.wurstscript.jassIm.*; import de.peeeq.wurstscript.utils.Utils; +import java.util.Collection; import java.util.LinkedHashSet; import java.util.Set; import java.util.stream.Collectors; @@ -28,6 +29,124 @@ public SideEffectAnalyzer(ImProg prog) { this.prog = prog; } + /** + * checks if this expression might have side effects + * (does not do a deep analysis, all function calls and statements are considered to have side effects) + */ + public static boolean quickcheckHasSideeffects(ImExpr expr) { + return expr.match(new ImExpr.Matcher() { + @Override + public Boolean case_ImFunctionCall(ImFunctionCall imFunctionCall) { + return true; + } + + @Override + public Boolean case_ImTypeIdOfClass(ImTypeIdOfClass imTypeIdOfClass) { + return false; + } + + @Override + public Boolean case_ImVarArrayAccess(ImVarArrayAccess e) { + return e.getIndexes().stream().anyMatch(SideEffectAnalyzer::quickcheckHasSideeffects); + } + + @Override + public Boolean case_ImRealVal(ImRealVal imRealVal) { + return false; + } + + @Override + public Boolean case_ImTupleSelection(ImTupleSelection e) { + return quickcheckHasSideeffects(e.getTupleExpr()); + } + + @Override + public Boolean case_ImInstanceof(ImInstanceof e) { + return quickcheckHasSideeffects(e.getObj()); + } + + @Override + public Boolean case_ImDealloc(ImDealloc imDealloc) { + return true; + } + + @Override + public Boolean case_ImMemberAccess(ImMemberAccess e) { + return quickcheckHasSideeffects(e.getReceiver()); + } + + @Override + public Boolean case_ImBoolVal(ImBoolVal imBoolVal) { + return false; + } + + @Override + public Boolean case_ImTupleExpr(ImTupleExpr e) { + return e.getExprs().stream().anyMatch(SideEffectAnalyzer::quickcheckHasSideeffects); + } + + @Override + public Boolean case_ImNull(ImNull imNull) { + return false; + } + + @Override + public Boolean case_ImGetStackTrace(ImGetStackTrace imGetStackTrace) { + return true; + } + + @Override + public Boolean case_ImOperatorCall(ImOperatorCall e) { + return e.getArguments().stream().anyMatch(SideEffectAnalyzer::quickcheckHasSideeffects); + } + + @Override + public Boolean case_ImStringVal(ImStringVal imStringVal) { + return false; + } + + @Override + public Boolean case_ImMethodCall(ImMethodCall imMethodCall) { + return true; + } + + @Override + public Boolean case_ImAlloc(ImAlloc imAlloc) { + return true; + } + + @Override + public Boolean case_ImCompiletimeExpr(ImCompiletimeExpr imCompiletimeExpr) { + return true; + } + + @Override + public Boolean case_ImTypeIdOfObj(ImTypeIdOfObj e) { + return quickcheckHasSideeffects(e.getObj()); + } + + @Override + public Boolean case_ImVarAccess(ImVarAccess imVarAccess) { + return false; + } + + @Override + public Boolean case_ImIntVal(ImIntVal imIntVal) { + return false; + } + + @Override + public Boolean case_ImFuncRef(ImFuncRef imFuncRef) { + return false; + } + + @Override + public Boolean case_ImStatementExpr(ImStatementExpr imStatementExpr) { + return true; + } + }); + } + /** * @return f -> set of functions directly called by f */ @@ -146,45 +265,66 @@ public void visit(ImVarArrayAccess va) { } @Override - public void visit(ImVarArrayMultiAccess va) { + public void visit(ImMemberAccess va) { super.visit(va); imVars.add(va.getVar()); } @Override - public void visit(ImMemberAccess va) { + public void visit(ImSet va) { super.visit(va); - imVars.add(va.getVar()); + ImLExpr assignable = va.getLeft(); + collectVars(imVars, assignable); + } @Override - public void visit(ImSet va) { + public void visit(ImVarargLoop va) { super.visit(va); - imVars.add(va.getLeft()); + imVars.add(va.getLoopVar()); } + }); + return imVars; + } + + private void collectVars(Collection imVars, ImLExpr assignable) { + assignable.match(new ImLExpr.MatcherVoid() { @Override - public void visit(ImSetTuple va) { - super.visit(va); - imVars.add(va.getLeft()); + public void case_ImVarAccess(ImVarAccess v) { + imVars.add(v.getVar()); } @Override - public void visit(ImSetArrayTuple va) { - super.visit(va); - imVars.add(va.getLeft()); + public void case_ImStatementExpr(ImStatementExpr imStatementExpr) { + throw new RuntimeException("TODO"); // TODO } @Override - public void visit(ImVarargLoop va) { - super.visit(va); - imVars.add(va.getLoopVar()); + public void case_ImTupleSelection(ImTupleSelection v) { + collectVars(imVars, (ImLExpr) v.getTupleExpr()); + } + + @Override + public void case_ImVarArrayAccess(ImVarArrayAccess v) { + imVars.add(v.getVar()); + } + + @Override + public void case_ImMemberAccess(ImMemberAccess v) { + throw new RuntimeException("Should run after objects"); } + @Override + public void case_ImTupleExpr(ImTupleExpr te) { + for (ImExpr e : te.getExprs()) { + ((ImLExpr) e).match(this); + } + } }); - return imVars; } + /** * Variables directly used in e */ @@ -204,12 +344,6 @@ public void visit(ImVarArrayAccess va) { imVars.add(va.getVar()); } - @Override - public void visit(ImVarArrayMultiAccess va) { - super.visit(va); - imVars.add(va.getVar()); - } - @Override public void visit(ImMemberAccess va) { super.visit(va); @@ -230,19 +364,7 @@ public Set directlySetVariables(Element e) { @Override public void visit(ImSet va) { super.visit(va); - imVars.add(va.getLeft()); - } - - @Override - public void visit(ImSetTuple va) { - super.visit(va); - imVars.add(va.getLeft()); - } - - @Override - public void visit(ImSetArrayTuple va) { - super.visit(va); - imVars.add(va.getLeft()); + collectVars(imVars, va.getLeft()); } @Override diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/SimpleRewrites.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/SimpleRewrites.java index dae74f48a..bc15bb27e 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/SimpleRewrites.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/SimpleRewrites.java @@ -571,8 +571,18 @@ private void optimizeIf(ImIf imIf) { * like code that is created by the branch merger */ private void optimizeConsecutiveSet(ImSet imSet1, ImSet imSet2) { - ImVar leftVar1 = imSet1.getLeft(); - ImVar leftVar2 = imSet2.getLeft(); + ImVar leftVar1; + if (imSet1.getLeft() instanceof ImVarAccess) { + leftVar1 = ((ImVarAccess) imSet1.getLeft()).getVar(); + } else { + return; + } + ImVar leftVar2; + if (imSet2.getLeft() instanceof ImVarAccess) { + leftVar2 = ((ImVarAccess) imSet2.getLeft()).getVar(); + } else { + return; + } ImExpr rightExpr1 = imSet1.getRight(); ImExpr rightExpr2 = imSet2.getRight(); diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/TempMerger.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/TempMerger.java index 65c5ee705..4f0c1e86b 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/TempMerger.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/TempMerger.java @@ -1,5 +1,6 @@ package de.peeeq.wurstscript.intermediatelang.optimizer; +import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import de.peeeq.wurstscript.jassIm.*; @@ -56,9 +57,11 @@ private void optimizeStatements(ImStmts stmts) { for (ImStmt s : stmts) { if (s instanceof ImSet) { ImSet imSet = (ImSet) s; - if (imSet.getRight() instanceof ImVarAccess) { + if (imSet.getRight() instanceof ImVarAccess + && imSet.getLeft() instanceof ImVarAccess) { ImVarAccess right = (ImVarAccess) imSet.getRight(); - if (imSet.getLeft() == right.getVar()) { + ImVarAccess left = (ImVarAccess) imSet.getLeft(); + if (left.getVar() == right.getVar()) { // statement has the form 'x = x' so remove it totalMerged++; imSet.replaceBy(JassIm.ImNull()); @@ -103,10 +106,14 @@ private void optimizeStatements(ImStmts stmts) { } if (s instanceof ImSet) { ImSet imSet = (ImSet) s; - // update the knowledge with the new set statement - kn.update(imSet.getLeft(), imSet); - } else if (s instanceof ImSetArray) { - kn.invalidateVar(((ImSetArray) s).getLeft()); + if (imSet.getLeft() instanceof ImVarRead) { + ImVarRead va = (ImVarRead) imSet.getLeft(); + // update the knowledge with the new set statement + kn.update(va.getVar(), imSet); + } else if (imSet.getLeft() instanceof ImVarArrayAccess) { + ImVarArrayAccess va = (ImVarArrayAccess) imSet.getLeft(); + kn.invalidateVar(va.getVar()); + } } else if (s instanceof ImExitwhen || s instanceof ImIf || s instanceof ImLoop) { kn.clear(); // TODO this could be more precise for local variables, @@ -121,7 +128,9 @@ private void optimizeStatements(ImStmts stmts) { } if (elem instanceof ImVarAccess) { ImVarAccess va = (ImVarAccess) elem; - return kn.getReplacementIfPossible(va); + if (!va.isUsedAsLValue()) { + return kn.getReplacementIfPossible(va); + } } else if (elem instanceof ImLoop) { return null; } else if (elem instanceof ImIf) { @@ -224,6 +233,7 @@ class Replacement { public final ImVarAccess read; public Replacement(ImSet set, ImVarAccess read) { + Preconditions.checkArgument(set.getLeft() instanceof ImVarAccess); this.set = set; this.read = read; } @@ -235,7 +245,7 @@ public String toString() { public void apply() { ImExpr e = set.getRight(); - if (set.getLeft().attrReads().size() <= 1) { + if (getAssignedVar().attrReads().size() <= 1) { // make sure that an impure expression is only evaluated once // by removing the assignment set.replaceBy(JassIm.ImNull()); @@ -249,7 +259,7 @@ public void apply() { ImExpr newE = (ImExpr) e.copy(); read.replaceBy(newE); // update attrReads: - set.getLeft().attrReads().remove(read); + getAssignedVar().attrReads().remove(read); // for all the variables in e: add to read for (ImVarRead r : readVariables(newE)) { @@ -258,6 +268,10 @@ public void apply() { } + private ImVar getAssignedVar() { + return ((ImVarAccess) set.getLeft()).getVar(); + } + } private Collection readVariables(Element e) { diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/lua/translation/ExprTranslation.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/lua/translation/ExprTranslation.java index 84f82bea4..72bbf4b12 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/lua/translation/ExprTranslation.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/lua/translation/ExprTranslation.java @@ -155,16 +155,11 @@ public static LuaExpr translate(ImVarAccess e, LuaTranslator tr) { return LuaAst.LuaExprVarAccess(tr.luaVar.getFor(e.getVar())); } - public static LuaExpr translate(ImVarArrayMultiAccess e, LuaTranslator tr) { - LuaExprlist indexes = LuaAst.LuaExprlist(); - indexes.add(e.getIndex1().translateToLua(tr)); - indexes.add(e.getIndex2().translateToLua(tr)); - return LuaAst.LuaExprArrayAccess(LuaAst.LuaExprVarAccess(tr.luaVar.getFor(e.getVar())), indexes); - } - public static LuaExpr translate(ImVarArrayAccess e, LuaTranslator tr) { LuaExprlist indexes = LuaAst.LuaExprlist(); - indexes.add(e.getIndex().translateToLua(tr)); + for (ImExpr ie : e.getIndexes()) { + indexes.add(ie.translateToLua(tr)); + } return LuaAst.LuaExprArrayAccess(LuaAst.LuaExprVarAccess(tr.luaVar.getFor(e.getVar())), indexes); } @@ -175,4 +170,5 @@ public static LuaExpr translate(ImGetStackTrace e, LuaTranslator tr) { public static LuaExpr translate(ImCompiletimeExpr imCompiletimeExpr, LuaTranslator tr) { throw new Error("not implemented"); } + } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/lua/translation/LuaTranslator.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/lua/translation/LuaTranslator.java index 224db96d3..3a2739658 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/lua/translation/LuaTranslator.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/lua/translation/LuaTranslator.java @@ -136,8 +136,7 @@ private void translateClass(ImClass c) { private void translateGlobal(ImVar v) { LuaVariable lv = luaVar.getFor(v); if (v.getType() instanceof ImArrayType - || v.getType() instanceof ImArrayTypeMulti - || v.getType() instanceof ImTupleArrayType) { + || v.getType() instanceof ImArrayTypeMulti) { lv.setInitialValue(LuaAst.LuaTableConstructor(LuaAst.LuaTableFields())); } luaModel.add(lv); diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/lua/translation/StmtTranslation.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/lua/translation/StmtTranslation.java index 20572ed36..91f4b819e 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/lua/translation/StmtTranslation.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/lua/translation/StmtTranslation.java @@ -37,34 +37,12 @@ public static void translate(ImReturn s, List res, LuaTranslator t } public static void translate(ImSet s, List res, LuaTranslator tr) { - res.add(LuaAst.LuaAssignment(LuaAst.LuaExprVarAccess(tr.luaVar.getFor(s.getLeft())), s.getRight().translateToLua(tr))); + res.add(LuaAst.LuaAssignment(s.getLeft().translateToLua(tr), s.getRight().translateToLua(tr))); } - public static void translate(ImSetArray s, List res, LuaTranslator tr) { - res.add(LuaAst.LuaAssignment( - LuaAst.LuaExprArrayAccess(LuaAst.LuaExprVarAccess(tr.luaVar.getFor(s.getLeft())), LuaAst.LuaExprlist(s.getIndex().translateToLua(tr))), - s.getRight().translateToLua(tr))); - } - - public static void translate(ImSetArrayMulti s, List res, LuaTranslator tr) { - res.add(LuaAst.LuaAssignment( - LuaAst.LuaExprArrayAccess(LuaAst.LuaExprVarAccess(tr.luaVar.getFor(s.getLeft())), tr.translateExprList(s.getIndices())), - s.getRight().translateToLua(tr))); - } - - public static void translate(ImSetArrayTuple s, List res, LuaTranslator tr) { - res.add(LuaAst.LuaAssignment( - LuaAst.LuaExprArrayAccess(LuaAst.LuaExprVarAccess(tr.luaVar.getFor(s.getLeft())), LuaAst.LuaExprlist(s.getIndex().translateToLua(tr), LuaAst.LuaExprIntVal("" + s.getTupleIndex()))), - s.getRight().translateToLua(tr))); - } - - public static void translate(ImSetTuple s, List res, LuaTranslator tr) { - res.add(LuaAst.LuaAssignment( - LuaAst.LuaExprArrayAccess(LuaAst.LuaExprVarAccess(tr.luaVar.getFor(s.getLeft())), LuaAst.LuaExprlist(LuaAst.LuaExprIntVal("" + s.getTupleIndex()))), - s.getRight().translateToLua(tr))); - } public static void translate(ImVarargLoop imVarargLoop, List res, LuaTranslator tr) { throw new Error("not implemented"); } + } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/GlobalsInliner.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/GlobalsInliner.java index 4015cb3aa..074fc66dc 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/GlobalsInliner.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/GlobalsInliner.java @@ -49,8 +49,8 @@ public int optimize(ImTranslator trans) { if (replacement != null || v.attrReads().size() == 0) { obsoleteVars.add(v); } - } else if (v.attrWrites().size() > 1 && !(v.getType() instanceof ImArrayType || v.getType() instanceof ImTupleArrayType - || v.getType() instanceof ImTupleType || v.getType() instanceof ImTupleArrayType)) { + } else if (v.attrWrites().size() > 1 && !(v.getType() instanceof ImArrayType + || v.getType() instanceof ImTupleType)) { List initWrites = v.attrWrites().stream().filter(write -> { ImFunction nearestFunc = write.getNearestFunc(); return isInInit(nearestFunc); diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/ImInliner.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/ImInliner.java index 77e2af033..ffdfba7e3 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/ImInliner.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/ImInliner.java @@ -114,7 +114,7 @@ private void inlineCall(ImFunction f, Element parent, int parentI, ImFunctionCal f.getLocals().add(tempVar); varSubtitutions.put(param, tempVar); // set temp var - stmts.add(JassIm.ImSet(arg.attrTrace(), tempVar, arg)); + stmts.add(JassIm.ImSet(arg.attrTrace(), JassIm.ImVarAccess(tempVar), arg)); } // add locals for (ImVar l : called.getLocals()) { diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/ImOptimizer.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/ImOptimizer.java index 45c99fc12..a74ea1923 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/ImOptimizer.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/ImOptimizer.java @@ -8,8 +8,10 @@ import de.peeeq.wurstscript.utils.Pair; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.stream.Collectors; public class ImOptimizer { private int totalFunctionsRemoved = 0; @@ -105,44 +107,45 @@ public void removeGarbage() { totalFunctionsRemoved += functionsRemoved; for (ImFunction f : prog.getFunctions()) { // remove set statements to unread variables - final List> replacements = Lists.newArrayList(); + final List>> replacements = Lists.newArrayList(); f.accept(new ImFunction.DefaultVisitor() { @Override public void visit(ImSet e) { super.visit(e); - if (!trans.getReadVariables().contains(e.getLeft())) { - replacements.add(Pair.create(e, e.getRight())); + if (e.getLeft() instanceof ImVarAccess) { + ImVarAccess va = (ImVarAccess) e.getLeft(); + if (!trans.getReadVariables().contains(va.getVar())) { + replacements.add(Pair.create(e, Collections.singletonList(e.getRight()))); + } + } else if (e.getLeft() instanceof ImVarArrayAccess) { + ImVarArrayAccess va = (ImVarArrayAccess) e.getLeft(); + if (!trans.getReadVariables().contains(va.getVar())) { + // TODO indexes might have side effects that we need to keep + List exprs = va.getIndexes().removeAll(); + exprs.add(e.getRight()); + replacements.add(Pair.create(e, exprs)); + } } } - @Override - public void visit(ImSetArrayTuple e) { - super.visit(e); - if (!trans.getReadVariables().contains(e.getLeft())) { - replacements.add(Pair.create(e, e.getRight())); - } - } - - @Override - public void visit(ImSetArray e) { - super.visit(e); - if (!trans.getReadVariables().contains(e.getLeft())) { - replacements.add(Pair.create(e, e.getRight())); - } - } - - @Override - public void visit(ImSetTuple e) { - super.visit(e); - if (!trans.getReadVariables().contains(e.getLeft())) { - replacements.add(Pair.create(e, e.getRight())); - } - } }); - for (Pair pair : replacements) { + for (Pair> pair : replacements) { changes = true; - pair.getB().setParent(null); - pair.getA().replaceBy(pair.getB()); + ImExpr r; + if (pair.getB().size() == 1) { + r = pair.getB().get(0); + r.setParent(null); + } else { + List exprs = Collections.unmodifiableList(pair.getB()); + for (ImStmt expr : exprs) { + expr.setParent(null); + } + r = JassIm.ImStatementExpr( + JassIm.ImStmts(exprs), + JassIm.ImNull() + ); + } + pair.getA().replaceBy(r); } // keep only read local variables diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/NullSetter.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/NullSetter.java index 1206a1c2b..e175d3545 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/NullSetter.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/NullSetter.java @@ -50,7 +50,7 @@ private void optimizeFunc(final ImFunction f) { final List nullSetStmts = Lists.newArrayList(); final de.peeeq.wurstscript.ast.Element trace = f.getTrace(); for (ImVar local : handleVars) { - nullSetStmts.add(JassIm.ImSet(trace, local, JassIm.ImNull())); + nullSetStmts.add(JassIm.ImSet(trace, JassIm.ImVarAccess(local), JassIm.ImNull())); } boolean returns = optimizeChildren(f, handleVars, nullSetStmts, trace, f.getBody()); @@ -124,7 +124,7 @@ private void handleReturnStmt(final ImFunction f, } imReturn.setReturnValue(JassIm.ImVarAccess(tempReturn)); - parent2.add(parentIndex, JassIm.ImSet(trace, tempReturn, returnExpr)); + parent2.add(parentIndex, JassIm.ImSet(trace, JassIm.ImVarAccess(tempReturn), returnExpr)); } } else { // normal return diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/UselessFunctionCallsRemover.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/UselessFunctionCallsRemover.java index 6700f0a52..d02f27c2f 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/UselessFunctionCallsRemover.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/UselessFunctionCallsRemover.java @@ -2,6 +2,7 @@ import de.peeeq.wurstscript.WurstOperator; import de.peeeq.wurstscript.jassIm.*; +import de.peeeq.wurstscript.translation.imtranslation.Flatten; import de.peeeq.wurstscript.translation.imtranslation.ImTranslator; import java.util.Arrays; @@ -23,7 +24,7 @@ public int optimize(ImTranslator trans) { totalCallsRemoved = 0; ImProg prog = trans.getImProg(); for (ImFunction func : prog.getFunctions()) { - optimizeFunc(func); + optimizeFunc(func, trans); } return totalCallsRemoved; } @@ -33,9 +34,9 @@ public String getName() { return "Useless function calls removed"; } - private void optimizeFunc(ImFunction func) { + private void optimizeFunc(ImFunction func, ImTranslator trans) { optimizeStmts(func.getBody()); - + func.flatten(trans); } private void optimizeStmts(ImStmts stmts) { diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/VariableUses.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/VariableUses.java index 10451824e..7dd1d305b 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/VariableUses.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/VariableUses.java @@ -27,27 +27,48 @@ public static Uses calcVarUses(ImProg imProg) { imProg.accept(new ImProg.DefaultVisitor() { @Override public void visit(ImSet imSet) { - super.visit(imSet); - result.addWrite(imSet.getLeft(), imSet); + Element.DefaultVisitor thiz = this; + + imSet.getRight().accept(this); + imSet.getLeft().match(new ImLExpr.MatcherVoid() { + @Override + public void case_ImVarAccess(ImVarAccess e) { + result.addWrite(e.getVar(), imSet); + } + + @Override + public void case_ImStatementExpr(ImStatementExpr e) { + e.getStatements().accept(thiz); + ((ImLExpr) e.getExpr()).match(this); + } + + @Override + public void case_ImTupleSelection(ImTupleSelection e) { + ((ImLExpr) e.getTupleExpr()).match(this); + } + + @Override + public void case_ImTupleExpr(ImTupleExpr e) { + for (ImExpr expr : e.getExprs()) { + ((ImLExpr) expr).match(this); + } + } + + @Override + public void case_ImVarArrayAccess(ImVarArrayAccess e) { + result.addWrite(e.getVar(), imSet); + e.getIndexes().accept(thiz); + } + + @Override + public void case_ImMemberAccess(ImMemberAccess e) { + e.getReceiver().accept(thiz); + result.addWrite(e.getVar(), imSet); + } + + }); } - @Override - public void visit(ImSetArray imSet) { - super.visit(imSet); - result.addWrite(imSet.getLeft(), imSet); - } - - @Override - public void visit(ImSetArrayTuple imSet) { - super.visit(imSet); - result.addWrite(imSet.getLeft(), imSet); - } - - @Override - public void visit(ImSetTuple imSet) { - super.visit(imSet); - result.addWrite(imSet.getLeft(), imSet); - } @Override public void visit(ImVarAccess r) { diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/DefaultValue.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/DefaultValue.java index 1f907c199..6e12689fd 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/DefaultValue.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/DefaultValue.java @@ -6,11 +6,12 @@ import de.peeeq.wurstscript.jassIm.*; import java.util.List; +import java.util.function.Supplier; public class DefaultValue { public static ILconst get(ImArrayType t) { - return JassIm.ImSimpleType(t.getTypename()).defaultValue(); + return t.getEntryType().defaultValue(); } public static ILconst get(ImSimpleType t) { @@ -23,14 +24,6 @@ public static ILconst get(ImSimpleType t) { return ILconstNull.instance(); } - public static ILconst get(ImTupleArrayType tt) { - List values = Lists.newArrayList(); - for (ImType t : tt.getTypes()) { - values.add(t.defaultValue()); - } - return new ILconstTuple(values.toArray(new ILconst[0])); - } - public static ILconst get(ImTupleType tt) { List values = Lists.newArrayList(); for (ImType t : tt.getTypes()) { @@ -43,8 +36,15 @@ public static ILconst get(ImVoid t) { throw new Error("Could not get default value for void variable."); } - public static ILconst get(ImArrayTypeMulti imArrayTypeMulti) { - return JassIm.ImSimpleType(imArrayTypeMulti.getTypename()).defaultValue(); + public static ILconst get(ImArrayTypeMulti t) { + return new ILconstArray(makeSupplier(t.getArraySize().size() - 1, t.getEntryType())); + } + + private static Supplier makeSupplier(int depth, ImType entryType) { + if (depth <= 1) { + return entryType::defaultValue; + } + return () -> new ILconstArray(makeSupplier(depth - 1, entryType)); } } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/ExprTranslation.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/ExprTranslation.java index 587f22aa4..b8545fa13 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/ExprTranslation.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/ExprTranslation.java @@ -1,6 +1,7 @@ package de.peeeq.wurstscript.translation.imtojass; +import com.google.common.base.Preconditions; import de.peeeq.wurstscript.WurstOperator; import de.peeeq.wurstscript.attributes.CompileError; import de.peeeq.wurstscript.jassAst.*; @@ -88,7 +89,7 @@ public static JassExpr translate(ImRealVal e, ImToJassTranslator translator) { } public static JassExpr translate(ImStatementExpr e, ImToJassTranslator translator) { - throw new Error("this expr should have been flattened: " + e); + throw new Error("this expr should have been flattened: " + e + "\n\n" + e.getNearestFunc()); } public static JassExpr translate(ImStringVal e, ImToJassTranslator translator) { @@ -110,7 +111,10 @@ public static JassExprVarAccess translate(ImVarAccess e, ImToJassTranslator tran public static JassExprVarArrayAccess translate(ImVarArrayAccess e, ImToJassTranslator translator) { JassVar v = translator.getJassVarFor(e.getVar()); - return JassExprVarArrayAccess(v.getName(), e.getIndex().translate(translator)); + if (e.getIndexes().size() != 1) { + throw new CompileError(e.attrTrace().attrSource(), "Only one array index allowed."); + } + return JassExprVarArrayAccess(v.getName(), e.getIndexes().get(0).translate(translator)); } public static JassExpr translate(ImClassRelatedExpr e, @@ -118,11 +122,6 @@ public static JassExpr translate(ImClassRelatedExpr e, throw new RuntimeException("Eliminate method calls before translating to jass"); } - public static JassExpr translate( - ImVarArrayMultiAccess imVarArrayMultiAccess, - ImToJassTranslator translator) { - throw new Error("not implemented"); - } public static JassExpr translate(ImGetStackTrace imGetStackTrace, ImToJassTranslator translator) { return JassAst.JassExprStringVal(""); @@ -134,4 +133,5 @@ public static JassExpr translate(ImCompiletimeExpr e, ImToJassTranslator transla "Compiletime expression must be evaluated before translation. " + "Enable '-runcompiletimefunctions' to evaluate compiletime expressions."); } + } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/ImAttrType.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/ImAttrType.java index d44cea9c4..6943a67be 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/ImAttrType.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/ImAttrType.java @@ -100,10 +100,10 @@ public static ImType getType(ImVarArrayAccess e) { ImType ar = e.getVar().getType(); if (ar instanceof ImArrayType) { ImArrayType t = (ImArrayType) ar; - return JassIm.ImSimpleType(t.getTypename()); - } else if (ar instanceof ImTupleArrayType) { - ImTupleArrayType t = (ImTupleArrayType) ar; - return JassIm.ImTupleType(t.getTypes(), t.getNames()); + return t.getEntryType(); + } else if (ar instanceof ImArrayTypeMulti) { + ImArrayTypeMulti t = (ImArrayTypeMulti) ar; + return t.getEntryType(); } return ar; } @@ -119,6 +119,7 @@ public static ImType getType(ImTupleExpr imTupleExpr) { return JassIm.ImTupleType(types, names); } + public static ImType getType(ImMethodCall mc) { return mc.getMethod().getImplementation().getReturnType(); } @@ -147,9 +148,6 @@ public static ImType getType(ImTypeIdOfObj imTypeIdOfObj) { return TypesHelper.imInt(); } - public static ImType getType(ImVarArrayMultiAccess imVarArrayMultiAccess) { - throw new Error("not implemented"); - } public static ImType getType(ImGetStackTrace imGetStackTrace) { return TypesHelper.imString(); diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/ImAttributes.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/ImAttributes.java index 8e9ce9be7..b710989dc 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/ImAttributes.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/ImAttributes.java @@ -19,7 +19,7 @@ public static ImFunction getNearestFunc(Element e) { public static String translateType(ImArrayType t) { - return t.getTypename(); + return t.getEntryType().translateType(); } public static String translateType(ImArrayTypeMulti imArrayTypeMulti) { @@ -42,11 +42,6 @@ public static String translateType(ImVoid t) { } - public static String translateType(ImTupleArrayType t) { - throw new Error("tuples should be eliminated in earlier phase"); - } - - public static boolean isGlobal(ImVar imVar) { return imVar.getParent().getParent() instanceof ImProg; } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/ImToJassTranslator.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/ImToJassTranslator.java index da592d835..d095aa7e6 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/ImToJassTranslator.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/ImToJassTranslator.java @@ -186,7 +186,7 @@ private String getUniqueLocalName(ImFunction imFunction, String name) { JassVar getJassVarFor(ImVar v) { JassVar result = jassVars.get(v); if (result == null) { - boolean isArray = v.getType() instanceof ImArrayType || v.getType() instanceof ImTupleArrayType; + boolean isArray = v.getType() instanceof ImArrayType; String type = v.getType().translateType(); String name = v.getName(); if (v.getNearestFunc() != null) { diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/StatementTranslation.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/StatementTranslation.java index fd34ee176..698e4fb7a 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/StatementTranslation.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/StatementTranslation.java @@ -42,9 +42,19 @@ public static void translate(ImReturn imReturn, List stmts, JassF } public static void translate(ImSet imSet, List stmts, JassFunction f, ImToJassTranslator translator) { - JassVar vars = translator.getJassVarFor(imSet.getLeft()); - JassExpr exprs = imSet.getRight().translate(translator); - stmts.add(JassStmtSet(vars.getName(), exprs)); + ImLExpr updatedExpr = imSet.getLeft(); + if (updatedExpr instanceof ImVarAccess) { + ImVarAccess va = (ImVarAccess) updatedExpr; + JassVar var = translator.getJassVarFor(va.getVar()); + JassExpr exprs = imSet.getRight().translate(translator); + stmts.add(JassStmtSet(var.getName(), exprs)); + } else if (updatedExpr instanceof ImVarArrayAccess) { + ImVarArrayAccess vaa = (ImVarArrayAccess) updatedExpr; + ImVar var = vaa.getVar(); + JassExpr indexes = vaa.getIndexes().get(0).translate(translator); + JassExpr exprs = imSet.getRight().translate(translator); + stmts.add(JassStmtSetArray(var.getName(), indexes, exprs)); + } } public static void translate(ImExpr imExpr, List stmts, JassFunction f, ImToJassTranslator translator) { @@ -66,20 +76,6 @@ private static void addAllCalls(List stmts, de.peeeq.wurstscript. } } - public static void translate(ImSetArray imSet, List stmts, JassFunction f, ImToJassTranslator translator) { - JassVar leftVar = translator.getJassVarFor(imSet.getLeft()); - JassExpr right = imSet.getRight().translate(translator); - stmts.add(JassAst.JassStmtSetArray(leftVar.getName(), imSet.getIndex().translate(translator), right)); - } - - public static void translate(ImSetArrayTuple imSet, List stmts, JassFunction f, - ImToJassTranslator translator) { - throw new Error("tuples should be eliminated in earlier phase"); - } - - public static void translate(ImSetTuple imSet, List stmts, JassFunction f, ImToJassTranslator translator) { - throw new Error("tuples should be eliminated in earlier phase"); - } public static void translate(ImStmts imStmts, List stmts, JassFunction f, ImToJassTranslator translator) { for (ImStmt s : imStmts) { @@ -87,15 +83,9 @@ public static void translate(ImStmts imStmts, List stmts, JassFun } } - public static void translate(ImSetArrayMulti imSetArrayMulti, - List stmts, JassFunction f, - ImToJassTranslator translator) { - throw new Error("not implemented"); - - } - public static void translate(ImVarargLoop imVarargLoop, List stmts, JassFunction f, ImToJassTranslator translator) { throw new Error("not implemented"); } + } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/TypeEquality.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/TypeEquality.java index a13f58abb..f59881ab6 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/TypeEquality.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/TypeEquality.java @@ -7,7 +7,7 @@ public class TypeEquality { public static boolean isEqualType(ImArrayType a, ImType b) { if (b instanceof ImArrayType) { ImArrayType at = (ImArrayType) b; - return at.getTypename().equals(a.getTypename()); + return at.getEntryType().equalsType(a.getEntryType()); } return false; } @@ -16,7 +16,7 @@ public static boolean isEqualType(ImArrayTypeMulti a, ImType b) { if (b instanceof ImArrayTypeMulti) { ImArrayTypeMulti at = (ImArrayTypeMulti) b; // TODO check dimensions - return at.getTypename().equals(a.getTypename()); + return at.getEntryType().equalsType(a.getEntryType()); } return false; } @@ -30,20 +30,6 @@ public static boolean isEqualType(ImSimpleType a, ImType b) { return false; } - public static boolean isEqualType(ImTupleArrayType a, ImType b) { - if (b instanceof ImTupleArrayType) { - ImTupleArrayType at = (ImTupleArrayType) b; - if (at.getTypes().size() != a.getTypes().size()) { - return false; - } - for (int i = 0; i < a.getTypes().size(); i++) { - if (!a.getTypes().get(i).equalsType(at.getTypes().get(i))) { - return false; - } - } - } - return false; - } public static boolean isEqualType(ImTupleType a, ImType b) { if (b instanceof ImTupleType) { diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ClassManagementVars.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ClassManagementVars.java index 66b8cf321..e525cb44c 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ClassManagementVars.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ClassManagementVars.java @@ -7,6 +7,8 @@ import de.peeeq.wurstscript.jassIm.JassIm; import de.peeeq.wurstscript.types.TypesHelper; +import java.lang.reflect.Type; + public class ClassManagementVars { /** * array, nextFree[x] is the element which comes next in the queue @@ -31,7 +33,7 @@ public class ClassManagementVars { public ClassManagementVars(ImClass repClass, ImTranslator translator) { Element tr = repClass.getTrace(); ImProg prog = translator.getImProg(); - free = JassIm.ImVar(tr, JassIm.ImArrayType("integer"), repClass.getName() + "_nextFree", false); + free = JassIm.ImVar(tr, JassIm.ImArrayType(TypesHelper.imInt()), repClass.getName() + "_nextFree", false); prog.getGlobals().add(free); freeCount = JassIm.ImVar(tr, TypesHelper.imInt(), repClass.getName() + "_firstFree", false); @@ -40,7 +42,7 @@ public ClassManagementVars(ImClass repClass, ImTranslator translator) { maxIndex = JassIm.ImVar(tr, TypesHelper.imInt(), repClass.getName() + "_maxIndex", false); translator.addGlobalWithInitalizer(maxIndex, JassIm.ImIntVal(0)); - typeId = JassIm.ImVar(tr, JassIm.ImArrayType("integer"), repClass.getName() + "_typeId", false); + typeId = JassIm.ImVar(tr, JassIm.ImArrayType(TypesHelper.imInt()), repClass.getName() + "_typeId", false); prog.getGlobals().add(typeId); } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ClassTranslator.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ClassTranslator.java index 32295bb34..b2b3b57e1 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ClassTranslator.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ClassTranslator.java @@ -6,15 +6,12 @@ import de.peeeq.wurstscript.ast.Element; import de.peeeq.wurstscript.jassIm.Element.DefaultVisitor; import de.peeeq.wurstscript.jassIm.ImClass; +import de.peeeq.wurstscript.jassIm.*; import de.peeeq.wurstscript.jassIm.ImExprs; import de.peeeq.wurstscript.jassIm.ImFunction; import de.peeeq.wurstscript.jassIm.ImMethod; import de.peeeq.wurstscript.jassIm.ImProg; import de.peeeq.wurstscript.jassIm.ImSet; -import de.peeeq.wurstscript.jassIm.ImSetArray; -import de.peeeq.wurstscript.jassIm.ImSetArrayTuple; -import de.peeeq.wurstscript.jassIm.ImSetTuple; -import de.peeeq.wurstscript.jassIm.*; import de.peeeq.wurstscript.jassIm.ImVar; import de.peeeq.wurstscript.jassIm.ImVarAccess; import de.peeeq.wurstscript.types.*; @@ -26,6 +23,7 @@ import java.util.Map.Entry; import static de.peeeq.wurstscript.jassIm.JassIm.*; + public class ClassTranslator { private ClassDef classDef; @@ -184,37 +182,6 @@ public void visit(ImVarAccess v) { } } - @Override - public void visit(ImSet v) { - super.visit(v); - if (v.getLeft() == oldThis) { - v.setLeft(newThis); - } - } - - @Override - public void visit(ImSetArray v) { - super.visit(v); - if (v.getLeft() == oldThis) { - v.setLeft(newThis); - } - } - - @Override - public void visit(ImSetTuple v) { - super.visit(v); - if (v.getLeft() == oldThis) { - v.setLeft(newThis); - } - } - - @Override - public void visit(ImSetArrayTuple v) { - super.visit(v); - if (v.getLeft() == oldThis) { - v.setLeft(newThis); - } - } }; for (ImStmt s : stmts) { s.accept(replacer); @@ -366,7 +333,7 @@ private void createNewFunc(ConstructorDef constr) { f.getLocals().add(thisVar); // allocate class - f.getBody().add(ImSet(trace, thisVar, JassIm.ImAlloc(imClass))); + f.getBody().add(ImSet(trace, ImVarAccess(thisVar), JassIm.ImAlloc(imClass))); // call user defined constructor code: ImFunction constrFunc = translator.getConstructFunc(constr); @@ -402,13 +369,13 @@ private void createConstructFunc(ConstructorDef constr) { ImVar v = i.getA(); if (i.getB() instanceof Expr) { Expr e = (Expr) i.getB(); - ImStmt s = ImSetArray(trace, v, ImVarAccess(thisVar), e.imTranslateExpr(translator, f)); + ImStmt s = ImSet(trace, ImVarArrayAccess(trace, v, ImExprs((ImExpr) ImVarAccess(thisVar))), e.imTranslateExpr(translator, f)); f.getBody().add(s); } else if (i.getB() instanceof ArrayInitializer) { ArrayInitializer ai = (ArrayInitializer) i.getB(); int index = 0; for (Expr e : ai.getValues()) { - ImStmt s = ImSetArrayMulti(trace, v, ImExprs(ImVarAccess(thisVar), JassIm.ImIntVal(index)), e.imTranslateExpr(translator, f)); + ImStmt s = ImSet(trace, ImVarArrayAccess(trace, v, ImExprs(ImVarAccess(thisVar), JassIm.ImIntVal(index))), e.imTranslateExpr(translator, f)); f.getBody().add(s); index++; } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ClosureTranslator.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ClosureTranslator.java index 7140edb27..345500473 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ClosureTranslator.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ClosureTranslator.java @@ -40,13 +40,13 @@ public ImExpr translate() { f.getLocals().add(clVar); ImStmts stmts = JassIm.ImStmts(); // allocate closure - stmts.add(JassIm.ImSet(e, clVar, JassIm.ImAlloc(c))); + stmts.add(JassIm.ImSet(e, JassIm.ImVarAccess(clVar), JassIm.ImAlloc(c))); callSuperConstructor(clVar, stmts, c); // set closure vars for (Entry entry : closureVars.entrySet()) { ImVar orig = entry.getKey(); ImVar v = entry.getValue(); - stmts.add(JassIm.ImSetArray(e, v, JassIm.ImVarAccess(clVar), JassIm.ImVarAccess(orig))); + stmts.add(JassIm.ImSet(e, JassIm.ImVarArrayAccess(e, v, JassIm.ImExprs((ImExpr) JassIm.ImVarAccess(clVar))), JassIm.ImVarAccess(orig))); } return JassIm.ImStatementExpr(stmts, JassIm.ImVarAccess(clVar)); } @@ -112,7 +112,7 @@ public void visit(ImVarAccess va) { public void visit(ImSet s) { super.visit(s); if (isLocalToOtherFunc(s.getLeft())) { - throw new CompileError(s.attrTrace().attrSource(), "Anonymous functions used as 'code' cannot capture variables. Captured " + s.getLeft().getName()); + throw new CompileError(s.attrTrace().attrSource(), "Anonymous functions used as 'code' cannot capture variables. Captured " + s.getLeft()); } } }); @@ -166,8 +166,6 @@ private ImClass createClass() { private void transformTranslated(ImExpr t) { final List vas = Lists.newArrayList(); - final List sets = Lists.newArrayList(); - final List tupleSets = Lists.newArrayList(); t.accept(new ImExpr.DefaultVisitor() { @Override public void visit(ImVarAccess va) { @@ -177,38 +175,12 @@ public void visit(ImVarAccess va) { } } - @Override - public void visit(ImSet s) { - super.visit(s); - if (isLocalToOtherFunc(s.getLeft())) { - sets.add(s); - } - } - @Override - public void visit(ImSetTuple s) { - super.visit(s); - if (isLocalToOtherFunc(s.getLeft())) { - tupleSets.add(s); - } - } }); for (ImVarAccess va : vas) { ImVar v = getClosureVarFor(va.getVar()); - va.replaceBy(JassIm.ImVarArrayAccess(v, closureThis())); - } - for (ImSet s : sets) { - ImVar v = getClosureVarFor(s.getLeft()); - ImExpr right = s.getRight(); - right.setParent(null); - s.replaceBy(JassIm.ImSetArray(e, v, closureThis(), right)); - } - for (ImSetTuple s : tupleSets) { - ImVar v = getClosureVarFor(s.getLeft()); - ImExpr right = s.getRight(); - right.setParent(null); - s.replaceBy(JassIm.ImSetArrayTuple(e, v, closureThis(), s.getTupleIndex(), right)); + va.replaceBy(JassIm.ImVarArrayAccess(e, v, JassIm.ImExprs(closureThis()))); } } @@ -220,7 +192,7 @@ private ImExpr closureThis() { private ImVar getClosureVarFor(ImVar var) { ImVar v = closureVars.get(var); if (v == null) { - v = JassIm.ImVar(e, arrayType(var.getType()), var.getName(), false); + v = JassIm.ImVar(e, JassIm.ImArrayType(var.getType()), var.getName(), false); tr.imProg().getGlobals().add(v); closureVars.put(var, v); } @@ -228,30 +200,28 @@ private ImVar getClosureVarFor(ImVar var) { } - private ImType arrayType(ImType type) { - if (type instanceof ImSimpleType) { - ImSimpleType t = (ImSimpleType) type; - return JassIm.ImArrayType(t.getTypename()); - } else if (type instanceof ImTupleType) { - ImTupleType t = (ImTupleType) type; - return JassIm.ImTupleArrayType(t.getTypes(), t.getNames()); - } - throw new CompileError(e.getSource(), "Closure references array variable."); - } - - - private boolean isLocalToOtherFunc(ImVar imVar) { - if (imVar.getParent() == null - || imVar.getParent().getParent() == null) { + private boolean isLocalToOtherFunc(ImVar v) { + if (v.getParent() == null + || v.getParent().getParent() == null) { return false; } - if (imVar.getParent().getParent() instanceof ImFunction) { - boolean r = imVar.getParent().getParent() != impl; + if (v.getParent().getParent() instanceof ImFunction) { + boolean r = v.getParent().getParent() != impl; return r; } return false; } + private boolean isLocalToOtherFunc(ImLExpr e) { + if (e instanceof ImVarAccess) { + return isLocalToOtherFunc(((ImVarAccess) e).getVar()); + } else if (e instanceof ImTupleSelection) { + ImTupleSelection ts = (ImTupleSelection) e; + return isLocalToOtherFunc((ImLExpr) ts.getTupleExpr()); + } + return false; + } + private FuncDef getSuperMethod() { NameLink nl = e.attrClosureAbstractMethod(); diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/CyclicFunctionRemover.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/CyclicFunctionRemover.java index bc9e8b5cf..a6b1a0efe 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/CyclicFunctionRemover.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/CyclicFunctionRemover.java @@ -213,7 +213,7 @@ private void replaceReturn(Element e, ImType returnType) { ImExprOpt returnValue = r.getReturnValue(); returnValue.setParent(null); ImStmts stmts = JassIm.ImStmts( - JassIm.ImSet(r.getTrace(), getTempReturnVar(returnType), (ImExpr) returnValue), + JassIm.ImSet(r.getTrace(), JassIm.ImVarAccess(getTempReturnVar(returnType)), (ImExpr) returnValue), JassIm.ImReturn(r.getTrace(), JassIm.ImNoExpr()) ); r.replaceBy(JassIm.ImStatementExpr(stmts, JassIm.ImNull())); diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/EliminateClasses.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/EliminateClasses.java index bab3d5b8d..f70d272cd 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/EliminateClasses.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/EliminateClasses.java @@ -51,7 +51,7 @@ private void eliminateClass(ImClass c) { // for each field, create a global array variable for (ImVar f : c.getFields()) { ImVar v = JassIm - .ImVar(f.getTrace(), toArrayType(f.getType()), f.getName(), false); + .ImVar(f.getTrace(), JassIm.ImArrayType(f.getType()), f.getName(), false); prog.getGlobals().add(v); fieldToArray.put(f, v); } @@ -109,8 +109,7 @@ public void createDispatchFunc(ImClass c, ImMethod m) { ClassManagementVars mVars = translator.getClassManagementVarsFor(c); ImVar thisVar = df.getParameters().get(0); - ImExpr typeId = JassIm.ImVarArrayAccess(mVars.typeId, - JassIm.ImVarAccess(thisVar)); + ImExpr typeId = JassIm.ImVarArrayAccess(m.getTrace(), mVars.typeId, JassIm.ImExprs((ImExpr) JassIm.ImVarAccess(thisVar))); // ckeck if destroyed or nullpointer if (checkedDispatch) { @@ -172,7 +171,7 @@ private void createDispatch(ImFunction df, ImStmts stmts, ImVar resultVar, if (resultVar == null) { stmts.add(call); } else { - stmts.add(JassIm.ImSet(df.getTrace(), resultVar, call)); + stmts.add(JassIm.ImSet(df.getTrace(), JassIm.ImVarAccess(resultVar), call)); } } else { int mid = (start + end) / 2; @@ -333,7 +332,7 @@ private void replaceTypeIdOfObj(ImTypeIdOfObj e) { ImVar typeIdVar = translator.getClassManagementVarsFor(e.getClazz()).typeId; ImExpr obj = e.getObj(); obj.setParent(null); - e.replaceBy(JassIm.ImVarArrayAccess(typeIdVar, obj)); + e.replaceBy(JassIm.ImVarArrayAccess(e.attrTrace(), typeIdVar, JassIm.ImExprs(obj))); } private void replaceTypeIdOfClass(ImTypeIdOfClass e) { @@ -351,7 +350,7 @@ private void replaceInstanceof(ImInstanceof e) { obj.setParent(null); ImVar typeIdVar = translator.getClassManagementVarsFor(e.getClazz()).typeId; - ImExpr objTypeId = JassIm.ImVarArrayAccess(typeIdVar, obj); + ImExpr objTypeId = JassIm.ImVarArrayAccess(e.attrTrace(), typeIdVar, JassIm.ImExprs(obj)); boolean useTempVar = idRanges.size() >= 2 || idRanges.get(0).start < idRanges.get(0).end; ImVar tempVar = null; @@ -368,7 +367,7 @@ private void replaceInstanceof(ImInstanceof e) { } if (useTempVar) { newExpr = JassIm.ImStatementExpr(JassIm.ImStmts( - JassIm.ImSet(f.getTrace(), tempVar, objTypeId) + JassIm.ImSet(f.getTrace(), JassIm.ImVarAccess(tempVar), objTypeId) ), newExpr); } e.replaceBy(newExpr); @@ -437,19 +436,8 @@ private void replaceMemberAccess(ImMemberAccess ma) { ImExpr receiver = ma.getReceiver(); receiver.setParent(null); - ma.replaceBy(JassIm.ImVarArrayAccess(fieldToArray.get(ma.getVar()), - receiver)); + ma.replaceBy(JassIm.ImVarArrayAccess(ma.attrTrace(), fieldToArray.get(ma.getVar()), JassIm.ImExprs(receiver))); } - private ImType toArrayType(ImType t) { - if (t instanceof ImSimpleType) { - return JassIm.ImArrayType(((ImSimpleType) t).getTypename()); - } else if (t instanceof ImTupleType) { - return JassIm.ImTupleArrayType(((ImTupleType) t).getTypes(), - ((ImTupleType) t).getNames()); - } - throw new RuntimeException("unhandled case: " + t.getClass()); - } - } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/EliminateTuples.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/EliminateTuples.java index 850264053..5a05ecc72 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/EliminateTuples.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/EliminateTuples.java @@ -1,15 +1,19 @@ package de.peeeq.wurstscript.translation.imtranslation; import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; -import de.peeeq.datastructures.ImmutableTree; import de.peeeq.wurstscript.WurstOperator; import de.peeeq.wurstscript.attributes.CompileError; +import de.peeeq.wurstscript.intermediatelang.optimizer.SideEffectAnalyzer; import de.peeeq.wurstscript.jassIm.*; +import de.peeeq.wurstscript.translation.imtranslation.ImTranslator.VarsForTupleResult; +import de.peeeq.wurstscript.types.TypesHelper; +import de.peeeq.wurstscript.utils.Utils; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.ListIterator; +import java.util.stream.Collectors; /** * a rewrite would return a combination of @@ -19,745 +23,471 @@ */ public class EliminateTuples { + + public static void eliminateTuplesProg(ImProg imProg, ImTranslator translator) { - transformVars(imProg.getGlobals(), translator); + Runnable removeOldGlobals = transformVars(imProg.getGlobals(), translator); for (ImFunction f : imProg.getFunctions()) { - f.eliminateTuples(translator); + transformFunctionReturnsAndParameters(f, translator); } - - for (ImFunction f : imProg.getFunctions()) { - transformStatements(f, f.getBody(), translator); + eliminateTuplesFunc(f, translator); } - + removeOldGlobals.run(); translator.assertProperties(AssertProperty.NOTUPLES); } + private static void transformFunctionReturnsAndParameters(ImFunction f, ImTranslator translator) { + transformVars(f.getParameters(), translator).run(); + translator.setOriginalReturnValue(f, f.getReturnType()); + f.setReturnType(getFirstType(f.getReturnType())); + } - public static void eliminateTuplesFunc(ImFunction f, final ImTranslator translator) { - // transform parameters - transformVars(f.getParameters(), translator); - transformVars(f.getLocals(), translator); - translator.setOriginalReturnValue(f, f.getReturnType()); + private static void eliminateTuplesFunc(ImFunction f, final ImTranslator translator) { + transformVars(f.getLocals(), translator).run(); - f.setReturnType(getFirstType(f.getReturnType())); - f.getBody().accept(new ImStmts.DefaultVisitor() { + tryStep(f, translator, EliminateTuples::toTupleExpressions); + tryStep(f, translator, EliminateTuples::normalizeTuplesInStatementExprs); + tryStep(f, translator, EliminateTuples::removeTupleSelections); + tryStep(f, translator, EliminateTuples::normalizeTuplesInStatementExprs); + tryStep(f, translator, EliminateTuples::removeTupleExprs); + + } + + private static void removeTupleSelections(ImStmts stmts, ImTranslator tr, ImFunction f) { + stmts.accept(new Element.DefaultVisitor() { @Override - public void visit(ImFunctionCall e) { - super.visit(e); - // use temp return valus instead of tuples - List tempVars = translator.getTupleTempReturnVarsFor(e.getFunc()); - if (tempVars.size() > 1) { - Element parent = e.getParent(); - int parentIndex = -1; - for (int i = 0; i < parent.size(); i++) { - if (parent.get(i) == e) { - parentIndex = i; - parent.set(i, JassIm.ImNull()); // dummy - break; - } - } + public void visit(ImTupleSelection ts) { + super.visit(ts); + + if (!(ts.getTupleExpr() instanceof ImTupleExpr)) { + throw new CompileError(ts.attrTrace().attrSource(), "Wrong tuple selection: " + ts); + } + + ImTupleExpr tupleExpr = (ImTupleExpr) ts.getTupleExpr(); + + int ti = ts.getTupleIndex(); + + ImStmts stmts = JassIm.ImStmts(); + ImExpr result = null; - ImExprs exprs = JassIm.ImExprs(e); - for (int i = 1; i < tempVars.size(); i++) { - exprs.add(JassIm.ImVarAccess(tempVars.get(i))); + assert ti >= 0; + if (ti >= tupleExpr.getExprs().size()) { + throw new RuntimeException("invalid selection: " + ts); + } + for (int i = 0; i < tupleExpr.getExprs().size(); i++) { + ImExpr te = tupleExpr.getExprs().get(i); + de.peeeq.wurstscript.ast.Element trace = te.attrTrace(); + te.setParent(null); + if (i != ti) { + // if not the thing we want to return, just keep it in statements for side-effects + extractSideEffect(te, stmts); + } else { // if it is the part we want to return ... + result = extractSideEffect(te, stmts); } - ImExpr newExpr = JassIm.ImTupleExpr(exprs); - parent.set(parentIndex, newExpr); } - e.setTuplesEliminated(true); - e.clearAttributes(); + assert result != null; + ImStatementExpr replacement1 = JassIm.ImStatementExpr(stmts, result); + ImLExpr replacement2 = normalizeStatementExpr(replacement1, tr); + if (replacement2 == null) { + ts.replaceBy(replacement1); + } else { + ts.replaceBy(replacement2); + } } - }); } - - private static ImType getFirstType(ImType t) { - if (t instanceof ImTupleType) { - ImTupleType tt = (ImTupleType) t; - return getFirstType(tt.getTypes().get(0)); - } - return t; + interface Step { + void apply(ImStmts e, ImTranslator t, ImFunction f); } - private static void transformStatements(ImFunction f, ImStmts stmts, - ImTranslator translator) { - ListIterator it = stmts.listIterator(); - while (it.hasNext()) { - ImStmt s = it.next(); - ImStmt newS = s.eliminateTuples(translator, f); - if (newS instanceof ImStatementExpr) { - ImStatementExpr se = (ImStatementExpr) newS; - if (se.getExpr() instanceof ImTupleExpr) { - ImTupleExpr t = (ImTupleExpr) se.getExpr(); - ImStmts tupleExprs = JassIm.ImStmts(); - tupleExprs.addAll(t.getExprs().removeAll()); - newS = JassIm.ImStatementExpr(tupleExprs, JassIm.ImNull()); - } - } - if (newS != s) { - // element changed, replace it - it.set(newS); - } + private static void tryStep(ImFunction f, final ImTranslator translator, Step step) { + String before = f.toString(); + try { + step.apply(f.getBody(), translator, f); +// translator.assertProperties(Collections.emptySet(), f.getBody()); + } catch (Throwable t) { + throw new RuntimeException("\n//// Before -----------\n" + before + + "\n\n// After -------------------\n" + f, t); } + } - private static void transformVars(ImVars vars, ImTranslator translator) { + + private static Runnable transformVars(ImVars vars, ImTranslator translator) { + List varsToRemove = new ArrayList<>(); ListIterator it = vars.listIterator(); while (it.hasNext()) { ImVar v = it.next(); Preconditions.checkNotNull(v.getParent(), "null parent: " + v); - if (v.getType() instanceof ImTupleType || v.getType() instanceof ImTupleArrayType) { - ImmutableTree varsForTuple = translator.getVarsForTuple(v); - it.remove(); + if (TypesHelper.typeContainsTuples(v.getType())) { + VarsForTupleResult varsForTuple = translator.getVarsForTuple(v); + varsToRemove.add(v); for (ImVar nv : varsForTuple.allValues()) { it.add(nv); } } } - for (ImVar v : vars) { - if (v.getType() instanceof ImTupleType || v.getType() instanceof ImTupleArrayType) { - throw new Error("still contains a bad var: " + v + " in: \n" + v.getParent().getParent()); - } - } + return () -> vars.removeAll(varsToRemove); } - /** - * eliminates tuples in all subexpressions. - * Use this for all ast-elements which are not directly related to tuple-elimination - */ - public static T eliminateTuples2(T e, ImTranslator translator, ImFunction f) { - for (int i = 0; i < e.size(); i++) { - Element c = e.get(i); - Element newC = eliminateTuplesDispatch(c, translator, f); - if (newC != c) { - e.set(i, newC); - } - } - return e; - } - - private static Element eliminateTuplesDispatch(Element e, - ImTranslator translator, ImFunction f) { - if (e instanceof ImExprOpt) { - ImExprOpt imExprOpt = (ImExprOpt) e; - return imExprOpt.eliminateTuplesExprOpt(translator, f); - } else if (e instanceof ImStmt) { - ImStmt stmt = (ImStmt) e; - return stmt.eliminateTuples(translator, f); - } else if (e instanceof ImStmts) { - ImStmts stmts = (ImStmts) e; - transformStatements(f, stmts, translator); - return stmts; - } - return eliminateTuples2(e, translator, f); - } - - - public static ImStmt eliminateTuples(ImExitwhen e, ImTranslator translator, ImFunction f) { - return eliminateTuples2(e, translator, f); - } - public static ImStmt eliminateTuples(ImIf e, ImTranslator translator, ImFunction f) { - return eliminateTuples2(e, translator, f); - } - - public static ImStmt eliminateTuples(ImLoop e, ImTranslator translator, ImFunction f) { - return eliminateTuples2(e, translator, f); - } - - public static ImStmt eliminateTuples(ImExpr e, ImTranslator translator, ImFunction f) { - ImExpr e2 = e.eliminateTuplesExpr(translator, f); - if (e2 instanceof ImTupleExpr) { - ImTupleExpr te = (ImTupleExpr) e2; - ImStmts stmts = JassIm.ImStmts(); - stmts.addAll(te.getExprs().removeAll()); - return JassIm.ImStatementExpr(stmts, JassIm.ImNull()); + private static ImType getFirstType(ImType t) { + if (t instanceof ImTupleType) { + ImTupleType tt = (ImTupleType) t; + return getFirstType(tt.getTypes().get(0)); } - return e2; + return t; } - public static ImStmt eliminateTuples(ImSet e, ImTranslator translator, ImFunction f) { - // TODO I think the whole thing can be made much simpler - ImStmts statements = JassIm.ImStmts(); - ImmutableTree vars = translator.getVarsForTuple(e.getLeft()); - if (vars.size() == 0) { - // void expression, only keep right hand side - return copyExpr(e.getRight().eliminateTuplesExpr(translator, f)); - } if (vars.size() == 1) { // TODO do this only if it is a leaf - ImExpr newExpr = copyExpr(e.getRight().eliminateTuplesExpr(translator, f)); - newExpr = elimStatementExpr(statements, newExpr, translator, f); - if (newExpr instanceof ImTupleExpr) { - ImTupleExpr te = (ImTupleExpr) newExpr; - if (te.getExprs().size() > 1) { - throw new Error(); + /** + * 1. replace tuples with tuple-expression + *

+ * - Variable access + * a --> + * - Function calls + * f() --> + * - Tuple selections + * .2 --> {e_1; temp = e_2; e_3 >> temp} + * .3 --> {e_1; e_2 >> e_3} + * - ... + */ + private static void toTupleExpressions(ImStmts body, ImTranslator translator, ImFunction f) { + body.accept(new Element.DefaultVisitor() { + @Override + public void visit(ImVarAccess va) { + if (va.attrTyp() instanceof ImTupleType) { + ImVar v = va.getVar(); + VarsForTupleResult vars = translator.getVarsForTuple(v); + ImExpr expr = vars.map( + parts -> JassIm.ImTupleExpr( + parts.collect(Collectors.toCollection(JassIm::ImExprs))), + JassIm::ImVarAccess + ); + va.replaceBy(expr); } - newExpr = te.getExprs().remove(0); } - if (statements.size() > 0) { - statements.add(JassIm.ImSet(e.getTrace(), vars.getOnlyEment(), copyExpr(newExpr))); - return JassIm.ImStatementExpr(statements, JassIm.ImNull()); - } else { - e.setLeft(vars.getOnlyEment()); - newExpr.setParent(null); - e.setRight(newExpr); - return e; - } - } + @Override + public void visit(ImVarArrayAccess va) { + super.visit(va); + if (va.attrTyp() instanceof ImTupleType) { + ImExprs indexes = va.getIndexes(); + ImExprs indexExprs = JassIm.ImExprs(); + ImStmts stmts = JassIm.ImStmts(); + boolean sideEffects = indexes.stream().anyMatch(SideEffectAnalyzer::quickcheckHasSideeffects); + for (ImExpr ie : indexes) { + if (sideEffects) { + // use temp variables if there are side effects + ImVar tempIndex = JassIm.ImVar(ie.attrTrace(), TypesHelper.imInt(), "tempIndex", false); + indexExprs.add(JassIm.ImVarAccess(tempIndex)); + f.getLocals().add(tempIndex); + ie.setParent(null); + stmts.add(JassIm.ImSet(va.attrTrace(), JassIm.ImVarAccess(tempIndex), ie)); + } else { + ie.setParent(null); + indexExprs.add(ie); + } + } - ImExpr right1 = e.getRight().eliminateTuplesExpr(translator, f); - right1 = elimStatementExpr(statements, right1, translator, f); - if (right1 instanceof ImTupleExpr) { - ImTupleExpr right = (ImTupleExpr) right1; - ImExprs exprs = right.getExprs(); - int exprsSize = exprs.size(); - int varsSize = vars.size(); - if (exprsSize != varsSize) { - throw new Error(exprsSize + " != " + varsSize + " in " + e); - } - // TODO only use tempvars, when left hand side is used in the expression - List tempVars = Lists.newArrayList(); - ImmutableList varsList = vars.allValues(); - for (ImVar v : varsList) { - ImVar tempVar = v.copy(); - tempVar.setName("temp_" + tempVar.getName()); - tempVars.add(tempVar); + ImVar v = va.getVar(); + VarsForTupleResult vars = translator.getVarsForTuple(v); + ImExpr expr = vars.map( + parts -> JassIm.ImTupleExpr( + parts.collect(Collectors.toCollection(JassIm::ImExprs))), + var -> JassIm.ImVarArrayAccess(va.getTrace(), var, indexExprs.copy()) + ); + if (stmts.isEmpty()) { + va.replaceBy(expr); + } else { + va.replaceBy( + JassIm.ImStatementExpr(stmts, + expr)); + } + } } - f.getLocals().addAll(tempVars); - for (int i = 0; i < varsSize; i++) { - statements.add(JassIm.ImSet(e.getTrace(), tempVars.get(i), copyExpr(exprs.get(i)))); - } - for (int i = 0; i < tempVars.size(); i++) { - statements.add(JassIm.ImSet(e.getTrace(), varsList.get(i), JassIm.ImVarAccess(tempVars.get(i)))); - } - } else { - throw new Error("unhandled case: " + right1.getClass()); - } - return JassIm.ImStatementExpr(statements, JassIm.ImNull()); - } + @Override + public void visit(ImFunctionCall fc) { + super.visit(fc); + if (translator.getOriginalReturnValue(fc.getFunc()) instanceof ImTupleType) { + Element parent = fc.getParent(); + fc.setParent(null); - private static ImExpr copyExpr(ImExpr e) { - if (e.getParent() == null) { - return e; - } - return e.copy(); - } + VarsForTupleResult returnVars = translator.getTupleTempReturnVarsFor(fc.getFunc()); + ImVar firstVar = returnVars.allValuesStream().findFirst().get(); - public static ImStmt eliminateTuples(ImSetArray e, ImTranslator translator, ImFunction f) { - ImStmts statements = JassIm.ImStmts(); + ImExpr newFc = returnVars.map( + parts -> JassIm.ImTupleExpr( + parts.collect(Collectors.toCollection(JassIm::ImExprs))), + var -> var == firstVar + ? fc.copy() + : JassIm.ImVarAccess(var) + ); - ImmutableTree vars = translator.getVarsForTuple(e.getLeft()); - if (vars.size() == 1) { - ImExpr newExpr = copyExpr(e.getRight().eliminateTuplesExpr(translator, f)); - newExpr = elimStatementExpr(statements, newExpr, translator, f); - if (newExpr instanceof ImTupleExpr) { - ImTupleExpr te = (ImTupleExpr) newExpr; - if (te.getExprs().size() > 1) { - throw new Error(); + Utils.replace(parent, fc, newFc); } - newExpr = te.getExprs().remove(0); } - ImExpr indexExpr = copyExpr(e.getIndex().eliminateTuplesExpr(translator, f)); - if (statements.size() > 0) { - statements.add(JassIm.ImSetArray(e.getTrace(), - vars.getOnlyEment(), - indexExpr, - copyExpr(newExpr))); - return JassIm.ImStatementExpr(statements, JassIm.ImNull()); - } else { - e.setLeft(vars.getOnlyEment()); - e.setRight(copyExpr(newExpr)); - e.setIndex(copyExpr(indexExpr)); - return e; - } - } - // assign index to temporary variable - ImVar tempIndex = JassIm.ImVar(e.getTrace(), JassIm.ImSimpleType("integer"), "tempIndex", false); - f.getLocals().add(tempIndex); - statements.add(JassIm.ImSet(e.getTrace(), tempIndex, copyExpr(e.getIndex().eliminateTuplesExpr(translator, f)))); - - - ImExpr right1 = e.getRight().eliminateTuplesExpr(translator, f); - right1 = elimStatementExpr(statements, right1, translator, f); - if (right1 instanceof ImTupleExpr) { - ImTupleExpr right = (ImTupleExpr) right1; - ImExprs exprs = right.getExprs(); - int exprsSize = exprs.size(); - int varsSize = vars.size(); - ImmutableList allVars = vars.allValues(); - if (exprsSize != varsSize) { - throw new Error(exprsSize + " != " + varsSize); - } - for (int i = 0; i < varsSize; i++) { - statements.add(JassIm.ImSetArray(e.getTrace(), allVars.get(i), - JassIm.ImVarAccess(tempIndex), - copyExpr(exprs.get(i)))); - } - } else { - throw new Error("unhandled case: " + right1); - } - return JassIm.ImStatementExpr(statements, JassIm.ImNull()); + }); } - private static ImExpr elimStatementExpr(ImStmts statements, ImExpr expr, - ImTranslator translator, ImFunction f) { - while (expr instanceof ImStatementExpr) { - ImStatementExpr right = (ImStatementExpr) expr; - List ss = right.getStatements().removeAll(); - for (ImStmt s : ss) { - statements.add(s.eliminateTuples(translator, f)); - } - expr = right.getExpr(); - } - return expr; - } - public static ImStmt eliminateTuples(ImSetTuple e, ImTranslator translator, ImFunction f) { - ImVar left = e.getLeft(); - IntRange range = getTupleIndexRange((ImTupleType) left.getType(), e.getTupleIndex()); - ImmutableTree vars = translator.getVarsForTuple(left); - ImmutableList allVars = vars.allValues(); - - ImExpr expr = e.getRight().eliminateTuplesExpr(translator, f); - ImStmts statements = JassIm.ImStmts(); - expr = elimStatementExpr(statements, expr, translator, f); - int rangeSize = range.size(); - if (expr instanceof ImTupleExpr) { - ImTupleExpr tupleExpr = (ImTupleExpr) expr; - ImExprs exprs = tupleExpr.getExprs(); - int exprsSize = exprs.size(); - if (exprsSize != rangeSize) { - throw new Error(exprsSize + " != " + rangeSize); - } - List tempVars = Lists.newArrayList(); - for (ImVar v : allVars) { - ImVar tempVar = v.copy(); - tempVars.add(tempVar); - } - f.getLocals().addAll(tempVars); + /** + * Normalize Tuples in statement-expressions (move to first tuple param) + * {stmts >> } + * becomes <{stmts >> e1}, e2, e3} + */ + private static void normalizeTuplesInStatementExprs(ImStmts body, ImTranslator translator, ImFunction f) { + body.accept(new Element.DefaultVisitor() { - for (int i : range) { - ImExpr right = exprs.get(i - range.start); - statements.add(JassIm.ImSet(e.attrTrace(), tempVars.get(i), right)); - } - for (int i : range) { - statements.add(JassIm.ImSet(e.attrTrace(), allVars.get(i), JassIm.ImVarAccess(tempVars.get(i)))); - } - } else { - if (rangeSize > 1) { - throw new Error("range size was " + rangeSize); + @Override + public void visit(ImStatementExpr se) { + super.visit(se); + ImTupleExpr newExpr = normalizeStatementExpr(se, translator); + if (newExpr != null) { + se.replaceBy(newExpr); + newExpr.getExprs().get(0).accept(this); + } } - statements.add(JassIm.ImSet(e.attrTrace(), allVars.get(range.start), copyExpr(expr))); - } - return JassIm.ImStatementExpr(statements, JassIm.ImNull()); + }); } - public static ImStmt eliminateTuples(ImSetArrayTuple e, ImTranslator translator, ImFunction f) { - // TODO use tuple index - ImStmts statements = JassIm.ImStmts(); - // assign index to temporary variable - ImVar tempIndex = JassIm.ImVar(e.getTrace(), JassIm.ImSimpleType("integer"), "tempIndex", false); - f.getLocals().add(tempIndex); - statements.add(JassIm.ImSet(e.getTrace(), tempIndex, copyExpr(e.getIndex().eliminateTuplesExpr(translator, f)))); - - ImVar left = e.getLeft(); - IntRange range = getTupleIndexRange((ImTupleArrayType) left.getType(), e.getTupleIndex()); - ImmutableTree vars = translator.getVarsForTuple(left); - ImmutableList allVars = vars.allValues(); - - ImExpr expr = e.getRight().eliminateTuplesExpr(translator, f); - expr = elimStatementExpr(statements, expr, translator, f); - int rangeSize = range.size(); - if (expr instanceof ImTupleExpr) { - ImTupleExpr tupleExpr = (ImTupleExpr) expr; - ImExprs exprs = tupleExpr.getExprs(); - int exprsSize = exprs.size(); - if (exprsSize != rangeSize) { - throw new Error(exprsSize + " != " + rangeSize); - } - for (int i : range) { - statements.add(JassIm.ImSetArray(e.attrTrace(), - allVars.get(i), - JassIm.ImVarAccess(tempIndex), - exprs.get(i - range.start))); - } - } else { - if (rangeSize > 1) { - throw new Error("range size was " + rangeSize); - } - statements.add(JassIm.ImSetArray(e.attrTrace(), - allVars.get(range.start), - JassIm.ImVarAccess(tempIndex), - copyExpr(expr))); + private static ImTupleExpr normalizeStatementExpr(ImStatementExpr se, ImTranslator translator) { + if (se.getExpr() instanceof ImTupleExpr) { + ImTupleExpr te = (ImTupleExpr) se.getExpr(); + translator.assertProperties(Collections.emptySet(), te); + ImStmts seStmts = se.getStatements(); + seStmts.setParent(null); + ImExpr firstExpr = te.getExprs().remove(0); + ImStatementExpr newStatementExpr = JassIm.ImStatementExpr(seStmts, firstExpr); + te.getExprs().add(0, newStatementExpr); + te.setParent(null); + translator.assertProperties(Collections.emptySet(), te.getExprs()); + return te; } - return JassIm.ImStatementExpr(statements, JassIm.ImNull()); + return null; } - public static ImExprOpt eliminateTuplesExpr(ImNoExpr e, ImTranslator translator, ImFunction f) { - return e; - } - - - public static ImExpr eliminateTuplesExpr(ImTupleExpr e, ImTranslator translator, ImFunction f) { - ListIterator it = e.getExprs().listIterator(); - while (it.hasNext()) { - ImExpr expr = it.next(); - ImExpr newExpr = expr.eliminateTuplesExpr(translator, f); - if (newExpr instanceof ImTupleExpr) { - ImTupleExpr te = (ImTupleExpr) newExpr; - it.remove(); - for (ImExpr child : te.getExprs()) { - it.add(copyExpr(child)); + /** + * Remove tuple expressions + * - In parameters: Just flatten + * - Assignments: Become several assignments + * - In Return: Use temp returns + */ + private static void removeTupleExprs(Element elem, ImTranslator translator, ImFunction f) { + if (elem.getParent() == null) { + throw new RuntimeException("elem not used: " + elem); + } + for (int i = 0; i < elem.size(); i++) { + Element child = elem.get(i); + removeTupleExprs(child, translator, f); + } + for (int i = 0; i < elem.size(); i++) { + Element child = elem.get(i); + + if (child instanceof ImTupleExpr) { + ImTupleExpr tupleExpr = (ImTupleExpr) child; + + Element newElem; + if (elem instanceof ImTupleSelection) { + newElem = inTupleSelection((ImTupleSelection) elem, tupleExpr, f); + } else if (elem instanceof ImReturn) { + newElem = inReturn((ImReturn) elem, tupleExpr, translator, f); + } else if (elem instanceof ImSet) { + ImSet imSet = (ImSet) elem; + newElem = inSet(imSet, f); + } else if (elem instanceof ImExprs) { + ImExprs exprs = (ImExprs) elem; + if (exprs.getParent() instanceof ImOperatorCall) { + ImOperatorCall opCall = (ImOperatorCall) exprs.getParent(); + handleTupleInOpCall(opCall); + return; + } else { + // in function arguments, other tuples + // just flatten tuples + exprs.remove(i); + List tupleExprs = tupleExpr.getExprs().removeAll(); + exprs.addAll(i, tupleExprs); + i--; + } + continue; + } else if (elem instanceof ImStmts) { + ImStmts stmts = (ImStmts) elem; + stmts.remove(i); + List tupleExprs = tupleExpr.getExprs().removeAll(); + stmts.addAll(i, tupleExprs); + i--; + continue; + } else { + throw new CompileError(tupleExpr.attrTrace().attrSource(), "Unhandled tuple position: " + elem.getClass().getSimpleName() + " // " + elem); } - } else if (newExpr != expr) { - it.set(newExpr); - } - } - if (e.getExprs().size() == 1) { - ImExpr r = e.getExprs().get(0); - r.setParent(null); - return r; - } - return e; - } + elem.replaceBy(newElem); + // since we replaced elem we are done + // the new element should have no more tuple expressions - public static ImExpr eliminateTuplesExpr(ImTupleSelection e, ImTranslator translator, ImFunction f) { -// System.out.println("selecting " + e.getTupleIndex() + " from " + e.getTupleExpr()); - IntRange range; - -// WLogger.info("tuple selection = " + e); - if (e.getTupleExpr() instanceof ImVarAccess) { - ImVarAccess varAccess = (ImVarAccess) e.getTupleExpr(); - if (varAccess.attrTyp() instanceof ImTupleType) { - ImTupleType tt = (ImTupleType) varAccess.attrTyp(); - range = getTupleIndexRange(tt, e.getTupleIndex()); -// System.out.println("range = " + range); - } else { - throw new Error("problem with " + varAccess + "\n" + - "has type " + varAccess.attrTyp()); - } - ImVar v = varAccess.getVar(); - ImmutableTree vars = translator.getVarsForTuple(v); - ImmutableList allVars = vars.allValues(); // TODO probably should not use allVars and do this differently -// WLogger.info("is a var, selecting range " + range + " from vars " + vars); - if (range.size() == 1) { - return JassIm.ImVarAccess(allVars.get(range.start)); - } else { - ImExprs exprs = JassIm.ImExprs(); - for (int i : range) { - exprs.add(JassIm.ImVarAccess(allVars.get(i))); - } - return JassIm.ImTupleExpr(exprs); + return; } - } - ImExpr tupleExpr = e.getTupleExpr().eliminateTuplesExpr(translator, f); -// System.out.println("translated: " + tupleExpr); -// System.out.println("back to selecting " + e.getTupleIndex() + " from " + e.getTupleExpr()); - if (tupleExpr.attrTyp() instanceof ImTupleType) { - ImTupleType tt = (ImTupleType) tupleExpr.attrTyp(); - range = getTupleIndexRange(tt, e.getTupleIndex()); -// System.out.println("tupleExpr-range: " + range); - } else { - if (e.getTupleIndex() == 0) { - return tupleExpr.copy(); - } - throw new CompileError(e.attrTrace().attrSource(), "problem with " + tupleExpr + "\n" + - "has type " + tupleExpr.attrTyp()); } + } - ImVar tempVar = JassIm.ImVar(e.attrTrace(), tupleExpr.attrTyp(), "tempTupleSelectionResult", false); - ImmutableTree vars = translator.getVarsForTuple(tempVar); - ImmutableList allVars = vars.allValues(); - f.getLocals().addAll(allVars); + private static void handleTupleInOpCall(ImOperatorCall opCall) { + if (opCall.getParent() == null) { + throw new RuntimeException("opCall not used: " + opCall); + } + ImTupleExpr left = (ImTupleExpr) opCall.getArguments().get(0); + ImTupleExpr right = (ImTupleExpr) opCall.getArguments().get(1); + WurstOperator op = opCall.getOp(); - ImStmts statements = JassIm.ImStmts(); - statements.add( - JassIm.ImSet(tupleExpr.attrTrace(), tempVar, copyExpr(tupleExpr)) - .eliminateTuples(translator, f) - ); + List componentComparisons = new ArrayList<>(); + for (int i = 0; i < left.getExprs().size(); i++) { + ImExpr l = left.getExprs().get(i); + ImExpr r = right.getExprs().get(i); + l.setParent(null); + r.setParent(null); + componentComparisons.add(JassIm.ImOperatorCall(op, JassIm.ImExprs(l, r))); + } - ImExpr result; - if (range.size() == 1) { - result = JassIm.ImVarAccess(allVars.get(range.start)); + ImExpr newExpr; + if (op == WurstOperator.EQ) { + // (x1,y1,z1) == (x2,y2,z2) + // ==> x1 == x2 && y1 == y2 && z1 == z2 + newExpr = componentComparisons.stream() + .reduce((l, r) -> JassIm.ImOperatorCall(WurstOperator.AND, JassIm.ImExprs(l, r))) + .get(); } else { - ImExprs exprs = JassIm.ImExprs(); - for (int i : range) { -// System.out.println("adding range ." + i); - exprs.add(JassIm.ImVarAccess(allVars.get(i))); - } - result = JassIm.ImTupleExpr(exprs); + assert op == WurstOperator.NOTEQ; + // (x1,y1,z1) == (x2,y2,z2) + // ==> x1 != x2 || y1 != y2 && z1 != z2 + newExpr = componentComparisons.stream() + .reduce((l, r) -> JassIm.ImOperatorCall(WurstOperator.OR, JassIm.ImExprs(l, r))) + .get(); } - - - return JassIm.ImStatementExpr(statements, result); + opCall.replaceBy(newExpr); } - private static IntRange getTupleIndexRange(ElementWithTypes tt, int index) { -// System.out.println("get tuple index range " + tt + " # " + index); - int start = 0; - for (int i = 0; i < index; i++) { - ImType t = tt.getTypes().get(i); - start += getTypeSize(t); + private static ImStatementExpr inSet(ImSet imSet, ImFunction f) { + if (!(imSet.getLeft() instanceof ImTupleExpr && imSet.getRight() instanceof ImTupleExpr)) { + throw new RuntimeException("invalid set statement:\n" + imSet); } - int end = start + getTypeSize(tt.getTypes().get(index)); -// System.out.println("result = " + start + "..<" + end); - return new IntRange(start, end); - } - - private static int getTypeSize(ImType imType) { - return imType.match(new ImType.Matcher() { + ImTupleExpr left = (ImTupleExpr) imSet.getLeft(); + ImTupleExpr right = (ImTupleExpr) imSet.getRight(); - @Override - public Integer case_ImTupleArrayType( - ImTupleArrayType tt) { - int sum = 0; - for (ImType t : tt.getTypes()) { - sum += getTypeSize(t); - } - return sum; - } - - @Override - public Integer case_ImSimpleType(ImSimpleType t) { - return 1; - } - - @Override - public Integer case_ImVoid(ImVoid t) { - return 0; - } - - @Override - public Integer case_ImArrayType(ImArrayType t) { - return 1; - } - - @Override - public Integer case_ImTupleType(ImTupleType tt) { - int sum = 0; - for (ImType t : tt.getTypes()) { - sum += getTypeSize(t); - } - return sum; - } - - @Override - public Integer case_ImArrayTypeMulti( - ImArrayTypeMulti imArrayTypeMulti) { - return 1; - } + ImStmts stmts = JassIm.ImStmts(); + // 1) extract side effects from left expressions + List leftExprs = new ArrayList<>(); + for (ImExpr expr : left.getExprs()) { + leftExprs.add(extractSideEffect(expr, stmts)); + } - }); - } - public static ImExpr eliminateTuplesExpr(ImVarAccess e, ImTranslator translator, ImFunction f) { - ImVar v = e.getVar(); - ImmutableTree varsForTuple = translator.getVarsForTuple(v); - if (varsForTuple.size() > 1 || varsForTuple.getOnlyEment() != v) { - return makeVarAccessToTuple(varsForTuple); + List tempVars = new ArrayList<>(); + // 2) assign right hand side to temporary variables: + for (ImExpr expr : right.getExprs()) { + ImVar temp = JassIm.ImVar(expr.attrTrace(), expr.attrTyp(), "tuple_temp", false); + expr.setParent(null); + stmts.add(JassIm.ImSet(expr.attrTrace(), JassIm.ImVarAccess(temp), expr)); + tempVars.add(temp); + f.getLocals().add(temp); } - return eliminateTuples2(e, translator, f); - } - - private static ImExpr makeVarAccessToTuple(ImmutableTree varsForTuple) { - if (varsForTuple.isLeaf()) { - return JassIm.ImVarAccess(varsForTuple.getOnlyEment()); - } else { - ImExprs exprs = JassIm.ImExprs(); - for (ImmutableTree t : varsForTuple) { - exprs.add(makeVarAccessToTuple(t)); - } - return JassIm.ImTupleExpr(exprs); + // then assign right vars + for (int i = 0; i < leftExprs.size(); i++) { + ImLExpr leftE = (ImLExpr) leftExprs.get(i); + leftE.setParent(null); + stmts.add(JassIm.ImSet(imSet.getTrace(), leftE, JassIm.ImVarAccess(tempVars.get(i)))); } + return JassIm.ImStatementExpr(stmts, JassIm.ImNull()); } + private static ImStatementExpr inReturn(ImReturn parent, ImTupleExpr tupleExpr, ImTranslator translator, ImFunction f) { + VarsForTupleResult returnVars1 = translator.getTupleTempReturnVarsFor(f); + List returnVars = returnVars1.allValuesStream().collect(Collectors.toList()); + ImStmts stmts = JassIm.ImStmts(); - public static ImExpr eliminateTuplesExpr(ImVarArrayAccess e, ImTranslator translator, ImFunction f) { - ImVar v = e.getVar(); - ImmutableTree varsForTuple = translator.getVarsForTuple(v); - if (varsForTuple.size() > 1 || varsForTuple.getOnlyEment() != v) { - ImVar tempIndex = JassIm.ImVar(e.attrTrace(), e.getIndex().attrTyp(), "tempIndex", false); - f.getLocals().add(tempIndex); - - ImStmts statements = JassIm.ImStmts(JassIm.ImSet(e.attrTrace(), tempIndex, copyExpr(e.getIndex().eliminateTuplesExpr(translator, f)))); - ImExpr tupleExpr = makeArrayAccessToTuple(varsForTuple, tempIndex); - return JassIm.ImStatementExpr(statements, tupleExpr); + for (int i = 0; i < returnVars.size(); i++) { + ImVar rv = returnVars.get(i); + ImExpr te = tupleExpr.getExprs().get(i); + te.setParent(null); + stmts.add(JassIm.ImSet(parent.getTrace(), JassIm.ImVarAccess(rv), te)); } - return eliminateTuples2(e, translator, f); - } + stmts.add(JassIm.ImReturn(parent.getTrace(), JassIm.ImVarAccess(returnVars.get(0)))); - private static ImExpr makeArrayAccessToTuple(ImmutableTree varsForTuple, ImVar tempIndex) { - if (varsForTuple.isLeaf()) { - return JassIm.ImVarArrayAccess(varsForTuple.getOnlyEment(), JassIm.ImVarAccess(tempIndex)); - } else { - ImExprs exprs = JassIm.ImExprs(); - for (ImmutableTree t : varsForTuple) { - exprs.add(makeArrayAccessToTuple(t, tempIndex)); - } - return JassIm.ImTupleExpr(exprs); - } + return JassIm.ImStatementExpr(stmts, JassIm.ImNull()); } - public static ImExpr eliminateTuplesExpr(ImConst e, ImTranslator translator, ImFunction f) { - // constants cannot contain tuples and thus do not change - return e; - } + private static Element inTupleSelection(ImTupleSelection ts, ImTupleExpr tupleExpr, ImFunction f) { + assert ts.getTupleExpr() == tupleExpr; - public static ImExpr eliminateTuplesExpr(ImStatementExpr imStatementExpr, - ImTranslator translator, ImFunction f) { - ImStatementExpr e = eliminateTuples2(imStatementExpr, translator, f); - if (e.getExpr() instanceof ImStatementExpr) { - ImStatementExpr se = (ImStatementExpr) e.getExpr(); - e.getStatements().addAll(se.getStatements().removeAll()); - ImExpr see = se.getExpr(); - see.setParent(null); - e.setExpr(see); - } - return e; - } + int ti = ts.getTupleIndex(); + ImStmts stmts = JassIm.ImStmts(); + ImExpr result = null; - public static ImExpr eliminateTuplesExpr(ImFunctionCall e, ImTranslator translator, ImFunction f) { - // eliminate tuple expressions in arguments - eliminateTuplesInArgs(e, translator, f); - return e; - } - public static ImExpr eliminateTuplesExpr(ImOperatorCall e, ImTranslator translator, ImFunction f) { - // eliminate tuple expressions in arguments - eliminateTuplesInArgs(e, translator, f); - - if (e.getArguments().size() > 2) { - List arguments = e.getArguments().removeAll(); - int size = arguments.size() / 2; - WurstOperator logicOp; - WurstOperator compareOp = e.getOp(); - if (compareOp == WurstOperator.EQ) { - logicOp = WurstOperator.AND; - } else if (compareOp == WurstOperator.NOTEQ) { - logicOp = WurstOperator.OR; - } else { - throw new Error("unsupported tuple operator " + e); - } - ImExpr result = null; - for (int i = 0; i < size; i++) { - ImExpr left = arguments.get(i); - ImExpr right = arguments.get(size + i); - ImOperatorCall comparison = JassIm.ImOperatorCall(compareOp, JassIm.ImExprs(left, right)); - if (result == null) { - result = comparison; + for (int i = 0; i < tupleExpr.getExprs().size(); i++) { + ImExpr te = tupleExpr.getExprs().get(i); + de.peeeq.wurstscript.ast.Element trace = te.attrTrace(); + te.setParent(null); + if (i != ti) { + // if not the thing we want to return, just keep it in statements for side-effects + stmts.add(te); + } else { // if it is the part we want to return ... + if (i == tupleExpr.getExprs().size() - 1) { + // last expression of tuple + result = te; } else { - result = JassIm.ImOperatorCall(logicOp, JassIm.ImExprs(result, comparison)); - } - } - return result; - } - - return e; - } - - private static void eliminateTuplesInArgs(ImCall e, - ImTranslator translator, ImFunction f) { - ListIterator it = e.getArguments().listIterator(); - while (it.hasNext()) { - ImExpr arg = it.next(); - ImStmts stmts = JassIm.ImStmts(); - ImExpr newArg = arg.eliminateTuplesExpr(translator, f); - newArg = elimStatementExpr(stmts, newArg, translator, f); - if (newArg instanceof ImTupleExpr) { - ImTupleExpr te = (ImTupleExpr) newArg; - it.remove(); - int i = 0; - for (ImExpr child : te.getExprs()) { - ImExpr newArg2 = copyExpr(child); - if (i == 0 && !stmts.isEmpty()) { - newArg2 = JassIm.ImStatementExpr(stmts, newArg2); + if (ts.isUsedAsLValue()) { + // if this is used as L-value we cannot use temporary variables, so just + // use the current expression as result. + // This assumes that the expression te cannot be influenced by subsequent expressions + // TODO maybe this assumption should be validated ... + result = extractSideEffect(te, stmts); + } else { + ImVar temp = JassIm.ImVar(trace, te.attrTyp(), "tupleSelection", false); + f.getLocals().add(temp); + stmts.add(JassIm.ImSet(trace, JassIm.ImVarAccess(temp), te)); + result = JassIm.ImVarAccess(temp); } - it.add(newArg2); - i++; } - } else if (newArg != arg) { - if (!stmts.isEmpty()) { - newArg = JassIm.ImStatementExpr(stmts, copyExpr(newArg)); - } - it.set(copyExpr(newArg)); } } + assert result != null; + + return JassIm.ImStatementExpr(stmts, result); } - public static ImStmt eliminateTuples(ImReturn e, ImTranslator translator, ImFunction f) { - ImExprOpt ret1 = e.getReturnValue().eliminateTuplesExprOpt(translator, f); - if (ret1 instanceof ImNoExpr) { - // returns nothing - return e; - } - ImExpr ret = (ImExpr) ret1; - ImStmts statements = JassIm.ImStmts(); - ImExpr retExpr = elimStatementExpr(statements, ret, translator, f); - ImExpr result; - if (retExpr instanceof ImTupleExpr) { - ImTupleExpr te = (ImTupleExpr) retExpr; - List tempReturnVars = translator.getTupleTempReturnVarsFor(f); - if (tempReturnVars.size() == 1) { - result = copyExpr(te.getExprs().get(0)); - } else { - for (int i = 0; i < tempReturnVars.size(); i++) { - statements.add(JassIm.ImSet(e.getTrace(), - tempReturnVars.get(i), - copyExpr(te.getExprs().get(i)))); - } - result = JassIm.ImVarAccess(tempReturnVars.get(0)); + /** + * extracts all side effects into the list of statements + */ + private static ImExpr extractSideEffect(ImExpr e, List into) { + if (e instanceof ImStatementExpr) { + ImStatementExpr se = (ImStatementExpr) e; + for (ImStmt s : se.getStatements()) { + s.setParent(null); + into.add(s); } - } else { - result = copyExpr(retExpr); + ImExpr expr = se.getExpr(); + expr.setParent(null); + return extractSideEffect(expr, into); } - statements.add(JassIm.ImReturn(e.attrTrace(), result)); - return JassIm.ImStatementExpr(statements, JassIm.ImNull()); - } - - - public static ImExpr eliminateTuplesExpr(ImClassRelatedExpr e, - ImTranslator translator, ImFunction f) { - throw new RuntimeException("Must execute method elemination first."); - } - - - public static ImStmt eliminateTuples(ImSetArrayMulti imSetArrayMulti, - ImTranslator translator, ImFunction f) { - throw new Error("not implemented"); - } - - - public static ImExpr eliminateTuplesExpr( - ImVarArrayMultiAccess imVarArrayMultiAccess, - ImTranslator translator, ImFunction f) { - throw new Error("not implemented"); - } - - - public static ImExpr eliminateTuplesExpr(ImGetStackTrace e, - ImTranslator translator, ImFunction f) { return e; } - public static ImExpr eliminateTuplesExpr(ImCompiletimeExpr e, ImTranslator translator, ImFunction f) { - return eliminateTuples2(e, translator, f); + private static ImExprs accessVars(List tempIndexes) { + return tempIndexes.stream() + .map(JassIm::ImVarAccess) + .collect(Collectors.toCollection(JassIm::ImExprs)); } - public static ImStmt eliminateTuples(ImVarargLoop imVarargLoop, ImTranslator translator, ImFunction f) { - return imVarargLoop; - } + } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ExprTranslation.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ExprTranslation.java index 57204020f..a6904d0e5 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ExprTranslation.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ExprTranslation.java @@ -6,22 +6,16 @@ import de.peeeq.wurstscript.ast.Element; import de.peeeq.wurstscript.attributes.CompileError; import de.peeeq.wurstscript.attributes.names.NameLink; -import de.peeeq.wurstscript.attributes.prettyPrint.DefaultSpacer; -import de.peeeq.wurstscript.attributes.prettyPrint.PrettyPrinter; import de.peeeq.wurstscript.jassIm.ImClass; import de.peeeq.wurstscript.jassIm.*; import de.peeeq.wurstscript.jassIm.ImExprs; import de.peeeq.wurstscript.jassIm.ImFunction; import de.peeeq.wurstscript.jassIm.ImMethod; import de.peeeq.wurstscript.jassIm.ImStmts; -import de.peeeq.wurstscript.jassIm.ImTupleExpr; import de.peeeq.wurstscript.jassIm.ImVar; -import de.peeeq.wurstscript.translation.imtranslation.purity.Pure; -import de.peeeq.wurstscript.translation.imtranslation.purity.ReadsGlobals; import de.peeeq.wurstscript.types.*; import de.peeeq.wurstscript.utils.Utils; -import java.util.ArrayList; import java.util.List; import static de.peeeq.wurstscript.jassIm.JassIm.*; @@ -249,11 +243,11 @@ private static ImExpr translateNameDef(NameRef e, ImTranslator t, ImFunction f) if (e instanceof AstElementWithIndexes) { ImExpr index1 = implicitParam.imTranslateExpr(t, f); ImExpr index2 = ((AstElementWithIndexes) e).getIndexes().get(0).imTranslateExpr(t, f); - return JassIm.ImVarArrayMultiAccess(v, index1, index2); + return JassIm.ImVarArrayAccess(e, v, JassIm.ImExprs(index1, index2)); } else { ImExpr index = implicitParam.imTranslateExpr(t, f); - return ImVarArrayAccess(v, index); + return ImVarArrayAccess(e, v, JassIm.ImExprs(index)); } } else { // direct var access @@ -264,7 +258,7 @@ private static ImExpr translateNameDef(NameRef e, ImTranslator t, ImFunction f) throw new CompileError(e.getSource(), "More than one index is not supported."); } ImExpr index = withIndexes.getIndexes().get(0).imTranslateExpr(t, f); - return ImVarArrayAccess(v, index); + return ImVarArrayAccess(e, v, JassIm.ImExprs(index)); } else { // not an array var return ImVarAccess(v); @@ -280,6 +274,28 @@ private static ImExpr translateNameDef(NameRef e, ImTranslator t, ImFunction f) } } + private static ImExpr translateTupleSelection(ImTranslator t, ImFunction f, ExprMemberVar mv) { + ImExpr left = mv.getLeft().imTranslateExpr(t, f); + WParameter tupleParam = (WParameter) mv.attrNameDef(); + WParameters tupleParams = (WParameters) tupleParam.getParent(); + int tupleIndex = tupleParams.indexOf(tupleParam); + if (left instanceof ImLExpr) { + return ImTupleSelection((ImLExpr) left, tupleIndex); + } else { + // if tupleExpr is not an l-value (e.g. foo().x) + // store result in intermediate variable first: + ImVar v = ImVar(left.attrTrace(), left.attrTyp(), "temp_tuple", false); + f.getLocals().add(v); + return JassIm.ImStatementExpr( + JassIm.ImStmts( + ImSet(left.attrTrace(), ImVarAccess(v), left) + ), + ImTupleSelection(ImVarAccess(v), tupleIndex) + ); + } + } + + /* private static ImExpr translateTupleSelection(ImTranslator t, ImFunction f, ExprMemberVar mv) { List indexes = new ArrayList<>(); @@ -318,10 +334,11 @@ private static ImExpr translateTupleSelection(ImTranslator t, ImFunction f, Expr // if the result is a tuple, create it: int tupleSize = tupleSize(resultTupleType); - if (exprTr.attrPurity() instanceof Pure || exprTr.attrPurity() instanceof ReadsGlobals) { + if (exprTr instanceof ImLExpr + && (exprTr.attrPurity() instanceof Pure || exprTr.attrPurity() instanceof ReadsGlobals)) { ImExprs exprs = JassIm.ImExprs(); for (int i = 0; i < tupleSize; i++) { - exprs.add(ImTupleSelection((ImExpr) exprTr.copy(), tupleIndex + i)); + exprs.add(ImTupleSelection((ImLExpr) exprTr.copy(), tupleIndex + i)); } return ImTupleExpr(exprs); } else { @@ -334,13 +351,26 @@ private static ImExpr translateTupleSelection(ImTranslator t, ImFunction f, Expr // TODO use temporary var exprs.add(ImTupleSelection(JassIm.ImVarAccess(temp), tupleIndex + i)); } - return JassIm.ImStatementExpr(JassIm.ImStmts(JassIm.ImSet(expr, temp, exprTr)), ImTupleExpr(exprs)); + return JassIm.ImStatementExpr(JassIm.ImStmts(ImSet(expr, ImVarAccess(temp), exprTr)), ImTupleExpr(exprs)); } } else { - return ImTupleSelection(exprTr, tupleIndex); + if (exprTr instanceof ImLExpr) { + return ImTupleSelection((ImLExpr) exprTr, tupleIndex); + } else { + // if tupleExpr is not an l-value (e.g. foo().x) + // store result in intermediate variable first: + ImVar v = ImVar(exprTr.attrTrace(), exprTr.attrTyp(), "temp_tuple", false); + f.getLocals().add(v); + return JassIm.ImStatementExpr( + JassIm.ImStmts( + ImSet(exprTr.attrTrace(), ImVarAccess(v), exprTr) + ), + ImTupleSelection(ImVarAccess(v), tupleIndex) + ); + } } - } + */ /** * counts the components of a tuple (including nested) @@ -446,9 +476,7 @@ private static ImExpr translateFunctionCall(FunctionCall e, ImTranslator t, ImFu if (calledFunc instanceof TupleDef) { // creating a new tuple... - ImExprs tupleArgs = JassIm.ImExprs(); - flattenTupleArgs(tupleArgs, imArgs); - return ImTupleExpr(tupleArgs); + return ImTupleExpr(imArgs); } ImStmts stmts = null; @@ -458,7 +486,7 @@ private static ImExpr translateFunctionCall(FunctionCall e, ImTranslator t, ImFu throw new Error("impossible"); tempVar = JassIm.ImVar(leftExpr, leftExpr.attrTyp().imTranslateType(), "receiver", false); f.getLocals().add(tempVar); - stmts = JassIm.ImStmts(JassIm.ImSet(e, tempVar, receiver)); + stmts = JassIm.ImStmts(ImSet(e, ImVarAccess(tempVar), receiver)); receiver = JassIm.ImVarAccess(tempVar); } @@ -484,18 +512,6 @@ private static ImExpr translateFunctionCall(FunctionCall e, ImTranslator t, ImFu } } - private static void flattenTupleArgs(ImExprs tupleArgs, ImExprs imArgs) { - for (ImExpr e : imArgs.removeAll()) { - if (e instanceof ImTupleExpr) { - ImTupleExpr te = (ImTupleExpr) e; - flattenTupleArgs(tupleArgs, te.getExprs()); - } else { - tupleArgs.add(e); - } - } - - } - private static boolean isCalledOnDynamicRef(FunctionCall e) { if (e instanceof ExprMemberMethod) { ExprMemberMethod mm = (ExprMemberMethod) e; @@ -569,13 +585,10 @@ public static ImExpr translate(ExprStatementsBlock e, ImTranslator translator, I statements.add(translated); } - ImExprOpt expr = null; StmtReturn r = e.getReturnStmt(); if (r != null && r.getReturnedObj() instanceof Expr) { - expr = ((Expr) r.getReturnedObj()).imTranslateExpr(translator, f); - } - if (expr instanceof ImExpr) { - return JassIm.ImStatementExpr(statements, (ImExpr) expr); + ImExpr expr = ((Expr) r.getReturnedObj()).imTranslateExpr(translator, f); + return JassIm.ImStatementExpr(statements, expr); } else { return JassIm.ImStatementExpr(statements, JassIm.ImNull()); } @@ -617,13 +630,102 @@ public static ImExpr translate(ExprIfElse e, ImTranslator t, ImFunction f) { ImStmts( ImIf(e, e.getCond().imTranslateExpr(t, f), ImStmts( - ImSet(e.getIfTrue(), res, ifTrue) + ImSet(e.getIfTrue(), ImVarAccess(res), ifTrue) ), ImStmts( - ImSet(e.getIfFalse(), res, ifFalse) + ImSet(e.getIfFalse(), ImVarAccess(res), ifFalse) )) ), JassIm.ImVarAccess(res) ); } + + public static ImLExpr translateLvalue(LExpr e, ImTranslator t, ImFunction f) { + NameDef decl = e.attrNameDef(); + if (decl == null) { + // should only happen with gg_ variables + throw new CompileError(e.getSource(), "Translation Error: Could not find definition of " + e.getVarName() + "."); + } + if (decl instanceof VarDef) { + VarDef varDef = (VarDef) decl; + + ImVar v = t.getVarFor(varDef); + + if (e.attrImplicitParameter() instanceof Expr) { + // we have implicit parameter + // e.g. "someObject.someField" + Expr implicitParam = (Expr) e.attrImplicitParameter(); + + if (implicitParam.attrTyp() instanceof WurstTypeTuple) { + WurstTypeTuple tupleType = (WurstTypeTuple) implicitParam.attrTyp(); + if (e instanceof ExprMemberVar && ((ExprMemberVar) e).getLeft() instanceof LExpr) { + ExprMemberVar emv = (ExprMemberVar) e; + LExpr left = (LExpr) emv.getLeft(); + ImLExpr lt = left.imTranslateExprLvalue(t, f); + return JassIm.ImTupleSelection(lt, tupleType.getTupleIndex(varDef)); + } else { + throw new CompileError(e.getSource(), "Cannot create tuple access"); + } + } + + if (e instanceof AstElementWithIndexes) { + ImExpr index1 = implicitParam.imTranslateExpr(t, f); + ImExpr index2 = ((AstElementWithIndexes) e).getIndexes().get(0).imTranslateExpr(t, f); + return JassIm.ImVarArrayAccess(e, v, JassIm.ImExprs(index1, index2)); + + } else { + ImExpr index = implicitParam.imTranslateExpr(t, f); + return ImVarArrayAccess(e, v, JassIm.ImExprs(index)); + } + } else { + // direct var access + if (e instanceof AstElementWithIndexes) { + // direct access array var + AstElementWithIndexes withIndexes = (AstElementWithIndexes) e; + if (withIndexes.getIndexes().size() > 1) { + throw new CompileError(e.getSource(), "More than one index is not supported."); + } + ImExpr index = withIndexes.getIndexes().get(0).imTranslateExpr(t, f); + return ImVarArrayAccess(e, v, JassIm.ImExprs(index)); + } else { + // not an array var + return ImVarAccess(v); + + } + } + } else { + throw new CompileError(e.getSource(), "Cannot translate reference to " + Utils.printElement(decl)); + } + } + +// public static ImLExpr translateLvalue(ExprVarArrayAccess e, ImTranslator translator, ImFunction f) { +// NameDef nameDef = e.tryGetNameDef(); +// if (nameDef instanceof VarDef) { +// VarDef varDef = (VarDef) nameDef; +// ImVar v = translator.getVarFor(varDef); +// ImExprs indexes = e.getIndexes().stream() +// .map(ie -> ie.imTranslateExpr(translator, f)) +// .collect(Collectors.toCollection(JassIm::ImExprs)); +// return JassIm.ImVarArrayAccess(v, indexes); +// } +// throw new RuntimeException("TODO"); +// +// } +// +// public static ImLExpr translateLvalue(ExprMemberVar e, ImTranslator translator, ImFunction f) { +// ImExpr receiver = e.getLeft().imTranslateExpr(translator, f); +// NameDef nameDef = e.tryGetNameDef(); +// if (nameDef instanceof VarDef) { +// VarDef v = (VarDef) nameDef; +// ImVar imVar = translator.getVarFor(v); +// return JassIm.ImMemberAccess(receiver, imVar); +// } +// throw new RuntimeException("TODO"); +// } +// +// public static ImLExpr translateLvalue(ExprMemberArrayVar e, ImTranslator translator, ImFunction f) { +// throw new RuntimeException("TODO"); +// } + + } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/Flatten.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/Flatten.java index 164a90096..48d7b77f4 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/Flatten.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/Flatten.java @@ -1,5 +1,6 @@ package de.peeeq.wurstscript.translation.imtranslation; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import de.peeeq.wurstscript.WurstOperator; import de.peeeq.wurstscript.jassIm.*; @@ -10,14 +11,11 @@ import de.peeeq.wurstscript.jassIm.ImGetStackTrace; import de.peeeq.wurstscript.jassIm.ImIf; import de.peeeq.wurstscript.jassIm.ImLoop; +import de.peeeq.wurstscript.jassIm.ImMemberAccess; import de.peeeq.wurstscript.jassIm.ImOperatorCall; import de.peeeq.wurstscript.jassIm.ImProg; import de.peeeq.wurstscript.jassIm.ImReturn; import de.peeeq.wurstscript.jassIm.ImSet; -import de.peeeq.wurstscript.jassIm.ImSetArray; -import de.peeeq.wurstscript.jassIm.ImSetArrayMulti; -import de.peeeq.wurstscript.jassIm.ImSetArrayTuple; -import de.peeeq.wurstscript.jassIm.ImSetTuple; import de.peeeq.wurstscript.jassIm.ImStatementExpr; import de.peeeq.wurstscript.jassIm.ImStmts; import de.peeeq.wurstscript.jassIm.ImTupleExpr; @@ -25,7 +23,6 @@ import de.peeeq.wurstscript.jassIm.ImVar; import de.peeeq.wurstscript.jassIm.ImVarAccess; import de.peeeq.wurstscript.jassIm.ImVarArrayAccess; -import de.peeeq.wurstscript.jassIm.ImVarArrayMultiAccess; import de.peeeq.wurstscript.jassIm.ImVarargLoop; import de.peeeq.wurstscript.translation.imtranslation.purity.Pure; import de.peeeq.wurstscript.types.WurstTypeBool; @@ -65,9 +62,9 @@ public static class Result { final List stmts; final ImExpr expr; - public Result(List stmts, ImExpr epxr) { + public Result(List stmts, ImExpr expr) { this.stmts = stmts; - this.expr = epxr; + this.expr = expr; } public Result(ImExpr epxr) { @@ -85,6 +82,32 @@ public void intoStatements(List result, ImTranslator t, ImFunction f) { exprToStatements(result, expr, t, f); } + public List getStmts() { + return stmts; + } + + public ImExpr getExpr() { + return expr; + } + + public ImStatementExpr toStatementExpr() { + return JassIm.ImStatementExpr(JassIm.ImStmts(stmts), expr); + } + } + + public static class ResultL extends Result { + public ResultL(List stmts, ImLExpr expr) { + super(stmts, expr); + } + + public ResultL(ImLExpr expr) { + super(expr); + } + + @Override + public ImLExpr getExpr() { + return (ImLExpr) super.getExpr(); + } } public static class MultiResult { @@ -102,6 +125,22 @@ public ImExpr expr(int i) { return exprs.get(i); } + } + + public static class MultiResultL extends MultiResult { + + public MultiResultL(List stmts, List exprs) { + super(stmts, ImmutableList.copyOf(exprs)); + } + + public ImLExpr expr(int i) { + return (ImLExpr) super.expr(i); + } + + public List getLExprs() { + //noinspection unchecked,rawtypes + return (List) exprs; + } } @@ -195,32 +234,14 @@ public static Result flatten(ImReturn s, ImTranslator t, ImFunction f) { public static Result flatten(ImSet s, ImTranslator t, ImFunction f) { - Result e = s.getRight().flatten(t, f); - List stmts = Lists.newArrayList(e.stmts); - stmts.add(JassIm.ImSet(s.getTrace(), s.getLeft(), e.expr)); - return new Result(stmts); - } - - - public static Result flatten(ImSetTuple s, ImTranslator t, ImFunction f) { - Result e = s.getRight().flatten(t, f); - List stmts = Lists.newArrayList(e.stmts); - stmts.add(ImSetTuple(s.getTrace(), s.getLeft(), s.getTupleIndex(), e.expr)); + Result l = s.getLeft().flatten(t, f); + Result r = s.getRight().flatten(t, f); + List stmts = Lists.newArrayList(l.stmts); + stmts.addAll(r.stmts); + stmts.add(JassIm.ImSet(s.getTrace(), (ImLExpr) l.expr, r.expr)); return new Result(stmts); } - public static Result flatten(ImSetArray s, ImTranslator t, ImFunction f) { - MultiResult res = flattenExprs(t, f, s.getIndex(), s.getRight()); - res.stmts.add(JassIm.ImSetArray(s.getTrace(), s.getLeft(), res.expr(0), res.expr(1))); - return new Result(res.stmts); - } - - public static Result flatten(ImSetArrayTuple s, ImTranslator t, ImFunction f) { - MultiResult res = flattenExprs(t, f, s.getIndex(), s.getRight()); - res.stmts.add(JassIm.ImSetArrayTuple(s.getTrace(), s.getLeft(), res.expr(0), s.getTupleIndex(), res.expr(1))); - return new Result(res.stmts); - } - public static Result flatten(ImFunctionCall e, ImTranslator t, ImFunction f) { MultiResult r = flattenExprs(t, f, e.getArguments()); @@ -244,9 +265,9 @@ public static Result flatten(ImOperatorCall e, ImTranslator t, ImFunction f) { ImStmts thenBlock = JassIm.ImStmts(); // if left is true then check right thenBlock.addAll(right.stmts); - thenBlock.add(JassIm.ImSet(trace, tempVar, right.expr)); + thenBlock.add(ImSet(trace, ImVarAccess(tempVar), right.expr)); // else the result is false - ImStmts elseBlock = JassIm.ImStmts(JassIm.ImSet(trace, tempVar, JassIm.ImBoolVal(false))); + ImStmts elseBlock = JassIm.ImStmts(ImSet(trace, ImVarAccess(tempVar), JassIm.ImBoolVal(false))); stmts.add(ImIf(trace, left.expr, thenBlock, elseBlock)); return new Result(stmts, JassIm.ImVarAccess(tempVar)); } @@ -262,11 +283,11 @@ public static Result flatten(ImOperatorCall e, ImTranslator t, ImFunction f) { ImVar tempVar = JassIm.ImVar(trace, WurstTypeBool.instance().imTranslateType(), "andLeft", false); f.getLocals().add(tempVar); // if left is true then result is ture - ImStmts thenBlock = JassIm.ImStmts(JassIm.ImSet(trace, tempVar, JassIm.ImBoolVal(true))); + ImStmts thenBlock = JassIm.ImStmts(ImSet(trace, ImVarAccess(tempVar), JassIm.ImBoolVal(true))); // else check right ImStmts elseBlock = JassIm.ImStmts(); elseBlock.addAll(right.stmts); - elseBlock.add(JassIm.ImSet(trace, tempVar, right.expr)); + elseBlock.add(ImSet(trace, ImVarAccess(tempVar), right.expr)); stmts.add(ImIf(trace, left.expr, thenBlock, elseBlock)); return new Result(stmts, JassIm.ImVarAccess(tempVar)); } @@ -292,28 +313,66 @@ public static Result flatten(ImStatementExpr e, ImTranslator t, ImFunction f) { return new Result(stmts, r.expr); } + public static ResultL flattenL(ImStatementExpr e, ImTranslator t, ImFunction f) { + List stmts = Lists.newArrayList(); + flattenStatementsInto(stmts, e.getStatements(), t, f); + ResultL r = ((ImLExpr) e.getExpr()).flattenL(t, f); + stmts.addAll(r.stmts); + return new ResultL(stmts, r.getExpr()); + } + public static Result flatten(ImTupleExpr e, ImTranslator t, ImFunction f) { MultiResult r = flattenExprs(t, f, e.getExprs()); return new Result(r.stmts, JassIm.ImTupleExpr(ImExprs(r.exprs))); } + public static ResultL flattenL(ImTupleExpr e, ImTranslator t, ImFunction f) { + @SuppressWarnings({"unchecked", "rawtypes"}) + List exprs = (List) e.getExprs(); + MultiResultL r = flattenExprsL(t, f, exprs); + ImExprs newExprs = ImExprs(); + newExprs.addAll(r.getLExprs()); + return new ResultL(r.stmts, JassIm.ImTupleExpr(newExprs)); + } + public static Result flatten(ImTupleSelection e, ImTranslator t, ImFunction f) { - Result r = e.getTupleExpr().flatten(t, f); - return new Result(r.stmts, JassIm.ImTupleSelection(r.expr, e.getTupleIndex())); + return flattenL(e, t, f); } + public static ResultL flattenL(ImTupleSelection e, ImTranslator t, ImFunction f) { + Result r = e.getTupleExpr().flatten(t, f); + ImLExpr tupleExpr; + List stmts; + if (r.expr instanceof ImLExpr) { + tupleExpr = (ImLExpr) r.expr; + stmts = r.stmts; + } else { + // in the unlikely event that this is not an l-value (e.g. foo().x) + // we create a temporary variable and store the result there + ImVar v = JassIm.ImVar(e.attrTrace(), r.expr.attrTyp(), "tuple_temp", false); + f.getLocals().add(v); + stmts = new ArrayList<>(r.stmts); + stmts.add(JassIm.ImSet(e.attrTrace(), ImVarAccess(v), r.expr)); + tupleExpr = JassIm.ImVarAccess(v); + } + return new ResultL(stmts, JassIm.ImTupleSelection(tupleExpr, e.getTupleIndex())); + } - public static Result flatten(ImVarAccess e, ImTranslator t, ImFunction f) { + public static ResultL flattenL(ImVarAccess e, ImTranslator t, ImFunction f) { e.setParent(null); - return new Result(e); + return new ResultL(e); } - public static Result flatten(ImVarArrayAccess e, ImTranslator t, ImFunction f) { - Result index = e.getIndex().flatten(t, f); - return new Result(index.stmts, ImVarArrayAccess(e.getVar(), index.expr)); + public static ResultL flatten(ImLExpr e, ImTranslator t, ImFunction f) { + return e.flattenL(t, f); + } + + public static ResultL flattenL(ImVarArrayAccess e, ImTranslator t, ImFunction f) { + MultiResult indexes = flattenExprs(t, f, e.getIndexes()); + return new ResultL(indexes.stmts, ImVarArrayAccess(e.getTrace(), e.getVar(), ImExprs(indexes.exprs))); } @@ -362,29 +421,58 @@ private static MultiResult flattenExprs(ImTranslator t, ImFunction f, List exprs) { + // TODO optimize this function to use less temporary variables + List stmts = Lists.newArrayList(); + List newExprs = Lists.newArrayList(); + List results = Lists.newArrayList(); + int withStmts = -1; + for (int i = 0; i < exprs.size(); i++) { + ResultL r = exprs.get(i).flattenL(t, f); + results.add(r); + if (!r.stmts.isEmpty()) { + withStmts = i; + } + } + for (int i = 0; i < exprs.size(); i++) { + ImExpr e = exprs.get(i); + ResultL r = results.get(i); + + stmts.addAll(r.stmts); + if (r.expr.attrPurity() instanceof Pure + || i >= withStmts) { + newExprs.add(r.getExpr()); + } else { + ImVar tempVar = JassIm.ImVar(e.attrTrace(), r.expr.attrTyp(), "temp", false); + f.getLocals().add(tempVar); + stmts.add(ImSet(e.attrTrace(), ImVarAccess(tempVar), r.expr)); + newExprs.add(JassIm.ImVarAccess(tempVar)); + } + } + return new MultiResultL(stmts, newExprs); + } + public static Result flatten(ImClassRelatedExpr e, ImTranslator translator, ImFunction f) { throw new RuntimeException("Eliminate method calls before calling flatten."); } - - public static Result flatten(ImSetArrayMulti imSetArrayMulti, + public static Result flatten(ImMemberAccess e, ImTranslator translator, ImFunction f) { - throw new Error("not implemented"); + throw new RuntimeException("Eliminate method calls before calling flatten."); } - - public static Result flatten(ImVarArrayMultiAccess imVarArrayMultiAccess, - ImTranslator translator, ImFunction f) { - throw new Error("not implemented"); + public static ResultL flattenL(ImMemberAccess e, + ImTranslator translator, ImFunction f) { + throw new RuntimeException("Eliminate method calls before calling flatten."); } @@ -399,4 +487,7 @@ public static Result flatten(ImVarargLoop s, ImTranslator translator, ImFunction return new Result(Collections.singletonList( JassIm.ImVarargLoop(s.getTrace(), flattenStatements(s.getBody(), translator, f), s.getLoopVar()))); } + + + } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ImHelper.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ImHelper.java index 5d93d4ec5..95168cda5 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ImHelper.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ImHelper.java @@ -24,20 +24,18 @@ static void translateParameters(WParameters params, ImVars result, ImTranslator public static ImType toArray(ImType t) { if (t instanceof ImSimpleType) { ImSimpleType imSimpleType = (ImSimpleType) t; - return JassIm.ImArrayType(imSimpleType.getTypename()); - + return JassIm.ImArrayType(imSimpleType); } else if (t instanceof ImTupleType) { ImTupleType imTupleType = (ImTupleType) t; - ImType result = JassIm.ImTupleArrayType(imTupleType.getTypes(), imTupleType.getNames()); - return result; - } - if (t instanceof ImArrayType) { - return JassIm.ImArrayType(((ImArrayType) t).getTypename()); + return JassIm.ImArrayType(imTupleType); + } else if (t instanceof ImArrayType) { + // already an array + return t; } else if (t instanceof ImArrayTypeMulti) { ImArrayTypeMulti mat = ((ImArrayTypeMulti) t); ArrayList nsize = new ArrayList<>(mat.getArraySize()); nsize.add(8192); - return JassIm.ImArrayTypeMulti(mat.getTypename(), nsize); + return JassIm.ImArrayTypeMulti(mat.getEntryType(), nsize); } throw new Error("Can't make array type from " + t); } @@ -71,44 +69,8 @@ ImVar getReplaceVar(ImVar v) { } abstract static class VarReplaceVisitor extends ImStmt.DefaultVisitor { - abstract ImVar getReplaceVar(ImVar v); - @Override - public void visit(ImSetTuple e) { - super.visit(e); - ImVar newVar = getReplaceVar(e.getLeft()); - if (newVar != null) { - e.setLeft(newVar); - } - } - - @Override - public void visit(ImSetArray e) { - super.visit(e); - ImVar newVar = getReplaceVar(e.getLeft()); - if (newVar != null) { - e.setLeft(newVar); - } - } - - @Override - public void visit(ImSetArrayTuple e) { - super.visit(e); - ImVar newVar = getReplaceVar(e.getLeft()); - if (newVar != null) { - e.setLeft(newVar); - } - - } - - @Override - public void visit(ImVars imVars) { - super.visit(imVars); - // TODO ? - } - - @Override public void visit(ImVarArrayAccess e) { super.visit(e); @@ -128,33 +90,6 @@ public void visit(ImVarAccess e) { e.setVar(newVar); } } - - - @Override - public void visit(ImSet e) { - super.visit(e); - ImVar newVar = getReplaceVar(e.getLeft()); - if (newVar != null) { - e.setLeft(newVar); - } - - } - - @Override - public void visit(ImStringVal imStringVal) { - super.visit(imStringVal); - // TODO Auto-generated method stub - - } - - @Override - public void visit(ImNoExpr imNoExpr) { - super.visit(imNoExpr); - // TODO Auto-generated method stub - - } - - } public static void replaceElem(Element oldElem, Element newElement) { diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ImPrinter.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ImPrinter.java index 414b97065..ac9525159 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ImPrinter.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ImPrinter.java @@ -79,18 +79,7 @@ public static void print(ImSimpleType p, Appendable sb, int indent) { public static void print(ImArrayType t, Appendable sb, int indent) { append(sb, "array "); - append(sb, t.getTypename()); - } - - public static void print(ImTupleArrayType p, Appendable sb, int indent) { - append(sb, "array<"); - boolean first = true; - for (ImType t : p.getTypes()) { - if (!first) append(sb, ", "); - t.print(sb, indent); - first = false; - } - append(sb, ">"); + t.getEntryType().print(sb, indent); } public static void print(ImTupleType p, Appendable sb, int indent) { @@ -173,39 +162,7 @@ public static void print(ImReturn p, Appendable sb, int indent) { } public static void print(ImSet p, Appendable sb, int indent) { - append(sb, p.getLeft().getName()); - append(sb, smallHash(p.getLeft())); - append(sb, " = "); - p.getRight().print(sb, indent); - } - - public static void print(ImSetTuple p, Appendable sb, int indent) { - append(sb, p.getLeft().getName()); - append(sb, smallHash(p.getLeft())); - append(sb, " #"); - append(sb, p.getTupleIndex()); - append(sb, " = "); - p.getRight().print(sb, indent); - } - - public static void print(ImSetArray p, Appendable sb, int indent) { - append(sb, p.getLeft().getName()); - append(sb, smallHash(p.getLeft())); - append(sb, "["); - p.getIndex().print(sb, indent); - append(sb, "]"); - append(sb, " = "); - p.getRight().print(sb, indent); - } - - public static void print(ImSetArrayTuple p, Appendable sb, int indent) { - append(sb, p.getLeft().getName()); - append(sb, smallHash(p.getLeft())); - append(sb, "["); - p.getIndex().print(sb, indent); - append(sb, "]"); - append(sb, " #"); - append(sb, p.getTupleIndex()); + p.getLeft().print(sb, indent); append(sb, " = "); p.getRight().print(sb, indent); } @@ -219,7 +176,7 @@ public static void print(ImStatementExpr p, Appendable sb, int indent) { p.getStatements().print(sb, indent + 1); indent(sb, indent + 1); append(sb, ">>> "); - p.getExpr().print(sb, indent); + p.getExpr().print(sb, indent + 1); append(sb, "}"); } @@ -247,6 +204,7 @@ public static void printArgumentList(Appendable sb, int indent, public static void print(ImVarAccess p, Appendable sb, int indent) { append(sb, p.getVar().getName()); + append(sb, "_"); append(sb, smallHash(p.getVar())); } @@ -258,10 +216,13 @@ private static String smallHash(Object g) { public static void print(ImVarArrayAccess p, Appendable sb, int indent) { append(sb, p.getVar().getName()); + append(sb, "_"); append(sb, smallHash(p.getVar())); - append(sb, "["); - p.getIndex().print(sb, indent); - append(sb, "]"); + for (ImExpr ie : p.getIndexes()) { + append(sb, "["); + ie.print(sb, indent + 1); + append(sb, "]"); + } } @@ -430,36 +391,13 @@ public static void print(ImTypeIdOfObj e, Appendable sb, public static void print(ImArrayTypeMulti imArrayTypeMulti, Appendable sb, int indent) { append(sb, "array "); - append(sb, imArrayTypeMulti.getTypename()); + imArrayTypeMulti.getEntryType().print(sb, indent); append(sb, " size: "); append(sb, imArrayTypeMulti.getArraySize()); } - public static void print(ImSetArrayMulti imSetArrayMulti, Appendable sb, - int indent) { - append(sb, imSetArrayMulti.getLeft().getName()); - append(sb, smallHash(imSetArrayMulti.getLeft())); - append(sb, "["); - imSetArrayMulti.getIndices().get(0).print(sb, indent); - append(sb, "]"); - append(sb, "["); - imSetArrayMulti.getIndices().get(1).print(sb, indent); - append(sb, "]"); - append(sb, " = "); - imSetArrayMulti.getRight().print(sb, indent); - - } - - - public static void print(ImVarArrayMultiAccess imVarArrayMultiAccess, - Appendable sb, int indent) { - append(sb, imVarArrayMultiAccess.getVar().getName()); - append(sb, smallHash(imVarArrayMultiAccess.getVar())); - - } - public static void print(ImGetStackTrace e, Appendable sb, int indent) { append(sb, "#getStackTrace()"); diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ImTranslator.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ImTranslator.java index eb0d18ed4..ccf315f5f 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ImTranslator.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ImTranslator.java @@ -3,7 +3,6 @@ import com.google.common.base.Preconditions; import com.google.common.collect.*; import com.google.common.collect.ImmutableList.Builder; -import de.peeeq.datastructures.ImmutableTree; import de.peeeq.datastructures.Partitions; import de.peeeq.wurstscript.WLogger; import de.peeeq.wurstscript.WurstOperator; @@ -15,6 +14,7 @@ import de.peeeq.wurstscript.jassIm.Element; import de.peeeq.wurstscript.jassIm.*; import de.peeeq.wurstscript.jassIm.ImArrayType; +import de.peeeq.wurstscript.jassIm.ImArrayTypeMulti; import de.peeeq.wurstscript.jassIm.ImClass; import de.peeeq.wurstscript.jassIm.ImExprs; import de.peeeq.wurstscript.jassIm.ImFuncRef; @@ -26,7 +26,6 @@ import de.peeeq.wurstscript.jassIm.ImSimpleType; import de.peeeq.wurstscript.jassIm.ImStatementExpr; import de.peeeq.wurstscript.jassIm.ImStmts; -import de.peeeq.wurstscript.jassIm.ImTupleArrayType; import de.peeeq.wurstscript.jassIm.ImTupleExpr; import de.peeeq.wurstscript.jassIm.ImTupleSelection; import de.peeeq.wurstscript.jassIm.ImTupleType; @@ -42,7 +41,9 @@ import org.jetbrains.annotations.NotNull; import java.util.*; +import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.Stream; import static de.peeeq.wurstscript.jassIm.JassIm.*; import static de.peeeq.wurstscript.translation.imtranslation.FunctionFlagEnum.*; @@ -83,7 +84,7 @@ public class ImTranslator { private @Nullable ImFunction configFunc = null; - private final Map> varsForTupleVar = new LinkedHashMap<>(); + private final Map varsForTupleVar = new LinkedHashMap<>(); private boolean isUnitTestMode; @@ -347,8 +348,7 @@ private ImVar prepareTrigger() { // initTrigVar = CreateTrigger() ImFunction createTrigger = getNativeFunc("CreateTrigger"); if (createTrigger != null) { - getMainFunc().getBody().add(JassIm.ImSet(getMainFunc().getTrace(), initTrigVar, - JassIm.ImFunctionCall(getMainFunc().getTrace(), getNativeFunc("CreateTrigger"), JassIm.ImExprs(), false, CallType.NORMAL))); + getMainFunc().getBody().add(ImSet(getMainFunc().getTrace(), ImVarAccess(initTrigVar), JassIm.ImFunctionCall(getMainFunc().getTrace(), getNativeFunc("CreateTrigger"), JassIm.ImExprs(), false, CallType.NORMAL))); } return initTrigVar; } @@ -403,7 +403,7 @@ private boolean createInitFuncCall(WPackage p, ImVar initTrigVar, ImFunction ini || native_TriggerEvaluate == null || native_DisplayTimedTextToPlayer == null || native_GetLocalPlayer == null - ) { + ) { return false; } @@ -480,7 +480,7 @@ public void addGlobalInitalizer(ImVar v, PackageOrGlobal packageOrGlobal, VarIni if (!v.getIsBJ()) { // add init statement for non-bj vars // bj-vars are already initalized by blizzard - f.getBody().add(ImSet(trace, v, translated)); + f.getBody().add(ImSet(trace, ImVarAccess(v), translated)); } imProg.getGlobalInits().put(v, Collections.singletonList(translated)); } else if (initialExpr instanceof ArrayInitializer) { @@ -490,7 +490,7 @@ public void addGlobalInitalizer(ImVar v, PackageOrGlobal packageOrGlobal, VarIni .collect(Collectors.toList()); for (int i = 0; i < arInit.getValues().size(); i++) { ImExpr translated = translatedExprs.get(i); - f.getBody().add(ImSetArray(trace, v, JassIm.ImIntVal(i), translated)); + f.getBody().add(ImSet(trace, ImVarArrayAccess(trace, v, ImExprs((ImExpr) JassIm.ImIntVal(i))), translated)); } // add list of init-values to translatedExprs imProg.getGlobalInits().put(v, translatedExprs); @@ -499,8 +499,8 @@ public void addGlobalInitalizer(ImVar v, PackageOrGlobal packageOrGlobal, VarIni public void addGlobalWithInitalizer(ImVar g, ImExpr initial) { imProg.getGlobals().add(g); - getGlobalInitFunc().getBody().add(ImSet(g.getTrace(), g, initial)); - imProg.getGlobalInits().put(g, Collections.singletonList(initial)); + getGlobalInitFunc().getBody().add(ImSet(g.getTrace(), ImVarAccess(g), initial)); + imProg.getGlobalInits().put(g, Collections.singletonList((ImExpr) initial.copy())); } @@ -1086,57 +1086,158 @@ public void setEclipseMode(boolean enabled) { isEclipseMode = enabled; } - public ImmutableTree getVarsForTuple(ImVar v) { - ImmutableTree result = varsForTupleVar.get(v); + interface VarsForTupleResult { + + default Iterable allValues() { + return allValuesStream()::iterator; + } + + Stream allValuesStream(); + + T map(Function, T> nodeBuilder, Function leafBuilder); + } + + static class SingleVarResult implements VarsForTupleResult { + private final ImVar var; + + public SingleVarResult(ImVar var) { + this.var = var; + } + + public ImVar getVar() { + return var; + } + + @Override + public Stream allValuesStream() { + return Stream.of(var); + } + + @Override + public T map(Function, T> nodeBuilder, Function leafBuilder) { + return leafBuilder.apply(var); + } + + @Override + public String toString() { + return var.toString(); + } + } + + static class TupleResult implements VarsForTupleResult { + private final List items; + + public TupleResult(List items) { + this.items = items; + } + + public List getItems() { + return items; + } + + @Override + public Stream allValuesStream() { + return items.stream().flatMap(VarsForTupleResult::allValuesStream); + } + + @Override + public T map(Function, T> nodeBuilder, Function leafBuilder) { + return nodeBuilder.apply(items.stream().map(e -> e.map(nodeBuilder, leafBuilder))); + } + + @Override + public String toString() { + return "<" + Utils.printSep(", ", items) + ">"; + } + } + + public VarsForTupleResult getVarsForTuple(ImVar v) { + // TODO use list instead of tree + VarsForTupleResult result = varsForTupleVar.get(v); if (result == null) { - if (v.getType() instanceof ImArrayType || v.getType() instanceof ImSimpleType) { - result = ImmutableTree.leaf(v); + if (TypesHelper.typeContainsTuples(v.getType())) { + result = createVarsForType(v.getName(), v.getType(), Function.identity(), v.getTrace()); } else { - result = createVarsForType(v.getName(), v.getType(), false, v.getTrace()); + result = new SingleVarResult(v); } - -// if (v.getType() instanceof ImArrayType || v.getType() instanceof ImSimpleType) { -// result = ImmutableTree.leaf(v); -// } else { -// result = Lists.newArrayList(); -// addVarsForType(result, v.getName(), v.getType(), false, v.getTrace()); -// } varsForTupleVar.put(v, result); } return result; } - private ImmutableTree createVarsForType(String name, ImType type, boolean array, de.peeeq.wurstscript.ast.Element tr) { - if (type instanceof ImTupleType) { - ImTupleType tt = (ImTupleType) type; - int i = 0; - Builder> ts = ImmutableList.builder(); - for (ImType t : tt.getTypes()) { - ts.add(createVarsForType(name + "_" + tt.getNames().get(i), t, array, tr)); - i++; + + /** + * Creates variables for the given type, eliminating tuple types + * + * @param name base name for the variables + * @param type the type for which to create variables + * @param typeConstructor how the types are constructed (creating an array or multi-array, just returning the type) + * @param tr trace for the variables + * @return + */ + private VarsForTupleResult createVarsForType(String name, final ImType type, Function typeConstructor, de.peeeq.wurstscript.ast.Element tr) { + return type.match(new ImType.Matcher() { + @Override + public VarsForTupleResult case_ImArrayType(ImArrayType at) { + if (at.getEntryType() instanceof ImTupleType) { + // if it is an array of tuples, create multiple array variables: + ImTupleType tt = (ImTupleType) at.getEntryType(); + Builder ts = ImmutableList.builder(); + int i = 0; + for (ImType t : tt.getTypes()) { + ts.add(createVarsForType(name + "_" + tt.getNames().get(i), t, JassIm::ImArrayType, tr)); + i++; + } + return new TupleResult(ts.build()); + } + // otherwise just create the array variable + return new SingleVarResult(JassIm.ImVar(tr, type, name, false)); } - return ImmutableTree.node(ts.build()); - } else if (type instanceof ImTupleArrayType) { - ImTupleArrayType tt = (ImTupleArrayType) type; - Builder> ts = ImmutableList.builder(); - for (ImType t : tt.getTypes()) { - ts.add(createVarsForType(name, t, true, tr)); + + @Override + public VarsForTupleResult case_ImArrayTypeMulti(ImArrayTypeMulti at) { + if (at.getEntryType() instanceof ImTupleType) { + // if it is an array of tuples, create multiple array variables: + ImTupleType tt = (ImTupleType) at.getEntryType(); + Builder ts = ImmutableList.builder(); + int i = 0; + for (ImType t : tt.getTypes()) { + ts.add(createVarsForType(name + "_" + tt.getNames().get(i), t, et -> JassIm.ImArrayTypeMulti(et, new ArrayList<>(at.getArraySize())), tr)); + i++; + } + return new TupleResult(ts.build()); + } + // otherwise just create the array variable + return new SingleVarResult(JassIm.ImVar(tr, type, name, false)); } - return ImmutableTree.node(ts.build()); - } else if (type instanceof ImVoid) { - return ImmutableTree.empty(); - } else { - if (array && type instanceof ImSimpleType) { - ImSimpleType st = (ImSimpleType) type; - type = JassIm.ImArrayType(st.getTypename()); + + @Override + public VarsForTupleResult case_ImVoid(ImVoid imVoid) { + return new TupleResult(Collections.emptyList()); } - return ImmutableTree.leaf(JassIm.ImVar(tr, type, name, false)); - } + + @Override + public VarsForTupleResult case_ImSimpleType(ImSimpleType st) { + ImType type = typeConstructor.apply(st); + return new SingleVarResult(JassIm.ImVar(tr, type, name, false)); + } + + @Override + public VarsForTupleResult case_ImTupleType(ImTupleType tt) { + int i = 0; + Builder ts = ImmutableList.builder(); + for (ImType t : tt.getTypes()) { + ts.add(createVarsForType(name + "_" + tt.getNames().get(i), t, typeConstructor, tr)); + i++; + } + return new TupleResult(ts.build()); + } + }); } - private void addVarsForType(List result, String name, ImType type, boolean array, de.peeeq.wurstscript.ast.Element tr) { + private void addVarsForType(List result, String name, ImType type, de.peeeq.wurstscript.ast.Element tr) { Preconditions.checkNotNull(type); Preconditions.checkNotNull(result); // TODO handle names @@ -1144,36 +1245,25 @@ private void addVarsForType(List result, String name, ImType type, boolea ImTupleType tt = (ImTupleType) type; int i = 0; for (ImType t : tt.getTypes()) { - addVarsForType(result, name + "_" + tt.getNames().get(i), t, false, tr); + addVarsForType(result, name + "_" + tt.getNames().get(i), t, tr); i++; } - } else if (type instanceof ImTupleArrayType) { - ImTupleArrayType tt = (ImTupleArrayType) type; - for (ImType t : tt.getTypes()) { - addVarsForType(result, name, t, true, tr); - } } else if (type instanceof ImVoid) { - + // nothing to add } else { - if (array && type instanceof ImSimpleType) { - ImSimpleType st = (ImSimpleType) type; - type = JassIm.ImArrayType(st.getTypename()); - } result.add(JassIm.ImVar(tr, type, name, false)); } } - private Map> tempReturnVars = Maps.newLinkedHashMap(); + private Map tempReturnVars = Maps.newLinkedHashMap(); - public List getTupleTempReturnVarsFor(ImFunction f) { - List result = tempReturnVars.get(f); + public VarsForTupleResult getTupleTempReturnVarsFor(ImFunction f) { + VarsForTupleResult result = tempReturnVars.get(f); if (result == null) { - result = Lists.newArrayList(); - addVarsForType(result, f.getName() + "_return", getOriginalReturnValue(f), false, f.getTrace()); - if (result.size() > 1) { - imProg.getGlobals().addAll(result); - // if we only have one return var it will never get used + result = createVarsForType(f.getName() + "_return", getOriginalReturnValue(f), Function.identity(), f.getTrace()); + for (ImVar value : result.allValues()) { + imProg.getGlobals().add(value); } tempReturnVars.put(f, result); } @@ -1196,23 +1286,19 @@ public void assertProperties(AssertProperty... properties1) { assertProperties(properties, imProg); } - private void assertProperties(Set properties, Element e) { - if (e instanceof ElementWithLeft) { - checkVar(((ElementWithLeft) e).getLeft(), properties); - } + public void assertProperties(Set properties, Element e) { if (e instanceof ElementWithVar) { checkVar(((ElementWithVar) e).getVar(), properties); } if (properties.contains(AssertProperty.NOTUPLES)) { if (e instanceof ImTupleExpr || e instanceof ImTupleSelection - ) { - throw new Error("contains tuple expr " + e); + ) { + throw new Error("contains tuple exprs " + e); } if (e instanceof ImVar) { ImVar v = (ImVar) e; - if (v.getType() instanceof ImTupleType - || v.getType() instanceof ImTupleArrayType) { + if (TypesHelper.typeContainsTuples(v.getType())) { throw new Error("contains tuple var: " + v + " in\n" + v.getParent().getParent()); } } @@ -1223,7 +1309,11 @@ private void assertProperties(Set properties, Element e) { } } for (int i = 0; i < e.size(); i++) { - assertProperties(properties, e.get(i)); + Element child = e.get(i); + if (child.getParent() == null) { + throw new Error("Child " + i + " (" + child + ") of " + e + " not attached to tree"); + } + assertProperties(properties, child); } } @@ -1232,8 +1322,7 @@ private void checkVar(ImVar left, Set properties) { throw new Error("var not attached: " + left); } if (properties.contains(AssertProperty.NOTUPLES)) { - if (left.getType() instanceof ImTupleType - || left.getType() instanceof ImTupleArrayType) { + if (TypesHelper.typeContainsTuples(left.getType())) { throw new Error("program contains tuple var " + left); } } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/LValues.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/LValues.java new file mode 100644 index 000000000..af90c6625 --- /dev/null +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/LValues.java @@ -0,0 +1,25 @@ +package de.peeeq.wurstscript.translation.imtranslation; + +import de.peeeq.wurstscript.jassIm.*; + +/** + * + */ +public class LValues { + public static boolean isUsedAsLValue(ImLExpr e) { + Element parent = e.getParent(); + if (parent != null) { + if (parent instanceof ImTupleSelection) { + ImTupleSelection ts = (ImTupleSelection) parent; + return isUsedAsLValue(ts); + } else if (parent instanceof ImSet) { + ImSet set = (ImSet) parent; + return set.getLeft() == e; + } else if (parent instanceof ImStatementExpr) { + ImStatementExpr se = (ImStatementExpr) parent; + return isUsedAsLValue(se); + } + } + return false; + } +} diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/MultiArrayEliminator.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/MultiArrayEliminator.java index a67e759c8..bce9dfbe0 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/MultiArrayEliminator.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/MultiArrayEliminator.java @@ -3,8 +3,10 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import de.peeeq.wurstscript.WurstOperator; +import de.peeeq.wurstscript.attributes.CompileError; import de.peeeq.wurstscript.jassIm.*; import de.peeeq.wurstscript.types.TypesHelper; +import de.peeeq.wurstscript.utils.Utils; import java.util.HashMap; import java.util.List; @@ -42,7 +44,7 @@ public void run() { int size0 = arraySize.get(0); List newArrays = Lists.newArrayList(); for (int i = 0; i < size0; i++) { - ImVar newVar = JassIm.ImVar(v.getTrace(), JassIm.ImArrayType(type.getTypename()), v.getName() + "_" + i, false); + ImVar newVar = JassIm.ImVar(v.getTrace(), JassIm.ImArrayType(type.getEntryType()), v.getName() + "_" + i, false); newArrays.add(newVar); } ImFunction setFunc = generateSetFunc(v, newArrays); @@ -62,44 +64,88 @@ public void run() { } private void replaceVars(Element e, Map oldToNewVar) { - // process children - for (int i = 0; i < e.size(); i++) { - replaceVars(e.get(i), oldToNewVar); - } - if (e instanceof ImSetArrayMulti) { - ImSetArrayMulti sm = (ImSetArrayMulti) e; - ImExprs args = JassIm.ImExprs(); - for (ImExpr val : sm.getIndices()) { - args.add((ImExpr) val.copy()); + if (e instanceof ImSet) { + ImSet set = (ImSet) e; + + // normalize statement expression on left hand side + ImStmts stmts = JassIm.ImStmts(); + ImLExpr left = set.getLeft(); + while (left instanceof ImStatementExpr) { + ImStatementExpr se = (ImStatementExpr) left; + stmts.addAll(se.getStatements().removeAll()); + left = (ImLExpr) se.getExpr(); + left.setParent(null); } - args.add((ImExpr) ((ImSetArrayMulti) e).getRight().copy()); - if (getSetMap.containsKey(sm.getLeft())) { - sm.replaceBy(JassIm.ImFunctionCall(sm.getTrace(), getSetMap.get(sm.getLeft()).setter, args, false, CallType.NORMAL)); + if (left != set.getLeft()) { + set.setLeft(left); + + // replace vars in statements: + for (ImStmt s : stmts) { + replaceVars(s, oldToNewVar); + } + + // move statements around set-statement + Element setParent = set.getParent(); + set.setParent(null); + stmts.add(set); + Utils.replace(setParent, set, JassIm.ImStatementExpr(stmts, JassIm.ImNull())); } - } else if (e instanceof ImVarArrayMultiAccess) { - ImVarArrayMultiAccess am = (ImVarArrayMultiAccess) e; - ImExprs args = JassIm.ImExprs(); - args.add((ImExpr) am.getIndex1().copy()); - args.add((ImExpr) am.getIndex2().copy()); - if (getSetMap.containsKey(am.getVar())) { - am.replaceBy(JassIm.ImFunctionCall(am.attrTrace(), getSetMap.get(am.getVar()).getter, args, false, CallType.NORMAL)); + + + if (left instanceof ImVarArrayAccess) { + ImVarArrayAccess va = (ImVarArrayAccess) left; + if (va.getIndexes().size() > 1) { + if (getSetMap.containsKey(va.getVar())) { + // process children (but not the updatedExpr): + replaceVars(va.getIndexes(), oldToNewVar); + replaceVars(set.getRight(), oldToNewVar); + ImExprs args = JassIm.ImExprs(); + for (ImExpr val : va.getIndexes()) { + args.add(val.copy()); + } + args.add(set.getRight().copy()); + + set.replaceBy(JassIm.ImFunctionCall(set.getTrace(), getSetMap.get(va.getVar()).setter, args, false, CallType.NORMAL)); + return; + } + } } + } + // process children + for (int i = 0; i < e.size(); i++) { + replaceVars(e.get(i), oldToNewVar); + } + if (e instanceof ImVarArrayAccess) { + ImVarArrayAccess am = (ImVarArrayAccess) e; + if (am.getIndexes().size() > 1) { + if (am.isUsedAsLValue()) { + throw new CompileError(am.attrTrace().attrSource(), "Invalid multi array access " + e); + } + ImExprs args = JassIm.ImExprs(); + for (ImExpr val : am.getIndexes()) { + args.add(val.copy()); + } + if (getSetMap.containsKey(am.getVar())) { + am.replaceBy(JassIm.ImFunctionCall(am.attrTrace(), getSetMap.get(am.getVar()).getter, args, false, CallType.NORMAL)); + } + } } } + private ImFunction generateSetFunc(ImVar aVar, List newArrays) { ImArrayTypeMulti mtype = (ImArrayTypeMulti) aVar.getType(); ImVars locals = JassIm.ImVars(); ImVar instanceId = JassIm.ImVar(aVar.getTrace(), TypesHelper.imInt(), "instanceId", false); ImVar arrayIndex = JassIm.ImVar(aVar.getTrace(), TypesHelper.imInt(), "arrayIndex", false); - ImVar value = JassIm.ImVar(aVar.getTrace(), JassIm.ImSimpleType(mtype.getTypename()), "value", false); + ImVar value = JassIm.ImVar(aVar.getTrace(), mtype.getEntryType(), "value", false); ImStmts thenBlock = JassIm.ImStmts(translator.imError(aVar.getTrace(), JassIm.ImStringVal("Index out of Bounds"))); ImStmts elseBlock = JassIm.ImStmts(); - generateBinSearchSet(elseBlock, instanceId, arrayIndex, value, newArrays, 0, newArrays.size() - 1); + generateBinSearchSet(elseBlock, instanceId, arrayIndex, value, newArrays, 0, newArrays.size() - 1, aVar.getTrace()); ImExpr highCond = JassIm.ImOperatorCall(WurstOperator.GREATER_EQ, JassIm.ImExprs(JassIm.ImVarAccess(arrayIndex), JassIm.ImIntVal(mtype.getArraySize().get(0)))); ImExpr lowCond = JassIm.ImOperatorCall(WurstOperator.LESS, JassIm.ImExprs(JassIm.ImVarAccess(arrayIndex), JassIm.ImIntVal(0))); ImExpr condition = JassIm.ImOperatorCall(WurstOperator.OR, JassIm.ImExprs(lowCond, highCond)); @@ -111,9 +157,9 @@ private ImFunction generateSetFunc(ImVar aVar, List newArrays) { private void generateBinSearchSet(ImStmts stmts, ImVar indexVar1, ImVar indexVar2, ImVar value, List newArrays, int start, - int end) { + int end, de.peeeq.wurstscript.ast.Element trace) { if (start == end) { - stmts.add(JassIm.ImSetArray(value.getTrace(), newArrays.get(start), JassIm.ImVarAccess(indexVar1), JassIm.ImVarAccess(value))); + stmts.add(JassIm.ImSet(value.getTrace(), JassIm.ImVarArrayAccess(trace, newArrays.get(start), JassIm.ImExprs((ImExpr) JassIm.ImVarAccess(indexVar1))), JassIm.ImVarAccess(value))); } else { int mid = (start + end) / 2; ImStmts thenBlock = JassIm.ImStmts(); @@ -126,35 +172,35 @@ private void generateBinSearchSet(ImStmts stmts, ImVar indexVar1, ImVar indexVar stmts.add(JassIm.ImIf(value.getTrace(), condition, thenBlock, elseBlock)); - generateBinSearchSet(thenBlock, indexVar1, indexVar2, value, newArrays, start, mid); - generateBinSearchSet(elseBlock, indexVar1, indexVar2, value, newArrays, mid + 1, end); + generateBinSearchSet(thenBlock, indexVar1, indexVar2, value, newArrays, start, mid, trace); + generateBinSearchSet(elseBlock, indexVar1, indexVar2, value, newArrays, mid + 1, end, trace); } } private ImFunction generateGetFunc(ImVar aVar, List newArrays) { ImArrayTypeMulti mtype = (ImArrayTypeMulti) aVar.getType(); - ImVar returnVal = JassIm.ImVar(aVar.getTrace(), JassIm.ImSimpleType(mtype.getTypename()), "returnVal", false); + ImVar returnVal = JassIm.ImVar(aVar.getTrace(), mtype.getEntryType(), "returnVal", false); ImVars locals = JassIm.ImVars(returnVal); ImVar instanceId = JassIm.ImVar(aVar.getTrace(), TypesHelper.imInt(), "index1", false); ImVar arrayIndex = JassIm.ImVar(aVar.getTrace(), TypesHelper.imInt(), "index2", false); ImStmts thenBlock = JassIm.ImStmts(translator.imError(aVar.getTrace(), JassIm.ImStringVal("Index out of Bounds"))); ImStmts elseBlock = JassIm.ImStmts(); - generateBinSearchGet(elseBlock, instanceId, arrayIndex, returnVal, newArrays, 0, newArrays.size() - 1); + generateBinSearchGet(elseBlock, instanceId, arrayIndex, returnVal, newArrays, 0, newArrays.size() - 1, aVar.getTrace()); ImExpr highCond = JassIm.ImOperatorCall(WurstOperator.GREATER_EQ, JassIm.ImExprs(JassIm.ImVarAccess(arrayIndex), JassIm.ImIntVal(mtype.getArraySize().get(0)))); ImExpr lowCond = JassIm.ImOperatorCall(WurstOperator.LESS, JassIm.ImExprs(JassIm.ImVarAccess(arrayIndex), JassIm.ImIntVal(0))); ImExpr condition = JassIm.ImOperatorCall(WurstOperator.OR, JassIm.ImExprs(lowCond, highCond)); ImStmts body = JassIm.ImStmts(JassIm.ImIf(aVar.getTrace(), condition, thenBlock, elseBlock), JassIm.ImReturn(returnVal.getTrace(), JassIm.ImVarAccess(returnVal))); - ImFunction getFunc = JassIm.ImFunction(aVar.getTrace(), aVar.getName() + "_get", JassIm.ImVars(instanceId, arrayIndex), JassIm.ImSimpleType(mtype.getTypename()), locals, body, Lists.newArrayList()); + ImFunction getFunc = JassIm.ImFunction(aVar.getTrace(), aVar.getName() + "_get", JassIm.ImVars(instanceId, arrayIndex), mtype.getEntryType(), locals, body, Lists.newArrayList()); return getFunc; } private void generateBinSearchGet(ImStmts stmts, ImVar indexVar1, ImVar indexVar2, ImVar resultVar, List newArrays, int start, - int end) { + int end, de.peeeq.wurstscript.ast.Element trace) { if (start == end) { - stmts.add(JassIm.ImSet(resultVar.getTrace(), resultVar, JassIm.ImVarArrayAccess(newArrays.get(start), JassIm.ImVarAccess(indexVar1)))); + stmts.add(JassIm.ImSet(resultVar.getTrace(), JassIm.ImVarAccess(resultVar), JassIm.ImVarArrayAccess(trace, newArrays.get(start), JassIm.ImExprs((ImExpr) JassIm.ImVarAccess(indexVar1))))); } else { int mid = (start + end) / 2; ImStmts thenBlock = JassIm.ImStmts(); @@ -167,8 +213,8 @@ private void generateBinSearchGet(ImStmts stmts, ImVar indexVar1, ImVar indexVar stmts.add(JassIm.ImIf(resultVar.getTrace(), condition, thenBlock, elseBlock)); - generateBinSearchGet(thenBlock, indexVar1, indexVar2, resultVar, newArrays, start, mid); - generateBinSearchGet(elseBlock, indexVar1, indexVar2, resultVar, newArrays, mid + 1, end); + generateBinSearchGet(thenBlock, indexVar1, indexVar2, resultVar, newArrays, start, mid, trace); + generateBinSearchGet(elseBlock, indexVar1, indexVar2, resultVar, newArrays, mid + 1, end, trace); } } } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/RecycleCodeGeneratorQueue.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/RecycleCodeGeneratorQueue.java index 9ed2cbc28..e23a1c53d 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/RecycleCodeGeneratorQueue.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/RecycleCodeGeneratorQueue.java @@ -38,25 +38,24 @@ public void createAllocFunc(ImTranslator translator, ImProg prog, ImClass c) { JassIm.ImOperatorCall(WurstOperator.LESS, JassIm.ImExprs(JassIm.ImVarAccess(mVars.maxIndex), JassIm.ImIntVal(maxSize))), ifEnoughMemory, ifNotEnoughMemory)); // maxIndex = maxIndex + 1 - ifEnoughMemory.add(JassIm.ImSet(tr, mVars.maxIndex, - JassIm.ImOperatorCall(WurstOperator.PLUS, JassIm.ImExprs(JassIm.ImVarAccess(mVars.maxIndex), JassIm.ImIntVal(1))))); + ifEnoughMemory.add(JassIm.ImSet(tr, JassIm.ImVarAccess(mVars.maxIndex), JassIm.ImOperatorCall(WurstOperator.PLUS, JassIm.ImExprs(JassIm.ImVarAccess(mVars.maxIndex), JassIm.ImIntVal(1))))); // this = maxIndex - ifEnoughMemory.add(JassIm.ImSet(tr, thisVar, JassIm.ImVarAccess(mVars.maxIndex))); + ifEnoughMemory.add(JassIm.ImSet(tr, JassIm.ImVarAccess(thisVar), JassIm.ImVarAccess(mVars.maxIndex))); // typeId[this] = ... - ifEnoughMemory.add(JassIm.ImSetArray(tr, mVars.typeId, JassIm.ImVarAccess(thisVar), JassIm.ImIntVal(c.attrTypeId()))); + ifEnoughMemory.add(JassIm.ImSet(tr, JassIm.ImVarArrayAccess(tr, mVars.typeId, JassIm.ImExprs((ImExpr) JassIm.ImVarAccess(thisVar))), JassIm.ImIntVal(c.attrTypeId()))); // else: // error("out of memory") ifNotEnoughMemory.add(translator.imError(c.getTrace(), JassIm.ImStringVal("Out of memory: Could not create " + c.getName() + "."))); // this = 0 - ifNotEnoughMemory.add(JassIm.ImSet(tr, thisVar, JassIm.ImIntVal(0))); + ifNotEnoughMemory.add(JassIm.ImSet(tr, JassIm.ImVarAccess(thisVar), JassIm.ImIntVal(0))); // else: // freeCount = freeCount - 1 - elseBlock.add(JassIm.ImSet(tr, mVars.freeCount, JassIm.ImOperatorCall(WurstOperator.MINUS, JassIm.ImExprs(JassIm.ImVarAccess(mVars.freeCount), JassIm + elseBlock.add(JassIm.ImSet(tr, JassIm.ImVarAccess(mVars.freeCount), JassIm.ImOperatorCall(WurstOperator.MINUS, JassIm.ImExprs(JassIm.ImVarAccess(mVars.freeCount), JassIm .ImIntVal(1))))); // this = free[freeCount] - elseBlock.add(JassIm.ImSet(tr, thisVar, JassIm.ImVarArrayAccess(mVars.free, JassIm.ImVarAccess(mVars.freeCount)))); + elseBlock.add(JassIm.ImSet(tr, JassIm.ImVarAccess(thisVar), JassIm.ImVarArrayAccess(tr, mVars.free, JassIm.ImExprs((ImExpr) JassIm.ImVarAccess(mVars.freeCount))))); // typeId[this] = ... - elseBlock.add(JassIm.ImSetArray(tr, mVars.typeId, JassIm.ImVarAccess(thisVar), JassIm.ImIntVal(c.attrTypeId()))); + elseBlock.add(JassIm.ImSet(tr, JassIm.ImVarArrayAccess(tr, mVars.typeId, JassIm.ImExprs((ImExpr) JassIm.ImVarAccess(thisVar))), JassIm.ImIntVal(c.attrTypeId()))); // endif @@ -78,19 +77,19 @@ public void createDeallocFunc(ImTranslator translator, ImProg prog, ImClass c) { // if typeId[this] == 0 then error body.add(JassIm.ImIf(tr, JassIm.ImOperatorCall(WurstOperator.EQ, - JassIm.ImExprs(JassIm.ImVarArrayAccess(mVars.typeId, JassIm.ImVarAccess(thisVar)), JassIm.ImIntVal(0))), + JassIm.ImExprs(JassIm.ImVarArrayAccess(tr, mVars.typeId, JassIm.ImExprs((ImExpr) JassIm.ImVarAccess(thisVar))), JassIm.ImIntVal(0))), // then // error JassIm.ImStmts(translator.imError(c.getTrace(), JassIm.ImStringVal("Double free: object of type " + c.getName()))), // else JassIm.ImStmts( // free[freeCount] = this - JassIm.ImSetArray(tr, mVars.free, JassIm.ImVarAccess(mVars.freeCount), JassIm.ImVarAccess(thisVar)), + JassIm.ImSet(tr, JassIm.ImVarArrayAccess(tr, mVars.free, JassIm.ImExprs((ImExpr) JassIm.ImVarAccess(mVars.freeCount))), JassIm.ImVarAccess(thisVar)), // freeCount++ - JassIm.ImSet(tr, mVars.freeCount, JassIm.ImOperatorCall(WurstOperator.PLUS, JassIm.ImExprs(JassIm.ImVarAccess(mVars.freeCount), + JassIm.ImSet(tr, JassIm.ImVarAccess(mVars.freeCount), JassIm.ImOperatorCall(WurstOperator.PLUS, JassIm.ImExprs(JassIm.ImVarAccess(mVars.freeCount), JassIm.ImIntVal(1)))), // typeId[this] = 0 - JassIm.ImSetArray(tr, mVars.typeId, JassIm.ImVarAccess(thisVar), JassIm.ImIntVal(0)) + JassIm.ImSet(tr, JassIm.ImVarArrayAccess(tr, mVars.typeId, JassIm.ImExprs((ImExpr) JassIm.ImVarAccess(thisVar))), JassIm.ImIntVal(0)) ))); } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ReferenceRewritingCopy.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ReferenceRewritingCopy.java index bfed16dec..317312797 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ReferenceRewritingCopy.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ReferenceRewritingCopy.java @@ -48,50 +48,6 @@ public void visit(ImMethod e) { } } - @Override - public void visit(ImSet e) { - super.visit(e); - Element newChild = oldToNew.get(e.getLeft()); - if (newChild != null) { - e.setLeft((ImVar) newChild); - } - } - - @Override - public void visit(ImSetTuple e) { - super.visit(e); - Element newChild = oldToNew.get(e.getLeft()); - if (newChild != null) { - e.setLeft((ImVar) newChild); - } - } - - @Override - public void visit(ImSetArray e) { - super.visit(e); - Element newChild = oldToNew.get(e.getLeft()); - if (newChild != null) { - e.setLeft((ImVar) newChild); - } - } - - @Override - public void visit(ImSetArrayMulti e) { - super.visit(e); - Element newChild = oldToNew.get(e.getLeft()); - if (newChild != null) { - e.setLeft((ImVar) newChild); - } - } - - @Override - public void visit(ImSetArrayTuple e) { - super.visit(e); - Element newChild = oldToNew.get(e.getLeft()); - if (newChild != null) { - e.setLeft((ImVar) newChild); - } - } @Override public void visit(ImVarargLoop e) { @@ -120,15 +76,6 @@ public void visit(ImVarArrayAccess e) { } } - @Override - public void visit(ImVarArrayMultiAccess e) { - super.visit(e); - Element newChild = oldToNew.get(e.getVar()); - if (newChild != null) { - e.setVar((ImVar) newChild); - } - } - @Override public void visit(ImMethodCall e) { super.visit(e); diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/StackTraceInjector2.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/StackTraceInjector2.java index 7123b1b02..24daac136 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/StackTraceInjector2.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/StackTraceInjector2.java @@ -59,9 +59,9 @@ public void visit(ImFuncRef imFuncRef) { }); de.peeeq.wurstscript.ast.Element trace = prog.attrTrace(); - stackSize = JassIm.ImVar(trace, JassIm.ImSimpleType("integer"), "wurst_stack_depth", false); + stackSize = JassIm.ImVar(trace, TypesHelper.imInt(), "wurst_stack_depth", false); prog.getGlobals().add(stackSize); - stack = JassIm.ImVar(trace, JassIm.ImArrayType("string"), "wurst_stack", false); + stack = JassIm.ImVar(trace, TypesHelper.imStringArray(), "wurst_stack", false); prog.getGlobals().add(stack); prog.getGlobalInits().put(stackSize, Collections.singletonList(JassIm.ImIntVal(0))); @@ -94,7 +94,7 @@ private void addStackTracePush(Multimap calls, Set funcRefs, Set affectedFuncs) { @@ -262,7 +260,7 @@ private void rewriteFuncRefs(final List funcRefs, Set aff throw new RuntimeException("no trace"); } // reset stack and add information for callback: - body.add(JassIm.ImSet(trace, stackSize, JassIm.ImIntVal(0))); + body.add(JassIm.ImSet(trace, JassIm.ImVarAccess(stackSize), JassIm.ImIntVal(0))); ImFunctionCall call = JassIm.ImFunctionCall(fr.attrTrace(), f, args, true, CallType.NORMAL); if (bridgeFunc.getReturnType() instanceof ImVoid) { @@ -283,16 +281,16 @@ private void rewriteErrorStatements(final Multimap ImGetStackTrace s = e.getValue(); de.peeeq.wurstscript.ast.Element trace = s.attrTrace(); - ImVar traceStr = JassIm.ImVar(trace, JassIm.ImSimpleType("string"), "stacktraceStr", false); + ImVar traceStr = JassIm.ImVar(trace, TypesHelper.imString(), "stacktraceStr", false); f.getLocals().add(traceStr); - ImVar traceI = JassIm.ImVar(trace, JassIm.ImSimpleType("integer"), "stacktraceIndex", false); + ImVar traceI = JassIm.ImVar(trace, TypesHelper.imInt(), "stacktraceIndex", false); f.getLocals().add(traceI); - ImVar traceLimit = JassIm.ImVar(trace, JassIm.ImSimpleType("integer"), "stacktraceLimit", false); + ImVar traceLimit = JassIm.ImVar(trace, TypesHelper.imInt(), "stacktraceLimit", false); f.getLocals().add(traceLimit); ImStmts stmts = JassIm.ImStmts(); - stmts.add(JassIm.ImSet(trace, traceStr, JassIm.ImStringVal(""))); - stmts.add(JassIm.ImSet(trace, traceI, JassIm.ImVarAccess(stackSize))); - stmts.add(JassIm.ImSet(trace, traceLimit, JassIm.ImIntVal(0))); + stmts.add(JassIm.ImSet(trace, JassIm.ImVarAccess(traceStr), JassIm.ImStringVal(""))); + stmts.add(JassIm.ImSet(trace, JassIm.ImVarAccess(traceI), JassIm.ImVarAccess(stackSize))); + stmts.add(JassIm.ImSet(trace, JassIm.ImVarAccess(traceLimit), JassIm.ImIntVal(0))); ImStmts loopBody = JassIm.ImStmts(); stmts.add(JassIm.ImLoop(trace, loopBody)); // i = i - 1 @@ -306,10 +304,10 @@ private void rewriteErrorStatements(final Multimap loopBody.add(JassIm.ImExitwhen(trace, JassIm.ImOperatorCall(WurstOperator.LESS, JassIm.ImExprs(JassIm.ImVarAccess(traceI), JassIm.ImIntVal(0))))); // s = s + "\n " + stack[i] - loopBody.add(JassIm.ImSet(trace, traceStr, JassIm.ImOperatorCall(WurstOperator.PLUS, + loopBody.add(JassIm.ImSet(trace, JassIm.ImVarAccess(traceStr), JassIm.ImOperatorCall(WurstOperator.PLUS, JassIm.ImExprs(JassIm.ImVarAccess(traceStr), JassIm.ImOperatorCall(WurstOperator.PLUS, JassIm.ImExprs(JassIm.ImStringVal("\n "), - JassIm.ImVarArrayAccess(stack, JassIm.ImVarAccess(traceI)))))))); + JassIm.ImVarArrayAccess(trace, stack, JassIm.ImExprs((ImExpr) JassIm.ImVarAccess(traceI))))))))); s.replaceBy(JassIm.ImStatementExpr(stmts, JassIm.ImVarAccess(traceStr))); } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/StmtTranslation.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/StmtTranslation.java index a0b1ec7a7..2605622a2 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/StmtTranslation.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/StmtTranslation.java @@ -15,17 +15,11 @@ import de.peeeq.wurstscript.jassIm.ImSet; import de.peeeq.wurstscript.jassIm.ImStatementExpr; import de.peeeq.wurstscript.jassIm.ImStmts; -import de.peeeq.wurstscript.jassIm.ImTupleExpr; -import de.peeeq.wurstscript.jassIm.ImTupleSelection; import de.peeeq.wurstscript.jassIm.ImVar; -import de.peeeq.wurstscript.jassIm.ImVarAccess; -import de.peeeq.wurstscript.jassIm.ImVarArrayAccess; -import de.peeeq.wurstscript.jassIm.ImVarArrayMultiAccess; import de.peeeq.wurstscript.types.TypesHelper; import de.peeeq.wurstscript.types.WurstType; import de.peeeq.wurstscript.types.WurstTypeVararg; -import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -42,14 +36,14 @@ public static ImStmt translate(LocalVarDef s, ImTranslator t, ImFunction f) { f.getLocals().add(v); if (s.getInitialExpr() instanceof Expr) { Expr inital = (Expr) s.getInitialExpr(); - return ImSet(s, v, inital.imTranslateExpr(t, f)); + return ImSet(s, ImVarAccess(v), inital.imTranslateExpr(t, f)); } else if (s.getInitialExpr() instanceof ArrayInitializer) { ArrayInitializer ai = (ArrayInitializer) s.getInitialExpr(); ImStmts stmts = ImStmts(); for (int i = 0; i < ai.getValues().size(); i++) { Expr expr = ai.getValues().get(i); ImExpr translatedExpr = expr.imTranslateExpr(t, f); - stmts.add(JassIm.ImSetArray(s, v, JassIm.ImIntVal(i), translatedExpr)); + stmts.add(ImSet(s, ImVarArrayAccess(s, v, ImExprs((ImExpr) JassIm.ImIntVal(i))), translatedExpr)); } return JassIm.ImStatementExpr(stmts, ImNull()); } else { @@ -93,7 +87,7 @@ public static ImStmt translate(StmtForFrom s, ImTranslator t, ImFunction f) { ImExpr iterationTargetTr = iterationTarget.imTranslateExpr(t, f); ImVar fromVar = ImVar(s, iterationTargetTr.attrTyp(), "from", false); f.getLocals().add(fromVar); - result.add(ImSet(s, fromVar, iterationTargetTr)); + result.add(ImSet(s, ImVarAccess(fromVar), iterationTargetTr)); fromTarget = JassIm.ImExprs(ImVarAccess(fromVar)); } @@ -108,7 +102,7 @@ public static ImStmt translate(StmtForFrom s, ImTranslator t, ImFunction f) { WurstType nextReturn = nextFunc.getReturnType(); ImExpr nextCallWrapped = ExprTranslation.wrapTranslation(s, t, nextCall, nextReturn, loopVarType); - imBody.add(JassIm.ImSet(s, t.getVarFor(s.getLoopVar()), nextCallWrapped)); + imBody.add(ImSet(s, ImVarAccess(t.getVarFor(s.getLoopVar())), nextCallWrapped)); imBody.addAll(t.translateStatements(f, s.getBody())); @@ -161,7 +155,7 @@ public static ImStmt translate(StmtForIn forIn, ImTranslator t, ImFunction f) { f.getLocals().add(t.getVarFor(forIn.getLoopVar())); // create code for initializing iterator: - ImSet setIterator = JassIm.ImSet(forIn, iteratorVar, iteratorCall); + ImSet setIterator = ImSet(forIn, ImVarAccess(iteratorVar), iteratorCall); result.add(setIterator); @@ -176,7 +170,7 @@ public static ImStmt translate(StmtForIn forIn, ImTranslator t, ImFunction f) { WurstType nextReturn = nextFunc.getReturnType(); ImExpr nextCallWrapped = ExprTranslation.wrapTranslation(forIn, t, nextCall, nextReturn, loopVarType); - imBody.add(JassIm.ImSet(forIn, t.getVarFor(forIn.getLoopVar()), nextCallWrapped)); + imBody.add(ImSet(forIn, ImVarAccess(t.getVarFor(forIn.getLoopVar())), nextCallWrapped)); imBody.addAll(t.translateStatements(f, forIn.getBody())); @@ -241,7 +235,7 @@ private static ImStmt case_StmtForRange(ImTranslator t, ImFunction f, LocalVarDe Expr from = (Expr) loopVar.getInitialExpr(); ImExpr fromExpr = from.imTranslateExpr(t, f); List result = Lists.newArrayList(); - result.add(ImSet(loopVar, imLoopVar, fromExpr)); + result.add(ImSet(loopVar, ImVarAccess(imLoopVar), fromExpr)); ImExpr toExpr = addCacheVariableSmart(t, f, result, to, TypesHelper.imInt()); ImExpr stepExpr = addCacheVariableSmart(t, f, result, step, TypesHelper.imInt()); @@ -252,7 +246,7 @@ private static ImStmt case_StmtForRange(ImTranslator t, ImFunction f, LocalVarDe // loop body: imBody.addAll(t.translateStatements(f, body)); // set imLoopVar = imLoopVar + stepExpr - imBody.add(ImSet(trace, imLoopVar, ImOperatorCall(opStep, ImExprs(ImVarAccess(imLoopVar), stepExpr)))); + imBody.add(ImSet(trace, ImVarAccess(imLoopVar), ImOperatorCall(opStep, ImExprs(ImVarAccess(imLoopVar), stepExpr)))); result.add(ImLoop(trace, imBody)); return ImStatementExpr(ImStmts(result), ImNull()); } @@ -265,7 +259,7 @@ private static ImExpr addCacheVariableSmart(ImTranslator t, ImFunction f, List statements = Lists.newArrayList(); - updated = flatten(updated, statements); - + ImLExpr updated = s.getUpdatedExpr().imTranslateExprLvalue(t, f); ImExpr right = s.getRight().imTranslateExpr(t, f); - - return translateAssignment(s, updated, right, f); + return ImSet(s, updated, right); } - private static ImStmt translateAssignment(AstElementWithSource s, ImExpr updated, ImExpr right, ImFunction f) throws CompileError { - if (updated instanceof ImTupleSelection) { - ImTupleSelection tupleSelection = (ImTupleSelection) updated; - ImExpr tupleExpr = tupleSelection.getTupleExpr(); - - if (tupleExpr instanceof ImVarAccess) { - // case: tuple var - ImVarAccess va = (ImVarAccess) tupleExpr; - return ImSetTuple(s, va.getVar(), tupleSelection.getTupleIndex(), right); - } else if (tupleExpr instanceof ImVarArrayAccess) { - // case: tuple array var - ImVarArrayAccess va = (ImVarArrayAccess) tupleExpr; - return ImSetArrayTuple(s, va.getVar(), va.getIndex().copy(), tupleSelection.getTupleIndex(), right); - } else { - throw new CompileError(s.getSource(), "Cannot translate tuple access"); - } - } else if (updated instanceof ImVarAccess) { - ImVarAccess va = (ImVarAccess) updated; - return ImSet(s, va.getVar(), right); - } else if (updated instanceof ImVarArrayAccess) { - ImVarArrayAccess va = (ImVarArrayAccess) updated; - return ImSetArray(s, va.getVar(), va.getIndex().copy(), right); - } else if (updated instanceof ImVarArrayMultiAccess) { - ImVarArrayMultiAccess va = (ImVarArrayMultiAccess) updated; - return JassIm.ImSetArrayMulti(s, va.getVar(), JassIm.ImExprs(va.getIndex1().copy(), va.getIndex2().copy()), right); - } else if (updated instanceof ImTupleExpr) { - ImTupleExpr te = (ImTupleExpr) updated; - ImStmts stmts = JassIm.ImStmts(); - List parts = new ArrayList<>(); - if (right instanceof ImTupleExpr) { - parts = ((ImTupleExpr) right).getExprs().removeAll(); - } else { - // first assign to temporary and then select parts: - ImVar temp = JassIm.ImVar(s, right.attrTyp(), "tuple_temp", false); - f.getLocals().add(temp); - stmts.add(JassIm.ImSet(s, temp, right)); - for (int i = 0; i < te.getExprs().size(); i++) { - parts.add(JassIm.ImTupleSelection(JassIm.ImVarAccess(temp), i)); - } - } - - for (int i = 0; i < te.getExprs().size(); i++) { - ImExpr l = te.getExprs().get(i).copy(); - ImExpr r = parts.get(i); - stmts.add(translateAssignment(s, l, r, f)); - } - return JassIm.ImStatementExpr(stmts, JassIm.ImNull()); - } else { - throw new CompileError(s.getSource(), "Cannot translate set statement, updated = " + updated.getClass().getSimpleName()); - } - } - - - private static ImExpr flatten(ImExpr updated, List statements) { - while (updated instanceof ImStatementExpr) { - ImStatementExpr se = (ImStatementExpr) updated; - statements.addAll(se.getStatements().removeAll()); - updated = se.getExpr(); - } - return updated; - } public static ImStmt translate(StmtWhile s, ImTranslator t, ImFunction f) { List body = Lists.newArrayList(); diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/UsedVariables.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/UsedVariables.java index ce5d31deb..2a920fbd4 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/UsedVariables.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/UsedVariables.java @@ -10,29 +10,6 @@ public class UsedVariables { public static Set calculate(ImFunction f) { final Set result = Sets.newLinkedHashSet(); f.accept(new ImFunction.DefaultVisitor() { - @Override - public void visit(ImSet e) { - super.visit(e); - result.add(e.getLeft()); - } - - @Override - public void visit(ImSetArrayTuple e) { - super.visit(e); - result.add(e.getLeft()); - } - - @Override - public void visit(ImSetArray e) { - super.visit(e); - result.add(e.getLeft()); - } - - @Override - public void visit(ImSetTuple e) { - super.visit(e); - result.add(e.getLeft()); - } @Override public void visit(ImVarAccess e) { @@ -52,6 +29,47 @@ public void visit(ImVarArrayAccess e) { public static Set calculateReadVars(ImFunction f) { final Set result = Sets.newLinkedHashSet(); f.accept(new ImFunction.DefaultVisitor() { + + @Override + public void visit(ImSet e) { + Element.DefaultVisitor thiz = this; + e.getLeft().match(new ImLExpr.MatcherVoid() { + @Override + public void case_ImVarAccess(ImVarAccess e) { + // only written, not read + } + + @Override + public void case_ImStatementExpr(ImStatementExpr e) { + e.getStatements().accept(thiz); + ((ImLExpr) e.getExpr()).match(this); + } + + @Override + public void case_ImTupleSelection(ImTupleSelection e) { + ((ImLExpr) e.getTupleExpr()).match(this); + } + + @Override + public void case_ImVarArrayAccess(ImVarArrayAccess e) { + e.getIndexes().accept(thiz); + } + + @Override + public void case_ImMemberAccess(ImMemberAccess e) { + e.getReceiver().accept(thiz); + } + + @Override + public void case_ImTupleExpr(ImTupleExpr e) { + for (ImExpr ie : e.getExprs()) { + ((ImLExpr) ie).match(this); + } + } + }); + e.getRight().accept(this); + } + @Override public void visit(ImVarAccess e) { super.visit(e); diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/purity/PurityLevels.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/purity/PurityLevels.java index 7a5b263fb..4eb38a0b3 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/purity/PurityLevels.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/purity/PurityLevels.java @@ -29,18 +29,6 @@ public static PurityLevel calculate(ImSet s) { return mergeWithChildren(s, WritesGlobals.instance); } - public static PurityLevel calculate(ImSetArray s) { - return mergeWithChildren(s, WritesGlobals.instance); - } - - public static PurityLevel calculate(ImSetTuple s) { - return mergeWithChildren(s, WritesGlobals.instance); - } - - public static PurityLevel calculate(ImSetArrayTuple s) { - return mergeWithChildren(s, WritesGlobals.instance); - } - public static PurityLevel calculate(ImVarAccess s) { return mergeWithChildren(s, ReadsGlobals.instance); } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/types/TypesHelper.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/types/TypesHelper.java index ef00c40ae..5ba25dbb3 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/types/TypesHelper.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/types/TypesHelper.java @@ -1,7 +1,6 @@ package de.peeeq.wurstscript.types; -import de.peeeq.wurstscript.jassIm.ImSimpleType; -import de.peeeq.wurstscript.jassIm.ImType; +import de.peeeq.wurstscript.jassIm.*; public class TypesHelper { @@ -31,6 +30,20 @@ public static ImType imBool() { return WurstTypeBool.instance().imTranslateType(); } + public static ImArrayType imIntArray() { + return JassIm.ImArrayType(imInt()); + } + + public static ImArrayType imStringArray() { + return JassIm.ImArrayType(imString()); + } + + public static boolean typeContainsTuples(ImType vt) { + return vt instanceof ImTupleType + || vt instanceof ImArrayType && typeContainsTuples(((ImArrayType) vt).getEntryType()) + || vt instanceof ImArrayTypeMulti && typeContainsTuples(((ImArrayTypeMulti) vt).getEntryType()); + } + // public static boolean checkTypeArgs(InstanceDef iDef, List classParams, List interfaceParams) { // if (classParams.size() == 0 && interfaceParams.size() == 0) { // return true; diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/types/WurstType.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/types/WurstType.java index a8af63974..e07ec75bd 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/types/WurstType.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/types/WurstType.java @@ -2,6 +2,7 @@ import de.peeeq.wurstscript.ast.Element; import de.peeeq.wurstscript.ast.TypeParamDef; +import de.peeeq.wurstscript.ast.VarDef; import de.peeeq.wurstscript.attributes.names.FuncLink; import de.peeeq.wurstscript.attributes.names.NameLink; import de.peeeq.wurstscript.jassIm.ImExprOpt; diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/types/WurstTypeArray.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/types/WurstTypeArray.java index 6bdd76af8..3a97228b9 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/types/WurstTypeArray.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/types/WurstTypeArray.java @@ -112,27 +112,18 @@ public int getSize(int i) { public ImType imTranslateType() { initSizes(); ImType bt = baseType.imTranslateType(); - - if (bt instanceof ImSimpleType) { - String typename = ((ImSimpleType) bt).getTypename(); - if (sizes.length > 0) { - if (sizes[0] == 0) { - return JassIm.ImArrayType(typename); - } - List nsizes = Lists.newArrayList(); - for (int size : sizes) { - nsizes.add(size); - } - - return JassIm.ImArrayTypeMulti(typename, nsizes); + if (sizes.length > 0) { + if (sizes[0] == 0) { + return JassIm.ImArrayType(bt); + } + List nsizes = Lists.newArrayList(); + for (int size : sizes) { + nsizes.add(size); } - return JassIm.ImArrayType(typename); - } else if (bt instanceof ImTupleType) { - ImTupleType tt = (ImTupleType) bt; - return JassIm.ImTupleArrayType(tt.getTypes(), tt.getNames()); - } else { - throw new Error("cannot translate array type " + getName() + " " + bt); + + return JassIm.ImArrayTypeMulti(bt, nsizes); } + return JassIm.ImArrayType(bt); } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/types/WurstTypeIntLiteral.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/types/WurstTypeIntLiteral.java index a34d056d1..357b49b6d 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/types/WurstTypeIntLiteral.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/types/WurstTypeIntLiteral.java @@ -39,7 +39,7 @@ public ImExprOpt getDefaultValue() { @Override public ImSimpleType imTranslateType() { - return JassIm.ImSimpleType("integer"); + return TypesHelper.imInt(); } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/types/WurstTypeTuple.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/types/WurstTypeTuple.java index 678b7454c..43ecfc5cb 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/types/WurstTypeTuple.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/types/WurstTypeTuple.java @@ -3,10 +3,10 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import de.peeeq.wurstscript.ast.Element; -import de.peeeq.wurstscript.ast.TupleDef; -import de.peeeq.wurstscript.ast.TypeParamDef; -import de.peeeq.wurstscript.ast.WParameter; +import de.peeeq.wurstscript.ast.*; +import de.peeeq.wurstscript.attributes.CompileError; import de.peeeq.wurstscript.jassIm.*; +import de.peeeq.wurstscript.utils.Utils; import fj.data.TreeMap; import org.eclipse.jdt.annotation.Nullable; @@ -57,17 +57,8 @@ public ImType imTranslateType() { List names = Lists.newArrayList(); for (WParameter p : tupleDef.getParameters()) { ImType pt = p.attrTyp().imTranslateType(); - if (pt instanceof ImTupleType) { - ImTupleType ptt = (ImTupleType) pt; - // add flattened - for (int i = 0; i < ptt.getTypes().size(); i++) { - types.add(ptt.getTypes().get(i)); - names.add(p.getName() + "_" + ptt.getNames().get(i)); - } - } else { - types.add(pt); - names.add(p.getName()); - } + types.add(pt); + names.add(p.getName()); } return JassIm.ImTupleType(types, names); } @@ -80,4 +71,13 @@ public ImExprOpt getDefaultValue() { } return JassIm.ImTupleExpr(exprs); } + + public int getTupleIndex(VarDef varDef) { + WParameter v = (WParameter) varDef; + int index = tupleDef.getParameters().indexOf(v); + if (index < 0) { + throw new CompileError(varDef.getSource(), "Could not determine tuple index of " + Utils.printElementWithSource(varDef) + " in tuple " + this); + } + return index; + } } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/utils/Utils.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/utils/Utils.java index 47dbb6baa..5db401751 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/utils/Utils.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/utils/Utils.java @@ -7,8 +7,11 @@ import com.google.common.io.Files; import de.peeeq.wurstio.Pjass; import de.peeeq.wurstscript.ast.*; +import de.peeeq.wurstscript.attributes.CompileError; import de.peeeq.wurstscript.attributes.names.NameLink; import de.peeeq.wurstscript.attributes.prettyPrint.DefaultSpacer; +import de.peeeq.wurstscript.jassIm.ImExpr; +import de.peeeq.wurstscript.jassIm.ImFunctionCall; import de.peeeq.wurstscript.jassIm.JassImElementWithName; import de.peeeq.wurstscript.parser.WPos; import de.peeeq.wurstscript.types.WurstType; @@ -128,6 +131,10 @@ public static String printSep(String sep, String[] args) { return sb.toString(); } + public static String printSep(String sep, List args) { + return args.stream().map(Object::toString).collect(Collectors.joining(sep)); + } + /** * is a piece of code jass code? */ @@ -996,4 +1003,23 @@ public static String printTypeExpr(TypeExpr t) { } return wt.toString(); } + + /** + * Replaces oldElement with newElement in parent + */ + public static void replace(de.peeeq.wurstscript.jassIm.Element parent, de.peeeq.wurstscript.jassIm.Element oldElement, de.peeeq.wurstscript.jassIm.Element newElement) { + if (oldElement == newElement) { + return; + } + de.peeeq.wurstscript.jassIm.Element oldElementParent = oldElement.getParent(); + for (int i=0; i 0 ) { // for( int j = 0; j>>>>>>>>>>>>>>>"+c.getExpr()); - // WLogger.info(">>>>>>>>>>>>>>>>"+s.getCases().get(j).getExpr()); - // if ( c.getExpr().attrN.equals(s.getCases().get(j).getExpr()) + // WLogger.info(">>>>>>>>>>>>>>>>"+c.getExprs()); + // WLogger.info(">>>>>>>>>>>>>>>>"+s.getCases().get(j).getExprs()); + // if ( c.getExprs().attrN.equals(s.getCases().get(j).getExprs()) // ) // c.addError("Case " + j + " and " + i + " are the same."); // } diff --git a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/ArrayTests.java b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/ArrayTests.java index cf6736833..9ae95bc80 100644 --- a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/ArrayTests.java +++ b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/ArrayTests.java @@ -119,6 +119,21 @@ public void array_init_global_fail3() { ); } + @Test + public void multiArrayDefaultValue() { + testAssertOkLines(true, + "package test", + "native testSuccess()", + "class C", + " int array[5] v", + "init", + " let c = new C", + " c.v[2] = c.v[3] + 1", + " if c.v[2] == 1", + " testSuccess()" + ); + } + public void assertOk(boolean executeProg, String... input) { String prog = "package test\n" + diff --git a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/TupleTests.java b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/TupleTests.java index a512b632e..3c18cc24b 100644 --- a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/TupleTests.java +++ b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/TupleTests.java @@ -437,4 +437,94 @@ public void nestedTuple() { // #713 } + @Test + public void nestedTuple2() { // #713 + testAssertOkLines(true, + "package test", + "native testSuccess()", + "native println(string s)", + "@extern native I2S(int x) returns string", + "function print(int x)", + " println(I2S(x))", + "tuple parent(child a, child b)", + "tuple child(int x, int y, int z)", + "init", + " var t = parent(child(1,2,3), child(4,5,6))", + " print(t.a.x)", + " print(t.a.y)", + " print(t.a.z)", + " print(t.b.x)", + " print(t.b.y)", + " print(t.b.z)", + " t.a = child(7,8,9)", + " print(t.a.x)", + " print(t.a.y)", + " print(t.a.z)", + " if t.a == child(7, 8, 9)", + " testSuccess()" + ); + } + + @Test + public void tupleArrayInClass() { // see #572 + testAssertOkLines(true, + "package test", + "native testSuccess()", + "class C", + " angle array[2] ang", + "tuple angle(real rad)", + "init", + " let c = new C", + " c.ang[0] = angle(4.)", + " c.ang[1] = angle(2.)", + " if c.ang[0].rad == 4. and c.ang[1].rad == 2", + " testSuccess()" + ); + } + + @Test + public void tupleArrayInClass2() { // see #572 + testAssertOkLines(true, + "package test", + "native testSuccess()", + "@extern native R2S(real r) returns string", + "native println(string s)", + "class C", + " vec array[5] v", + "tuple vec(real x, real y, real z)", + "init", + " let c = new C", + " c.v[0] = vec(1,2,3)", + " c.v[1].x = 5", + " c.v[1].y = 6", + " c.v[1].z = 7", + " println(R2S(c.v[0].x))", + " println(R2S(c.v[0].z))", + " println(R2S(c.v[1].y))", + " if c.v[0].x == 1 and c.v[0].z == 3 and c.v[1].y == 6", + " testSuccess()" + ); + } + + @Test + public void tupleArraySideEvaluationOrder() { + testAssertOkLines(true, + "package test", + "native testSuccess()", + "int x = 1", + "tuple p(int x, int y)", + "p array ar", + "function foo() returns int", + " x = x * 2", + " return 1", + "function bar() returns int", + " x = x + 1", + " return 1", + "init", + " ar[foo()] = p(bar(), 7)", + " if x == 3 and ar[1].x == 1 and ar[1].y == 7", + " testSuccess()" + ); + } + }