1 | //=== LexHLSLRootSignature.cpp - Lex Root Signature -----------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "clang/Lex/LexHLSLRootSignature.h" |
10 | |
11 | namespace clang { |
12 | namespace hlsl { |
13 | |
14 | using TokenKind = RootSignatureToken::Kind; |
15 | |
16 | // Lexer Definitions |
17 | |
18 | static bool isNumberChar(char C) { |
19 | return isdigit(C) // integer support |
20 | || C == '.' // float support |
21 | || C == 'e' || C == 'E' || C == '-' || C == '+' // exponent support |
22 | || C == 'f' || C == 'F'; // explicit float support |
23 | } |
24 | |
25 | RootSignatureToken RootSignatureLexer::lexToken() { |
26 | // Discard any leading whitespace |
27 | advanceBuffer(NumCharacters: Buffer.take_while(F: isspace).size()); |
28 | |
29 | if (isEndOfBuffer()) |
30 | return RootSignatureToken(TokenKind::end_of_stream, SourceLoc); |
31 | |
32 | // Record where this token is in the text for usage in parser diagnostics |
33 | RootSignatureToken Result(SourceLoc); |
34 | |
35 | char C = Buffer.front(); |
36 | |
37 | // Punctuators |
38 | switch (C) { |
39 | #define PUNCTUATOR(X, Y) \ |
40 | case Y: { \ |
41 | Result.TokKind = TokenKind::pu_##X; \ |
42 | advanceBuffer(); \ |
43 | return Result; \ |
44 | } |
45 | #include "clang/Lex/HLSLRootSignatureTokenKinds.def" |
46 | default: |
47 | break; |
48 | } |
49 | |
50 | // Number literal |
51 | if (isdigit(C) || C == '.') { |
52 | Result.NumSpelling = Buffer.take_while(F: isNumberChar); |
53 | |
54 | // If all values are digits then we have an int literal |
55 | bool IsInteger = Result.NumSpelling.find_if_not(F: isdigit) == StringRef::npos; |
56 | |
57 | Result.TokKind = |
58 | IsInteger ? TokenKind::int_literal : TokenKind::float_literal; |
59 | advanceBuffer(NumCharacters: Result.NumSpelling.size()); |
60 | return Result; |
61 | } |
62 | |
63 | // All following tokens require at least one additional character |
64 | if (Buffer.size() <= 1) { |
65 | Result = RootSignatureToken(TokenKind::invalid, SourceLoc); |
66 | return Result; |
67 | } |
68 | |
69 | // Peek at the next character to deteremine token type |
70 | char NextC = Buffer[1]; |
71 | |
72 | // Registers: [tsub][0-9+] |
73 | if ((C == 't' || C == 's' || C == 'u' || C == 'b') && isdigit(NextC)) { |
74 | // Convert character to the register type. |
75 | switch (C) { |
76 | case 'b': |
77 | Result.TokKind = TokenKind::bReg; |
78 | break; |
79 | case 't': |
80 | Result.TokKind = TokenKind::tReg; |
81 | break; |
82 | case 'u': |
83 | Result.TokKind = TokenKind::uReg; |
84 | break; |
85 | case 's': |
86 | Result.TokKind = TokenKind::sReg; |
87 | break; |
88 | default: |
89 | llvm_unreachable("Switch for an expected token was not provided" ); |
90 | } |
91 | |
92 | advanceBuffer(); |
93 | |
94 | // Lex the integer literal |
95 | Result.NumSpelling = Buffer.take_while(F: isNumberChar); |
96 | advanceBuffer(NumCharacters: Result.NumSpelling.size()); |
97 | |
98 | return Result; |
99 | } |
100 | |
101 | // Keywords and Enums: |
102 | StringRef TokSpelling = |
103 | Buffer.take_while(F: [](char C) { return isalnum(C) || C == '_'; }); |
104 | |
105 | // Define a large string switch statement for all the keywords and enums |
106 | auto Switch = llvm::StringSwitch<TokenKind>(TokSpelling); |
107 | #define KEYWORD(NAME) Switch.CaseLower(#NAME, TokenKind::kw_##NAME); |
108 | #define ENUM(NAME, LIT) Switch.CaseLower(LIT, TokenKind::en_##NAME); |
109 | #include "clang/Lex/HLSLRootSignatureTokenKinds.def" |
110 | |
111 | // Then attempt to retreive a string from it |
112 | Result.TokKind = Switch.Default(Value: TokenKind::invalid); |
113 | advanceBuffer(NumCharacters: TokSpelling.size()); |
114 | return Result; |
115 | } |
116 | |
117 | RootSignatureToken RootSignatureLexer::consumeToken() { |
118 | // If we previously peeked then just return the previous value over |
119 | if (NextToken && NextToken->TokKind != TokenKind::end_of_stream) { |
120 | RootSignatureToken Result = *NextToken; |
121 | NextToken = std::nullopt; |
122 | return Result; |
123 | } |
124 | return lexToken(); |
125 | } |
126 | |
127 | RootSignatureToken RootSignatureLexer::peekNextToken() { |
128 | // Already peeked from the current token |
129 | if (NextToken) |
130 | return *NextToken; |
131 | |
132 | NextToken = lexToken(); |
133 | return *NextToken; |
134 | } |
135 | |
136 | } // namespace hlsl |
137 | } // namespace clang |
138 | |