001/*
002 * Copyright (c) 2018 Chris K Wensel <chris@wensel.net>. All Rights Reserved.
003 *
004 * This Source Code Form is subject to the terms of the Mozilla Public
005 * License, v. 2.0. If a copy of the MPL was not distributed with this
006 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
007 */
008
009package heretical.parser.common;
010
011import java.util.List;
012
013import org.parboiled.errors.DefaultInvalidInputErrorFormatter;
014import org.parboiled.errors.ErrorUtils;
015import org.parboiled.errors.InvalidInputError;
016import org.parboiled.errors.ParseError;
017
018/**
019 *
020 */
021public class ParserSyntaxException extends RuntimeException
022  {
023  public static final String SEARCH_PARSE_ERROR = "parser syntax error";
024  private Result result;
025  private List<String> errorMessages;
026  private static final DefaultInvalidInputErrorFormatter formatter = new DefaultInvalidInputErrorFormatter();
027
028  public ParserSyntaxException( Result result )
029    {
030    super( makeMessage( result ) );
031    this.result = result;
032    this.errorMessages = result.getErrorMessages();
033    }
034
035  public ParserSyntaxException( List<String> errorMessages )
036    {
037    super( makeMessage( errorMessages ) );
038
039    this.errorMessages = errorMessages;
040    }
041
042  public String getSyntaxError()
043    {
044    if( result == null )
045      return null;
046
047    return getSyntaxError( result );
048    }
049
050  public List<String> getErrorMessages()
051    {
052    return errorMessages;
053    }
054
055  public List<ParseError> getParserErrorObjects()
056    {
057    if( result == null )
058      return null;
059
060    return result.getParsingResult().parseErrors;
061    }
062
063  // Parboiled doesn't provide a clean error message
064  // independent from their logging needs, so isolating this utility method to extract it for our REST API. The below
065  // was inferred from the Parboiled source.
066  public static String getErrorMessage( ParseError error )
067    {
068    if( error.getErrorMessage() != null )
069      return error.getErrorMessage();
070
071    if( error instanceof InvalidInputError )
072      return formatter.format( (InvalidInputError) error );
073
074    return error.getClass().getSimpleName();
075    }
076
077  private static String makeMessage( Result result )
078    {
079    String errors = getSyntaxError( result );
080
081    return String.format( "%s: %s", SEARCH_PARSE_ERROR, errors );
082    }
083
084  private static String getSyntaxError( Result result )
085    {
086    return ErrorUtils.printParseErrors( result.getParsingResult() );
087    }
088
089  public static String makeMessage( List<String> errorMessages )
090    {
091    if( errorMessages == null || errorMessages.isEmpty() || isEmpty( errorMessages.get( 0 ) ) )
092      return SEARCH_PARSE_ERROR;
093
094    return SEARCH_PARSE_ERROR + ": " + errorMessages.get( 0 );
095    }
096
097  private static boolean isEmpty( String string )
098    {
099    return string == null || string.isEmpty();
100    }
101  }