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

wurstscript / WurstScript / 215

08 Nov 2023 06:49PM CUT coverage: 62.561% (-0.04%) from 62.602%
215

Pull #1081

circleci

Frotty
fixes and master merge
Pull Request #1081: More performance improvements

17307 of 27664 relevant lines covered (62.56%)

0.63 hits per line

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

62.64
de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/utils/Utils.java
1
package de.peeeq.wurstscript.utils;
2

3
import com.google.common.base.Function;
4
import com.google.common.base.Preconditions;
5
import com.google.common.collect.*;
6
import com.google.common.collect.ImmutableList.Builder;
7
import com.google.common.io.Files;
8
import de.peeeq.wurstio.Pjass;
9
import de.peeeq.wurstscript.ast.*;
10
import de.peeeq.wurstscript.attributes.CompileError;
11
import de.peeeq.wurstscript.attributes.names.NameLink;
12
import de.peeeq.wurstscript.attributes.prettyPrint.DefaultSpacer;
13
import de.peeeq.wurstscript.jassIm.JassImElementWithName;
14
import de.peeeq.wurstscript.parser.WPos;
15
import de.peeeq.wurstscript.translation.imoptimizer.Replacer;
16
import de.peeeq.wurstscript.types.WurstType;
17
import de.peeeq.wurstscript.types.WurstTypeUnknown;
18
import org.eclipse.jdt.annotation.Nullable;
19
import org.jetbrains.annotations.NotNull;
20

21
import java.awt.event.MouseAdapter;
22
import java.awt.event.MouseEvent;
23
import java.awt.event.MouseListener;
24
import java.io.*;
25
import java.time.Duration;
26
import java.util.*;
27
import java.util.Map.Entry;
28
import java.util.concurrent.TimeUnit;
29
import java.util.function.*;
30
import java.util.stream.Collector;
31
import java.util.stream.Collectors;
32

