Skip to content

Commit 0fdb4e7

Browse files
author
Finn Plummer
committed
[HLSL][RootSignature] Implement parsing of an empty DescriptorTable
- defines the Parser class and an initial set of helper methods to support consuming tokens. functionality is demonstrated through a simple empty descriptor table test case - defines an initial in-memory representation of a DescriptorTable - implements a test harness that will be used to validate the correct diagnostics are generated. it will construct a dummy pre-processor with diagnostics consumer to do so
1 parent a2d3cb7 commit 0fdb4e7

File tree

7 files changed

+498
-0
lines changed

7 files changed

+498
-0
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//===--- ParseHLSLRootSignature.h -------------------------------*- C++ -*-===//
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+
// This file defines the ParseHLSLRootSignature interface.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_CLANG_PARSE_PARSEHLSLROOTSIGNATURE_H
14+
#define LLVM_CLANG_PARSE_PARSEHLSLROOTSIGNATURE_H
15+
16+
#include "clang/Basic/DiagnosticParse.h"
17+
#include "clang/Lex/Preprocessor.h"
18+
#include "clang/Lex/LexHLSLRootSignature.h"
19+
20+
#include "llvm/ADT/SmallVector.h"
21+
#include "llvm/ADT/StringRef.h"
22+
23+
#include "llvm/Frontend/HLSL/HLSLRootSignature.h"
24+
25+
namespace clang {
26+
namespace hlsl {
27+
28+
class RootSignatureParser {
29+
public:
30+
RootSignatureParser(SmallVector<llvm::hlsl::rootsig::RootElement> &Elements,
31+
RootSignatureLexer &Lexer, clang::Preprocessor &PP);
32+
33+
/// Consumes tokens from the Lexer and constructs the in-memory
34+
/// representations of the RootElements. Tokens are consumed until an
35+
/// error is encountered or the end of the buffer.
36+
///
37+
/// Returns true if a parsing error is encountered.
38+
bool Parse();
39+
40+
private:
41+
DiagnosticsEngine &Diags() { return PP.getDiagnostics(); }
42+
43+
/// Root Element parse methods:
44+
bool ParseDescriptorTable();
45+
46+
/// Invoke the Lexer to consume a token and update CurToken with the result
47+
void ConsumeNextToken() { CurToken = Lexer.ConsumeToken(); }
48+
49+
/// Return true if the next token one of the expected kinds
50+
bool PeekExpectedToken(TokenKind Expected);
51+
bool PeekExpectedToken(ArrayRef<TokenKind> AnyExpected);
52+
53+
/// Consumes the next token and report an error if it is not of the expected
54+
/// kind.
55+
///
56+
/// Returns true if there was an error reported.
57+
bool ConsumeExpectedToken(TokenKind Expected,
58+
unsigned DiagID = diag::err_expected,
59+
TokenKind Context = TokenKind::invalid);
60+
bool ConsumeExpectedToken(ArrayRef<TokenKind> AnyExpected,
61+
unsigned DiagID = diag::err_expected,
62+
TokenKind Context = TokenKind::invalid);
63+
64+
/// Peek if the next token is of the expected kind and if it is then consume
65+
/// it.
66+
///
67+
/// Returns true if it successfully matches the expected kind and the token
68+
/// was consumed.
69+
bool TryConsumeExpectedToken(TokenKind Expected);
70+
bool TryConsumeExpectedToken(ArrayRef<TokenKind> Expected);
71+
72+
private:
73+
SmallVector<llvm::hlsl::rootsig::RootElement> &Elements;
74+
RootSignatureLexer &Lexer;
75+
76+
clang::Preprocessor &PP;
77+
78+
RootSignatureToken CurToken;
79+
};
80+
81+
} // namespace hlsl
82+
} // namespace clang
83+
84+
#endif // LLVM_CLANG_PARSE_PARSEHLSLROOTSIGNATURE_H

