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 (alandefreitas@gmail.com)
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
0 commit comments