| // 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>..."); |
| compileTimeErrorExit(); |
| } |
| |
| /// 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."); |
| } |
| } |
| } |
| } |