/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of QtUiTest. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "scriptpreprocessor.h" #include "qscriptsystemtest.h" #include #include #include #include ScriptPreprocessor::ScriptPreprocessor() { QScriptEngine engine; QScriptSystemTest::loadInternalScript("config.js", &engine); QScriptValue settings = engine.globalObject().property("preprocess"); if (!settings.isObject()) return; /* The documentation for the following settings objects is in config.js */ { QScriptValueIterator it(settings.property("functionAppends")); while (it.hasNext()) { it.next(); functionAppends[it.name()] = it.value().toString(); } } } void ScriptPreprocessor::preprocess(QString &script) { QString out; out.reserve(script.size()); bool in_singleline_comment = false; bool in_multiline_comment = false; bool in_singlequote_literal = false; bool in_doublequote_literal = false; const char singlequote = '\''; const char doublequote = '"'; const char brace_open = '('; const char brace_close = ')'; const char curlybrace_open = '{'; const char curlybrace_close = '}'; const char newline = '\n'; const char cr = '\r'; const char backslash = '\\'; const char forwardslash = '/'; const char asterisk = '*'; QString identifier_chars = "_"; for (char c = '0'; c <= '9'; ++c) identifier_chars.append(c); for (char c = 'a'; c <= 'z'; ++c) identifier_chars.append(c); for (char c = 'A'; c <= 'Z'; ++c) identifier_chars.append(c); int braces = 0; int curlybraces = 0; QString function_append; int function_append_braces = 0; for (int i = 0; i < script.count(); ++i) { QChar c1 = script[i];//.toLatin1(); QChar c2 = script[i+1];//.toLatin1(); // OK; QByteArray is always null-terminated. if (in_singleline_comment) { if (newline == c1) { in_singleline_comment = false; out.append(c1); continue; } out.append(c1); continue; } if (in_multiline_comment) { if (asterisk == c1 && forwardslash == c2) { in_multiline_comment = false; out.append(c1); out.append(c2); ++i; continue; } out.append(c1); continue; } if (in_singlequote_literal) { if (backslash == c1) { out.append(c1); out.append(c2); ++i; continue; } if (singlequote == c1) { in_singlequote_literal = false; out.append(c1); continue; } if (cr == c1 && newline == c2) { out.append("\\n\'+\r\n\'"); ++i; continue; } if (newline == c1) { out.append("\\n\'+\n\'"); continue; } out.append(c1); continue; } if (in_doublequote_literal) { if (backslash == c1) { out.append(c1); out.append(c2); ++i; continue; } if (doublequote == c1) { in_doublequote_literal = false; out.append(c1); continue; } if (cr == c1 && newline == c2) { out.append("\\n\"+\r\n\""); ++i; continue; } if (newline == c1) { out.append("\\n\"+\n\""); continue; } out.append(c1); continue; } switch(c1.toLatin1()) { case singlequote: in_singlequote_literal = true; out.append(c1); continue; case doublequote: in_doublequote_literal = true; out.append(c1); continue; case forwardslash: out.append(c1); if (c2 == forwardslash) { in_singleline_comment = true; out.append(c2); ++i; } if (c2 == asterisk) { in_multiline_comment = true; out.append(c2); ++i; } continue; case brace_open: ++braces; out.append(c1); continue; case brace_close: --braces; out.append(c1); if (!function_append.isEmpty() && function_append_braces == braces) { out.append(function_append); function_append = QString(); } continue; case curlybrace_open: ++curlybraces; out.append(c1); continue; case curlybrace_close: --curlybraces; out.append(c1); continue; default: // Look ahead to next non-identifier character int tok_len; for (tok_len = 0; i + tok_len < script.count() && identifier_chars.contains(script[i+tok_len]); ++tok_len) {} if (tok_len < 2) { out.append(c1); continue; } QString tok = script.mid(i, tok_len); // Apply preprocessing rules // 1. Function appends - text placed immediately after the closing // bracket of a function invocation. if (functionAppends.contains(tok)) { function_append = functionAppends[tok]; function_append_braces = braces; } out.append(tok); i += tok_len - 1; continue; } } out.squeeze(); script = out; }