001    /*
002     * Copyright 2007 Google Inc.
003     * 
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005     * use this file except in compliance with the License. You may obtain a copy of
006     * the License at
007     * 
008     * http://www.apache.org/licenses/LICENSE-2.0
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012     * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013     * License for the specific language governing permissions and limitations under
014     * the License.
015     */
016    package com.google.gwt.dev.js;
017    
018    /**
019     * Indicates inability to parse JavaScript source.
020     */
021    public class JsParserException extends Exception {
022    
023      /**
024       * Represents the location of a parser exception.
025       */
026      public static class SourceDetail {
027        private final String fileName;
028        private final int line;
029        private final int lineOffset;
030        private final String lineSource;
031    
032        public SourceDetail(int line, String lineSource, int lineOffset,
033            String fileName) {
034          this.line = line;
035          this.lineSource = lineSource;
036          this.lineOffset = lineOffset;
037          this.fileName = fileName;
038        }
039    
040        public String getFileName() {
041          return fileName;
042        }
043    
044        public int getLine() {
045          return line;
046        }
047    
048        public int getLineOffset() {
049          return lineOffset;
050        }
051    
052        public String getLineSource() {
053          return lineSource;
054        }
055      }
056    
057      private static String createMessageWithDetail(String msg,
058          SourceDetail sourceDetail) {
059        if (sourceDetail == null) {
060          return msg;
061        }
062        StringBuffer sb = new StringBuffer();
063        sb.append(sourceDetail.getFileName());
064        sb.append('(');
065        sb.append(sourceDetail.getLine());
066        sb.append(')');
067        sb.append(": ");
068        sb.append(msg);
069        if (sourceDetail.getLineSource() != null) {
070          sb.append("\n> ");
071          sb.append(sourceDetail.getLineSource());
072          sb.append("\n> ");
073          for (int i = 0, n = sourceDetail.getLineOffset(); i < n; ++i) {
074            sb.append('-');
075          }
076          sb.append('^');
077        }
078        return sb.toString();
079      }
080    
081      private final SourceDetail sourceDetail;
082    
083      public JsParserException(String msg) {
084        this(msg, null);
085      }
086    
087      public JsParserException(String msg, int line, String lineSource,
088          int lineOffset, String fileName) {
089        this(msg, new SourceDetail(line, lineSource, lineOffset, fileName));
090      }
091    
092      public JsParserException(String msg, SourceDetail sourceDetail) {
093        super(createMessageWithDetail(msg, sourceDetail));
094        this.sourceDetail = sourceDetail;
095      }
096    
097      /**
098       * Provides additional source detail in some cases.
099       * 
100       * @return additional detail regarding the error, or <code>null</code> if no
101       *         additional detail is available
102       */
103      public SourceDetail getSourceDetail() {
104        return sourceDetail;
105      }
106    }