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

wurstscript / WurstScript / 228

29 Nov 2023 05:00PM UTC coverage: 62.48% (-0.09%) from 62.574%
228

push

circleci

web-flow
Show dialog for choosing game path, cleanup (#1083)

* show dialog for choosing game path

* cleanup code

* remove logs and refactor

* remove confusing mpq error, make some mpq loads readonly

17295 of 27681 relevant lines covered (62.48%)

0.62 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.Element;
6
import de.peeeq.wurstscript.ast.*;
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.ImClass;
11
import de.peeeq.wurstscript.jassIm.ImClassType;
12
import de.peeeq.wurstscript.jassIm.ImExprs;
13
import de.peeeq.wurstscript.jassIm.ImFunction;
14
import de.peeeq.wurstscript.jassIm.ImMethod;
15
import de.peeeq.wurstscript.jassIm.ImStmts;
16
import de.peeeq.wurstscript.jassIm.ImTypeArguments;
17
import de.peeeq.wurstscript.jassIm.ImTypeClassFunc;
18
import de.peeeq.wurstscript.jassIm.ImTypeVar;
19
import de.peeeq.wurstscript.jassIm.ImTypeVars;
20
import de.peeeq.wurstscript.jassIm.ImVar;
21
import de.peeeq.wurstscript.jassIm.*;
22
import de.peeeq.wurstscript.types.*;
23
import de.peeeq.wurstscript.utils.Utils;
24
import io.vavr.control.Either;
25
import io.vavr.control.Option;
26
import org.eclipse.jdt.annotation.Nullable;
27

28
import java.util.HashMap;
29
import java.util.List;
30
import java.util.Map;
31

32
import static de.peeeq.wurstscript.jassIm.JassIm.*;
33

34
public class ExprTranslation {
×
35

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

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

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

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

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

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

60
    public static ImExpr translate(ExprRealVal e, ImTranslator t, ImFunction f) {
61
        return wrapTranslation(e, t, translateIntern(e, t, f));
1✔
62
    }
63

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

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

72
    public static ImExpr translate(ExprSuper e, ImTranslator t, ImFunction f) {
73
        return wrapTranslation(e, t, translateIntern(e, t, f));
×
74
    }
75

76
    public static ImExpr translate(NameRef e, ImTranslator t, ImFunction f) {
77
        return wrapTranslation(e, t, translateIntern(e, t, f));
1✔
78
    }
79

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

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

88
    public static ImExpr translate(ExprIncomplete e, ImTranslator t, ImFunction f) {
89
        return wrapTranslation(e, t, translateIntern(e, t, f));
×
90
    }
91

92
    public static ImExpr translate(ExprNewObject e, ImTranslator t, ImFunction f) {
93
        return wrapTranslation(e, t, translateIntern(e, t, f));
1✔
94
    }
95

96
    public static ImExpr translate(ExprInstanceOf e, ImTranslator t, ImFunction f) {
97
        return wrapTranslation(e, t, translateIntern(e, t, f));
1✔
98
    }
99

100
    private static ImExpr wrapTranslation(Expr e, ImTranslator t, ImExpr translated) {
101
        WurstType actualType = e.attrTypRaw();
1✔
102
        WurstType expectedTypRaw = e.attrExpectedTypRaw();
1✔
103
        return wrapTranslation(e, t, translated, actualType, expectedTypRaw);
1✔
104
    }
105

106
    static ImExpr wrapLua(Element trace, ImTranslator t, ImExpr translated, WurstType actualType) {
107
        // use ensureType functions for lua
108
        // these functions convert nil to the default value for primitive types (int, string, bool, real)
109
        if (t.isLuaTarget() && actualType instanceof WurstTypeBoundTypeParam) {
1✔
110
            WurstTypeBoundTypeParam wtb = (WurstTypeBoundTypeParam) actualType;
1✔
111

112
            @Nullable ImFunction ensureType = null;
1✔
113
            switch (wtb.getName()) {
1✔
114
                case "integer":
115
                    ensureType = t.ensureIntFunc;
1✔
116
                    break;
1✔
117
                case "string":
118
                    ensureType = t.ensureStrFunc;
×
119
                    break;
×
120
                case "boolean":
121
                    ensureType = t.ensureBoolFunc;
×
122
                    break;
×
123
                case "real":
124
                    ensureType = t.ensureRealFunc;
×
125
                    break;
126
            }
127
            if(ensureType != null) {
1✔
128
                return ImFunctionCall(trace, ensureType, ImTypeArguments(), JassIm.ImExprs(translated), false, CallType.NORMAL);
1✔
129
            }
130
        }
131
        return translated;
1✔
132
    }
133

134
    static ImExpr wrapTranslation(Element trace, ImTranslator t, ImExpr translated, WurstType actualType, WurstType expectedTypRaw) {
135
        ImFunction toIndex = null;
1✔
136
        ImFunction fromIndex = null;
1✔
137
        if (actualType instanceof WurstTypeBoundTypeParam) {
1✔
138
            WurstTypeBoundTypeParam wtb = (WurstTypeBoundTypeParam) actualType;
1✔
139
            FuncDef fromIndexFunc = wtb.getFromIndex();
1✔
140
            if (fromIndexFunc != null) {
1✔
141
                fromIndex = t.getFuncFor(fromIndexFunc);
1✔
142
            }
143
        }
144
        if (expectedTypRaw instanceof WurstTypeBoundTypeParam) {
1✔
145
            WurstTypeBoundTypeParam wtb = (WurstTypeBoundTypeParam) expectedTypRaw;
1✔
146
            FuncDef toIndexFunc = wtb.getToIndex();
1✔
147
            if (toIndexFunc != null) {
1✔
148
                toIndex = t.getFuncFor(toIndexFunc);
1✔
149
            }
150
        }
151

152
//        System.out.println("CAll " + Utils.prettyPrintWithLine(trace));
153
//        System.out.println("  actualType = " + actualType.getFullName());
154
//        System.out.println("  expectedTypRaw = " + expectedTypRaw.getFullName());
155

156
        if (toIndex != null && fromIndex != null) {
1✔
157
//            System.out.println("  --> cancel");
158
            // the two conversions cancel each other out
159
            return wrapLua(trace, t, translated, actualType);
1✔
160
        } else if (fromIndex != null) {
1✔
161
//            System.out.println("  --> fromIndex");
162
            if(t.isLuaTarget()) {
1✔
163
                translated = ImFunctionCall(trace, t.ensureIntFunc, ImTypeArguments(), JassIm.ImExprs(translated), false, CallType.NORMAL);
1✔
164
            }
165
            // no ensure type necessary here, because the fromIndex function is already type safe
166
            return ImFunctionCall(trace, fromIndex, ImTypeArguments(), JassIm.ImExprs(translated), false, CallType.NORMAL);
1✔
167
        } else if (toIndex != null) {
1✔
168
//            System.out.println("  --> toIndex");
169
            return wrapLua(trace, t, ImFunctionCall(trace, toIndex, ImTypeArguments(), JassIm.ImExprs(translated), false, CallType.NORMAL), actualType);
1✔
170
        }
171
        return wrapLua(trace, t, translated, actualType);
1✔
172
    }
173

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

205
    public static ImExpr translateIntern(ExprUnary e, ImTranslator t, ImFunction f) {
206
        return ImOperatorCall(e.getOpU(), ImExprs(e.getRight().imTranslateExpr(t, f)));
1✔
207
    }
208

209
    public static ImExpr translateIntern(ExprBoolVal e, ImTranslator t, ImFunction f) {
210
        return JassIm.ImBoolVal(e.getValB());
1✔
211
    }
212

213
    public static ImExpr translateIntern(ExprFuncRef e, ImTranslator t, ImFunction f) {
214
        ImFunction func = t.getFuncFor(e.attrFuncDef());
1✔
215
        return ImFuncRef(e, func);
1✔
216
    }
217

218
    public static ImExpr translateIntern(ExprIntVal e, ImTranslator t, ImFunction f) {
219
        if (e.attrExpectedTyp() instanceof WurstTypeReal) {
1✔
220
            // translate differently when real is expected
221
            return ImRealVal(e.getValI() + ".");
1✔
222
        }
223

224
        return ImIntVal(e.getValI());
1✔
225
    }
226

227
    public static ImExpr translateIntern(ExprNull e, ImTranslator t, ImFunction f) {
228
        WurstType expectedTypeRaw = e.attrExpectedTypRaw();
1✔
229
        if (expectedTypeRaw instanceof WurstTypeUnknown) {
1✔
230
            e.addError("Cannot use 'null' in this context.");
×
231
        }
232
        return ImNull(expectedTypeRaw.imTranslateType(t));
1✔
233
    }
234

235
    public static ImExpr translateIntern(ExprRealVal e, ImTranslator t, ImFunction f) {
236
        return ImRealVal(e.getValR());
1✔
237
    }
238

239
    public static ImExpr translateIntern(ExprStringVal e, ImTranslator t, ImFunction f) {
240
        return ImStringVal(e.getValS());
1✔
241
    }
242

243
    public static ImExpr translateIntern(ExprThis e, ImTranslator t, ImFunction f) {
244
        ImVar var = t.getThisVar(f, e);
1✔
245
        return ImVarAccess(var);
1✔
246
    }
247

248
    public static ImExpr translateIntern(ExprSuper e, ImTranslator t, ImFunction f) {
249
        ImVar var = t.getThisVar(f, e);
×
250
        return ImVarAccess(var);
×
251
    }
252

253
    public static ImExpr translateIntern(NameRef e, ImTranslator t, ImFunction f) {
254
        return translateNameDef(e, t, f);
1✔
255
    }
256

257
    private static ImExpr translateNameDef(NameRef e, ImTranslator t, ImFunction f) throws CompileError {
258
        NameLink link = e.attrNameLink();
1✔
259
        NameDef decl = link == null ? null : link.getDef();
1✔
260
        if (decl == null) {
1✔
261
            // should only happen with gg_ variables
262
            if (!t.isEclipseMode()) {
1✔
263
                e.addError("Translation Error: Could not find definition of " + e.getVarName() + ".");
×
264
            }
265
            return ImHelper.nullExpr();
×
266
        }
267
        if (decl instanceof VarDef) {
1✔
268
            VarDef varDef = (VarDef) decl;
1✔
269

270
            ImVar v = t.getVarFor(varDef);
1✔
271

272
            if (e.attrImplicitParameter() instanceof Expr) {
1✔
273
                // we have implicit parameter
274
                // e.g. "someObject.someField"
275
                Expr implicitParam = (Expr) e.attrImplicitParameter();
1✔
276

277
                if (implicitParam.attrTyp() instanceof WurstTypeTuple) {
1✔
278
                    WurstTypeTuple tupleType = (WurstTypeTuple) implicitParam.attrTyp();
1✔
279
                    if (e instanceof ExprMemberVar) {
1✔
280
                        ExprMemberVar e2 = (ExprMemberVar) e;
1✔
281
                        return translateTupleSelection(t, f, e2);
1✔
282
                    } else {
283
                        throw new CompileError(e.getSource(), "Cannot create tuple access");
×
284
                    }
285
                }
286

287
                if (e instanceof AstElementWithIndexes) {
1✔
288
                    ImExpr index1 = implicitParam.imTranslateExpr(t, f);
1✔
289
                    ImExpr index2 = ((AstElementWithIndexes) e).getIndexes().get(0).imTranslateExpr(t, f);
1✔
290
                    return JassIm.ImMemberAccess(e, index1, JassIm.ImTypeArguments(), v, JassIm.ImExprs(index2));
1✔
291
                } else {
292
                    ImExpr index = implicitParam.imTranslateExpr(t, f);
1✔
293
                    return JassIm.ImMemberAccess(e, index, JassIm.ImTypeArguments(), v, JassIm.ImExprs());
1✔
294
                }
295
            } else {
296
                // direct var access
297
                if (e instanceof AstElementWithIndexes) {
1✔
298
                    // direct access array var
299
                    AstElementWithIndexes withIndexes = (AstElementWithIndexes) e;
1✔
300
                    if (withIndexes.getIndexes().size() > 1) {
1✔
301
                        throw new CompileError(e.getSource(), "More than one index is not supported.");
×
302
                    }
303
                    ImExpr index = withIndexes.getIndexes().get(0).imTranslateExpr(t, f);
1✔
304
                    return ImVarArrayAccess(e, v, JassIm.ImExprs(index));
1✔
305
                } else {
306
                    // not an array var
307
                    return ImVarAccess(v);
1✔
308

309
                }
310
            }
311
        } else if (decl instanceof EnumMember) {
1✔
312
            EnumMember enumMember = (EnumMember) decl;
1✔
313
            int id = t.getEnumMemberId(enumMember);
1✔
314
            return ImIntVal(id);
1✔
315
        } else if (link instanceof OtherLink) {
1✔
316
            OtherLink otherLink = (OtherLink) link;
1✔
317
            return otherLink.translate(e, t, f);
1✔
318
        } else {
319
            throw new CompileError(e.getSource(), "Cannot translate reference to " + Utils.printElement(decl));
×
320
        }
321
    }
322

323
    private static ImExpr translateTupleSelection(ImTranslator t, ImFunction f, ExprMemberVar mv) {
324
        ImExpr left = mv.getLeft().imTranslateExpr(t, f);
1✔
325
        WParameter tupleParam = (WParameter) mv.attrNameDef();
1✔
326
        WParameters tupleParams = (WParameters) tupleParam.getParent();
1✔
327
        int tupleIndex = tupleParams.indexOf(tupleParam);
1✔
328
        if (left instanceof ImLExpr) {
1✔
329
            return ImTupleSelection(left, tupleIndex);
1✔
330
        } else {
331
            // if tupleExpr is not an l-value (e.g. foo().x)
332
            // store result in intermediate variable first:
333
            ImVar v = ImVar(left.attrTrace(), left.attrTyp(), "temp_tuple", false);
1✔
334
            f.getLocals().add(v);
1✔
335
            return JassIm.ImStatementExpr(
1✔
336
                    JassIm.ImStmts(
1✔
337
                            ImSet(left.attrTrace(), ImVarAccess(v), left)
1✔
338
                    ),
339
                    ImTupleSelection(ImVarAccess(v), tupleIndex)
1✔
340
            );
341
        }
342
    }
343

344
    /*
345
    private static ImExpr translateTupleSelection(ImTranslator t, ImFunction f, ExprMemberVar mv) {
346
        List<WParameter> indexes = new ArrayList<>();
347

348
        Expr expr = mv;
349
        while (true) {
350
            if (expr instanceof ExprMemberVar) {
351
                ExprMemberVar mv2 = (ExprMemberVar) expr;
352
                Expr left = mv2.getLeft();
353
                if (left.attrTyp() instanceof WurstTypeTuple) {
354
                    indexes.add(0, (WParameter) mv2.attrNameDef());
355
                    expr = left;
356
                    continue;
357
                }
358
            }
359
            break;
360
        }
361

362
        WurstTypeTuple tt = (WurstTypeTuple) expr.attrTyp();
363
        int tupleIndex = 0;
364
        WurstType resultTupleType = null;
365
        for (int i = 0; i < indexes.size(); i++) {
366
            WParameter param = indexes.get(i);
367
            TupleDef tdef = tt.getTupleDef();
368
            int pos = 0;
369
            while (tdef.getParameters().get(pos) != param) {
370
                tupleIndex += tupleSize(tdef.getParameters().get(pos).getTyp().attrTyp());
371
                pos++;
372
            }
373
            resultTupleType = tdef.getParameters().get(pos).getTyp().attrTyp();
374
            if (i < indexes.size() - 1) {
375
                tt = (WurstTypeTuple) tdef.getParameters().get(pos).getTyp().attrTyp();
376
            }
377
        }
378
        ImExpr exprTr = expr.imTranslateExpr(t, f);
379
        if (resultTupleType instanceof WurstTypeTuple) {
380
            // if the result is a tuple, create it:
381
            int tupleSize = tupleSize(resultTupleType);
382

383
            if (exprTr instanceof ImLExpr
384
                    && (exprTr.attrPurity() instanceof Pure || exprTr.attrPurity() instanceof ReadsGlobals)) {
385
                ImExprs exprs = JassIm.ImExprs();
386
                for (int i = 0; i < tupleSize; i++) {
387
                    exprs.add(ImTupleSelection((ImLExpr) exprTr.copy(), tupleIndex + i));
388
                }
389
                return ImTupleExpr(exprs);
390
            } else {
391
                ImVar temp = JassIm.ImVar(expr, exprTr.attrTyp(), "temp", false);
392
                // for impure expressions use a temporary:
393
                f.getLocals().add(temp);
394

395
                ImExprs exprs = JassIm.ImExprs();
396
                for (int i = 0; i < tupleSize; i++) {
397
                    // TODO use temporary var
398
                    exprs.add(ImTupleSelection(JassIm.ImVarAccess(temp), tupleIndex + i));
399
                }
400
                return JassIm.ImStatementExpr(JassIm.ImStmts(ImSet(expr, ImVarAccess(temp), exprTr)), ImTupleExpr(exprs));
401
            }
402
        } else {
403
            if (exprTr instanceof ImLExpr) {
404
                return ImTupleSelection((ImLExpr) exprTr, tupleIndex);
405
            } else {
406
                // if tupleExpr is not an l-value (e.g. foo().x)
407
                // store result in intermediate variable first:
408
                ImVar v = ImVar(exprTr.attrTrace(), exprTr.attrTyp(), "temp_tuple", false);
409
                f.getLocals().add(v);
410
                return JassIm.ImStatementExpr(
411
                        JassIm.ImStmts(
412
                                ImSet(exprTr.attrTrace(), ImVarAccess(v), exprTr)
413
                        ),
414
                        ImTupleSelection(ImVarAccess(v), tupleIndex)
415
                );
416
            }
417
        }
418
    }
419
    */
420

421
    /**
422
     * counts the components of a tuple (including nested)
423
     */
424
    private static int tupleSize(WurstType t) {
425
        if (t instanceof WurstTypeTuple) {
×
426
            WurstTypeTuple tt = (WurstTypeTuple) t;
×
427
            int sum = 0;
×
428
            for (WParameter p : tt.getTupleDef().getParameters()) {
×
429
                sum += tupleSize(p.getTyp().attrTyp());
×
430
            }
×
431
            return sum;
×
432
        }
433
        // all other types have size 1
434
        return 1;
×
435
    }
436

437
    public static ImExpr translateIntern(ExprCast e, ImTranslator t, ImFunction f) {
438
        ImExpr et = e.getExpr().imTranslateExpr(t, f);
1✔
439
        ImType toType = e.getTyp().attrTyp().imTranslateType(t);
1✔
440
        return JassIm.ImCast(et, toType);
1✔
441
    }
442

443
    public static ImExpr translateIntern(FunctionCall e, ImTranslator t, ImFunction f) {
444
        if (e instanceof ExprMemberMethodDotDot) {
1✔
445
            return translateFunctionCall(e, t, f, true);
1✔
446
        } else {
447
            return translateFunctionCall(e, t, f, false);
1✔
448
        }
449
    }
450

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

453
        if (e.getFuncName().equals("getStackTraceString") && e.attrImplicitParameter() instanceof NoExpr
1✔
454
                && e.getArgs().size() == 0) {
1✔
455
            // special built-in error function
456
            return JassIm.ImGetStackTrace();
1✔
457
        }
458

459
        if (e.getFuncName().equals("ExecuteFunc")) {
1✔
460
            ExprStringVal s = (ExprStringVal) e.getArgs().get(0);
1✔
461
            String exFunc = s.getValS();
1✔
462
            NameLink func = Utils.getFirst(e.lookupFuncs(exFunc));
1✔
463
            ImFunction executedFunc = t.getFuncFor((TranslatedToImFunction) func.getDef());
1✔
464
            return ImFunctionCall(e, executedFunc, ImTypeArguments(), JassIm.ImExprs(), true, CallType.EXECUTE);
1✔
465
        }
466

467
        if (e.getFuncName().equals("compiletime")
1✔
468
                && e.attrImplicitParameter() instanceof NoExpr
1✔
469
                && e.getArgs().size() == 1) {
1✔
470
            // special compiletime-expression
471
            return JassIm.ImCompiletimeExpr(e, e.getArgs().get(0).imTranslateExpr(t, f), t.getCompiletimeExpressionsOrder(e));
1✔
472
        }
473

474
        List<Expr> arguments = Lists.newArrayList(e.getArgs());
1✔
475
        Expr leftExpr = null;
1✔
476
        boolean dynamicDispatch = false;
1✔
477

478
        FunctionDefinition calledFunc = e.attrFuncDef();
1✔
479

480
        if (e.attrImplicitParameter() instanceof Expr) {
1✔
481
            if (isCalledOnDynamicRef(e) && calledFunc instanceof FuncDef) {
1✔
482
                dynamicDispatch = true;
1✔
483
            }
484
            // add implicit parameter to front
485
            // TODO why would I add the implicit parameter here, if it is
486
            // not a dynamic dispatch?
487
            leftExpr = (Expr) e.attrImplicitParameter();
1✔
488
        }
489

490
        // get real func def (override of module function)
491
        boolean useRealFuncDef = true;
1✔
492
        if (e instanceof ExprMemberMethod) {
1✔
493
            ExprMemberMethod exprMemberMethod = (ExprMemberMethod) e;
1✔
494
            WurstType left = exprMemberMethod.getLeft().attrTyp();
1✔
495
            if (left instanceof WurstTypeModuleInstanciation) {
1✔
496
                // if we have a call like A.foo() and A is a module,
497
                // use this function
498
                useRealFuncDef = false;
1✔
499
            }
500
        }
501

502
        if (calledFunc == null) {
1✔
503
            // this must be an ignored function
504
            return ImHelper.nullExpr();
1✔
505
        }
506

507
        if (useRealFuncDef) {
1✔
508
            calledFunc = calledFunc.attrRealFuncDef();
1✔
509
        }
510

511
        if (leftExpr instanceof ExprThis && calledFunc == e.attrNearestFuncDef()) {
1✔
512
            // recursive self calls are bound statically
513
            // this is different to other objectoriented languages but it is
514
            // necessary
515
            // because jass does not allow mutually recursive calls
516
            // The only situation where this would make a difference is with
517
            // super-calls
518
            // (or other statically bound calls)
519
            dynamicDispatch = false;
1✔
520
        }
521

522
        ImExpr receiver = leftExpr == null ? null : leftExpr.imTranslateExpr(t, f);
1✔
523
        ImExprs imArgs = translateExprs(arguments, t, f);
1✔
524

525
        if (calledFunc instanceof TupleDef) {
1✔
526
            // creating a new tuple...
527
            return ImTupleExpr(imArgs);
1✔
528
        }
529

530
        ImStmts stmts = null;
1✔
531
        ImVar tempVar = null;
1✔
532
        if (returnReveiver) {
1✔
533
            if (leftExpr == null)
1✔
534
                throw new Error("impossible");
×
535
            tempVar = JassIm.ImVar(leftExpr, leftExpr.attrTyp().imTranslateType(t), "receiver", false);
1✔
536
            f.getLocals().add(tempVar);
1✔
537
            stmts = JassIm.ImStmts(ImSet(e, ImVarAccess(tempVar), receiver));
1✔
538
            receiver = JassIm.ImVarAccess(tempVar);
1✔
539
        }
540

541

542

543
        ImExpr call;
544
        if (dynamicDispatch) {
1✔
545
            ImMethod method = t.getMethodFor((FuncDef) calledFunc);
1✔
546
            ImTypeArguments typeArguments = getFunctionCallTypeArguments(t, e.attrFunctionSignature(), e, method.getImplementation().getTypeVariables());
1✔
547
            call = ImMethodCall(e, method, typeArguments, receiver, imArgs, false);
1✔
548
        } else {
1✔
549
            ImFunction calledImFunc = t.getFuncFor(calledFunc);
1✔
550
            if (receiver != null) {
1✔
551
                imArgs.add(0, receiver);
1✔
552
            }
553
            ImTypeArguments typeArguments = getFunctionCallTypeArguments(t, e.attrFunctionSignature(), e, calledImFunc.getTypeVariables());
1✔
554
            call = ImFunctionCall(e, calledImFunc, typeArguments, imArgs, false, CallType.NORMAL);
1✔
555
        }
556

557
        if (returnReveiver) {
1✔
558
            if (stmts == null)
1✔
559
                throw new Error("impossible");
×
560
            stmts.add(call);
1✔
561
            return JassIm.ImStatementExpr(stmts, JassIm.ImVarAccess(tempVar));
1✔
562
        } else {
563
            return call;
1✔
564
        }
565
    }
566

567
    private static ImTypeArguments getFunctionCallTypeArguments(ImTranslator tr, FunctionSignature sig, Element location, ImTypeVars typeVariables) {
568
        ImTypeArguments res = ImTypeArguments();
1✔
569
        VariableBinding mapping = sig.getMapping();
1✔
570
        for (ImTypeVar tv : typeVariables) {
1✔
571
            TypeParamDef tp = tr.getTypeParamDef(tv);
1✔
572
            Option<WurstTypeBoundTypeParam> to = mapping.get(tp);
1✔
573
            if (to.isEmpty()) {
1✔
574
                throw new CompileError(location, "Type variable " + tp.getName() + " not bound in mapping.");
×
575
            }
576
            WurstTypeBoundTypeParam t = to.get();
1✔
577
            if (!t.isTemplateTypeParameter()) {
1✔
578
                continue;
×
579
            }
580
            ImType type = t.imTranslateType(tr);
1✔
581
            // TODO handle constraints
582
            Map<ImTypeClassFunc, Either<ImMethod, ImFunction>> typeClassBinding = new HashMap<>();
1✔
583
            res.add(ImTypeArgument(type, typeClassBinding));
1✔
584
        }
1✔
585
        return res;
1✔
586
    }
587

588
    private static boolean isCalledOnDynamicRef(FunctionCall e) {
589
        if (e instanceof ExprMemberMethod) {
1✔
590
            ExprMemberMethod mm = (ExprMemberMethod) e;
1✔
591
            return mm.getLeft().attrTyp().allowsDynamicDispatch();
1✔
592
        } else return e.attrIsDynamicContext();
1✔
593
    }
594

595
    private static ImExprs translateExprs(List<Expr> arguments, ImTranslator t, ImFunction f) {
596
        ImExprs result = ImExprs();
1✔
597
        for (Expr e : arguments) {
1✔
598
            result.add(e.imTranslateExpr(t, f));
1✔
599
        }
1✔
600
        return result;
1✔
601
    }
602

603
    public static ImExpr translateIntern(ExprIncomplete e, ImTranslator t, ImFunction f) {
604
        throw new CompileError(e.getSource(), "Incomplete expression.");
×
605
    }
606

607
    public static ImExpr translateIntern(ExprNewObject e, ImTranslator t, ImFunction f) {
608
        ConstructorDef constructorFunc = e.attrConstructorDef();
1✔
609
        ImFunction constructorImFunc = t.getConstructNewFunc(constructorFunc);
1✔
610
        FunctionSignature sig = e.attrFunctionSignature();
1✔
611
        WurstTypeClass wurstType = (WurstTypeClass) e.attrTyp();
1✔
612
        ImClass imClass = t.getClassFor(wurstType.getClassDef());
1✔
613
        ImTypeArguments typeArgs = getFunctionCallTypeArguments(t, sig, e, imClass.getTypeVariables());
1✔
614
        return ImFunctionCall(e, constructorImFunc, typeArgs, translateExprs(e.getArgs(), t, f), false, CallType.NORMAL);
1✔
615
    }
616

617
    public static ImExprOpt translate(NoExpr e, ImTranslator translator, ImFunction f) {
618
        return JassIm.ImNoExpr();
1✔
619
    }
620

621
    public static ImExpr translateIntern(ExprInstanceOf e, ImTranslator translator, ImFunction f) {
622
        WurstType targetType = e.getTyp().attrTyp();
1✔
623
        ImType imTargetType = targetType.imTranslateType(translator);
1✔
624
        if (imTargetType instanceof ImClassType) {
1✔
625
            return JassIm.ImInstanceof(e.getExpr().imTranslateExpr(translator, f), (ImClassType) imTargetType);
1✔
626
        }
627
        throw new Error("Cannot compile instanceof " + targetType);
×
628
    }
629

630
    public static ImExpr translate(ExprTypeId e, ImTranslator translator, ImFunction f) {
631
        WurstType leftType = e.getLeft().attrTyp();
1✔
632
        ImType imLeftType = leftType.imTranslateType(translator);
1✔
633
        if (imLeftType instanceof ImClassType) {
1✔
634
            ImClassType imLeftTypeC = (ImClassType) imLeftType;
1✔
635
            if (leftType instanceof WurstTypeClassOrInterface) {
1✔
636
                WurstTypeClassOrInterface wtc = (WurstTypeClassOrInterface) leftType;
1✔
637

638
                if (wtc.isStaticRef()) {
1✔
639
                    return JassIm.ImTypeIdOfClass(imLeftTypeC);
1✔
640
                } else {
641
                    return JassIm.ImTypeIdOfObj(e.getLeft().imTranslateExpr(translator, f), imLeftTypeC);
1✔
642
                }
643
            } else {
644
                throw new CompileError(e, "not implemented for " + leftType);
×
645
            }
646
        } else {
647
            throw new CompileError(e, "not implemented for " + leftType);
×
648
        }
649
    }
650

651
    public static ImExpr translate(ExprClosure e, ImTranslator tr, ImFunction f) {
652
        return new ClosureTranslator(e, tr, f).translate();
1✔
653
    }
654

655
    public static ImExpr translate(ExprStatementsBlock e, ImTranslator translator, ImFunction f) {
656

657
        ImStmts statements = JassIm.ImStmts();
1✔
658
        for (WStatement s : e.getBody()) {
1✔
659
            if (s instanceof StmtReturn) {
1✔
660
                continue;
1✔
661
            }
662
            ImStmt translated = s.imTranslateStmt(translator, f);
1✔
663
            statements.add(translated);
1✔
664
        }
1✔
665

666
        StmtReturn r = e.getReturnStmt();
1✔
667
        if (r != null && r.getReturnedObj() instanceof Expr) {
1✔
668
            ImExpr expr = ((Expr) r.getReturnedObj()).imTranslateExpr(translator, f);
1✔
669
            return JassIm.ImStatementExpr(statements, expr);
1✔
670
        } else {
671
            return ImHelper.statementExprVoid(statements);
1✔
672
        }
673
    }
674

675
    public static ImExpr translate(ExprDestroy s, ImTranslator t, ImFunction f) {
676
        WurstType typ = s.getDestroyedObj().attrTyp();
1✔
677
        if (typ instanceof WurstTypeClass) {
1✔
678
            WurstTypeClass classType = (WurstTypeClass) typ;
1✔
679
            return destroyClass(s, t, f, classType.getClassDef());
1✔
680
        } else if (typ instanceof WurstTypeInterface) {
1✔
681
            WurstTypeInterface wti = (WurstTypeInterface) typ;
1✔
682
            return destroyClass(s, t, f, wti.getDef());
1✔
683
        } else if (typ instanceof WurstTypeModuleInstanciation) {
×
684
            WurstTypeModuleInstanciation minsType = (WurstTypeModuleInstanciation) typ;
×
685
            ClassDef classDef = minsType.getDef().attrNearestClassDef();
×
686
            return destroyClass(s, t, f, classDef);
×
687
        }
688
        // TODO destroy interfaces?
689
        throw new CompileError(s.getSource(), "cannot destroy object of type " + typ);
×
690
    }
691

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

696
    }
