Skip to content

Commit 1482098

Browse files
ParsingTools: add ParseType function
1 parent 5d3ed43 commit 1482098

2 files changed

Lines changed: 297 additions & 3 deletions

File tree

Common/interface/ParsingTools.hpp

Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2025 Diligent Graphics LLC
2+
* Copyright 2019-2026 Diligent Graphics LLC
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -1350,6 +1350,130 @@ inline void StripPreprocessorDirectives(std::string& Source, const std::vector<s
13501350
}
13511351
}
13521352

1353+
1354+
/// Describes a type parsed from the source code
1355+
template <typename TokenClass>
1356+
struct TypeDesc
1357+
{
1358+
/// Type token.
1359+
TokenClass* TypeToken = nullptr;
1360+
1361+
/// Members of the type.
1362+
struct Member
1363+
{
1364+
/// Member type.
1365+
TokenClass* TypeToken = nullptr;
1366+
1367+
/// Member name.
1368+
TokenClass* NameToken = nullptr;
1369+
1370+
/// Array dimensions (if the member is an array).
1371+
std::vector<TokenClass*> ArrayDimensions = {};
1372+
};
1373+
/// Members of the type.
1374+
std::vector<Member> Members = {};
1375+
};
1376+
1377+
template <typename TokenClass, typename TokenIterType>
1378+
TypeDesc<TokenClass> ParseType(const TokenIterType& Start, const TokenIterType& End, const TokenIterType& NameToken)
1379+
{
1380+
TokenIterType Token = NameToken;
1381+
1382+
TypeDesc<TokenClass> Type;
1383+
Type.TypeToken = &(*Token);
1384+
1385+
using TokenType = typename TokenClass::TokenType;
1386+
1387+
// struct TestStruct
1388+
// ^
1389+
++Token;
1390+
if (Token == End || Token->GetType() != TokenType::OpenBrace)
1391+
return {};
1392+
1393+
// struct TestStruct
1394+
// {
1395+
// ^
1396+
1397+
TokenIterType ClosingBrace = FindMatchingBracket(Start, End, Token);
1398+
if (ClosingBrace == End)
1399+
return {};
1400+
1401+
++Token;
1402+
// struct TestStruct
1403+
// {
1404+
// int i;
1405+
// ^
1406+
while (Token != ClosingBrace)
1407+
{
1408+
TokenClass& MemberTypeToken = *Token;
1409+
1410+
++Token;
1411+
if (Token == ClosingBrace || Token->GetType() != TokenType::Identifier)
1412+
{
1413+
// int ;
1414+
// ^
1415+
return {};
1416+
}
1417+
1418+
// int i;
1419+
// ^
1420+
1421+
TokenClass& MemberNameToken = *Token;
1422+
Type.Members.push_back({&MemberTypeToken, &MemberNameToken});
1423+
1424+
++Token;
1425+
while (Token != ClosingBrace && Token->GetType() != TokenType::Semicolon)
1426+
{
1427+
if (Token->GetType() == TokenType::OpenSquareBracket)
1428+
{
1429+
// int i[10];
1430+
// ^
1431+
TokenIterType ClosingSquareBracket = FindMatchingBracket(Start, ClosingBrace, Token);
1432+
if (ClosingSquareBracket == ClosingBrace)
1433+
{
1434+
// int i[10
1435+
// ^
1436+
return {};
1437+
}
1438+
++Token;
1439+
1440+
if (Token == ClosingSquareBracket)
1441+
{
1442+
// int i[]
1443+
// ^
1444+
return {};
1445+
}
1446+
1447+
// int i[10];
1448+
// ^
1449+
Type.Members.back().ArrayDimensions.push_back(&(*Token));
1450+
Token = ClosingSquareBracket;
1451+
// int i[10];
1452+
// ^
1453+
}
1454+
else
1455+
{
1456+
// int x y;
1457+
// ^
1458+
return {};
1459+
}
1460+
++Token;
1461+
}
1462+
1463+
if (Token == ClosingBrace || Token->GetType() != TokenType::Semicolon)
1464+
{
1465+
// int i
1466+
// }
1467+
// ^
1468+
return {};
1469+
}
1470+
1471+
++Token;
1472+
}
1473+
1474+
return Type;
1475+
}
1476+
13531477
} // namespace Parsing
13541478

13551479
} // namespace Diligent

Tests/DiligentCoreTest/src/Common/ParsingToolsTest.cpp

Lines changed: 172 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2025 Diligent Graphics LLC
2+
* Copyright 2019-2026 Diligent Graphics LLC
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -665,7 +665,8 @@ enum class TestTokenType
665665
Keyword1,
666666
Keyword2,
667667
Keyword3,
668-
kw_void
668+
kw_void,
669+
Struct
669670
};
670671

671672
struct TestToken
@@ -726,6 +727,9 @@ struct TestToken
726727
if (strncmp(IdentifierStart, "void", IdentifierEnd - IdentifierStart) == 0)
727728
return TokenType::kw_void;
728729

730+
if (strncmp(IdentifierStart, "struct", IdentifierEnd - IdentifierStart) == 0)
731+
return TokenType::Struct;
732+
729733
return TokenType::Identifier;
730734
}
731735

