dart-sdk/tools/spec_parser/SpecParser.java
Erik Ernst 1c2c6ea1cd Adjust spec parser to use exit code 0 when parsing no files
Invocations of the spec parser used to exit with an error code (245)
in the case where no files were specified. This was considered to be a
useless type of invocation, and the spec parser would print out a help
message.

However, it is perfectly possible for a Gerrit CL to give rise to
invocations like that, e.g., when the CL deletes some files and does
nothing else. Also, it causes no known issues to report a success exit
code (0) in the case where no files are specified, and hence this CL
changes the spec parser accordingly.

Change-Id: I9bd75839f1a8052b3daa62fa5440451e46fb59e8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/253280
Reviewed-by: Alexander Thomas <athom@google.com>
Commit-Queue: Erik Ernst <eernst@google.com>
2022-08-01 23:29:44 +00:00

160 lines
5.4 KiB
Java

// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import java.io.*;
import java.util.*;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.dfa.*;
import org.antlr.v4.runtime.atn.*;
class ParsingResult {
public int numberOfFileArguments;
public int numberOfFailures;
}
class DartErrorListener implements ANTLRErrorListener {
public void reportAmbiguity(
Parser recognizer,
DFA dfa,
int startIndex,
int stopIndex,
boolean exact,
BitSet ambigAlts,
ATNConfigSet configs) {}
public void reportAttemptingFullContext(
Parser recognizer,
DFA dfa,
int startIndex,
int stopIndex,
BitSet conflictingAlts,
ATNConfigSet configs) {}
public void reportContextSensitivity(
Parser recognizer,
DFA dfa,
int startIndex,
int stopIndex,
int prediction,
ATNConfigSet configs) {}
public void syntaxError(
Recognizer<?,?> recognizer,
Object offendingSymbol,
int line,
int charPositionInLine,
String msg,
RecognitionException e) {
if (!DartParser.errorHasOccurred) DartParser.prepareForErrors();
}
}
/// Class for `main` which will parse files given as command line arguments.
public class SpecParser {
private static void normalExit() {
// Terminate with exit code indicating normal termination.
System.exit(0);
}
private static void compileTimeErrorExit() {
// Terminate with exit code indicating a parse error.
System.exit(245);
}
private static void helpAndExit() {
System.err.println("Expected arguments: [--verbose] <file>...");
normalExit();
}
/// Receive command lines from standard input and produce feedback about
/// the outcome on standard output and standard error, as expected by
/// tools/test.py when running with `--batch`.
public static void runAsBatch() throws IOException, RecognitionException {
ParsingResult result = new ParsingResult();
long startTime = System.currentTimeMillis();
InputStreamReader input = new InputStreamReader(System.in);
BufferedReader bufferedInput = new BufferedReader(input);
String cmdLine;
System.out.println(">>> BATCH START");
while ((cmdLine = bufferedInput.readLine()) != null) {
if (cmdLine.length() == 0) {
System.out.println(
">>> BATCH END (" +
(result.numberOfFileArguments - result.numberOfFailures) +
"/" + result.numberOfFileArguments + ") " +
(System.currentTimeMillis() - startTime) + "ms");
if (result.numberOfFailures > 0) compileTimeErrorExit();
normalExit();
}
String[] lineArgs = cmdLine.split("\\s+");
result = parseFiles(lineArgs);
// Write stderr end token and flush.
System.err.println(">>> EOF STDERR");
String resultPassString =
result.numberOfFailures == 0 ? "PASS" : "PARSE_FAIL";
System.out.println(">>> TEST " + resultPassString + " " +
(System.currentTimeMillis() - startTime) + "ms");
startTime = System.currentTimeMillis();
}
}
/// From [arguments], obey the flags ("--<flag_name>", "-<any>") if known and
/// ignore them if unknown; treat the remaining [arguments] as file paths and
/// parse each of them. Return a [ParsingResult] specifying how many files
/// were parsed, and how many of them failed to parse.
private static ParsingResult parseFiles(String[] arguments)
throws IOException, RecognitionException {
ParsingResult result = new ParsingResult();
boolean verbose = false;
result.numberOfFileArguments = arguments.length;
for (int i = 0; i < arguments.length; i++) {
String filePath = arguments[i];
if (filePath.startsWith("-")) {
result.numberOfFileArguments--;
if (result.numberOfFileArguments == 0) return result;
if (filePath.equals("--verbose")) verbose = true;
if (filePath.equals("--batch")) runAsBatch();
// Ignore all other flags.
continue;
}
if (verbose) System.err.println("Parsing file: " + filePath);
DartLexer lexer = new DartLexer(new ANTLRFileStream(filePath));
DartParser parser = new DartParser(new CommonTokenStream(lexer));
ANTLRErrorListener errorListener = new DartErrorListener();
lexer.addErrorListener(errorListener);
parser.addErrorListener(errorListener);
if (!parser.parseLibrary(filePath)) result.numberOfFailures++;
}
return result;
}
public static void main(String[] args) throws Exception {
if (args.length == 0) helpAndExit();
ParsingResult result = parseFiles(args);
if (result.numberOfFileArguments == 0) {
helpAndExit();
} else if (result.numberOfFileArguments == 1) {
if (result.numberOfFailures > 0) {
System.err.println("Parsing failed");
compileTimeErrorExit();
} else {
System.out.println("Parsing succeeded.");
}
} else {
if (result.numberOfFailures > 0) {
System.err.println(
"Parsed " + result.numberOfFileArguments + " files, " +
result.numberOfFailures + " failed.");
compileTimeErrorExit();
} else {
System.out.println("Parsed " + result.numberOfFileArguments +
" files successfully.");
}
}
}
}