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 }