package tool trait Reporter { // Informs scalac that this will be mixed-in with the class Compiler, so // we'll have access to the source file information (scala.io.Source has nice // methods for displaying error messages). this: Compiler => private var foundErrors = false /** Simple warnings */ def warn(msg: String): Unit = outputErrorMsg("Warning", msg) def warn(msg: String, i: Int): Unit = report(i, "Warning: " + msg) def warn(msg: String, pos: Positional): Unit = warn(msg, pos.pos) /** Non-fatal errors. The compiler should call terminateIfErrors * before the errors can have an impact (for instance at the end * of the phase). */ def error(msg: String): Unit = { foundErrors = true; outputErrorMsg("Error", msg) } def error(msg: String, i: Int): Unit = { foundErrors = true; report(i, "Error: " + msg) } def error(msg: String, pos: Positional): Unit = error(msg, pos.pos) /** Errors from which the compiler cannot recover or continue. */ def fatalError(msg: String): Nothing = { outputErrorMsg("Fatal error", msg); terminate } def fatalError(msg: String, i: Int): Nothing = { report(i, "Fatal error: " + msg) terminate } def fatalError(msg: String, pos: Positional): Nothing = fatalError(msg, pos.pos) /** Stops the compiler if they were non-fatal errors. */ def terminateIfErrors = { if(foundErrors) { Console.err.println("There were errors.") terminate } } private def outputErrorMsg(prefix: String, msg: String) = { Console.err.println(prefix + ": " + msg) } private def terminate: Nothing = { exit(-1) } // circumvents what I think is a bug in scala.io.Source private def report(pos: Int, msg: String): Unit = { val buf = new StringBuilder val line = scala.io.Position.line(pos) val col = scala.io.Position.column(pos) buf.append(line + ":" + col + ": " + msg) buf.append("\n") buf.append(source.getLine(line)) buf.append("\n") var i = 1 while(i < col) { buf.append(' ') i += 1 } buf.append('^') Console.err.println(buf.toString) } }