Coveralls logob
Coveralls logo
  • Home
  • Features
  • Pricing
  • Docs
  • Sign In

wurstscript / WurstScript / 1198

22 Oct 2019 - 20:22 coverage decreased (-0.04%) to 62.819%
1198

Pull #899

travis-ci

9181eb84f9c35729a3bad740fb7f9d93?size=18&default=identiconweb-flow
fixes
Pull Request #899: Workspace config

16348 of 26024 relevant lines covered (62.82%)

0.63 hits per line

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

56.61
de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/WurstCompilerJassImpl.java
1
package de.peeeq.wurstio;
2

3
import com.google.common.base.Charsets;
4
import com.google.common.base.Preconditions;
5
import com.google.common.collect.*;
6
import com.google.common.io.Files;
7
import de.peeeq.wurstio.languageserver.requests.RequestFailedException;
8
import de.peeeq.wurstio.map.importer.ImportFile;
9
import de.peeeq.wurstio.mpq.MpqEditor;
10
import de.peeeq.wurstio.utils.FileReading;
11
import de.peeeq.wurstio.utils.FileUtils;
12
import de.peeeq.wurstscript.*;
13
import de.peeeq.wurstscript.ast.*;
14
import de.peeeq.wurstscript.ast.Element;
15
import de.peeeq.wurstscript.attributes.CompilationUnitInfo;
16
import de.peeeq.wurstscript.attributes.CompileError;
17
import de.peeeq.wurstscript.attributes.ErrorHandler;
18
import de.peeeq.wurstscript.gui.WurstGui;
19
import de.peeeq.wurstscript.jassAst.JassProg;
20
import de.peeeq.wurstscript.jassIm.*;
21
import de.peeeq.wurstscript.jassprinter.JassPrinter;
22
import de.peeeq.wurstscript.luaAst.LuaCompilationUnit;
23
import de.peeeq.wurstscript.parser.WPos;
24
import de.peeeq.wurstscript.translation.imoptimizer.ImOptimizer;
25
import de.peeeq.wurstscript.translation.imtojass.ImToJassTranslator;
26
import de.peeeq.wurstscript.translation.imtranslation.*;
27
import de.peeeq.wurstscript.translation.lua.translation.LuaTranslator;
28
import de.peeeq.wurstscript.types.TypesHelper;
29
import de.peeeq.wurstscript.utils.LineOffsets;
30
import de.peeeq.wurstscript.utils.NotNullList;
31
import de.peeeq.wurstscript.utils.TempDir;
32
import de.peeeq.wurstscript.utils.Utils;
33
import org.eclipse.jdt.annotation.Nullable;
34
import org.eclipse.lsp4j.MessageType;
35
import org.jetbrains.annotations.NotNull;
36

37
import java.io.*;
38
import java.util.*;
39
import java.util.Map.Entry;
40
import java.util.function.Function;
41

42
import static de.peeeq.wurstio.CompiletimeFunctionRunner.FunctionFlagToRun.CompiletimeFunctions;
43