clang/lib/Parse/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ add_clang_library(clangParse
1414
ParseExpr.cpp
1515
ParseExprCXX.cpp
1616
ParseHLSL.cpp
17+
ParseHLSLRootSignature.cpp
1718
ParseInit.cpp
1819
ParseObjc.cpp
1920
ParseOpenMP.cpp
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#include "clang/Parse/ParseHLSLRootSignature.h"
2+
3+
#include "llvm/Support/raw_ostream.h"
4+
5+
using namespace llvm::hlsl::rootsig;
6+
7+
namespace clang {
8+
namespace hlsl {
9+
10+
static std::string FormatTokenKinds(ArrayRef<TokenKind> Kinds) {
11+
std::string TokenString;
12+
llvm::raw_string_ostream Out(TokenString);
13+
bool First = true;
14+
for (auto Kind : Kinds) {
15+
if (!First)
16+
Out << ", ";
17+
switch (Kind) {
18+
#define TOK(X, SPELLING) \
19+
case TokenKind::X: \
20+
Out << SPELLING; \
21+
break;
22+
#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
23+
}
24+
First = false;
25+
}
26+
27+
return TokenString;
28+
}
29+
30+
// Parser Definitions
31+
32+
RootSignatureParser::RootSignatureParser(SmallVector<RootElement> &Elements,
33+
RootSignatureLexer &Lexer,
34+
Preprocessor &PP)
35+
: Elements(Elements), Lexer(Lexer), PP(PP), CurToken(SourceLocation()) {}
36+
37+
bool RootSignatureParser::Parse() {
38+
// Iterate as many RootElements as possible
39+
while (TryConsumeExpectedToken(TokenKind::kw_DescriptorTable)) {
40+
bool Error = false;
41+
// Dispatch onto parser method.
42+
// We guard against the unreachable here as we just ensured that CurToken
43+
// will be one of the kinds in the while condition
44+
switch (CurToken.Kind) {
45+
case TokenKind::kw_DescriptorTable:
46+
Error = ParseDescriptorTable();
47+
break;
48+
default:
49+
llvm_unreachable("Switch for consumed token was not provided");
50+
}
51+
52+
if (Error) return true;
53+
54+
if (!TryConsumeExpectedToken(TokenKind::pu_comma))
55+
break;
56+
}
57+
58+
return ConsumeExpectedToken(TokenKind::end_of_stream, diag::err_expected);
59+
}
60+
61+
bool RootSignatureParser::ParseDescriptorTable() {
62+
DescriptorTable Table;
63+
64+
if (ConsumeExpectedToken(TokenKind::pu_l_paren, diag::err_expected_after,
65+
CurToken.Kind))
66+
return true;
67+
68+
if (ConsumeExpectedToken(TokenKind::pu_r_paren, diag::err_expected_after,
69+
CurToken.Kind))
70+
return true;
71+
72+
Elements.push_back(Table);
73+
return false;
74+
}
75+
76+
// Returns true when given token is one of the expected kinds
77+
static bool IsExpectedToken(TokenKind Kind, ArrayRef<TokenKind> AnyExpected) {
78+
for (auto Expected : AnyExpected)
79+
if (Kind == Expected)
80+
return true;
81+
return false;
82+
}
83+
84+
bool RootSignatureParser::PeekExpectedToken(TokenKind Expected) {
85+
return PeekExpectedToken(ArrayRef{Expected});
86+
}
87+
88+
bool RootSignatureParser::PeekExpectedToken(ArrayRef<TokenKind> AnyExpected) {
89+
RootSignatureToken Result = Lexer.PeekNextToken();
90+
return IsExpectedToken(Result.Kind, AnyExpected);
91+
}
92+
93+
bool RootSignatureParser::ConsumeExpectedToken(TokenKind Expected,
94+
unsigned DiagID,
95+
TokenKind Context) {
96+
return ConsumeExpectedToken(ArrayRef{Expected}, DiagID, Context);
97+
}
98+
99+
bool RootSignatureParser::ConsumeExpectedToken(ArrayRef<TokenKind> AnyExpected,
100+
unsigned DiagID,
101+
TokenKind Context) {
102+
if (TryConsumeExpectedToken(AnyExpected))
103+
return false;
104+
105+
// Report unexpected token kind error
106+
DiagnosticBuilder DB = Diags().Report(CurToken.TokLoc, DiagID);
107+
switch (DiagID) {
108+
case diag::err_expected:
109+
DB << FormatTokenKinds(AnyExpected);
110+
break;
111+
case diag::err_expected_either:
112+
case diag::err_expected_after:
113+
DB << FormatTokenKinds(AnyExpected) << FormatTokenKinds({Context});
114+
break;
115+
default:
116+
break;
117+
}
118+
return true;
119+
}
120+
121+
bool RootSignatureParser::TryConsumeExpectedToken(TokenKind Expected) {
122+
return TryConsumeExpectedToken(ArrayRef{Expected});
123+
}
124+
125+
bool RootSignatureParser::TryConsumeExpectedToken(
126+
ArrayRef<TokenKind> AnyExpected) {
127+
// If not the expected token just return
128+
if (!PeekExpectedToken(AnyExpected))
129+
return false;
130+
ConsumeNextToken();
131+
return true;
132+
}
133+
134+
} // namespace hlsl
135+
} // namespace clang

clang/unittests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ endfunction()
2525

2626
add_subdirectory(Basic)
2727
add_subdirectory(Lex)
28+
add_subdirectory(Parse)
2829
add_subdirectory(Driver)
2930
if(CLANG_ENABLE_STATIC_ANALYZER)
3031
add_subdirectory(Analysis)

clang/unittests/Parse/CMakeLists.txt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
set(LLVM_LINK_COMPONENTS
2+
Support
3+
)
4+
add_clang_unittest(ParseTests
5+
ParseHLSLRootSignatureTest.cpp
6+
)
7+
clang_target_link_libraries(ParseTests
8+
PRIVATE
9+
clangAST
10+
clangASTMatchers
11+
clangBasic
12+
clangFrontend
13+
clangParse
14+
clangSema
15+
clangSerialization
16+
clangTooling
17+
)
18+
target_link_libraries(ParseTests
19+
PRIVATE
20+
LLVMTestingAnnotations
21+
LLVMTestingSupport
22+
clangTesting
23+
)

0 commit comments

Comments
 (0)