Fix automatic semicolon insertion.
authorRoberto Raggi <roberto.raggi@nokia.com>
Wed, 14 Sep 2011 12:50:24 +0000 (14:50 +0200)
committerQt by Nokia <qt-info@nokia.com>
Mon, 19 Sep 2011 10:07:46 +0000 (12:07 +0200)
The parser should insert a T_SEMICOLON token when it reaches an
error state and the lookahead token is following a closing brace.

Change-Id: Ib849e7fbfe50c2a3e679ae0794f5780cc0b94de5
Reviewed-on: http://codereview.qt-project.org/4896
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Kent Hansen <kent.hansen@nokia.com>
src/declarative/qml/parser/qdeclarativejs.g
src/declarative/qml/parser/qdeclarativejslexer.cpp
src/declarative/qml/parser/qdeclarativejslexer_p.h
src/declarative/qml/parser/qdeclarativejsparser.cpp
tests/auto/declarative/qdeclarativeecmascript/data/automaticSemicolon.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp

index d30c697..7f8e0b6 100644 (file)
@@ -407,14 +407,6 @@ void Parser::reallocateStack()
     string_stack = reinterpret_cast<QStringRef*> (qRealloc(string_stack, stack_size * sizeof(QStringRef)));
 }
 
-inline static bool automatic(Engine *driver, int token)
-{
-    return token == $table::T_RBRACE
-        || token == 0
-        || driver->lexer()->prevTerminator();
-}
-
-
 Parser::Parser(Engine *engine):
     driver(engine),
     pool(engine->pool()),
@@ -2890,7 +2882,7 @@ PropertyNameAndValueListOpt: PropertyNameAndValueList ;
         const int errorState = state_stack[tos];
 
         // automatic insertion of `;'
-        if (yytoken != -1 && t_action(errorState, T_AUTOMATIC_SEMICOLON) && automatic(driver, yytoken)) {
+        if (yytoken != -1 && t_action(errorState, T_AUTOMATIC_SEMICOLON) && lexer->canInsertAutomaticSemicolon(yytoken)) {
             SavedToken &tk = token_buffer[0];
             tk.token = yytoken;
             tk.dval = yylval;
index def027c..dd74ffa 100644 (file)
@@ -111,6 +111,7 @@ Lexer::Lexer(Engine *engine)
     , _prohibitAutomaticSemicolon(false)
     , _restrictedKeyword(false)
     , _terminator(false)
+    , _followsClosingBrace(false)
     , _delimited(false)
     , _qmlMode(true)
 {
@@ -160,6 +161,7 @@ void Lexer::setCode(const QString &code, int lineno, bool qmlMode)
     _prohibitAutomaticSemicolon = false;
     _restrictedKeyword = false;
     _terminator = false;
+    _followsClosingBrace = false;
     _delimited = false;
 }
 
@@ -175,12 +177,15 @@ void Lexer::scanChar()
 
 int Lexer::lex()
 {
+    const int previousTokenKind = _tokenKind;
+
     _tokenSpell = QStringRef();
     _tokenKind = scanToken();
     _tokenLength = _codePtr - _tokenStartPtr - 1;
 
     _delimited = false;
     _restrictedKeyword = false;
+    _followsClosingBrace = (previousTokenKind == T_RBRACE);
 
     // update the flags
     switch (_tokenKind) {
@@ -1044,4 +1049,17 @@ bool Lexer::prevTerminator() const
     return _terminator;
 }
 
+bool Lexer::followsClosingBrace() const
+{
+    return _followsClosingBrace;
+}
+
+bool Lexer::canInsertAutomaticSemicolon(int token) const
+{
+    return token == T_RBRACE
+            || token == EOF_SYMBOL
+            || _terminator
+            || _followsClosingBrace;
+}
+
 #include "qdeclarativejskeywords_p.h"
index 34cd987..6d32786 100644 (file)
@@ -144,6 +144,8 @@ public:
     QString errorMessage() const;
 
     bool prevTerminator() const;
+    bool followsClosingBrace() const;
+    bool canInsertAutomaticSemicolon(int token) const;
 
     enum ParenthesesState {
         IgnoreParentheses,
@@ -201,6 +203,7 @@ private:
     bool _prohibitAutomaticSemicolon;
     bool _restrictedKeyword;
     bool _terminator;
+    bool _followsClosingBrace;
     bool _delimited;
     bool _qmlMode;
 };
index 5c82359..b6cb1fa 100644 (file)
@@ -76,14 +76,6 @@ void Parser::reallocateStack()
     string_stack = reinterpret_cast<QStringRef*> (qRealloc(string_stack, stack_size * sizeof(QStringRef)));
 }
 
-inline static bool automatic(Engine *driver, int token)
-{
-    return token == QDeclarativeJSGrammar::T_RBRACE
-        || token == 0
-        || driver->lexer()->prevTerminator();
-}
-
-
 Parser::Parser(Engine *engine):
     driver(engine),
     pool(engine->pool()),
@@ -1696,7 +1688,7 @@ case 342: {
         const int errorState = state_stack[tos];
 
         // automatic insertion of `;'
-        if (yytoken != -1 && t_action(errorState, T_AUTOMATIC_SEMICOLON) && automatic(driver, yytoken)) {
+        if (yytoken != -1 && t_action(errorState, T_AUTOMATIC_SEMICOLON) && lexer->canInsertAutomaticSemicolon(yytoken)) {
             SavedToken &tk = token_buffer[0];
             tk.token = yytoken;
             tk.dval = yylval;
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/automaticSemicolon.qml b/tests/auto/declarative/qdeclarativeecmascript/data/automaticSemicolon.qml
new file mode 100644 (file)
index 0000000..6db68f2
--- /dev/null
@@ -0,0 +1,11 @@
+
+import QtQuick 2.0
+
+QtObject {
+    function code() {
+        if (1) {
+            var a;
+            function f1(){}a=1;
+        }
+    }
+}
index dc3f053..36941af 100644 (file)
@@ -199,6 +199,8 @@ private slots:
     void revisionErrors();
     void revision();
 
+    void automaticSemicolon();
+
 private:
     QDeclarativeEngine engine;
 };
@@ -4199,6 +4201,13 @@ void tst_qdeclarativeecmascript::dynamicString()
              QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
 }
 
+void tst_qdeclarativeecmascript::automaticSemicolon()
+{
+    QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
+    QObject *object = component.create();
+    QVERIFY(object != 0);
+}
+
 QTEST_MAIN(tst_qdeclarativeecmascript)
 
 #include "tst_qdeclarativeecmascript.moc"