ada.editor/src/org/netbeans/modules/ada/editor/parser/Ada95ErrorHandler.java
author Andrea Lucarelli <raster@netbeans.org>
Sun, 22 Aug 2010 23:37:11 +0200
branchrelease68
changeset 16367 d2820c029d3a
parent 15779 367c7fdb5d23
permissions -rw-r--r--
Add JVM compiler support.
     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
     5  *
     6  * The contents of this file are subject to the terms of either the GNU
     7  * General Public License Version 2 only ("GPL") or the Common
     8  * Development and Distribution License("CDDL") (collectively, the
     9  * "License"). You may not use this file except in compliance with the
    10  * License. You can obtain a copy of the License at
    11  * http://www.netbeans.org/cddl-gplv2.html
    12  * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    13  * specific language governing permissions and limitations under the
    14  * License.  When distributing the software, include this License Header
    15  * Notice in each file and include the License file at
    16  * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
    17  * particular file as subject to the "Classpath" exception as provided
    18  * by Sun in the GPL Version 2 section of the License file that
    19  * accompanied this code. If applicable, add the following below the
    20  * License Header, with the fields enclosed by brackets [] replaced by
    21  * your own identifying information:
    22  * "Portions Copyrighted [year] [name of copyright owner]"
    23  *
    24  * If you wish your version of this file to be governed by only the CDDL
    25  * or only the GPL Version 2, indicate your decision by adding
    26  * "[Contributor] elects to include this software in this distribution
    27  * under the [CDDL or GPL Version 2] license." If you do not indicate a
    28  * single choice of license, a recipient has the option to distribute
    29  * your version of this file under either the CDDL, the GPL Version 2 or
    30  * to extend the choice of license to its licensees as provided above.
    31  * However, if you add GPL Version 2 code and therefore, elected the GPL
    32  * Version 2 license, then the option applies only if the new code is
    33  * made subject to such option by the copyright holder.
    34  *
    35  * Contributor(s):
    36  *
    37  * Portions Copyrighted 2008 Sun Microsystems, Inc.
    38  */
    39 
    40 package org.netbeans.modules.ada.editor.parser;
    41 
    42 import java.util.ArrayList;
    43 import java.util.Arrays;
    44 import java.util.List;
    45 import java.util.logging.Level;
    46 import java.util.logging.Logger;
    47 import java_cup.runtime.Symbol;
    48 import org.netbeans.modules.ada.editor.parser.AdaParser.Context;
    49 import org.netbeans.modules.ada.editor.ast.ASTError;
    50 import org.netbeans.modules.ada.editor.ast.ASTNode;
    51 import org.netbeans.modules.ada.editor.ast.nodes.Program;
    52 import org.netbeans.modules.csl.api.Severity;
    53 import org.openide.util.NbBundle;
    54 import org.netbeans.modules.csl.api.Error;
    55 
    56 /**
    57  * Based on org.netbeans.modules.php.editor.parser.PHP5ErrorHandler
    58  *
    59  * @author Andrea Lucarelli
    60  */
    61 public class Ada95ErrorHandler implements ParserErrorHandler {
    62 
    63     private static final Logger LOGGER = Logger.getLogger(Ada95ErrorHandler.class.getName());
    64     
    65     public static class SyntaxError {
    66         private final short[] expectedTokens;
    67         private final Symbol currentToken;
    68         private final Symbol previousToken;
    69 
    70         public SyntaxError(short[] expectedTokens, Symbol currentToken, Symbol previousToken) {
    71             this.expectedTokens = expectedTokens;
    72             this.currentToken = currentToken;
    73             this.previousToken = previousToken;
    74         }
    75 
    76         public Symbol getCurrentToken() {
    77             return currentToken;
    78         }
    79 
    80         public Symbol getPreviousToken() {
    81             return previousToken;
    82         }
    83 
    84         public short[] getExpectedTokens() {
    85             return expectedTokens;
    86         }
    87     }
    88     
    89     private final List<SyntaxError> syntaxErrors;
    90 
    91     private final Context context;
    92     AdaParser outer;
    93 
    94     public Ada95ErrorHandler(Context context, AdaParser outer) {
    95         super();
    96         this.outer = outer;
    97         this.context = context;
    98         syntaxErrors = new ArrayList<SyntaxError>();
    99         //LOGGER.setLevel(Level.FINE);
   100     }
   101 
   102     public void handleError(Type type, short[] expectedtokens, Symbol current, Symbol previous) {
   103         Error error;
   104         if (type == ParserErrorHandler.Type.SYNTAX_ERROR) {
   105             // logging syntax error
   106             if (LOGGER.isLoggable(Level.FINE)) {
   107                 LOGGER.fine("Syntax error:"); //NOI18N
   108                 LOGGER.fine("Current [" + current.left + ", " + current.right + "](" + Utils.getASTScannerTokenName(current.sym) + "): " + current.value); //NOI18N
   109                 LOGGER.fine("Previous [" + previous.left + ", " + previous.right + "] (" + Utils.getASTScannerTokenName(previous.sym) + "):" + previous.value); //NOI18N
   110                 StringBuffer message = new StringBuffer();
   111                 message.append("Expected tokens:"); //NOI18N
   112                 for (int i = 0; i < expectedtokens.length; i += 2) {
   113                     message.append(" ").append( Utils.getASTScannerTokenName(expectedtokens[i])); //NOI18N
   114                 }
   115                 LOGGER.fine(message.toString());
   116             }
   117             syntaxErrors.add(new SyntaxError(expectedtokens, current, previous));
   118         } else {
   119             String message = null;
   120             if (current != null) {
   121                 String tagText = getTokenTextForm(current.sym);
   122                 if (tagText != null) {
   123                     message = NbBundle.getMessage(Ada95ErrorHandler.class, "SE_Unexpected") + " " + tagText;
   124                 }
   125                 else {
   126                     message = NbBundle.getMessage(Ada95ErrorHandler.class, "SE_Unexpected") + " " + Utils.getASTScannerTokenName(current.sym);
   127                 }
   128             }
   129             if (message == null) {
   130                 message = "Parser error"; // NOI18N
   131             }
   132             error = new AdaError(message, context.getSnapshot().getSource().getFileObject(), current.left, current.right, Severity.ERROR, null);
   133             //context.getListener().error(error);
   134         }
   135     }
   136 
   137     public void handleError(Type type, Symbol symbol, String message) {
   138         Error error;
   139         if (symbol != null) {
   140             if (message == null) {
   141                 message = "Parser error";
   142             }
   143             error = new AdaError(message,  context.getSnapshot().getSource().getFileObject(), symbol.left, symbol.right, Severity.ERROR, null);
   144             //TODO: context.getListener().error(error);
   145         }
   146     }
   147 
   148     public List<Error> displayFatalError(){
   149         Error error = new FatalError();
   150         return Arrays.asList(error);
   151     }
   152     
   153     public List<Error>  displaySyntaxErrors(Program program) {
   154         List<Error> errors = new ArrayList<Error>();
   155         for (SyntaxError syntaxError : syntaxErrors) {
   156             ASTNode astError = null;
   157             if (program != null) {
   158                 astError = org.netbeans.modules.ada.editor.ast.ASTUtils.getNodeAtOffset(program, syntaxError.currentToken.left);
   159                 if (!(astError instanceof ASTError)) {
   160                     astError = org.netbeans.modules.ada.editor.ast.ASTUtils.getNodeAtOffset(program, syntaxError.previousToken.right);
   161                     if (!(astError instanceof ASTError)) {
   162                         astError = null;
   163                     }
   164                 }
   165                 if (astError != null) {
   166                     LOGGER.fine("ASTError [" + astError.getStartOffset() + ", " + astError.getEndOffset() + "]"); //NOI18N
   167                 } else {
   168                     LOGGER.fine("ASTError was not found");  //NOI18N
   169                 }
   170             }
   171             Error error = defaultSyntaxErrorHandling(syntaxError, astError);
   172             errors.add(error);
   173         }
   174         return errors;
   175     }
   176     
   177     // This is just defualt handling. We can do a logic, which will find metter 
   178     private Error defaultSyntaxErrorHandling(SyntaxError syntaxError, ASTNode astError) {
   179         Error error = null;
   180         String unexpectedText = "";     //NOI18N
   181         StringBuffer message = new StringBuffer();
   182         boolean isUnexpected = false;
   183         int start  = syntaxError.getCurrentToken().left;
   184         int end = syntaxError.getCurrentToken().right;
   185         
   186         if (syntaxError.getCurrentToken().sym == Ada95ASTSymbols.EOF) {
   187             isUnexpected = true;
   188             unexpectedText = NbBundle.getMessage(Ada95ErrorHandler.class, "SE_EOF");
   189             start = end - 1;
   190         }
   191         else {
   192             String currentText = (String)syntaxError.getCurrentToken().value;
   193             isUnexpected = currentText != null && currentText.trim().length() > 0;
   194             if (isUnexpected) {
   195                 unexpectedText = currentText.trim();
   196                 end = start + unexpectedText.length();
   197             }
   198         }
   199         
   200         List<String> possibleTags = new ArrayList<String>();
   201         for (int i = 0; i < syntaxError.getExpectedTokens().length; i += 2) {
   202             String text = getTokenTextForm(syntaxError.getExpectedTokens()[i]);
   203             if (text != null) {
   204                 possibleTags.add(text);
   205             }
   206         }
   207 
   208         message.append(NbBundle.getMessage(Ada95ErrorHandler.class, "SE_Message"));
   209         message.append(':'); //NOI18N
   210         if (isUnexpected) {
   211             message.append(' ').append(NbBundle.getMessage(Ada95ErrorHandler.class, "SE_Unexpected"));
   212             message.append(": "); //NOI18N
   213             message.append(unexpectedText);
   214         }
   215         if (possibleTags.size() > 0) {
   216             message.append('\n').append(NbBundle.getMessage(Ada95ErrorHandler.class, "SE_Expected"));
   217             message.append(": "); //NOI18N
   218             boolean addOR = false;
   219             for (String tag : possibleTags) {
   220                 if (addOR) {
   221                     message.append(" " + NbBundle.getMessage(Ada95ErrorHandler.class, "SE_Or") + " ");
   222                 }
   223                 else {
   224                     addOR = true;
   225                 }
   226                 
   227                 message.append(tag);
   228             }
   229         }
   230 
   231         if (astError != null){
   232             start = astError.getStartOffset();
   233             end = astError.getEndOffset();
   234             // if the asterror is trough two lines, the problem is ussually at the end
   235             String text = context.getSource().substring(start, end);
   236             int lastNewLine = text.length()-1;
   237             while (text.charAt(lastNewLine) == '\n' || text.charAt(lastNewLine) == '\r'
   238                     || text.charAt(lastNewLine) == '\t' || text.charAt(lastNewLine) == ' ') {
   239                 lastNewLine--;
   240                 if (lastNewLine < 0) {
   241                     break;
   242                 }
   243             }
   244             lastNewLine = text.lastIndexOf('\n', lastNewLine);   //NOI18N
   245             if (lastNewLine > 0) {
   246                 start = start + lastNewLine + 1;
   247             }
   248         }
   249         error = new AdaError(message.toString(), context.getSnapshot().getSource().getFileObject(), start, end, Severity.ERROR, new Object[]{syntaxError});
   250         return error;
   251     }
   252 
   253     public List<SyntaxError> getSyntaxErrors() {
   254         return syntaxErrors;
   255     }
   256 
   257     private String getTokenTextForm (int token) {
   258         String text = null;
   259         switch (token) {
   260             case Ada95ASTSymbols.BASED_LITERAL : text = "number"; break; //NOI18N
   261             case Ada95ASTSymbols.DECIMAL_LITERAL : text = "number"; break; //NOI18N
   262             case Ada95ASTSymbols.IDENTIFIER : text = "identifier"; break; //NOI18N
   263             case Ada95ASTSymbols.ABORT : text = "abort"; break; //NOI18N
   264             case Ada95ASTSymbols.ABS : text = "abs"; break; //NOI18N
   265             case Ada95ASTSymbols.ABSTRACT : text = "abstract"; break; //NOI18N
   266             case Ada95ASTSymbols.ACCESS : text = "access"; break; //NOI18N
   267             case Ada95ASTSymbols.ACCEPT : text = "access"; break; //NOI18N
   268             case Ada95ASTSymbols.ALIASED : text = "aliased"; break; //NOI18N
   269             case Ada95ASTSymbols.ALL : text = "all"; break; //NOI18N
   270             case Ada95ASTSymbols.AND : text = "and"; break; //NOI18N
   271             case Ada95ASTSymbols.ARRAY : text = "array"; break; //NOI18N
   272             case Ada95ASTSymbols.AT : text = "at"; break; //NOI18N
   273             case Ada95ASTSymbols.BEGIN : text = "begin"; break; //NOI18N
   274             case Ada95ASTSymbols.BODY : text = "body"; break; //NOI18N
   275             case Ada95ASTSymbols.CONSTANT : text = "constant"; break; //NOI18N
   276             case Ada95ASTSymbols.CASE : text = "case"; break; //NOI18N
   277             case Ada95ASTSymbols.DECLARE : text = "declare"; break; //NOI18N
   278             case Ada95ASTSymbols.DELAY : text = "delay"; break; //NOI18N
   279             case Ada95ASTSymbols.DELTA : text = "delta"; break; //NOI18N
   280             case Ada95ASTSymbols.DIGITS : text = "digits"; break; //NOI18N
   281             case Ada95ASTSymbols.DO : text = "do"; break; //NOI18N
   282             case Ada95ASTSymbols.ELSE : text = "else"; break; //NOI18N
   283             case Ada95ASTSymbols.ELSIF : text = "elsif"; break; //NOI18N
   284             case Ada95ASTSymbols.END : text = "end"; break; //NOI18N
   285             case Ada95ASTSymbols.ENTRY : text = "entry"; break; //NOI18N
   286             case Ada95ASTSymbols.EXCEPTION : text = "exception"; break; //NOI18N
   287             case Ada95ASTSymbols.EXIT : text = "exit"; break; //NOI18N
   288             case Ada95ASTSymbols.FOR : text = "for"; break; //NOI18N
   289             case Ada95ASTSymbols.FUNCTION : text = "function"; break; //NOI18N
   290             case Ada95ASTSymbols.GENERIC : text = "generic"; break; //NOI18N
   291             case Ada95ASTSymbols.GOTO : text = "goto"; break; //NOI18N
   292             case Ada95ASTSymbols.IF : text = "if"; break; //NOI18N
   293             case Ada95ASTSymbols.IN : text = "in"; break; //NOI18N
   294             case Ada95ASTSymbols.IS : text = "is"; break; //NOI18N
   295             case Ada95ASTSymbols.LIMITED : text = "limited"; break; //NOI18N
   296             case Ada95ASTSymbols.LOOP : text = "loop"; break; //NOI18N
   297             case Ada95ASTSymbols.MOD : text = "mod"; break; //NOI18N
   298             case Ada95ASTSymbols.NEW : text = "new"; break; //NOI18N
   299             case Ada95ASTSymbols.NOT : text = "not"; break; //NOI18N
   300             case Ada95ASTSymbols.NULL : text = "null"; break; //NOI18N
   301             case Ada95ASTSymbols.OF : text = "of"; break; //NOI18N
   302             case Ada95ASTSymbols.OR : text = "or"; break; //NOI18N
   303             case Ada95ASTSymbols.OTHERS : text = "others"; break; //NOI18N
   304             case Ada95ASTSymbols.OUT : text = "out"; break; //NOI18N
   305             case Ada95ASTSymbols.PACKAGE : text = "package"; break; //NOI18N
   306             case Ada95ASTSymbols.PRAGMA : text = "pragma"; break; //NOI18N
   307             case Ada95ASTSymbols.PRIVATE : text = "private"; break; //NOI18N
   308             case Ada95ASTSymbols.PROCEDURE : text = "procedure"; break; //NOI18N
   309             case Ada95ASTSymbols.PROTECTED : text = "protected"; break; //NOI18N
   310             case Ada95ASTSymbols.RETURN : text = "return"; break; //NOI18N
   311             case Ada95ASTSymbols.REVERSE : text = "reverse"; break; //NOI18N
   312             case Ada95ASTSymbols.RAISE : text = "raise"; break; //NOI18N
   313             case Ada95ASTSymbols.RANGE : text = "range"; break; //NOI18N
   314             case Ada95ASTSymbols.RECORD : text = "record"; break; //NOI18N
   315             case Ada95ASTSymbols.REM : text = "rem"; break; //NOI18N
   316             case Ada95ASTSymbols.RENAMES : text = "renames"; break; //NOI18N
   317             case Ada95ASTSymbols.REQUEUE : text = "requeue"; break; //NOI18N
   318             case Ada95ASTSymbols.SELECT : text = "select"; break; //NOI18N
   319             case Ada95ASTSymbols.SEPARATE : text = "separate"; break; //NOI18N
   320             case Ada95ASTSymbols.SUBTYPE : text = "subtype"; break; //NOI18N
   321             case Ada95ASTSymbols.TAGGED : text = "tagged"; break; //NOI18N
   322             case Ada95ASTSymbols.TASK : text = "task"; break; //NOI18N
   323             case Ada95ASTSymbols.TERMINATE : text = "terminate"; break; //NOI18N
   324             case Ada95ASTSymbols.THEN : text = "then"; break; //NOI18N
   325             case Ada95ASTSymbols.TYPE : text = "type"; break; //NOI18N
   326             case Ada95ASTSymbols.UNTIL : text = "until"; break; //NOI18N
   327             case Ada95ASTSymbols.USE : text = "use"; break; //NOI18N
   328             case Ada95ASTSymbols.WHEN : text = "when"; break; //NOI18N
   329             case Ada95ASTSymbols.WHILE : text = "while"; break; //NOI18N
   330             case Ada95ASTSymbols.WITH : text = "with"; break; //NOI18N
   331             case Ada95ASTSymbols.XOR : text = "xor"; break; //NOI18N
   332             case Ada95ASTSymbols.AMP : text = "&"; break; //NOI18N
   333             case Ada95ASTSymbols.TICK : text = "'"; break; //NOI18N
   334             case Ada95ASTSymbols.LPAREN : text = "("; break; //NOI18N
   335             case Ada95ASTSymbols.RPAREN : text = ")"; break; //NOI18N
   336             case Ada95ASTSymbols.STAR : text = "*"; break; //NOI18N
   337             case Ada95ASTSymbols.PLUS : text = "+"; break; //NOI18N
   338             case Ada95ASTSymbols.COMMA : text = ","; break; //NOI18N
   339             case Ada95ASTSymbols.MINUS : text = "-"; break; //NOI18N
   340             case Ada95ASTSymbols.DOT : text = "."; break; //NOI18N
   341             case Ada95ASTSymbols.SLASH : text = "/"; break; //NOI18N
   342             case Ada95ASTSymbols.COLON : text = ":"; break; //NOI18N
   343             case Ada95ASTSymbols.SEMICOLON : text = ";"; break; //NOI18N
   344             case Ada95ASTSymbols.GT : text = "<"; break; //NOI18N
   345             case Ada95ASTSymbols.EQ : text = "="; break; //NOI18N
   346             case Ada95ASTSymbols.LT : text = ">"; break; //NOI18N
   347             case Ada95ASTSymbols.BAR : text = "|"; break; //NOI18N
   348             case Ada95ASTSymbols.ARROW : text = "=>"; break; //NOI18N
   349             case Ada95ASTSymbols.DOT_DOT : text = ".."; break; //NOI18N
   350             case Ada95ASTSymbols.EXPON : text = "**"; break; //NOI18N
   351             case Ada95ASTSymbols.ASSIGNMENT : text = ":="; break; //NOI18N
   352             case Ada95ASTSymbols.INEQ : text = "/="; break; //NOI18N
   353             case Ada95ASTSymbols.GTEQ : text = ">="; break; //NOI18N
   354             case Ada95ASTSymbols.LTEQ : text = "<="; break; //NOI18N
   355             case Ada95ASTSymbols.LTLT : text = "<<"; break; //NOI18N
   356             case Ada95ASTSymbols.GTGT : text = ">>"; break; //NOI18N
   357             case Ada95ASTSymbols.BOX : text = "<>"; break; //NOI18N
   358         }
   359         return text;
   360     }
   361 
   362     private class FatalError extends AdaError{
   363         FatalError(){
   364             super(NbBundle.getMessage(Ada95ErrorHandler.class, "MSG_FatalError"),
   365                 context.getSnapshot().getSource().getFileObject(),
   366                 0, context.getSource().length(),
   367                 Severity.ERROR, null);
   368         }
   369 
   370         @Override
   371         public boolean isLineError() {
   372             return false;
   373         }
   374     }
   375 }