• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

wurstscript / WurstScript / 271

29 Sep 2025 12:12PM UTC coverage: 64.649% (+2.4%) from 62.222%
271

Pull #1096

circleci

Frotty
Merge branch 'perf-improvements' of https://github.com/wurstscript/WurstScript into perf-improvements
Pull Request #1096: Perf improvements

18202 of 28155 relevant lines covered (64.65%)

0.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.67
de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/StmtTranslation.java
1
package de.peeeq.wurstscript.translation.imtranslation;
2

3
import com.google.common.collect.Lists;
4
import de.peeeq.wurstscript.WurstOperator;
5
import de.peeeq.wurstscript.ast.*;
6
import de.peeeq.wurstscript.ast.Element;
7
import de.peeeq.wurstscript.attributes.CompileError;
8
import de.peeeq.wurstscript.attributes.names.FuncLink;
9
import de.peeeq.wurstscript.jassIm.*;
10
import de.peeeq.wurstscript.types.TypesHelper;
11
import de.peeeq.wurstscript.types.WurstType;
12
import de.peeeq.wurstscript.types.WurstTypeVararg;
13

14
import java.util.List;
15
import java.util.Optional;
16

17
import static de.peeeq.wurstscript.jassIm.JassIm.*;
18

19
public class StmtTranslation {
×
20

21
    public static ImStmt translate(Expr s, ImTranslator t, ImFunction f) {
22
        return s.imTranslateExpr(t, f);
1✔
23
    }
24

25
    public static ImStmt translate(LocalVarDef s, ImTranslator t, ImFunction f) {
26
        ImVar v = t.getVarFor(s);
1✔
27
        f.getLocals().add(v);
1✔
28
        if (s.getInitialExpr() instanceof Expr) {
1✔
29
            Expr inital = (Expr) s.getInitialExpr();
1✔
30
            return ImSet(s, ImVarAccess(v), inital.imTranslateExpr(t, f));
1✔
31
        } else if (s.getInitialExpr() instanceof ArrayInitializer) {
1✔
32
            ArrayInitializer ai = (ArrayInitializer) s.getInitialExpr();
1✔
33
            ImStmts stmts = ImStmts();
1✔
34
            for (int i = 0; i < ai.getValues().size(); i++) {
1✔
35
                Expr expr = ai.getValues().get(i);
1✔
36
                ImExpr translatedExpr = expr.imTranslateExpr(t, f);
1✔
37
                stmts.add(ImSet(s, ImVarArrayAccess(s, v, ImExprs(JassIm.ImIntVal(i))), translatedExpr));
1✔
38
            }
39
            return ImHelper.statementExprVoid(stmts);
1✔
40
        } else {
41
            return ImHelper.nullExpr();
1✔
42
        }
43
    }
44

45

46
    public static ImStmt translate(StmtErr s, ImTranslator t, ImFunction f) {
47
        throw new CompileError(s.getSource(), "Source contains errors.");
×
48
    }
49

50

51
    public static ImStmt translate(StmtExitwhen s, ImTranslator t, ImFunction f) {
52
        return ImExitwhen(s, s.getCond().imTranslateExpr(t, f));
1✔
53
    }
54

55

56
    public static ImStmt translate(StmtForFrom s, ImTranslator t, ImFunction f) {
57
        Expr iterationTarget = s.getIn();
1✔
58
        // Type of loop Variable:
59
        WurstType loopVarType = s.getLoopVar().attrTyp();
1✔
60
        List<ImStmt> result = Lists.newArrayList();
1✔
61
        Optional<FuncLink> nextFuncOpt = s.attrGetNextFunc();
1✔
62
        Optional<FuncLink> hasNextFuncOpt = s.attrHasNextFunc();
1✔
63
        if (nextFuncOpt.isPresent() && hasNextFuncOpt.isPresent()) {
1✔
64
            FuncLink nextFunc = nextFuncOpt.get();
1✔
65
            FuncLink hasNextFunc = hasNextFuncOpt.get();
1✔
66

67
            // get the iterator function in the intermediate language
68
            ImFunction nextFuncIm = t.getFuncFor(nextFunc.getDef());
1✔
69
            ImFunction hasNextFuncIm = t.getFuncFor(hasNextFunc.getDef());
1✔
70

71
            f.getLocals().add(t.getVarFor(s.getLoopVar()));
1✔
72

73
            ImExprs fromTarget;
74
            if (iterationTarget.attrTyp().isStaticRef()) {
1✔
75
                fromTarget = ImExprs();
×
76
            } else {
77
                // store from-expression in variable, so that it is only evaluated once
78
                ImExpr iterationTargetTr = iterationTarget.imTranslateExpr(t, f);
1✔
79
                ImVar fromVar = ImVar(s, iterationTargetTr.attrTyp(), "from", false);
1✔
80
                f.getLocals().add(fromVar);
1✔
81
                result.add(ImSet(s, ImVarAccess(fromVar), iterationTargetTr));
1✔
82
                fromTarget = JassIm.ImExprs(ImVarAccess(fromVar));
1✔
83
            }
84

85
            ImStmts imBody = ImStmts();
1✔
86
            // exitwhen not #hasNext()
87
            imBody.add(ImExitwhen(s, JassIm.ImOperatorCall(WurstOperator.NOT, JassIm.ImExprs(ImFunctionCall(s, hasNextFuncIm, ImTypeArguments(), fromTarget, false, CallType
1✔
88
                    .NORMAL)))));
89
            // elem = next()
90
            ImFunctionCall nextCall = ImFunctionCall(s, nextFuncIm, ImTypeArguments(), fromTarget.copy(), false, CallType.NORMAL);
1✔
91

92
            WurstType nextReturn = nextFunc.getReturnType();
1✔
93
            ImExpr nextCallWrapped = ExprTranslation.wrapTranslation(s, t, nextCall, nextReturn, loopVarType);
1✔
94

95
            imBody.add(ImSet(s, ImVarAccess(t.getVarFor(s.getLoopVar())), nextCallWrapped));
1✔
96

97
            imBody.addAll(t.translateStatements(f, s.getBody()));
1✔
98

99
            result.add(ImLoop(s, imBody));
1✔
100
        }
101

102
        return ImHelper.statementExprVoid(ImStmts(result));
1✔
103
    }
104

105

106
    public static ImStmt translate(StmtForIn forIn, ImTranslator t, ImFunction f) {
107
        Expr iterationTarget = forIn.getIn();
1✔
108
        WurstType itrType = iterationTarget.attrTyp();
1✔
109
        if (itrType instanceof WurstTypeVararg) {
1✔
110
            return case_StmtForVararg(forIn, t, f);
1✔
111
        }
112
        List<ImStmt> result = Lists.newArrayList();
1✔
113

114
        Optional<FuncLink> iteratorFuncOpt = forIn.attrIteratorFunc();
1✔
115
        Optional<FuncLink> nextFuncOpt = forIn.attrGetNextFunc();
1✔
116
        Optional<FuncLink> hasNextFuncOpt = forIn.attrHasNextFunc();
1✔
117
        if (iteratorFuncOpt.isPresent() && nextFuncOpt.isPresent() && hasNextFuncOpt.isPresent()) {
1✔
118
            FuncLink iteratorFunc = iteratorFuncOpt.get();
1✔
119
            FuncLink nextFunc = nextFuncOpt.get();
1✔
120
            FuncLink hasNextFunc = hasNextFuncOpt.get();
1✔
121

122
            // Type of loop Variable:
123
            WurstType loopVarType = forIn.getLoopVar().attrTyp();
1✔
124

125
            // get the iterator function in the intermediate language
126
            ImFunction iteratorFuncIm = t.getFuncFor(iteratorFunc.getDef());
1✔
127
            ImFunction nextFuncIm = t.getFuncFor(nextFunc.getDef());
1✔
128
            ImFunction hasNextFuncIm = t.getFuncFor(hasNextFunc.getDef());
1✔
129

130
            // translate target:
131
            ImExprs iterationTargetList;
132
            if (forIn.getIn().attrTyp().isStaticRef()) {
1✔
133
                iterationTargetList = ImExprs();
1✔
134
            } else {
135
                ImExpr iterationTargetIm = forIn.getIn().imTranslateExpr(t, f);
1✔
136
                iterationTargetList = JassIm.ImExprs(iterationTargetIm);
1✔
137
            }
138

139
            // call XX.iterator()
140
            ImFunctionCall iteratorCall = ImFunctionCall(forIn, iteratorFuncIm, ImTypeArguments(), iterationTargetList, false, CallType.NORMAL);
1✔
141
            // create IM-variable for iterator
142
            ImVar iteratorVar = JassIm.ImVar(forIn.getLoopVar(), iteratorCall.attrTyp(), "iterator", false);
1✔
143

144
            f.getLocals().add(iteratorVar);
1✔
145
            f.getLocals().add(t.getVarFor(forIn.getLoopVar()));
1✔
146
            // create code for initializing iterator:
147

148
            ImSet setIterator = ImSet(forIn, ImVarAccess(iteratorVar), iteratorCall);
1✔
149

150
            result.add(setIterator);
1✔
151

152
            ImStmts imBody = ImStmts();
1✔
153
            // exitwhen not #hasNext()
154
            imBody.add(ImExitwhen(forIn, JassIm.ImOperatorCall(WurstOperator.NOT, JassIm.ImExprs(ImFunctionCall(forIn, hasNextFuncIm, ImTypeArguments(), JassIm.ImExprs
1✔
155
                    (JassIm
1✔
156
                            .ImVarAccess(iteratorVar)), false, CallType.NORMAL)))));
1✔
157
            // elem = next()
158
            ImFunctionCall nextCall = ImFunctionCall(forIn, nextFuncIm, ImTypeArguments(), JassIm.ImExprs(JassIm.ImVarAccess(iteratorVar)), false, CallType.NORMAL);
1✔
159
            WurstType nextReturn = nextFunc.getReturnType();
1✔
160
            ImExpr nextCallWrapped = ExprTranslation.wrapTranslation(forIn, t, nextCall, nextReturn, loopVarType);
1✔
161

162
            imBody.add(ImSet(forIn, ImVarAccess(t.getVarFor(forIn.getLoopVar())), nextCallWrapped));
1✔
163

164
            imBody.addAll(t.translateStatements(f, forIn.getBody()));
1✔
165

166
            Optional<FuncLink> closeFunc = forIn.attrCloseFunc();
1✔
167
            closeFunc.ifPresent(funcLink -> {
1✔
168

169
                // close iterator before each return
170
                imBody.accept(new de.peeeq.wurstscript.jassIm.Element.DefaultVisitor() {
1✔
171
                    @Override
172
                    public void visit(ImReturn imReturn) {
173
                        super.visit(imReturn);
1✔
174
                        imReturn.replaceBy(ImHelper.statementExprVoid(JassIm.ImStmts(ImFunctionCall(forIn, t.getFuncFor(funcLink.getDef()), ImTypeArguments(), JassIm
1✔
175
                                .ImExprs(JassIm.ImVarAccess(iteratorVar)), false, CallType.NORMAL), imReturn.copy())));
1✔
176
                    }
1✔
177

178
                });
179

180
            });
1✔
181

182
            result.add(ImLoop(forIn, imBody));
1✔
183
            // close iterator after loop
184
            closeFunc.ifPresent(nameLink -> result.add(ImFunctionCall(forIn, t.getFuncFor(nameLink.getDef()), ImTypeArguments(), JassIm.ImExprs(JassIm
1✔
185
                    .ImVarAccess(iteratorVar)), false, CallType.NORMAL)));
1✔
186

187
        }
188

189

190
        return ImHelper.statementExprVoid(ImStmts(result));
1✔
191
    }
192

193
    /**
194
     * Translate a for in vararg loop. Unlike the other for loops we don't need
195
     * an iterator etc. because the loop is unrolled in the VarargEliminator
196
     */
197
    private static ImStmt case_StmtForVararg(StmtForIn s, ImTranslator t, ImFunction f) {
198
        List<ImStmt> result = Lists.newArrayList();
1✔
199
        ImVar loopVar = t.getVarFor(s.getLoopVar());
1✔
200

201
        result.add(ImVarargLoop(s, ImStmts(t.translateStatements(f, s.getBody())), loopVar));
1✔
202

203
        f.getLocals().add(loopVar);
1✔
204
        return ImHelper.statementExprVoid(ImStmts(result));
1✔
205
    }
206

207

208
    public static ImStmt translate(StmtForRangeUp s, ImTranslator t, ImFunction f) {
209
        return case_StmtForRange(t, f, s.getLoopVar(), s.getTo(), s.getStep(), s.getBody(), WurstOperator.PLUS,
1✔
210
                WurstOperator.GREATER, s);
211
    }
212

213

214
    public static ImStmt translate(StmtForRangeDown s, ImTranslator t, ImFunction f) {
215
        return case_StmtForRange(t, f, s.getLoopVar(), s.getTo(), s.getStep(), s.getBody(),
1✔
216
                WurstOperator.MINUS, WurstOperator.LESS, s);
217
    }
218

219
    private static ImStmt case_StmtForRange(ImTranslator t, ImFunction f, LocalVarDef loopVar,
220
                                            Expr to, Expr step, WStatements body, WurstOperator opStep, WurstOperator opCompare, Element trace) {
221
        ImVar imLoopVar = t.getVarFor(loopVar);
1✔
222
        f.getLocals().add(imLoopVar);
1✔
223

224
        Expr from = (Expr) loopVar.getInitialExpr();
1✔
225
        ImExpr fromExpr = from.imTranslateExpr(t, f);
1✔
226
        List<ImStmt> result = Lists.newArrayList();
1✔
227
        result.add(ImSet(loopVar, ImVarAccess(imLoopVar), fromExpr));
1✔
228

229
        ImExpr toExpr = addCacheVariableSmart(t, f, result, to, TypesHelper.imInt());
1✔
230
        ImExpr stepExpr = addCacheVariableSmart(t, f, result, step, TypesHelper.imInt());
1✔
231

232
        ImStmts imBody = ImStmts();
1✔
233
        // exitwhen imLoopVar > toExpr
234
        imBody.add(ImExitwhen(trace, ImOperatorCall(opCompare, ImExprs(ImVarAccess(imLoopVar), toExpr))));
1✔
235
        // loop body:
236
        imBody.addAll(t.translateStatements(f, body));
1✔
237
        // set imLoopVar = imLoopVar + stepExpr
238
        imBody.add(ImSet(trace, ImVarAccess(imLoopVar), ImOperatorCall(opStep, ImExprs(ImVarAccess(imLoopVar), stepExpr))));
1✔
239
        result.add(ImLoop(trace, imBody));
1✔
240
        return ImHelper.statementExprVoid(ImStmts(result));
1✔
241
    }
242

243

244
    private static ImExpr addCacheVariableSmart(ImTranslator t, ImFunction f, List<ImStmt> result, Expr toCache, ImType type) {
245
        ImExpr r = toCache.imTranslateExpr(t, f);
1✔
246
        if (r instanceof ImConst) {
1✔
247
            return r;
1✔
248
        }
249
        ImVar tempVar = JassIm.ImVar(toCache, type, "temp", false);
1✔
250
        f.getLocals().add(tempVar);
1✔
251
        result.add(ImSet(toCache, ImVarAccess(tempVar), r));
1✔
252
        return ImVarAccess(tempVar);
1✔
253
    }
254

255
    public static ImStmt translate(StmtIf s, ImTranslator t, ImFunction f) {
256
        return ImIf(s, s.getCond().imTranslateExpr(t, f), ImStmts(t.translateStatements(f, s.getThenBlock())), ImStmts(t.translateStatements(f, s
1✔
257
                .getElseBlock())));
1✔
258
    }
259

260

261
    public static ImStmt translate(StmtLoop s, ImTranslator t, ImFunction f) {
262
        return ImLoop(s, ImStmts(t.translateStatements(f, s.getBody())));
1✔
263
    }
264

265

266
    public static ImStmt translate(StmtReturn s, ImTranslator t, ImFunction f) {
267
        return ImReturn(s, s.getReturnedObj().imTranslateExprOpt(t, f));
1✔
268
    }
269

270

271
    public static ImStmt translate(StmtSet s, ImTranslator t, ImFunction f) {
272
        ImLExpr updated = s.getUpdatedExpr().imTranslateExprLvalue(t, f);
1✔
273
        ImExpr right = s.getRight().imTranslateExpr(t, f);
1✔
274
        return ImSet(s, updated, right);
1✔
275
    }
276

277

278
    public static ImStmt translate(StmtWhile s, ImTranslator t, ImFunction f) {
279
        List<ImStmt> body = Lists.newArrayList();
1✔
280
        // exitwhen not while_condition
281
        body.add(ImExitwhen(s.getCond(), ImOperatorCall(WurstOperator.NOT, ImExprs(s.getCond().imTranslateExpr(t, f)))));
1✔
282
        body.addAll(t.translateStatements(f, s.getBody()));
1✔
283
        return ImLoop(s, ImStmts(body));
1✔
284
    }
285

286
    public static ImStmt translate(StmtSkip s, ImTranslator translator, ImFunction f) {
287
        return ImHelper.nullExpr();
1✔
288
    }
289

290
    public static ImStmt translate(SwitchStmt switchStmt, ImTranslator t, ImFunction f) {
291
        List<ImStmt> result = Lists.newArrayList();
1✔
292
        ImType type = switchStmt.getExpr().attrTyp().imTranslateType(t);
1✔
293
        ImExpr tempVar = addCacheVariableSmart(t, f, result, switchStmt.getExpr(), type);
1✔
294
        // generate ifs
295
        // leerer Block:
296
        //ImStmts();
297
        // if else
298
        //ImIf(trace, condition, thenBlock, elseBlock);
299
        // vergleich
300
        //ImOperatorCall(Ast.OpEquals(), ImExprs(a,b))
301

302
        ImIf lastIf = null;
1✔
303
        SwitchCase cse;
304
        for (int i = 0; i < switchStmt.getCases().size(); i++) {
1✔
305
            cse = switchStmt.getCases().get(i);
1✔
306
            if (lastIf == null) {
1✔
307
                lastIf = ImIf(switchStmt, translateSwitchCase(cse, tempVar, f, t), ImStmts(t
1✔
308
                        .translateStatements(f, cse.getStmts())), ImStmts());
1✔
309
                result.add(lastIf);
1✔
310
            } else if (i == switchStmt.getCases().size() - 1
1✔
311
                    && switchStmt.getSwitchDefault() instanceof NoDefaultCase
1✔
312
                    && switchStmt.calculateHandlesAllCases()) {
1✔
313
                // if this is the last case and all cases are covered, then just add
314
                // the code to the else statement without checking the condition:
315
                lastIf.setElseBlock(ImStmts(t.translateStatements(f, cse.getStmts())));
1✔
316
            } else {
317
                ImIf tmp = ImIf(switchStmt, translateSwitchCase(cse, tempVar, f, t), ImStmts
1✔
318
                        (t.translateStatements(f, cse.getStmts())), ImStmts());
1✔
319
                lastIf.setElseBlock(ImStmts(tmp));
1✔
320
                lastIf = tmp;
1✔
321
            }
322
        }
323

324
        if (lastIf == null) {
1✔
325
            throw new CompileError(switchStmt.attrSource(), "No cases in switch?");
×
326
        }
327

328
//                WLogger.info("it is a " + switchStmt.getSwitchDefault().getClass());
329
        if (switchStmt.getSwitchDefault() instanceof SwitchDefaultCaseStatements) {
1✔
330

331
//                        WLogger.info("indeed it is");
332
            SwitchDefaultCaseStatements dflt = (SwitchDefaultCaseStatements) switchStmt.getSwitchDefault();
1✔
333
            lastIf.setElseBlock(ImStmts(t.translateStatements(f, dflt.getStmts())));
1✔
334
        } else if (switchStmt.getSwitchDefault() instanceof NoDefaultCase) {
1✔
335
//                        WLogger.info("wtf?");
336
        }
337

338

339
        return ImHelper.statementExprVoid(ImStmts(result));
1✔
340
    }
341

342
    /**
343
     * translate the expressions of a switch case to
344
     * <p>
345
     * case x | y | z
346
     * <p>
347
     * is translated to
348
     * <p>
349
     * tempVar == x or tempVar == y or tempVar == z
350
     */
351
    private static ImExpr translateSwitchCase(SwitchCase cse, ImExpr tempVar, ImFunction f, ImTranslator t) {
352
        return cse.getExpressions()
1✔
353
                .stream()
1✔
354
                .<ImExpr>map(e -> ImOperatorCall(WurstOperator.EQ, ImExprs(tempVar.copy(), e.imTranslateExpr(t, f))))
1✔
355
                .reduce((x, y) -> ImOperatorCall(WurstOperator.OR, ImExprs(x, y)))
1✔
356
                .orElseGet(() -> JassIm.ImBoolVal(true));
1✔
357
    }
358

359
    public static ImStmt translate(EndFunctionStatement endFunctionStatement, ImTranslator translator, ImFunction f) {
360
        return ImHelper.nullExpr();
1✔
361
    }
362

363
    public static ImStmt translate(StartFunctionStatement startFunctionStatement, ImTranslator translator, ImFunction f) {
364
        return ImHelper.nullExpr();
1✔
365
    }
366

367
    public static ImStmt translate(WBlock block, ImTranslator translator, ImFunction f) {
368
        ImStmts stmts = ImStmts();
×
369
        for (WStatement s : block.getBody()) {
×
370
            stmts.add(s.imTranslateStmt(translator, f));
×
371
        }
×
372
        return ImHelper.statementExprVoid(stmts);
×
373
    }
374

375

376
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc