Coverage Report

Created: 2026-09-28 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/include/po/parser.h
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
//===-- wasmedge/po/parser.h - Single Argument parser ---------------------===//
5
//
6
// Part of the WasmEdge Project.
7
//
8
//===----------------------------------------------------------------------===//
9
#pragma once
10
11
#include "po/error.h"
12
#include <algorithm>
13
#include <cstdint>
14
#include <fmt/format.h>
15
#include <string>
16
#include <utility>
17
18
namespace WasmEdge {
19
namespace PO {
20
21
0
inline void tolower(std::string &String) noexcept {
22
0
  std::transform(
23
0
      String.begin(), String.end(), String.begin(),
24
0
      [](char C) noexcept { return static_cast<char>(std::tolower(C)); });
25
0
}
26
27
template <typename ConvResultT, typename ResultT = ConvResultT>
28
inline cxx20::expected<ResultT, Error>
29
stringToInteger(ConvResultT (&Conv)(const char *, char **, int),
30
203k
                std::string Value) noexcept {
31
203k
  using namespace std::literals;
32
203k
  char *EndPtr;
33
203k
  const char *CStr = Value.c_str();
34
203k
  auto SavedErrNo = std::exchange(errno, 0);
35
203k
  const auto Result = Conv(CStr, &EndPtr, 10);
36
203k
  std::swap(SavedErrNo, errno);
37
203k
  if (Value.empty() || *EndPtr != '\0') {
38
164
    return cxx20::unexpected<Error>(
39
164
        std::in_place, ErrCode::InvalidArgument,
40
164
        fmt::format("invalid integer value: {}"sv, Value));
41
164
  }
42
203k
  auto InsideRange = [](auto WiderResult) constexpr noexcept {
43
203k
    using WiderResultT = decltype(WiderResult);
44
203k
    if constexpr (std::is_same_v<ResultT, WiderResultT>) {
45
70.1k
      return true;
46
132k
    } else {
47
132k
      return static_cast<WiderResultT>(std::numeric_limits<ResultT>::min()) <=
48
132k
                 WiderResult &&
49
132k
             WiderResult <=
50
132k
                 static_cast<WiderResultT>(std::numeric_limits<ResultT>::max());
51
132k
    }
52
203k
  };
auto WasmEdge::PO::stringToInteger<long, int>(long (&)(char const*, char**, int), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)::{lambda(auto:1)#1}::operator()<long>(long) const
Line
Count
Source
42
132k
  auto InsideRange = [](auto WiderResult) constexpr noexcept {
43
132k
    using WiderResultT = decltype(WiderResult);
44
    if constexpr (std::is_same_v<ResultT, WiderResultT>) {
45
      return true;
46
132k
    } else {
47
132k
      return static_cast<WiderResultT>(std::numeric_limits<ResultT>::min()) <=
48
132k
                 WiderResult &&
49
132k
             WiderResult <=
50
132k
                 static_cast<WiderResultT>(std::numeric_limits<ResultT>::max());
51
132k
    }
52
132k
  };
Unexecuted instantiation: auto WasmEdge::PO::stringToInteger<unsigned long, unsigned int>(unsigned long (&)(char const*, char**, int), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)::{lambda(auto:1)#1}::operator()<unsigned long>(unsigned long) const
Unexecuted instantiation: auto WasmEdge::PO::stringToInteger<long, signed char>(long (&)(char const*, char**, int), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)::{lambda(auto:1)#1}::operator()<long>(long) const
Unexecuted instantiation: auto WasmEdge::PO::stringToInteger<unsigned long, unsigned char>(unsigned long (&)(char const*, char**, int), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)::{lambda(auto:1)#1}::operator()<unsigned long>(unsigned long) const
Unexecuted instantiation: auto WasmEdge::PO::stringToInteger<long, short>(long (&)(char const*, char**, int), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)::{lambda(auto:1)#1}::operator()<long>(long) const
Unexecuted instantiation: auto WasmEdge::PO::stringToInteger<unsigned long, unsigned short>(unsigned long (&)(char const*, char**, int), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)::{lambda(auto:1)#1}::operator()<unsigned long>(unsigned long) const
Unexecuted instantiation: auto WasmEdge::PO::stringToInteger<long, long>(long (&)(char const*, char**, int), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)::{lambda(auto:1)#1}::operator()<long>(long) const
Unexecuted instantiation: auto WasmEdge::PO::stringToInteger<long long, long long>(long long (&)(char const*, char**, int), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)::{lambda(auto:1)#1}::operator()<long long>(long long) const
auto WasmEdge::PO::stringToInteger<unsigned long, unsigned long>(unsigned long (&)(char const*, char**, int), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)::{lambda(auto:1)#1}::operator()<unsigned long>(unsigned long) const
Line
Count
Source
42
70.1k
  auto InsideRange = [](auto WiderResult) constexpr noexcept {
43
70.1k
    using WiderResultT = decltype(WiderResult);
44
70.1k
    if constexpr (std::is_same_v<ResultT, WiderResultT>) {
45
70.1k
      return true;
46
    } else {
47
      return static_cast<WiderResultT>(std::numeric_limits<ResultT>::min()) <=
48
                 WiderResult &&
49
             WiderResult <=
50
                 static_cast<WiderResultT>(std::numeric_limits<ResultT>::max());
51
    }
52
70.1k
  };
Unexecuted instantiation: auto WasmEdge::PO::stringToInteger<unsigned long long, unsigned long long>(unsigned long long (&)(char const*, char**, int), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)::{lambda(auto:1)#1}::operator()<unsigned long long>(unsigned long long) const
53
203k
  if (SavedErrNo == ERANGE || !InsideRange(Result)) {
54
96
    return cxx20::unexpected<Error>(
55
96
        std::in_place, ErrCode::OutOfRange,
56
96
        fmt::format("integer value out of range: {}"sv, Value));
57
96
  }
58
203k
  return static_cast<ResultT>(Result);
59
203k
}
cxx20::expected<int, WasmEdge::PO::Error> WasmEdge::PO::stringToInteger<long, int>(long (&)(char const*, char**, int), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)
Line
Count
Source
30
133k
                std::string Value) noexcept {
31
133k
  using namespace std::literals;
32
133k
  char *EndPtr;
33
133k
  const char *CStr = Value.c_str();
34
133k
  auto SavedErrNo = std::exchange(errno, 0);
35
133k
  const auto Result = Conv(CStr, &EndPtr, 10);
36
133k
  std::swap(SavedErrNo, errno);
37
133k
  if (Value.empty() || *EndPtr != '\0') {
38
112
    return cxx20::unexpected<Error>(
39
112
        std::in_place, ErrCode::InvalidArgument,
40
112
        fmt::format("invalid integer value: {}"sv, Value));
41
112
  }
42
132k
  auto InsideRange = [](auto WiderResult) constexpr noexcept {
43
132k
    using WiderResultT = decltype(WiderResult);
44
132k
    if constexpr (std::is_same_v<ResultT, WiderResultT>) {
45
132k
      return true;
46
132k
    } else {
47
132k
      return static_cast<WiderResultT>(std::numeric_limits<ResultT>::min()) <=
48
132k
                 WiderResult &&
49
132k
             WiderResult <=
50
132k
                 static_cast<WiderResultT>(std::numeric_limits<ResultT>::max());
51
132k
    }
52
132k
  };
53
132k
  if (SavedErrNo == ERANGE || !InsideRange(Result)) {
54
84
    return cxx20::unexpected<Error>(
55
84
        std::in_place, ErrCode::OutOfRange,
56
84
        fmt::format("integer value out of range: {}"sv, Value));
57
84
  }
58
132k
  return static_cast<ResultT>(Result);
59
132k
}
Unexecuted instantiation: cxx20::expected<unsigned int, WasmEdge::PO::Error> WasmEdge::PO::stringToInteger<unsigned long, unsigned int>(unsigned long (&)(char const*, char**, int), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)
Unexecuted instantiation: cxx20::expected<signed char, WasmEdge::PO::Error> WasmEdge::PO::stringToInteger<long, signed char>(long (&)(char const*, char**, int), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)
Unexecuted instantiation: cxx20::expected<unsigned char, WasmEdge::PO::Error> WasmEdge::PO::stringToInteger<unsigned long, unsigned char>(unsigned long (&)(char const*, char**, int), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)
Unexecuted instantiation: cxx20::expected<short, WasmEdge::PO::Error> WasmEdge::PO::stringToInteger<long, short>(long (&)(char const*, char**, int), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)
Unexecuted instantiation: cxx20::expected<unsigned short, WasmEdge::PO::Error> WasmEdge::PO::stringToInteger<unsigned long, unsigned short>(unsigned long (&)(char const*, char**, int), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)
Unexecuted instantiation: cxx20::expected<long, WasmEdge::PO::Error> WasmEdge::PO::stringToInteger<long, long>(long (&)(char const*, char**, int), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)
Unexecuted instantiation: cxx20::expected<long long, WasmEdge::PO::Error> WasmEdge::PO::stringToInteger<long long, long long>(long long (&)(char const*, char**, int), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)
cxx20::expected<unsigned long, WasmEdge::PO::Error> WasmEdge::PO::stringToInteger<unsigned long, unsigned long>(unsigned long (&)(char const*, char**, int), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)
Line
Count
Source
30
70.1k
                std::string Value) noexcept {
31
70.1k
  using namespace std::literals;
32
70.1k
  char *EndPtr;
33
70.1k
  const char *CStr = Value.c_str();
34
70.1k
  auto SavedErrNo = std::exchange(errno, 0);
35
70.1k
  const auto Result = Conv(CStr, &EndPtr, 10);
36
70.1k
  std::swap(SavedErrNo, errno);
37
70.1k
  if (Value.empty() || *EndPtr != '\0') {
38
52
    return cxx20::unexpected<Error>(
39
52
        std::in_place, ErrCode::InvalidArgument,
40
52
        fmt::format("invalid integer value: {}"sv, Value));
41
52
  }
42
70.1k
  auto InsideRange = [](auto WiderResult) constexpr noexcept {
43
70.1k
    using WiderResultT = decltype(WiderResult);
44
70.1k
    if constexpr (std::is_same_v<ResultT, WiderResultT>) {
45
70.1k
      return true;
46
70.1k
    } else {
47
70.1k
      return static_cast<WiderResultT>(std::numeric_limits<ResultT>::min()) <=
48
70.1k
                 WiderResult &&
49
70.1k
             WiderResult <=
50
70.1k
                 static_cast<WiderResultT>(std::numeric_limits<ResultT>::max());
51
70.1k
    }
52
70.1k
  };
53
70.1k
  if (SavedErrNo == ERANGE || !InsideRange(Result)) {
54
12
    return cxx20::unexpected<Error>(
55
12
        std::in_place, ErrCode::OutOfRange,
56
12
        fmt::format("integer value out of range: {}"sv, Value));
57
12
  }
58
70.1k
  return static_cast<ResultT>(Result);
59
70.1k
}
Unexecuted instantiation: cxx20::expected<unsigned long long, WasmEdge::PO::Error> WasmEdge::PO::stringToInteger<unsigned long long, unsigned long long>(unsigned long long (&)(char const*, char**, int), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)
60
61
template <typename ConvResultT, typename ResultT = ConvResultT>
62
inline cxx20::expected<ResultT, Error>
63
stringToFloating(ConvResultT (&Conv)(const char *, char **),
64
0
                 std::string Value) noexcept {
65
0
  using namespace std::literals;
66
0
  char *EndPtr;
67
0
  const char *CStr = Value.c_str();
68
0
  auto SavedErrNo = std::exchange(errno, 0);
69
0
  const auto Result = Conv(CStr, &EndPtr);
70
0
  std::swap(SavedErrNo, errno);
71
0
  if (Value.empty() || *EndPtr != '\0') {
72
0
    return cxx20::unexpected<Error>(
73
0
        std::in_place, ErrCode::InvalidArgument,
74
0
        fmt::format("invalid floating-point value: {}"sv, Value));
75
0
  }
76
0
  if (SavedErrNo == ERANGE) {
77
0
    return cxx20::unexpected<Error>(
78
0
        std::in_place, ErrCode::OutOfRange,
79
0
        fmt::format("floating-point value out of range: {}"sv, Value));
80
0
  }
81
0
  return Result;
82
0
}
Unexecuted instantiation: cxx20::expected<float, WasmEdge::PO::Error> WasmEdge::PO::stringToFloating<float, float>(float (&)(char const*, char**), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)
Unexecuted instantiation: cxx20::expected<double, WasmEdge::PO::Error> WasmEdge::PO::stringToFloating<double, double>(double (&)(char const*, char**), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)
Unexecuted instantiation: cxx20::expected<long double, WasmEdge::PO::Error> WasmEdge::PO::stringToFloating<long double, long double>(long double (&)(char const*, char**), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)
83
84
template <typename T> struct Parser;
85
86
template <> struct Parser<std::string> {
87
1.57M
  static cxx20::expected<std::string, Error> parse(std::string Value) noexcept {
88
1.57M
    return Value;
89
1.57M
  }
90
};
91
92
template <> struct Parser<bool> {
93
0
  static cxx20::expected<bool, Error> parse(std::string Value) noexcept {
94
0
    using namespace std::literals;
95
0
    if (!Value.empty()) {
96
0
      switch (Value[0]) {
97
0
      case 'T':
98
0
      case 't':
99
0
        if (Value.size() == 4) {
100
0
          tolower(Value);
101
0
          if (Value == "true"sv) {
102
0
            return true;
103
0
          }
104
0
        }
105
0
        break;
106
0
      case '1':
107
0
        if (Value.size() == 1) {
108
0
          return true;
109
0
        }
110
0
        break;
111
0
      case 'F':
112
0
      case 'f':
113
0
        if (Value.size() == 5) {
114
0
          tolower(Value);
115
0
          if (Value == "false"sv) {
116
0
            return false;
117
0
          }
118
0
        }
119
0
        break;
120
0
      case '0':
121
0
        if (Value.size() == 1) {
122
0
          return false;
123
0
        }
124
0
        break;
125
0
      default:
126
0
        break;
127
0
      }
128
0
    }
129
0
    return cxx20::unexpected<Error>(std::in_place, ErrCode::InvalidArgument,
130
0
                                    "invalid boolean string: "s + Value);
131
0
  }
132
};
133
134
template <> struct Parser<int> {
135
133k
  static cxx20::expected<int, Error> parse(std::string Value) noexcept {
136
133k
    return stringToInteger<long, int>(std::strtol, std::move(Value));
137
133k
  }
138
};
139
140
template <> struct Parser<unsigned int> {
141
  static cxx20::expected<unsigned int, Error>
142
0
  parse(std::string Value) noexcept {
143
0
    return stringToInteger<unsigned long, unsigned int>(std::strtoul,
144
0
                                                        std::move(Value));
145
0
  }
146
};
147
148
template <> struct Parser<signed char> {
149
0
  static cxx20::expected<signed char, Error> parse(std::string Value) noexcept {
150
0
    return stringToInteger<long, signed char>(std::strtol, std::move(Value));
151
0
  }
152
};
153
154
template <> struct Parser<unsigned char> {
155
  static cxx20::expected<unsigned char, Error>
156
0
  parse(std::string Value) noexcept {
157
0
    return stringToInteger<unsigned long, unsigned char>(std::strtoul,
158
0
                                                         std::move(Value));
159
0
  }
160
};
161
162
template <> struct Parser<short> {
163
0
  static cxx20::expected<short, Error> parse(std::string Value) noexcept {
164
0
    return stringToInteger<long, short>(std::strtol, std::move(Value));
165
0
  }
166
};
167
168
template <> struct Parser<unsigned short> {
169
  static cxx20::expected<unsigned short, Error>
170
0
  parse(std::string Value) noexcept {
171
0
    return stringToInteger<unsigned long, unsigned short>(std::strtoul,
172
0
                                                          std::move(Value));
173
0
  }
174
};
175
176
template <> struct Parser<long> {
177
0
  static cxx20::expected<long, Error> parse(std::string Value) noexcept {
178
0
    return stringToInteger(std::strtol, std::move(Value));
179
0
  }
180
};
181
182
template <> struct Parser<long long> {
183
0
  static cxx20::expected<long long, Error> parse(std::string Value) noexcept {
184
0
    return stringToInteger(std::strtoll, std::move(Value));
185
0
  }
186
};
187
188
template <> struct Parser<unsigned long> {
189
  static cxx20::expected<unsigned long, Error>
190
70.1k
  parse(std::string Value) noexcept {
191
70.1k
    return stringToInteger(std::strtoul, std::move(Value));
192
70.1k
  }
193
};
194
195
template <> struct Parser<unsigned long long> {
196
  static cxx20::expected<unsigned long long, Error>
197
0
  parse(std::string Value) noexcept {
198
0
    return stringToInteger(std::strtoull, std::move(Value));
199
0
  }
200
};
201
202
template <> struct Parser<float> {
203
0
  static cxx20::expected<float, Error> parse(std::string Value) noexcept {
204
0
    return stringToFloating(std::strtof, std::move(Value));
205
0
  }
206
};
207
208
template <> struct Parser<double> {
209
0
  static cxx20::expected<double, Error> parse(std::string Value) noexcept {
210
0
    return stringToFloating(std::strtod, std::move(Value));
211
0
  }
212
};
213
214
template <> struct Parser<long double> {
215
0
  static cxx20::expected<long double, Error> parse(std::string Value) noexcept {
216
0
    return stringToFloating(std::strtold, std::move(Value));
217
0
  }
218
};
219
220
} // namespace PO
221
} // namespace WasmEdge