@@ -1662,4 +1666,170 @@ void main()
16621666
{{"version"}, {"extension"}, {"error"}});
16631667
}
16641668

1669+
1670+
struct ReferenceTypeDesc
1671+
{
1672+
std::string Type;
1673+
1674+
struct Member
1675+
{
1676+
std::string Type;
1677+
std::string Name;
1678+
std::vector<std::string> ArrayDimensions = {};
1679+
};
1680+
std::vector<Member> Members = {};
1681+
1682+
bool operator==(const Parsing::TypeDesc<const TestToken>& Other) const
1683+
{
1684+
if (Type != (Other.TypeToken ? Other.TypeToken->Literal : ""))
1685+
return false;
1686+
if (Members.size() != Other.Members.size())
1687+
return false;
1688+
for (size_t i = 0; i < Members.size(); ++i)
1689+
{
1690+
const Member& RefMember = Members[i];
1691+
const auto& OtherMember = Other.Members[i];
1692+
if (RefMember.Name != OtherMember.NameToken->Literal)
1693+
return false;
1694+
if (RefMember.Type != OtherMember.TypeToken->Literal)
1695+
return false;
1696+
if (RefMember.ArrayDimensions.size() != OtherMember.ArrayDimensions.size())
1697+
return false;
1698+
for (size_t j = 0; j < RefMember.ArrayDimensions.size(); ++j)
1699+
{
1700+
if (RefMember.ArrayDimensions[j] != OtherMember.ArrayDimensions[j]->Literal)
1701+
return false;
1702+
}
1703+
}
1704+
return true;
1705+
}
1706+
};
1707+
1708+
TEST(Common_ParsingTools, ParseType)
1709+
{
1710+
auto Test = [](std::string Source, const ReferenceTypeDesc& RefType) {
1711+
const auto Tokens = Tokenize<TestToken, std::vector<TestToken>>(Source.c_str(), Source.c_str() + Source.length(), TestToken::Create, TestToken::FindType);
1712+
1713+
auto it = std::find_if(Tokens.begin(), Tokens.end(), [](const TestToken& Tok) { return Tok.GetType() == TestTokenType::Struct; });
1714+
if (it == Tokens.end())
1715+
{
1716+
ADD_FAILURE() << "Struct keyword not found in the test source";
1717+
return;
1718+
}
1719+
++it;
1720+
1721+
Parsing::TypeDesc<const TestToken> Type = Parsing::ParseType<const TestToken>(Tokens.begin(), Tokens.end(), it);
1722+
EXPECT_EQ(RefType, Type);
1723+
};
1724+
1725+
Test(R"(struct TestStruct
1726+
{
1727+
})",
1728+
{"TestStruct"});
1729+
1730+
Test(R"(struct TestStruct
1731+
{
1732+
int x;
1733+
})",
1734+
{
1735+
"TestStruct",
1736+
{
1737+
{"int", "x"},
1738+
},
1739+
});
1740+
1741+
Test(R"(struct TestStruct
1742+
{
1743+
int i;
1744+
float f[10];
1745+
double d[5][20];
1746+
InnerStruct inner;
1747+
InnerStruct inner2[10];
1748+
})",
1749+
{
1750+
"TestStruct",
1751+
{
1752+
{"int", "i"},
1753+
{"float", "f", {"10"}},
1754+
{"double", "d", {"5", "20"}},
1755+
{"InnerStruct", "inner"},
1756+
{"InnerStruct", "inner2", {"10"}},
1757+
},
1758+
});
1759+
1760+
Test(R"(struct TestStruct)",
1761+
{});
1762+
1763+
Test(R"(struct TestStruct int)",
1764+
{});
1765+
1766+
Test(R"(struct TestStruct
1767+
{
1768+
int x;
1769+
int i;)",
1770+
{});
1771+
1772+
Test(R"(struct TestStruct
1773+
{
1774+
int x;
1775+
int i
1776+
})",
1777+
{});
1778+
1779+
Test(R"(struct TestStruct
1780+
{
1781+
int x;
1782+
int;
1783+
})",
1784+
{});
1785+
1786+
Test(R"(struct TestStruct
1787+
{
1788+
int x;
1789+
int
1790+
})",
1791+
{});
1792+
1793+
Test(R"(struct TestStruct
1794+
{
1795+
int x;
1796+
int i[;
1797+
})",
1798+
{});
1799+
1800+
Test(R"(struct TestStruct
1801+
{
1802+
int x;
1803+
int i[10;
1804+
})",
1805+
{});
1806+
1807+
Test(R"(struct TestStruct
1808+
{
1809+
int x;
1810+
int i[];
1811+
})",
1812+
{});
1813+
1814+
Test(R"(struct TestStruct
1815+
{
1816+
int x;
1817+
int i[10][;
1818+
})",
1819+
{});
1820+
1821+
Test(R"(struct TestStruct
1822+
{
1823+
int x;
1824+
int i[10][]
1825+
})",
1826+
{});
1827+
1828+
Test(R"(struct TestStruct
1829+
{
1830+
int x y;
1831+
})",
1832+
{});
1833+
}
1834+
16651835
} // namespace

0 commit comments

Comments
 (0)