diff options
Diffstat (limited to 'sources/shiboken6/ApiExtractor/typeparser.cpp')
-rw-r--r-- | sources/shiboken6/ApiExtractor/typeparser.cpp | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/sources/shiboken6/ApiExtractor/typeparser.cpp b/sources/shiboken6/ApiExtractor/typeparser.cpp new file mode 100644 index 000000000..11d7bf641 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/typeparser.cpp @@ -0,0 +1,292 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "typeparser.h" +#include <typeinfo.h> + +#include <QtCore/QDebug> +#include <QtCore/QStack> +#include <QtCore/QTextStream> + +using namespace Qt::StringLiterals; + +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 = 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] == u' ') + ++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 == u'_') { + 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 == u'_') + ++m_pos; + else + break; + } + } + + if (tok == Identifier) { + switch (m_pos - m_tokenStart) { + case 5: + if (m_chars[m_tokenStart] == u'c' + && m_chars[m_tokenStart + 1] == u'o' + && m_chars[m_tokenStart + 2] == u'n' + && m_chars[m_tokenStart + 3] == u's' + && m_chars[m_tokenStart + 4] == u't') { + tok = ConstToken; + } + break; + case 8: + if (m_chars[m_tokenStart] == u'v' + && m_chars[m_tokenStart + 1] == u'o' + && m_chars[m_tokenStart + 2] == u'l' + && m_chars[m_tokenStart + 3] == u'a' + && m_chars[m_tokenStart + 4] == u't' + && m_chars[m_tokenStart + 5] == u'i' + && m_chars[m_tokenStart + 6] == u'l' + && m_chars[m_tokenStart + 7] == u'e') { + tok = VolatileToken; + } + break; + } + } + + return tok; + +} + +QString Scanner::msgParseError(const QString &why) const +{ + return "TypeParser: Unable to parse \""_L1 + + QString(m_chars, m_length) + "\": "_L1 + why; +} + +TypeInfo TypeParser::parse(const QString &str, QString *errorMessage) +{ + Scanner scanner(str); + + QStack<TypeInfo> stack; + stack.push(TypeInfo()); + + 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 {}; + +// 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("Too many '&' qualifiers"_L1); + if (errorMessage) + *errorMessage = message; + else + qWarning().noquote().nospace() << message; + return {}; + } + break; + case Scanner::LessThanToken: + stack.push(TypeInfo()); + break; + + case Scanner::CommaToken: + { + auto i = stack.pop(); + stack.top().addInstantiation(i); // Add after populating to prevent detach + stack.push(TypeInfo()); + } + break; + + case Scanner::GreaterThanToken: { + auto i = stack.pop(); + stack.top().addInstantiation(i); // Add after populating to prevent detach + } + break; + + case Scanner::ColonToken: + colon_prefix = true; + break; + + case Scanner::ConstToken: + if (seenStar) { // "int *const": Last indirection is const. + auto indirections = stack.top().indirectionsV(); + Q_ASSERT(!indirections.isEmpty()); + indirections[0] = Indirection::ConstPointer; + stack.top().setIndirectionsV(indirections); + } else { + stack.top().setConstant(true); + } + break; + + case Scanner::VolatileToken: + stack.top().setVolatile(true); + break; + + case Scanner::OpenParenToken: // function pointers not supported + case Scanner::CloseParenToken: { + const QString message = scanner.msgParseError("Function pointers are not supported"_L1); + if (errorMessage) + *errorMessage = message; + else + qWarning().noquote().nospace() << message; + return {}; + } + + case Scanner::Identifier: + if (in_array) { + array = scanner.identifier(); + } else if (colon_prefix || stack.top().qualifiedName().isEmpty()) { + stack.top().addName(scanner.identifier()); + colon_prefix = false; + } else { + QStringList qualifiedName = stack.top().qualifiedName(); + qualifiedName.last().append(u' ' + scanner.identifier()); + stack.top().setQualifiedName(qualifiedName); + } + break; + + case Scanner::SquareBegin: + in_array = true; + break; + + case Scanner::SquareEnd: + in_array = false; + stack.top().addArrayElement(array); + break; + + + default: + break; + } + + tok = scanner.nextToken(errorMessage); + } + + if (stack.isEmpty() || stack.constFirst().qualifiedName().isEmpty()) { + *errorMessage = u"Unable to parse type \""_s + str + u"\"."_s; + return {}; + } + return stack.constFirst(); +} |