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

wurstscript / WurstScript / 228

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

push

circleci

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

* show dialog for choosing game path

* cleanup code

* remove logs and refactor

* remove confusing mpq error, make some mpq loads readonly

17295 of 27681 relevant lines covered (62.48%)

0.62 hits per line

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

93.68
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.Element;
4
import de.peeeq.wurstscript.ast.*;
5
import de.peeeq.wurstscript.jassIm.Element.DefaultVisitor;
6
import de.peeeq.wurstscript.jassIm.ImClass;
7
import de.peeeq.wurstscript.jassIm.ImClassType;
8
import de.peeeq.wurstscript.jassIm.ImExprs;
9
import de.peeeq.wurstscript.jassIm.ImFunction;
10
import de.peeeq.wurstscript.jassIm.ImMethod;
11
import de.peeeq.wurstscript.jassIm.ImProg;
12
import de.peeeq.wurstscript.jassIm.ImTypeArguments;
13
import de.peeeq.wurstscript.jassIm.ImTypeVar;
14
import de.peeeq.wurstscript.jassIm.ImVar;
15
import de.peeeq.wurstscript.jassIm.ImVarAccess;
16
import de.peeeq.wurstscript.jassIm.*;
17
import de.peeeq.wurstscript.types.*;
18
import de.peeeq.wurstscript.utils.Pair;
19

20
import java.util.Collections;
21
import java.util.List;
22
import java.util.Map;
23
import java.util.Map.Entry;
24
import java.util.stream.Collectors;
25

26
import static de.peeeq.wurstscript.attributes.SmallHelpers.superArgs;
27
import static de.peeeq.wurstscript.jassIm.JassIm.*;
28

