diff options
Diffstat (limited to 'sources/shiboken6/ApiExtractor/typeparser.cpp')
-rw-r--r-- | sources/shiboken6/ApiExtractor/typeparser.cpp | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/sources/shiboken6/ApiExtractor/typeparser.cpp b/sources/shiboken6/ApiExtractor/typeparser.cpp new file mode 100644 index 000000000..c440fb66d --- /dev/null +++ b/sources/shiboken6/ApiExtractor/typeparser.cpp @@ -0,0 +1,305 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "typeparser.h" +#include <codemodel.h> + +#include <QtCore/QDebug> +#include <QtCore/QStack> +#include <QtCore/QTextStream> + +class Scanner +{ +public: + enum Token { + StarToken, + AmpersandToken, + LessThanToken, + ColonToken, + CommaToken, + OpenParenToken, + CloseParenToken, + SquareBegin, + SquareEnd, + GreaterThanToken, + + ConstToken, + VolatileToken, + Identifier, + NoToken, + InvalidToken + }; + + Scanner(const QString &s) + : m_pos(0), m_length(s.length()), m_tokenStart(-1), m_chars(s.constData()) + { + } + + Token nextToken(QString *errorMessage = Q_NULLPTR); + QString identifier() const; + + QString msgParseError(const QString &why) const; + +private: + int m_pos; + int m_length; + int m_tokenStart; + const QChar *m_chars; +}; + +QString Scanner::identifier() const +{ + return QString(m_chars + m_tokenStart, m_pos - m_tokenStart); +} + +Scanner::Token Scanner::nextToken(QString *errorMessage) +{ + Token tok = NoToken; + + // remove whitespace + while (m_pos < m_length && m_chars[m_pos] == QLatin1Char(' ')) + ++m_pos; + + m_tokenStart = m_pos; + + while (m_pos < m_length) { + + const QChar &c = m_chars[m_pos]; + + if (tok == NoToken) { + switch (c.toLatin1()) { + case '*': tok = StarToken; break; + case '&': tok = AmpersandToken; break; + case '<': tok = LessThanToken; break; + case '>': tok = GreaterThanToken; break; + case ',': tok = CommaToken; break; + case '(': tok = OpenParenToken; break; + case ')': tok = CloseParenToken; break; + case '[': tok = SquareBegin; break; + case ']' : tok = SquareEnd; break; + case ':': + tok = ColonToken; + Q_ASSERT(m_pos + 1 < m_length); + ++m_pos; + break; + default: + if (c.isLetterOrNumber() || c == QLatin1Char('_')) { + tok = Identifier; + } else { + QString message; + QTextStream (&message) << ": Unrecognized character in lexer at " + << m_pos << " : '" << c << '\''; + message = msgParseError(message); + if (errorMessage) + *errorMessage = message; + else + qWarning().noquote().nospace() << message; + return InvalidToken; + } + break; + } + } + + if (tok <= GreaterThanToken) { + ++m_pos; + break; + } + + if (tok == Identifier) { + if (c.isLetterOrNumber() || c == QLatin1Char('_')) + ++m_pos; + else + break; + } + } + + if (tok == Identifier) { + switch (m_pos - m_tokenStart) { + case 5: + if (m_chars[m_tokenStart] == QLatin1Char('c') + && m_chars[m_tokenStart + 1] == QLatin1Char('o') + && m_chars[m_tokenStart + 2] == QLatin1Char('n') + && m_chars[m_tokenStart + 3] == QLatin1Char('s') + && m_chars[m_tokenStart + 4] == QLatin1Char('t')) { + tok = ConstToken; + } + break; + case 8: + if (m_chars[m_tokenStart] == QLatin1Char('v') + && m_chars[m_tokenStart + 1] == QLatin1Char('o') + && m_chars[m_tokenStart + 2] == QLatin1Char('l') + && m_chars[m_tokenStart + 3] == QLatin1Char('a') + && m_chars[m_tokenStart + 4] == QLatin1Char('t') + && m_chars[m_tokenStart + 5] == QLatin1Char('i') + && m_chars[m_tokenStart + 6] == QLatin1Char('l') + && m_chars[m_tokenStart + 7] == QLatin1Char('e')) { + tok = VolatileToken; + } + break; + } + } + + return tok; + +} + +QString Scanner::msgParseError(const QString &why) const +{ + return QStringLiteral("TypeParser: Unable to parse \"") + + QString(m_chars, m_length) + QStringLiteral("\": ") + why; +} + +TypeInfo TypeParser::parse(const QString &str, QString *errorMessage) +{ + Scanner scanner(str); + + TypeInfo info; + QStack<TypeInfo *> stack; + stack.push(&info); + + bool colon_prefix = false; + bool in_array = false; + QString array; + bool seenStar = false; + + Scanner::Token tok = scanner.nextToken(errorMessage); + while (tok != Scanner::NoToken) { + if (tok == Scanner::InvalidToken) + return TypeInfo(); + +// switch (tok) { +// case Scanner::StarToken: printf(" - *\n"); break; +// case Scanner::AmpersandToken: printf(" - &\n"); break; +// case Scanner::LessThanToken: printf(" - <\n"); break; +// case Scanner::GreaterThanToken: printf(" - >\n"); break; +// case Scanner::ColonToken: printf(" - ::\n"); break; +// case Scanner::CommaToken: printf(" - ,\n"); break; +// case Scanner::ConstToken: printf(" - const\n"); break; +// case Scanner::SquareBegin: printf(" - [\n"); break; +// case Scanner::SquareEnd: printf(" - ]\n"); break; +// case Scanner::Identifier: printf(" - '%s'\n", qPrintable(scanner.identifier())); break; +// default: +// break; +// } + + switch (tok) { + + case Scanner::StarToken: + seenStar = true; + stack.top()->addIndirection(Indirection::Pointer); + break; + + case Scanner::AmpersandToken: + switch (stack.top()->referenceType()) { + case NoReference: + stack.top()->setReferenceType(LValueReference); + break; + case LValueReference: + stack.top()->setReferenceType(RValueReference); + break; + case RValueReference: + const QString message = scanner.msgParseError(QStringLiteral("Too many '&' qualifiers")); + if (errorMessage) + *errorMessage = message; + else + qWarning().noquote().nospace() << message; + return TypeInfo(); + } + break; + case Scanner::LessThanToken: + stack.top()->m_instantiations << TypeInfo(); + stack.push(&stack.top()->m_instantiations.last()); + break; + + case Scanner::CommaToken: + stack.pop(); + stack.top()->m_instantiations << TypeInfo(); + stack.push(&stack.top()->m_instantiations.last()); + break; + + case Scanner::GreaterThanToken: + stack.pop(); + break; + + case Scanner::ColonToken: + colon_prefix = true; + break; + + case Scanner::ConstToken: + if (seenStar) { // "int *const": Last indirection is const. + Q_ASSERT(!stack.top()->m_indirections.isEmpty()); + *stack.top()->m_indirections.rbegin() = Indirection::ConstPointer; + } else { + stack.top()->m_constant = true; + } + break; + + case Scanner::VolatileToken: + stack.top()->m_volatile = true; + break; + + case Scanner::OpenParenToken: // function pointers not supported + case Scanner::CloseParenToken: { + const QString message = scanner.msgParseError(QStringLiteral("Function pointers are not supported")); + if (errorMessage) + *errorMessage = message; + else + qWarning().noquote().nospace() << message; + return TypeInfo(); + } + + case Scanner::Identifier: + if (in_array) { + array = scanner.identifier(); + } else if (colon_prefix || stack.top()->m_qualifiedName.isEmpty()) { + stack.top()->m_qualifiedName << scanner.identifier(); + colon_prefix = false; + } else { + stack.top()->m_qualifiedName.last().append(QLatin1Char(' ') + scanner.identifier()); + } + break; + + case Scanner::SquareBegin: + in_array = true; + break; + + case Scanner::SquareEnd: + in_array = false; + stack.top()->m_arrayElements += array; + break; + + + default: + break; + } + + tok = scanner.nextToken(); + } + + return info; +} |