/* * Copyright (C) 2011 Laurent Caillette * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.novelang.common; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.google.common.base.Preconditions; import org.antlr.runtime.RecognitionException; //import novelang.parser.antlr.AntlrErrorInterpreter; /** * Represents something bad that happened during document generation. * * @author Laurent Caillette */ public class Problem implements Comparable< Problem > { final Location location ; final String message ; private Problem( final Location location, final String message ) { this.location = Preconditions.checkNotNull( location ) ; this.message = Preconditions.checkNotNull( message ) ; } public Location getLocation() { return location; } public String getMessage() { return message; } @Override public String toString() { return getLocation() + " " + getMessage() ; } /** * Kinda dependency towards ANTLR formatting but who cares?. */ private static final Pattern MESSAGE_WITH_LOCATION = Pattern.compile( "line (\\d+):(\\d+) (.+)" ) ; public static Problem createProblem( final String message ) { return createProblem( new Location( "<unknown file>", -1, -1 ), message ) ; } public static Problem createProblem( final Location location, final String message ) { return new Problem( location, message ) ; } public static Problem createProblem( final Exception exception ) { return new Problem( new Location( "<unknown file>", -1, -1 ), exception.getMessage() ) ; } public static Problem createProblem( final LocationFactory locationFactory, final Exception exception ) { int line = -1 ; int column = -1 ; final String bareMessage = exception.getMessage() ; if( exception instanceof RecognitionException ) { final RecognitionException recognitionException = ( RecognitionException ) exception ; line = recognitionException.line ; column = recognitionException.charPositionInLine ; } final Location location = locationFactory.createLocation( line, column ) ; return new Problem( location, bareMessage ) ; } public static Problem createProblem( final LocationFactory locationFactory, final RecognitionException exception, final String[] tokenNames ) { final Location location = locationFactory.createLocation( exception.line, exception.charPositionInLine ) ; // TODO reactivate this once solved dependency mess introduced (unveiled) by Maven. // final String message = AntlrErrorInterpreter.getErrorMessage( exception, tokenNames ) ; // return new Problem( location, message ) ; return createProblem( location, "TODO: interpret error" + exception.getMessage() ) ; // Bad. } public static Problem createProblem( final LocationFactory locationFactory, final RecognitionException exception ) { final Location location = locationFactory.createLocation( exception.line, exception.charPositionInLine ) ; final String message = exception.getMessage() == null ? "?" : exception.getMessage() ; return new Problem( location, message ) ; } /** * @deprecated, use standard exception-aware * {@link #createProblem(LocationFactory, Exception) method}. The parser should trap those * exceptions. */ public static Problem createProblem( final LocationFactory locationFactory, final String message ) { final Matcher matcher = MESSAGE_WITH_LOCATION.matcher( message ) ; int line = -1 ; int column = -1 ; final String bareMessage ; if( matcher.matches() && 3 == matcher.groupCount() ) { line = Integer.parseInt( matcher.group( 1 ) ) ; column = Integer.parseInt( matcher.group( 2 ) ) ; bareMessage = matcher.group( 3 ) ; } else { bareMessage = message ; } final Location location = locationFactory.createLocation( line, column ) ; return new Problem( location, bareMessage ) ; } public static Problem createProblem( final String message, final Location location ) { return new Problem( location, message ) ; } public static Problem createProblem( final String message, final LocationFactory locationFactory, final int line, final int column ) { return new Problem( locationFactory.createLocation( line, column ), message ) ; } // ============== // Usual suspects // ============== @Override public boolean equals( final Object o ) { if( this == o ) return true; if( o == null || getClass() != o.getClass() ) return false; final Problem problem = ( Problem ) o; if( location != null ? !location.equals( problem.location ) : problem.location != null ) return false; if( message != null ? !message.equals( problem.message ) : problem.message != null ) return false; return true; } @Override public int hashCode() { int result = location != null ? location.hashCode() : 0; result = 31 * result + ( message != null ? message.hashCode() : 0 ); return result; } @Override public int compareTo( final Problem other ) { if( this.equals( other ) ) { return 0 ; } if( other == null ) { return 1 ; } final int locationDifference = getLocation().compareTo( other.getLocation() ) ; if( locationDifference == 0 ) { return message.compareTo( other.getMessage() ) ; } else { return locationDifference ; } } }