src/script/parser/qscriptsyntaxchecker.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtScript module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qscriptsyntaxchecker_p.h"
       
    43 
       
    44 #include "qscriptlexer_p.h"
       
    45 #include "qscriptparser_p.h"
       
    46 
       
    47 QT_BEGIN_NAMESPACE
       
    48 
       
    49 namespace QScript {
       
    50 
       
    51 
       
    52 SyntaxChecker::SyntaxChecker():
       
    53     tos(0),
       
    54     stack_size(0),
       
    55     state_stack(0)
       
    56 {
       
    57 }
       
    58 
       
    59 SyntaxChecker::~SyntaxChecker()
       
    60 {
       
    61     if (stack_size) {
       
    62         qFree(state_stack);
       
    63     }
       
    64 }
       
    65 
       
    66 bool SyntaxChecker::automatic(QScript::Lexer *lexer, int token) const
       
    67 {
       
    68     return token == T_RBRACE || token == 0 || lexer->prevTerminator();
       
    69 }
       
    70 
       
    71 SyntaxChecker::Result SyntaxChecker::checkSyntax(const QString &code)
       
    72 {
       
    73   const int INITIAL_STATE = 0;
       
    74   QScript::Lexer lexer (/*engine=*/ 0);
       
    75   lexer.setCode(code, /*lineNo*/ 1);
       
    76 
       
    77   int yytoken = -1;
       
    78   int saved_yytoken = -1;
       
    79   QString error_message;
       
    80   int error_lineno = -1;
       
    81   int error_column = -1;
       
    82   State checkerState = Valid;
       
    83 
       
    84   reallocateStack();
       
    85 
       
    86   tos = 0;
       
    87   state_stack[++tos] = INITIAL_STATE;
       
    88 
       
    89   while (true)
       
    90     {
       
    91       const int state = state_stack [tos];
       
    92       if (yytoken == -1 && - TERMINAL_COUNT != action_index [state])
       
    93         {
       
    94           if (saved_yytoken == -1)
       
    95             yytoken = lexer.lex();
       
    96           else
       
    97             {
       
    98               yytoken = saved_yytoken;
       
    99               saved_yytoken = -1;
       
   100             }
       
   101         }
       
   102 
       
   103       int act = t_action (state, yytoken);
       
   104 
       
   105       if (act == ACCEPT_STATE) {
       
   106           if (lexer.error() == QScript::Lexer::UnclosedComment)
       
   107               checkerState = Intermediate;
       
   108           else
       
   109               checkerState = Valid;
       
   110           break;
       
   111       } else if (act > 0) {
       
   112           if (++tos == stack_size)
       
   113             reallocateStack();
       
   114 
       
   115           state_stack [tos] = act;
       
   116           yytoken = -1;
       
   117         }
       
   118 
       
   119       else if (act < 0)
       
   120         {
       
   121           int r = - act - 1;
       
   122 
       
   123           tos -= rhs [r];
       
   124           act = state_stack [tos++];
       
   125 
       
   126           if ((r == Q_SCRIPT_REGEXPLITERAL_RULE1)
       
   127               || (r == Q_SCRIPT_REGEXPLITERAL_RULE2)) {
       
   128               // Skip the rest of the RegExp literal
       
   129               bool rx = lexer.scanRegExp();
       
   130               if (!rx) {
       
   131                   checkerState = Intermediate;
       
   132                   break;
       
   133               }
       
   134           }
       
   135 
       
   136           state_stack [tos] = nt_action (act, lhs [r] - TERMINAL_COUNT);
       
   137         }
       
   138 
       
   139       else
       
   140         {
       
   141           if (saved_yytoken == -1 && automatic (&lexer, yytoken) && t_action (state, T_AUTOMATIC_SEMICOLON) > 0)
       
   142             {
       
   143               saved_yytoken = yytoken;
       
   144               yytoken = T_SEMICOLON;
       
   145               continue;
       
   146             }
       
   147 
       
   148           else if ((state == INITIAL_STATE) && (yytoken == 0)) {
       
   149               // accept empty input
       
   150               yytoken = T_SEMICOLON;
       
   151               continue;
       
   152           }
       
   153 
       
   154           int ers = state;
       
   155           int shifts = 0;
       
   156           int reduces = 0;
       
   157           int expected_tokens [3];
       
   158           for (int tk = 0; tk < TERMINAL_COUNT; ++tk)
       
   159             {
       
   160               int k = t_action (ers, tk);
       
   161 
       
   162               if (! k)
       
   163                 continue;
       
   164               else if (k < 0)
       
   165                 ++reduces;
       
   166               else if (spell [tk])
       
   167                 {
       
   168                   if (shifts < 3)
       
   169                     expected_tokens [shifts] = tk;
       
   170                   ++shifts;
       
   171                 }
       
   172             }
       
   173 
       
   174           error_message.clear ();
       
   175           if (shifts && shifts < 3)
       
   176             {
       
   177               bool first = true;
       
   178 
       
   179               for (int s = 0; s < shifts; ++s)
       
   180                 {
       
   181                   if (first)
       
   182                     error_message += QLatin1String ("Expected ");
       
   183                   else
       
   184                     error_message += QLatin1String (", ");
       
   185 
       
   186                   first = false;
       
   187                   error_message += QLatin1Char('`');
       
   188                   error_message += QLatin1String (spell [expected_tokens [s]]);
       
   189                   error_message += QLatin1Char('\'');
       
   190                 }
       
   191             }
       
   192 
       
   193           if (error_message.isEmpty())
       
   194               error_message = lexer.errorMessage();
       
   195 
       
   196           error_lineno = lexer.startLineNo();
       
   197           error_column = lexer.startColumnNo();
       
   198           checkerState = Error;
       
   199           break;
       
   200         }
       
   201     }
       
   202 
       
   203   if (checkerState == Error) {
       
   204       if (lexer.error() == QScript::Lexer::UnclosedComment)
       
   205           checkerState = Intermediate;
       
   206       else if (yytoken == 0)
       
   207           checkerState = Intermediate;
       
   208   }
       
   209   return Result(checkerState, error_lineno, error_column, error_message);
       
   210 }
       
   211 
       
   212 } // namespace QScript
       
   213 
       
   214 QT_END_NAMESPACE