697

698
    public static ImExpr translate(ExprEmpty s, ImTranslator translator, ImFunction f) {
699
        throw new CompileError(s.getSource(), "cannot translate empty expression");
×
700
    }
701

702
    public static ImExpr translate(ExprIfElse e, ImTranslator t, ImFunction f) {
703
        ImExpr ifTrue = e.getIfTrue().imTranslateExpr(t, f);
1✔
704
        ImExpr ifFalse = e.getIfFalse().imTranslateExpr(t, f);
1✔
705
        // TODO common super type of both
706
        ImVar res = JassIm.ImVar(e, ifTrue.attrTyp(), "cond_result", false);
1✔
707
        f.getLocals().add(res);
1✔
708
        return JassIm.ImStatementExpr(
1✔
709
                ImStmts(
1✔
710
                        ImIf(e, e.getCond().imTranslateExpr(t, f),
1✔
711
                                ImStmts(
1✔
712
                                        ImSet(e.getIfTrue(), ImVarAccess(res), ifTrue)
1✔
713
                                ),
714
                                ImStmts(
1✔
715
                                        ImSet(e.getIfFalse(), ImVarAccess(res), ifFalse)
1✔
716
                                ))
717
                ),
718
                JassIm.ImVarAccess(res)
1✔
719
        );
720
    }