29
public class ClassTranslator {
1✔
30

31
    private final ClassDef classDef;
32
    private final ImTranslator translator;
33
    //        /** list of statements to initialize a new object **/
34
    final private List<Pair<ImVar, VarInitialization>> dynamicInits;
35
    private ImClass imClass;
36
    private final ImProg prog;
37
    private ImFunction classInitFunc;
38

39
    public ClassTranslator(ClassDef classDef, ImTranslator translator) {
1✔
40
        this.classDef = classDef;
1✔
41
        this.translator = translator;
1✔
42
        this.prog = translator.getImProg();
1✔
43
//                initStatements = translator.getInitStatement(classDef);
44
        dynamicInits = translator.getDynamicInits(classDef);
1✔
45
    }
1✔
46

47
    public static void translate(ClassDef classDef, ImTranslator translator) {
48
        new ClassTranslator(classDef, translator).translate();
1✔
49

50
        // translate inner classes:
51
        translateInnerClasses(classDef, translator);
1✔
52
    }
1✔
53

54
    private static void translateInnerClasses(ClassOrModuleOrModuleInstanciation mi, ImTranslator translator) {
55
        for (ModuleInstanciation mi2 : mi.getModuleInstanciations()) {
1✔
56
            translateInnerClasses(mi2, translator);
1✔
57
        }
1✔
58
        for (ClassDef innerClass : mi.getInnerClasses()) {
1✔
59
            translate(innerClass, translator);
1✔
60
        }
1✔
61
    }
1✔
62

63
    /**
64
     * translates the given classDef
65
     */
66
    private void translate() {
67
        imClass = translator.getClassFor(classDef);
1✔
68
        prog.getClasses().add(imClass);
1✔
69

70
        addSuperClasses();
1✔
71

72
        List<ClassDef> subClasses = translator.getSubClasses(classDef);
1✔
73

74
        // order is important here
75
        translateMethods(classDef, subClasses);
1✔
76
        translateVars(classDef);
1✔
77
        translateClassInitFunc();
1✔
78
        translateConstructors();
1✔
79
        createOnDestroyMethod();
1✔
80
        createDestroyMethod(subClasses);
1✔
81

82
    }
1✔
83

84

85

86
    private void addSuperClasses() {
87
        if (classDef.getExtendedClass() instanceof TypeExpr) {
1✔
88
            TypeExpr extended = (TypeExpr) classDef.getExtendedClass();
1✔
89
            addSuperClass(extended);
1✔
90
        }
91
        for (TypeExpr impl : classDef.getImplementsList()) {
1✔
92
            addSuperClass(impl);
1✔
93
        }
1✔
94

95
    }
1✔
96

97
    private void addSuperClass(TypeExpr extended) {
98
        imClass.getSuperClasses().add((ImClassType) extended.attrTyp().imTranslateType(translator));
1✔
99
    }
1✔
100

101
    private void createDestroyMethod(List<ClassDef> subClasses) {
102
        ImMethod m = translator.destroyMethod.getFor(classDef);
1✔
103
        imClass.getMethods().add(m);
1✔
104
        ImFunction f = translator.destroyFunc.getFor(classDef);
1✔
105

106
        // set sub methods
107
        for (ClassDef sc : subClasses) {
1✔
108
            ImMethod dm = translator.destroyMethod.getFor(sc);
1✔
109
            if (hasOwnDestroy(sc, classDef)) {
1✔
110
                m.getSubMethods().add(dm);
1✔
111
            }
112
        }
1✔
113

114
        Element trace = classDef.getOnDestroy();
1✔
115

116
        ImVar thisVar = f.getParameters().get(0);
1✔
117

118
        // call ondestroy methods
119
        ClassDef c = classDef;
1✔
120
        ImFunction scOnDestroy = translator.getFuncFor(c.getOnDestroy());
1✔
121
        f.getBody().add(ImFunctionCall(trace, scOnDestroy, ImTypeArguments(), ImExprs(ImVarAccess(thisVar)), false, CallType.NORMAL));
1✔
122

123
        // deallocate
124
        f.getBody().add(JassIm.ImDealloc(c.getOnDestroy(), imClassType(), JassIm.ImVarAccess(thisVar)));
1✔
125
    }
1✔
126

127
    private ImClassType imClassType() {
128
        ImTypeArguments typeArgs = imClass.getTypeVariables().stream()
1✔
129
                .map(tv -> JassIm.ImTypeArgument(JassIm.ImTypeVarRef(tv), Collections.emptyMap()))
1✔
130
                .collect(Collectors.toCollection(JassIm::ImTypeArguments));
1✔
131
        return JassIm.ImClassType(imClass, typeArgs);
1✔
132
    }
133

134
    /**
135
     *
136
     */
137
    private boolean hasOwnDestroy(ClassDef sc, ClassDef classDef2) {
138
        if (sc == classDef2) {
1✔
139
            return false;
1✔
140
        }
141
        if (sc.getOnDestroy().attrHasEmptyBody()) {
1✔
142
            WurstTypeClass superClass = (WurstTypeClass) sc.getExtendedClass().attrTyp();
1✔
143
            if (hasOwnDestroy(superClass.getClassDef(), classDef2)) {
1✔
144
                return true;
1✔
145
            }
146
            for (ModuleInstanciation mi : sc.getModuleInstanciations()) {
1✔
147
                if (hasOwnDestroy(mi)) {
1✔
148
                    return true;
1✔
149
                }
150
            }
1✔
151
            return false;
1✔
152
        } else {
153
            return true;
1✔
154
        }
155
    }
156

157
    private boolean hasOwnDestroy(ModuleInstanciation mi) {
158
        if (!mi.getOnDestroy().attrHasEmptyBody()) {
1✔
159
            return true;
1✔
160
        }
161
        for (ModuleInstanciation subMod : mi.getModuleInstanciations()) {
1✔
162
            if (hasOwnDestroy(subMod)) {
×
163
                return true;
×
164
            }
165
        }
×
166
        return false;
1✔
167
    }
168

169
    private void createOnDestroyMethod() {
170
        OnDestroyDef onDestroy = classDef.getOnDestroy();
1✔
171
        ImFunction f = translator.getFuncFor(onDestroy);
1✔
172
        addOnDestroyActions(f, f.getBody(), classDef, translator.getThisVar(onDestroy));
1✔
173
    }
1✔
174

175
    private void addOnDestroyActions(ImFunction f, List<ImStmt> addTo, ClassOrModuleInstanciation c, ImVar thisVar) {
176
        // translate ondestroy statements
177
        List<ImStmt> stmts = translator.translateStatements(f, c.getOnDestroy().getBody());
1✔
178
        replaceThisExpr(stmts, translator.getThisVar(c.getOnDestroy()), thisVar);
1✔
179
        addTo.addAll(stmts);
1✔
180

181
        // add onDestroy actions from modules
182
        for (ModuleInstanciation mi : c.getModuleInstanciations()) {
1✔
183
            addOnDestroyActions(f, addTo, mi, thisVar);
1✔
184
        }
1✔
185

186
        if (c instanceof ClassDef) {
1✔
187
            ClassDef cd = (ClassDef) c;
1✔
188
            WurstTypeClass ct = cd.attrTypC();
1✔
189
            WurstTypeClass extended = ct.extendedClass();
1✔
190
            if (extended != null) {
1✔
191
                // call onDestroy of super class
192
                ImFunction onDestroy = translator.getFuncFor(extended.getClassDef().getOnDestroy());
1✔
193
                ImTypeArguments typeArgs = ImTypeArguments();
1✔
194
                for (WurstTypeBoundTypeParam tp : extended.getTypeParameters()) {
1✔
195
                    if (tp.isTemplateTypeParameter()) {
1✔
196
                        typeArgs.add(tp.imTranslateToTypeArgument(translator));
×
197
                    }
198
                }
1✔
199
                addTo.add(ImFunctionCall(c, onDestroy, typeArgs, ImExprs(ImVarAccess(thisVar)), false, CallType.NORMAL));
1✔
200
            }
201
        }
202
    }
1✔
203

204
    private void replaceThisExpr(List<ImStmt> stmts, final ImVar oldThis, final ImVar newThis) {
205
        if (oldThis == newThis) {
1✔
206
            return;
1✔
207
        }
208
        DefaultVisitor replacer = new DefaultVisitor() {
×
209
            @Override
210
            public void visit(ImVarAccess v) {
211
                super.visit(v);
×
212
                if (v.getVar() == oldThis) {
×
213
                    v.setVar(newThis);
×
214
                }
215
            }
×
216

217
        };
218
        for (ImStmt s : stmts) {
×
219
            s.accept(replacer);
×
220
        }
×
221

222
    }
×
223

224
    private void translateConstructors() {
225
        // translate constructors of module instantiations:
226
        for (ModuleInstanciation mi : classDef.getModuleInstanciations()) {
1✔
227
            translateModuleConstructors(mi);
1✔
228
        }
1✔
229

230
        for (ConstructorDef c : classDef.getConstructors()) {
1✔
231
            translateConstructor(c);
1✔
232
        }
1✔
233

234
    }
1✔
235

236

237
    private void translateModuleConstructors(ModuleInstanciation mi) {
238
        for (ModuleInstanciation child : mi.getModuleInstanciations()) {
1✔
239
            translateModuleConstructors(child);
1✔
240
        }
1✔
241

242
        for (ConstructorDef c : mi.getConstructors()) {
1✔
243
            translateModuleConstructor(c, mi);
1✔
244
        }
1✔
245
    }
1✔
246

247

248
    private void translateVars(ClassOrModuleInstanciation c) {
249
        for (ModuleInstanciation mi : c.getModuleInstanciations()) {
1✔
250
            translateVars(mi);
1✔
251
        }
1✔
252
        for (GlobalVarDef v : c.getVars()) {
1✔
253
            translateVar(v);
1✔
254
        }
1✔
255
    }
1✔
256

257
    private void translateVar(GlobalVarDef s) {
258
        ImVar v = translator.getVarFor(s);
1✔
259
        if (s.attrIsDynamicClassMember()) {
1✔
260
            // add dynamic class members to the class
261
            imClass.getFields().add(v);
1✔
262
            dynamicInits.add(Pair.create(v, s.getInitialExpr()));
1✔
263
        } else { // static class member
264
            translator.addGlobalInitalizer(v, classDef.attrNearestPackage(), s.getInitialExpr());
1✔
265
            translator.addGlobal(v);
1✔
266
        }
267
    }
1✔
268

269
    private void translateMethods(ClassOrModuleInstanciation c, List<ClassDef> subClasses) {
270
        for (FuncDef f : c.getMethods()) {
1✔
271
            translateMethod(f, subClasses);
1✔
272
        }
1✔
273
        for (ModuleInstanciation mi : c.getModuleInstanciations()) {
1✔
274
            translateMethods(mi, subClasses);
1✔
275
        }
1✔
276
    }
1✔
277

278
    private void translateMethod(FuncDef s, List<ClassDef> subClasses) {
279
        ImFunction f = createStaticCallFunc(s);
1✔
280
        if (s.attrIsStatic()) {
1✔
281
            // static method
282
        } else {
283
            // dynamic method
284
            ImMethod m = translator.getMethodFor(s);
1✔
285
            imClass.getMethods().add(m);
1✔
286
            m.setImplementation(f);
1✔
287
            m.setIsAbstract(s.attrIsAbstract());
1✔
288
            // set sub methods
289
            Map<ClassDef, FuncDef> subClasses2 = translator.getClassesWithImplementation(subClasses, s);
1✔
290
            for (Entry<ClassDef, FuncDef> subE : subClasses2.entrySet()) {
1✔
291
                FuncDef subM = subE.getValue();
1✔
292
                ClassDef subC = subE.getKey();
1✔
293

294
                WurstTypeClass ct = getExtendedClassType(subC);
1✔
295
                VariableBinding typeBinding;
296
                if (ct == null) {
1✔
297
                    typeBinding = VariableBinding.emptyMapping();
×
298
                } else {
299
                    typeBinding = ct.getTypeArgBinding();
1✔
300
                }
301

302
                ImClass subClass = translator.getClassFor(subC);
1✔
303
                ImMethod subMethod = translator.getMethodFor(subM);
1✔
304

305

306
                OverrideUtils.addOverride(translator, s, subClass, subMethod, subM, typeBinding);
1✔
307
//                                m.getSubMethods().add(translator.getMethodFor(subM));
308
            }
1✔
309
        }
310
    }
1✔
311

312
    private WurstTypeClass getExtendedClassType(ClassDef subC) {
313
        if (subC.getExtendedClass() == null) {
1✔
314
            return null;
×
315
        }
316
        WurstType t = subC.getExtendedClass().attrTyp();
1✔
317
        if (t instanceof WurstTypeClass) {
1✔
318
            WurstTypeClass ct = (WurstTypeClass) t;
1✔
319
            ClassDef superClass = ct.getClassDef();
1✔
320
            if (superClass == classDef) {
1✔
321
                return ct;
1✔
322
            } else {
323
                WurstTypeClass t2 = getExtendedClassType(superClass);
1✔
324
                assert t2 != null;
1✔
325
                t2.setTypeArgs(ct.getTypeArgBinding());
1✔
326
                return t2;
1✔
327
            }
328

329
        }
330
        return null;
×
331
    }
332

333
    private ImFunction createStaticCallFunc(FuncDef funcDef) {
334
        ImFunction f = translator.getFuncFor(funcDef);
1✔
335
        f.getBody().addAll(translator.translateStatements(f, funcDef.getBody()));
1✔
336
        // TODO add return for abstract function
337
        if (funcDef.attrIsAbstract() && !(funcDef.attrReturnType() instanceof WurstTypeVoid)) {
1✔
338
            f.getBody().add(ImReturn(funcDef, funcDef.attrReturnType().getDefaultValue(translator)));
1✔
339
        }
340
        return f;
1✔
341
    }
342

343

344
    private void translateConstructor(ConstructorDef constr) {
345
        createNewFunc(constr);
1✔
346
        createConstructFunc(constr);
1✔
347
    }
1✔
348

349

350
    private void createNewFunc(ConstructorDef constr) {
351
        ConstructorDef trace = constr;
1✔
352
        ImFunction f = translator.getConstructNewFunc(constr);
1✔
353

354
        for (WParameter p : constr.getParameters()) {
1✔
355
            ImVar imP = ImVar(p, p.attrTyp().imTranslateType(translator), p.getName(), false);
1✔
356
            f.getParameters().add(imP);
1✔
357
        }
1✔
358

359

360
        ImVar thisVar = JassIm.ImVar(constr, imClassType(), "this", false);
1✔
361
        f.getLocals().add(thisVar);
1✔
362

363
        // allocate class
364
        f.getBody().add(ImSet(trace, ImVarAccess(thisVar), JassIm.ImAlloc(constr, imClassType())));
1✔
365

366
        // call user defined constructor code:
367
        ImFunction constrFunc = translator.getConstructFunc(constr);
1✔
368
        ImExprs arguments = ImExprs(ImVarAccess(thisVar));
1✔
369
        for (ImVar a : f.getParameters()) {
1✔
370
            arguments.add(ImVarAccess(a));
1✔
371
        }
1✔
372
        ImTypeArguments typeArgs = ImTypeArguments();
1✔
373
        for (ImTypeVar tv : imClass.getTypeVariables()) {
1✔
374
            typeArgs.add(JassIm.ImTypeArgument(JassIm.ImTypeVarRef(tv), Collections.emptyMap()));
1✔
375
        }
1✔
376
        f.getBody().add(ImFunctionCall(trace, constrFunc, typeArgs, arguments, false, CallType.NORMAL));
1✔
377

378

379
        // return this
380
        f.getBody().add(ImReturn(trace, ImVarAccess(thisVar)));
1✔
381

382
    }
1✔
383

384

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

421
    private void translateClassInitFunc() {
422
        ClassDef trace = classDef;
1✔
423
        ImVar thisVar = JassIm.ImVar(trace, imClassType(), "this", false);
1✔
424
        classInitFunc = JassIm.ImFunction(classDef, translator.getNameFor(classDef) + "_init", ImTypeVars(), ImVars(thisVar), ImVoid(), ImVars(), ImStmts(), Collections.emptyList());
1✔
425
        imClass.getFunctions().add(classInitFunc);
1✔
426

427
        ImFunction f = classInitFunc;
1✔
428
        // initialize vars
429
        for (Pair<ImVar, VarInitialization> i : translator.getDynamicInits(classDef)) {
1✔
430
            ImVar v = i.getA();
1✔
431
            if (i.getB() instanceof Expr) {
1✔
432
                Expr e = (Expr) i.getB();
1✔
433
                ImStmt s = ImSet(trace, ImMemberAccess(trace, ImVarAccess(thisVar), ImTypeArguments(), v, ImExprs()), e.imTranslateExpr(translator, f));
1✔
434

435
                f.getBody().add(s);
1✔
436
            } else if (i.getB() instanceof ArrayInitializer) {
1✔
437
                ArrayInitializer ai = (ArrayInitializer) i.getB();
1✔
438
                int index = 0;
1✔
439
                for (Expr e : ai.getValues()) {
1✔
440
                    ImStmt s = ImSet(trace, ImMemberAccess(trace, ImVarAccess(thisVar), ImTypeArguments(), v, ImExprs(JassIm.ImIntVal(index))), e.imTranslateExpr(translator, f));
1✔
441
                    f.getBody().add(s);
1✔
442
                    index++;
1✔
443
                }
1✔
444
            }
445
        }
1✔
446
        // add initializers from modules
447
        for (ModuleInstanciation mi : classDef.getModuleInstanciations()) {
1✔
448
            addModuleInits(f, mi, thisVar);
1✔
449
        }
1✔
450
    }
1✔
451

452
    private void addModuleInits(ImFunction f, ModuleInstanciation mi, ImVar thisVar) {
453
        // call constructors of used modules:
454
        for (ConstructorDef c : mi.getConstructors()) {
1✔
455
            ImFunction moduleConstr = translator.getConstructFunc(c);
1✔
456
            f.getBody().add(ImFunctionCall(c, moduleConstr, ImTypeArguments(), JassIm.ImExprs(JassIm.ImVarAccess(thisVar)), false, CallType.NORMAL));
1✔
457
        }
1✔
458
    }
1✔
459

460

461
    private void translateModuleConstructor(ConstructorDef constr, ModuleInstanciation mi) {
462
        ImFunction f = translator.getConstructFunc(constr);
1✔
463
        ImVar thisVar = translator.getThisVar(constr);
1✔
464
        // first call constructors of children:
465
        for (ModuleInstanciation child : mi.getModuleInstanciations()) {
1✔
466
            addModuleInits(f, child, thisVar);
1✔
467
        }
1✔
468

469
        // constructor user code
470
        f.getBody().addAll(translator.translateStatements(f, constr.getBody()));
1✔
471

472

473
    }
1✔
474

475

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