• 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

87.39
de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ExprTranslation.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.NameLink;
9
import de.peeeq.wurstscript.attributes.names.OtherLink;
10
import de.peeeq.wurstscript.jassIm.*;
11
import de.peeeq.wurstscript.types.*;
12
import de.peeeq.wurstscript.utils.Utils;
13
import io.vavr.control.Either;
14
import io.vavr.control.Option;
15
import org.eclipse.jdt.annotation.Nullable;
16

17
import java.util.HashMap;
18
import java.util.List;
19
import java.util.Map;
20

21
import static de.peeeq.wurstscript.jassIm.JassIm.*;
22

23
public class ExprTranslation {
×
24

25
    public static ImExpr translate(ExprBinary e, ImTranslator t, ImFunction f) {
26
        return wrapTranslation(e, t, translateIntern(e, t, f));
1✔
27
    }
28

29
    public static ImExpr translate(ExprUnary e, ImTranslator t, ImFunction f) {
30
        return wrapTranslation(e, t, translateIntern(e, t, f));
1✔
31
    }
32

33
    public static ImExpr translate(ExprBoolVal e, ImTranslator t, ImFunction f) {
34
        return wrapTranslation(e, t, translateIntern(e, t, f));
1✔
35
    }
36

37
    public static ImExpr translate(ExprFuncRef e, ImTranslator t, ImFunction f) {
38
        return wrapTranslation(e, t, translateIntern(e, t, f));
1✔
39
    }
40

41
    public static ImExpr translate(ExprIntVal e, ImTranslator t, ImFunction f) {
42
        return wrapTranslation(e, t, translateIntern(e, t, f));
1✔
43
    }
44

45
    public static ImExpr translate(ExprNull e, ImTranslator t, ImFunction f) {
46
        return wrapTranslation(e, t, translateIntern(e, t, f));
1✔
47
    }
48

49
    public static ImExpr translate(ExprRealVal e, ImTranslator t, ImFunction f) {
50
        return wrapTranslation(e, t, translateIntern(e, t, f));
1✔
51
    }
52

53
    public static ImExpr translate(ExprStringVal e, ImTranslator t, ImFunction f) {
54
        return wrapTranslation(e, t, translateIntern(e, t, f));
1✔
55
    }
56

57
    public static ImExpr translate(ExprThis e, ImTranslator t, ImFunction f) {
58
        return wrapTranslation(e, t, translateIntern(e, t, f));
1✔
59
    }
60

61
    public static ImExpr translate(ExprSuper e, ImTranslator t, ImFunction f) {
62
        return wrapTranslation(e, t, translateIntern(e, t, f));
×
63
    }
64

65
    public static ImExpr translate(NameRef e, ImTranslator t, ImFunction f) {
66
        return wrapTranslation(e, t, translateIntern(e, t, f));
1✔
67
    }
68

69
    public static ImExpr translate(ExprCast e, ImTranslator t, ImFunction f) {
70
        return wrapTranslation(e, t, translateIntern(e, t, f));
1✔
71
    }
72

73
    public static ImExpr translate(FunctionCall e, ImTranslator t, ImFunction f) {
74
        return wrapTranslation(e, t, translateIntern(e, t, f));
1✔
75
    }
76

77
    public static ImExpr translate(ExprIncomplete e, ImTranslator t, ImFunction f) {
78
        return wrapTranslation(e, t, translateIntern(e, t, f));
×
79
    }
80

81
    public static ImExpr translate(ExprNewObject e, ImTranslator t, ImFunction f) {
82
        return wrapTranslation(e, t, translateIntern(e, t, f));
1✔
83
    }
84

85
    public static ImExpr translate(ExprInstanceOf e, ImTranslator t, ImFunction f) {
86
        return wrapTranslation(e, t, translateIntern(e, t, f));
1✔
87
    }
88

89
    private static ImExpr wrapTranslation(Expr e, ImTranslator t, ImExpr translated) {
90
        WurstType actualType = e.attrTypRaw();
1✔
91
        WurstType expectedTypRaw = e.attrExpectedTypRaw();
1✔
92
        return wrapTranslation(e, t, translated, actualType, expectedTypRaw);
1✔
93
    }
94

95
    static ImExpr wrapLua(Element trace, ImTranslator t, ImExpr translated, WurstType actualType) {
96
        // use ensureType functions for lua
97
        // these functions convert nil to the default value for primitive types (int, string, bool, real)
98
        if (t.isLuaTarget() && actualType instanceof WurstTypeBoundTypeParam) {
1✔
99
            WurstTypeBoundTypeParam wtb = (WurstTypeBoundTypeParam) actualType;
1✔
100

101
            @Nullable ImFunction ensureType = null;
1✔
102
            switch (wtb.getName()) {
1✔
103
                case "integer":
104
                    ensureType = t.ensureIntFunc;
1✔
105
                    break;
1✔
106
                case "string":
107
                    ensureType = t.ensureStrFunc;
×
108
                    break;
×
109
                case "boolean":
110
                    ensureType = t.ensureBoolFunc;
×
111
                    break;
×
112
                case "real":
113
                    ensureType = t.ensureRealFunc;
×
114
                    break;
115
            }
116
            if(ensureType != null) {
1✔
117
                return ImFunctionCall(trace, ensureType, ImTypeArguments(), JassIm.ImExprs(translated), false, CallType.NORMAL);
1✔
118
            }
119
        }
120
        return translated;
1✔
121
    }
122

123
    static ImExpr wrapTranslation(Element trace, ImTranslator t, ImExpr translated, WurstType actualType, WurstType expectedTypRaw) {
124
        ImFunction toIndex = null;
1✔
125
        ImFunction fromIndex = null;
1✔
126
        if (actualType instanceof WurstTypeBoundTypeParam) {
1✔
127
            WurstTypeBoundTypeParam wtb = (WurstTypeBoundTypeParam) actualType;
1✔
128
            FuncDef fromIndexFunc = wtb.getFromIndex();
1✔
129
            if (fromIndexFunc != null) {
1✔
130
                fromIndex = t.getFuncFor(fromIndexFunc);
1✔
131
            }
132
        }
133
        if (expectedTypRaw instanceof WurstTypeBoundTypeParam) {
1✔
134
            WurstTypeBoundTypeParam wtb = (WurstTypeBoundTypeParam) expectedTypRaw;
1✔
135
            FuncDef toIndexFunc = wtb.getToIndex();
1✔
136
            if (toIndexFunc != null) {
1✔
137
                toIndex = t.getFuncFor(toIndexFunc);
1✔
138
            }
139
        }
140

141
//        System.out.println("CAll " + Utils.prettyPrintWithLine(trace));
142
//        System.out.println("  actualType = " + actualType.getFullName());
143
//        System.out.println("  expectedTypRaw = " + expectedTypRaw.getFullName());
144

145
        if (toIndex != null && fromIndex != null) {
1✔
146
//            System.out.println("  --> cancel");
147
            // the two conversions cancel each other out
148
            return wrapLua(trace, t, translated, actualType);
1✔
149
        } else if (fromIndex != null) {
1✔
150
//            System.out.println("  --> fromIndex");
151
            if(t.isLuaTarget()) {
1✔
152
                translated = ImFunctionCall(trace, t.ensureIntFunc, ImTypeArguments(), JassIm.ImExprs(translated), false, CallType.NORMAL);
1✔
153
            }
154
            // no ensure type necessary here, because the fromIndex function is already type safe
155
            return ImFunctionCall(trace, fromIndex, ImTypeArguments(), JassIm.ImExprs(translated), false, CallType.NORMAL);
1✔
156
        } else if (toIndex != null) {
1✔
157
//            System.out.println("  --> toIndex");
158
            return wrapLua(trace, t, ImFunctionCall(trace, toIndex, ImTypeArguments(), JassIm.ImExprs(translated), false, CallType.NORMAL), actualType);
1✔
159
        }
160
        return wrapLua(trace, t, translated, actualType);
1✔
161
    }
162

163
    public static ImExpr translateIntern(ExprBinary e, ImTranslator t, ImFunction f) {
164
        ImExpr left = e.getLeft().imTranslateExpr(t, f);
1✔
165
        ImExpr right = e.getRight().imTranslateExpr(t, f);
1✔
166
        WurstOperator op = e.getOp();
1✔
167
        if (e.attrFuncLink() != null) {
1✔
168
            // overloaded operator
169
            ImFunction calledFunc = t.getFuncFor(e.attrFuncDef());
1✔
170
            return ImFunctionCall(e, calledFunc, ImTypeArguments(), ImExprs(left, right), false, CallType.NORMAL);
1✔
171
        }
172
        if (op == WurstOperator.DIV_REAL) {
1✔
173
            if (Utils.isJassCode(e)) {
1✔
174
                if (e.getLeft().attrTyp().isSubtypeOf(WurstTypeInt.instance(), e)
1✔
175
                        && e.getRight().attrTyp().isSubtypeOf(WurstTypeInt.instance(), e)) {
1✔
176
                    // in jass when we have int1 / int2 this actually means int1
177
                    // div int2
178
                    op = WurstOperator.DIV_INT;
1✔
179
                }
180
            } else {
181
                if (e.getLeft().attrTyp().isSubtypeOf(WurstTypeInt.instance(), e)
1✔
182
                        && e.getRight().attrTyp().isSubtypeOf(WurstTypeInt.instance(), e)) {
1✔
183
                    // we want a real division but have 2 ints so we need to
184
                    // multiply with 1.0
185
                    // TODO is this really needed or handled in IM->Jass
186
                    // translation?
187
                    left = ImOperatorCall(WurstOperator.MULT, ImExprs(left, ImRealVal("1.")));
1✔
188
                }
189
            }
190
        }
191
        return ImOperatorCall(op, ImExprs(left, right));
1✔
192
    }
193

194
    public static ImExpr translateIntern(ExprUnary e, ImTranslator t, ImFunction f) {
195
        return ImOperatorCall(e.getOpU(), ImExprs(e.getRight().imTranslateExpr(t, f)));
1✔
196
    }
197

198
    public static ImExpr translateIntern(ExprBoolVal e, ImTranslator t, ImFunction f) {
199
        return JassIm.ImBoolVal(e.getValB());
1✔
200
    }
201

202
    public static ImExpr translateIntern(ExprFuncRef e, ImTranslator t, ImFunction f) {
203
        ImFunction func = t.getFuncFor(e.attrFuncDef());
1✔
204
        return ImFuncRef(e, func);
1✔
205
    }
206

207
    public static ImExpr translateIntern(ExprIntVal e, ImTranslator t, ImFunction f) {
208
        if (e.attrExpectedTyp() instanceof WurstTypeReal) {
1✔
209
            // translate differently when real is expected
210
            return ImRealVal(e.getValI() + ".");
1✔
211
        }
212

213
        return ImIntVal(e.getValI());
1✔
214
    }
215

216
    public static ImExpr translateIntern(ExprNull e, ImTranslator t, ImFunction f) {
217
        WurstType expectedTypeRaw = e.attrExpectedTypRaw();
1✔
218
        if (expectedTypeRaw instanceof WurstTypeUnknown) {
1✔
219
            e.addError("Cannot use 'null' in this context.");
×
220
        }
221
        return ImNull(expectedTypeRaw.imTranslateType(t));
1✔
222
    }
223

224
    public static ImExpr translateIntern(ExprRealVal e, ImTranslator t, ImFunction f) {
225
        return ImRealVal(e.getValR());
1✔
226
    }
227

228
    public static ImExpr translateIntern(ExprStringVal e, ImTranslator t, ImFunction f) {
229
        return ImStringVal(e.getValS());
1✔
230
    }
231

232
    public static ImExpr translateIntern(ExprThis e, ImTranslator t, ImFunction f) {
233
        ImVar var = t.getThisVar(f, e);
1✔
234
        return ImVarAccess(var);
1✔
235
    }
236

237
    public static ImExpr translateIntern(ExprSuper e, ImTranslator t, ImFunction f) {
238
        ImVar var = t.getThisVar(f, e);
×
239
        return ImVarAccess(var);
×
240
    }
241

242
    public static ImExpr translateIntern(NameRef e, ImTranslator t, ImFunction f) {
243
        return translateNameDef(e, t, f);
1✔
244
    }
245

246
    private static ImExpr translateNameDef(NameRef e, ImTranslator t, ImFunction f) throws CompileError {
247
        NameLink link = e.attrNameLink();
1✔
248
        NameDef decl = link == null ? null : link.getDef();
1✔
249
        if (decl == null) {
1✔
250
            // should only happen with gg_ variables
251
            if (!t.isEclipseMode()) {
1✔
252
                e.addError("Translation Error: Could not find definition of " + e.getVarName() + ".");
×
253
            }
254
            return ImHelper.nullExpr();
×
255
        }
256
        if (decl instanceof VarDef) {
1✔
257
            VarDef varDef = (VarDef) decl;
1✔
258

259
            ImVar v = t.getVarFor(varDef);
1✔
260

261
            if (e.attrImplicitParameter() instanceof Expr) {
1✔
262
                // we have implicit parameter
263
                // e.g. "someObject.someField"
264
                Expr implicitParam = (Expr) e.attrImplicitParameter();
1✔
265

266
                if (implicitParam.attrTyp() instanceof WurstTypeTuple) {
1✔
267
                    WurstTypeTuple tupleType = (WurstTypeTuple) implicitParam.attrTyp();
1✔
268
                    if (e instanceof ExprMemberVar) {
1✔
269
                        ExprMemberVar e2 = (ExprMemberVar) e;
1✔
270
                        return translateTupleSelection(t, f, e2);
1✔
271
                    } else {
272
                        throw new CompileError(e.getSource(), "Cannot create tuple access");
×
273
                    }
274
                }
275

276
                if (e instanceof AstElementWithIndexes) {
1✔
277
                    ImExpr index1 = implicitParam.imTranslateExpr(t, f);
1✔
278
                    ImExpr index2 = ((AstElementWithIndexes) e).getIndexes().get(0).imTranslateExpr(t, f);
1✔
279
                    return JassIm.ImMemberAccess(e, index1, JassIm.ImTypeArguments(), v, JassIm.ImExprs(index2));
1✔
280
                } else {
281
                    ImExpr index = implicitParam.imTranslateExpr(t, f);
1✔
282
                    return JassIm.ImMemberAccess(e, index, JassIm.ImTypeArguments(), v, JassIm.ImExprs());
1✔
283
                }
284
            } else {
285
                // direct var access
286
                if (e instanceof AstElementWithIndexes) {
1✔
287
                    // direct access array var
288
                    AstElementWithIndexes withIndexes = (AstElementWithIndexes) e;
1✔
289
                    if (withIndexes.getIndexes().size() > 1) {
1✔
290
                        throw new CompileError(e.getSource(), "More than one index is not supported.");
×
291
                    }
292
                    ImExpr index = withIndexes.getIndexes().get(0).imTranslateExpr(t, f);
1✔
293
                    return ImVarArrayAccess(e, v, JassIm.ImExprs(index));
1✔
294
                } else {
295
                    // not an array var
296
                    return ImVarAccess(v);
1✔
297

298
                }
299
            }
300
        } else if (decl instanceof EnumMember) {
1✔
301
            EnumMember enumMember = (EnumMember) decl;
1✔
302
            int id = t.getEnumMemberId(enumMember);
1✔
303
            return ImIntVal(id);
1✔
304
        } else if (link instanceof OtherLink) {
1✔
305
            OtherLink otherLink = (OtherLink) link;
1✔
306
            return otherLink.translate(e, t, f);
1✔
307
        } else {
308
            throw new CompileError(e.getSource(), "Cannot translate reference to " + Utils.printElement(decl));
×
309
        }
310
    }
311

312
    private static ImExpr translateTupleSelection(ImTranslator t, ImFunction f, ExprMemberVar mv) {
313
        ImExpr left = mv.getLeft().imTranslateExpr(t, f);
1✔
314
        WParameter tupleParam = (WParameter) mv.attrNameDef();
1✔
315
        WParameters tupleParams = (WParameters) tupleParam.getParent();
1✔
316
        int tupleIndex = tupleParams.indexOf(tupleParam);
1✔
317
        if (left instanceof ImLExpr) {
1✔
318
            return ImTupleSelection(left, tupleIndex);
1✔
319
        } else {
320
            // if tupleExpr is not an l-value (e.g. foo().x)
321
            // store result in intermediate variable first:
322
            ImVar v = ImVar(left.attrTrace(), left.attrTyp(), "temp_tuple", false);
1✔
323
            f.getLocals().add(v);
1✔
324
            return JassIm.ImStatementExpr(
1✔
325
                    JassIm.ImStmts(
1✔
326
                            ImSet(left.attrTrace(), ImVarAccess(v), left)
1✔
327
                    ),
328
                    ImTupleSelection(ImVarAccess(v), tupleIndex)
1✔
329
            );
330
        }
331
    }
332

333
    /*
334
    private static ImExpr translateTupleSelection(ImTranslator t, ImFunction f, ExprMemberVar mv) {
335
        List<WParameter> indexes = new ArrayList<>();
336

337
        Expr expr = mv;
338
        while (true) {
339
            if (expr instanceof ExprMemberVar) {
340
                ExprMemberVar mv2 = (ExprMemberVar) expr;
341
                Expr left = mv2.getLeft();
342
                if (left.attrTyp() instanceof WurstTypeTuple) {
343
                    indexes.add(0, (WParameter) mv2.attrNameDef());
344
                    expr = left;
345
                    continue;
346
                }
347
            }
348
            break;
349
        }
350

351
        WurstTypeTuple tt = (WurstTypeTuple) expr.attrTyp();
352
        int tupleIndex = 0;
353
        WurstType resultTupleType = null;
354
        for (int i = 0; i < indexes.size(); i++) {
355
            WParameter param = indexes.get(i);
356
            TupleDef tdef = tt.getTupleDef();
357
            int pos = 0;
358
            while (tdef.getParameters().get(pos) != param) {
359
                tupleIndex += tupleSize(tdef.getParameters().get(pos).getTyp().attrTyp());
360
                pos++;
361
            }
362
            resultTupleType = tdef.getParameters().get(pos).getTyp().attrTyp();
363
            if (i < indexes.size() - 1) {
364
                tt = (WurstTypeTuple) tdef.getParameters().get(pos).getTyp().attrTyp();
365
            }
366
        }
367
        ImExpr exprTr = expr.imTranslateExpr(t, f);
368
        if (resultTupleType instanceof WurstTypeTuple) {
369
            // if the result is a tuple, create it:
370
            int tupleSize = tupleSize(resultTupleType);
371

372
            if (exprTr instanceof ImLExpr
373
                    && (exprTr.attrPurity() instanceof Pure || exprTr.attrPurity() instanceof ReadsGlobals)) {
374
                ImExprs exprs = JassIm.ImExprs();
375
                for (int i = 0; i < tupleSize; i++) {
376
                    exprs.add(ImTupleSelection((ImLExpr) exprTr.copy(), tupleIndex + i));
377
                }
378
                return ImTupleExpr(exprs);
379
            } else {
380
                ImVar temp = JassIm.ImVar(expr, exprTr.attrTyp(), "temp", false);
381
                // for impure expressions use a temporary:
382
                f.getLocals().add(temp);
383

384
                ImExprs exprs = JassIm.ImExprs();
385
                for (int i = 0; i < tupleSize; i++) {
386
                    // TODO use temporary var
387
                    exprs.add(ImTupleSelection(JassIm.ImVarAccess(temp), tupleIndex + i));
388
                }
389
                return JassIm.ImStatementExpr(JassIm.ImStmts(ImSet(expr, ImVarAccess(temp), exprTr)), ImTupleExpr(exprs));
390
            }
391
        } else {
392
            if (exprTr instanceof ImLExpr) {
393
                return ImTupleSelection((ImLExpr) exprTr, tupleIndex);
394
            } else {
395
                // if tupleExpr is not an l-value (e.g. foo().x)
396
                // store result in intermediate variable first:
397
                ImVar v = ImVar(exprTr.attrTrace(), exprTr.attrTyp(), "temp_tuple", false);
398
                f.getLocals().add(v);
399
                return JassIm.ImStatementExpr(
400
                        JassIm.ImStmts(
401
                                ImSet(exprTr.attrTrace(), ImVarAccess(v), exprTr)
402
                        ),
403
                        ImTupleSelection(ImVarAccess(v), tupleIndex)
404
                );
405
            }
406
        }
407
    }
408
    */
409

410
    /**
411
     * counts the components of a tuple (including nested)
412
     */
413
    private static int tupleSize(WurstType t) {
414
        if (t instanceof WurstTypeTuple) {
×
415
            WurstTypeTuple tt = (WurstTypeTuple) t;
×
416
            int sum = 0;
×
417
            for (WParameter p : tt.getTupleDef().getParameters()) {
×
418
                sum += tupleSize(p.getTyp().attrTyp());
×
419
            }
×
420
            return sum;
×
421
        }
422
        // all other types have size 1
423
        return 1;
×
424
    }
425

426
    public static ImExpr translateIntern(ExprCast e, ImTranslator t, ImFunction f) {
427
        ImExpr et = e.getExpr().imTranslateExpr(t, f);
1✔
428
        ImType toType = e.getTyp().attrTyp().imTranslateType(t);
1✔
429
        return JassIm.ImCast(et, toType);
1✔
430
    }
431

432
    public static ImExpr translateIntern(FunctionCall e, ImTranslator t, ImFunction f) {
433
        if (e instanceof ExprMemberMethodDotDot) {
1✔
434
            return translateFunctionCall(e, t, f, true);
1✔
435
        } else {
436
            return translateFunctionCall(e, t, f, false);
1✔
437
        }
438
    }
439

440
    private static ImExpr translateFunctionCall(FunctionCall e, ImTranslator t, ImFunction f, boolean returnReveiver) {
441

442
        if (e.getFuncName().equals("getStackTraceString") && e.attrImplicitParameter() instanceof NoExpr
1✔
443
                && e.getArgs().size() == 0) {
1✔
444
            // special built-in error function
445
            return JassIm.ImGetStackTrace();
1✔
446
        }
447

448
        if (e.getFuncName().equals("ExecuteFunc")) {
1✔
449
            ExprStringVal s = (ExprStringVal) e.getArgs().get(0);
1✔
450
            String exFunc = s.getValS();
1✔
451
            NameLink func = Utils.getFirst(e.lookupFuncs(exFunc));
1✔
452
            ImFunction executedFunc = t.getFuncFor((TranslatedToImFunction) func.getDef());
1✔
453
            return ImFunctionCall(e, executedFunc, ImTypeArguments(), JassIm.ImExprs(), true, CallType.EXECUTE);
1✔
454
        }
455

456
        if (e.getFuncName().equals("compiletime")
1✔
457
                && e.attrImplicitParameter() instanceof NoExpr
1✔
458
                && e.getArgs().size() == 1) {
1✔
459
            // special compiletime-expression
460
            return JassIm.ImCompiletimeExpr(e, e.getArgs().get(0).imTranslateExpr(t, f), t.getCompiletimeExpressionsOrder(e));
1✔
461
        }
462

463
        List<Expr> arguments = Lists.newArrayList(e.getArgs());
1✔
464
        Expr leftExpr = null;
1✔
465
        boolean dynamicDispatch = false;
1✔
466

467
        FunctionDefinition calledFunc = e.attrFuncDef();
1✔
468

469
        if (e.attrImplicitParameter() instanceof Expr) {
1✔
470
            if (isCalledOnDynamicRef(e) && calledFunc instanceof FuncDef) {
1✔
471
                dynamicDispatch = true;
1✔
472
            }
473
            // add implicit parameter to front
474
            // TODO why would I add the implicit parameter here, if it is
475
            // not a dynamic dispatch?
476
            leftExpr = (Expr) e.attrImplicitParameter();
1✔
477
        }
478

479
        // get real func def (override of module function)
480
        boolean useRealFuncDef = true;
1✔
481
        if (e instanceof ExprMemberMethod) {
1✔
482
            ExprMemberMethod exprMemberMethod = (ExprMemberMethod) e;
1✔
483
            WurstType left = exprMemberMethod.getLeft().attrTyp();
1✔
484
            if (left instanceof WurstTypeModuleInstanciation) {
1✔
485
                // if we have a call like A.foo() and A is a module,
486
                // use this function
487
                useRealFuncDef = false;
1✔
488
            }
489
        }
490

491
        if (calledFunc == null) {
1✔
492
            // this must be an ignored function
493
            return ImHelper.nullExpr();
1✔
494
        }
495

496
        if (useRealFuncDef) {
1✔
497
            calledFunc = calledFunc.attrRealFuncDef();
1✔
498
        }
499

500
        if (leftExpr instanceof ExprThis && calledFunc == e.attrNearestFuncDef()) {
1✔
501
            // recursive self calls are bound statically
502
            // this is different to other objectoriented languages but it is
503
            // necessary
504
            // because jass does not allow mutually recursive calls
505
            // The only situation where this would make a difference is with
506
            // super-calls
507
            // (or other statically bound calls)
508
            dynamicDispatch = false;
1✔
509
        }
510

511
        ImExpr receiver = leftExpr == null ? null : leftExpr.imTranslateExpr(t, f);
1✔
512
        ImExprs imArgs = translateExprs(arguments, t, f);
1✔
513

514
        if (calledFunc instanceof TupleDef) {
1✔
515
            // creating a new tuple...
516
            return ImTupleExpr(imArgs);
1✔
517
        }
518

519
        ImStmts stmts = null;
1✔
520
        ImVar tempVar = null;
1✔
521
        if (returnReveiver) {
1✔
522
            if (leftExpr == null)
1✔
523
                throw new Error("impossible");
×
524
            tempVar = JassIm.ImVar(leftExpr, leftExpr.attrTyp().imTranslateType(t), "receiver", false);
1✔
525
            f.getLocals().add(tempVar);
1✔
526
            stmts = JassIm.ImStmts(ImSet(e, ImVarAccess(tempVar), receiver));
1✔
527
            receiver = JassIm.ImVarAccess(tempVar);
1✔
528
        }
529

530

531

532
        ImExpr call;
533
        if (dynamicDispatch) {
1✔
534
            ImMethod method = t.getMethodFor((FuncDef) calledFunc);
1✔
535
            ImTypeArguments typeArguments = getFunctionCallTypeArguments(t, e.attrFunctionSignature(), e, method.getImplementation().getTypeVariables());
1✔
536
            call = ImMethodCall(e, method, typeArguments, receiver, imArgs, false);
1✔
537
        } else {
1✔
538
            ImFunction calledImFunc = t.getFuncFor(calledFunc);
1✔
539
            if (receiver != null) {
1✔
540
                imArgs.add(0, receiver);
1✔
541
            }
542
            ImTypeArguments typeArguments = getFunctionCallTypeArguments(t, e.attrFunctionSignature(), e, calledImFunc.getTypeVariables());
1✔
543
            call = ImFunctionCall(e, calledImFunc, typeArguments, imArgs, false, CallType.NORMAL);
1✔
544
        }
545

546
        if (returnReveiver) {
1✔
547
            if (stmts == null)
1✔
548
                throw new Error("impossible");
×
549
            stmts.add(call);
1✔
550
            return JassIm.ImStatementExpr(stmts, JassIm.ImVarAccess(tempVar));
1✔
551
        } else {
552
            return call;
1✔
553
        }
554
    }
555

556
    private static ImTypeArguments getFunctionCallTypeArguments(ImTranslator tr, FunctionSignature sig, Element location, ImTypeVars typeVariables) {
557
        ImTypeArguments res = ImTypeArguments();
1✔
558
        VariableBinding mapping = sig.getMapping();
1✔
559
        for (ImTypeVar tv : typeVariables) {
1✔
560
            TypeParamDef tp = tr.getTypeParamDef(tv);
1✔
561
            Option<WurstTypeBoundTypeParam> to = mapping.get(tp);
1✔
562
            if (to.isEmpty()) {
1✔
563
                throw new CompileError(location, "Type variable " + tp.getName() + " not bound in mapping.");
×
564
            }
565
            WurstTypeBoundTypeParam t = to.get();
1✔
566
            if (!t.isTemplateTypeParameter()) {
1✔
567
                continue;
×
568
            }
569
            ImType type = t.imTranslateType(tr);
1✔
570
            // TODO handle constraints
571
            Map<ImTypeClassFunc, Either<ImMethod, ImFunction>> typeClassBinding = new HashMap<>();
1✔
572
            res.add(ImTypeArgument(type, typeClassBinding));
1✔
573
        }
1✔
574
        return res;
1✔
575
    }
576

577
    private static boolean isCalledOnDynamicRef(FunctionCall e) {
578
        if (e instanceof ExprMemberMethod) {
1✔
579
            ExprMemberMethod mm = (ExprMemberMethod) e;
1✔
580
            return mm.getLeft().attrTyp().allowsDynamicDispatch();
1✔
581
        } else return e.attrIsDynamicContext();
1✔
582
    }
583

584
    private static ImExprs translateExprs(List<Expr> arguments, ImTranslator t, ImFunction f) {
585
        ImExprs result = ImExprs();
1✔
586
        for (Expr e : arguments) {
1✔
587
            result.add(e.imTranslateExpr(t, f));
1✔
588
        }
1✔
589
        return result;
1✔
590
    }
591

592
    public static ImExpr translateIntern(ExprIncomplete e, ImTranslator t, ImFunction f) {
593
        throw new CompileError(e.getSource(), "Incomplete expression.");
×
594
    }
595

596
    public static ImExpr translateIntern(ExprNewObject e, ImTranslator t, ImFunction f) {
597
        ConstructorDef constructorFunc = e.attrConstructorDef();
1✔
598
        ImFunction constructorImFunc = t.getConstructNewFunc(constructorFunc);
1✔
599
        FunctionSignature sig = e.attrFunctionSignature();
1✔
600
        WurstTypeClass wurstType = (WurstTypeClass) e.attrTyp();
1✔
601
        ImClass imClass = t.getClassFor(wurstType.getClassDef());
1✔
602
        ImTypeArguments typeArgs = getFunctionCallTypeArguments(t, sig, e, imClass.getTypeVariables());
1✔
603
        return ImFunctionCall(e, constructorImFunc, typeArgs, translateExprs(e.getArgs(), t, f), false, CallType.NORMAL);
1✔
604
    }
605

606
    public static ImExprOpt translate(NoExpr e, ImTranslator translator, ImFunction f) {
607
        return JassIm.ImNoExpr();
1✔
608
    }
609

610
    public static ImExpr translateIntern(ExprInstanceOf e, ImTranslator translator, ImFunction f) {
611
        WurstType targetType = e.getTyp().attrTyp();
1✔
612
        ImType imTargetType = targetType.imTranslateType(translator);
1✔
613
        if (imTargetType instanceof ImClassType) {
1✔
614
            return JassIm.ImInstanceof(e.getExpr().imTranslateExpr(translator, f), (ImClassType) imTargetType);
1✔
615
        }
616
        throw new Error("Cannot compile instanceof " + targetType);
×
617
    }
618

619
    public static ImExpr translate(ExprTypeId e, ImTranslator translator, ImFunction f) {
620
        WurstType leftType = e.getLeft().attrTyp();
1✔
621
        ImType imLeftType = leftType.imTranslateType(translator);
1✔
622
        if (imLeftType instanceof ImClassType) {
1✔
623
            ImClassType imLeftTypeC = (ImClassType) imLeftType;
1✔
624
            if (leftType instanceof WurstTypeClassOrInterface) {
1✔
625
                WurstTypeClassOrInterface wtc = (WurstTypeClassOrInterface) leftType;
1✔
626

627
                if (wtc.isStaticRef()) {
1✔
628
                    return JassIm.ImTypeIdOfClass(imLeftTypeC);
1✔
629
                } else {
630
                    return JassIm.ImTypeIdOfObj(e.getLeft().imTranslateExpr(translator, f), imLeftTypeC);
1✔
631
                }
632
            } else {
633
                throw new CompileError(e, "not implemented for " + leftType);
×
634
            }
635
        } else {
636
            throw new CompileError(e, "not implemented for " + leftType);
×
637
        }
638
    }
639

640
    public static ImExpr translate(ExprClosure e, ImTranslator tr, ImFunction f) {
641
        return new ClosureTranslator(e, tr, f).translate();
1✔
642
    }
643

644
    public static ImExpr translate(ExprStatementsBlock e, ImTranslator translator, ImFunction f) {
645

646
        ImStmts statements = JassIm.ImStmts();
1✔
647
        for (WStatement s : e.getBody()) {
1✔
648
            if (s instanceof StmtReturn) {
1✔
649
                continue;
1✔
650
            }
651
            ImStmt translated = s.imTranslateStmt(translator, f);
1✔
652
            statements.add(translated);
1✔
653
        }
1✔
654

655
        StmtReturn r = e.getReturnStmt();
1✔
656
        if (r != null && r.getReturnedObj() instanceof Expr) {
1✔
657
            ImExpr expr = ((Expr) r.getReturnedObj()).imTranslateExpr(translator, f);
1✔
658
            return JassIm.ImStatementExpr(statements, expr);
1✔
659
        } else {
660
            return ImHelper.statementExprVoid(statements);
1✔
661
        }
662
    }
663

664
    public static ImExpr translate(ExprDestroy s, ImTranslator t, ImFunction f) {
665
        WurstType typ = s.getDestroyedObj().attrTyp();
1✔
666
        if (typ instanceof WurstTypeClass) {
1✔
667
            WurstTypeClass classType = (WurstTypeClass) typ;
1✔
668
            return destroyClass(s, t, f, classType.getClassDef());
1✔
669
        } else if (typ instanceof WurstTypeInterface) {
1✔
670
            WurstTypeInterface wti = (WurstTypeInterface) typ;
1✔
671
            return destroyClass(s, t, f, wti.getDef());
1✔
672
        } else if (typ instanceof WurstTypeModuleInstanciation) {
×
673
            WurstTypeModuleInstanciation minsType = (WurstTypeModuleInstanciation) typ;
×
674
            ClassDef classDef = minsType.getDef().attrNearestClassDef();
×
675
            return destroyClass(s, t, f, classDef);
×
676
        }
677
        // TODO destroy interfaces?
678
        throw new CompileError(s.getSource(), "cannot destroy object of type " + typ);
×
679
    }
680

681
    public static ImExpr destroyClass(ExprDestroy s, ImTranslator t, ImFunction f, StructureDef classDef) {
682
        ImMethod destroyFunc = t.destroyMethod.getFor(classDef);
1✔
683
        return ImMethodCall(s, destroyFunc, ImTypeArguments(), s.getDestroyedObj().imTranslateExpr(t, f), ImExprs(), false);
1✔
684

685
    }
686

687
    public static ImExpr translate(ExprEmpty s, ImTranslator translator, ImFunction f) {
688
        throw new CompileError(s.getSource(), "cannot translate empty expression");
×
689
    }
690

691
    public static ImExpr translate(ExprIfElse e, ImTranslator t, ImFunction f) {
692
        ImExpr ifTrue = e.getIfTrue().imTranslateExpr(t, f);
1✔
693
        ImExpr ifFalse = e.getIfFalse().imTranslateExpr(t, f);
1✔
694
        // TODO common super type of both
695
        ImVar res = JassIm.ImVar(e, ifTrue.attrTyp(), "cond_result", false);
1✔
696
        f.getLocals().add(res);
1✔
697
        return JassIm.ImStatementExpr(
1✔
698
                ImStmts(
1✔
699
                        ImIf(e, e.getCond().imTranslateExpr(t, f),
1✔
700
                                ImStmts(
1✔
701
                                        ImSet(e.getIfTrue(), ImVarAccess(res), ifTrue)
1✔
702
                                ),
703
                                ImStmts(
1✔
704
                                        ImSet(e.getIfFalse(), ImVarAccess(res), ifFalse)
1✔
705
                                ))
706
                ),
707
                JassIm.ImVarAccess(res)
1✔
708
        );
709
    }
710

711
    public static ImLExpr translateLvalue(LExpr e, ImTranslator t, ImFunction f) {
712
        NameDef decl = e.attrNameDef();
1✔
713
        if (decl == null) {
1✔
714
            // should only happen with gg_ variables
715
            throw new CompileError(e.getSource(), "Translation Error: Could not find definition of " + e.getVarName() + ".");
×
716
        }
717
        if (decl instanceof VarDef) {
1✔
718
            VarDef varDef = (VarDef) decl;
1✔
719

720
            ImVar v = t.getVarFor(varDef);
1✔
721

722
            if (e.attrImplicitParameter() instanceof Expr) {
1✔
723
                // we have implicit parameter
724
                // e.g. "someObject.someField"
725
                Expr implicitParam = (Expr) e.attrImplicitParameter();
1✔
726

727
                if (implicitParam.attrTyp() instanceof WurstTypeTuple) {
1✔
728
                    WurstTypeTuple tupleType = (WurstTypeTuple) implicitParam.attrTyp();
1✔
729
                    if (e instanceof ExprMemberVar && ((ExprMemberVar) e).getLeft() instanceof LExpr) {
1✔
730
                        ExprMemberVar emv = (ExprMemberVar) e;
1✔
731
                        LExpr left = (LExpr) emv.getLeft();
1✔
732
                        ImLExpr lt = left.imTranslateExprLvalue(t, f);
1✔
733
                        return JassIm.ImTupleSelection(lt, tupleType.getTupleIndex(varDef));
1✔
734
                    } else {
735
                        throw new CompileError(e.getSource(), "Cannot create tuple access");
×
736
                    }
737
                }
738

739
                if (e instanceof AstElementWithIndexes) {
1✔
740
                    ImExpr index1 = implicitParam.imTranslateExpr(t, f);
1✔
741
                    ImExpr index2 = ((AstElementWithIndexes) e).getIndexes().get(0).imTranslateExpr(t, f);
1✔
742
                    return JassIm.ImMemberAccess(e, index1, JassIm.ImTypeArguments(), v, JassIm.ImExprs(index2));
1✔
743

744
                } else {
745
                    ImExpr index = implicitParam.imTranslateExpr(t, f);
1✔
746
                    return JassIm.ImMemberAccess(e, index, JassIm.ImTypeArguments(), v, JassIm.ImExprs());
1✔
747
                }
748
            } else {
749
                // direct var access
750
                if (e instanceof AstElementWithIndexes) {
1✔
751
                    // direct access array var
752
                    AstElementWithIndexes withIndexes = (AstElementWithIndexes) e;
1✔
753
                    if (withIndexes.getIndexes().size() > 1) {
1✔
754
                        throw new CompileError(e.getSource(), "More than one index is not supported.");
×
755
                    }
756
                    ImExpr index = withIndexes.getIndexes().get(0).imTranslateExpr(t, f);
1✔
757
                    return ImVarArrayAccess(e, v, JassIm.ImExprs(index));
1✔
758
                } else {
759
                    // not an array var
760
                    return ImVarAccess(v);
1✔
761

762
                }
763
            }
764
        } else {
765
            throw new CompileError(e.getSource(), "Cannot translate reference to " + Utils.printElement(decl));
×
766
        }
767
    }
768

769
//    public static ImLExpr translateLvalue(ExprVarArrayAccess e, ImTranslator translator, ImFunction f) {
770
//        NameDef nameDef = e.tryGetNameDef();
771
//        if (nameDef instanceof VarDef) {
772
//            VarDef varDef = (VarDef) nameDef;
773
//            ImVar v = translator.getVarFor(varDef);
774
//            ImExprs indexes = e.getIndexes().stream()
775
//                    .map(ie -> ie.imTranslateExpr(translator, f))
776
//                    .collect(Collectors.toCollection(JassIm::ImExprs));
777
//            return JassIm.ImVarArrayAccess(v, indexes);
778
//        }
779
//        throw new RuntimeException("TODO");
780
//
781
//    }
782
//
783
//    public static ImLExpr translateLvalue(ExprMemberVar e, ImTranslator translator, ImFunction f) {
784
//        ImExpr receiver = e.getLeft().imTranslateExpr(translator, f);
785
//        NameDef nameDef = e.tryGetNameDef();
786
//        if (nameDef instanceof VarDef) {
787
//            VarDef v = (VarDef) nameDef;
788
//            ImVar imVar = translator.getVarFor(v);
789
//            return JassIm.ImMemberAccess(receiver, imVar);
790
//        }
791
//        throw new RuntimeException("TODO");
792
//    }
793
//
794
//    public static ImLExpr translateLvalue(ExprMemberArrayVar e, ImTranslator translator, ImFunction f) {
795
//        throw new RuntimeException("TODO");
796
//    }
797

798

799
}
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