All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gw.lang.parser.exceptions.ParseIssue Maven / Gradle / Ivy

There is a newer version: 1.18.2
Show newest version
/*
 * Copyright 2014 Guidewire Software, Inc.
 */

package gw.lang.parser.exceptions;

import gw.lang.parser.IExpression;
import gw.lang.parser.ISource;
import gw.lang.parser.expressions.IProgram;
import gw.lang.reflect.gs.IGosuClass;
import gw.lang.parser.resources.ResourceKey;
import gw.lang.parser.IParseIssue;
import gw.lang.parser.ISymbolTable;
import gw.lang.parser.IParsedElement;
import gw.lang.parser.IParserState;
import gw.lang.parser.IFullParserState;
import gw.lang.parser.IParserPart;
import gw.lang.parser.IScriptPartId;
import gw.lang.reflect.IType;
import gw.config.CommonServices;

public abstract class ParseIssue extends Exception implements IParseIssue
{
  private static final String SOURCE_DELIMITER = "\nat line ";
  private static final int CONTEXT_LINES = 3;

  private Integer _lineNumber;
  private Integer _lineOffset;
  private Integer _tokenColumn;
  private Integer _tokenStart;
  private Integer _tokenEnd;
  private ResourceKey _messageKey;
  private Object[] _messageArgs;

  private ISymbolTable _symbolTable;
  private IParsedElement _parentElement;
  private String _stateSource;
  private IGosuClass _parentClass;

  private void debug() {
//    if (toString().contains("PXLOGGER")) {
//      int uuuu = 0;
//    }
  }

  protected ParseIssue( IParserState parserState, ResourceKey key, Object... msgArgs )
  {
    super( "" );
    _messageKey = key;
    _messageArgs = normalizeMessageArgs(msgArgs);
    initFieldsFromParserState( parserState );
    debug();
  }

  protected ParseIssue( Integer lineNumber, Integer lineOffset, Integer tokenColumn,
                                Integer tokenStart, Integer tokenEnd,
                                ISymbolTable symbolTable, ResourceKey key, Object... msgArgs )
  {
    super( "" );
    _messageKey = key;
    _messageArgs = normalizeMessageArgs(msgArgs);
    _symbolTable = symbolTable;
    _lineNumber = lineNumber;
    _lineOffset = lineOffset == null ? 1 : Math.max( 1, lineOffset );
    _tokenColumn = tokenColumn;
    _tokenStart = tokenStart;
    _tokenEnd = tokenEnd;
    debug();
  }

  protected ParseIssue( IParserState state, Throwable t )
  {
    super( t );
    initFieldsFromParserState( state );
    debug();
  }

