/* ____ ____ ____ ____ ______ *\ ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** ** /_____/\____/\___/\____/____/ ** \* */ // $Id$ package scalac.util; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; import java.io.PrintWriter; import java.util.HashSet; import ch.epfl.lamp.util.Position; import scalac.ApplicationError; public class Reporter { //######################################################################## // Private Fields /** The reader to ask for failures on demand */ private final BufferedReader reader; /** The writer to print messages */ private final PrintWriter writer; /** Log of error positions (used to avoid printing errors twice) */ private final HashSet positions; /** Number of errors issued totally */ private int errors; /** Number of warning issued totally */ private int warnings; //######################################################################## // Public Fields /** Whether warnings should be issued */ public boolean nowarn; /** Whether information messages should be issued */ public boolean verbose; /** Whether a prompt should be displayed after errors and warnings */ public boolean prompt; /** Whether a short file name should be displayed before errors */ public boolean shortname; //######################################################################## // Public Constructors /** Initializes a new instance. */ public Reporter() { this( new BufferedReader(new InputStreamReader(System.in)), new PrintWriter(System.err, true)); } /** Initializes a new instance. */ public Reporter(BufferedReader reader, PrintWriter writer) { this.reader = reader; this.writer = writer; this.positions = new HashSet(); this.prompt = false; this.nowarn = false; this.verbose = false; this.errors = 0; } //######################################################################## // Public Methods - Count /** Returns the number of errors issued totally */ public int errors() { return errors; } /** Returns the number of warnings issued totally */ public int warnings() { return warnings; } /** Returns the number of errors issued totally as a string */ public String getErrorCountString() { return getCountString(errors, "error"); } /** Returns the number of warnings issued totally as a string */ public String getWarningCountString() { return getCountString(warnings, "warning"); } /** Returns a string meaning "n elements". */ public String getCountString(int n, String elements) { switch (n) { case 0: return "no " + elements + "s"; case 1: return "one " + elements; case 2: return "two " + elements + "s"; case 3: return "three " + elements + "s"; case 4: return "four " + elements + "s"; default: return n + " " + elements + "s"; } } /** Resets all counters */ public void resetCounters() { errors = 0; warnings = 0; } //######################################################################## // Public Methods - Report /** Issues a message */ public void report(String message) { printMessage(message); } /** Issues a message */ public void inform(String message) { if (verbose) printMessage(message); } /** Issues an error */ public void error(Position position, String message) { boolean hidden = testAndLog(position); if (!hidden || prompt) printError(position, message); if (!hidden) errors++; if (prompt) failOnDemand(); } /** Issues a warning */ public void warning(Position position, String message) { boolean hidden = testAndLog(position); if (nowarn) return; if (!hidden || prompt) printWarning(position, message); if (!hidden) warnings++; if (prompt) failOnDemand(); } //######################################################################## // Public Methods - Print /** Prints the message. */ public void printMessage(String message) { writer.println(message); } /** Prints the message with the given position indication. */ public void printMessage(Position position, String message) { if (position != null) { message = " " + message; if (position.line() != 0) message = position.line() + ":" + message; if (shortname) message = position.file().getShortName() + ":" + message; else message = position.file().name() + ":" + message; } printMessage(message); printSourceLine(position); } /** Prints the error message. */ public void printError(Position position, String message) { if (position == null) message = "error: " + message; printMessage(position, message); } /** Prints the warning message. */ public void printWarning(Position position, String message) { message = "warning: " + message; printMessage(position, message); } /** Prints the number of errors and warnings if their are non-zero. */ public void printSummary() { if (errors() > 0) report(getErrorCountString() + " found"); if (warnings() > 0) report(getWarningCountString() + " found"); } /** Prints the source line of the given position. */ public void printSourceLine(Position position) { if (position == null || position.line() == 0) return; printMessage(position.file().getLine(position.line())); printColumnMarker(position); } /** Prints the column marker of the given position. */ public void printColumnMarker(Position position) { int column = position == null ? 0 : position.column(); StringBuffer buffer = new StringBuffer(column); for (int i = 1; i < column; i++) buffer.append(' '); if (column > 0) buffer.append('^'); printMessage(buffer.toString()); } //######################################################################## // Public Methods - Fail on demand /** Fails only if requested. */ public void failOnDemand() { failOnDemand("user abort"); } /** Fails only if requested. */ public void failOnDemand(String message) { try { while (true) { writer.print("r)esume, a)bort: "); writer.flush(); String line = reader.readLine(); if (line == null) continue; else line = line.toLowerCase(); if ("abort".startsWith(line)) throw new ApplicationError(message); if ("resume".startsWith(line)) return; } } catch (IOException e) { throw new ApplicationError("input read error"); } } //######################################################################## // Private Methods /** Logs a position and returns true if it was already logged. */ private boolean testAndLog(Position position) { if (position == null) return false; if (position.column() == 0) return false; if (positions.contains(position)) return true; positions.add(position); return false; } //######################################################################## }