Skip to content

Commit 1b3227b

Browse files
committed
Parse support header
#improvement
1 parent 9cbaca5 commit 1b3227b

File tree

6 files changed

+180
-12
lines changed

6 files changed

+180
-12
lines changed

include/mrdocs/Metadata/Template.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ enum class TArgKind : int
3434
Template
3535
};
3636

37-
MRDOCS_DECL std::string_view toString(TArgKind kind) noexcept;
37+
MRDOCS_DECL
38+
std::string_view
39+
toString(TArgKind kind) noexcept;
3840

3941
inline
4042
void

include/mrdocs/Support/Error.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class MRDOCS_DECL
5353
A default constructed error is
5454
equivalent to success.
5555
*/
56-
Error() noexcept = delete;
56+
Error() noexcept = default;
5757

5858
/** Constructor.
5959
*/
@@ -122,7 +122,7 @@ class MRDOCS_DECL
122122
constexpr bool
123123
failed() const noexcept
124124
{
125-
return ! message_.empty();
125+
return !message_.empty();
126126
}
127127

128128
/** Return true if this holds an error.

include/mrdocs/Support/Parse.hpp

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
//
2+
// Licensed under the Apache License v2.0 with LLVM Exceptions.
3+
// See https://llvm.org/LICENSE.txt for license information.
4+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5+
//
6+
// Copyright (c) 2025 Alan de Freitas ([email protected])
7+
//
8+
// Official repository: https://github.com/cppalliance/mrdocs
9+
//
10+
11+
#ifndef MRDOCS_API_SUPPORT_PARSE_HPP
12+
#define MRDOCS_API_SUPPORT_PARSE_HPP
13+
14+
#include <mrdocs/Support/Error.hpp>
15+
#include <mrdocs/Support/Expected.hpp>
16+
17+
namespace clang::mrdocs {
18+
19+
/** The result of a parse operation.
20+
21+
This class holds the result of a parse operation.
22+
The structure is similar to `std::from_chars_result`,
23+
where we have a `ptr` member that points to the
24+
first character not parsed, and a `ec` member that
25+
holds the error code.
26+
27+
If parsing was successful, then `ec` stores
28+
a default constructed `Error` object, which
29+
indicates success. The `operator bool` can
30+
also be used to check for success.
31+
32+
The typical format of a parsing function is:
33+
34+
@code
35+
ParseResult
36+
parseType(
37+
char const* first,
38+
char const* last,
39+
Type& value);
40+
@endcode
41+
42+
where more parameters can be defined as needed for
43+
parsing options.
44+
*/
45+
struct ParseResult {
46+
const char* ptr;
47+
Error ec;
48+
49+
friend
50+
bool
51+
operator==(
52+
const ParseResult&,
53+
const ParseResult& ) = default;
54+
55+
constexpr
56+
explicit
57+
operator bool() const noexcept
58+
{
59+
return !ec.failed();
60+
}
61+
};
62+
63+
/** Concept to determine if there's a parse function for a type.
64+
65+
This concept checks if a type `T` has a parse function
66+
with the signature:
67+
68+
@code
69+
ParseResult
70+
parse(
71+
char const* first,
72+
char const* last,
73+
T& value);
74+
@endcode
75+
*/
76+
template <class T>
77+
concept HasParse = requires(
78+
char const* first,
79+
char const* last,
80+
T& value)
81+
{
82+
{ parse(first, last, value) } -> std::same_as<ParseResult>;
83+
};
84+
85+
/** Parse a string view
86+
87+
This function parses a string view `sv` into a value
88+
of type `T`. The function calls the `parse` function
89+
for the type `T` with the `sv.data()` and `sv.data() + sv.size()`
90+
as the first and last pointers, respectively.
91+
92+
If the parse function returns an error, then the function
93+
returns the error.
94+
95+
If the parse function returns success, but there are
96+
characters left in the string view, then the function
97+
returns an error with the message "trailing characters".
98+
99+
Otherwise, it returns the value.
100+
101+
@param sv The string view to parse
102+
@param value The value to store the result
103+
*/
104+
template <HasParse T>
105+
ParseResult
106+
parse(std::string_view sv, T& value)
107+
{
108+
ParseResult result = parse(sv.data(), sv.data() + sv.size(), value);
109+
if (result)
110+
{
111+
if (result.ptr != sv.data() + sv.size())
112+
{
113+
result.ec = Error("trailing characters");
114+
}
115+
}
116+
return result;
117+
}
118+
119+
/** Parse a string view
120+
121+
Parse a string view `sv` as an object of type `T`.
122+
If parsing fails, the function returns an error.
123+
124+
This overload does not return the `ParseResult` object
125+
containing the pointer to the first character not parsed.
126+
Instead, the position of the error is calculated and
127+
the error message is formatted with the error position.
128+
129+
@copydetails parse(std::string_view, T&)
130+
131+
*/
132+
template <HasParse T>
133+
Expected<T>
134+
parse(std::string_view sv)
135+
{
136+
T v;
137+
ParseResult const result = parse(sv, v);
138+
if (result)
139+
{
140+
return v;
141+
}
142+
std::size_t const pos = result.ptr - sv.data();
143+
return Unexpected(formatError(
144+
"'{}' at position {}: {}",
145+
sv, pos, result.ec.reason()));
146+
}
147+
148+
} // clang::mrdocs
149+
150+
#endif

src/lib/AST/ParseRef.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2139,12 +2139,24 @@ class RefParser
21392139
} // (anon)
21402140

21412141
// Function to parse a C++ symbol name
2142-
Expected<ParsedRef>
2143-
parseRef(std::string_view sv)
2142+
ParseResult
2143+
parse(
2144+
char const* first,
2145+
char const* last,
2146+
ParsedRef& value)
21442147
{
2145-
RefParser parser(sv);
2146-
parser.parse();
2147-
return parser.result();
2148+
RefParser parser(first, last, value);
2149+
ParseResult res;
2150+
if (parser.parse())
2151+
{
2152+
res.ptr = parser.position();
2153+
}
2154+
else
2155+
{
2156+
res.ec = parser.error();
2157+
res.ptr = parser.errorPos();
2158+
}
2159+
return res;
21482160
}
21492161

21502162
} // clang::mrdocs

src/lib/AST/ParseRef.hpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include <mrdocs/Metadata/Specifiers.hpp>
1515
#include <mrdocs/Metadata/Type.hpp>
16+
#include <mrdocs/Support/Parse.hpp>
1617
#include <mrdocs/ADT/Polymorphic.hpp>
1718
#include <llvm/ADT/SmallVector.h>
1819
#include <string_view>
@@ -70,8 +71,11 @@ struct ParsedRef {
7071
NoexceptInfo ExceptionSpec;
7172
};
7273

73-
Expected<ParsedRef>
74-
parseRef(std::string_view sv);
74+
ParseResult
75+
parse(
76+
char const* first,
77+
char const* last,
78+
ParsedRef& value);
7579

7680
} // clang::mrdocs
7781

src/test/lib/AST/ParseRef.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ namespace clang::mrdocs {
1515
struct ParseRef_test
1616
{
1717

18-
#define ok(str) BOOST_TEST(parseRef(str).has_value())
19-
#define fail(str) BOOST_TEST(!parseRef(str).has_value())
18+
#define ok(str) BOOST_TEST(parse<ParsedRef>(str).has_value())
19+
#define fail(str) BOOST_TEST(!parse<ParsedRef>(str).has_value())
2020

2121
void
2222
testComponents()

0 commit comments

Comments
 (0)