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

wurstscript / WurstScript / 210

26 Oct 2023 10:10PM UTC coverage: 62.609% (-1.1%) from 63.756%
210

push

circleci

web-flow
Jass And Wurst Formatter (#620)

Support for formatting .wurst and .j files.

Thanks @karlek 

Co-authored-by: Frotty <Frotty@users.noreply.github.com>
Co-authored-by: Peter Zeller <Peter.peq@googlemail.com>

17297 of 27627 relevant lines covered (62.61%)

0.63 hits per line

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

56.12
de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/WurstParser.java
1
package de.peeeq.wurstscript;
2

3
import de.peeeq.wurstscript.antlr.JassParser;
4
import de.peeeq.wurstscript.antlr.WurstLexer;
5
import de.peeeq.wurstscript.antlr.WurstParser.CompilationUnitContext;
6
import de.peeeq.wurstscript.ast.Ast;
7
import de.peeeq.wurstscript.ast.CompilationUnit;
8
import de.peeeq.wurstscript.attributes.CompilationUnitInfo;
9
import de.peeeq.wurstscript.attributes.CompileError;
10
import de.peeeq.wurstscript.attributes.ErrorHandler;
11
import de.peeeq.wurstscript.gui.WurstGui;
12
import de.peeeq.wurstscript.jass.AntlrJassParseTreeTransformer;
13
import de.peeeq.wurstscript.jass.ExtendedJassLexer;
14
import de.peeeq.wurstscript.jurst.AntlrJurstParseTreeTransformer;
15
import de.peeeq.wurstscript.jurst.ExtendedJurstLexer;
16
import de.peeeq.wurstscript.jurst.antlr.JurstParser;
17
import de.peeeq.wurstscript.parser.WPos;
18
import de.peeeq.wurstscript.parser.antlr.AntlrWurstParseTreeTransformer;
19
import de.peeeq.wurstscript.parser.antlr.ExtendedWurstLexer;
20
import de.peeeq.wurstscript.utils.LineOffsets;
21
import org.antlr.v4.runtime.*;
22
import org.antlr.v4.runtime.misc.Interval;
23

24
import java.io.IOException;
25
import java.io.Reader;
26
import java.io.StringReader;
27
import java.util.regex.Matcher;
28
import java.util.regex.Pattern;
29

30
public class WurstParser {
31
    private static final int MAX_SYNTAX_ERRORS = 15;
32
    private final ErrorHandler errorHandler;
33
    private final WurstGui gui;
34
    private boolean removeSugar = true;
1✔
35

36
    public WurstParser(ErrorHandler errorHandler, WurstGui gui) {
1✔
37
        this.errorHandler = errorHandler;
1✔
38
        this.gui = gui;
1✔
39
    }
1✔
40

41
    public void setRemoveSugar(boolean removeSugar) {
42
        this.removeSugar = removeSugar;
×
43
    }
×
44

45
    public CompilationUnit parse(Reader reader, String source, boolean hasCommonJ) {
46
        return parseWithAntlr(reader, source, hasCommonJ);
1✔
47
    }
48

49
    private static final Pattern pattern = Pattern.compile("\\s*");
1✔
50

51
    private CompilationUnit parseWithAntlr(Reader reader, final String source, boolean hasCommonJ) {
52
        try {
53
            CharStream input = CharStreams.fromReader(reader);
1✔
54
            // create a lexer that feeds off of input CharStream
55
            final ExtendedWurstLexer lexer = new ExtendedWurstLexer(input);
1✔
56
            // create a buffer of tokens pulled from the lexer
57
            TokenStream tokens = new CommonTokenStream(lexer);
1✔
58
            // create a parser that feeds off the tokens buffer
59
            de.peeeq.wurstscript.antlr.WurstParser parser = new de.peeeq.wurstscript.antlr.WurstParser(tokens);
1✔
60
            ANTLRErrorListener l = new BaseErrorListener() {
1✔
61

62
                int errorCount = 0;
1✔
63

64

65

66
                @Override
67
                public void syntaxError(@SuppressWarnings("null") Recognizer<?, ?> recognizer, @SuppressWarnings("null") Object offendingSymbol, int line,
68
                                        int charPositionInLine,
69
                                        @SuppressWarnings("null") String msg, @SuppressWarnings("null") RecognitionException e) {
70

71
                    // try to improve error message
72
                    if (e instanceof NoViableAltException) {
1✔
73
                        NoViableAltException ne = (NoViableAltException) e;
1✔
74
                        if (ne.getStartToken().getType() == WurstLexer.HOTDOC_COMMENT) {
1✔
75
                            msg = "Hotdoc comment is in invalid position, it can " +
×
76
                                    "only appear before function definitions, classes, and " +
77
                                    "other elements that can be documented.";
78
                            offendingSymbol = ne.getStartToken();
×
79
                        }
80
                    }
81

82
                    LineOffsets offsets = lexer.getLineOffsets();
1✔
83
                    int pos;
84
                    int posStop;
85
                    if (offendingSymbol instanceof Token) {
1✔
86
                        Token token = (Token) offendingSymbol;
1✔
87
                        pos = token.getStartIndex();
1✔
88
                        posStop = token.getStopIndex() + 1;
1✔
89
                    } else {
1✔
90
                        pos = offsets.get(line) + charPositionInLine;
1✔
91
                        posStop = pos + 1;
1✔
92
                    }
93

94
                    if (posStop >= input.size()) {
1✔
95
                        posStop = input.size() - 1;
1✔
96
                    }
97

98
                    Matcher matcher = pattern.matcher(input.getText(new Interval(pos, posStop)));
1✔
99
                    while (pos > 0 && matcher.matches()){
1✔
100
                        pos--;
1✔
101
                    }
102
                    CompileError err = new CompileError(new WPos(source, offsets, pos, posStop), msg);
1✔
103
                    gui.sendError(err);
1✔
104

105
                    errorCount++;
1✔
106
                    if (errorCount > MAX_SYNTAX_ERRORS) {
1✔
107
                        throw new TooManyErrorsException();
×
108
                    }
109
                }
1✔
110

111
            };
112
            lexer.setErrorListener(l);
1✔
113
            parser.removeErrorListeners();
1✔
114
            parser.addErrorListener(l);
1✔
115

116
            CompilationUnitContext cu = parser.compilationUnit(); // begin parsing at init rule
1✔
117

118
            if (lexer.getTabWarning() != null) {
1✔
119
                CompileError warning = lexer.getTabWarning();
1✔
120
                warning = new CompileError(warning.getSource().withFile(source), warning.getMessage(), CompileError.ErrorType.WARNING);
1✔
121
                gui.sendError(warning);
1✔
122
            }
123

124
            CompilationUnit root = new AntlrWurstParseTreeTransformer(source, errorHandler, lexer.getLineOffsets(), lexer.getCommentTokens(), true).transform(cu);
1✔
125
            if (this.removeSugar) {
1✔
126
                removeSyntacticSugar(root, hasCommonJ);
1✔
127
            }
128
            root.getCuInfo().setIndentationMode(lexer.getIndentationMode());
1✔
129
            return root;
1✔
130

131
        } catch (IOException e) {
×
132
            WLogger.severe(e);
×
133
            throw new Error(e);
×
134
        } catch (TooManyErrorsException e) {
×
135
            WLogger.info("Stopped parsing file " + source + ", too many errors");
×
136
            return emptyCompilationUnit();
×
137
        }
138
    }
139

140

141
    public CompilationUnit parseJurst(Reader reader, String source, boolean hasCommonJ) {
142
        return parseJurstWithAntlr(reader, source, hasCommonJ);
1✔
143
    }
144

145
    private CompilationUnit parseJurstWithAntlr(Reader reader, final String source, boolean hasCommonJ) {
146
        try {
147
            CharStream input = CharStreams.fromReader(reader);
1✔
148
            // create a lexer that feeds off of input CharStream
149
            final ExtendedJurstLexer lexer = new ExtendedJurstLexer(input);
1✔
150
            // create a buffer of tokens pulled from the lexer
151
            TokenStream tokens = new CommonTokenStream(lexer);
1✔
152
            // create a parser that feeds off the tokens buffer
153
            JurstParser parser = new JurstParser(tokens);
1✔
154
            ANTLRErrorListener l = new BaseErrorListener() {
1✔
155

156
                int errorCount = 0;
1✔
157

158
                @Override
159
                public void syntaxError(@SuppressWarnings("null") Recognizer<?, ?> recognizer, @SuppressWarnings("null") Object offendingSymbol, int line,
160
                                        int charPositionInLine,
161
                                        @SuppressWarnings("null") String msg, @SuppressWarnings("null") RecognitionException e) {
162

163
                    LineOffsets offsets = lexer.getLineOffsets();
×
164
                    int pos;
165
                    int posStop;
166
                    if (offendingSymbol instanceof Token) {
×
167
                        Token token = (Token) offendingSymbol;
×
168
                        pos = token.getStartIndex();
×
169
                        posStop = token.getStopIndex() + 1;
×
170
                    } else {
×
171
                        pos = offsets.get(line) + charPositionInLine;
×
172
                        posStop = pos + 1;
×
173
                    }
174

175
                    msg = "line " + line + ": " + msg;
×
176

177
                    Matcher matcher = pattern.matcher(input.getText(new Interval(pos, posStop)));
×
178
                    while (pos > 0 && matcher.matches()) {
×
179
                        pos--;
×
180
                    }
181
                    CompileError err = new CompileError(new WPos(source, offsets, pos, posStop), msg);
×
182
                    gui.sendError(err);
×
183

184

185
                    errorCount++;
×
186
                    if (errorCount > MAX_SYNTAX_ERRORS) {
×
187
                        throw new TooManyErrorsException();
×
188
                    }
189
                }
×
190

191
            };
192
            lexer.addErrorListener(l);
1✔
193
            parser.removeErrorListeners();
1✔
194
            parser.addErrorListener(l);
1✔
195

196
            de.peeeq.wurstscript.jurst.antlr.JurstParser.CompilationUnitContext cu = parser.compilationUnit(); // begin parsing at init rule
1✔
197
            CompilationUnit root = new AntlrJurstParseTreeTransformer(source, errorHandler, lexer.getLineOffsets()).transform(cu);
1✔
198
            if (this.removeSugar) {
1✔
199
                removeSyntacticSugar(root, hasCommonJ);
1✔
200
            }
201
            return root;
1✔
202

203
        } catch (IOException e) {
×
204
            WLogger.severe(e);
×
205
            throw new Error(e);
×
206
        } catch (TooManyErrorsException e) {
×
207
            WLogger.info("Stopped parsing file " + source + ", too many errors");
×
208
            return emptyCompilationUnit();
×
209
        }
210
    }
211

212
    public CompilationUnit parseJass(Reader reader, String source, boolean hasCommonJ) {
213
        return parseJassAntlr(reader, source, hasCommonJ);
1✔
214
    }
215

216
    private CompilationUnit parseJassAntlr(Reader reader, final String source, boolean hasCommonJ) {
217
        try {
218
            CharStream input = CharStreams.fromReader(reader);
1✔
219
            // create a lexer that feeds off of input CharStream
220
            final ExtendedJassLexer lexer = new ExtendedJassLexer(input);
1✔
221
            // create a buffer of tokens pulled from the lexer
222
            TokenStream tokens = new CommonTokenStream(lexer);
1✔
223
            // create a parser that feeds off the tokens buffer
224
            JassParser parser = new JassParser(tokens);
1✔
225
            ANTLRErrorListener l = new BaseErrorListener() {
1✔
226

227
                int errorCount = 0;
1✔
228

229
                @Override
230
                public void syntaxError(@SuppressWarnings("null") Recognizer<?, ?> recognizer, @SuppressWarnings("null") Object offendingSymbol, int line,
231
                                        int charPositionInLine,
232
                                        @SuppressWarnings("null") String msg, @SuppressWarnings("null") RecognitionException e) {
233

234
                    LineOffsets offsets = lexer.getLineOffsets();
×
235
                    int pos;
236
                    int posStop;
237
                    if (offendingSymbol instanceof Token) {
×
238
                        Token token = (Token) offendingSymbol;
×
239
                        pos = token.getStartIndex();
×
240
                        posStop = token.getStopIndex() + 1;
×
241
                    } else {
×
242
                        pos = offsets.get(line) + charPositionInLine;
×
243
                        posStop = pos + 1;
×
244
                    }
245

246
                    msg = "line " + line + ": " + msg;
×
247

248
                    Matcher matcher = pattern.matcher(input.getText(new Interval(pos, posStop)));
×
249
                    while (pos > 0 && matcher.matches()) {
×
250
                        pos--;
×
251
                    }
252
                    CompileError err = new CompileError(new WPos(source, offsets, pos, posStop), msg);
×
253
                    gui.sendError(err);
×
254

255

256
                    errorCount++;
×
257
                    if (errorCount > MAX_SYNTAX_ERRORS) {
×
258
                        throw new TooManyErrorsException();
×
259
                    }
260
                }
×
261

262
            };
263
            lexer.addErrorListener(l);
1✔
264
            parser.removeErrorListeners();
1✔
265
            parser.addErrorListener(l);
1✔
266

267
            JassParser.CompilationUnitContext cu = parser.compilationUnit(); // begin parsing at init rule
1✔
268
            CompilationUnit root = new AntlrJassParseTreeTransformer(source, errorHandler, lexer.getLineOffsets()).transform(cu);
1✔
269
            removeSyntacticSugar(root, hasCommonJ);
1✔
270
            return root;
1✔
271

272
        } catch (IOException e) {
×
273
            WLogger.severe(e);
×
274
            throw new Error(e);
×
275
        } catch (TooManyErrorsException e) {
×
276
            WLogger.info("Stopped parsing file " + source + ", too many errors");
×
277
            return emptyCompilationUnit();
×
278
        }
279
    }
280

281

282
    public CompilationUnit emptyCompilationUnit() {
283
        return Ast.CompilationUnit(new CompilationUnitInfo(errorHandler), Ast.JassToplevelDeclarations(), Ast.WPackages());
×
284
    }
285

286
    private void removeSyntacticSugar(CompilationUnit root, boolean hasCommonJ) {
287
        new SyntacticSugar().removeSyntacticSugar(root, hasCommonJ);
1✔
288
    }
1✔
289

290
    static class TooManyErrorsException extends RuntimeException {
×
291
    }
292
}
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