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 <qhash.h> |
11 | #include <qlist.h> |
12 | #include <qstack.h> |
13 | #include <qstring.h> |
14 | #include <qset.h> |
15 | |
16 | QT_BEGIN_NAMESPACE |
17 | |
18 | //#define USE_LEXEM_STORE |
19 | |
20 | struct SubArray |
21 | { |
22 | inline SubArray() = default; |
23 | inline SubArray(const QByteArray &a):array(a),from(0), len(a.size()){} |
24 | inline SubArray(const char *s):array(s),from(0) { len = array.size(); } |
25 | SubArray(const QByteArray &a, qsizetype from, qsizetype len) |
26 | : array(a), from(from), len(len) |
27 | { |
28 | } |
29 | QByteArray array; |
30 | qsizetype from = 0; |
31 | qsizetype len = -1; |
32 | inline bool operator==(const SubArray &other) const { |
33 | if (len != other.len) |
34 | return false; |
35 | const auto begin = array.cbegin() + from; |
36 | const auto end = begin + len; |
37 | const auto other_begin = other.array.cbegin() + other.from; |
38 | return std::equal(first1: begin, last1: end, first2: other_begin); |
39 | } |
40 | }; |
41 | |
42 | inline size_t qHash(const SubArray &key) |
43 | { |
44 | return qHash(key: QLatin1StringView(key.array.constData() + key.from, key.len)); |
45 | } |
46 | |
47 | |
48 | struct Symbol |
49 | { |
50 | |
51 | #ifdef USE_LEXEM_STORE |
52 | typedef QHash<SubArray, QHashDummyValue> LexemStore; |
53 | static LexemStore lexemStore; |
54 | |
55 | inline Symbol() : lineNum(-1),token(NOTOKEN){} |
56 | inline Symbol(int lineNum, Token token): |
57 | lineNum(lineNum), token(token){} |
58 | inline Symbol(int lineNum, Token token, const QByteArray &lexem): |
59 | lineNum(lineNum), token(token),lex(lexem){} |
60 | inline Symbol(int lineNum, Token token, const QByteArray &lexem, int from, int len): |
61 | lineNum(lineNum), token(token){ |
62 | LexemStore::const_iterator it = lexemStore.constFind(SubArray(lexem, from, len)); |
63 | |
64 | if (it != lexemStore.constEnd()) { |
65 | lex = it.key().array; |
66 | } else { |
67 | lex = lexem.mid(from, len); |
68 | lexemStore.insert(lex, QHashDummyValue()); |
69 | } |
70 | } |
71 | int lineNum; |
72 | Token token; |
73 | inline QByteArray unquotedLexem() const { return lex.mid(1, lex.length()-2); } |
74 | inline QByteArray lexem() const { return lex; } |
75 | inline operator QByteArray() const { return lex; } |
76 | QByteArray lex; |
77 | |
78 | #else |
79 | |
80 | inline Symbol() = default; |
81 | inline Symbol(int lineNum, Token token) : lineNum(lineNum), token(token) { } |
82 | inline Symbol(int lineNum, Token token, const QByteArray &lexem) |
83 | : lineNum(lineNum), token(token), lex(lexem), len(lex.size()) |
84 | { |
85 | } |
86 | Symbol(int lineNum, Token token, const QByteArray &lexem, qsizetype from, qsizetype len) |
87 | : lineNum(lineNum), token(token), lex(lexem), from(from), len(len) |
88 | { |
89 | } |
90 | int lineNum = -1; |
91 | Token token = NOTOKEN; |
92 | inline QByteArray lexem() const { return lex.mid(index: from, len); } |
93 | inline QByteArray unquotedLexem() const { return lex.mid(index: from+1, len: len-2); } |
94 | inline operator SubArray() const { return SubArray(lex, from, len); } |
95 | bool operator==(const Symbol& o) const |
96 | { |
97 | return SubArray(lex, from, len) == SubArray(o.lex, o.from, o.len); |
98 | } |
99 | QByteArray lex; |
100 | qsizetype from = 0; |
101 | qsizetype len = -1; |
102 | |
103 | #endif |
104 | }; |
105 | Q_DECLARE_TYPEINFO(Symbol, Q_RELOCATABLE_TYPE); |
106 | |
107 | typedef QList<Symbol> Symbols; |
108 | |
109 | struct SafeSymbols { |
110 | Symbols symbols; |
111 | QByteArray expandedMacro; |
112 | QSet<QByteArray> excludedSymbols; |
113 | qsizetype index; |
114 | }; |
115 | Q_DECLARE_TYPEINFO(SafeSymbols, Q_RELOCATABLE_TYPE); |
116 | |
117 | class SymbolStack : public QStack<SafeSymbols> |
118 | { |
119 | public: |
120 | inline bool hasNext() { |
121 | while (!isEmpty() && top().index >= top().symbols.size()) |
122 | pop(); |
123 | return !isEmpty(); |
124 | } |
125 | inline Token next() { |
126 | while (!isEmpty() && top().index >= top().symbols.size()) |
127 | pop(); |
128 | if (isEmpty()) |
129 | return NOTOKEN; |
130 | return top().symbols.at(i: top().index++).token; |
131 | } |
132 | bool test(Token); |
133 | inline const Symbol &symbol() const { return top().symbols.at(i: top().index-1); } |
134 | inline Token token() { return symbol().token; } |
135 | inline QByteArray lexem() const { return symbol().lexem(); } |
136 | inline QByteArray unquotedLexem() { return symbol().unquotedLexem(); } |
137 | |
138 | bool dontReplaceSymbol(const QByteArray &name) const; |
139 | QSet<QByteArray> excludeSymbols() const; |
140 | }; |
141 | |
142 | inline bool SymbolStack::test(Token token) |
143 | { |
144 | qsizetype stackPos = size() - 1; |
145 | while (stackPos >= 0 && at(i: stackPos).index >= at(i: stackPos).symbols.size()) |
146 | --stackPos; |
147 | if (stackPos < 0) |
148 | return false; |
149 | if (at(i: stackPos).symbols.at(i: at(i: stackPos).index).token == token) { |
150 | next(); |
151 | return true; |
152 | } |
153 | return false; |
154 | } |
155 | |
156 | inline bool SymbolStack::dontReplaceSymbol(const QByteArray &name) const |
157 | { |
158 | auto matchesName = [&name](const SafeSymbols &sf) { |
159 | return name == sf.expandedMacro || sf.excludedSymbols.contains(value: name); |
160 | }; |
161 | return std::any_of(first: cbegin(), last: cend(), pred: matchesName); |
162 | } |
163 | |
164 | inline QSet<QByteArray> SymbolStack::excludeSymbols() const |
165 | { |
166 | QSet<QByteArray> set; |
167 | for (const SafeSymbols &sf : *this) { |
168 | set << sf.expandedMacro; |
169 | set += sf.excludedSymbols; |
170 | } |
171 | return set; |
172 | } |
173 | |
174 | QT_END_NAMESPACE |
175 | |
176 | #endif // SYMBOLS_H |
177 | |