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

wurstscript / WurstScript / 271

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

Pull #1096

circleci

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

18202 of 28155 relevant lines covered (64.65%)

0.65 hits per line

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

62.08
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.names.NameLink;
11
import de.peeeq.wurstscript.attributes.prettyPrint.DefaultSpacer;
12
import de.peeeq.wurstscript.jassIm.JassImElementWithName;
13
import de.peeeq.wurstscript.parser.WPos;
14
import de.peeeq.wurstscript.types.WurstType;
15
import de.peeeq.wurstscript.types.WurstTypeUnknown;
16
import org.eclipse.jdt.annotation.Nullable;
17
import org.jetbrains.annotations.NotNull;
18

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

31
public class Utils {
×
32

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

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

52

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

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

69
    }
70

71

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

81

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

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

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

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

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

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

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

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

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

172

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

196

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

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

232

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

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

244

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

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

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

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

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

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

340

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

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

380

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

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

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

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

426

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

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

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

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

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

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

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

471

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

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

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

499

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

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

528

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

545
        }
1✔
546
        return subseqLength;
1✔
547
    }
548

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

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

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

588
    public static String escapeStringWithoutQuotes(String v) {
589
        StringBuilder builder = new StringBuilder();
1✔
590
        escapeStringParts(v, builder);
1✔
591
        return builder.toString();
1✔
592
    }
593

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

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

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

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

623

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

628

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

632
            final ListIterator<T> it = elements.listIterator(elements.size());
×
633

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

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

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

651

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

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

665

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

677

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

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

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

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

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

712
        ImmutableMap.Builder<K, V> builder = ImmutableMap.builder();
1✔
713

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

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

730
        return builder.build();
1✔
731
    }
732

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

817

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

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

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

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

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

872
        int nRead;
873
        byte[] data = new byte[16384];
1✔
874

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

879
        buffer.flush();
1✔
880

881
        return buffer.toByteArray();
1✔
882
    }
883

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

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

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

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

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

934
    private static final Map<String, File> resourceMap = new HashMap<>();
1✔
935

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

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

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

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

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

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

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

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

1009
    public static class ExecResult {
1010
        private final String stdOut;
1011
        private final String stdErr;
1012

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

1018
        public String getStdOut() {
1019
            return stdOut;
×
1020
        }
1021

1022
        public String getStdErr() {
1023
            return stdErr;
×
1024
        }
1025
    }
1026

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

1033
            Collector(InputStream in) {
×
1034
                this.in = in;
×
1035
            }
×
1036

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

1050
            String getContents() {
1051
                return sb.toString();
×
1052
            }
1053
        }
1054

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

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

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

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

1099

1100

1101
    }
1102

1103

1104

1105

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