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
27namespace ark::es2panda::lexer {
28
29using ENUMBITOPS_OPERATORS;
30
31enum 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
41template <>
42struct enumbitops::IsAllowedType<ark::es2panda::lexer::NumberFlags> : std::true_type {
43};
44
45namespace ark::es2panda::lexer {
46
47// NOLINTBEGIN(readability-identifier-naming)
48// NOLINTBEGIN(fuchsia-multiple-inheritance)
49template <class... Ts>
50struct overloaded : Ts... {
51    using Ts::operator()...;
52};
53
54template <class... Ts>
55overloaded(Ts...) -> overloaded<Ts...>;
56// NOLINTEND(fuchsia-multiple-inheritance)
57
58template <typename>
59inline constexpr bool dependent_false_v = false;
60// NOLINTEND(readability-identifier-naming)
61
62// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
63class Number {
64public:
65    // NOLINTBEGIN(cppcoreguidelines-pro-type-member-init)
66    explicit Number() noexcept : num_(static_cast<int32_t>(0)) {};
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;
70    explicit Number(util::StringView str, double num) noexcept : str_(str), num_(num) {}
71    explicit Number(uint32_t num) noexcept : Number(static_cast<int32_t>(num)) {}
72    explicit Number(int32_t num) noexcept : num_(num) {}
73    explicit Number(uint64_t num) noexcept : Number(static_cast<int64_t>(num)) {}
74    explicit Number(int64_t num) noexcept : num_(num) {}
75    explicit Number(float num) noexcept : 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
112    bool ConversionError() const
113    {
114        return (flags_ & NumberFlags::ERROR) != 0;
115    }
116
117    int32_t GetInt() const
118    {
119        ASSERT(IsInt());
120        return std::get<int32_t>(num_);
121    }
122
123    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
134    float GetFloat() const
135    {
136        ASSERT(IsFloat());
137        return std::get<float>(num_);
138    }
139
140    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
212private:
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