44
public class WurstCompilerJassImpl implements WurstCompiler {
45

46
    private List<File> files = Lists.newArrayList();
1×
47
    private Map<String, Reader> otherInputs = Maps.newLinkedHashMap();
1×
48
    private @Nullable JassProg prog;
49
    private WurstGui gui;
50
    private boolean hasCommonJ;
51
    private RunArgs runArgs;
52
    private @Nullable File mapFile;
53
    private @Nullable File projectFolder;
54
    private ErrorHandler errorHandler;
55
    private @Nullable Map<String, File> libCache = null;
1×
56
    private @Nullable ImProg imProg;
57
    private List<File> parsedFiles = Lists.newArrayList();
1×
58
    private final WurstParser parser;
59
    private final WurstChecker checker;
60
    private @Nullable ImTranslator imTranslator;
61
    private List<File> dependencies = Lists.newArrayList();
1×
62
    private final @Nullable MpqEditor mapFileMpq;
63
    private TimeTaker timeTaker;
64

65
    public WurstCompilerJassImpl(@Nullable File projectFolder, WurstGui gui, @Nullable MpqEditor mapFileMpq, RunArgs runArgs) {
66
        this(new TimeTaker.Default(), projectFolder, gui, mapFileMpq, runArgs);
1×
67
    }
1×
68

69
    public WurstCompilerJassImpl(TimeTaker timeTaker, @Nullable File projectFolder, WurstGui gui, @Nullable MpqEditor mapFileMpq, RunArgs runArgs) {
1×
70
        this.timeTaker = timeTaker;
1×
71
        this.projectFolder = projectFolder;
1×
72
        this.gui = gui;
1×
73
        this.runArgs = runArgs;
1×
74
        this.errorHandler = new ErrorHandler(gui);
1×
75
        this.parser = new WurstParser(errorHandler, gui);
1×
76
        this.checker = new WurstChecker(gui, errorHandler);
1×
77
        this.mapFileMpq = mapFileMpq;
1×
78
    }
1×
79

80
    @Override
81
    public void loadFiles(String... filenames) {
82
        gui.sendProgress("Loading Files");
!
83
        for (String filename : filenames) {
!
84
            File file = new File(filename);
!
85
            if (!file.exists()) {
!
86
                throw new Error("File " + filename + " does not exist.");
!
87
            }
88
            files.add(file);
!
89
        }
90
    }
!
91

92
    @Override
93
    public void loadFiles(File... files) {
94
        gui.sendProgress("Loading Files");
1×
95
        for (File file : files) {
1×
96
            loadFile(file);
1×
97
        }
98
    }
1×
99

100
    @Override
101
    public void runCompiletime() {
102
        if (runArgs.runCompiletimeFunctions()) {
1×
103
            // compile & inject object-editor data
104
            // TODO run optimizations later?
105
            gui.sendProgress("Running compiletime functions");
1×
106
            CompiletimeFunctionRunner ctr = new CompiletimeFunctionRunner(imTranslator, getImProg(), getMapFile(), getMapfileMpqEditor(), gui,
1×
107
                    CompiletimeFunctions);
108
            ctr.setInjectObjects(runArgs.isInjectObjects());
1×
109
            ctr.setOutputStream(new PrintStream(System.err));
1×
110
            ctr.run();
1×
111
        }
112

113
        if (gui.getErrorCount() > 0) {
1×
114
            CompileError compileError = gui
!
115
                    .getErrorList().get(0);
!
116
            throw new RequestFailedException(MessageType.Error, "Could not compile project (error in running compiletime functions/expressions): ", compileError);
!
117
        }
118

119

120
        if (runArgs.isInjectObjects()) {
1×
121
            Preconditions.checkNotNull(mapFileMpq);
!
122
            Preconditions.checkNotNull(projectFolder);
!
123
            // add the imports
124
            ImportFile.importFilesFromImportDirectory(projectFolder, mapFileMpq);
!
125
        }
126
    }
1×
127

128
    private void loadFile(File file) throws Error {
129
        Preconditions.checkNotNull(file);
1×
130
        if (!file.exists()) {
1×
131
            throw new Error("File " + file + " does not exist.");
!
132
        }
133
        this.files.add(file);
1×
134
    }
1×
135

136
    public void loadWurstFilesInDir(File dir) {
137
        for (File f : dir.listFiles()) {
!
138
            if (f.isDirectory()) {
!
139
                loadWurstFilesInDir(f);
!
140
            } else if (Utils.isWurstFile(f)) {
!
141
                loadFile(f);
!
142
            } else if (f.getName().equals("wurst.dependencies")) {
!
143
                addDependencyFile(f);
!
144
            } else if ((mapFile == null || runArgs.isNoExtractMapScript()) && f.getName().equals("war3map.j")) {
!
145
                loadFile(f);
!
146
            }
147
        }
148
    }
!
149

150
    private void addDependencyFile(File f) {
151
        try (FileReader fr = new FileReader(f); BufferedReader reader = new BufferedReader(fr)) {
!
152
            while (true) {
153
                String line = reader.readLine();
!
154
                if (line == null)
!
155
                    break;
!
156
                addDependencyFolder(f, line);
!
157
            }
!
158
        } catch (IOException e) {
!
159
            e.printStackTrace();
!
160
            throw new Error(e);
!
161
        }
!
162
    }
!
163

164
    private void addDependencyFolder(File f, String folderName) {
165
        File folder = new File(folderName);
!
166
        if (!folder.exists()) {
!
167
            gui.sendError(new CompileError(new WPos(f.getAbsolutePath(), new LineOffsets(), 0, 1), "Folder " + folderName + " not found."));
!
168
        } else if (!folder.isDirectory()) {
!
169
            gui.sendError(new CompileError(new WPos(f.getAbsolutePath(), new LineOffsets(), 0, 1), "" + folderName + " is not a folder."));
!
170
        } else {
171
            dependencies.add(folder);
!
172
        }
173
    }
!
174

175
    @Override
176
    public @Nullable WurstModel parseFiles() {
177

178
        // search mapFile
179
        for (File file : files) {
1×
180
            if (file.getName().endsWith(".w3x") || file.getName().endsWith(".w3m")) {
1×
181
                mapFile = file;
!
182
            } else if (file.isDirectory()) {
1×
183
                if (projectFolder != null && !file.getParent().equals(projectFolder.getAbsolutePath())) {
!
184
                    throw new RuntimeException("Cannot set projectFolder to " + file + " because it is already set to non parent " + projectFolder);
!
185
                }
186
                projectFolder = file;
!
187
            }
188
        }
1×
189

190

191

192
        // import wurst folder if it exists
193
        File l_mapFile = mapFile;
1×
194
        if (l_mapFile != null) {
1×
195
            if (projectFolder == null) {
!
196
                projectFolder = l_mapFile.getParentFile();
!
197
            }
198
            File relativeWurstDir = new File(projectFolder, "wurst");
!
199
            if (relativeWurstDir.exists()) {
!
200
                WLogger.info("Importing wurst files from " + relativeWurstDir);
!
201
                loadWurstFilesInDir(relativeWurstDir);
!
202
            } else {
203
                WLogger.info("No wurst folder found in " + relativeWurstDir);
!
204
            }
205
            File dependencyFile = new File(projectFolder, "wurst.dependencies");
!
206
            if (dependencyFile.exists()) {
!
207
                addDependencyFile(dependencyFile);
!
208
            }
209
            addDependenciesFromFolder(projectFolder, dependencies);
!
210
        }
211

212
        // add directories:
213
        List<File> dirs = Lists.newArrayList();
1×
214
        for (File file : files) {
1×
215
            if (file.isDirectory()) {
1×
216
                dirs.add(file);
!
217
            }
218
        }
1×
219
        for (File dir : dirs) {
1×
220
            loadWurstFilesInDir(dir);
!
221
        }
!
222

223
        gui.sendProgress("Parsing Files");
1×
224
        // parse all the files:
225
        List<CompilationUnit> compilationUnits = new NotNullList<>();
1×
226

227
        for (File file : files) {
1×
228
            if (file.isDirectory()) {
1×
229
                // ignore dirs
230
            } else if (file.getName().endsWith(".w3x") || file.getName().endsWith(".w3m")) {
1×
231
                CompilationUnit r = processMap(file);
!
232
                if (r != null) {
!
233
                    compilationUnits.add(r);
!
234
                }
235
            } else {
!
236
                if (file.getName().endsWith("common.j")) {
1×
237
                    hasCommonJ = true;
1×
238
                }
239
                compilationUnits.add(parseFile(file));
1×
240
            }
241
        }
1×
242
        for (Entry<String, Reader> in : otherInputs.entrySet()) {
1×
243
            compilationUnits.add(parse(in.getKey(), in.getValue()));
1×
244
        }
1×
245

246
        try {
247
            addImportedLibs(compilationUnits);
1×
248
        } catch (CompileError e) {
!
249
            gui.sendError(e);
!
250
            return null;
!
251
        }
1×
252

253
        if (errorHandler.getErrorCount() > 0)
1×
254
            return null;
1×
255

256
        // merge the compilationUnits:
257
        WurstModel merged = mergeCompilationUnits(compilationUnits);
1×
258
        StringBuilder sb = new StringBuilder();
1×
259
        for (CompilationUnit cu : merged) {
1×
260
            sb.append(cu.getCuInfo().getFile()).append(", ");
1×
261
        }
1×
262
        WLogger.info("Compiling compilation units: " + sb);
1×
263

264
        return merged;
1×
265
    }
266

267
    /**
268
     * Adds dependencies from the _build/dependencies folder
269
     */
270
    public static void addDependenciesFromFolder(File projectFolder, Collection<File> dependencies) {
271
        File dependencyFolder = new File(new File(projectFolder, "_build"), "dependencies");
!
272
        File[] depProjects = dependencyFolder.listFiles();
!
273
        if (depProjects != null) {
!
274
            for (File depFile : depProjects) {
!
275
                if (depFile.isDirectory()
!
276
                        && dependencies.stream().noneMatch(f -> FileUtils.sameFile(f, depFile))) {
!
277
                    dependencies.add(depFile);
!
278
                }
279
            }
280
        }
281
    }
!
282

283
    private void addImportedLibs(List<CompilationUnit> compilationUnits) {
284
        addImportedLibs(compilationUnits, file -> {
1×
285
            CompilationUnit lib = parseFile(file);
1×
286
            lib.getCuInfo().setFile(file.getAbsolutePath());
1×
287
            compilationUnits.add(lib);
1×
288
            return lib;
1×
289
        });
290
    }
1×
291

292
    /**
293
     * this method scans for unsatisfied imports and tries to find them in the lib-path
294
     */
295
    public void addImportedLibs(List<CompilationUnit> compilationUnits, Function<File, CompilationUnit> addCompilationUnit) {
296
        Set<String> packages = Sets.newLinkedHashSet();
1×
297
        Set<WImport> imports = new LinkedHashSet<>();
1×
298
        for (CompilationUnit c : compilationUnits) {
1×
299
            c.getCuInfo().setCuErrorHandler(errorHandler);
1×
300
            for (WPackage p : c.getPackages()) {
1×
301
                packages.add(p.getName());
1×
302
                imports.addAll(p.getImports());
1×
303
            }
1×
304
        }
1×
305

306
        for (WImport imp : imports) {
1×
307
            resolveImport(addCompilationUnit, packages, imp);
1×
308
        }
1×
309

310
    }
1×
311

312
    private void resolveImport(Function<File, CompilationUnit> addCompilationUnit, Set<String> packages, WImport imp) throws CompileError {
313
        //                WLogger.info("resolving import: " + imp.getPackagename());
314
        if (!packages.contains(imp.getPackagename())) {
1×
315
            if (getLibs().containsKey(imp.getPackagename())) {
1×
316
                CompilationUnit lib = loadLibPackage(addCompilationUnit, imp.getPackagename());
1×
317
                boolean foundPackage = false;
1×
318
                for (WPackage p : lib.getPackages()) {
1×
319
                    packages.add(p.getName());
1×
320
                    if (p.getName().equals(imp.getPackagename())) {
1×
321
                        foundPackage = true;
1×
322
                    }
323
                    for (WImport i : p.getImports()) {
1×
324
                        resolveImport(addCompilationUnit, packages, i);
1×
325
                    }
1×
326
                }
1×
327
                if (!foundPackage) {
1×
328
                    imp.addError("The import " + imp.getPackagename() + " could not be found in file " + lib.getCuInfo().getFile());
!
329
                }
330
            } else {
1×
331
                if (imp.getPackagename().equals("Wurst")) {
1×
332
                    imp.addError("The standard library could not be imported.");
!
333
                }
334
                if (imp.getPackagename().equals("NoWurst")) {
1×
335
                    // ignore this package
336
                } else {
337
                    imp.addError("The import '" + imp.getPackagename() + "' could not be resolved.\n" + "Available packages: "
1×
338
                            + Utils.join(getLibs().keySet(), ", "));
1×
339
                }
340
            }
341
        } else {
342
            //                        WLogger.info("already imported: " + imp.getPackagename());
343
        }
344
    }
1×
345

346
    private CompilationUnit loadLibPackage(Function<File, CompilationUnit> addCompilationUnit, String imp) {
347
        File file = getLibs().get(imp);
1×
348
        if (file == null) {
1×
349
            gui.sendError(new CompileError(new WPos("", null, 0, 0), "Could not find lib-package " + imp + ". Are you missing your wurst.dependencies file?"));
!
350
            return Ast.CompilationUnit(new CompilationUnitInfo(errorHandler), Ast.JassToplevelDeclarations(), Ast.WPackages());
!
351
        } else {
352
            return addCompilationUnit.apply(file);
1×
353
        }
354
    }
355

356
    public Map<String, File> getLibs() {
357
        Map<String, File> lc = libCache;
1×
358
        if (lc == null) {
1×
359
            lc = Maps.newLinkedHashMap();
1×
360
            libCache = lc;
1×
361
            for (File libDir : runArgs.getAdditionalLibDirs()) {
1×
362
                addLibDir(libDir);
1×
363
            }
1×
364
            for (File libDir : dependencies) {
1×
365
                addLibDir(libDir);
!
366
            }
!
367
        }
368
        return lc;
1×
369
    }
370

371
    private void addLibDir(File libDir) throws Error {
372
        if (!libDir.exists() || !libDir.isDirectory()) {
1×
373
            throw new Error("Library folder " + libDir + " does not exist.");
!
374
        }
375
        for (File f : libDir.listFiles()) {
1×
376
            if (f.isDirectory()) {
1×
377
                // recursively scan directory
378
                addLibDir(f);
1×
379
            }
380
            if (Utils.isWurstFile(f)) {
1×
381
                String libName = Utils.getLibName(f);
1×
382
                getLibs().put(libName, f);
1×
383
            }
384
        }
385
    }
1×
386

387
    public void checkProg(WurstModel model) {
388
        checkProg(model, model);
1×
389
    }
1×
390

391
    public void checkProg(WurstModel model, List<CompilationUnit> toCheck) {
392
        for (CompilationUnit cu : toCheck) {
1×
393
            Preconditions.checkNotNull(cu);
1×
394
            if (!model.contains(cu)) {
1×
395
                // model has changed since then, no need to do 'toCheck'
396
                throw new ModelChangedException();
!
397
            }
398
        }
1×
399

400
        checker.checkProg(model, toCheck);
1×
401
    }
1×
402

403
    public JassProg transformProgToJass() {
404
        ImTranslator imTranslator2 = getImTranslator();
1×
405
        ImProg imProg2 = getImProg();
1×
406
        imTranslator2.assertProperties();
1×
407
        checkNoCompiletimeExpr(imProg2);
1×
408
        int stage = 2;
1×
409
        // eliminate
410
        beginPhase(2, "Eliminate generics");
1×
411
        new EliminateGenerics(imTranslator2, imProg2).transform();
1×
412
        printDebugImProg("./test-output/im " + stage++ + "_genericsEliminated.im");
1×
413

414
        // eliminate classes
415
        beginPhase(2, "translate classes");
1×
416

417
        new EliminateClasses(imTranslator2, imProg2, !runArgs.isUncheckedDispatch()).eliminateClasses();
1×
418
        imTranslator2.assertProperties();
1×
419
        printDebugImProg("./test-output/im " + stage++ + "_classesEliminated.im");
1×
420

421
        new VarargEliminator(imProg2).run();
1×
422
        printDebugImProg("./test-output/im " + stage++ + "_varargEliminated.im");
1×
423
        imTranslator2.assertProperties();
1×
424
        if (runArgs.isNoDebugMessages()) {
1×
425
            beginPhase(3, "remove debug messages");
!
426
            DebugMessageRemover.removeDebugMessages(imProg2);
!
427
        } else {
428
            // debug: add stacktraces
429
            if (runArgs.isIncludeStacktraces()) {
1×
430
                beginPhase(4, "add stack traces");
1×
431
                new StackTraceInjector2(imProg2, imTranslator2).transform(timeTaker);
1×
432
            }
433
        }
434
        imTranslator2.assertProperties();
1×
435

436
        ImOptimizer optimizer = new ImOptimizer(timeTaker, imTranslator2);
1×
437

438
        // inliner
439
        if (runArgs.isInline()) {
1×
440
            beginPhase(5, "inlining");
1×
441
            optimizer.doInlining();
1×
442
            imTranslator2.assertProperties();
1×
443

444
            printDebugImProg("./test-output/im " + stage++ + "_afterinline.im");
1×
445
        }
446

447
        // eliminate tuples
448
        beginPhase(6, "eliminate tuples");
1×
449
        getImProg().flatten(imTranslator2);
1×
450
        EliminateTuples.eliminateTuplesProg(getImProg(), imTranslator2);
1×
451
        getImTranslator().assertProperties(AssertProperty.NOTUPLES);
1×
452

453
        printDebugImProg("./test-output/im " + stage++ + "_withouttuples.im");
1×
454

455
        new MultiArrayEliminator(imProg2, imTranslator2, runArgs.isIncludeStacktraces() && !runArgs.isNoDebugMessages()).run();
1×
456
        printDebugImProg("./test-output/im " + stage++ + "_withoutmultiarrays.im");
1×
457
        imTranslator2.assertProperties();
1×
458

459
        beginPhase(7, "remove func refs");
1×
460
        new FuncRefRemover(imProg2, imTranslator2).run();
1×
461

462
        // remove cycles:
463
        beginPhase(8, "remove cyclic functions");
1×
464
        new CyclicFunctionRemover(imTranslator2, imProg2).work();
1×
465

466
        printDebugImProg("./test-output/im " + stage++ + "_nocyc.im");
1×
467

468
        // flatten
469
        beginPhase(9, "flatten");
1×
470
        getImProg().flatten(imTranslator2);
1×
471
        getImTranslator().assertProperties(AssertProperty.NOTUPLES, AssertProperty.FLAT);
1×
472

473
        printDebugImProg("./test-output/im " + stage++ + "_flat.im");
1×
474

475
        if (runArgs.isLocalOptimizations()) {
1×
476
            beginPhase(10, "local optimizations");
1×
477
            optimizer.localOptimizations();
1×
478
        }
479

480
        printDebugImProg("./test-output/im " + stage++ + "_afterlocalopts.im");
1×
481

482
        if (runArgs.isNullsetting()) {
1×
483
            beginPhase(11, "null setting");
1×
484
            optimizer.doNullsetting();
1×
485
            printDebugImProg("./test-output/im " + stage++ + "_afternullsetting.im");
1×
486
        }
487

488
        optimizer.removeGarbage();
1×
489
        imProg.flatten(imTranslator);
1×
490

491
        // Re-run to avoid #883
492
        optimizer.removeGarbage();
1×
493
        imProg.flatten(imTranslator);
1×
494

495
        printDebugImProg("./test-output/im " + stage++ + "_afterremoveGarbage1.im");
1×
496

497
        if (runArgs.isHotStartmap() || runArgs.isHotReload()) {
1×
498
            addJassHotCodeReloadCode();
!
499
        }
500
        if (runArgs.isOptimize()) {
1×
UNCOV
501
            beginPhase(12, "froptimize");
!
502
            optimizer.optimize();
!
503

UNCOV
504
            optimizer.removeGarbage();
!
505
            imProg.flatten(imTranslator);
!
506
            printDebugImProg("./test-output/im " + stage++ + "_afteroptimize.im");
!
507
        }
508

509

510

511
        // translate flattened intermediate lang to jass:
512

513
        beginPhase(13, "translate to jass");
1×
514
        getImTranslator().calculateCallRelationsAndUsedVariables();
1×
515
        ImToJassTranslator translator =
1×
516
                new ImToJassTranslator(getImProg(), getImTranslator().getCalledFunctions(), getImTranslator().getMainFunc(), getImTranslator().getConfFunc());
1×
517
        prog = translator.translate();
1×
518
        if (errorHandler.getErrorCount() > 0) {
1×
UNCOV
519
            prog = null;
!
520
        }
521
        timeTaker.endPhase();
1×
522
        return prog;
1×
523
    }
524

525
    private void addJassHotCodeReloadCode() {
UNCOV
526
        Preconditions.checkNotNull(imTranslator);
!
527
        Preconditions.checkNotNull(imProg);
!
528
        ImFunction mainFunc = imTranslator.getMainFunc();
!
529
        Preconditions.checkNotNull(mainFunc);
!
530
        Element trace = imProg.getTrace();
!
531

UNCOV
532
        List<ImStmt> stmts = new ArrayList<>();
!
533

534
        // add call to JHCR_Init_init in main
UNCOV
535
        stmts.add(callExtern(trace, CallType.EXECUTE, "JHCR_Init_init"));
!
536

537

538
        // add reload trigger for pressing escape
UNCOV
539
        ImStmts reloadBody = JassIm.ImStmts(
!
540
                callExtern(trace, CallType.EXECUTE, "JHCR_Init_parse"),
!
541
                callExtern(trace, CallType.NORMAL, "BJDebugMsg", JassIm.ImStringVal("Code reloaded!"))
!
542
        );
UNCOV
543
        ImFunction jhcr_reload = JassIm.ImFunction(trace, "jhcr_reload_on_escape", JassIm.ImTypeVars(), JassIm.ImVars(), JassIm.ImVoid(), JassIm.ImVars(), reloadBody, Collections.emptyList());
!
544

545

UNCOV
546
        ImVar trig = JassIm.ImVar(trace, TypesHelper.imTrigger(), "trig", false);
!
547
        mainFunc.getLocals().add(trig);
!
548
        // TriggerRegisterPlayerEventEndCinematic(trig, Player(0))
UNCOV
549
        stmts.add(JassIm.ImSet(trace, JassIm.ImVarAccess(trig), callExtern(trace, CallType.NORMAL, "CreateTrigger")));
!
550
        stmts.add(callExtern(trace, CallType.NORMAL, "TriggerRegisterPlayerEventEndCinematic", JassIm.ImVarAccess(trig),
!
551
                callExtern(trace, CallType.NORMAL, "Player", JassIm.ImIntVal(0))));
!
552
        stmts.add(callExtern(trace, CallType.NORMAL, "TriggerAddAction", JassIm.ImVarAccess(trig),
!
553
                JassIm.ImFuncRef(trace, jhcr_reload)));
!
554

UNCOV
555
        mainFunc.getBody().addAll(0, stmts);
!
556
    }
!
557

558
    @NotNull
559
    private ImFunctionCall callExtern(Element trace, CallType callType, String functionName, ImExpr... arguments) {
UNCOV
560
        ImFunction jhcrinit = JassIm.ImFunction(trace, functionName, JassIm.ImTypeVars(), JassIm.ImVars(), JassIm.ImVoid(), JassIm.ImVars(), JassIm.ImStmts(), Collections.singletonList(FunctionFlagEnum.IS_EXTERN));
!
561
        return JassIm.ImFunctionCall(trace, jhcrinit, JassIm.ImTypeArguments(), JassIm.ImExprs(arguments), true, callType);
!
562
    }
563

564
    public void checkNoCompiletimeExpr(ImProg prog) {
565
        prog.accept(new ImProg.DefaultVisitor() {
1×
566
            @Override
567
            public void visit(ImCompiletimeExpr e) {
UNCOV
568
                super.visit(e);
!
569
                throw new CompileError(e.attrTrace().attrSource(), "Compiletime expressions require compilation with '-runcompiletimefunctions' option.");
!
570
            }
571
        });
572
    }
1×
573

574
    private ImTranslator getImTranslator() {
575
        final ImTranslator t = imTranslator;
1×
576
        if (t != null) {
1×
577
            return t;
1×
578
        } else {
UNCOV
579
            throw new Error("translator not initialized");
!
580
        }
581
    }
582

583
    public @Nullable ImProg translateProgToIm(WurstModel root) {
584
        beginPhase(1, "to intermediate lang");
1×
585
        // translate wurst to intermediate lang:
586
        imTranslator = new ImTranslator(root, errorHandler.isUnitTestMode(), runArgs);
1×
587
        imProg = getImTranslator().translateProg();
1×
588
        int stage = 1;
1×
589
        printDebugImProg("./test-output/im " + stage++ + ".im");
1×
590
        timeTaker.endPhase();
1×
591
        return imProg;
1×
592
    }
593

594
    private void beginPhase(int phase, String description) {
595
        errorHandler.setProgress("Translating wurst. Phase " + phase + ": " + description, 0.6 + 0.01 * phase);
1×
596
        timeTaker.beginPhase(description);
1×
597
    }
1×
598

599
    private void printDebugImProg(String debugFile) {
600
        if (!errorHandler.isUnitTestMode() ) {
1×
601
            // output only in unit test mode
UNCOV
602
            return;
!
603
        }
604
        try {
605
            // TODO remove test output
606
            File file = new File(debugFile);
1×
607
            file.getParentFile().mkdirs();
1×
608
            try (Writer w = Files.newWriter(file, Charsets.UTF_8)) {
1×
609
                getImProg().print(w, 0);
1×
610
            }
UNCOV
611
        } catch (IOException e) {
!
612
            ErrorReporting.instance.handleSevere(e, getCompleteSourcecode());
!
613
        }
1×
614
    }
1×
615

616
    private WurstModel mergeCompilationUnits(List<CompilationUnit> compilationUnits) {
617
        gui.sendProgress("Merging Files");
1×
618
        WurstModel result = Ast.WurstModel();
1×
619
        for (CompilationUnit compilationUnit : compilationUnits) {
1×
620
            // remove from old parent
621
            compilationUnit.setParent(null);
1×
622
            result.add(compilationUnit);
1×
623
        }
1×
624
        return result;
1×
625
    }
626

627
    private CompilationUnit processMap(File file) {
UNCOV
628
        gui.sendProgress("Processing Map " + file.getName());
!
629
        if (!file.equals(mapFile)) {
!
630
            // TODO check if file != mapFile is possible, would be strange
631
            // so this should definitely be done differently
UNCOV
632
            throw new Error("file: " + file + " is not the mapfile: " + mapFile);
!
633
        }
634

UNCOV
635
        MpqEditor mapMpq = mapFileMpq;
!
636
        if (mapMpq == null) {
!
637
            throw new RuntimeException("map mpq is null");
!
638
        }
639

UNCOV
640
        if (runArgs.isNoExtractMapScript()) {
!
641
            return null;
!
642
        }
643

644
        // extract mapscript:
645
        try {
UNCOV
646
            byte[] tempBytes = mapMpq.extractFile("war3map.j");
!
647
            File tempFile = File.createTempFile("war3map", ".j", TempDir.get()); // TODO work directly with bytes without temp file
!
648
            tempFile.deleteOnExit();
!
649
            Files.write(tempBytes, tempFile);
!
650

UNCOV
651
            if (isWurstGenerated(tempFile)) {
!
652
                // the war3map.j file was generated by wurst
653
                // this should not be the case, as we will get duplicate function errors in this case
UNCOV
654
                throw new AbortCompilationException(
!
655
                        "Map was not saved correctly. Please try saving the map again.\n\n" + "This usually happens if you change the name of the map or \n"
656
                                + "if you have used the test-map-button without saving the map first.");
657
            }
658

659
            // move file to wurst directory
UNCOV
660
            File wurstFolder = new File(file.getParentFile(), "wurst");
!
661
            wurstFolder.mkdirs();
!
662
            if (!wurstFolder.isDirectory()) {
!
663
                throw new AbortCompilationException("Could not create Wurst folder at " + wurstFolder + ".");
!
664
            }
UNCOV
665
            File wurstwar3map = new File(wurstFolder, "war3map.j");
!
666
            wurstwar3map.delete();
!
667
            if (tempFile.renameTo(wurstwar3map)) {
!
668
                return parseFile(wurstwar3map);
!
669
            } else {
UNCOV
670
                throw new Error("Could not move war3map.j from " + tempFile + " to " + wurstwar3map);
!
671
            }
UNCOV
672
        } catch (RuntimeException e) {
!
673
            throw e;
!
674
        } catch (Exception e) {
!
675
            throw new Error(e);
!
676
        }
677

678
    }
679

680
    private boolean isWurstGenerated(File tempFile) {
UNCOV
681
        try (FileReader fr = new FileReader(tempFile); BufferedReader in = new BufferedReader(fr)) {
!
682
            String firstLine = in.readLine();
!
683
            WLogger.info("firstLine = '" + firstLine + "'");
!
684
            return firstLine.equals(JassPrinter.WURST_COMMENT);
!
685
        } catch (IOException e) {
!
686
            WLogger.severe(e);
!
687
        }
UNCOV
688
        return false;
!
689
    }
690

691
    private CompilationUnit parseFile(File file) {
692
        if (file.isDirectory()) {
1×
UNCOV
693
            throw new Error("Is a directory: " + file);
!
694
        }
695
        parsedFiles.add(file);
1×
696

697
        gui.sendProgress("Parsing File " + file.getName());
1×
698
        String source = file.getAbsolutePath();
1×
699
        try (Reader reader = FileReading.getFileReader(file)) {
1×
700
            // scanning
701
            return parse(source, reader);
1×
702

UNCOV
703
        } catch (CompileError e) {
!
704
            gui.sendError(e);
!
705
            return emptyCompilationUnit();
!
706
        } catch (FileNotFoundException e) {
!
707
            gui.sendError(new CompileError(new WPos(source, LineOffsets.dummy, 0, 0), "File not found."));
!
708
            return emptyCompilationUnit();
!
709
        } catch (IOException e) {
!
710
            gui.sendError(new CompileError(new WPos(source, LineOffsets.dummy, 0, 0), "Could not read file."));
!
711
            return emptyCompilationUnit();
!
712
        }
713
    }
714

715
    public CompilationUnit parse(String fileName, Reader reader) {
716
        if (fileName.endsWith(".j")) {
1×
717
            return parser.parseJass(reader, fileName, hasCommonJ);
1×
718
        }
719
        if (fileName.endsWith(".jurst")) {
1×
720
            return parser.parseJurst(reader, fileName, hasCommonJ);
1×
721
        }
722
        return parser.parse(reader, fileName, hasCommonJ);
1×
723
    }
724

725
    private CompilationUnit emptyCompilationUnit() {
UNCOV
726
        return parser.emptyCompilationUnit();
!
727
    }
728

729
    public @Nullable JassProg getProg() {
UNCOV
730
        return prog;
!
731
    }
732

733
    public void loadReader(String name, Reader input) {
734
        otherInputs.put(name, input);
1×
735
    }
1×
736

737
    public void setHasCommonJ(boolean hasCommonJ) {
738
        this.hasCommonJ = hasCommonJ;
1×
739
    }
1×
740

741
    public ImProg getImProg() {
742
        final ImProg imProg2 = imProg;
1×
743
        if (imProg2 != null) {
1×
744
            return imProg2;
1×
745
        } else {
UNCOV
746
            throw new Error("imProg is null");
!
747
        }
748
    }
749

750
    public @Nullable File getMapFile() {
751
        return mapFile;
1×
752
    }
753

754
    public ErrorHandler getErrorHandler() {
755
        return errorHandler;
1×
756
    }
757

758
    public String getCompleteSourcecode() {
759

UNCOV
760
        StringBuilder sb = new StringBuilder();
!
761
        try {
UNCOV
762
            for (File f : parsedFiles) {
!
763
                sb.append(" //######################################################\n");
!
764
                sb.append(" // File ").append(f.getAbsolutePath()).append("\n");
!
765
                sb.append(" //######################################################\n");
!
766
                sb.append(Files.toString(f, Charsets.UTF_8));
!
767
            }
!
768

UNCOV
769
            for (Entry<String, Reader> entry : otherInputs.entrySet()) {
!
770
                sb.append(" //######################################################\n");
!
771
                sb.append(" // Input ").append(entry.getKey()).append("\n");
!
772
                sb.append(" //######################################################\n");
!
773
                try (Reader reader = entry.getValue()) {
!
774
                    char[] buffer = new char[1024];
!
775
                    while (true) {
UNCOV
776
                        int len = reader.read(buffer);
!
777
                        if (len < 0) {
!
778
                            break;
!
779
                        }
UNCOV
780
                        sb.append(buffer, 0, len);
!
781
                    }
!
782
                }
UNCOV
783
            }
!
784
        } catch (Throwable t) {
!
785
            sb.append(Utils.printExceptionWithStackTrace(t));
!
786
            WLogger.severe(t);
!
787
        }
!
788
        return sb.toString();
!
789
    }
790

791
    public void setRunArgs(RunArgs runArgs) {
792
        this.runArgs = runArgs;
1×
793
    }
1×
794

795
    public void setMapFile(File mapFile) {
UNCOV
796
        this.mapFile = mapFile;
!
797
    }
!
798

799
    public @Nullable MpqEditor getMapfileMpqEditor() {
800
        return mapFileMpq;
1×
801
    }
802

803
    public LuaCompilationUnit transformProgToLua() {
804

805
        if (runArgs.isNoDebugMessages()) {
1×
UNCOV
806
            beginPhase(3, "remove debug messages");
!
807
            DebugMessageRemover.removeDebugMessages(imProg);
!
808
        } else {
809
            // debug: add stacktraces
810
            if (runArgs.isIncludeStacktraces()) {
1×
UNCOV
811
                beginPhase(4, "add stack traces");
!
812
                new StackTraceInjector2(imProg, imTranslator).transform(timeTaker);
!
813
            }
814
        }
815

816
        LuaTranslator luaTranslator = new LuaTranslator(imProg, imTranslator);
1×
817
        LuaCompilationUnit luaCode = luaTranslator.translate();
1×
818
        return luaCode;
1×
819
    }
820
}
Troubleshooting · Open an Issue · Sales · Support · ENTERPRISE · CAREERS · STATUS
BLOG · TWITTER · Legal & Privacy · Supported CI Services · What's a CI service? · Automated Testing

© 2022 Coveralls, Inc