1/**
2 * Copyright (c) 2021-2022 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 ASSEMBLER_ANNOTATION_H
17#define ASSEMBLER_ANNOTATION_H
18
19#include <cstddef>
20#include <memory>
21#include <string>
22#include <string_view>
23#include <type_traits>
24#include <variant>
25#include <vector>
26
27#include "assembly-type.h"
28
29#include "macros.h"
30
31namespace panda::pandasm {
32
33class AnnotationElement;
34
35class AnnotationData {
36public:
37    AnnotationData(const std::string_view &record_name, std::vector<AnnotationElement> elements)
38        : record_name_(record_name), elements_(std::move(elements))
39    {
40    }
41
42    explicit AnnotationData(const std::string_view &record_name) : record_name_(record_name) {}
43
44    DEFAULT_MOVE_SEMANTIC(AnnotationData);
45    DEFAULT_COPY_SEMANTIC(AnnotationData);
46
47    ~AnnotationData() = default;
48
49    std::string GetName() const
50    {
51        return record_name_;
52    }
53
54    const std::vector<AnnotationElement> &GetElements() const
55    {
56        return elements_;
57    }
58
59    void AddElement(AnnotationElement &&element)
60    {
61        elements_.push_back(std::forward<AnnotationElement>(element));
62    }
63
64    void DeleteAnnotationElementByName(const std::string_view &annotation_elem_name);
65
66    void SetOrAddElementByIndex(size_t ele_idx, AnnotationElement &&element);
67
68private:
69    std::string record_name_;
70    std::vector<AnnotationElement> elements_;
71};
72
73class ScalarValue;
74class ArrayValue;
75
76class Value {
77public:
78    enum class Type {
79        U1,
80        I8,
81        U8,
82        I16,
83        U16,
84        I32,
85        U32,
86        I64,
87        U64,
88        F32,
89        F64,
90        STRING,
91        STRING_NULLPTR,
92        RECORD,
93        METHOD,
94        ENUM,
95        ANNOTATION,
96        ARRAY,
97        VOID,
98        METHOD_HANDLE,
99        LITERALARRAY,
100        UNKNOWN
101    };
102
103    static constexpr char GetTypeAsChar(Type t)
104    {
105        char type = '0';
106        switch (t) {
107            case Type::U1:
108                type = '1';
109                break;
110            case Type::I8:
111                type = '2';
112                break;
113            case Type::U8:
114                type = '3';
115                break;
116            case Type::I16:
117                type = '4';
118                break;
119            case Type::U16:
120                type = '5';
121                break;
122            case Type::I32:
123                type = '6';
124                break;
125            case Type::U32:
126                type = '7';
127                break;
128            case Type::I64:
129                type = '8';
130                break;
131            case Type::U64:
132                type = '9';
133                break;
134            case Type::F32:
135                type = 'A';
136                break;
137            case Type::F64:
138                type = 'B';
139                break;
140            case Type::STRING:
141                type = 'C';
142                break;
143            case Type::RECORD:
144                type = 'D';
145                break;
146            case Type::METHOD:
147                type = 'E';
148                break;
149            case Type::ENUM:
150                type = 'F';
151                break;
152            case Type::ANNOTATION:
153                type = 'G';
154                break;
155            case Type::ARRAY:
156                type = 'H';
157                break;
158            case Type::VOID:
159                type = 'I';
160                break;
161            case Type::METHOD_HANDLE:
162                type = 'J';
163                break;
164            case Type::STRING_NULLPTR:
165                type = '*';
166                break;
167            case Type::LITERALARRAY:
168                type = '#';
169                break;
170            case Type::UNKNOWN:
171            default:
172                type = '0';
173        }
174        return type;
175    }
176
177    static constexpr char GetArrayTypeAsChar(Type t)
178    {
179        char type = '0';
180        switch (t) {
181            case Type::U1:
182                type = 'K';
183                break;
184            case Type::I8:
185                type = 'L';
186                break;
187            case Type::U8:
188                type = 'M';
189                break;
190            case Type::I16:
191                type = 'N';
192                break;
193            case Type::U16:
194                type = 'O';
195                break;
196            case Type::I32:
197                type = 'P';
198                break;
199            case Type::U32:
200                type = 'Q';
201                break;
202            case Type::I64:
203                type = 'R';
204                break;
205            case Type::U64:
206                type = 'S';
207                break;
208            case Type::F32:
209                type = 'T';
210                break;
211            case Type::F64:
212                type = 'U';
213                break;
214            case Type::STRING:
215                type = 'V';
216                break;
217            case Type::RECORD:
218                type = 'W';
219                break;
220            case Type::METHOD:
221                type = 'X';
222                break;
223            case Type::ENUM:
224                type = 'Y';
225                break;
226            case Type::ANNOTATION:
227                type = 'Z';
228                break;
229            case Type::METHOD_HANDLE:
230                type = '@';
231                break;
232            case Type::UNKNOWN:
233            default:
234                type = '0';
235        }
236        return type;
237    }
238
239    static constexpr Type GetCharAsType(char c)
240    {
241        Type type = Type::UNKNOWN;
242        switch (c) {
243            case '1':
244                type = Type::U1;
245                break;
246            case '2':
247                type = Type::I8;
248                break;
249            case '3':
250                type = Type::U8;
251                break;
252            case '4':
253                type = Type::I16;
254                break;
255            case '5':
256                type = Type::U16;
257                break;
258            case '6':
259                type = Type::I32;
260                break;
261            case '7':
262                type = Type::U32;
263                break;
264            case '8':
265                type = Type::I64;
266                break;
267            case '9':
268                type = Type::U64;
269                break;
270            case 'A':
271                type = Type::F32;
272                break;
273            case 'B':
274                type = Type::F64;
275                break;
276            case 'C':
277                type = Type::STRING;
278                break;
279            case 'D':
280                type = Type::RECORD;
281                break;
282            case 'E':
283                type = Type::METHOD;
284                break;
285            case 'F':
286                type = Type::ENUM;
287                break;
288            case 'G':
289                type = Type::ANNOTATION;
290                break;
291            case 'H':
292                type = Type::ARRAY;
293                break;
294            case 'I':
295                type = Type::VOID;
296                break;
297            case 'J':
298                type = Type::METHOD_HANDLE;
299                break;
300            case '*':
301                type = Type::STRING_NULLPTR;
302                break;
303            case '#':
304                type = Type::LITERALARRAY;
305                break;
306            case '0':
307            default:
308                type = Type::UNKNOWN;
309        }
310        return type;
311    }
312
313    static constexpr Type GetCharAsArrayType(char c)
314    {
315        Type type = Type::UNKNOWN;
316        switch (c) {
317            case 'K':
318                type = Type::U1;
319                break;
320            case 'L':
321                type = Type::I8;
322                break;
323            case 'M':
324                type = Type::U8;
325                break;
326            case 'N':
327                type = Type::I16;
328                break;
329            case 'O':
330                type = Type::U16;
331                break;
332            case 'P':
333                type = Type::I32;
334                break;
335            case 'Q':
336                type = Type::U32;
337                break;
338            case 'R':
339                type = Type::I64;
340                break;
341            case 'S':
342                type = Type::U64;
343                break;
344            case 'T':
345                type = Type::F32;
346                break;
347            case 'U':
348                type = Type::F64;
349                break;
350            case 'V':
351                type = Type::STRING;
352                break;
353            case 'W':
354                type = Type::RECORD;
355                break;
356            case 'X':
357                type = Type::METHOD;
358                break;
359            case 'Y':
360                type = Type::ENUM;
361                break;
362            case 'Z':
363                type = Type::ANNOTATION;
364                break;
365            case '@':
366                type = Type::METHOD_HANDLE;
367                break;
368            case '#':
369                type = Type::LITERALARRAY;
370                break;
371            case '0':
372            default:
373                type = Type::UNKNOWN;
374        }
375        return type;
376    }
377
378    Type GetType() const
379    {
380        return type_;
381    }
382
383    bool IsArray() const
384    {
385        return type_ == Type::ARRAY;
386    }
387
388    ScalarValue *GetAsScalar();
389
390    const ScalarValue *GetAsScalar() const;
391
392    ArrayValue *GetAsArray();
393
394    const ArrayValue *GetAsArray() const;
395
396    virtual ~Value() = default;
397
398    DEFAULT_COPY_SEMANTIC(Value);
399    DEFAULT_MOVE_SEMANTIC(Value);
400
401protected:
402    explicit Value(Type type) : type_(type) {}
403
404private:
405    Type type_;
406};
407
408// clang-format off
409
410template <Value::Type value_type>
411struct ValueTypeHelper {
412    // Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=40640
413    // NOLINTNEXTLINE(readability-magic-numbers)
414    using type = std::conditional_t<value_type == Value::Type::U1, uint8_t,
415                // NOLINTNEXTLINE(readability-magic-numbers)
416                std::conditional_t<value_type == Value::Type::I8, int8_t,
417                // NOLINTNEXTLINE(readability-magic-numbers)
418                std::conditional_t<value_type == Value::Type::U8, uint8_t,
419                // NOLINTNEXTLINE(readability-magic-numbers)
420                std::conditional_t<value_type == Value::Type::I16, int16_t,
421                // NOLINTNEXTLINE(readability-magic-numbers)
422                std::conditional_t<value_type == Value::Type::U16, uint16_t,
423                // NOLINTNEXTLINE(readability-magic-numbers)
424                std::conditional_t<value_type == Value::Type::I32, int32_t,
425                // NOLINTNEXTLINE(readability-magic-numbers)
426                std::conditional_t<value_type == Value::Type::U32, uint32_t,
427                // NOLINTNEXTLINE(readability-magic-numbers)
428                std::conditional_t<value_type == Value::Type::I64, int64_t,
429                // NOLINTNEXTLINE(readability-magic-numbers)
430                std::conditional_t<value_type == Value::Type::U64, uint64_t,
431                // NOLINTNEXTLINE(readability-magic-numbers)
432                std::conditional_t<value_type == Value::Type::F32, float,
433                // NOLINTNEXTLINE(readability-magic-numbers)
434                std::conditional_t<value_type == Value::Type::F64, double,
435                // NOLINTNEXTLINE(readability-magic-numbers)
436                std::conditional_t<value_type == Value::Type::STRING, std::string_view,
437                // NOLINTNEXTLINE(readability-magic-numbers)
438                std::conditional_t<value_type == Value::Type::STRING_NULLPTR, uint32_t,
439                // NOLINTNEXTLINE(readability-magic-numbers)
440                std::conditional_t<value_type == Value::Type::RECORD, pandasm::Type,
441                // NOLINTNEXTLINE(readability-magic-numbers)
442                std::conditional_t<value_type == Value::Type::METHOD, std::string_view,
443                // NOLINTNEXTLINE(readability-magic-numbers)
444                std::conditional_t<value_type == Value::Type::ENUM, std::string_view,
445                // NOLINTNEXTLINE(readability-magic-numbers)
446                std::conditional_t<value_type == Value::Type::ANNOTATION, AnnotationData,
447                // NOLINTNEXTLINE(readability-magic-numbers)
448                std::conditional_t<value_type == Value::Type::LITERALARRAY, std::string_view,
449                void>>>>>>>>>>>>>>>>>>;
450};
451
452// clang-format on
453
454template <Value::Type type>
455using ValueTypeHelperT = typename ValueTypeHelper<type>::type;
456
457class ScalarValue : public Value {
458public:
459    template <Value::Type type>
460    // Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=40640
461    // NOLINTNEXTLINE(readability-magic-numbers)
462    static ScalarValue Create(ValueTypeHelperT<type> value)
463    {
464        // NOLINTNEXTLINE(readability-magic-numbers)
465        using T = ValueTypeHelperT<type>;
466        // Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203
467        // NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements)
468        if constexpr (std::is_integral_v<T>) {  // NOLINT(bugprone-suspicious-semicolon)
469            // NOLINTNEXTLINE(readability-magic-numbers)
470            return ScalarValue(type, static_cast<uint64_t>(value));
471        }
472
473        // NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements)
474        if constexpr (!std::is_integral_v<T>) {  // NOLINT(bugprone-suspicious-semicolon)
475            // NOLINTNEXTLINE(readability-magic-numbers)
476            return ScalarValue(type, value);
477        }
478    }
479
480    template <class T>
481    T GetValue() const
482    {
483        // Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203
484        // NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements)
485        if constexpr (std::is_integral_v<T>) {  // NOLINT(bugprone-suspicious-semicolon)
486            return static_cast<T>(std::get<uint64_t>(value_));
487        }
488
489        // NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements)
490        if constexpr (!std::is_integral_v<T>) {  // NOLINT(bugprone-suspicious-semicolon)
491            return std::get<T>(value_);
492        }
493    }
494
495    DEFAULT_MOVE_SEMANTIC(ScalarValue);
496    DEFAULT_COPY_SEMANTIC(ScalarValue);
497
498    ~ScalarValue() override = default;
499
500private:
501    ScalarValue(Type type, uint64_t value) : Value(type), value_(value) {}
502
503    ScalarValue(Type type, float value) : Value(type), value_(value) {}
504
505    ScalarValue(Type type, double value) : Value(type), value_(value) {}
506
507    ScalarValue(Type type, const std::string_view &value) : Value(type), value_(std::string(value)) {}
508
509    ScalarValue(Type type, pandasm::Type value) : Value(type), value_(std::move(value)) {}
510
511    ScalarValue(Type type, AnnotationData &value) : Value(type), value_(value) {}
512
513    std::variant<uint64_t, float, double, std::string, pandasm::Type, AnnotationData> value_;
514};
515
516class ArrayValue : public Value {
517public:
518    ArrayValue(Type component_type, std::vector<ScalarValue> values)
519        : Value(Type::ARRAY), component_type_(component_type), values_(std::move(values))
520    {
521    }
522
523    DEFAULT_MOVE_SEMANTIC(ArrayValue);
524    DEFAULT_COPY_SEMANTIC(ArrayValue);
525
526    ~ArrayValue() override = default;
527
528    const std::vector<ScalarValue> &GetValues() const
529    {
530        return values_;
531    }
532
533    Type GetComponentType() const
534    {
535        return component_type_;
536    }
537
538private:
539    Type component_type_;
540    std::vector<ScalarValue> values_;
541};
542
543class AnnotationElement {
544public:
545    AnnotationElement(const std::string_view &name, std::unique_ptr<Value> value)
546        : name_(name), value_(std::move(value)) {}
547
548    AnnotationElement(const AnnotationElement &ann_elem);
549    AnnotationElement &operator=(const AnnotationElement &ann_elem);
550    DEFAULT_MOVE_SEMANTIC(AnnotationElement);
551    ~AnnotationElement() = default;
552
553    std::string GetName() const
554    {
555        return name_;
556    }
557
558    Value *GetValue() const
559    {
560        return value_.get();
561    }
562
563    static std::string TypeToString(Value::Type type);
564
565private:
566    std::string name_;
567    std::unique_ptr<Value> value_;
568};
569
570}  // namespace panda::pandasm
571
572#endif  // ASSEMBLER_ANNOTATION_H
573