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