1 /*
2 * Copyright (c) 2021 - 2023 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
19 namespace panda::es2panda::lexer {
20 // NOLINTNEXTLINE(google-default-arguments)
NextToken(NextTokenFlags flags)21 void ETSLexer::NextToken(NextTokenFlags flags)
22 {
23 ETSKeywords kws(this, static_cast<NextTokenFlags>(flags & ~NextTokenFlags::KEYWORD_TO_IDENT));
24 Lexer::NextToken(&kws);
25 }
26
ScanHashMark()27 void ETSLexer::ScanHashMark()
28 {
29 ThrowUnexpectedToken(TokenType::PUNCTUATOR_HASH_MARK);
30 }
31
ScanCharLiteral()32 bool 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
CheckNumberLiteralEnd()75 void 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
CheckUtf16Compatible(char32_t cp) const90 void ETSLexer::CheckUtf16Compatible(char32_t cp) const
91 {
92 if (cp >= util::StringView::Constants::CELESTIAL_OFFSET) {
93 ThrowError("Unsupported character literal");
94 }
95 }
96
SkipMultiLineComment()97 void ETSLexer::SkipMultiLineComment()
98 {
99 uint32_t depth = 1U;
100
101 // Just to reduce extra nested level(s)
102 auto const checkAsterisk = [this, &depth]() -> bool {
103 if (Iterator().Peek() == LEX_CHAR_SLASH) {
104 Iterator().Forward(1);
105
106 if (--depth == 0U) {
107 return false;
108 }
109 }
110 return true;
111 };
112
113 while (true) {
114 switch (Iterator().Next()) {
115 case util::StringView::Iterator::INVALID_CP: {
116 ThrowError("Unterminated multi-line comment");
117 break;
118 }
119 case LEX_CHAR_LF:
120 case LEX_CHAR_CR:
121 case LEX_CHAR_LS:
122 case LEX_CHAR_PS: {
123 Pos().NextTokenLine()++;
124 continue;
125 }
126 case LEX_CHAR_ASTERISK: {
127 if (!checkAsterisk()) {
128 return;
129 }
130 break;
131 }
132 case LEX_CHAR_SLASH: {
133 if (Iterator().Peek() == LEX_CHAR_ASTERISK) {
134 Iterator().Forward(1);
135 depth++;
136 }
137 break;
138 }
139
140 default: {
141 break;
142 }
143 }
144 }
145 }
146
ScanAsteriskPunctuator()147 void ETSLexer::ScanAsteriskPunctuator()
148 {
149 GetToken().type_ = TokenType::PUNCTUATOR_MULTIPLY;
150
151 switch (Iterator().Peek()) {
152 case LEX_CHAR_EQUALS: {
153 GetToken().type_ = TokenType::PUNCTUATOR_MULTIPLY_EQUAL;
154 Iterator().Forward(1);
155 break;
156 }
157 default: {
158 break;
159 }
160 }
161 }
162
ConvertNumber(const std::string & utf8,NumberFlags flags)163 void ETSLexer::ConvertNumber(const std::string &utf8, NumberFlags flags)
164 {
165 GetToken().number_ = lexer::Number(GetToken().src_, utf8, flags);
166
167 if (GetToken().number_.ConversionError()) {
168 ThrowError("Invalid number");
169 }
170 }
171
ScanEqualsPunctuator()172 void ETSLexer::ScanEqualsPunctuator()
173 {
174 GetToken().type_ = TokenType::PUNCTUATOR_SUBSTITUTION;
175
176 switch (Iterator().Peek()) {
177 case LEX_CHAR_EQUALS: {
178 GetToken().type_ = TokenType::PUNCTUATOR_EQUAL;
179 Iterator().Forward(1);
180
181 if (Iterator().Peek() == LEX_CHAR_EQUALS) {
182 GetToken().type_ = TokenType::PUNCTUATOR_STRICT_EQUAL;
183 Iterator().Forward(1);
184 }
185 break;
186 }
187 case LEX_CHAR_GREATER_THAN: {
188 GetToken().type_ = TokenType::PUNCTUATOR_ARROW;
189 Iterator().Forward(1);
190 break;
191 }
192 default: {
193 break;
194 }
195 }
196 }
197
ScanExclamationPunctuator()198 void ETSLexer::ScanExclamationPunctuator()
199 {
200 GetToken().type_ = TokenType::PUNCTUATOR_EXCLAMATION_MARK;
201
202 switch (Iterator().Peek()) {
203 case LEX_CHAR_EQUALS: {
204 GetToken().type_ = TokenType::PUNCTUATOR_NOT_EQUAL;
205 Iterator().Forward(1);
206
207 if (Iterator().Peek() == LEX_CHAR_EQUALS) {
208 GetToken().type_ = TokenType::PUNCTUATOR_NOT_STRICT_EQUAL;
209 Iterator().Forward(1);
210 }
211 break;
212 }
213 default: {
214 break;
215 }
216 }
217 }
218
ScanDollarPunctuator()219 bool ETSLexer::ScanDollarPunctuator()
220 {
221 if (Iterator().Peek() != LEX_CHAR_DOLLAR_SIGN) {
222 return false;
223 }
224
225 GetToken().type_ = TokenType::PUNCTUATOR_DOLLAR_DOLLAR;
226 Iterator().Forward(1);
227 return true;
228 }
229 } // namespace panda::es2panda::lexer
230