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