[clang] [llvm] [HLSL][RootSignature] Implement parsing of a DescriptorTable with empty clauses (PR #133302)

Justin Bogner via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 27 14:57:02 PDT 2025


================
@@ -0,0 +1,188 @@
+#include "clang/Parse/ParseHLSLRootSignature.h"
+
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm::hlsl::rootsig;
+
+namespace clang {
+namespace hlsl {
+
+static std::string FormatTokenKinds(ArrayRef<TokenKind> Kinds) {
+  std::string TokenString;
+  llvm::raw_string_ostream Out(TokenString);
+  bool First = true;
+  for (auto Kind : Kinds) {
+    if (!First)
+      Out << ", ";
+    switch (Kind) {
+#define TOK(X, SPELLING)                                                       \
+  case TokenKind::X:                                                           \
+    Out << SPELLING;                                                           \
+    break;
+#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
+    }
+    First = false;
+  }
+
+  return TokenString;
+}
+
+// Parser Definitions
+
+RootSignatureParser::RootSignatureParser(SmallVector<RootElement> &Elements,
+                                         RootSignatureLexer &Lexer,
+                                         Preprocessor &PP)
+    : Elements(Elements), Lexer(Lexer), PP(PP), CurToken(SourceLocation()) {}
+
+bool RootSignatureParser::Parse() {
+  // Iterate as many RootElements as possible
+  while (TryConsumeExpectedToken(TokenKind::kw_DescriptorTable)) {
+    bool Error = false;
+    // Dispatch onto parser method.
+    // We guard against the unreachable here as we just ensured that CurToken
+    // will be one of the kinds in the while condition
+    switch (CurToken.Kind) {
+    case TokenKind::kw_DescriptorTable:
+      Error = ParseDescriptorTable();
+      break;
+    default:
+      llvm_unreachable("Switch for consumed token was not provided");
+    }
+
+    if (Error)
+      return true;
+
+    if (!TryConsumeExpectedToken(TokenKind::pu_comma))
+      break;
+  }
+
+  return ConsumeExpectedToken(TokenKind::end_of_stream, diag::err_expected);
+}
+
+bool RootSignatureParser::ParseDescriptorTable() {
+  assert(CurToken.Kind == TokenKind::kw_DescriptorTable &&
+         "Expects to only be invoked starting at given keyword");
+
+  DescriptorTable Table;
+
+  if (ConsumeExpectedToken(TokenKind::pu_l_paren, diag::err_expected_after,
+                           CurToken.Kind))
+    return true;
+
+  // Iterate as many Clauses as possible
+  while (TryConsumeExpectedToken({TokenKind::kw_CBV, TokenKind::kw_SRV,
+                                  TokenKind::kw_UAV, TokenKind::kw_Sampler})) {
+    if (ParseDescriptorTableClause())
+      return true;
+
+    Table.NumClauses++;
+
+    if (!TryConsumeExpectedToken(TokenKind::pu_comma))
+      break;
+  }
+
+  if (ConsumeExpectedToken(TokenKind::pu_r_paren, diag::err_expected_after,
+                           CurToken.Kind))
+    return true;
+
+  Elements.push_back(Table);
+  return false;
+}
+
+bool RootSignatureParser::ParseDescriptorTableClause() {
+  assert((CurToken.Kind == TokenKind::kw_CBV ||
+          CurToken.Kind == TokenKind::kw_SRV ||
+          CurToken.Kind == TokenKind::kw_UAV ||
+          CurToken.Kind == TokenKind::kw_Sampler) &&
+         "Expects to only be invoked starting at given keyword");
+
+  DescriptorTableClause Clause;
+  switch (CurToken.Kind) {
+  default:
+    break; // Unreachable given Try + assert pattern
+  case TokenKind::kw_CBV:
+    Clause.Type = ClauseType::CBuffer;
+    break;
+  case TokenKind::kw_SRV:
+    Clause.Type = ClauseType::SRV;
+    break;
+  case TokenKind::kw_UAV:
+    Clause.Type = ClauseType::UAV;
+    break;
+  case TokenKind::kw_Sampler:
+    Clause.Type = ClauseType::Sampler;
+    break;
+  }
+
+  if (ConsumeExpectedToken(TokenKind::pu_l_paren, diag::err_expected_after,
+                           CurToken.Kind))
+    return true;
+
+  if (ConsumeExpectedToken(TokenKind::pu_r_paren, diag::err_expected_after,
+                           CurToken.Kind))
+    return true;
+
+  Elements.push_back(Clause);
+  return false;
+}
+
+// Returns true when given token is one of the expected kinds
+static bool IsExpectedToken(TokenKind Kind, ArrayRef<TokenKind> AnyExpected) {
+  for (auto Expected : AnyExpected)
+    if (Kind == Expected)
+      return true;
+  return false;
+}
+
+bool RootSignatureParser::PeekExpectedToken(TokenKind Expected) {
+  return PeekExpectedToken(ArrayRef{Expected});
+}
+
+bool RootSignatureParser::PeekExpectedToken(ArrayRef<TokenKind> AnyExpected) {
+  RootSignatureToken Result = Lexer.PeekNextToken();
+  return IsExpectedToken(Result.Kind, AnyExpected);
----------------
bogner wrote:

You could just use `std::find` (or it's range-aware llvm version) here if you like.

https://github.com/llvm/llvm-project/pull/133302


More information about the llvm-commits mailing list