33
public class Utils {
×
34

35
    @SuppressWarnings("rawtypes")
36
    public static int size(Iterable<?> i) {
37
        if (i instanceof Collection) {
1✔
38
            return ((Collection) i).size();
1✔
39
        }
40
        int size = 0;
×
41
        for (@SuppressWarnings("unused")
42
                Object o : i) {
×
43
            size++;
×
44
        }
×
45
        return size;
×
46
    }
47

48
    public static void printIndent(StringBuilder sb, int indent) {
49
        for (int i = 0; i < indent; i++) {
1✔
50
            sb.append("\t");
1✔
51
        }
52
    }
1✔
53

54

55
    @SafeVarargs
56
    public static <T> List<T> list(T... args) {
57
        List<T> result = new NotNullList<>();
1✔
58
        Collections.addAll(result, args);
1✔
59
        return result;
1✔
60
    }
61

62
    public static <T> List<T> removedDuplicates(List<T> list) {
63
        List<T> result = new NotNullList<>();
1✔
64
        for (T t : list) {
1✔
65
            if (!result.contains(t)) {
1✔
66
                result.add(t);
1✔
67
            }
68
        }
1✔
69
        return result;
1✔
70

71
    }
72

73

74
    public static <T> void printSep(StringBuilder sb, String seperator, T[] args) {
75
        for (int i = 0; i < args.length; i++) {
×
76
            if (i > 0) {
×
77
                sb.append(seperator);
×
78
            }
79
            sb.append(args[i]);
×
80
        }
81
    }
×
82

83

84
    public static int parseInt(String yytext) {
85
        if (yytext.startsWith("0")) {
1✔
86
            return Integer.parseInt(yytext, 8);
1✔
87
        } else {
88
            return Integer.parseInt(yytext);
1✔
89
        }
90
    }
91

92
    public static int parseAsciiInt(String yytext) throws NumberFormatException {
93
        if (yytext.length() == 3) {
1✔
94
            // 'x' can directly return
95
            return yytext.charAt(1);
1✔
96
        }
97
        int result = 0;
1✔
98
        int i = 1;
1✔
99
        int chars = 0;
1✔
100
        for (; i < yytext.length() - 1; i++) {
1✔
101
            if (yytext.charAt(i) == '\\') {
1✔
102
                i++;
1✔
103
            }
104
            result = result * 256 + yytext.charAt(i);
1✔
105
            chars++;
1✔
106
        }
107
        if (chars != 1 && chars != 4) {
1✔
108
            throw new NumberFormatException("Ascii ints must have 4 or 1 characters but this one has " + chars + " characters.");
×
109
        }
110
        return result;
1✔
111
    }
112

113
    public static int parseOctalInt(String yytext) {
114
        return (int) Long.parseLong(yytext, 8);
1✔
115
    }
116

117
    public static int parseHexInt(String yytext, int offset) {
118
        if (yytext.startsWith("-")) {
1✔
119
            return (int) -Long.parseLong(yytext.substring(offset+1), 16);
1✔
120
        } else {
121
            return (int) Long.parseLong(yytext.substring(offset), 16);
1✔
122
        }
123
    }
124

125
    public static <T> String printSep(String sep, T[] args) {
126
        StringBuilder sb = new StringBuilder();
×
127
        printSep(sb, sep, args);
×
128
        return sb.toString();
×
129
    }
130

131
    public static String printSep(String sep, List<?> args) {
132
        return args.stream().map(String::valueOf).collect(Collectors.joining(sep));
×
133
    }
134

135
    /**
136
     * is a piece of code jass code?
137
     */
138
    public static boolean isJassCode(@Nullable Element pos) {
139
        while (pos != null) {
1✔
140
            if (pos instanceof WPackage) {
1✔
141
                return false; // code is inside package -> wurstscript code
1✔
142
            }
143
            pos = pos.getParent();
1✔
144
        }
145
        return true; // no package found -> jass code
1✔
146
    }
147

148
    public static <T> String join(Iterable<T> hints, String seperator) {
149
        StringBuilder builder = new StringBuilder();
1✔
150
        boolean first = true;
1✔
151
        for (T s : hints) {
1✔
152
            if (!first) {
1✔
153
                builder.append(seperator);
1✔
154
            }
155
            builder.append(s);
1✔
156
            first = false;
1✔
157
        }
1✔
158
        return builder.toString();
1✔
159
    }
160

161
    public static <T> String join(T[] arguments, String seperator) {
162
        StringBuilder builder = new StringBuilder();
1✔
163
        boolean first = true;
1✔
164
        for (T s : arguments) {
1✔
165
            if (!first) {
1✔
166
                builder.append(seperator);
1✔
167
            }
168
            builder.append(s);
1✔
169
            first = false;
1✔
170
        }
171
        return builder.toString();
1✔
172
    }
173

174

175
    /**
176
     * sorts a list with partitial ordering topologically. If a > b then a will
177
     * appear before b in the result list
178
     *
179
     * @param items       items to sort
180
     * @param biggerItems a function to get all the bigger items for a given item
181
     * @return a sorted list
182
     * @throws TopsortCycleException if there exist items a,b so that a > b and b > a
183
     */
184
    public static <T> List<T> topSort(Collection<T> items,
185
                                      java.util.function.Function<T, ? extends Collection<T>> biggerItems)
186
            throws TopsortCycleException {
187
        Set<T> visitedItems = new HashSet<>();
1✔
188
        List<T> result = new ArrayList<>(items.size());
1✔
189
        LinkedList<T> activeItems = Lists.newLinkedList();
1✔
190
        for (T t : items) {
1✔
191
            if (t == null)
1✔
192
                throw new IllegalArgumentException();
×
193
            topSortHelper(result, visitedItems, activeItems, biggerItems::apply, t);
1✔
194
        }
1✔
195
        return result;
1✔
196
    }
197

198

199
    private static <T> void topSortHelper(List<T> result, Set<T> visitedItems,
200
                                          LinkedList<T> activeItems,
201
                                          Function<T, ? extends Collection<T>> biggerItems, T item)
202
            throws TopsortCycleException {
203
        if (visitedItems.contains(item)) {
1✔
204
            return;
1✔
205
        }
206
        if (activeItems.contains(item)) { // This is not constant time, could be
1✔
207
            // more efficient
208
            while (activeItems.get(0) != item) {
×
209
                activeItems.remove(0);
×
210
            }
211
            throw new TopsortCycleException(activeItems);
×
212
        }
213
        activeItems.add(item);
1✔
214
        visitedItems.add(item);
1✔
215
        for (T t : biggerItems.apply(item)) {
1✔
216
            if (t == null)
1✔
217
                throw new IllegalArgumentException();
×
218
            topSortHelper(result, visitedItems, activeItems, biggerItems, t);
1✔
219
        }
1✔
220
        result.add(item);
1✔
221
        activeItems.removeLast();
1✔
222
    }
1✔
223

224
    @SafeVarargs
225
    public static <T> boolean oneOf(T obj, T... ts) {
226
        for (T t : ts) {
1✔
227
            if (t.equals(obj)) {
1✔
228
                return true;
1✔
229
            }
230
        }
231
        return false;
1✔
232
    }
233

234

235
    public static <T> T getFirst(Iterable<T> ts) {
236
        for (T t : ts) {
1✔
237
            return t;
1✔
238
        }
239
        throw new Error("collection has no first element");
×
240
    }
241

242
    public static <T> T getLast(List<T> ts) {
243
        return ts.get(ts.size() - 1);
1✔
244
    }
245

246

247
    public static <T extends Element> String printElement(Optional<T> el) {
248
        return el.map(e -> {
1✔
249
            String type = makeReadableTypeName(e);
1✔
250
            String name = "";
1✔
251
            if (e instanceof ExprFunctionCall) {
1✔
252
                ExprFunctionCall fc = (ExprFunctionCall) e;
1✔
253
                return "function call " + fc.getFuncName() + "()";
1✔
254
            } else if (e instanceof FuncDef) {
1✔
255
                FuncDef fd = (FuncDef) e;
1✔
256
                return "function " + fd.getName();
1✔
257
            } else if (e instanceof OnDestroyDef) {
1✔
258
                return "destroy function for "
×
259
                        + e.attrNearestStructureDef().getName();
×
260
            } else if (e instanceof ConstructorDef) {
1✔
261
                return "constructor for " + e.attrNearestStructureDef().getName();
×
262
            } else if (e instanceof LocalVarDef) {
1✔
263
                LocalVarDef l = (LocalVarDef) e;
1✔
264
                return "local variable " + l.getName();
1✔
265
            } else if (e instanceof VarDef) {
1✔
266
                VarDef l = (VarDef) e;
1✔
267
                return "variable " + l.getName();
1✔
268
            } else if (e instanceof AstElementWithNameId) {
1✔
269
                name = ((AstElementWithNameId) e).getNameId().getName();
1✔
270
            } else if (e instanceof WImport) {
1✔
271
                WImport wImport = (WImport) e;
1✔
272
                return "import " + wImport.getPackagename();
1✔
273
            } else if (e instanceof TypeExprSimple) {
1✔
274
                TypeExprSimple t = (TypeExprSimple) e;
×
275
                name = t.getTypeName();
×
276
                if (t.getTypeArgs().size() > 0) {
×
277
                    name += "{";
×
278
                    boolean first = true;
×
279
                    StringBuilder builder = new StringBuilder();
×
280
                    builder.append(name);
×
281
                    for (TypeExpr ta : t.getTypeArgs()) {
×
282
                        if (!first) {
×
283
                            builder.append(", ");
×
284
                        }
285
                        builder.append(printElement(ta));
×
286
                        first = false;
×
287
                    }
×
288
                    name = builder.toString();
×
289
                    name += "}";
×
290
                }
291
                type = "type";
×
292
            }
293
            return type + " " + name;
1✔
294
        }).orElse("null");
1✔
295
    }
296

297
    public static String printElement(@Nullable Element e) {
298
        return printElement(Optional.ofNullable(e));
1✔
299
    }
300

301
    private static String makeReadableTypeName(Element e) {
302
        String type = e.getClass().getName()
1✔
303
                .replaceAll("de.peeeq.wurstscript.ast.", "")
1✔
304
                .replaceAll("Impl$", "").replaceAll("Def$", "").toLowerCase();
1✔
305
        if (type.equals("wpackage")) {
1✔
306
            type = "package";
1✔
307
        }
308
        return type;
1✔
309
    }
310

311
    public static int inBorders(int min, int x, int max) {
312
        return Math.max(min, Math.min(max, x));
×
313
    }
314

315
    public static String printStackTrace(StackTraceElement[] stackTrace) {
316
        StringBuilder builder = new StringBuilder();
×
317
        for (StackTraceElement s : stackTrace) {
×
318
            builder.append(s.toString());
×
319
            builder.append("\n");
×
320
        }
321
        return builder.toString();
×
322
    }
323

324
    public static String printExceptionWithStackTrace(Throwable t) {
325
        StringBuilder builder = new StringBuilder();
×
326
        builder.append(t);
×
327
        builder.append("\n");
×
328
        for (; ; ) {
329
            for (StackTraceElement s : t.getStackTrace()) {
×
330
                builder.append(s.toString());
×
331
                builder.append("\n");
×
332
            }
333
            t = t.getCause();
×
334
            if (t == null) {
×
335
                break;
×
336
            }
337
            builder.append("Caused by: ").append(t.toString()).append("\n");
×
338
        }
339
        return builder.toString();
×
340
    }
341

342

343
    public static Optional<Element> getAstElementAtPos(Element elem,
344
                                             int caretPosition, boolean usesMouse) {
345
        List<Element> betterResults = Lists.newArrayList();
×
346
        for (int i = 0; i < elem.size(); i++) {
×
347
            getAstElementAtPos(elem.get(i), caretPosition, usesMouse).map(betterResults::add);
×
348
        }
349
        if (betterResults.size() == 0) {
×
350
            if (elem instanceof Identifier) {
×
351
                return Optional.ofNullable(elem.getParent());
×
352
            }
353
            return Optional.ofNullable(elem);
×
354
        } else {
355
            return bestResult(betterResults);
×
356
        }
357
    }
358

359
    public static Optional<Element> getAstElementAtPos(Element elem, int line, int column, boolean usesMouse) {
360
        if (elem instanceof ModuleInstanciation) {
1✔
361
            // do not helicopter into module instantiations
362
            return Optional.of(elem);
×
363
        }
364
        List<Element> betterResults = Lists.newArrayList();
1✔
365
        for (int i = 0; i < elem.size(); i++) {
1✔
366
            Element e = elem.get(i);
1✔
367
            if (elementContainsPos(e, line, column, usesMouse) || e.attrSource().isArtificial()) {
1✔
368
                getAstElementAtPos(e, line, column, usesMouse).map(betterResults::add);
1✔
369
            }
370
        }
371
        Optional<Element> bestResult = bestResult(betterResults);
1✔
372
        if (!bestResult.isPresent()) {
1✔
373
            if (elem instanceof Identifier) {
1✔
374
                return Optional.ofNullable(elem.getParent());
1✔
375
            }
376
            return Optional.of(elem);
1✔
377
        } else {
378
            return bestResult;
1✔
379
        }
380
    }
381

382

383
    public static Optional<Element> getAstElementAtPosIgnoringLists(Element elem,
384
                                                          int caretPosition, boolean usesMouse) {
385
        Optional<Element> r = getAstElementAtPos(elem, caretPosition, usesMouse);
×
386
        while (r.isPresent() && r.get() instanceof List<?>) {
×
387
            r = r.flatMap(el -> Optional.ofNullable(el.getParent()));
×
388
        }
389
        return r;
×
390
    }
391

392
    /**
393
     * return the element with the smallest size
394
     */
395
    private static Optional<Element> bestResult(List<Element> betterResults) {
396
        int minSize = Integer.MAX_VALUE;
1✔
397
        Optional<Element> min = Optional.empty();
1✔
398
        for (Element e : betterResults) {
1✔
399
            WPos source = e.attrSource();
1✔
400
            int size = source.isArtificial() ?
1✔
401
                    Integer.MAX_VALUE
1✔
402
                    : source.getRightPos() - source.getLeftPos();
1✔
403
            if (size < minSize) {
1✔
404
                minSize = size;
1✔
405
                min = Optional.of(e);
1✔
406
            }
407
        }
1✔
408
        return min;
1✔
409
    }
410

411
    public static boolean elementContainsPos(Element e, int pos, boolean usesMouse) {
412
        return e.attrSource().getLeftPos() <= pos
×
413
                && e.attrSource().getRightPos() >= pos + (usesMouse ? 1 : 0);
×
414
    }
415

416
    private static boolean elementContainsPos(Element e, int line, int column, boolean usesMouse) {
417
        WPos pos = e.attrSource();
1✔
418
        if (pos.getLine() > line) {
1✔
419
            return false;
1✔
420
        }
421
        if (pos.getEndLine() < line) {
1✔
422
            return false;
1✔
423
        }
424
        return (pos.getLine() < line || pos.getStartColumn() <= column)
1✔
425
                && (pos.getEndLine() > line || pos.getEndColumn() >= column);
1✔
426
    }
427

428

429
    public static <T extends NameDef> List<T> sortByName(
430
            Collection<T> c) {
431
        List<T> r = Lists.newArrayList(c);
1✔
432
        r.sort(Comparator.comparing(NameDef::getName));
1✔
433
        return r;
1✔
434
    }
435

436
    public static String printPos(WPos source) {
437
        return source.getFile() + ", line " + source.getLine();
1✔
438
    }
439

440
    public static boolean isEmptyCU(Optional<CompilationUnit> cu) {
441
        return !cu.isPresent()
×
442
                || (cu.get().getJassDecls().size() + cu.get().getPackages().size() == 0);
×
443
    }
444

445
    public static String printElementWithSource(Optional<Element> e) {
446
        Optional<WPos> src = e.map(Element::attrSource);
1✔
447
        return printElement(e) + " (" + src.map(WPos::printShort).orElse("unknown position") + ")";
1✔
448
    }
449

450
    public static int[] copyArray(int[] ar) {
451
        int[] r = new int[ar.length];
×
452
        System.arraycopy(ar, 0, r, 0, ar.length);
×
453
        return r;
×
454
    }
455

456
    public static String toFirstUpper(String s) {
457
        if (s.isEmpty()) {
×
458
            return s;
×
459
        }
460
        return s.substring(0, 1).toUpperCase() + s.substring(1);
×
461
    }
462

463
    public static Optional<VarDef> getParentVarDef(Optional<Element> node) {
464
        while (node.isPresent()) {
1✔
465
            if (node.get() instanceof VarDef) {
1✔
466
                return node.map(n -> (VarDef) n);
1✔
467
            }
468
            node = node.map(Element::getParent);
1✔
469
        }
470
        return null;
1✔
471
    }
472

473

474
    public static String printAlternatives(Collection<? extends NameLink> alternatives) {
475
        List<String> result = Lists.newArrayList();
1✔
476
        for (NameLink a : alternatives) {
1✔
477
            WPos source = a.getDef().attrSource();
1✔
478
            String s = Utils.printElement(a.getDef()) + " defined in line "
1✔
479
                    + source.getLine() + " (" + source.getFile() + ")";
1✔
480
            result.add(s);
1✔
481
        }
1✔
482
        return " * " + Utils.join(result, "\n * ");
1✔
483
    }
484

485
    public static <T, S> Multimap<T, S> inverse(Multimap<S, T> orig) {
486
        Multimap<T, S> result = LinkedHashMultimap.create();
×
487
        for (Entry<S, T> e : orig.entries()) {
×
488
            result.put(e.getValue(), e.getKey());
×
489
        }
×
490
        return result;
×
491
    }
492

493
    public static <T extends Comparable<? extends T>, S> TreeMap<T, Set<S>> inverseMapToSet(Map<S, T> orig) {
494
        TreeMap<T, Set<S>> result = new TreeMap<>();
1✔
495
        for (Entry<S, T> e : orig.entrySet()) {
1✔
496
            result.computeIfAbsent(e.getValue(), x -> new LinkedHashSet<>()).add(e.getKey());
1✔
497
        }
1✔
498
        return result;
1✔
499
    }
500

501

502
    public static boolean isSubsequenceIgnoreCase(String a, String b) {
503
        int bPos = -1;
1✔
504
        for (int i = 0; i < a.length(); i++) {
1✔
505
            char c = Character.toLowerCase(a.charAt(i));
1✔
506
            do {
507
                bPos++;
1✔
508
                if (bPos >= b.length()) {
1✔
509
                    return false;
1✔
510
                }
511
            } while (Character.toLowerCase(b.charAt(bPos)) != c);
1✔
512
        }
513
        return true;
1✔
514
    }
515

516
    public static boolean isSubsequence(String a, String b) {
517
        int bPos = -1;
×
518
        for (int i = 0; i < a.length(); i++) {
×
519
            char c = a.charAt(i);
×
520
            do {
521
                bPos++;
×
522
                if (bPos >= b.length()) {
×
523
                    return false;
×
524
                }
525
            } while (b.charAt(bPos) != c);
×
526
        }
527
        return true;
×
528
    }
529

530

531
    public static List<Integer> subsequenceLengthes(String a, String b) {
532
        List<Integer> subseqLength = Lists.newArrayList();
1✔
533
        while (!a.isEmpty()) {
1✔
534
            int prefixlen = a.length();
1✔
535
            while (prefixlen > 0 && !containsPrefix(b, a, prefixlen)) {
1✔
536
                prefixlen--;
1✔
537
            }
538
            if (prefixlen == 0) {
1✔
539
                subseqLength.add(0);
×
540
                break;
×
541
            }
542
            subseqLength.add(prefixlen);
1✔
543
            String found = a.substring(0, prefixlen);
1✔
544
            b = b.substring(prefixlen + b.indexOf(found));
1✔
545
            a = a.substring(prefixlen);
1✔
546

547
        }
1✔
548
        return subseqLength;
1✔
549
    }
550

551
    /**
552
     * checks if b contains the first n characters of a as a substring
553
     */
554
    private static boolean containsPrefix(String b, String a, int n) {
555
        return b.contains(a.substring(0, n));
1✔
556
    }
557

558
    public static <T> T getFirstAndOnly(Collection<T> c) {
559
        if (c.size() != 1) {
1✔
560
            throw new Error("Size must be 1 but was " + c.size());
×
561
        }
562
        return getFirst(c);
1✔
563
    }
564

565
    private static void escapeStringParts(String v, StringBuilder builder) {
566
        for (int i = 0; i < v.length(); i++) {
1✔
567
            char c = v.charAt(i);
1✔
568
            switch (c) {
1✔
569
                case '\n':
570
                    builder.append("\\n");
1✔
571
                    break;
1✔
572
                case '\r':
573
                    builder.append("\\r");
1✔
574
                    break;
1✔
575
                case '\"':
576
                    builder.append("\\\"");
1✔
577
                    break;
1✔
578
                case '\t':
579
                    builder.append("\\t");
1✔
580
                    break;
1✔
581
                case '\\':
582
                    builder.append("\\\\");
1✔
583
                    break;
1✔
584
                default:
585
                    builder.append(c);
1✔
586
            }
587
        }
588
    }
1✔
589

590
    public static String escapeStringWithoutQuotes(String v) {
591
        StringBuilder builder = new StringBuilder();
×
592
        escapeStringParts(v, builder);
×
593
        return builder.toString();
×
594
    }
595

596
    public static String escapeString(String v) {
597
        StringBuilder builder = new StringBuilder();
1✔
598
        builder.append("\"");
1✔
599
        escapeStringParts(v, builder);
1✔
600
        builder.append("\"");
1✔
601
        return builder.toString();
1✔
602
    }
603

604
    public static String escapeHtml(String s) {
605
        s = s.replace("<", "&lt;");
×
606
        s = s.replace(">", "&gt;");
×
607
        return s;
×
608
    }
609

610
    /**
611
     * returns the filename from the given path
612
     */
613
    public static String fileName(String path) {
614
        int pos = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
1✔
615
        if (pos > 0) {
1✔
616
            return path.substring(pos + 1);
1✔
617
        }
618
        return path;
×
619
    }
620

621
    public static String printException(Throwable e) {
622
        return e + "\n" + Utils.printExceptionWithStackTrace(e);
×
623
    }
624

625

626
    public static String stripHtml(String s) {
627
        return s.replaceAll("<.*?>", "");
×
628
    }
629

630

631
    public static <T> Iterable<T> iterateReverse(final List<T> elements) {
632
        return () -> new Iterator<T>() {
×
633

634
            ListIterator<T> it = elements.listIterator(elements.size());
×
635

636
            @Override
637
            public boolean hasNext() {
638
                return it.hasPrevious();
×
639
            }
640

641
            @Override
642
            public T next() {
643
                return it.previous();
×
644
            }
645

646
            @Override
647
            public void remove() {
648
                it.remove();
×
649
            }
×
650
        };
651
    }
652

653

654
    public static String readWholeStream(BufferedReader r) throws IOException {
655
        StringBuilder sb = new StringBuilder();
×
656
        Optional<String> line;
657
        while ((line = Optional.ofNullable(r.readLine())).isPresent()) {
×
658
            line.map(sb::append);
×
659
        }
660
        return sb.toString();
×
661
    }
662

663
    public static String readWholeStream(InputStream inputStream) throws IOException {
664
        return readWholeStream(new BufferedReader(new InputStreamReader(inputStream)));
×
665
    }
666

667

668
    @SuppressWarnings("unchecked")
669
    public static <T extends Element> Optional<T> getNearestByType(Optional<Element> e, Class<T> clazz) {
670
        while (e.isPresent()) {
1✔
671
            if (clazz.isInstance(e.get())) {
1✔
672
                return Optional.of((T) e.get());
1✔
673
            }
674
            e = e.flatMap(el -> Optional.ofNullable(el.getParent()));
1✔
675
        }
676
        return Optional.empty();
1✔
677
    }
678

679

680
    public static <T extends JassImElementWithName> Comparator<T> compareByNameIm() {
681
        return Comparator.comparing(JassImElementWithName::getName);
×
682
    }
683

684
    public static String getParameterListText(AstElementWithParameters f) {
685
        StringBuilder descr = new StringBuilder();
1✔
686
        for (WParameter p : f.getParameters()) {
1✔
687
            if (descr.length() > 0) {
1✔
688
                descr.append(", ");
1✔
689
            }
690
            descr.append(p.attrTyp()).append(" ").append(p.getName());
1✔
691
        }
1✔
692
        return descr.toString();
1✔
693
    }
694

695
    public static <T> List<T> subList(List<T> l, int start) {
696
        return subList(l, start, l.size() - 1);
1✔
697
    }
698

699
    public static <T> List<T> subList(List<T> l, int start, int stop) {
700
        List<T> result = Lists.newArrayListWithCapacity(stop - start);
1✔
701
        for (int i = start; i <= stop; i++) {
1✔
702
            result.add(l.get(i));
1✔
703
        }
704
        return result;
1✔
705
    }
706

707
    public static <K, V> ImmutableMap<K, V> mergeMaps(
708
            ImmutableMap<K, V> a,
709
            ImmutableMap<K, V> b,
710
            Function2<V, V, V> mergeFunc) {
711
        if (a.isEmpty()) return b;
1✔
712
        if (b.isEmpty()) return a;
1✔
713

714
        ImmutableMap.Builder<K, V> builder = ImmutableMap.builder();
1✔
715

716
        for (Entry<K, V> e : a.entrySet()) {
1✔
717
            K key = e.getKey();
1✔
718
            if (b.containsKey(key)) {
1✔
719
                builder.put(key, mergeFunc.apply(e.getValue(), b.get(key)));
1✔
720
            } else {
721
                builder.put(e);
×
722
            }
723
        }
1✔
724

725
        for (Entry<K, V> e : b.entrySet()) {
1✔
726
            K key = e.getKey();
1✔
727
            if (!a.containsKey(key)) {
1✔
728
                builder.put(e);
×
729
            }
730
        }
1✔
731

732
        return builder.build();
1✔
733
    }
734

735
    public static <K, V> ImmutableSetMultimap<K, V> mergeMultiMaps(
736
            ImmutableSetMultimap<K, V> a, ImmutableSetMultimap<K, V> b) {
737
        if (a.isEmpty()) return b;
1✔
738
        if (b.isEmpty()) return a;
1✔
739

740
        ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder();
1✔
741
        builder.putAll(a);
1✔
742
        builder.putAll(b);
1✔
743
        return builder.build();
1✔
744
    }
745

746
    public static <T> ImmutableSet<T> mergeSets(ImmutableSet<T> a, ImmutableSet<T> b) {
747
        ImmutableSet.Builder<T> builder = ImmutableSet.<T>builder();
1✔
748
        builder.addAll(a).addAll(b);
1✔
749
        return builder.build();
1✔
750
    }
751

752
    public static <T> T[] joinArrays(T[] a, T[] b) {
753
        T[] res = Arrays.copyOf(a, a.length + b.length);
1✔
754
        System.arraycopy(b, 0, res, a.length, b.length);
1✔
755
        return res;
1✔
756
    }
757

758
    public static <K, V> void removeValuesFromMap(Map<K, V> map, Collection<V> removed) {
759
        map.entrySet().removeIf(e -> removed.contains(e.getValue()));
×
760
    }
×
761

762
    public static <T> ImmutableList<T> emptyList() {
763
        return ImmutableList.of();
×
764
    }
765

766
    public static <T>
767
    Collector<T, ?, ImmutableList<T>> toImmutableList() {
768
        return new Collector<T, Builder<T>, ImmutableList<T>>() {
1✔
769

770
            @Override
771
            public Supplier<Builder<T>> supplier() {
772
                return ImmutableList::builder;
1✔
773
            }
774

775
            @Override
776
            public BiConsumer<Builder<T>, T> accumulator() {
777
                return Builder::add;
1✔
778
            }
779

780
            @Override
781
            public BinaryOperator<Builder<T>> combiner() {
782
                return (a, b) -> a.addAll(b.build());
1✔
783
            }
784

785
            @Override
786
            public java.util.function.Function<Builder<T>, ImmutableList<T>> finisher() {
787
                return Builder::build;
1✔
788
            }
789

790
            @Override
791
            public Set<Characteristics> characteristics() {
792
                return Collections.emptySet();
1✔
793
            }
794
        };
795
    }
796

797
    public static MouseListener onClickDo(Consumer<MouseEvent> onclick) {
798
        return new MouseAdapter() {
×
799
            @Override
800
            public void mouseClicked(@Nullable MouseEvent e) {
801
                Preconditions.checkNotNull(e);
×
802
                onclick.accept(e);
×
803
            }
×
804
        };
805
    }
806

807
    public static boolean isWurstFile(File f) {
808
        return isWurstFile(f.getName());
1✔
809
    }
810

811
    public static boolean isWurstFile(String fileName) {
812
        return fileName.endsWith(".wurst") || fileName.endsWith(".jurst");
1✔
813
    }
814

815
    public static String getLibName(File f) {
816
        return f.getName().replaceAll("\\.[jw]urst$", "");
1✔
817
    }
818

819

820
    public static String repeat(char c, int size) {
821
        StringBuilder result = new StringBuilder(size);
1✔
822
        for (int i = 0; i < size; i++) {
1✔
823
            result.append(c);
1✔
824
        }
825
        return result.toString();
1✔
826
    }
827

828
    public static boolean elementContained(Optional<Element> e, Element in) {
829
        while (e.isPresent()) {
1✔
830
            if (e.get() == in) {
1✔
831
                return true;
1✔
832
            }
833
            e = e.flatMap(el -> Optional.ofNullable(el.getParent()));
1✔
834
        }
835
        return false;
1✔
836
    }
837

838
    /**
839
     * Executes a shell command in a given folder and returns the output of the executed command
840
     */
841
    public static String exec(File folder, String... cmds) {
842
        try {
843
            Process p = new ProcessBuilder(cmds)
×
844
                    .directory(folder)
×
845
                    .start();
×
846
            int res = p.waitFor();
×
847
            if (res != 0) {
×
848
                throw new RuntimeException("Could not execute " + Utils.join(Arrays.asList(cmds), " ")
×
849
                        + "\nErrors:\n"
850
                        + convertStreamToString(p.getErrorStream())
×
851
                        + "\nOutput:\n"
852
                        + convertStreamToString(p.getInputStream()));
×
853
            }
854
            return convertStreamToString(p.getInputStream());
×
855
        } catch (Exception e) {
×
856
            throw new RuntimeException(e);
×
857
        }
858
    }
859

860
    /**
861
     * Converts an input stream to a string
862
     * <p>
863
     * see http://stackoverflow.com/questions/309424/read-convert-an-inputstream-to-a-string
864
     */
865
    public static String convertStreamToString(InputStream is) {
866
        try(Scanner s = new Scanner(is).useDelimiter("\\A")) {
×
867
            return s.hasNext() ? s.next() : "";
×
868
        }
869
    }
870

871
    public static byte[] convertStreamToBytes(InputStream is) throws IOException {
872
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
1✔
873

874
        int nRead;
875
        byte[] data = new byte[16384];
1✔
876

877
        while ((nRead = is.read(data, 0, data.length)) != -1) {
1✔
878
            buffer.write(data, 0, nRead);
1✔
879
        }
880

881
        buffer.flush();
1✔
882

883
        return buffer.toByteArray();
1✔
884
    }
885

886
    /**
887
     * join lines
888
     */
889
    public static String string(String... lines) {
890
        return String.join("\n", lines) + "\n";
1✔
891
    }
892

893
    /**
894
     * Extracts a resource from the jar, stores it in a temp file and returns the abolute path to the tempfile
895
     */
896
    public static synchronized String getResourceFile(String name) {
897
        return getResourceFileF(name).getAbsolutePath();
1✔
898
    }
899

900
    /**
901
     * Extracts a resource from the jar, stores it in a temp file and returns the abolute path to the tempfile
902
     */
903
    public static synchronized File getResourceFileF(String name) {
904
        try {
905
            Optional<File> f = Optional.ofNullable(resourceMap.get(name));
1✔
906
            if (f.isPresent() && f.get().exists()) {
1✔
907
                return f.get();
1✔
908
            }
909

910
            String[] parts = splitFilename(name);
1✔
911
            File fi = File.createTempFile(parts[0], parts[1]);
1✔
912
            fi.deleteOnExit();
1✔
913
            try (InputStream is = Pjass.class.getClassLoader().getResourceAsStream(name)) {
1✔
914
                if (is == null) {
1✔
915
                    throw new RuntimeException("Could not find resource file " + name);
×
916
                }
917
                byte[] bytes = Utils.convertStreamToBytes(is);
1✔
918
                Files.write(bytes, fi);
1✔
919
                resourceMap.put(name, fi);
1✔
920
                return fi;
1✔
921
            }
922
        } catch (IOException e) {
×
923
            throw new RuntimeException(e);
×
924
        }
925
    }
926

927
    @NotNull
928
    private static String[] splitFilename(String name) {
929
        int dotPos = name.lastIndexOf('.');
1✔
930
        if (dotPos >= 0) {
1✔
931
            return new String[] { name.substring(0, dotPos), name.substring(dotPos + 1) };
1✔
932
        }
933
        return new String[] { name, "" };
1✔
934
    }
935

936
    private static Map<String, File> resourceMap = new HashMap<>();
1✔
937

938
    public static String elementNameWithPath(AstElementWithNameId n) {
939
        StringBuilder result = new StringBuilder(n.getNameId().getName());
1✔
940
        Optional<Element> e = Optional.ofNullable(n.getParent());
1✔
941
        while (e.isPresent()) {
1✔
942
            if (e.get() instanceof AstElementWithNameId) {
1✔
943
                result.insert(0, ((AstElementWithNameId) e.get()).getNameId().getName() + "_");
1✔
944
            }
945
            e = e.flatMap(el -> Optional.ofNullable(el.getParent()));
1✔
946
        }
947
        return result.toString();
1✔
948
    }
949

950
    @SafeVarargs
951
    public static <T> ImmutableList<T> append(List<T> list, T ... elems) {
952
        Builder<T> builder = ImmutableList.builderWithExpectedSize(list.size() + elems.length);
×
953
        builder.addAll(list);
×
954
        for (T elem : elems) {
×
955
            builder.add(elem);
×
956
        }
957
        return builder.build();
×
958
    }
959

960
    @SafeVarargs
961
    public static <T> ImmutableList<T> concatLists(List<T> ...lists) {
962
        Builder<T> builder = ImmutableList.builder();
1✔
963
        for (List<T> list : lists) {
1✔
964
            builder.addAll(list);
1✔
965
        }
966
        return builder.build();
1✔
967
    }
968

969
    public static String prettyPrint(Element e) {
970
        StringBuilder sb = new StringBuilder();
1✔
971
        e.prettyPrint(new DefaultSpacer(), sb, 0);
1✔
972
        return sb.toString();
1✔
973
    }
974

975
    public static String prettyPrintWithLine(Element e) {
976
        StringBuilder sb = new StringBuilder();
×
977
        sb.append(e.attrSource().getFile()).append(":").append(e.attrSource().getLine()).append(": ");
×
978
        e.prettyPrint(new DefaultSpacer(), sb, 4);
×
979
        return sb.toString();
×
980
    }
981

982
    public static String printTypeExpr(TypeExpr t) {
983
        WurstType wt = t.attrTyp();
×
984
        if (wt instanceof WurstTypeUnknown) {
×
985
            if (t instanceof TypeExprSimple) {
×
986
                return ((TypeExprSimple) t).getTypeName();
×
987
            }
988
            return "???";
×
989
        }
990
        return wt.toString();
×
991
    }
992

993
    /**
994
     * Copy of the list without its last element
995
     */
996
    public static <T> List<T> init(List<T> list) {
997
        return list.stream().limit(list.size() - 1).collect(Collectors.toList());
×
998
    }
999

1000
    public static Optional<String> getEnvOrConfig(String varName) {
1001
        String res = System.getenv(varName);
×
1002
        if (res == null || res.isEmpty()) {
×
1003
            res = System.getProperty(varName);
×
1004
        }
1005
        if (res == null || res.isEmpty()) {
×
1006
            return Optional.empty();
×
1007
        }
1008
        return Optional.of(res);
×
1009
    }
1010

1011
    public static class ExecResult {
1012
        private final String stdOut;
1013
        private final String stdErr;
1014

1015
        public ExecResult(String stdOut, String stdErr) {
×
1016
            this.stdOut = stdOut;
×
1017
            this.stdErr = stdErr;
×
1018
        }
×
1019

1020
        public String getStdOut() {
1021
            return stdOut;
×
1022
        }
1023

1024
        public String getStdErr() {
1025
            return stdErr;
×
1026
        }
1027
    }
1028

1029
    public static ExecResult exec(ProcessBuilder pb, Duration duration, Consumer<String> onInput) throws IOException, InterruptedException {
1030
        Process process = pb.start();
×
1031
        class Collector extends Thread {
1032
            private final StringBuilder sb = new StringBuilder();
×
1033
            private final InputStream in;
1034

1035
            Collector(InputStream in) {
×
1036
                this.in = in;
×
1037
            }
×
1038

1039
            @Override
1040
            public void run() {
1041
                try (BufferedReader input = new BufferedReader(new InputStreamReader(in))) {
×
1042
                    Optional<String> line;
1043
                    while ((line = Optional.ofNullable(input.readLine())).isPresent()) {
×
1044
                        onInput.accept(line.get());
×
1045
                        sb.append(line.get()).append("\n");
×
1046
                    }
1047
                } catch (IOException e) {
×
1048
                    throw new RuntimeException(e);
×
1049
                }
×
1050
            }
×
1051

1052
            String getContents() {
1053
                return sb.toString();
×
1054
            }
1055
        }
1056

1057
        Collector cIn = new Collector(process.getInputStream());
×
1058
        cIn.start();
×
1059
        Collector cErr = new Collector(process.getErrorStream());
×
1060
        cErr.start();
×
1061

1062
        boolean r = process.waitFor(duration.toMillis(), TimeUnit.MILLISECONDS);
×
1063
        process.destroyForcibly();
×
1064
        cIn.join();
×
1065
        cErr.join();
×
1066
        if (!r) {
×
1067
            throw new IOException("Timeout running external tool");
×
1068
        }
1069
        if (process.exitValue() != 0) {
×
1070
            throw new IOException("Failure when running external tool");
×
1071
        }
1072
        return new ExecResult(cIn.getContents(), cErr.getContents());
×
1073
    }
1074

1075
    public static String makeUniqueName(String baseName, Predicate<String> isValid) {
1076
        if (isValid.test(baseName)) {
1✔
1077
            return baseName;
1✔
1078
        }
1079
        int minI = 1;
1✔
1080
        int maxI = 1;
1✔
1081
        while (true) {
1082
            String name = baseName + "_" + maxI;
1✔
1083
            if (isValid.test(name)) {
1✔
1084
                break;
1✔
1085
            }
1086
            minI = maxI;
1✔
1087
            maxI *= 2;
1✔
1088
        }
1✔
1089

1090
        while (minI < maxI) {
1✔
1091
            int mid = minI + (maxI - minI) / 2;
1✔
1092
            String name = baseName + "_" + mid;
1✔
1093
            if (isValid.test(name)) {
1✔
1094
                maxI = mid;
1✔
1095
            } else {
1096
                minI = mid + 1;
1✔
1097
            }
1098
        }
1✔
1099
        return baseName + "_" + maxI;
1✔
1100

1101

1102

1103
    }
1104

1105

1106

1107

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