721

722
    public static ImLExpr translateLvalue(LExpr e, ImTranslator t, ImFunction f) {
723
        NameDef decl = e.attrNameDef();
1✔
724
        if (decl == null) {
1✔
725
            // should only happen with gg_ variables
726
            throw new CompileError(e.getSource(), "Translation Error: Could not find definition of " + e.getVarName() + ".");
×
727
        }
728
        if (decl instanceof VarDef) {
1✔
729
            VarDef varDef = (VarDef) decl;
1✔
730

731
            ImVar v = t.getVarFor(varDef);
1✔
732

733
            if (e.attrImplicitParameter() instanceof Expr) {
1✔
734
                // we have implicit parameter
735
                // e.g. "someObject.someField"
736
                Expr implicitParam = (Expr) e.attrImplicitParameter();
1✔
737

738
                if (implicitParam.attrTyp() instanceof WurstTypeTuple) {
1✔
739
                    WurstTypeTuple tupleType = (WurstTypeTuple) implicitParam.attrTyp();
1✔
740
                    if (e instanceof ExprMemberVar && ((ExprMemberVar) e).getLeft() instanceof LExpr) {
1✔
741
                        ExprMemberVar emv = (ExprMemberVar) e;
1✔
742
                        LExpr left = (LExpr) emv.getLeft();
1✔
743
                        ImLExpr lt = left.imTranslateExprLvalue(t, f);
1✔
744
                        return JassIm.ImTupleSelection(lt, tupleType.getTupleIndex(varDef));
1✔
745
                    } else {
746
                        throw new CompileError(e.getSource(), "Cannot create tuple access");
×
747
                    }
748
                }
749

750
                if (e instanceof AstElementWithIndexes) {
1✔
751
                    ImExpr index1 = implicitParam.imTranslateExpr(t, f);
1✔
752
                    ImExpr index2 = ((AstElementWithIndexes) e).getIndexes().get(0).imTranslateExpr(t, f);
1✔
753
                    return JassIm.ImMemberAccess(e, index1, JassIm.ImTypeArguments(), v, JassIm.ImExprs(index2));
1✔
754

755
                } else {
756
                    ImExpr index = implicitParam.imTranslateExpr(t, f);
1✔
757
                    return JassIm.ImMemberAccess(e, index, JassIm.ImTypeArguments(), v, JassIm.ImExprs());
1✔
758
                }
759
            } else {
760
                // direct var access
761
                if (e instanceof AstElementWithIndexes) {
1✔
762
                    // direct access array var
763
                    AstElementWithIndexes withIndexes = (AstElementWithIndexes) e;
1✔
764
                    if (withIndexes.getIndexes().size() > 1) {
1✔
765
                        throw new CompileError(e.getSource(), "More than one index is not supported.");
×
766
                    }
767
                    ImExpr index = withIndexes.getIndexes().get(0).imTranslateExpr(t, f);
1✔
768
                    return ImVarArrayAccess(e, v, JassIm.ImExprs(index));
1✔
769
                } else {
770
                    // not an array var
771
                    return ImVarAccess(v);
1✔
772

773
                }
774
            }
775
        } else {
776
            throw new CompileError(e.getSource(), "Cannot translate reference to " + Utils.printElement(decl));
×
777
        }
778
    }
