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 | |