Coverage Report

Created: 2025-07-01 06:18

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