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

wurstscript / WurstScript / 271

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

Pull #1096

circleci

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

18202 of 28155 relevant lines covered (64.65%)

0.65 hits per line

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

94.42
de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ClassTranslator.java
1
package de.peeeq.wurstscript.translation.imtranslation;
2

3
import de.peeeq.wurstscript.ast.*;
4
import de.peeeq.wurstscript.ast.Element;
5
import de.peeeq.wurstscript.jassIm.Element.DefaultVisitor;
6
import de.peeeq.wurstscript.jassIm.*;
7
import de.peeeq.wurstscript.types.*;
8
import de.peeeq.wurstscript.utils.Pair;
9

10
import java.util.Collections;
11
import java.util.List;
12
import java.util.Map;
13
import java.util.Map.Entry;
14
import java.util.stream.Collectors;
15

16
import static de.peeeq.wurstscript.attributes.SmallHelpers.superArgs;
17
import static de.peeeq.wurstscript.jassIm.JassIm.*;
18

19
public class ClassTranslator {
1✔
20

21
    private final ClassDef classDef;
22
    private final ImTranslator translator;
23
    //        /** list of statements to initialize a new object **/
24
    final private List<Pair<ImVar, VarInitialization>> dynamicInits;
25
    private ImClass imClass;
26
    private final ImProg prog;
27
    private ImFunction classInitFunc;
28

29
    public ClassTranslator(ClassDef classDef, ImTranslator translator) {
1✔
30
        this.classDef = classDef;
1✔
31
        this.translator = translator;
1✔
32
        this.prog = translator.getImProg();
1✔
33
//                initStatements = translator.getInitStatement(classDef);
34
        dynamicInits = translator.getDynamicInits(classDef);
1✔
35
    }
1✔
36

37
    public static void translate(ClassDef classDef, ImTranslator translator) {
38
        new ClassTranslator(classDef, translator).translate();
1✔
39

40
        // translate inner classes:
41
        translateInnerClasses(classDef, translator);
1✔
42
    }
1✔
43

44
    private static void translateInnerClasses(ClassOrModuleOrModuleInstanciation mi, ImTranslator translator) {
45
        for (ModuleInstanciation mi2 : mi.getModuleInstanciations()) {
1✔
46
            translateInnerClasses(mi2, translator);
1✔
47
        }
1✔
48
        for (ClassDef innerClass : mi.getInnerClasses()) {
1✔
49
            translate(innerClass, translator);
1✔
50
        }
1✔
51
    }
1✔
52

53
    /**
54
     * translates the given classDef
55
     */
56
    private void translate() {
57
        imClass = translator.getClassFor(classDef);
1✔
58
        prog.getClasses().add(imClass);
1✔
59

60
        addSuperClasses();
1✔
61

62
        List<ClassDef> subClasses = translator.getSubClasses(classDef);
1✔
63

64
        // order is important here
65
        translateMethods(classDef, subClasses);
1✔
66
        translateVars(classDef);
1✔
67
        translateClassInitFunc();
1✔
68
        translateConstructors();
1✔
69
        createOnDestroyMethod();
1✔
70
        createDestroyMethod(subClasses);
1✔
71

72
    }
1✔
73

74

75

76
    private void addSuperClasses() {
77
        if (classDef.getExtendedClass() instanceof TypeExpr) {
1✔
78
            TypeExpr extended = (TypeExpr) classDef.getExtendedClass();
1✔
79
            addSuperClass(extended);
1✔
80
        }
81
        for (TypeExpr impl : classDef.getImplementsList()) {
1✔
82
            addSuperClass(impl);
1✔
83
        }
1✔
84

85
    }
1✔
86

87
    private void addSuperClass(TypeExpr extended) {
88
        imClass.getSuperClasses().add((ImClassType) extended.attrTyp().imTranslateType(translator));
1✔
89
    }
1✔
90

91
    private void createDestroyMethod(List<ClassDef> subClasses) {
92
        ImMethod m = translator.destroyMethod.getFor(classDef);
1✔
93
        imClass.getMethods().add(m);
1✔
94
        ImFunction f = translator.destroyFunc.getFor(classDef);
1✔
95

96
        // set sub methods
97
        for (ClassDef sc : subClasses) {
1✔
98
            ImMethod dm = translator.destroyMethod.getFor(sc);
1✔
99
            if (hasOwnDestroy(sc, classDef)) {
1✔
100
                m.getSubMethods().add(dm);
1✔
101
            }
102
        }
1✔
103

104
        Element trace = classDef.getOnDestroy();
1✔
105

106
        ImVar thisVar = f.getParameters().get(0);
1✔
107

108
        // call ondestroy methods
109
        ClassDef c = classDef;
1✔
110
        ImFunction scOnDestroy = translator.getFuncFor(c.getOnDestroy());
1✔
111
        f.getBody().add(ImFunctionCall(trace, scOnDestroy, ImTypeArguments(), ImExprs(ImVarAccess(thisVar)), false, CallType.NORMAL));
1✔
112

113
        // deallocate
114
        f.getBody().add(JassIm.ImDealloc(c.getOnDestroy(), imClassType(), JassIm.ImVarAccess(thisVar)));
1✔
115
    }
1✔
116

117
    private ImClassType imClassType() {
118
        ImTypeArguments typeArgs = imClass.getTypeVariables().stream()
1✔
119
                .map(tv -> JassIm.ImTypeArgument(JassIm.ImTypeVarRef(tv), Collections.emptyMap()))
1✔
120
                .collect(Collectors.toCollection(JassIm::ImTypeArguments));
1✔
121
        return JassIm.ImClassType(imClass, typeArgs);
1✔
122
    }
123

124
    /**
125
     *
126
     */
127
    private boolean hasOwnDestroy(ClassDef sc, ClassDef classDef2) {
128
        if (sc == classDef2) {
1✔
129
            return false;
1✔
130
        }
131
        if (sc.getOnDestroy().attrHasEmptyBody()) {
1✔
132
            WurstTypeClass superClass = (WurstTypeClass) sc.getExtendedClass().attrTyp();
1✔
133
            if (hasOwnDestroy(superClass.getClassDef(), classDef2)) {
1✔
134
                return true;
1✔
135
            }
136
            for (ModuleInstanciation mi : sc.getModuleInstanciations()) {
1✔
137
                if (hasOwnDestroy(mi)) {
1✔
138
                    return true;
1✔
139
                }
140
            }
1✔
141
            return false;
1✔
142
        } else {
143
            return true;
1✔
144
        }
145
    }
146

147
    private boolean hasOwnDestroy(ModuleInstanciation mi) {
148
        if (!mi.getOnDestroy().attrHasEmptyBody()) {
1✔
149
            return true;
1✔
150
        }
151
        for (ModuleInstanciation subMod : mi.getModuleInstanciations()) {
1✔
152
            if (hasOwnDestroy(subMod)) {
×
153
                return true;
×
154
            }
155
        }
×
156
        return false;
1✔
157
    }
158

159
    private void createOnDestroyMethod() {
160
        OnDestroyDef onDestroy = classDef.getOnDestroy();
1✔
161
        ImFunction f = translator.getFuncFor(onDestroy);
1✔
162
        addOnDestroyActions(f, f.getBody(), classDef, translator.getThisVar(onDestroy));
1✔
163
    }
1✔
164

165
    private void addOnDestroyActions(ImFunction f, List<ImStmt> addTo, ClassOrModuleInstanciation c, ImVar thisVar) {
166
        // translate ondestroy statements
167
        List<ImStmt> stmts = translator.translateStatements(f, c.getOnDestroy().getBody());
1✔
168
        replaceThisExpr(stmts, translator.getThisVar(c.getOnDestroy()), thisVar);
1✔
169
        addTo.addAll(stmts);
1✔
170

171
        // add onDestroy actions from modules
172
        for (ModuleInstanciation mi : c.getModuleInstanciations()) {
1✔
173
            addOnDestroyActions(f, addTo, mi, thisVar);
1✔
174
        }
1✔
175

176
        if (c instanceof ClassDef) {
1✔
177
            ClassDef cd = (ClassDef) c;
1✔
178
            WurstTypeClass ct = cd.attrTypC();
1✔
179
            WurstTypeClass extended = ct.extendedClass();
1✔
180
            if (extended != null) {
1✔
181
                // call onDestroy of super class
182
                ImFunction onDestroy = translator.getFuncFor(extended.getClassDef().getOnDestroy());
1✔
183
                ImTypeArguments typeArgs = ImTypeArguments();
1✔
184
                for (WurstTypeBoundTypeParam tp : extended.getTypeParameters()) {
1✔
185
                    if (tp.isTemplateTypeParameter()) {
1✔
186
                        typeArgs.add(tp.imTranslateToTypeArgument(translator));
1✔
187
                    }
188
                }
1✔
189
                addTo.add(ImFunctionCall(c, onDestroy, typeArgs, ImExprs(ImVarAccess(thisVar)), false, CallType.NORMAL));
1✔
190
            }
191
        }
192
    }
1✔
193

194
    private void replaceThisExpr(List<ImStmt> stmts, final ImVar oldThis, final ImVar newThis) {
195
        if (oldThis == newThis) {
1✔
196
            return;
1✔
197
        }
198
        DefaultVisitor replacer = new DefaultVisitor() {
×
199
            @Override
200
            public void visit(ImVarAccess v) {
201
                super.visit(v);
×
202
                if (v.getVar() == oldThis) {
×
203
                    v.setVar(newThis);
×
204
                }
205
            }
×
206

207
        };
208
        for (ImStmt s : stmts) {
×
209
            s.accept(replacer);
×
210
        }
×
211

212
    }
×
213

214
    private void translateConstructors() {
215
        // translate constructors of module instantiations:
216
        for (ModuleInstanciation mi : classDef.getModuleInstanciations()) {
1✔
217
            translateModuleConstructors(mi);
1✔
218
        }
1✔
219

220
        for (ConstructorDef c : classDef.getConstructors()) {
1✔
221
            translateConstructor(c);
1✔
222
        }
1✔
223

224
    }
1✔
225

226

227
    private void translateModuleConstructors(ModuleInstanciation mi) {
228
        for (ModuleInstanciation child : mi.getModuleInstanciations()) {
1✔
229
            translateModuleConstructors(child);
1✔
230
        }
1✔
231

232
        for (ConstructorDef c : mi.getConstructors()) {
1✔
233
            translateModuleConstructor(c, mi);
1✔
234
        }
1✔
235
    }
1✔
236

237

238
    private void translateVars(ClassOrModuleInstanciation c) {
239
        for (ModuleInstanciation mi : c.getModuleInstanciations()) {
1✔
240
            translateVars(mi);
1✔
241
        }
1✔
242
        for (GlobalVarDef v : c.getVars()) {
1✔
243
            translateVar(v);
1✔
244
        }
1✔
245
    }
1✔
246

247
    private void translateVar(GlobalVarDef s) {
248
        ImVar v = translator.getVarFor(s);
1✔
249
        if (s.attrIsDynamicClassMember()) {
1✔
250
            // add dynamic class members to the class
251
            imClass.getFields().add(v);
1✔
252
            dynamicInits.add(Pair.create(v, s.getInitialExpr()));
1✔
253
        } else { // static class member
254
            translator.addGlobalInitalizer(v, classDef.attrNearestPackage(), s.getInitialExpr());
1✔
255
            translator.addGlobal(v);
1✔
256
        }
257
    }
1✔
258

259
    private void translateMethods(ClassOrModuleInstanciation c, List<ClassDef> subClasses) {
260
        for (FuncDef f : c.getMethods()) {
1✔
261
            translateMethod(f, subClasses);
1✔
262
        }
1✔
263
        for (ModuleInstanciation mi : c.getModuleInstanciations()) {
1✔
264
            translateMethods(mi, subClasses);
1✔
265
        }
1✔
266
    }
1✔
267

268
    private void translateMethod(FuncDef s, List<ClassDef> subClasses) {
269
        ImFunction f = createStaticCallFunc(s);
1✔
270
        if (s.attrIsStatic()) {
1✔
271
            // static method
272
        } else {
273
            // dynamic method
274
            ImMethod m = translator.getMethodFor(s);
1✔
275
            imClass.getMethods().add(m);
1✔
276
            m.setImplementation(f);
1✔
277
            m.setIsAbstract(s.attrIsAbstract());
1✔
278
            // set sub methods
279
            Map<ClassDef, FuncDef> subClasses2 = translator.getClassesWithImplementation(subClasses, s);
1✔
280
            for (Entry<ClassDef, FuncDef> subE : subClasses2.entrySet()) {
1✔
281
                FuncDef subM = subE.getValue();
1✔
282
                ClassDef subC = subE.getKey();
1✔
283

284
                WurstTypeClass ct = getExtendedClassType(subC);
1✔
285
                VariableBinding typeBinding;
286
                if (ct == null) {
1✔
287
                    typeBinding = VariableBinding.emptyMapping();
×
288
                } else {
289
                    typeBinding = ct.getTypeArgBinding();
1✔
290
                }
291

292
                ImClass subClass = translator.getClassFor(subC);
1✔
293
                ImMethod subMethod = translator.getMethodFor(subM);
1✔
294

295

296
                OverrideUtils.addOverride(translator, s, subClass, subMethod, subM, typeBinding);
1✔
297
//                                m.getSubMethods().add(translator.getMethodFor(subM));
298
            }
1✔
299
        }
300
    }
1✔
301

302
    private WurstTypeClass getExtendedClassType(ClassDef subC) {
303
        if (subC.getExtendedClass() == null) {
1✔
304
            return null;
×
305
        }
306
        WurstType t = subC.getExtendedClass().attrTyp();
1✔
307
        if (t instanceof WurstTypeClass) {
1✔
308
            WurstTypeClass ct = (WurstTypeClass) t;
1✔
309
            ClassDef superClass = ct.getClassDef();
1✔
310
            if (superClass == classDef) {
1✔
311
                return ct;
1✔
312
            } else {
313
                WurstTypeClass t2 = getExtendedClassType(superClass);
1✔
314
                assert t2 != null;
1✔
315
                t2.setTypeArgs(ct.getTypeArgBinding());
1✔
316
                return t2;
1✔
317
            }
318

319
        }
320
        return null;
×
321
    }
322

323
    private ImFunction createStaticCallFunc(FuncDef funcDef) {
324
        ImFunction f = translator.getFuncFor(funcDef);
1✔
325
        f.getBody().addAll(translator.translateStatements(f, funcDef.getBody()));
1✔
326
        // TODO add return for abstract function
327
        if (funcDef.attrIsAbstract() && !(funcDef.attrReturnType() instanceof WurstTypeVoid)) {
1✔
328
            f.getBody().add(ImReturn(funcDef, funcDef.attrReturnType().getDefaultValue(translator)));
1✔
329
        }
330
        return f;
1✔
331
    }
332

333

334
    private void translateConstructor(ConstructorDef constr) {
335
        createNewFunc(constr);
1✔
336
        createConstructFunc(constr);
1✔
337
    }
1✔
338

339

340
    private void createNewFunc(ConstructorDef constr) {
341
        ConstructorDef trace = constr;
1✔
342
        ImFunction f = translator.getConstructNewFunc(constr);
1✔
343

344
        for (WParameter p : constr.getParameters()) {
1✔
345
            ImVar imP = ImVar(p, p.attrTyp().imTranslateType(translator), p.getName(), false);
1✔
346
            f.getParameters().add(imP);
1✔
347
        }
1✔
348

349

350
        ImVar thisVar = JassIm.ImVar(constr, imClassType(), "this", false);
1✔
351
        f.getLocals().add(thisVar);
1✔
352

353
        // allocate class
354
        f.getBody().add(ImSet(trace, ImVarAccess(thisVar), JassIm.ImAlloc(constr, imClassType())));
1✔
355

356
        // call user defined constructor code:
357
        ImFunction constrFunc = translator.getConstructFunc(constr);
1✔
358
        ImExprs arguments = ImExprs(ImVarAccess(thisVar));
1✔
359
        for (ImVar a : f.getParameters()) {
1✔
360
            arguments.add(ImVarAccess(a));
1✔
361
        }
1✔
362
        ImTypeArguments typeArgs = ImTypeArguments();
1✔
363
        for (ImTypeVar tv : imClass.getTypeVariables()) {
1✔
364
            typeArgs.add(JassIm.ImTypeArgument(JassIm.ImTypeVarRef(tv), Collections.emptyMap()));
1✔
365
        }
1✔
366
        f.getBody().add(ImFunctionCall(trace, constrFunc, typeArgs, arguments, false, CallType.NORMAL));
1✔
367

368

369
        // return this
370
        f.getBody().add(ImReturn(trace, ImVarAccess(thisVar)));
1✔
371

372
    }
1✔
373

374

375
    private void createConstructFunc(ConstructorDef constr) {
376
        ConstructorDef trace = constr;
1✔
377
        ImFunction f = translator.getConstructFunc(constr);
1✔
378
        ImVar thisVar = translator.getThisVar(constr);
1✔
379
        ConstructorDef superConstr = constr.attrSuperConstructor();
1✔
380
        if (superConstr != null) {
1✔
381
            // call super constructor
382
            ImFunction superConstrFunc = translator.getConstructFunc(superConstr);
1✔
383
            ImExprs arguments = ImExprs(ImVarAccess(thisVar));
1✔
384
            for (Expr a : superArgs(constr)) {
1✔
385
                arguments.add(a.imTranslateExpr(translator, f));
1✔
386
            }
1✔
387
            ImTypeArguments typeArgs = ImTypeArguments();
1✔
388
            ClassDef classDef = constr.attrNearestClassDef();
1✔
389
            assert classDef != null;
1✔
390
            WurstType extendedType = classDef.getExtendedClass().attrTyp();
1✔
391
            if (extendedType instanceof WurstTypeClass) {
1✔
392
                WurstTypeClass extendedTypeC = (WurstTypeClass) extendedType;
1✔
393
                for (WurstTypeBoundTypeParam bt : extendedTypeC.getTypeParameters()) {
1✔
394
                    if (bt.isTemplateTypeParameter()) {
1✔
395
                        typeArgs.add(bt.imTranslateToTypeArgument(translator));
1✔
396
                    }
397
                }
1✔
398
            }
399
            f.getBody().add(ImFunctionCall(trace, superConstrFunc, typeArgs, arguments, false, CallType.NORMAL));
1✔
400
        }
401
        // call classInitFunc:
402
        ImTypeArguments typeArguments = JassIm.ImTypeArguments();
1✔
403
        for (ImTypeVar tv : imClass.getTypeVariables()) {
1✔
404
            typeArguments.add(JassIm.ImTypeArgument(JassIm.ImTypeVarRef(tv), Collections.emptyMap()));
1✔
405
        }
1✔
406
        f.getBody().add(ImFunctionCall(trace, classInitFunc, typeArguments, JassIm.ImExprs(JassIm.ImVarAccess(thisVar)), false, CallType.NORMAL));
1✔
407
        // constructor user code
408
        f.getBody().addAll(translator.translateStatements(f, constr.getBody()));
1✔
409
    }
1✔
410

411
    private void translateClassInitFunc() {
412
        ClassDef trace = classDef;
1✔
413
        ImVar thisVar = JassIm.ImVar(trace, imClassType(), "this", false);
1✔
414
        classInitFunc = JassIm.ImFunction(classDef, translator.getNameFor(classDef) + "_init", ImTypeVars(), ImVars(thisVar), ImVoid(), ImVars(), ImStmts(), Collections.emptyList());
1✔
415
        imClass.getFunctions().add(classInitFunc);
1✔
416

417
        ImFunction f = classInitFunc;
1✔
418
        // initialize vars
419
        for (Pair<ImVar, VarInitialization> i : translator.getDynamicInits(classDef)) {
1✔
420
            ImVar v = i.getA();
1✔
421
            if (i.getB() instanceof Expr) {
1✔
422
                Expr e = (Expr) i.getB();
1✔
423
                ImStmt s = ImSet(trace, ImMemberAccess(trace, ImVarAccess(thisVar), ImTypeArguments(), v, ImExprs()), e.imTranslateExpr(translator, f));
1✔
424

425
                f.getBody().add(s);
1✔
426
            } else if (i.getB() instanceof ArrayInitializer) {
1✔
427
                ArrayInitializer ai = (ArrayInitializer) i.getB();
1✔
428
                int index = 0;
1✔
429
                for (Expr e : ai.getValues()) {
1✔
430
                    ImStmt s = ImSet(trace, ImMemberAccess(trace, ImVarAccess(thisVar), ImTypeArguments(), v, ImExprs(JassIm.ImIntVal(index))), e.imTranslateExpr(translator, f));
1✔
431
                    f.getBody().add(s);
1✔
432
                    index++;
1✔
433
                }
1✔
434
            }
435
        }
1✔
436
        // add initializers from modules
437
        for (ModuleInstanciation mi : classDef.getModuleInstanciations()) {
1✔
438
            addModuleInits(f, mi, thisVar);
1✔
439
        }
1✔
440
    }
1✔
441

442
    private void addModuleInits(ImFunction f, ModuleInstanciation mi, ImVar thisVar) {
443
        // call constructors of used modules:
444
        for (ConstructorDef c : mi.getConstructors()) {
1✔
445
            ImFunction moduleConstr = translator.getConstructFunc(c);
1✔
446
            f.getBody().add(ImFunctionCall(c, moduleConstr, ImTypeArguments(), JassIm.ImExprs(JassIm.ImVarAccess(thisVar)), false, CallType.NORMAL));
1✔
447
        }
1✔
448
    }
1✔
449

450

451
    private void translateModuleConstructor(ConstructorDef constr, ModuleInstanciation mi) {
452
        ImFunction f = translator.getConstructFunc(constr);
1✔
453
        ImVar thisVar = translator.getThisVar(constr);
1✔
454
        // first call constructors of children:
455
        for (ModuleInstanciation child : mi.getModuleInstanciations()) {
1✔
456
            addModuleInits(f, child, thisVar);
1✔
457
        }
1✔
458

459
        // constructor user code
460
        f.getBody().addAll(translator.translateStatements(f, constr.getBody()));
1✔
461

462

463
    }
1✔
464

465

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

© 2025 Coveralls, Inc