  /**
   * Don't fill in stack trace since parse issues are not really "exceptional"
   * in terms of the parser's Java implementation; we don't care much about the
   * Java stack trace when these are thrown. Rather parse issues provide a means
   * to tag parsed elements with issues discovered during parsing, such as
   * syntax warnings and errors. Hence, the ParseIssue interface.
   * 

* Note this method is otherwise very costly from a performance standpoint. *

*/ public Throwable fillInStackTrace() { return this; } private void initFieldsFromParserState( IParserState parserState ) { if( parserState != null ) { if( parserState instanceof IFullParserState ) { IFullParserState fullParserState = (IFullParserState)parserState; _symbolTable = fullParserState.getSymbolTable(); } _lineNumber = parserState.getLineNumber(); _lineOffset = Math.max( 1, parserState.getLineOffset() ); _tokenColumn = parserState.getTokenColumn(); _tokenStart = parserState.getTokenStart(); _tokenEnd = parserState.getTokenEnd(); // Copy the value because the source is a string built from a StringBuffer which will have the whole array allocated. String parserSource = parserState.getSource(); setStateSource( parserSource ); } } /** * Normalize all non string & non number args to string types to prevent * race conditions wrt/ the TypeSystem lock when the message is formatted. */ private Object [] normalizeMessageArgs(Object [] args) { Object [] result = args; if(args != null && args.length > 0) { result = new Object[args.length]; for(int i = 0; i < args.length; i++) { if(args[i] == null || args[i] instanceof CharSequence || args[i] instanceof Number) { result[i] = args[i]; } else { result[i] = args[i].toString(); } } } return result; } protected static String formatError( ResourceKey key, Object... msgArgs ) { if( key != null ) { return CommonServices.getGosuLocalizationService().localize( key, msgArgs ); } else { return ""; } } public Integer getLineNumber() { return _lineNumber; } public Integer getLineOffset() { return _lineOffset; } public void addLineOffset( int offset ) { _lineOffset += offset; } public Integer getTokenColumn() { return _tokenColumn; } public Integer getTokenEnd() { return _tokenEnd; } public Integer getTokenStart() { return _tokenStart; } public String getContextString() { if( getStateSource() != null ) { return makeContextString( _lineNumber, getStateSource(), getLineReportingOffset() ); } else { return null; } } public String getContextStringNoLineNumbers() { if( getStateSource() != null ) { return makeContextString( _lineNumber, getStateSource(), getLineReportingOffset(), false ); } else { return null; } } public String getStateSource() { if( _stateSource == null && _parentClass != null ) { ISource source = _parentClass.getSourceFileHandle().getSource(); return source == null ? null : source.getSource(); } return _stateSource; } public void setStateSource( String parserSource ) { _stateSource = parserSource; } private String getMyMessage() { if (_messageKey != null) { return formatError(_messageKey, _messageArgs); } else if (getCause() != null){ return getCause().getMessage(); } else { return ""; } } public String getPlainMessage() { return getMyMessage(); } public String getConsoleMessage() { StringBuilder retVal = new StringBuilder(); retVal.append( getMyMessage() ); if( _lineNumber != null ) { retVal.append( " [line:" ).append( _lineNumber - getLineReportingOffset() ).append( " col:" ).append( _tokenColumn ); retVal.append( "]" ); if( getStateSource() != null ) { retVal.append( " in\n" ); retVal.append( getContextString() ); } } return (retVal.toString()); } public static String makeContextString( int lineOfError, String source, int lineReportingOffset ) { return makeContextString(lineOfError, source, lineReportingOffset, true); } private static String makeContextString( int lineOfError, String source, int lineReportingOffset, boolean showLineNumbers ) { int offset = (CONTEXT_LINES - 1) / 2; int minLine = Math.max( lineOfError - offset, 1 ); int maxLine = lineOfError + offset; int padding = maxLine <= 0 ? 1 : ((int)Math.log10( maxLine ) + 1); StringBuilder sb = new StringBuilder(); int pos = 0; int currentLine = 1; while( pos < source.length() && currentLine < minLine ) { char c = source.charAt( pos ); if( c == '\n' ) { ++currentLine; } ++pos; } if( showLineNumbers ) { sb.append( String.format( "line %1$" + padding + "s: ", currentLine - lineReportingOffset ) ); } while( pos < source.length() && currentLine <= maxLine ) { char c = source.charAt( pos ); if( c == '\n' ) { ++currentLine; if( currentLine <= maxLine ) { sb.append( '\n' ); if( showLineNumbers ) { sb.append( String.format( "line %1$" + padding + "s: ", currentLine - lineReportingOffset ) ); } } } else { sb.append( c ); } ++pos; } return sb.toString(); } public String getUIMessage() { String strMessage = getMyMessage(); if( strMessage != null ) { int iIndex = strMessage.indexOf( SOURCE_DELIMITER ); if( iIndex >= 0 ) { strMessage = strMessage.substring( 0, iIndex ); } } return strMessage; } public int getLine() { Integer lineNumber = getLineNumber(); return lineNumber == null ? -1 : lineNumber; } public int getColumn() { return getTokenColumn(); } /** * Warning: Only valid if called from the parser thread. Otherwise we null it out. */ public IParsedElement getSource() { return _parentElement; } public void setSource( IParsedElement sourceOfError ) { _parentElement = sourceOfError; } /** * Warning: Only valid if called from the parser thread. Otherwise we null it out. */ public ISymbolTable getSymbolTable() { return _symbolTable; } public boolean appliesToPosition( int iPos ) { Integer tokenStart = getTokenStart(); Integer tokenEnd = getTokenEnd(); return iPos >= tokenStart && iPos <= tokenEnd; } public ResourceKey getMessageKey() { return _messageKey; } public void resolve( IParserPart parserBase ) { if( parserBase != null ) { IScriptPartId scriptPart = parserBase.getOwner().getScriptPart(); IType parentType = scriptPart == null ? null : scriptPart.getContainingType(); if( parentType instanceof IGosuClass ) { _parentClass = (IGosuClass)parentType; _stateSource = null; } } if( _parentElement != null ) { resetPositions(); if( parserBase != null && !parserBase.getOwner().isEditorParser() ) { _parentElement = null; _symbolTable = null; } } } public void resetPositions() { if( _parentElement == null ) { return; } boolean bForce = _parentElement instanceof IExpression && !(_parentElement instanceof IProgram); if( bForce || _lineNumber == null ) { _lineNumber = _parentElement.getLineNum(); } if( bForce || _lineOffset == null ) { _lineOffset = _parentElement.getLocation().getOffset() - _parentElement.getLocation().getColumn(); } if( bForce || _tokenColumn == null ) { _tokenColumn = _parentElement.getColumn(); } if( bForce || _tokenStart == null ) { _tokenStart = _parentElement.getLocation().getOffset(); } if( bForce || _tokenEnd == null ) { _tokenEnd = _parentElement.getLocation().getExtent() + 1; } } public void adjustOffset(int offset, int lineNumOffset, int columnOffset) { _tokenStart += offset; _tokenEnd += offset; _lineNumber += lineNumOffset; _tokenColumn += columnOffset; } public void setMessage( ResourceKey key, Object... args ) { _messageKey = key; _messageArgs = normalizeMessageArgs(args); } public Object[] getMessageArgs() { return _messageArgs; } public int getLineReportingOffset() { return 0; } public IType getExpectedType() { return null; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy