33 * SPDX-License-Identifier: GPL-2.0-only */
44package de .uka .ilkd .key .nparser .format ;
55
6+ import java .io .IOException ;
7+ import java .nio .file .Path ;
68import java .util .List ;
79
810import de .uka .ilkd .key .nparser .KeYLexer ;
911import de .uka .ilkd .key .nparser .KeYParser ;
1012import de .uka .ilkd .key .nparser .KeYParserBaseVisitor ;
1113
14+ import de .uka .ilkd .key .nparser .ParsingFacade ;
1215import org .antlr .v4 .runtime .*;
1316import org .antlr .v4 .runtime .tree .ParseTree ;
1417import org .antlr .v4 .runtime .tree .RuleNode ;
1518import org .antlr .v4 .runtime .tree .TerminalNode ;
1619import org .jspecify .annotations .Nullable ;
1720
21+ /**
22+ * {@link KeYFileFormatter} is the entry point for reformatting operation on KeY files.
23+ * <p>
24+ * It works on the AST and also on the token stream
25+ * to also capture hidden tokens like comments.
26+ * <p>
27+ * For the future, it would be nice to move this onto a stable pretty-printing engine,
28+ * which also allows line breaks with indentation if necessary.
29+ * We already have such an engine for Java in the background
30+ * ({@link de.uka.ilkd.key.util.pp.Layouter}).
31+ *
32+ * @author Julian Wiesler
33+ */
1834public class KeYFileFormatter extends KeYParserBaseVisitor <Void > {
19- /** Maximum newlines between tokens (2 equals to 1 empty line) */
35+ /**
36+ * Maximum newlines between tokens (2 means one empty line)
37+ */
2038 private static final int MAX_NEWLINES_BETWEEN = 2 ;
2139
2240 private final Output output = new Output ();
2341 private final CommonTokenStream ts ;
2442
43+ /**
44+ * Create a {@link KeYFileFormatter} with the given stream of tokens.
45+ *
46+ * @param ts a token stream created by {@link KeYLexer}
47+ */
2548 public KeYFileFormatter (CommonTokenStream ts ) {
2649 this .ts = ts ;
2750 }
@@ -138,14 +161,14 @@ public Void visitModifiers(KeYParser.ModifiersContext ctx) {
138161
139162 @ Override
140163 public Void visitVarexplist (KeYParser .VarexplistContext ctx ) {
141- var varexps = ctx .varexp ();
164+ var varConditions = ctx .varexp ();
142165 var commas = ctx .COMMA ();
143- boolean multiline = varexps .size () > 3 ;
144- for (int i = 0 ; i < varexps .size (); i ++) {
166+ boolean multiline = varConditions .size () > 3 ;
167+ for (int i = 0 ; i < varConditions .size (); i ++) {
145168 if (multiline ) {
146169 output .assertNewLineAndIndent ();
147170 }
148- visit (varexps .get (i ));
171+ visit (varConditions .get (i ));
149172 if (i < commas .size ()) {
150173 visit (commas .get (i ));
151174 if (!multiline && output .isNewLine ()) {
@@ -239,8 +262,8 @@ private static void processHiddenTokens(@Nullable List<Token> tokens, Output out
239262 }
240263 }
241264
242- private static void processHiddenTokensAfterCurrent (Token currentToken , CommonTokenStream ts ,
243- Output output ) {
265+ static void processHiddenTokensAfterCurrent (Token currentToken , CommonTokenStream ts ,
266+ Output output ) {
244267 // add hidden tokens after the current token (whitespace, comments etc.)
245268 List <Token > list = ts .getHiddenTokensToRight (currentToken .getTokenIndex ());
246269 processHiddenTokens (list , output );
@@ -330,7 +353,7 @@ public Void visitTerminal(TerminalNode node) {
330353 var token = node .getSymbol ().getType ();
331354
332355 boolean isLBrace =
333- token == KeYLexer .LBRACE || token == KeYLexer .LPAREN || token == KeYLexer .LBRACKET ;
356+ token == KeYLexer .LBRACE || token == KeYLexer .LPAREN || token == KeYLexer .LBRACKET ;
334357 if (isLBrace ) {
335358 output .spaceBeforeNext ();
336359 } else if (token == KeYLexer .RBRACE || token == KeYLexer .RPAREN
@@ -344,9 +367,9 @@ public Void visitTerminal(TerminalNode node) {
344367 }
345368
346369 var noSpaceAround =
347- token == KeYLexer .COLON || token == KeYLexer .DOT || token == KeYLexer .DOUBLECOLON ;
370+ token == KeYLexer .COLON || token == KeYLexer .DOT || token == KeYLexer .DOUBLECOLON ;
348371 var noSpaceBefore =
349- token == KeYLexer .SEMI || token == KeYLexer .COMMA || token == KeYLexer .LPAREN ;
372+ token == KeYLexer .SEMI || token == KeYLexer .COMMA || token == KeYLexer .LPAREN ;
350373 if (noSpaceBefore || noSpaceAround ) {
351374 output .noSpaceBeforeNext ();
352375 }
@@ -376,29 +399,29 @@ private static int countNLs(String text) {
376399
377400 /**
378401 * Entry level method to the formatter.
379- * The formatter uses System.lineSeparator as line separator and accepts any line separator as
380- * input.
381402 *
382- * @param text the input text
383- * @return the formatted text *or null*, if the input was not parseable
403+ * @param stream char stream
404+ * @return the formatted text
405+ * @throws de.uka.ilkd.key.util.parsing.SyntaxErrorReporter.ParserException if the given text is not parser
384406 */
385- public static @ Nullable String format (String text ) {
386- var in = CharStreams .fromString (text .replaceAll ("\\ r\\ n?" , "\n " ));
387- KeYLexer lexer = new KeYLexer (in );
388- lexer .setTokenFactory (new CommonTokenFactory (true ));
407+ public static String format (CharStream stream ) {
408+ //weigl: Not necessary is handled within the lexer
409+ // var in = CharStreams.fromString(text.replaceAll("\\r\\n?", "\n"));
410+
411+ var lexer = ParsingFacade .createLexer (stream );
412+ //weigl: Should not be necessary
413+ // lexer.setTokenFactory(new CommonTokenFactory(true));
389414
390415 CommonTokenStream tokens = new CommonTokenStream (lexer );
391416 tokens .fill ();
392417
393418 KeYParser parser = new KeYParser (tokens );
394- KeYParser .FileContext ctx = parser .file ();
395- if (parser .getNumberOfSyntaxErrors () > 0 ) {
396- return null ;
397- }
419+ parser .removeErrorListeners ();
420+ parser .addErrorListener (parser .getErrorReporter ());
398421
422+ KeYParser .FileContext ctx = parser .file ();
399423 KeYFileFormatter formatter = new KeYFileFormatter (tokens );
400424 formatter .visitFile (ctx );
401- var formatted = formatter .output .toString ().trim () + "\n " ;
402- return formatted .replaceAll ("\n " , System .lineSeparator ());
425+ return formatter .output .toString ().trim () + "\n " ;
403426 }
404427}
0 commit comments