| 1 | // Copyright (C) 2016 The Qt Company Ltd. |
| 2 | // Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com> |
| 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 |
| 4 | |
| 5 | #ifndef SYMBOLS_H |
| 6 | #define SYMBOLS_H |
| 7 | |
| 8 | #include "token.h" |
| 9 | #include <qdebug.h> |
| 10 | #include <qhashfunctions.h> |
| 11 | #include <qlist.h> |
| 12 | #include <qstack.h> |
| 13 | #include <qstring.h> |
| 14 | #include <qset.h> |
| 15 | |
| 16 | QT_BEGIN_NAMESPACE |
| 17 | |
| 18 | struct SubArray |
| 19 | { |
| 20 | inline SubArray() = default; |
| 21 | inline SubArray(const QByteArray &a):array(a),from(0), len(a.size()){} |
| 22 | inline SubArray(const char *s):array(s),from(0) { len = array.size(); } |
| 23 | SubArray(const QByteArray &a, qsizetype from, qsizetype len) |
| 24 | : array(a), from(from), len(len) |
| 25 | { |
| 26 | } |
| 27 | QByteArray array; |
| 28 | qsizetype from = 0; |
| 29 | qsizetype len = -1; |
| 30 | inline bool operator==(const SubArray &other) const { |
| 31 | if (len != other.len) |
| 32 | return false; |
| 33 | const auto begin = array.cbegin() + from; |
| 34 | const auto end = begin + len; |
| 35 | const auto other_begin = other.array.cbegin() + other.from; |
| 36 | return std::equal(first1: begin, last1: end, first2: other_begin); |
| 37 | } |
| 38 | }; |
| 39 | |
| 40 | inline size_t qHash(const SubArray &key, size_t seed = 0) |
| 41 | { |
| 42 | return qHash(key: QLatin1StringView(key.array.constData() + key.from, key.len), seed); |
| 43 | } |
| 44 | |
| 45 | |
| 46 | struct Symbol |
| 47 | { |
| 48 | inline Symbol() = default; |
| 49 | inline Symbol(int lineNum, Token token) : lineNum(lineNum), token(token) { } |
| 50 | inline Symbol(int lineNum, Token token, const QByteArray &lexem) |
| 51 | : lineNum(lineNum), token(token), lex(lexem), len(lex.size()) |
| 52 | { |
| 53 | } |
| 54 | Symbol(int lineNum, Token token, const QByteArray &lexem, qsizetype from, qsizetype len) |
| 55 | : lineNum(lineNum), token(token), lex(lexem), from(from), len(len) |
| 56 | { |
| 57 | } |
| 58 | int lineNum = -1; |
| 59 | Token token = NOTOKEN; |
| 60 | inline QByteArray lexem() const { return lex.mid(index: from, len); } |
| 61 | inline QByteArray unquotedLexem() const { return lex.mid(index: from+1, len: len-2); } |
| 62 | inline operator SubArray() const { return SubArray(lex, from, len); } |
| 63 | bool operator==(const Symbol& o) const |
| 64 | { |
| 65 | return SubArray(lex, from, len) == SubArray(o.lex, o.from, o.len); |
| 66 | } |
| 67 | QByteArray lex; |
| 68 | qsizetype from = 0; |
| 69 | qsizetype len = -1; |
| 70 | }; |
| 71 | Q_DECLARE_TYPEINFO(Symbol, Q_RELOCATABLE_TYPE); |
| 72 | |
| 73 | typedef QList<Symbol> Symbols; |
| 74 | |
| 75 | struct SafeSymbols { |
| 76 | Symbols symbols; |
| 77 | QByteArray expandedMacro; |
| 78 | QSet<QByteArray> excludedSymbols; |
| 79 | qsizetype index; |
| 80 | }; |
| 81 | Q_DECLARE_TYPEINFO(SafeSymbols, Q_RELOCATABLE_TYPE); |
| 82 | |
| 83 | class SymbolStack : public QStack<SafeSymbols> |
| 84 | { |
| 85 | public: |
| 86 | inline bool hasNext() { |
| 87 | while (!isEmpty() && top().index >= top().symbols.size()) |
| 88 | pop(); |
| 89 | return !isEmpty(); |
| 90 | } |
| 91 | inline Token next() { |
| 92 | while (!isEmpty() && top().index >= top().symbols.size()) |
| 93 | pop(); |
| 94 | if (isEmpty()) |
| 95 | return NOTOKEN; |
| 96 | return top().symbols.at(i: top().index++).token; |
| 97 | } |
| 98 | bool test(Token); |
| 99 | inline const Symbol &symbol() const { return top().symbols.at(i: top().index-1); } |
| 100 | inline Token token() { return symbol().token; } |
| 101 | inline QByteArray lexem() const { return symbol().lexem(); } |
| 102 | inline QByteArray unquotedLexem() { return symbol().unquotedLexem(); } |
| 103 | |
| 104 | bool dontReplaceSymbol(const QByteArray &name) const; |
| 105 | QSet<QByteArray> excludeSymbols() const; |
| 106 | }; |
| 107 | |
| 108 | inline bool SymbolStack::test(Token token) |
| 109 | { |
| 110 | qsizetype stackPos = size() - 1; |
| 111 | while (stackPos >= 0 && at(i: stackPos).index >= at(i: stackPos).symbols.size()) |
| 112 | --stackPos; |
| 113 | if (stackPos < 0) |
| 114 | return false; |
| 115 | if (at(i: stackPos).symbols.at(i: at(i: stackPos).index).token == token) { |
| 116 | next(); |
| 117 | return true; |
| 118 | } |
| 119 | return false; |
| 120 | } |
| 121 | |
| 122 | inline bool SymbolStack::dontReplaceSymbol(const QByteArray &name) const |
| 123 | { |
| 124 | auto matchesName = [&name](const SafeSymbols &sf) { |
| 125 | return name == sf.expandedMacro || sf.excludedSymbols.contains(value: name); |
| 126 | }; |
| 127 | return std::any_of(first: cbegin(), last: cend(), pred: matchesName); |
| 128 | } |
| 129 | |
| 130 | inline QSet<QByteArray> SymbolStack::excludeSymbols() const |
| 131 | { |
| 132 | QSet<QByteArray> set; |
| 133 | for (const SafeSymbols &sf : *this) { |
| 134 | set << sf.expandedMacro; |
| 135 | set += sf.excludedSymbols; |
| 136 | } |
| 137 | return set; |
| 138 | } |
| 139 | |
| 140 | QT_END_NAMESPACE |
| 141 | |
| 142 | #endif // SYMBOLS_H |
| 143 | |