Coverage Report

Created: 2026-06-30 06:10

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
126k
                std::string Value) noexcept {
31
126k
  using namespace std::literals;
32
126k
  char *EndPtr;
33
126k
  const char *CStr = Value.c_str();
34
126k
  auto SavedErrNo = std::exchange(errno, 0);
35
126k
  const auto Result = Conv(CStr, &EndPtr, 10);
36
126k
  std::swap(SavedErrNo, errno);
37
126k
  if (Value.empty() || *EndPtr != '\0') {
38
137
    return cxx20::unexpected<Error>(
39
137
        std::in_place, ErrCode::InvalidArgument,
40
137
        fmt::format("invalid integer value: {}", Value));
41
137
  }
42
126k
  auto InsideRange = [](auto WiderResult) constexpr noexcept {
43
126k
    using WiderResultT = decltype(WiderResult);
44
126k
    if constexpr (std::is_same_v<ResultT, WiderResultT>) {
45
69.8k
      return true;
46
69.8k
    } else {
47
56.7k
      return static_cast<WiderResultT>(std::numeric_limits<ResultT>::min()) <=
48
56.7k
                 WiderResult &&
49
56.7k
             WiderResult <=
50
56.7k
                 static_cast<WiderResultT>(std::numeric_limits<ResultT>::max());
51
56.7k
    }
52
126k
  };
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
56.7k
  auto InsideRange = [](auto WiderResult) constexpr noexcept {
43
56.7k
    using WiderResultT = decltype(WiderResult);
44
    if constexpr (std::is_same_v<ResultT, WiderResultT>) {
45
      return true;
46
56.7k
    } else {
47
56.7k
      return static_cast<WiderResultT>(std::numeric_limits<ResultT>::min()) <=
48
56.7k
                 WiderResult &&
49
56.7k
             WiderResult <=
50
56.7k
                 static_cast<WiderResultT>(std::numeric_limits<ResultT>::max());
51
56.7k
    }
52
56.7k
  };
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
69.8k
  auto InsideRange = [](auto WiderResult) constexpr noexcept {
43
69.8k
    using WiderResultT = decltype(WiderResult);
44
69.8k
    if constexpr (std::is_same_v<ResultT, WiderResultT>) {
45
69.8k
      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
69.8k
  };
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
126k
  if (SavedErrNo == ERANGE || !InsideRange(Result)) {
54
70
    return cxx20::unexpected<Error>(
55
70
        std::in_place, ErrCode::OutOfRange,
56
70
        fmt::format("integer value out of range: {}", Value));
57
70
  }
58
126k
  return static_cast<ResultT>(Result);
59
126k
}
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
56.8k
                std::string Value) noexcept {
31
56.8k
  using namespace std::literals;
32
56.8k
  char *EndPtr;
33
56.8k
  const char *CStr = Value.c_str();
34
56.8k
  auto SavedErrNo = std::exchange(errno, 0);
35
56.8k
  const auto Result = Conv(CStr, &EndPtr, 10);
36
56.8k
  std::swap(SavedErrNo, errno);
37
56.8k
  if (Value.empty() || *EndPtr != '\0') {
38
116
    return cxx20::unexpected<Error>(
39
116
        std::in_place, ErrCode::InvalidArgument,
40
116
        fmt::format("invalid integer value: {}", Value));
41
116
  }
42
56.7k
  auto InsideRange = [](auto WiderResult) constexpr noexcept {
43
56.7k
    using WiderResultT = decltype(WiderResult);
44
56.7k
    if constexpr (std::is_same_v<ResultT, WiderResultT>) {
45
56.7k
      return true;
46
56.7k
    } else {
47
56.7k
      return static_cast<WiderResultT>(std::numeric_limits<ResultT>::min()) <=
48
56.7k
                 WiderResult &&
49
56.7k
             WiderResult <=
50
56.7k
                 static_cast<WiderResultT>(std::numeric_limits<ResultT>::max());
51
56.7k
    }
52
56.7k
  };
53
56.7k
  if (SavedErrNo == ERANGE || !InsideRange(Result)) {
54
67
    return cxx20::unexpected<Error>(
55
67
        std::in_place, ErrCode::OutOfRange,
56
67
        fmt::format("integer value out of range: {}", Value));
57
67
  }
58
56.7k
  return static_cast<ResultT>(Result);
59
56.7k
}
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
69.8k
                std::string Value) noexcept {
31
69.8k
  using namespace std::literals;
32
69.8k
  char *EndPtr;
33
69.8k
  const char *CStr = Value.c_str();
34
69.8k
  auto SavedErrNo = std::exchange(errno, 0);
35
69.8k
  const auto Result = Conv(CStr, &EndPtr, 10);
36
69.8k
  std::swap(SavedErrNo, errno);
37
69.8k
  if (Value.empty() || *EndPtr != '\0') {
38
21
    return cxx20::unexpected<Error>(
39
21
        std::in_place, ErrCode::InvalidArgument,
40
21
        fmt::format("invalid integer value: {}", Value));
41
21
  }
42
69.8k
  auto InsideRange = [](auto WiderResult) constexpr noexcept {
43
69.8k
    using WiderResultT = decltype(WiderResult);
44
69.8k
    if constexpr (std::is_same_v<ResultT, WiderResultT>) {
45
69.8k
      return true;
46
69.8k
    } else {
47
69.8k
      return static_cast<WiderResultT>(std::numeric_limits<ResultT>::min()) <=
48
69.8k
                 WiderResult &&
49
69.8k
             WiderResult <=
50
69.8k
                 static_cast<WiderResultT>(std::numeric_limits<ResultT>::max());
51
69.8k
    }
52
69.8k
  };
53
69.8k
  if (SavedErrNo == ERANGE || !InsideRange(Result)) {
54
3
    return cxx20::unexpected<Error>(
55
3
        std::in_place, ErrCode::OutOfRange,
56
3
        fmt::format("integer value out of range: {}", Value));
57
3
  }
58
69.8k
  return static_cast<ResultT>(Result);
59
69.8k
}
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: {}", 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: {}", 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.18M
  static cxx20::expected<std::string, Error> parse(std::string Value) noexcept {
88
1.18M
    return Value;
89
1.18M
  }
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
56.8k
  static cxx20::expected<int, Error> parse(std::string Value) noexcept {
136
56.8k
    return stringToInteger<long, int>(std::strtol, std::move(Value));
137
56.8k
  }
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
69.8k
  parse(std::string Value) noexcept {
191
69.8k
    return stringToInteger(std::strtoul, std::move(Value));
192
69.8k
  }
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