779

780
//    public static ImLExpr translateLvalue(ExprVarArrayAccess e, ImTranslator translator, ImFunction f) {
781
//        NameDef nameDef = e.tryGetNameDef();
782
//        if (nameDef instanceof VarDef) {
783
//            VarDef varDef = (VarDef) nameDef;
784
//            ImVar v = translator.getVarFor(varDef);
785
//            ImExprs indexes = e.getIndexes().stream()
786
//                    .map(ie -> ie.imTranslateExpr(translator, f))
787
//                    .collect(Collectors.toCollection(JassIm::ImExprs));
788
//            return JassIm.ImVarArrayAccess(v, indexes);
789
//        }
790
//        throw new RuntimeException("TODO");
791
//
792
//    }
793
//
794
//    public static ImLExpr translateLvalue(ExprMemberVar e, ImTranslator translator, ImFunction f) {
795
//        ImExpr receiver = e.getLeft().imTranslateExpr(translator, f);
796
//        NameDef nameDef = e.tryGetNameDef();
797
//        if (nameDef instanceof VarDef) {
798
//            VarDef v = (VarDef) nameDef;
799
//            ImVar imVar = translator.getVarFor(v);
800
//            return JassIm.ImMemberAccess(receiver, imVar);
801
//        }
802
//        throw new RuntimeException("TODO");
803
//    }
804
//
805
//    public static ImLExpr translateLvalue(ExprMemberArrayVar e, ImTranslator translator, ImFunction f) {
806
//        throw new RuntimeException("TODO");
807
//    }
808

809

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

© 2026 Coveralls, Inc