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#include "ETSLexer.h"
17#include "generated/keywords.h"
18
19namespace ark::es2panda::lexer {
20// NOLINTNEXTLINE(google-default-arguments)
21void ETSLexer::NextToken(NextTokenFlags flags)
22{
23    ETSKeywords kws(this, static_cast<NextTokenFlags>(flags & ~NextTokenFlags::KEYWORD_TO_IDENT));
24    Lexer::NextToken(&kws);
25}
26
27void ETSLexer::ScanHashMark()
28{
29    ThrowUnexpectedToken(TokenType::PUNCTUATOR_HASH_MARK);
30}
31
32bool ETSLexer::ScanCharLiteral()
33{
34    //  Note: for character literal on call iterator is pointed to the opening single quote (') character!
35    //  Otherwise it's another token.
36    if (Iterator().Peek() != LEX_CHAR_SINGLE_QUOTE) {
37        return false;
38    }
39
40    GetToken().type_ = TokenType::LITERAL_CHAR;
41
42    Iterator().Forward(1);
43    char32_t cp = Iterator().PeekCp();
44
45    switch (cp) {
46        case LEX_CHAR_SINGLE_QUOTE:
47        case util::StringView::Iterator::INVALID_CP: {
48            ThrowError("Invalid character literal");
49            break;
50        }
51        case LEX_CHAR_BACKSLASH: {
52            GetToken().flags_ |= TokenFlags::HAS_ESCAPE;
53
54            Iterator().Forward(1);
55            cp = ScanUnicodeCharacter();
56            break;
57        }
58        default: {
59            Iterator().SkipCp();
60            break;
61        }
62    }
63
64    CheckUtf16Compatible(cp);
65    GetToken().c16_ = cp;
66
67    if (Iterator().Peek() != LEX_CHAR_SINGLE_QUOTE) {
68        ThrowError("Unterminated character literal");
69    }
70
71    Iterator().Forward(1);
72    return true;
73}
74
75void ETSLexer::CheckNumberLiteralEnd()
76{
77    if (Iterator().Peek() == LEX_CHAR_LOWERCASE_F) {
78        GetToken().flags_ |= TokenFlags::NUMBER_FLOAT;
79        GetToken().src_ = SourceView(GetToken().Start().index, Iterator().Index());
80        Iterator().Forward(1);
81        const auto nextCp = Iterator().PeekCp();
82        if (KeywordsUtil::IsIdentifierStart(nextCp) || IsDecimalDigit(nextCp)) {
83            ThrowError("Invalid numeric literal");
84        }
85    } else {
86        Lexer::CheckNumberLiteralEnd();
87    }
88}
89
90void ETSLexer::CheckUtf16Compatible(char32_t cp) const
91{
92    if (cp >= util::StringView::Constants::CELESTIAL_OFFSET) {
93        ThrowError("Unsupported character literal");
94    }
95}
96
97void ETSLexer::ScanAsteriskPunctuator()
98{
99    GetToken().type_ = TokenType::PUNCTUATOR_MULTIPLY;
100
101    switch (Iterator().Peek()) {
102        case LEX_CHAR_EQUALS: {
103            GetToken().type_ = TokenType::PUNCTUATOR_MULTIPLY_EQUAL;
104            Iterator().Forward(1);
105            break;
106        }
107        default: {
108            break;
109        }
110    }
111}
112
113void ETSLexer::ConvertNumber(const std::string &utf8, NumberFlags flags)
114{
115    GetToken().number_ = lexer::Number(GetToken().src_, utf8, flags);
116
117    if (GetToken().number_.ConversionError()) {
118        ThrowError("Invalid number");
119    }
120}
121
122void ETSLexer::ScanEqualsPunctuator()
123{
124    GetToken().type_ = TokenType::PUNCTUATOR_SUBSTITUTION;
125
126    switch (Iterator().Peek()) {
127        case LEX_CHAR_EQUALS: {
128            GetToken().type_ = TokenType::PUNCTUATOR_EQUAL;
129            Iterator().Forward(1);
130
131            if (Iterator().Peek() == LEX_CHAR_EQUALS) {
132                GetToken().type_ = TokenType::PUNCTUATOR_STRICT_EQUAL;
133                Iterator().Forward(1);
134            }
135            break;
136        }
137        case LEX_CHAR_GREATER_THAN: {
138            GetToken().type_ = TokenType::PUNCTUATOR_ARROW;
139            Iterator().Forward(1);
140            break;
141        }
142        default: {
143            break;
144        }
145    }
146}
147
148void ETSLexer::ScanExclamationPunctuator()
149{
150    GetToken().type_ = TokenType::PUNCTUATOR_EXCLAMATION_MARK;
151
152    switch (Iterator().Peek()) {
153        case LEX_CHAR_EQUALS: {
154            GetToken().type_ = TokenType::PUNCTUATOR_NOT_EQUAL;
155            Iterator().Forward(1);
156
157            if (Iterator().Peek() == LEX_CHAR_EQUALS) {
158                GetToken().type_ = TokenType::PUNCTUATOR_NOT_STRICT_EQUAL;
159                Iterator().Forward(1);
160            }
161            break;
162        }
163        default: {
164            break;
165        }
166    }
167}
168
169bool ETSLexer::ScanDollarPunctuator()
170{
171    if (Iterator().Peek() != LEX_CHAR_DOLLAR_SIGN) {
172        return false;
173    }
174
175    GetToken().type_ = TokenType::PUNCTUATOR_DOLLAR_DOLLAR;
176    Iterator().Forward(1);
177    return true;
178}
179}  // namespace ark::es2panda::lexer
180