1 /*
2  * Copyright (c) 2021 - 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef ES2PANDA_LEXER_TOKEN_NUMBER_H
17 #define ES2PANDA_LEXER_TOKEN_NUMBER_H
18 
19 #include "macros.h"
20 #include "util/ustring.h"
21 #include "util/enumbitops.h"
22 
23 #include <cstdint>
24 #include <type_traits>
25 #include <utility>
26 
27 namespace ark::es2panda::lexer {
28 
29 using ENUMBITOPS_OPERATORS;
30 
31 enum class NumberFlags : uint32_t {
32     NONE,
33     BIGINT = 1U << 0U,
34     DECIMAL_POINT = 1U << 1U,
35     EXPONENT = 1U << 2U,
36     ERROR = 1U << 3U,
37 };
38 
39 }  // namespace ark::es2panda::lexer
40 
41 template <>
42 struct enumbitops::IsAllowedType<ark::es2panda::lexer::NumberFlags> : std::true_type {
43 };
44 
45 namespace ark::es2panda::lexer {
46 
47 // NOLINTBEGIN(readability-identifier-naming)
48 // NOLINTBEGIN(fuchsia-multiple-inheritance)
49 template <class... Ts>
50 struct overloaded : Ts... {
51     using Ts::operator()...;
52 };
53 
54 template <class... Ts>
55 overloaded(Ts...) -> overloaded<Ts...>;
56 // NOLINTEND(fuchsia-multiple-inheritance)
57 
58 template <typename>
59 inline constexpr bool dependent_false_v = false;
60 // NOLINTEND(readability-identifier-naming)
61 
62 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
63 class Number {
64 public:
65     // NOLINTBEGIN(cppcoreguidelines-pro-type-member-init)
66     explicit Number() noexcept : num_(static_cast<int32_t>(0)) {};
str_(str)67     explicit Number(util::StringView str) noexcept : str_(str) {}
68     // NOLINTNEXTLINE(bugprone-exception-escape)
69     explicit Number(util::StringView str, const std::string &utf8, NumberFlags flags) noexcept;
num_(num)70     explicit Number(util::StringView str, double num) noexcept : str_(str), num_(num) {}
static_cast(num)71     explicit Number(uint32_t num) noexcept : Number(static_cast<int32_t>(num)) {}
num_(num)72     explicit Number(int32_t num) noexcept : num_(num) {}
static_cast(num)73     explicit Number(uint64_t num) noexcept : Number(static_cast<int64_t>(num)) {}
num_(num)74     explicit Number(int64_t num) noexcept : num_(num) {}
num_(num)75     explicit Number(float num) noexcept : num_(num) {}
num_(num)76     explicit Number(double num) noexcept : num_(num) {}
77     DEFAULT_COPY_SEMANTIC(Number);
78     DEFAULT_MOVE_SEMANTIC(Number);
79     ~Number() = default;
80     // NOLINTEND(cppcoreguidelines-pro-type-member-init)
81 
82     bool IsInt() const noexcept
83     {
84         return std::holds_alternative<int32_t>(num_);
85     }
86 
87     bool IsLong() const noexcept
88     {
89         return std::holds_alternative<int64_t>(num_);
90     }
91 
92     bool IsInteger() const noexcept
93     {
94         return IsInt() || IsLong();
95     }
96 
97     bool IsFloat() const noexcept
98     {
99         return std::holds_alternative<float>(num_);
100     }
101 
102     bool IsDouble() const noexcept
103     {
104         return std::holds_alternative<double>(num_);
105     }
106 
107     bool IsReal() const noexcept
108     {
109         return IsFloat() || IsDouble();
110     }
111 
ConversionError() const112     bool ConversionError() const
113     {
114         return (flags_ & NumberFlags::ERROR) != 0;
115     }
116 
GetInt() const117     int32_t GetInt() const
118     {
119         ASSERT(IsInt());
120         return std::get<int32_t>(num_);
121     }
122 
GetLong() const123     int64_t GetLong() const
124     {
125         return std::visit(overloaded {[](int64_t value) { return value; },
126                                       [](int32_t value) { return static_cast<int64_t>(value); },
127                                       []([[maybe_unused]] auto value) {
128                                           ASSERT(false);
129                                           return static_cast<int64_t>(0);
130                                       }},
131                           num_);
132     }
133 
GetFloat() const134     float GetFloat() const
135     {
136         ASSERT(IsFloat());
137         return std::get<float>(num_);
138     }
139 
GetDouble() const140     double GetDouble() const
141     {
142         return std::visit(
143             overloaded {[](double value) { return value; }, [](auto value) { return static_cast<double>(value); }},
144             num_);
145     }
146 
147     const util::StringView &Str() const
148     {
149         return str_;
150     }
151 
152     void Negate()
153     {
154         std::visit(overloaded {[](auto &value) { value = -value; }}, num_);
155         if (std::holds_alternative<int64_t>(num_)) {
156             int64_t num = std::get<int64_t>(num_);
157             if (num == INT32_MIN) {
158                 SetValue<int32_t>(num);
159             }
160         }
161     }
162 
163     template <typename RT>
164     bool CanGetValue() const noexcept
165     {
166         using T = typename std::remove_cv_t<typename std::remove_reference_t<RT>>;
167 
168         if constexpr (std::is_same_v<T, int64_t>) {
169             return IsInteger();
170         } else if constexpr (std::is_same_v<T, int32_t>) {
171             return IsInt();
172         } else if constexpr (std::is_same_v<T, double>) {
173             return true;
174         } else if constexpr (std::is_same_v<T, float>) {
175             return IsFloat();
176         } else {
177             return false;
178         }
179     }
180 
181     template <typename RT>
182     auto GetValue() const
183     {
184         using T = typename std::remove_cv_t<typename std::remove_reference_t<RT>>;
185 
186         if constexpr (std::is_same_v<T, int64_t>) {
187             return GetLong();
188         } else if constexpr (std::is_same_v<T, int32_t>) {
189             return GetInt();
190         } else if constexpr (std::is_same_v<T, double>) {
191             return GetDouble();
192         } else if constexpr (std::is_same_v<T, float>) {
193             return GetFloat();
194         } else {
195             static_assert(dependent_false_v<T>, "Invalid value type was requested for Number.");
196         }
197     }
198 
199     template <typename RT>
200     void SetValue(RT &&value)
201     {
202         using T = typename std::remove_cv_t<typename std::remove_reference_t<RT>>;
203 
204         if constexpr (std::is_same_v<T, int64_t> || std::is_same_v<T, int32_t> || std::is_same_v<T, double> ||
205                       std::is_same_v<T, float>) {
206             num_ = std::forward<RT>(value);
207         } else {
208             static_assert(dependent_false_v<T>, "Invalid value type was requested for Number.");
209         }
210     }
211 
212 private:
213     util::StringView str_ {};
214     std::variant<int32_t, int64_t, float, double> num_;
215     NumberFlags flags_ {NumberFlags::NONE};
216 };
217 }  // namespace ark::es2panda::lexer
218 
219 #endif
220