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

wurstscript / WurstScript / 203

18 Oct 2023 02:20PM UTC coverage: 63.758% (+0.3%) from 63.447%
203

push

circleci

web-flow
Update deps, improve performance, JHCR fixes (#1080)

- update dependencies
- update stdlib verison for unit tests
- only apply nullsetting when `-opt` is enabled to save some build time for testing
- minor performance improvements
- make build deterministic
- apply build map config before compilation
- hot code reload now more reliable

17246 of 27049 relevant lines covered (63.76%)

0.64 hits per line

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

88.82
de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ImTranslator.java
1
package de.peeeq.wurstscript.translation.imtranslation;
2

3
import com.google.common.base.Preconditions;
4
import com.google.common.collect.*;
5
import com.google.common.collect.ImmutableList.Builder;
6
import de.peeeq.datastructures.Partitions;
7
import de.peeeq.datastructures.TransitiveClosure;
8
import de.peeeq.wurstscript.RunArgs;
9
import de.peeeq.wurstscript.WLogger;
10
import de.peeeq.wurstscript.WurstOperator;
11
import de.peeeq.wurstscript.ast.*;
12
import de.peeeq.wurstscript.attributes.CompileError;
13
import de.peeeq.wurstscript.attributes.names.FuncLink;
14
import de.peeeq.wurstscript.attributes.names.NameLink;
15
import de.peeeq.wurstscript.attributes.names.PackageLink;
16
import de.peeeq.wurstscript.jassIm.Element;
17
import de.peeeq.wurstscript.jassIm.ImAnyType;
18
import de.peeeq.wurstscript.jassIm.ImArrayType;
19
import de.peeeq.wurstscript.jassIm.ImArrayTypeMulti;
20
import de.peeeq.wurstscript.jassIm.ImClass;
21
import de.peeeq.wurstscript.jassIm.ImClassType;
22
import de.peeeq.wurstscript.jassIm.ImExprs;
23
import de.peeeq.wurstscript.jassIm.ImFuncRef;
24
import de.peeeq.wurstscript.jassIm.ImFunction;
25
import de.peeeq.wurstscript.jassIm.ImFunctionCall;
26
import de.peeeq.wurstscript.jassIm.ImMethod;
27
import de.peeeq.wurstscript.jassIm.ImProg;
28
import de.peeeq.wurstscript.jassIm.ImReturn;
29
import de.peeeq.wurstscript.jassIm.ImSet;
30
import de.peeeq.wurstscript.jassIm.ImSimpleType;
31
import de.peeeq.wurstscript.jassIm.ImStmts;
32
import de.peeeq.wurstscript.jassIm.ImTupleType;
33
import de.peeeq.wurstscript.jassIm.ImTypeArguments;
34
import de.peeeq.wurstscript.jassIm.ImTypeVar;
35
import de.peeeq.wurstscript.jassIm.ImTypeVarRef;
36
import de.peeeq.wurstscript.jassIm.ImTypeVars;
37
import de.peeeq.wurstscript.jassIm.ImVar;
38
import de.peeeq.wurstscript.jassIm.ImVars;
39
import de.peeeq.wurstscript.jassIm.ImVoid;
40
import de.peeeq.wurstscript.jassIm.*;
41
import de.peeeq.wurstscript.parser.WPos;
42
import de.peeeq.wurstscript.types.*;
43
import de.peeeq.wurstscript.utils.Pair;
44
import de.peeeq.wurstscript.utils.Utils;
45
import de.peeeq.wurstscript.validation.TRVEHelper;
46
import de.peeeq.wurstscript.validation.WurstValidator;
47
import org.eclipse.jdt.annotation.Nullable;
48
import org.jetbrains.annotations.NotNull;
49

50
import java.util.*;
51
import java.util.function.Function;
52
import java.util.stream.Collectors;
53
import java.util.stream.Stream;
54

55
import static de.peeeq.wurstscript.jassIm.JassIm.*;
56
import static de.peeeq.wurstscript.translation.imtranslation.FunctionFlagEnum.*;
57
import static de.peeeq.wurstscript.utils.Utils.elementNameWithPath;
58

59
public class ImTranslator {
60

61

62
    public static final String $DEBUG_PRINT = "$debugPrint";
63

64
    private static final de.peeeq.wurstscript.ast.Element emptyTrace = Ast.NoExpr();
1✔
65

66
    private @Nullable Multimap<ImFunction, ImFunction> callRelations = null;
1✔
67
    private @Nullable Set<ImVar> usedVariables = null;
1✔
68
    private @Nullable Set<ImVar> readVariables = null;
1✔
69
    private @Nullable Set<ImFunction> usedFunctions = null;
1✔
70

71
    private @Nullable ImFunction debugPrintFunction;
72

73
    private final Map<TranslatedToImFunction, ImFunction> functionMap = new LinkedHashMap<>();
1✔
74
    private @Nullable ImFunction globalInitFunc;
75

76
    private final ImProg imProg;
77

78
    final Map<WPackage, ImFunction> initFuncMap = new LinkedHashMap<>();
1✔
79

80
    private final Map<TranslatedToImFunction, ImVar> thisVarMap = new LinkedHashMap<>();
1✔
81

82
    private final Set<WPackage> translatedPackages = new LinkedHashSet<>();
1✔
83
    private final Set<ClassDef> translatedClasses = new LinkedHashSet<>();
1✔
84

85

86
    private final Map<VarDef, ImVar> varMap = new LinkedHashMap<>();
1✔
87

88
    private final WurstModel wurstProg;
89

90
    private @Nullable ImFunction mainFunc = null;
1✔
91

92
    private @Nullable ImFunction configFunc = null;
1✔
93

94
    @Nullable public ImFunction ensureIntFunc = null;
1✔
95
    @Nullable public ImFunction ensureBoolFunc = null;
1✔
96
    @Nullable public ImFunction ensureRealFunc = null;
1✔
97
    @Nullable public ImFunction ensureStrFunc = null;
1✔
98
    @Nullable public ImFunction stringConcatFunc = null;
1✔
99

100
    private final Map<ImVar, VarsForTupleResult> varsForTupleVar = new LinkedHashMap<>();
1✔
101

102
    private boolean isUnitTestMode;
103

104
    private ImVar lastInitFunc = JassIm.ImVar(emptyTrace, WurstTypeString.instance().imTranslateType(this), "lastInitFunc", false);
1✔
105

106
    private int compiletimeOrderCounter = 1;
1✔
107
    private final Map<TranslatedToImFunction, FunctionFlagCompiletime> compiletimeFlags = new HashMap<>();
1✔
108
    private final Map<ExprFunctionCall, Integer> compiletimeExpressionsOrder = new HashMap<>();
1✔
109

110
    de.peeeq.wurstscript.ast.Element lasttranslatedThing;
111
    private boolean debug = false;
1✔
112
    private final RunArgs runArgs;
113

114
    public ImTranslator(WurstModel wurstProg, boolean isUnitTestMode, RunArgs runArgs) {
1✔
115
        this.wurstProg = wurstProg;
1✔
116
        this.lasttranslatedThing = wurstProg;
1✔
117
        this.isUnitTestMode = isUnitTestMode;
1✔
118
        imProg = ImProg(wurstProg, ImVars(), ImFunctions(), ImMethods(), JassIm.ImClasses(), JassIm.ImTypeClassFuncs(), new LinkedHashMap<>());
1✔
119
        this.runArgs = runArgs;
1✔
120
    }
1✔
121

122

123
    /**
124
     * translates a program
125
     */
126
    public ImProg translateProg() {
127
        try {
128
            globalInitFunc = ImFunction(emptyTrace, "initGlobals", ImTypeVars(), ImVars(), ImVoid(), ImVars(), ImStmts(), flags());
1✔
129
            addFunction(getGlobalInitFunc());
1✔
130
            debugPrintFunction = ImFunction(emptyTrace, $DEBUG_PRINT, ImTypeVars(), ImVars(JassIm.ImVar(wurstProg, WurstTypeString.instance().imTranslateType(this), "msg",
1✔
131
                    false)), ImVoid(), ImVars(), ImStmts(), flags(IS_NATIVE, IS_BJ));
1✔
132

133
            if(isLuaTarget()) {
1✔
134
                ensureIntFunc = JassIm.ImFunction(emptyTrace, "intEnsure", ImTypeVars(), ImVars(JassIm.ImVar(wurstProg, WurstTypeInt.instance().imTranslateType(this), "x", false)), WurstTypeInt.instance().imTranslateType(this), ImVars(), ImStmts(), flags(IS_NATIVE, IS_BJ));
1✔
135
                ensureBoolFunc = JassIm.ImFunction(emptyTrace, "boolEnsure", ImTypeVars(), ImVars(JassIm.ImVar(wurstProg, WurstTypeBool.instance().imTranslateType(this), "x", false)), WurstTypeBool.instance().imTranslateType(this), ImVars(), ImStmts(), flags(IS_NATIVE, IS_BJ));
1✔
136
                ensureRealFunc = JassIm.ImFunction(emptyTrace, "realEnsure", ImTypeVars(), ImVars(JassIm.ImVar(wurstProg, WurstTypeReal.instance().imTranslateType(this), "x", false)), WurstTypeReal.instance().imTranslateType(this), ImVars(), ImStmts(), flags(IS_NATIVE, IS_BJ));
1✔
137
                ensureStrFunc = JassIm.ImFunction(emptyTrace, "stringEnsure", ImTypeVars(), ImVars(JassIm.ImVar(wurstProg, WurstTypeString.instance().imTranslateType(this), "x", false)), WurstTypeString.instance().imTranslateType(this), ImVars(), ImStmts(), flags(IS_NATIVE, IS_BJ));
1✔
138
                stringConcatFunc =JassIm.ImFunction(emptyTrace, "stringConcat", ImTypeVars(), ImVars(JassIm.ImVar(wurstProg, WurstTypeString.instance().imTranslateType(this), "x", false),JassIm.ImVar(wurstProg, WurstTypeString.instance().imTranslateType(this), "y", false)), WurstTypeString.instance().imTranslateType(this), ImVars(), ImStmts(), flags(IS_NATIVE, IS_BJ));
1✔
139
                addFunction(ensureIntFunc);
1✔
140
                addFunction(ensureBoolFunc);
1✔
141
                addFunction(ensureRealFunc);
1✔
142
                addFunction(ensureStrFunc);
1✔
143
                addFunction(stringConcatFunc);
1✔
144
            }
145

146
            calculateCompiletimeOrder();
1✔
147

148
            for (CompilationUnit cu : wurstProg) {
1✔
149
                translateCompilationUnit(cu);
1✔
150
            }
1✔
151

152
            if (mainFunc == null) {
1✔
153
                mainFunc = ImFunction(emptyTrace, "main", ImTypeVars(), ImVars(), ImVoid(), ImVars(), ImStmts(), flags());
1✔
154
                addFunction(mainFunc);
1✔
155
            }
156
            if (configFunc == null) {
1✔
157
                configFunc = ImFunction(emptyTrace, "config", ImTypeVars(), ImVars(), ImVoid(), ImVars(), ImStmts(), flags());
1✔
158
                addFunction(configFunc);
1✔
159
            }
160

161
            finishInitFunctions();
1✔
162
            EliminateCallFunctionsWithAnnotation.process(imProg);
1✔
163
            removeDuplicateNatives(imProg);
1✔
164
            sortEverything();
1✔
165
            return imProg;
1✔
166
        } catch (CompileError t) {
1✔
167
            throw t;
1✔
168
        } catch (Throwable t) {
×
169
            WLogger.severe(t);
×
170
            throw new RuntimeException("There was a Wurst bug in the translation of "
×
171
                    + Utils.printElementWithSource(Optional.of(lasttranslatedThing))
×
172
                    + ": "
173
                    + t.getMessage()
×
174
                    + "\nPlease open a ticket with source code and the error log.", t);
175
        }
176
    }
177

178
    /**
179
     * Number all the compiletime functions and expressions,
180
     * so that the one with the lowest number can be executed first.
181
     * <p>
182
     * Dependendend packages are executed first and inside a package
183
     * it goes from top to bottom.
184
     */
185
    private void calculateCompiletimeOrder() {
186
        Set<WPackage> visited = new HashSet<>();
1✔
187
        ImmutableCollection<WPackage> packages = wurstProg.attrPackages().values();
1✔
188

189
        for (WPackage p : packages) {
1✔
190
            calculateCompiletimeOrder_walk(p, visited);
1✔
191
        }
1✔
192
    }
1✔
193

194
    private void calculateCompiletimeOrder_walk(WPackage p, Set<WPackage> visited) {
195
        if (!visited.add(p)) {
1✔
196
            return;
1✔
197
        }
198
        for (WPackage dep : p.attrInitDependencies()) {
1✔
199
            calculateCompiletimeOrder_walk(dep, visited);
1✔
200
        }
1✔
201
        p.accept(new de.peeeq.wurstscript.ast.Element.DefaultVisitor() {
1✔
202
            @Override
203
            public void visit(FuncDef funcDef) {
204
                super.visit(funcDef);
1✔
205
                if (funcDef.attrIsCompiletime()) {
1✔
206
                    compiletimeFlags.put(funcDef, new FunctionFlagCompiletime(compiletimeOrderCounter++));
1✔
207
                }
208
            }
1✔
209

210
            @Override
211
            public void visit(ExprFunctionCall fc) {
212
                super.visit(fc);
1✔
213
                if (fc.getFuncName().equals("compiletime")) {
1✔
214
                    compiletimeExpressionsOrder.put(fc, compiletimeOrderCounter++);
1✔
215
                }
216
            }
1✔
217
        });
218
    }
1✔
219

220

221
    /**
222
     * sorting everything is supposed to make the translation deterministic
223
     */
224
    private void sortEverything() {
225
        sortList(imProg.getClasses());
1✔
226
        sortList(imProg.getGlobals());
1✔
227
        sortList(imProg.getFunctions());
1✔
228
        for (ImClass c : imProg.getClasses()) {
1✔
229
            sortList(c.getFields());
1✔
230
            sortList(c.getMethods());
1✔
231
        }
1✔
232
    }
1✔
233

234

235
    private <T extends Element> void sortList(List<T> list) {
236
        List<T> classes = removeAll(list);
1✔
237
        Comparator<T> comparator = Comparator.comparing(this::getQualifiedClassName);
1✔
238
        classes.sort(comparator);
1✔
239
        list.addAll(classes);
1✔
240
    }
1✔
241

242
    public <T> List<T> removeAll(List<T> list) {
243
        List<T> result = new ArrayList<>();
1✔
244
        while (!list.isEmpty()) {
1✔
245
            result.add(0, list.remove(list.size() - 1));
1✔
246
        }
247
        return result;
1✔
248
    }
249

250
    private String getQualifiedClassName(Element c) {
251
        return getQualifiedClassName(c.attrTrace());
1✔
252
    }
253

254

255
    private String getQualifiedClassName(de.peeeq.wurstscript.ast.Element e) {
256
        String result = "";
1✔
257
        if (e instanceof NamedScope) {
1✔
258
            NamedScope ns = (NamedScope) e;
1✔
259
            result = ns.getName();
1✔
260
        }
261
        de.peeeq.wurstscript.ast.Element parent = e.getParent();
1✔
262
        if (parent == null) {
1✔
263
            return result;
1✔
264
        }
265
        parent = parent.attrNearestNamedScope();
1✔
266
        if (parent == null) {
1✔
267
            return result;
1✔
268
        }
269
        return getQualifiedClassName(parent) + "_" + result;
1✔
270
    }
271

272

273
    /***
274
     * this phase removes duplicate native declarations
275
     */
276
    private void removeDuplicateNatives(ImProg imProg) {
277
        Map<String, ImFunction> natives = new HashMap<>();
1✔
278
        Map<ImFunction, ImFunction> removed = new HashMap<>();
1✔
279
        ListIterator<ImFunction> it = imProg.getFunctions().listIterator();
1✔
280
        while (it.hasNext()) {
1✔
281
            ImFunction f = it.next();
1✔
282
            if (f.isNative() && natives.containsKey(f.getName())) {
1✔
283
                ImFunction existing = natives.get(f.getName());
1✔
284
                if (!compatibleTypes(f, existing)) {
1✔
285
                    throw new CompileError(f, "Native function definition conflicts with other native function defined in " +
×
286
                            existing.attrTrace().attrErrorPos());
×
287
                }
288
                // remove duplicate
289
                it.remove();
1✔
290
                removed.put(f, existing);
1✔
291
            } else {
1✔
292
                natives.put(f.getName(), f);
1✔
293
            }
294
        }
1✔
295
        // rewrite removed links
296
        imProg.accept(new ImProg.DefaultVisitor() {
1✔
297
            public void visit(ImFunctionCall e) {
298
                super.visit(e);
1✔
299
                if (removed.containsKey(e.getFunc())) {
1✔
300
                    e.setFunc(removed.get(e.getFunc()));
1✔
301
                }
302
            }
1✔
303

304
            public void visit(ImFuncRef e) {
305
                super.visit(e);
1✔
306
                if (removed.containsKey(e.getFunc())) {
1✔
307
                    e.setFunc(removed.get(e.getFunc()));
×
308
                }
309
            }
1✔
310
        });
311
    }
1✔
312

313

314
    /**
315
     * checks if two functions f and g have compatible types
316
     */
317
    private boolean compatibleTypes(ImFunction f, ImFunction g) {
318
        if (!f.getReturnType().equalsType(g.getReturnType())) {
1✔
319
            return false;
×
320
        }
321
        if (f.getParameters().size() != g.getParameters().size()) {
1✔
322
            return false;
×
323
        }
324
        for (int i = 0; i < f.getParameters().size(); i++) {
1✔
325
            if (!f.getParameters().get(i).getType().equalsType(g.getParameters().get(i).getType())) {
×
326
                return false;
×
327
            }
328
        }
329
        return true;
1✔
330
    }
331

332

333
    private ArrayList<FunctionFlag> flags(FunctionFlag... flags) {
334
        return Lists.newArrayList(flags);
1✔
335
    }
336

337

338
    private void translateCompilationUnit(CompilationUnit cu) {
339
        lasttranslatedThing = cu;
1✔
340
        // TODO can we make this smarter? Only translate functions which are actually called...
341
        for (WPackage p : cu.getPackages()) {
1✔
342
            lasttranslatedThing = p;
1✔
343
            p.imTranslateTLD(this);
1✔
344
        }
1✔
345
        for (JassToplevelDeclaration tld : cu.getJassDecls()) {
1✔
346
            lasttranslatedThing = tld;
1✔
347
            tld.imTranslateTLD(this);
1✔
348
        }
1✔
349
    }
1✔
350

351

352
    private void finishInitFunctions() {
353
        // init globals, at beginning of main func:
354
        getMainFunc().getBody().add(0, ImFunctionCall(emptyTrace, globalInitFunc, ImTypeArguments(), ImExprs(), false, CallType.NORMAL));
1✔
355

356

357
        for (ImFunction initFunc : initFuncMap.values()) {
1✔
358
            addFunction(initFunc);
1✔
359
        }
1✔
360
        Set<WPackage> calledInitializers = Sets.newLinkedHashSet();
1✔
361

362
        ImVar initTrigVar = prepareTrigger();
1✔
363

364
        for (WPackage p : Utils.sortByName(initFuncMap.keySet())) {
1✔
365
            callInitFunc(calledInitializers, p, initTrigVar);
1✔
366
        }
1✔
367

368
        ImFunction native_DestroyTrigger = getNativeFunc("DestroyTrigger");
1✔
369
        if (native_DestroyTrigger != null) {
1✔
370
            getMainFunc().getBody().add(JassIm.ImFunctionCall(emptyTrace, native_DestroyTrigger, ImTypeArguments(),
1✔
371
                    JassIm.ImExprs(JassIm.ImVarAccess(initTrigVar)), false, CallType.NORMAL));
1✔
372
        }
373
    }
1✔
374

375
    @NotNull
376
    private ImVar prepareTrigger() {
377
        ImVar initTrigVar = JassIm.ImVar(emptyTrace, JassIm.ImSimpleType("trigger"), "initTrig", false);
1✔
378
        getMainFunc().getLocals().add(initTrigVar);
1✔
379

380
        // initTrigVar = CreateTrigger()
381
        ImFunction createTrigger = getNativeFunc("CreateTrigger");
1✔
382
        if (createTrigger != null) {
1✔
383
            getMainFunc().getBody().add(ImSet(getMainFunc().getTrace(), ImVarAccess(initTrigVar), JassIm.ImFunctionCall(getMainFunc().getTrace(), getNativeFunc("CreateTrigger"), ImTypeArguments(), JassIm.ImExprs(), false, CallType.NORMAL)));
1✔
384
        }
385
        return initTrigVar;
1✔
386
    }
387

388

389
    private ImFunction getNativeFunc(String funcName) {
390
        ImmutableCollection<FuncLink> wurstFunc = wurstProg.lookupFuncs(funcName);
1✔
391
        if (wurstFunc.isEmpty()) {
1✔
392
            return null;
1✔
393
        }
394
        return getFuncFor((TranslatedToImFunction) Utils.getFirst(wurstFunc).getDef());
1✔
395
    }
396

397
    private void callInitFunc(Set<WPackage> calledInitializers, WPackage p, ImVar initTrigVar) {
398
        Preconditions.checkNotNull(p);
1✔
399
        if (calledInitializers.contains(p)) {
1✔
400
            return;
1✔
401
        }
402
        calledInitializers.add(p);
1✔
403
        // first initialize all packages imported by this package:
404
        for (WPackage dep : p.attrInitDependencies()) {
1✔
405
            callInitFunc(calledInitializers, dep, initTrigVar);
1✔
406
        }
1✔
407
        ImFunction initFunc = initFuncMap.get(p);
1✔
408
        if (initFunc == null) {
1✔
409
            return;
1✔
410
        }
411
        if (initFunc.getBody().size() == 0) {
1✔
412
            return;
×
413
        }
414
        boolean successful = createInitFuncCall(p, initTrigVar, initFunc);
1✔
415

416
        if (!successful) {
1✔
417
            getMainFunc().getBody().add(ImFunctionCall(initFunc.getTrace(), initFunc, ImTypeArguments(), ImExprs(), false, CallType.NORMAL));
1✔
418
        }
419
    }
1✔
420

421

422
    private boolean createInitFuncCall(WPackage p, ImVar initTrigVar, ImFunction initFunc) {
423
        ImStmts mainBody = getMainFunc().getBody();
1✔
424

425
        ImFunction native_ClearTrigger = getNativeFunc("TriggerClearConditions");
1✔
426
        ImFunction native_TriggerAddCondition = getNativeFunc("TriggerAddCondition");
1✔
427
        ImFunction native_Condition = getNativeFunc("Condition");
1✔
428
        ImFunction native_TriggerEvaluate = getNativeFunc("TriggerEvaluate");
1✔
429
        ImFunction native_DisplayTimedTextToPlayer = getNativeFunc("DisplayTimedTextToPlayer");
1✔
430
        ImFunction native_GetLocalPlayer = getNativeFunc("GetLocalPlayer");
1✔
431

432
        if (native_ClearTrigger == null
1✔
433
                || native_TriggerAddCondition == null
434
                || native_Condition == null
435
                || native_TriggerEvaluate == null
436
                || native_DisplayTimedTextToPlayer == null
437
                || native_GetLocalPlayer == null
438
        ) {
439
            return false;
1✔
440
        }
441

442

443
        // rewrite init func to return boolean true:
444
        initFunc.setReturnType(WurstTypeBool.instance().imTranslateType(this));
1✔
445
        initFunc.accept(new ImFunction.DefaultVisitor() {
1✔
446
            @Override
447
            public void visit(ImReturn imReturn) {
448
                super.visit(imReturn);
×
449
                imReturn.setReturnValue(JassIm.ImBoolVal(true));
×
450
            }
×
451
        });
452
        de.peeeq.wurstscript.ast.Element trace = initFunc.getTrace();
1✔
453
        initFunc.getBody().add(JassIm.ImReturn(trace, JassIm.ImBoolVal(true)));
1✔
454

455

456
        // TriggerAddCondition(initTrigVar, Condition(function myInit))
457
        mainBody.add(ImFunctionCall(trace, native_TriggerAddCondition, ImTypeArguments(), JassIm.ImExprs(
1✔
458
                JassIm.ImVarAccess(initTrigVar),
1✔
459
                ImFunctionCall(trace, native_Condition, ImTypeArguments(), JassIm.ImExprs(
1✔
460
                        JassIm.ImFuncRef(trace, initFunc)), false, CallType.NORMAL)
1✔
461
        ), true, CallType.NORMAL));
462
        // if not TriggerEvaluate(initTrigVar) ...
463
        mainBody.add(JassIm.ImIf(trace,
1✔
464
                JassIm.ImOperatorCall(WurstOperator.NOT, JassIm.ImExprs(
1✔
465
                        ImFunctionCall(trace, native_TriggerEvaluate, ImTypeArguments(), JassIm.ImExprs(JassIm.ImVarAccess(initTrigVar)), false, CallType.NORMAL)
1✔
466
                )),
467
                // then: DisplayTimedTextToPlayer(GetLocalPlayer(), 0., 0., 45., "Could not initialize package")
468
                JassIm.ImStmts(
1✔
469
                    imError(trace, JassIm.ImStringVal("Could not initialize package " + p.getName() + "."))
1✔
470
                ),
471
                // else:
472
                JassIm.ImStmts()));
1✔
473
        mainBody.add(ImFunctionCall(trace, native_ClearTrigger, ImTypeArguments(), JassIm.ImExprs(JassIm.ImVarAccess(initTrigVar)), false, CallType.NORMAL));
1✔
474
        return true;
1✔
475
    }
476

477
    private void addFunction(ImFunction f, StructureDef s) {
478
        ImClass c = getClassFor(s.attrNearestClassOrInterface());
1✔
479
        c.getFunctions().add(f);
1✔
480
    }
1✔
481

482
    private void addFunction(ImFunction f, TranslatedToImFunction funcDef) {
483
        ImClass classForFunc = getClassForFunc(funcDef);
1✔
484
        if (classForFunc != null) {
1✔
485
            classForFunc.getFunctions().add(f);
1✔
486
        } else {
487
            addFunction(f);
1✔
488
        }
489
    }
1✔
490

491
    private void addFunction(ImFunction f) {
492
        imProg.getFunctions().add(f);
1✔
493
    }
1✔
494

495
    public void addGlobal(ImVar v) {
496
        imProg.getGlobals().add(v);
1✔
497
    }
1✔
498

499

500
    public void addGlobalInitalizer(ImVar v, PackageOrGlobal packageOrGlobal, VarInitialization initialExpr) {
501
        if (initialExpr instanceof NoExpr) {
1✔
502
            // nothing to initialize
503
            return;
1✔
504
        }
505

506

507
        ImFunction f;
508
        if (packageOrGlobal instanceof WPackage) {
1✔
509
            WPackage p = (WPackage) packageOrGlobal;
1✔
510
            f = getInitFuncFor(p);
1✔
511
        } else {
1✔
512
            f = globalInitFunc;
1✔
513
        }
514
        de.peeeq.wurstscript.ast.Element trace = packageOrGlobal == null ? emptyTrace : packageOrGlobal;
1✔
515
        if (initialExpr instanceof Expr) {
1✔
516
            Expr expr = (Expr) initialExpr;
1✔
517
            ImExpr translated = expr.imTranslateExpr(this, f);
1✔
518
            ImSet imSet = ImSet(trace, ImVarAccess(v), translated);
1✔
519
            if (!v.getIsBJ()) {
1✔
520
                // add init statement for non-bj vars
521
                // bj-vars are already initalized by blizzard
522
                f.getBody().add(imSet);
1✔
523
            }
524
            imProg.getGlobalInits().put(v, Collections.singletonList(imSet));
1✔
525
        } else if (initialExpr instanceof ArrayInitializer) {
1✔
526
            ArrayInitializer arInit = (ArrayInitializer) initialExpr;
1✔
527
            List<ImExpr> translatedExprs = arInit.getValues().stream()
1✔
528
                    .map(expr -> expr.imTranslateExpr(this, f))
1✔
529
                    .collect(Collectors.toList());
1✔
530
            List<ImSet> imSets = new ArrayList<>();
1✔
531
            for (int i = 0; i < arInit.getValues().size(); i++) {
1✔
532
                ImExpr translated = translatedExprs.get(i);
1✔
533
                ImSet imSet = ImSet(trace, ImVarArrayAccess(trace, v, ImExprs((ImExpr) JassIm.ImIntVal(i))), translated);
1✔
534
                imSets.add(imSet);
1✔
535
            }
536
            f.getBody().addAll(imSets);
1✔
537
            // add list of init-values to translatedExprs
538
            imProg.getGlobalInits().put(v, imSets);
1✔
539
        }
540
    }
1✔
541

542
    public void addGlobalWithInitalizer(ImVar g, ImExpr initial) {
543
        imProg.getGlobals().add(g);
1✔
544
        ImSet imSet = ImSet(g.getTrace(), ImVarAccess(g), initial);
1✔
545
        getGlobalInitFunc().getBody().add(imSet);
1✔
546
        imProg.getGlobalInits().put(g, Collections.singletonList(imSet));
1✔
547
    }
1✔
548

549

550
    public ImExpr getDefaultValueForJassType(ImType type) {
551
        if (type instanceof ImSimpleType) {
1✔
552
            ImSimpleType imSimpleType = (ImSimpleType) type;
1✔
553
            return ImHelper.defaultValueForType(imSimpleType);
1✔
554
        } else if (type instanceof ImAnyType) {
1✔
555
            return JassIm.ImIntVal(0);
1✔
556
        } else if (type instanceof ImTupleType) {
×
557
            ImTupleType imTupleType = (ImTupleType) type;
×
558
            return getDefaultValueForJassType(imTupleType.getTypes().get(0));
×
559
        } else {
560
            throw new IllegalArgumentException("could not get default value for type " + type);
×
561
        }
562
    }
563

564
    public GetAForB<StructureDef, ImFunction> destroyFunc = new GetAForB<StructureDef, ImFunction>() {
1✔
565

566
        @Override
567
        public ImFunction initFor(StructureDef classDef) {
568
            ImVars params = ImVars(JassIm.ImVar(classDef, selfType(classDef), "this", false));
1✔
569

570
            ImFunction f = ImFunction(classDef.getOnDestroy(), "destroy" + classDef.getName(), ImTypeVars(), params, TypesHelper.imVoid(), ImVars(), ImStmts(), flags());
1✔
571
            addFunction(f, classDef);
1✔
572
            return f;
1✔
573
        }
574
    };
575

576
    public GetAForB<StructureDef, ImMethod> destroyMethod = new GetAForB<StructureDef, ImMethod>() {
1✔
577

578
        @Override
579
        public ImMethod initFor(StructureDef classDef) {
580
            ImFunction impl = destroyFunc.getFor(classDef);
1✔
581
            ImMethod m = JassIm.ImMethod(classDef, selfType(classDef), "destroy" + classDef.getName(),
1✔
582
                    impl, Lists.<ImMethod>newArrayList(), false);
1✔
583
            return m;
1✔
584
        }
585
    };
586

587
    private ImType selfType(TranslatedToImFunction f) {
588
        return f.match(new TranslatedToImFunction.Matcher<ImType>() {
1✔
589
            @Override
590
            public ImType case_FuncDef(FuncDef f) {
591
                return selfType(f);
1✔
592
            }
593

594
            @Override
595
            public ImType case_ConstructorDef(ConstructorDef f) {
596
                return selfType(f.attrNearestClassOrInterface());
1✔
597
            }
598

599
            @Override
600
            public ImType case_NativeFunc(NativeFunc f) {
601
                throw new CompileError(f, "Cannot use 'this' here.");
×
602
            }
603

604
            @Override
605
            public ImType case_OnDestroyDef(OnDestroyDef f) {
606
                return selfType(f.attrNearestClassOrInterface());
1✔
607
            }
608

609
            @Override
610
            public ImType case_TupleDef(TupleDef f) {
611
                throw new CompileError(f, "Cannot use 'this' here.");
×
612
            }
613

614
            @Override
615
            public ImType case_ExprClosure(ExprClosure f) {
616
                return selfType(getClassForClosure(f));
1✔
617
            }
618

619
            @Override
620
            public ImType case_InitBlock(InitBlock f) {
621
                throw new CompileError(f, "Cannot use 'this' here.");
×
622
            }
623

624
            @Override
625
            public ImType case_ExtensionFuncDef(ExtensionFuncDef f) {
626
                return f.getExtendedType().attrTyp().imTranslateType(ImTranslator.this);
1✔
627
            }
628
        });
629
    }
630

631
    private ImClassType selfType(FuncDef f) {
632
        return selfType(f.attrNearestClassOrInterface());
1✔
633
    }
634

635
    public ImClassType selfType(StructureDef classDef) {
636
        ImClass imClass = getClassFor(classDef.attrNearestClassOrInterface());
1✔
637
        return selfType(imClass);
1✔
638
    }
639

640
    public ImClassType selfType(ImClass imClass) {
641
        ImTypeArguments typeArgs = JassIm.ImTypeArguments();
1✔
642
        for (ImTypeVar tv : imClass.getTypeVariables()) {
1✔
643
            typeArgs.add(JassIm.ImTypeArgument(JassIm.ImTypeVarRef(tv), Collections.emptyMap()));
1✔
644
        }
1✔
645
        return JassIm.ImClassType(imClass, typeArgs);
1✔
646
    }
647

648
    public GetAForB<ImClass, ImFunction> allocFunc = new GetAForB<ImClass, ImFunction>() {
1✔
649

650
        @Override
651
        public ImFunction initFor(ImClass c) {
652

653
            return ImFunction(c.getTrace(), "alloc_" + c.getName(), ImTypeVars(), JassIm.ImVars(), TypesHelper.imInt(), JassIm.ImVars(), JassIm.ImStmts(), Collections.<FunctionFlag>emptyList());
1✔
654
        }
655

656
    };
657

658
    public GetAForB<ImClass, ImFunction> deallocFunc = new GetAForB<ImClass, ImFunction>() {
1✔
659

660
        @Override
661
        public ImFunction initFor(ImClass c) {
662

663
            return ImFunction(c.getTrace(), "dealloc_" + c.getName(), ImTypeVars(), JassIm.ImVars(JassIm.ImVar(c.getTrace(), TypesHelper.imInt(), "obj", false)), TypesHelper.imVoid(), JassIm.ImVars(), JassIm.ImStmts(), Collections.<FunctionFlag>emptyList());
1✔
664
        }
665

666
    };
667

668
    private final Map<ImTypeVar, TypeParamDef> typeVariableReverse = new HashMap<>();
1✔
669

670
    private final GetAForB<TypeParamDef, ImTypeVar> typeVariable = new GetAForB<TypeParamDef, ImTypeVar>() {
1✔
671

672
        @Override
673
        public ImTypeVar initFor(TypeParamDef a) {
674
            ImTypeVar v = JassIm.ImTypeVar(a.getName());
1✔
675
            typeVariableReverse.put(v, a);
1✔
676
            return v;
1✔
677
        }
678
    };
679

680

681
    public ImFunction getFuncFor(TranslatedToImFunction funcDef) {
682
        if (functionMap.containsKey(funcDef)) {
1✔
683
            return functionMap.get(funcDef);
1✔
684
        }
685
        String name = getNameFor(funcDef);
1✔
686
        List<FunctionFlag> flags = flags();
1✔
687
        if (funcDef instanceof NativeFunc) {
1✔
688
            flags.add(IS_NATIVE);
1✔
689
        }
690
        if (isBJ(funcDef.getSource())) {
1✔
691
            flags.add(IS_BJ);
1✔
692
        }
693
        if (isExtern(funcDef)) {
1✔
694
            flags.add(FunctionFlagEnum.IS_EXTERN);
1✔
695
        }
696
        if (funcDef instanceof FuncDef) {
1✔
697
            FuncDef funcDef2 = (FuncDef) funcDef;
1✔
698
            if (funcDef2.attrIsCompiletime()) {
1✔
699
                FunctionFlagCompiletime flag = compiletimeFlags.get(funcDef);
1✔
700
                if (flag == null) {
1✔
701
                    throw new CompileError(funcDef.getSource(), "Compiletime flag not supported here.");
×
702
                }
703
                flags.add(flag);
1✔
704
            }
705
            if (funcDef2.attrHasAnnotation("compiletimenative")) {
1✔
706
                flags.add(FunctionFlagEnum.IS_COMPILETIME_NATIVE);
1✔
707
            }
708
            if (funcDef2.attrHasAnnotation("test")) {
1✔
709
                flags.add(IS_TEST);
1✔
710
            }
711
        }
712

713
        // Check if last parameter is vararg
714
        if (funcDef instanceof AstElementWithParameters) {
1✔
715
            WParameters params = ((AstElementWithParameters) funcDef).getParameters();
1✔
716
            if (params.size() >= 1 && params.get(params.size() - 1).attrIsVararg()) {
1✔
717
                flags.add(IS_VARARG);
1✔
718
            }
719
        }
720

721

722
        if (funcDef instanceof HasModifier) {
1✔
723
            HasModifier awm = (HasModifier) funcDef;
1✔
724
            for (Modifier m : awm.getModifiers()) {
1✔
725
                if (m instanceof Annotation) {
1✔
726
                    Annotation annotation = (Annotation) m;
1✔
727
                    flags.add(new FunctionFlagAnnotation(annotation.getAnnotationType()));
1✔
728
                }
729
            }
1✔
730
        }
731

732
        ImTypeVars typeVars = collectTypeVarsForFunction(funcDef);
1✔
733
        ImFunction f = ImFunction(funcDef, name, typeVars, ImVars(), ImVoid(), ImVars(), ImStmts(), flags);
1✔
734
        funcDef.imCreateFuncSkeleton(this, f);
1✔
735

736
        addFunction(f, funcDef);
1✔
737
        functionMap.put(funcDef, f);
1✔
738
        return f;
1✔
739
    }
740

741
    private ImClass getClassForFunc(TranslatedToImFunction funcDef) {
742
        if (funcDef == null) {
1✔
743
            return null;
×
744
        }
745
        return funcDef.match(new TranslatedToImFunction.Matcher<ImClass>() {
1✔
746
            @Override
747
            public ImClass case_TupleDef(TupleDef tupleDef) {
748
                return null;
×
749
            }
750

751
            @Override
752
            public ImClass case_FuncDef(FuncDef funcDef) {
753
                if (funcDef.attrIsDynamicClassMember()) {
1✔
754
                    return getClassFor(funcDef.attrNearestClassOrInterface());
1✔
755
                }
756
                return null;
1✔
757
            }
758

759
            @Override
760
            public ImClass case_NativeFunc(NativeFunc nativeFunc) {
761
                return null;
1✔
762
            }
763

764
            @Override
765
            public ImClass case_OnDestroyDef(OnDestroyDef funcDef) {
766
                return getClassFor(funcDef.attrNearestClassOrInterface());
1✔
767
            }
768

769
            @Override
770
            public ImClass case_InitBlock(InitBlock initBlock) {
771
                return null;
×
772
            }
773

774
            @Override
775
            public ImClass case_ExtensionFuncDef(ExtensionFuncDef extensionFuncDef) {
776
                return null;
1✔
777
            }
778

779
            @Override
780
            public ImClass case_ConstructorDef(ConstructorDef funcDef) {
781
                return getClassFor(funcDef.attrNearestClassOrInterface());
1✔
782
            }
783

784
            @Override
785
            public ImClass case_ExprClosure(ExprClosure exprClosure) {
786
                return null;
1✔
787
            }
788
        });
789
    }
790

791
    private ImTypeVars collectTypeVarsForFunction(TranslatedToImFunction funcDef) {
792
        ImTypeVars typeVars = ImTypeVars();
1✔
793
        funcDef.match(new TranslatedToImFunction.MatcherVoid() {
1✔
794
            @Override
795
            public void case_FuncDef(FuncDef funcDef) {
796
                handleTypeParameters(funcDef.getTypeParameters());
1✔
797
            }
1✔
798

799

800
            private void handleTypeParameters(TypeParamDefs tps) {
801
                for (TypeParamDef tp : tps) {
1✔
802
                    handleTypeParameter(tp);
1✔
803
                }
1✔
804
            }
1✔
805

806
            private void handleTypeParameter(TypeParamDef tp) {
807
                if (tp.getTypeParamConstraints() instanceof TypeExprList) {
1✔
808
                    typeVars.add(typeVariable.getFor(tp));
1✔
809
                }
810
            }
1✔
811

812
            @Override
813
            public void case_ConstructorDef(ConstructorDef constructorDef) {
814
            }
×
815

816
            @Override
817
            public void case_NativeFunc(NativeFunc nativeFunc) {
818
            }
1✔
819

820
            @Override
821
            public void case_OnDestroyDef(OnDestroyDef onDestroyDef) {
822
            }
1✔
823

824
            @Override
825
            public void case_TupleDef(TupleDef tupleDef) {
826
            }
×
827

828
            @Override
829
            public void case_ExprClosure(ExprClosure exprClosure) {
830
                // TODO where to set closure parameters?
831
            }
1✔
832

833
            @Override
834
            public void case_InitBlock(InitBlock initBlock) {
835

836
            }
×
837

838
            @Override
839
            public void case_ExtensionFuncDef(ExtensionFuncDef funcDef) {
840
                handleTypeParameters(funcDef.getTypeParameters());
1✔
841
            }
1✔
842
        });
843
        return typeVars;
1✔
844
    }
845

846

847
    private boolean isExtern(TranslatedToImFunction funcDef) {
848
        if (funcDef instanceof HasModifier) {
1✔
849
            HasModifier f = (HasModifier) funcDef;
1✔
850
            for (Modifier m : f.getModifiers()) {
1✔
851
                if (m instanceof Annotation) {
1✔
852
                    Annotation a = (Annotation) m;
1✔
853
                    if (a.getAnnotationType().equals("@extern")) {
1✔
854
                        return true;
1✔
855
                    }
856
                }
857
            }
1✔
858
        }
859
        return false;
1✔
860
    }
861

862

863
    private boolean isBJ(WPos source) {
864
        String f = source.getFile().toLowerCase();
1✔
865
        return f.endsWith("blizzard.j") || f.endsWith("common.j");
1✔
866
    }
867

868
    public ImFunction getInitFuncFor(WPackage p) {
869
        // TODO more precise trace
870
        return initFuncMap.computeIfAbsent(p, p1 -> ImFunction(p1, "init_" + p1.getName(), ImTypeVars(), ImVars(), ImVoid(), ImVars(), ImStmts(), flags()));
1✔
871
    }
872

873
    /**
874
     * returns a suitable name for the given element
875
     * the returned name is a valid jass identifier
876
     */
877
    public String getNameFor(de.peeeq.wurstscript.ast.Element e) {
878
        if (e instanceof FuncDef) {
1✔
879
            FuncDef f = (FuncDef) e;
1✔
880
            if (f.attrNearestStructureDef() != null) {
1✔
881
                return getNameFor(f.attrNearestStructureDef()) + "_" + f.getName();
1✔
882
            }
883
        } else if (e instanceof ExtensionFuncDef) {
1✔
884
            ExtensionFuncDef f = (ExtensionFuncDef) e;
1✔
885
            return getNameFor(f.getExtendedType()) + "_" + f.getName();
1✔
886
        } else if (e instanceof TypeExprSimple) {
1✔
887
            TypeExprSimple t = (TypeExprSimple) e;
1✔
888
            return t.getTypeName();
1✔
889
        } else if (e instanceof TypeExprThis) {
1✔
890
            return "thistype";
×
891
        } else if (e instanceof TypeExprArray) {
1✔
892
            TypeExprArray t = (TypeExprArray) e;
×
893
            return getNameFor(t.getBase()) + "Array";
×
894
        } else if (e instanceof ModuleInstanciation) {
1✔
895
            ModuleInstanciation mi = (ModuleInstanciation) e;
1✔
896
            return getNameFor(mi.getParent().attrNearestNamedScope()) + "_" + mi.getName();
1✔
897
        }
898

899

900
        if (e instanceof AstElementWithNameId) {
1✔
901
            AstElementWithNameId wn = (AstElementWithNameId) e;
1✔
902
            return wn.getNameId().getName();
1✔
903
        } else if (e instanceof ConstructorDef) {
1✔
904
            return "new_" + e.attrNearestClassDef().getName();
×
905
        } else if (e instanceof OnDestroyDef) {
1✔
906
            return "ondestroy_" + e.attrNearestClassDef().getName();
1✔
907
        } else if (e instanceof ExprClosure) {
1✔
908
            return e.attrNearestNamedScope().getName() + "_closure";
1✔
909
        }
910
        throw new RuntimeException("unhandled case: " + e.getClass().getName());
×
911
    }
912

913
    public ImVar getThisVar(TranslatedToImFunction f) {
914
        if (f instanceof OnDestroyDef) {
1✔
915
            // special case for onDestroy defs
916
            // TODO also special case for constructors needed?
917
            OnDestroyDef od = (OnDestroyDef) f;
1✔
918
            if (od.getParent() instanceof ModuleInstanciation) {
1✔
919
                ModuleInstanciation mi = (ModuleInstanciation) od.getParent();
1✔
920
                ClassDef c = mi.attrNearestClassDef();
1✔
921
                f = c.getOnDestroy();
1✔
922
            }
923
        }
924
        if (thisVarMap.containsKey(f)) {
1✔
925
            return thisVarMap.get(f);
1✔
926
        }
927
        ImVar v = JassIm.ImVar(f, selfType(f), "this", false);
1✔
928
        thisVarMap.put(f, v);
1✔
929
        return v;
1✔
930
    }
931

932
    public ImVar getThisVar(ImFunction f, ExprThis e) {
933
        return getThisVarForNode(f, e);
1✔
934
    }
935

936
    public ImVar getThisVar(ImFunction f, ExprSuper e) {
937
        return getThisVarForNode(f, e);
×
938
    }
939

940
    private ImVar getThisVarForNode(ImFunction f, de.peeeq.wurstscript.ast.Element node1) {
941
        de.peeeq.wurstscript.ast.Element node = node1;
1✔
942
        while (node != null) {
1✔
943
            if (node instanceof TranslatedToImFunction && !(node instanceof ExprClosure)) {
1✔
944
                return getThisVar((TranslatedToImFunction) node);
1✔
945
            }
946
            node = node.getParent();
1✔
947
        }
948
        if (f.getParameters().isEmpty()) {
1✔
949
            throw new CompileError(node1.attrSource(), "Could not get 'this'.");
×
950
        }
951
        return f.getParameters().get(0);
1✔
952
    }
953

954

955
    public int getTupleIndex(TupleDef tupleDef, VarDef parameter) {
956
        int i = 0;
×
957
        for (WParameter p : tupleDef.getParameters()) {
×
958
            if (p == parameter) {
×
959
                return i;
×
960
            }
961
            i++;
×
962
        }
×
963
        throw new Error("");
×
964
    }
965

966

967
    public ImVar getVarFor(VarDef varDef) {
968
        ImVar v = varMap.get(varDef);
1✔
969
        if (v == null) {
1✔
970
            ImType type = varDef.attrTyp().imTranslateType(this);
1✔
971
            String name = varDef.getName();
1✔
972
            if (isNamedScopeVar(varDef)) {
1✔
973
                name = getNameFor(varDef.attrNearestNamedScope()) + "_" + name;
1✔
974
            }
975
            boolean isBj = isBJ(varDef.getSource());
1✔
976
            v = JassIm.ImVar(varDef, type, name, isBj);
1✔
977
            varMap.put(varDef, v);
1✔
978
        }
979
        return v;
1✔
980
    }
981

982
    private boolean isNamedScopeVar(VarDef varDef) {
983
        if (varDef.getParent() == null) {
1✔
984
            return false;
×
985
        }
986
        return varDef.getParent().getParent() instanceof NamedScope;
1✔
987
    }
988

989
    public WurstModel getWurstProg() {
990
        return wurstProg;
×
991
    }
992

993
    public ImProg imProg() {
994
        return imProg;
1✔
995
    }
996

997
    public boolean isTranslated(WPackage pack) {
998
        return translatedPackages.contains(pack);
1✔
999
    }
1000

1001
    public void setTranslated(WPackage pack) {
1002
        translatedPackages.add(pack);
1✔
1003
    }
1✔
1004

1005
    public boolean isTranslated(ClassDef c) {
1006
        return translatedClasses.contains(c);
1✔
1007
    }
1008

1009
    public void setTranslated(ClassDef c) {
1010
        translatedClasses.add(c);
1✔
1011
    }
1✔
1012

1013
    public List<ImStmt> translateStatements(ImFunction f, List<WStatement> statements) {
1014
        List<ImStmt> result = Lists.newArrayList();
1✔
1015
        for (WStatement s : statements) {
1✔
1016
            lasttranslatedThing = s;
1✔
1017
            ImStmt translated = s.imTranslateStmt(this, f);
1✔
1018
            result.add(translated);
1✔
1019
        }
1✔
1020
        return result;
1✔
1021
    }
1022

1023
    public void setMainFunc(ImFunction f) {
1024
        if (mainFunc != null) {
1✔
1025
            throw new Error("mainFunction already set");
×
1026
        }
1027
        mainFunc = f;
1✔
1028
    }
1✔
1029

1030
    public void setConfigFunc(ImFunction f) {
1031
        if (configFunc != null) {
1✔
1032
            throw new Error("configFunction already set");
×
1033
        }
1034
        configFunc = f;
1✔
1035
    }
1✔
1036

1037
    public Multimap<ImFunction, ImFunction> getCalledFunctions() {
1038
        if (callRelations == null) {
1✔
1039
            calculateCallRelationsAndUsedVariables();
×
1040
        }
1041
        return callRelations;
1✔
1042
    }
1043

1044
    public void calculateCallRelationsAndUsedVariables() {
1045
        callRelations = LinkedHashMultimap.create();
1✔
1046
        usedVariables = Sets.newLinkedHashSet();
1✔
1047
        readVariables = Sets.newLinkedHashSet();
1✔
1048
        usedFunctions = Sets.newLinkedHashSet();
1✔
1049
        calculateCallRelations(getMainFunc());
1✔
1050
        calculateCallRelations(getConfFunc());
1✔
1051

1052
//                WLogger.info("USED FUNCS:");
1053
//                for (ImFunction f : usedFunctions) {
1054
//                        WLogger.info("        " + f.getName());
1055
//                }
1056
        imProg.getGlobals().forEach(global -> {
1✔
1057
            if (TRVEHelper.protectedVariables.contains(global.getName())) {
1✔
1058
                getReadVariables().add(global);
1✔
1059
            }
1060
        });
1✔
1061
    }
1✔
1062

1063
    private void calculateCallRelations(ImFunction rootFunction) {
1064
        // Early return if rootFunction is already processed
1065
        if (getUsedFunctions().contains(rootFunction)) {
1✔
1066
            return;
×
1067
        }
1068

1069
        Stack<ImFunction> functionStack = new Stack<>();
1✔
1070
        functionStack.push(rootFunction);
1✔
1071

1072
        while (!functionStack.isEmpty()) {
1✔
1073
            ImFunction f = functionStack.pop();
1✔
1074

1075
            // If the function is already processed, skip the remaining logic
1076
            // in this iteration
1077
            if (getUsedFunctions().contains(f)) {
1✔
1078
                continue;
1✔
1079
            }
1080

1081
            getUsedFunctions().add(f);
1✔
1082
            getUsedVariables().addAll(f.calcUsedVariables());
1✔
1083
            getReadVariables().addAll(f.calcReadVariables());
1✔
1084

1085
            Set<ImFunction> calledFuncs = f.calcUsedFunctions();
1✔
1086
            for (ImFunction called : calledFuncs) {
1✔
1087
                if (f != called) { // ignore reflexive call relations
1✔
1088
                    getCallRelations().put(f, called);
1✔
1089
                }
1090
                functionStack.push(called);
1✔
1091
            }
1✔
1092
        }
1✔
1093
    }
1✔
1094

1095
    private Multimap<ImFunction, ImFunction> getCallRelations() {
1096
        return callRelations;
1✔
1097
    }
1098

1099

1100
    public ImFunction getMainFunc() {
1101
        return mainFunc;
1✔
1102
    }
1103

1104
    public ImFunction getConfFunc() {
1105
        return configFunc;
1✔
1106
    }
1107

1108

1109
    /**
1110
     * returns a list of classes and functions implementing funcDef
1111
     */
1112
    public Map<ClassDef, FuncDef> getClassesWithImplementation(Collection<ClassDef> instances, FuncDef func) {
1113
        if (func.attrIsPrivate()) {
1✔
1114
            // private functions cannot be overridden
1115
            return Collections.emptyMap();
1✔
1116
        }
1117
        Map<ClassDef, FuncDef> result = Maps.newLinkedHashMap();
1✔
1118
        for (ClassDef c : instances) {
1✔
1119
            FuncLink funcNameLink = null;
1✔
1120
            WurstTypeClass cType = c.attrTypC();
1✔
1121
            for (FuncLink nameLink : func.lookupMemberFuncs(cType, func.getName())) {
1✔
1122
                if (nameLink.getDef() == func) {
1✔
1123
                    funcNameLink = nameLink;
1✔
1124
                }
1125
            }
1✔
1126
            if (funcNameLink == null) {
1✔
1127
                throw new Error("Could not find "
×
1128
                    + Utils.printElementWithSource(Optional.of(func))
×
1129
                    + " in "
1130
                    + Utils.printElementWithSource(Optional.of(c)));
×
1131
            }
1132
            for (NameLink nameLink : c.attrNameLinks().get(func.getName())) {
1✔
1133
                NameDef nameDef = nameLink.getDef();
1✔
1134
                if (nameLink.getDefinedIn() == c) {
1✔
1135
                    if (nameLink instanceof FuncLink && nameLink.getDef() instanceof FuncDef) {
1✔
1136
                        FuncLink funcLink = (FuncLink) nameLink;
1✔
1137
                        FuncDef f = (FuncDef) funcLink.getDef();
1✔
1138
                        // check if function f overrides func
1139
                        if (WurstValidator.canOverride(funcLink, funcNameLink, false)) {
1✔
1140
                            result.put(c, f);
1✔
1141
                        }
1142
                    }
1143
                }
1144
            }
1✔
1145
        }
1✔
1146
        return result;
1✔
1147
    }
1148

1149

1150
    private Map<ClassDef, List<Pair<ImVar, VarInitialization>>> classDynamicInitMap = Maps.newLinkedHashMap();
1✔
1151
    private Map<ClassDef, List<WStatement>> classInitStatements = Maps.newLinkedHashMap();
1✔
1152

1153
    public List<Pair<ImVar, VarInitialization>> getDynamicInits(ClassDef c) {
1154
        return classDynamicInitMap.computeIfAbsent(c, k -> Lists.newArrayList());
1✔
1155
    }
1156

1157

1158
    private Map<ConstructorDef, ImFunction> constructorFuncs = Maps.newLinkedHashMap();
1✔
1159

1160
    public ImFunction getConstructFunc(ConstructorDef constr) {
1161
        ImFunction f = constructorFuncs.get(constr);
1✔
1162
        if (f == null) {
1✔
1163
            String name = constructorName(constr);
1✔
1164
            ImVars params = ImVars(getThisVar(constr));
1✔
1165
            for (WParameter p : constr.getParameters()) {
1✔
1166
                params.add(getVarFor(p));
1✔
1167
            }
1✔
1168

1169
            f = ImFunction(constr, name, ImTypeVars(), params, ImVoid(), ImVars(), ImStmts(), flags());
1✔
1170
            addFunction(f, constr);
1✔
1171
            constructorFuncs.put(constr, f);
1✔
1172
        }
1173
        return f;
1✔
1174
    }
1175

1176

1177
    private String constructorName(ConstructorDef constr) {
1178
        ArrayDeque<String> names = new ArrayDeque<>();
1✔
1179
        de.peeeq.wurstscript.ast.Element e = constr;
1✔
1180
        while (e != null) {
1✔
1181
            if (e instanceof ClassOrModuleInstanciation) {
1✔
1182
                ClassOrModuleInstanciation mi = (ClassOrModuleInstanciation) e;
1✔
1183
                int index = mi.getConstructors().indexOf(constr);
1✔
1184
                names.addFirst(mi.getName() + (index > 0 ? 1 + index : ""));
1✔
1185
                if (e instanceof ClassDef) {
1✔
1186
                    break;
1✔
1187
                }
1188
            }
1189
            e = e.getParent();
1✔
1190
        }
1191
        return "construct_" + String.join("_", names);
1✔
1192
    }
1193

1194

1195
    Map<ConstructorDef, ImFunction> constrNewFuncs = Maps.newLinkedHashMap();
1✔
1196

1197
    public ImFunction getConstructNewFunc(ConstructorDef constr) {
1198
        ImFunction f = constrNewFuncs.get(constr);
1✔
1199
        if (f == null) {
1✔
1200
            String name = "new_" + constr.attrNearestClassDef().getName();
1✔
1201

1202
            f = ImFunction(constr, name, ImTypeVars(), ImVars(), selfType(constr.attrNearestClassOrInterface()), ImVars(), ImStmts(), flags());
1✔
1203
            addFunction(f, constr);
1✔
1204
            constrNewFuncs.put(constr, f);
1✔
1205
        }
1206
        return f;
1✔
1207
    }
1208

1209
    public ImProg getImProg() {
1210
        return imProg;
1✔
1211
    }
1212

1213

1214
    private Multimap<InterfaceDef, ClassDef> interfaceInstances = null;
1✔
1215

1216
    public Collection<ClassDef> getInterfaceInstances(InterfaceDef interfaceDef) {
1217
        if (interfaceInstances == null) {
1✔
1218
            calculateInterfaceInstances();
1✔
1219
        }
1220
        return interfaceInstances.get(interfaceDef);
1✔
1221
    }
1222

1223
    private void calculateInterfaceInstances() {
1224
        interfaceInstances = HashMultimap.create();
1✔
1225
        for (CompilationUnit cu : wurstProg) {
1✔
1226
            for (ClassDef c : cu.attrGetByType().classes) {
1✔
1227
                for (WurstTypeInterface i : c.attrTypC().transitiveSuperInterfaces()) {
1✔
1228
                    interfaceInstances.put(i.getDef(), c);
1✔
1229
                }
1✔
1230
            }
1✔
1231
        }
1✔
1232
    }
1✔
1233

1234

1235
    private TransitiveClosure<ClassDef> subclasses = null;
1✔
1236
    private Multimap<ClassDef, ClassDef> directSubclasses = null;
1✔
1237

1238
    private boolean isEclipseMode = false;
1✔
1239

1240
    public List<ClassDef> getSubClasses(ClassDef classDef) {
1241
        calculateSubclasses();
1✔
1242
        return subclasses.getAsList(classDef);
1✔
1243
    }
1244

1245
    private void calculateSubclasses() {
1246
        if (subclasses != null) {
1✔
1247
            return;
1✔
1248
        }
1249
        calculateDirectSubclasses();
1✔
1250
        subclasses = new TransitiveClosure<>(directSubclasses);
1✔
1251
    }
1✔
1252

1253

1254
    private void calculateDirectSubclasses() {
1255
        if (directSubclasses != null) {
1✔
1256
            return;
×
1257
        }
1258
        directSubclasses = HashMultimap.create();
1✔
1259
        for (ClassDef c : classes()) {
1✔
1260
            WurstTypeClass extendedClass = c.attrTypC().extendedClass();
1✔
1261
            if (extendedClass != null) {
1✔
1262
                directSubclasses.put(extendedClass.getDef(), c);
1✔
1263
            }
1264
        }
1✔
1265
    }
1✔
1266

1267
    /**
1268
     * calculates list of all classes
1269
     * ignoring the ones in modules, only module instantiations
1270
     */
1271
    private List<ClassDef> classes() {
1272
        List<ClassDef> result = new ArrayList<>();
1✔
1273
        for (CompilationUnit cu : wurstProg) {
1✔
1274
            for (WPackage p : cu.getPackages()) {
1✔
1275
                for (WEntity e : p.getElements()) {
1✔
1276
                    if (e instanceof ClassDef) {
1✔
1277
                        ClassDef c = (ClassDef) e;
1✔
1278
                        classesAdd(result, c);
1✔
1279
                    }
1280
                }
1✔
1281
            }
1✔
1282
        }
1✔
1283
        return result;
1✔
1284

1285
    }
1286

1287
    private void classesAdd(List<ClassDef> result, ClassOrModuleInstanciation c) {
1288
        if (c instanceof ClassDef) {
1✔
1289
            result.add(((ClassDef) c));
1✔
1290
        }
1291
        for (ClassDef ic : c.getInnerClasses()) {
1✔
1292
            classesAdd(result, ic);
1✔
1293
        }
1✔
1294
        for (ModuleInstanciation mi : c.getModuleInstanciations()) {
1✔
1295
            classesAdd(result, mi);
1✔
1296
        }
1✔
1297
    }
1✔
1298

1299
    public int getEnumMemberId(EnumMember enumMember) {
1300
        return ((EnumMembers) enumMember.getParent()).indexOf(enumMember);
1✔
1301
    }
1302

1303
    private ImFunction getDebugPrintFunction() {
1304
        return debugPrintFunction;
1✔
1305
    }
1306

1307
    public boolean isEclipseMode() {
1308
        return isEclipseMode;
1✔
1309
    }
1310

1311
    public void setEclipseMode(boolean enabled) {
1312
        isEclipseMode = enabled;
×
1313
    }
×
1314

1315
    public TypeParamDef getTypeParamDef(ImTypeVar tv) {
1316
        return typeVariableReverse.get(tv);
1✔
1317
    }
1318

1319
    public ImTypeVar getTypeVar(TypeParamDef tv) {
1320
        return typeVariable.getFor(tv);
1✔
1321
    }
1322

1323
    public boolean isLuaTarget() {
1324
        return runArgs.isLua();
1✔
1325
    }
1326

1327
    interface VarsForTupleResult {
1328

1329
        default Iterable<ImVar> allValues() {
1330
            return allValuesStream()::iterator;
1✔
1331
        }
1332

1333
        Stream<ImVar> allValuesStream();
1334

1335
        <T> T map(Function<Stream<T>, T> nodeBuilder, Function<ImVar, T> leafBuilder);
1336
    }
1337

1338
    static class SingleVarResult implements VarsForTupleResult {
1339
        private final ImVar var;
1340

1341
        public SingleVarResult(ImVar var) {
1✔
1342
            this.var = var;
1✔
1343
        }
1✔
1344

1345
        public ImVar getVar() {
1346
            return var;
×
1347
        }
1348

1349
        @Override
1350
        public Stream<ImVar> allValuesStream() {
1351
            return Stream.of(var);
1✔
1352
        }
1353

1354
        @Override
1355
        public <T> T map(Function<Stream<T>, T> nodeBuilder, Function<ImVar, T> leafBuilder) {
1356
            return leafBuilder.apply(var);
1✔
1357
        }
1358

1359
        @Override
1360
        public String toString() {
1361
            return var.toString();
×
1362
        }
1363
    }
1364

1365
    static class TupleResult implements VarsForTupleResult {
1366
        private final List<VarsForTupleResult> items;
1367

1368
        public TupleResult(List<VarsForTupleResult> items) {
1✔
1369
            this.items = items;
1✔
1370
        }
1✔
1371

1372
        public List<VarsForTupleResult> getItems() {
1373
            return items;
×
1374
        }
1375

1376
        @Override
1377
        public Stream<ImVar> allValuesStream() {
1378
            return items.stream().flatMap(VarsForTupleResult::allValuesStream);
1✔
1379
        }
1380

1381
        @Override
1382
        public <T> T map(Function<Stream<T>, T> nodeBuilder, Function<ImVar, T> leafBuilder) {
1383
            return nodeBuilder.apply(items.stream().map(e -> e.map(nodeBuilder, leafBuilder)));
1✔
1384
        }
1385

1386
        @Override
1387
        public String toString() {
1388
            return "<" + Utils.printSep(", ", items) + ">";
×
1389
        }
1390
    }
1391

1392
    public VarsForTupleResult getVarsForTuple(ImVar v) {
1393
        // TODO use list instead of tree
1394
        VarsForTupleResult result = varsForTupleVar.get(v);
1✔
1395
        if (result == null) {
1✔
1396
            if (TypesHelper.typeContainsTuples(v.getType())) {
1✔
1397
                result = createVarsForType(v.getName(), v.getType(), Function.identity(), v.getTrace());
1✔
1398
            } else {
1399
                result = new SingleVarResult(v);
×
1400
            }
1401
            varsForTupleVar.put(v, result);
1✔
1402
        }
1403
        return result;
1✔
1404
    }
1405

1406

1407
    /**
1408
     * Creates variables for the given type, eliminating tuple types
1409
     *
1410
     * @param name            base name for the variables
1411
     * @param type            the type for which to create variables
1412
     * @param typeConstructor how the types are constructed (creating an array or multi-array, just returning the type)
1413
     * @param tr              trace for the variables
1414
     * @return
1415
     */
1416
    private VarsForTupleResult createVarsForType(String name, final ImType type, Function<ImType, ImType> typeConstructor, de.peeeq.wurstscript.ast.Element tr) {
1417
        return type.match(new ImType.Matcher<VarsForTupleResult>() {
1✔
1418
            @Override
1419
            public VarsForTupleResult case_ImArrayType(ImArrayType at) {
1420
                if (at.getEntryType() instanceof ImTupleType) {
1✔
1421
                    // if it is an array of tuples, create multiple array variables:
1422
                    ImTupleType tt = (ImTupleType) at.getEntryType();
1✔
1423
                    Builder<VarsForTupleResult> ts = ImmutableList.builder();
1✔
1424
                    int i = 0;
1✔
1425
                    for (ImType t : tt.getTypes()) {
1✔
1426
                        ts.add(createVarsForType(name + "_" + tt.getNames().get(i), t, JassIm::ImArrayType, tr));
1✔
1427
                        i++;
1✔
1428
                    }
1✔
1429
                    return new TupleResult(ts.build());
1✔
1430
                }
1431
                // otherwise just create the array variable
1432
                return new SingleVarResult(JassIm.ImVar(tr, type, name, false));
×
1433
            }
1434

1435
            @Override
1436
            public VarsForTupleResult case_ImTypeVarRef(ImTypeVarRef imTypeVarRef) {
1437
                throw new RuntimeException("Should be called after eliminating generics.");
×
1438
            }
1439

1440
            @Override
1441
            public VarsForTupleResult case_ImArrayTypeMulti(ImArrayTypeMulti at) {
1442
                if (at.getEntryType() instanceof ImTupleType) {
1✔
1443
                    // if it is an array of tuples, create multiple array variables:
1444
                    ImTupleType tt = (ImTupleType) at.getEntryType();
1✔
1445
                    Builder<VarsForTupleResult> ts = ImmutableList.builder();
1✔
1446
                    int i = 0;
1✔
1447
                    for (ImType t : tt.getTypes()) {
1✔
1448
                        ts.add(createVarsForType(name + "_" + tt.getNames().get(i), t, et -> JassIm.ImArrayTypeMulti(et, new ArrayList<>(at.getArraySize())), tr));
1✔
1449
                        i++;
1✔
1450
                    }
1✔
1451
                    return new TupleResult(ts.build());
1✔
1452
                }
1453
                // otherwise just create the array variable
1454
                return new SingleVarResult(JassIm.ImVar(tr, type, name, false));
×
1455
            }
1456

1457
            @Override
1458
            public VarsForTupleResult case_ImVoid(ImVoid imVoid) {
1459
                return new TupleResult(Collections.emptyList());
×
1460
            }
1461

1462
            @Override
1463
            public VarsForTupleResult case_ImClassType(ImClassType st) {
1464
                ImType type = typeConstructor.apply(st);
×
1465
                return new SingleVarResult(JassIm.ImVar(tr, type, name, false));
×
1466
            }
1467

1468
            @Override
1469
            public VarsForTupleResult case_ImSimpleType(ImSimpleType st) {
1470
                ImType type = typeConstructor.apply(st);
1✔
1471
                return new SingleVarResult(JassIm.ImVar(tr, type, name, false));
1✔
1472
            }
1473

1474
            @Override
1475
            public VarsForTupleResult case_ImAnyType(ImAnyType at) {
1476
                ImType type = typeConstructor.apply(at);
×
1477
                return new SingleVarResult(JassIm.ImVar(tr, type, name, false));
×
1478
            }
1479

1480
            @Override
1481
            public VarsForTupleResult case_ImTupleType(ImTupleType tt) {
1482
                int i = 0;
1✔
1483
                Builder<VarsForTupleResult> ts = ImmutableList.builder();
1✔
1484
                for (ImType t : tt.getTypes()) {
1✔
1485
                    ts.add(createVarsForType(name + "_" + tt.getNames().get(i), t, typeConstructor, tr));
1✔
1486
                    i++;
1✔
1487
                }
1✔
1488
                return new TupleResult(ts.build());
1✔
1489
            }
1490
        });
1491
    }
1492

1493

1494
    private void addVarsForType(List<ImVar> result, String name, ImType type, de.peeeq.wurstscript.ast.Element tr) {
1495
        Preconditions.checkNotNull(type);
×
1496
        Preconditions.checkNotNull(result);
×
1497
        // TODO handle names
1498
        if (type instanceof ImTupleType) {
×
1499
            ImTupleType tt = (ImTupleType) type;
×
1500
            int i = 0;
×
1501
            for (ImType t : tt.getTypes()) {
×
1502
                addVarsForType(result, name + "_" + tt.getNames().get(i), t, tr);
×
1503
                i++;
×
1504
            }
×
1505
        } else if (type instanceof ImVoid) {
×
1506
            // nothing to add
1507
        } else {
1508
            result.add(JassIm.ImVar(tr, type, name, false));
×
1509
        }
1510

1511
    }
×
1512

1513
    private Map<ImFunction, VarsForTupleResult> tempReturnVars = Maps.newLinkedHashMap();
1✔
1514

1515
    public VarsForTupleResult getTupleTempReturnVarsFor(ImFunction f) {
1516
        VarsForTupleResult result = tempReturnVars.get(f);
1✔
1517
        if (result == null) {
1✔
1518
            result = createVarsForType(f.getName() + "_return", getOriginalReturnValue(f), Function.identity(), f.getTrace());
1✔
1519
            for (ImVar value : result.allValues()) {
1✔
1520
                imProg.getGlobals().add(value);
1✔
1521
            }
1✔
1522
            tempReturnVars.put(f, result);
1✔
1523
        }
1524
        return result;
1✔
1525
    }
1526

1527
    private Map<ImFunction, ImType> originalReturnValues = Maps.newLinkedHashMap();
1✔
1528

1529

1530
    public void setOriginalReturnValue(ImFunction f, ImType t) {
1531
        originalReturnValues.put(f, t);
1✔
1532
    }
1✔
1533

1534
    public ImType getOriginalReturnValue(ImFunction f) {
1535
        return originalReturnValues.computeIfAbsent(f, ImFunction::getReturnType);
1✔
1536
    }
1537

1538
    public void assertProperties(AssertProperty... properties1) {
1539
        if (!debug) {
1✔
1540
            return;
1✔
1541
        }
1542
        final Set<AssertProperty> properties = Sets.newHashSet(properties1);
×
1543
        assertProperties(properties, imProg);
×
1544
    }
×
1545

1546
    public void assertProperties(Set<AssertProperty> properties, Element e) {
1547
        if (e instanceof ElementWithVar) {
1✔
1548
            checkVar(((ElementWithVar) e).getVar(), properties);
1✔
1549
        }
1550
        properties.forEach(p -> p.check(e));
1✔
1551
        if (properties.contains(AssertProperty.NOTUPLES)) {
1✔
1552

1553
        }
1554
        if (properties.contains(AssertProperty.FLAT)) {
1✔
1555

1556
        }
1557
        for (int i = 0; i < e.size(); i++) {
1✔
1558
            Element child = e.get(i);
1✔
1559
            if (child.getParent() == null) {
1✔
1560
                throw new Error("Child " + i + " (" + child + ") of " + e + " not attached to tree");
×
1561
            } else if (child.getParent() != e) {
1✔
1562
                throw new Error("Child " + i + " (" + child + ") of " + e + " attached to wrong tree");
×
1563
            }
1564
            assertProperties(properties, child);
1✔
1565
        }
1566
    }
1✔
1567

1568
    private void checkVar(ImVar left, Set<AssertProperty> properties) {
1569
        if (left.getParent() == null) {
1✔
1570
            throw new Error("var not attached: " + left);
×
1571
        }
1572
        if (properties.contains(AssertProperty.NOTUPLES)) {
1✔
1573
            if (TypesHelper.typeContainsTuples(left.getType())) {
×
1574
                throw new Error("program contains tuple var " + left);
×
1575
            }
1576
        }
1577
    }
1✔
1578

1579
    public Set<ImVar> getUsedVariables() {
1580
        if (usedVariables == null) {
1✔
1581
            calculateCallRelationsAndUsedVariables();
×
1582
        }
1583
        return usedVariables;
1✔
1584
    }
1585

1586
    public Set<ImVar> getReadVariables() {
1587
        if (readVariables == null) {
1✔
1588
            calculateCallRelationsAndUsedVariables();
×
1589
        }
1590
        return readVariables;
1✔
1591
    }
1592

1593
    public Set<ImFunction> getUsedFunctions() {
1594
        if (usedFunctions == null) {
1✔
1595
            calculateCallRelationsAndUsedVariables();
×
1596
        }
1597
        return usedFunctions;
1✔
1598
    }
1599

1600
    public boolean isUnitTestMode() {
1601
        return isUnitTestMode;
1✔
1602
    }
1603

1604
    private Map<ExprClosure, ImClass> classForClosure = Maps.newLinkedHashMap();
1✔
1605

1606
    public ImClass getClassForClosure(ExprClosure s) {
1607
        Preconditions.checkNotNull(s);
1✔
1608
        return classForClosure.computeIfAbsent(s, s1 -> JassIm.ImClass(s1, "Closure", JassIm.ImTypeVars(), JassIm.ImVars(), JassIm.ImMethods(), JassIm.ImFunctions(), Lists.newArrayList()));
1✔
1609
    }
1610

1611

1612
    private Map<ClassOrInterface, @Nullable ImClass> classForStructureDef = Maps.newLinkedHashMap();
1✔
1613

1614
    public ImClass getClassFor(ClassOrInterface s) {
1615
        Preconditions.checkNotNull(s);
1✔
1616
        return classForStructureDef.computeIfAbsent(s, s1 -> {
1✔
1617
            ImTypeVars typeVariables = JassIm.ImTypeVars();
1✔
1618
            if (s instanceof AstElementWithTypeParameters) {
1✔
1619
                for (TypeParamDef tp : ((AstElementWithTypeParameters) s).getTypeParameters()) {
1✔
1620
                    if (tp.getTypeParamConstraints() instanceof TypeExprList) {
1✔
1621
                        ImTypeVar tv = getTypeVar(tp);
1✔
1622
                        typeVariables.add(tv);
1✔
1623
                    }
1624
                }
1✔
1625
            }
1626

1627
            return JassIm.ImClass(s1, s1.getName(), typeVariables, JassIm.ImVars(), JassIm.ImMethods(), JassIm.ImFunctions(), Lists.newArrayList());
1✔
1628
        });
1629
    }
1630

1631

1632
    Map<FuncDef, ImMethod> methodForFuncDef = Maps.newLinkedHashMap();
1✔
1633

1634
    public ImMethod getMethodFor(FuncDef f) {
1635
        ImMethod m = methodForFuncDef.get(f);
1✔
1636
        if (m == null) {
1✔
1637
            ImFunction imFunc = getFuncFor(f);
1✔
1638
            m = JassIm.ImMethod(f, selfType(f), elementNameWithPath(f), imFunc, Lists.<ImMethod>newArrayList(), false);
1✔
1639
            methodForFuncDef.put(f, m);
1✔
1640
        }
1641
        return m;
1✔
1642
    }
1643

1644
    public ClassManagementVars getClassManagementVarsFor(ImClass c) {
1645
        return getClassManagementVars().get(c);
1✔
1646
    }
1647

1648

1649
    private Map<ImClass, ClassManagementVars> classManagementVars = null;
1✔
1650

1651
    private @Nullable ImFunction errorFunc;
1652

1653
    public Map<ImClass, ClassManagementVars> getClassManagementVars() {
1654
        if (classManagementVars != null) {
1✔
1655
            return classManagementVars;
1✔
1656
        }
1657
        // create partitions, such that each sub-class and super-class are in
1658
        // the same partition
1659
        Partitions<ImClass> p = new Partitions<>();
1✔
1660
        for (ImClass c : imProg.getClasses()) {
1✔
1661
            p.add(c);
1✔
1662
            for (ImClassType sc : c.getSuperClasses()) {
1✔
1663
                p.union(c, sc.getClassDef());
1✔
1664
            }
1✔
1665
        }
1✔
1666
        // generate typeId variables
1667
        classManagementVars = Maps.newLinkedHashMap();
1✔
1668
        for (ImClass c : imProg.getClasses()) {
1✔
1669
            ImClass rep = p.getRep(c);
1✔
1670
            ClassManagementVars v = classManagementVars.computeIfAbsent(rep, r -> new ClassManagementVars(r, this));
1✔
1671
            classManagementVars.put(c, v);
1✔
1672
        }
1✔
1673
        return classManagementVars;
1✔
1674
    }
1675

1676

1677
    public ImFunction getGlobalInitFunc() {
1678
        return globalInitFunc;
1✔
1679
    }
1680

1681

1682
    public ImFunctionCall imError(de.peeeq.wurstscript.ast.Element trace, ImExpr message) {
1683
        ImFunction ef = errorFunc;
1✔
1684
        if (ef == null) {
1✔
1685
            Optional<ImFunction> f = findErrorFunc().map(this::getFuncFor);
1✔
1686
            ef = errorFunc = f.orElseGet(this::makeDefaultErrorFunc);
1✔
1687
        }
1688
        ImExprs arguments = JassIm.ImExprs(message);
1✔
1689
        return ImFunctionCall(trace, ef, ImTypeArguments(), arguments, false, CallType.NORMAL);
1✔
1690
    }
1691

1692
    private ImFunction makeDefaultErrorFunc() {
1693
        ImVar msgVar = JassIm.ImVar(emptyTrace, TypesHelper.imString(), "msg", false);
1✔
1694
        ImVars parameters = JassIm.ImVars(msgVar);
1✔
1695
        ImType returnType = JassIm.ImVoid();
1✔
1696
        ImVars locals = JassIm.ImVars();
1✔
1697
        ImStmts body = JassIm.ImStmts();
1✔
1698

1699
        // print message:
1700
        // msg = msg + stacktrace
1701
        ImExpr msg = JassIm.ImOperatorCall(WurstOperator.PLUS, ImExprs(JassIm.ImVarAccess(msgVar),
1✔
1702
            JassIm.ImOperatorCall(WurstOperator.PLUS,
1✔
1703
                ImExprs(
1✔
1704
                    JassIm.ImStringVal("\n"),
1✔
1705
                    JassIm.ImGetStackTrace()))));
1✔
1706

1707
        body.add(ImFunctionCall(emptyTrace, getDebugPrintFunction(), ImTypeArguments(), JassIm.ImExprs(msg), false, CallType.NORMAL));
1✔
1708
        // TODO divide by zero to crash thread:
1709

1710

1711
//                stmts.add(JassAst.JassStmtCall("BJDebugMsg",
1712
//                                JassAst.JassExprlist(JassAst.JassExprBinary(
1713
//                                                JassAst.JassExprStringVal("|cffFF3A29Wurst Error:|r" + nl),
1714
//                                                JassAst.JassOpPlus(),
1715
//                                                s.getMessage().translate(translator)))));
1716
//                // crash thread (divide by zero)
1717
//                stmts.add(JassAst.JassStmtCall("I2S", JassAst.JassExprlist(JassAst.JassExprBinary(JassAst.JassExprIntVal("1"), JassAst.JassOpDiv(), Jas
1718
//
1719

1720
        List<FunctionFlag> flags = Lists.newArrayList();
1✔
1721

1722
        ImFunction errorFunc = ImFunction(emptyTrace, "error", ImTypeVars(), parameters, returnType, locals, body, flags);
1✔
1723
        imProg.getFunctions().add(errorFunc);
1✔
1724
        return errorFunc;
1✔
1725
    }
1726

1727

1728
    private Optional<FuncDef> findErrorFunc() throws CompileError {
1729
        PackageLink p = wurstProg.lookupPackage("ErrorHandling");
1✔
1730
        if (p == null) {
1✔
1731
            return Optional.empty();
1✔
1732
        }
1733
        ImmutableCollection<FuncLink> funcs = p.getDef().getElements().lookupFuncs("error");
1✔
1734
        if (funcs.isEmpty()) {
1✔
1735
            return Optional.empty();
×
1736
        } else if (funcs.size() > 1) {
1✔
1737
            return Optional.empty();
×
1738
        }
1739
        FuncDef f = (FuncDef) funcs.stream().findAny().get().getDef();
1✔
1740
        return Optional.of(f);
1✔
1741
    }
1742

1743
    int getCompiletimeExpressionsOrder(FunctionCall fc) {
1744
        return compiletimeExpressionsOrder.getOrDefault(fc, 0);
1✔
1745
    }
1746

1747
    public RunArgs getRunArgs() {
1748
        return runArgs;
1✔
1749
    }
1750
}
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