1/*
2 * Copyright (C) 2018 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#if ENABLE(WEBGPU)
29
30#include <wtf/Optional.h>
31#include <wtf/Vector.h>
32#include <wtf/text/StringConcatenate.h>
33#include <wtf/text/StringConcatenateNumbers.h>
34#include <wtf/text/StringView.h>
35#include <wtf/text/WTFString.h>
36
37namespace WebCore {
38
39namespace WHLSL {
40
41class Lexer {
42public:
43 Lexer() = default;
44
45 Lexer(StringView stringView)
46 : m_stringView(stringView)
47 {
48 skipWhitespaceAndComments();
49 }
50
51 Lexer(const Lexer&) = delete;
52 Lexer(Lexer&&) = default;
53
54 Lexer& operator=(const Lexer&) = delete;
55 Lexer& operator=(Lexer&&) = default;
56
57 struct Token {
58 Token() = delete;
59 Token(const Token&) = default;
60 Token(Token&&) = default;
61 Token& operator=(const Token&) = default;
62 Token& operator=(Token&&) = default;
63
64 StringView stringView;
65 unsigned lineNumber;
66 enum class Type {
67 IntLiteral,
68 UintLiteral,
69 FloatLiteral,
70 Struct,
71 Typedef,
72 Enum,
73 Operator,
74 If,
75 Else,
76 Continue,
77 Break,
78 Switch,
79 Case,
80 Default,
81 Fallthrough,
82 For,
83 While,
84 Do,
85 Return,
86 Trap,
87 Null,
88 True,
89 False,
90 Constant,
91 Device,
92 Threadgroup,
93 Thread,
94 Space,
95 Vertex,
96 Fragment,
97 Compute,
98 NumThreads,
99 SVInstanceID,
100 SVVertexID,
101 PSize,
102 SVPosition,
103 SVIsFrontFace,
104 SVSampleIndex,
105 SVInnerCoverage,
106 SVTarget,
107 SVDepth,
108 SVCoverage,
109 SVDispatchThreadID,
110 SVGroupID,
111 SVGroupIndex,
112 SVGroupThreadID,
113 Attribute,
114 Register,
115 Specialized,
116 Native,
117 Restricted,
118 Underscore,
119 Auto,
120 Protocol,
121 Const,
122 Static,
123 Qualifier,
124 Identifier,
125 OperatorName,
126 EqualsSign,
127 Semicolon,
128 LeftCurlyBracket,
129 RightCurlyBracket,
130 Colon,
131 Comma,
132 LeftParenthesis,
133 RightParenthesis,
134 SquareBracketPair,
135 LeftSquareBracket,
136 RightSquareBracket,
137 Star,
138 LessThanSign,
139 GreaterThanSign,
140 FullStop,
141 PlusEquals,
142 MinusEquals,
143 TimesEquals,
144 DivideEquals,
145 ModEquals,
146 XorEquals,
147 AndEquals,
148 OrEquals,
149 RightShiftEquals,
150 LeftShiftEquals,
151 PlusPlus,
152 MinusMinus,
153 Arrow,
154 QuestionMark,
155 OrOr,
156 AndAnd,
157 Or,
158 Xor,
159 And,
160 LessThanOrEqualTo,
161 GreaterThanOrEqualTo,
162 EqualComparison,
163 NotEqual,
164 RightShift,
165 LeftShift,
166 Plus,
167 Minus,
168 Divide,
169 Mod,
170 Tilde,
171 ExclamationPoint,
172 At,
173 } type;
174
175 static const char* typeName(Type);
176 };
177
178 Optional<Token> consumeToken()
179 {
180 if (!m_stack.isEmpty())
181 return m_stack.takeLast();
182 return consumeTokenFromStream();
183 }
184
185 void unconsumeToken(Token&& token)
186 {
187 m_stack.append(WTFMove(token));
188 }
189
190 struct State {
191 Vector<Token> stack;
192 unsigned offset;
193 unsigned lineNumber;
194 };
195
196 State state() const
197 {
198 return { m_stack, m_offset, m_lineNumber };
199 }
200
201 void setState(const State& state)
202 {
203 m_stack = state.stack;
204 m_offset = state.offset;
205 m_lineNumber = state.lineNumber;
206 }
207
208 void setState(State&& state)
209 {
210 m_stack = WTFMove(state.stack);
211 m_offset = WTFMove(state.offset);
212 m_lineNumber = WTFMove(state.lineNumber);
213 }
214
215 bool isFullyConsumed() const
216 {
217 return m_offset == m_stringView.length();
218 }
219
220 String errorString(const Token& token, const String& message)
221 {
222 return makeString("Parse error at line ", token.lineNumber, ": ", message);
223 }
224
225private:
226 Optional<Token> consumeTokenFromStream();
227
228 void skipWhitespaceAndComments();
229 void skipWhitespace();
230 void skipLineComment();
231 void skipLongComment();
232
233 Optional<Token::Type> recognizeKeyword(unsigned end);
234
235 Optional<unsigned> coreDecimalIntLiteral(unsigned) const;
236 Optional<unsigned> decimalIntLiteral(unsigned) const;
237 Optional<unsigned> decimalUintLiteral(unsigned) const;
238 Optional<unsigned> coreHexadecimalIntLiteral(unsigned) const;
239 Optional<unsigned> hexadecimalIntLiteral(unsigned) const;
240 Optional<unsigned> hexadecimalUintLiteral(unsigned) const;
241 Optional<unsigned> intLiteral(unsigned) const;
242 Optional<unsigned> uintLiteral(unsigned) const;
243 Optional<unsigned> digit(unsigned) const;
244 unsigned digitStar(unsigned) const;
245 Optional<unsigned> character(char, unsigned) const;
246 template<unsigned length> Optional<unsigned> anyCharacter(const char (&string)[length], unsigned) const;
247 Optional<unsigned> coreFloatLiteralType1(unsigned) const;
248 Optional<unsigned> coreFloatLiteral(unsigned) const;
249 Optional<unsigned> floatLiteral(unsigned) const;
250 template<unsigned length> Optional<unsigned> string(const char (&string)[length], unsigned) const;
251 Optional<unsigned> validIdentifier(unsigned) const;
252 Optional<unsigned> identifier(unsigned) const;
253 Optional<unsigned> operatorName(unsigned) const;
254
255 StringView m_stringView;
256 Vector<Token> m_stack;
257 unsigned m_offset { 0 };
258 unsigned m_lineNumber { 0 };
259};
260
261template<unsigned length> Optional<unsigned> Lexer::string(const char (&string)[length], unsigned offset) const
262{
263 for (unsigned i = 0; i < length - 1; ++i) {
264 if (offset + i >= m_stringView.length() || m_stringView[offset + i] != string[i])
265 return WTF::nullopt;
266 }
267 return offset + length - 1;
268}
269
270template<unsigned length> Optional<unsigned> Lexer::anyCharacter(const char (&string)[length], unsigned offset) const
271{
272 if (offset >= m_stringView.length())
273 return WTF::nullopt;
274 for (unsigned i = 0; i < length - 1; ++i) {
275 if (m_stringView[offset] == string[i])
276 return offset + 1;
277 }
278 return WTF::nullopt;
279}
280
281} // namespace WHLSL
282
283} // namespace WebCore
284
285#endif // ENABLE(WEBGPU)
286