1 /**
2 * Copyright (c) 2021-2025 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 "parserImpl.h"
17 #include "parserStatusContext.h"
18
19 #include "generated/diagnostic.h"
20 #include "varbinder/privateBinding.h"
21 #include "ir/brokenTypeNode.h"
22 #include "ir/base/classDefinition.h"
23 #include "ir/base/classProperty.h"
24 #include "ir/base/classStaticBlock.h"
25 #include "ir/base/methodDefinition.h"
26 #include "ir/base/scriptFunction.h"
27 #include "ir/base/spreadElement.h"
28 #include "ir/expressions/arrayExpression.h"
29 #include "ir/expressions/assignmentExpression.h"
30 #include "ir/expressions/callExpression.h"
31 #include "ir/expressions/functionExpression.h"
32 #include "ir/expressions/literals/bigIntLiteral.h"
33 #include "ir/expressions/literals/numberLiteral.h"
34 #include "ir/expressions/literals/stringLiteral.h"
35 #include "ir/expressions/objectExpression.h"
36 #include "ir/expressions/superExpression.h"
37 #include "ir/ets/etsParameterExpression.h"
38 #include "ir/statements/blockStatement.h"
39 #include "ir/statements/expressionStatement.h"
40 #include "util/errorRecovery.h"
41
42 using namespace std::literals::string_literals;
43
44 namespace ark::es2panda::parser {
ParserImpl(Program * program,const util::Options * options,util::DiagnosticEngine & diagnosticEngine,ParserStatus status)45 ParserImpl::ParserImpl(Program *program, const util::Options *options, util::DiagnosticEngine &diagnosticEngine,
46 ParserStatus status)
47 : program_(program),
48 context_(program_, status, options == nullptr ? false : options->IsEnableJsdocParse()),
49 options_(options),
50 diagnosticEngine_(diagnosticEngine)
51 {
52 }
53
InitLexer(const SourceFile & sourceFile)54 std::unique_ptr<lexer::Lexer> ParserImpl::InitLexer(const SourceFile &sourceFile)
55 {
56 program_->SetSource(sourceFile);
57 std::unique_ptr<lexer::Lexer> lexer = std::make_unique<lexer::Lexer>(&context_, diagnosticEngine_);
58 lexer_ = lexer.get();
59 return lexer;
60 }
61
ParseScript(const SourceFile & sourceFile,bool genStdLib)62 void ParserImpl::ParseScript(const SourceFile &sourceFile, bool genStdLib)
63 {
64 auto lexer = InitLexer(sourceFile);
65
66 if (sourceFile.isModule) {
67 context_.Status() |= (ParserStatus::MODULE);
68 ParseProgram(ScriptKind::MODULE);
69 } else if (genStdLib) {
70 ParseProgram(ScriptKind::STDLIB);
71 } else {
72 ParseProgram(ScriptKind::SCRIPT);
73 }
74 }
75
ParseProgram(ScriptKind kind)76 void ParserImpl::ParseProgram(ScriptKind kind)
77 {
78 lexer::SourcePosition startLoc = lexer_->GetToken().Start();
79 lexer_->NextToken();
80 program_->SetKind(kind);
81
82 auto statements = ParseStatementList(StatementParsingFlags::STMT_GLOBAL_LEXICAL);
83
84 auto *blockStmt = AllocNode<ir::BlockStatement>(Allocator(), std::move(statements));
85 ES2PANDA_ASSERT(blockStmt != nullptr);
86 blockStmt->SetRange({startLoc, lexer_->GetToken().End()});
87
88 program_->SetAst(blockStmt);
89 }
90
InAmbientContext()91 bool ParserImpl::InAmbientContext()
92 {
93 return (context_.Status() & ParserStatus::IN_AMBIENT_CONTEXT) != 0;
94 }
95
CarryExpressionParserFlag(ExpressionParseFlags origin,ExpressionParseFlags carry)96 ExpressionParseFlags ParserImpl::CarryExpressionParserFlag(ExpressionParseFlags origin, ExpressionParseFlags carry)
97 {
98 return static_cast<ExpressionParseFlags>(origin & carry);
99 }
100
CarryPatternFlags(ExpressionParseFlags flags)101 ExpressionParseFlags ParserImpl::CarryPatternFlags(ExpressionParseFlags flags)
102 {
103 return CarryExpressionParserFlag(flags, ExpressionParseFlags::POTENTIALLY_IN_PATTERN |
104 ExpressionParseFlags::OBJECT_PATTERN);
105 }
106
GetAccessability(ir::ModifierFlags modifiers)107 ir::ModifierFlags ParserImpl::GetAccessability(ir::ModifierFlags modifiers)
108 {
109 if ((modifiers & ir::ModifierFlags::PUBLIC) != 0) {
110 return ir::ModifierFlags::PUBLIC;
111 }
112
113 if ((modifiers & ir::ModifierFlags::PRIVATE) != 0) {
114 return ir::ModifierFlags::PRIVATE;
115 }
116
117 if ((modifiers & ir::ModifierFlags::PROTECTED) != 0) {
118 return ir::ModifierFlags::PROTECTED;
119 }
120
121 if ((modifiers & ir::ModifierFlags::INTERNAL) != 0) {
122 return ir::ModifierFlags::INTERNAL;
123 }
124
125 return ir::ModifierFlags::NONE;
126 }
127
IsModifierKind(const lexer::Token & token)128 bool ParserImpl::IsModifierKind(const lexer::Token &token)
129 {
130 switch (token.KeywordType()) {
131 case lexer::TokenType::KEYW_STATIC:
132 case lexer::TokenType::KEYW_ASYNC:
133 return true;
134 default:
135 break;
136 }
137
138 return false;
139 }
140
ParseModifiers()141 ir::ModifierFlags ParserImpl::ParseModifiers()
142 {
143 ir::ModifierFlags resultStatus = ir::ModifierFlags::NONE;
144 ir::ModifierFlags prevStatus = ir::ModifierFlags::ALL;
145
146 while (IsModifierKind(lexer_->GetToken())) {
147 char32_t nextCp = lexer_->Lookahead();
148 if (nextCp == lexer::LEX_CHAR_LEFT_PAREN) {
149 return resultStatus;
150 }
151
152 lexer::TokenFlags tokenFlags = lexer_->GetToken().Flags();
153 if ((tokenFlags & lexer::TokenFlags::HAS_ESCAPE) != 0) {
154 LogError(diagnostic::KEYWORD_CONTAINS_ESCAPED_CHARS);
155 }
156
157 ir::ModifierFlags actualStatus = ir::ModifierFlags::NONE;
158 ir::ModifierFlags nextStatus = ir::ModifierFlags::NONE;
159
160 switch (lexer_->GetToken().KeywordType()) {
161 case lexer::TokenType::KEYW_STATIC: {
162 actualStatus = ir::ModifierFlags::STATIC;
163 nextStatus = ir::ModifierFlags::ASYNC;
164 break;
165 }
166 case lexer::TokenType::KEYW_ASYNC: {
167 actualStatus = ir::ModifierFlags::ASYNC;
168 nextStatus = ir::ModifierFlags::NONE;
169 break;
170 }
171 default: {
172 break;
173 }
174 }
175
176 if (lexer_->Lookahead() == lexer::LEX_CHAR_COLON || lexer_->Lookahead() == lexer::LEX_CHAR_COMMA ||
177 lexer_->Lookahead() == lexer::LEX_CHAR_RIGHT_PAREN || lexer_->Lookahead() == lexer::LEX_CHAR_QUESTION ||
178 lexer_->Lookahead() == lexer::LEX_CHAR_RIGHT_BRACE || lexer_->Lookahead() == lexer::LEX_CHAR_LESS_THAN) {
179 break;
180 }
181
182 if ((prevStatus & actualStatus) == 0) {
183 LogError(diagnostic::UNEXPECTED_MODIFIER);
184 }
185
186 if ((resultStatus & actualStatus) != 0) {
187 LogError(diagnostic::DUPLICATED_MODIFIER);
188 }
189
190 lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
191
192 resultStatus |= actualStatus;
193 prevStatus = nextStatus;
194 }
195
196 return resultStatus;
197 }
198
CheckAccessorPair(const ArenaVector<ir::AstNode * > & properties,const ir::Expression * propName,ir::MethodDefinitionKind methodKind,ir::ModifierFlags access)199 void ParserImpl::CheckAccessorPair(const ArenaVector<ir::AstNode *> &properties, const ir::Expression *propName,
200 ir::MethodDefinitionKind methodKind, ir::ModifierFlags access)
201 {
202 for (const auto &it : properties) {
203 if (!it->IsMethodDefinition() || it->AsMethodDefinition()->Kind() != methodKind) {
204 continue;
205 }
206
207 const ir::Expression *key = it->AsMethodDefinition()->Key();
208
209 if (key->Type() != propName->Type()) {
210 continue;
211 }
212
213 bool keyIsSame = false;
214
215 if (key->IsIdentifier()) {
216 const util::StringView &strName = propName->AsIdentifier()->Name();
217 const util::StringView &compareName = (key->AsIdentifier()->Name());
218
219 keyIsSame = strName == compareName;
220 } else if (key->IsNumberLiteral()) {
221 keyIsSame =
222 key->AsNumberLiteral()->Number().GetDouble() == propName->AsNumberLiteral()->Number().GetDouble();
223 } else if (key->IsStringLiteral()) {
224 keyIsSame = *key->AsStringLiteral() == *propName->AsStringLiteral();
225 }
226
227 if (!keyIsSame) {
228 continue;
229 }
230
231 ir::ModifierFlags getAccess;
232 ir::ModifierFlags setAccess;
233
234 if (methodKind == ir::MethodDefinitionKind::GET) {
235 setAccess = access;
236 getAccess = GetAccessability(it->Modifiers());
237 } else {
238 getAccess = access;
239 setAccess = GetAccessability(it->Modifiers());
240 }
241
242 if ((setAccess == ir::ModifierFlags::NONE && getAccess > ir::ModifierFlags::PUBLIC) ||
243 (setAccess != ir::ModifierFlags::NONE && getAccess > setAccess)) {
244 LogError(diagnostic::GET_ACCESSOR_MUST_BE_AT_LEAST_AS_ACCESSIBLE, {}, key->Start());
245 }
246 }
247 }
248
ParseClassAccessor(ClassElementDescriptor * desc,char32_t * nextCp)249 void ParserImpl::ParseClassAccessor(ClassElementDescriptor *desc, char32_t *nextCp)
250 {
251 ConsumeClassPrivateIdentifier(desc, nextCp);
252
253 if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
254 return;
255 }
256
257 auto keywordType = lexer_->GetToken().KeywordType();
258 if ((keywordType != lexer::TokenType::KEYW_GET && keywordType != lexer::TokenType::KEYW_SET) ||
259 (*nextCp == lexer::LEX_CHAR_EQUALS || *nextCp == lexer::LEX_CHAR_SEMICOLON ||
260 *nextCp == lexer::LEX_CHAR_LEFT_PAREN || *nextCp == lexer::LEX_CHAR_COLON ||
261 *nextCp == lexer::LEX_CHAR_LESS_THAN)) {
262 return;
263 }
264
265 LogIfPrivateIdent(desc, diagnostic::UNEXPECTED_ID);
266
267 if ((lexer_->GetToken().Flags() & lexer::TokenFlags::HAS_ESCAPE) != 0) {
268 LogError(diagnostic::KEYWORD_CONTAINS_ESCAPED_CHARS);
269 }
270
271 desc->methodKind =
272 keywordType == lexer::TokenType::KEYW_GET ? ir::MethodDefinitionKind::GET : ir::MethodDefinitionKind::SET;
273 desc->methodStart = lexer_->GetToken().Start();
274
275 lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
276 ConsumeClassPrivateIdentifier(desc, nextCp);
277 }
278
LogIfPrivateIdent(ClassElementDescriptor * desc,const diagnostic::DiagnosticKind & diagnostic,const util::DiagnosticMessageParams & diagnosticParams)279 void ParserImpl::LogIfPrivateIdent(ClassElementDescriptor *desc, const diagnostic::DiagnosticKind &diagnostic,
280 const util::DiagnosticMessageParams &diagnosticParams)
281 {
282 if (desc->isPrivateIdent) {
283 LogError(diagnostic, diagnosticParams);
284 }
285 }
286
CheckIfStaticConstructor(ir::ModifierFlags flags)287 void ParserImpl::CheckIfStaticConstructor([[maybe_unused]] ir::ModifierFlags flags) {}
288
ValidateClassKey(ClassElementDescriptor * desc)289 void ParserImpl::ValidateClassKey(ClassElementDescriptor *desc)
290 {
291 if (((desc->modifiers & ir::ModifierFlags::ASYNC) != 0 || desc->isGenerator) &&
292 (desc->methodKind == ir::MethodDefinitionKind::GET || desc->methodKind == ir::MethodDefinitionKind::SET)) {
293 LogError(diagnostic::INVALID_ACCESSOR);
294 }
295
296 const util::StringView &propNameStr = lexer_->GetToken().Ident();
297
298 if (propNameStr.Is("constructor")) {
299 if (lexer_->Lookahead() != lexer::LEX_CHAR_LEFT_PAREN) {
300 // test-class-constructor3.ts
301 LogError(diagnostic::CLASS_FIELD_CONSTRUCTOR);
302 }
303
304 LogIfPrivateIdent(desc, diagnostic::PRIVATE_IDENTIFIER_NOT_CONSTRUCTOR);
305
306 if ((desc->modifiers & ir::ModifierFlags::STATIC) == 0) {
307 if ((desc->modifiers & ir::ModifierFlags::ASYNC) != 0 ||
308 desc->methodKind == ir::MethodDefinitionKind::GET ||
309 desc->methodKind == ir::MethodDefinitionKind::SET || desc->isGenerator) {
310 LogError(diagnostic::SPECIAL_METHOD_CONSTRUCTOR);
311 }
312
313 desc->methodKind = ir::MethodDefinitionKind::CONSTRUCTOR;
314 desc->methodStart = lexer_->GetToken().Start();
315 desc->newStatus |= ParserStatus::CONSTRUCTOR_FUNCTION;
316
317 if (desc->hasSuperClass) {
318 desc->newStatus |= ParserStatus::ALLOW_SUPER_CALL;
319 }
320 }
321
322 CheckIfStaticConstructor(desc->modifiers);
323 } else if (propNameStr.Is("prototype") && (desc->modifiers & ir::ModifierFlags::STATIC) != 0) {
324 LogError(diagnostic::STATIC_PROPERTY_PROTOTYPE);
325 }
326 }
327
ParseComputedClassFieldOrIndexSignature(ir::Expression ** propName)328 std::tuple<bool, bool, bool> ParserImpl::ParseComputedClassFieldOrIndexSignature(ir::Expression **propName)
329 {
330 lexer_->NextToken(); // eat left square bracket
331 *propName = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA);
332
333 if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) {
334 // test exists for js extension only
335 LogExpectedToken(lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET);
336 }
337
338 return {true, false, false};
339 }
340
341 // CC-OFFNXT(huge_method[C++], G.FUN.01-CPP) solid logic
ParseClassKey(ClassElementDescriptor * desc)342 ir::Expression *ParserImpl::ParseClassKey(ClassElementDescriptor *desc)
343 {
344 ir::Expression *propName = nullptr;
345 if (lexer_->GetToken().IsKeyword()) {
346 lexer_->GetToken().SetTokenType(lexer::TokenType::LITERAL_IDENT);
347 Lexer()->GetToken().SetTokenStr(ERROR_LITERAL);
348 }
349
350 switch (lexer_->GetToken().Type()) {
351 case lexer::TokenType::LITERAL_IDENT: {
352 ValidateClassKey(desc);
353
354 propName = AllocNode<ir::Identifier>(lexer_->GetToken().Ident(), Allocator());
355 ES2PANDA_ASSERT(propName != nullptr);
356 propName->SetRange(lexer_->GetToken().Loc());
357 propName->AsIdentifier()->SetPrivate(desc->isPrivateIdent);
358 break;
359 }
360 case lexer::TokenType::LITERAL_STRING: {
361 LogIfPrivateIdent(desc, diagnostic::PRIVATE_IDENTIFIER_STRING);
362
363 if (lexer_->GetToken().Ident().Is("constructor")) {
364 LogError(diagnostic::CLASS_FIELD_CONSTRUCTOR);
365 }
366
367 if (lexer_->GetToken().Ident().Is("prototype") && (desc->modifiers & ir::ModifierFlags::STATIC) != 0) {
368 LogError(diagnostic::STATIC_PROPERTY_PROTOTYPE);
369 }
370
371 propName = AllocNode<ir::StringLiteral>(lexer_->GetToken().String());
372 ES2PANDA_ASSERT(propName != nullptr);
373 propName->SetRange(lexer_->GetToken().Loc());
374 break;
375 }
376 case lexer::TokenType::LITERAL_NUMBER: {
377 LogIfPrivateIdent(desc, diagnostic::PRIVATE_IDENTIFIER_NUMBER);
378
379 if ((lexer_->GetToken().Flags() & lexer::TokenFlags::NUMBER_BIGINT) != 0) {
380 propName = AllocNode<ir::BigIntLiteral>(lexer_->GetToken().BigInt());
381 } else {
382 propName = AllocNode<ir::NumberLiteral>(lexer_->GetToken().GetNumber());
383 }
384 ES2PANDA_ASSERT(propName != nullptr);
385
386 propName->SetRange(lexer_->GetToken().Loc());
387 break;
388 }
389 case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: {
390 LogIfPrivateIdent(desc, diagnostic::UNEXPECTED_CHAR_PRIVATE_IDENTIFIER);
391 std::tie(desc->isComputed, desc->invalidComputedProperty, desc->isIndexSignature) =
392 ParseComputedClassFieldOrIndexSignature(&propName);
393 break;
394 }
395 default: {
396 LogError(diagnostic::UNEXPECTED_TOKEN);
397 propName = AllocBrokenExpression(Lexer()->GetToken().Loc());
398 }
399 }
400
401 lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
402
403 return propName;
404 }
405
ValidateClassMethodStart(ClassElementDescriptor * desc,ir::TypeNode * typeAnnotation)406 void ParserImpl::ValidateClassMethodStart(ClassElementDescriptor *desc, [[maybe_unused]] ir::TypeNode *typeAnnotation)
407 {
408 if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) {
409 return;
410 }
411 desc->classMethod = true;
412
413 if ((desc->modifiers & ir::ModifierFlags::ASYNC) != 0) {
414 desc->newStatus |= ParserStatus::ASYNC_FUNCTION;
415 }
416
417 if (desc->isGenerator) {
418 desc->newStatus |= ParserStatus::GENERATOR_FUNCTION;
419 }
420 }
421
ValidateGetterSetter(ir::MethodDefinitionKind methodDefinition,size_t number)422 void ParserImpl::ValidateGetterSetter(ir::MethodDefinitionKind methodDefinition, size_t number)
423 {
424 if (methodDefinition == ir::MethodDefinitionKind::SET) {
425 if (number != 1) {
426 LogError(diagnostic::SETTER_FORMAL_PARAMS);
427 }
428 } else if (methodDefinition == ir::MethodDefinitionKind::GET) {
429 if (number != 0) {
430 LogError(diagnostic::GETTER_FORMAL_PARAMS);
431 }
432 }
433 }
434
ValidateClassSetter(ClassElementDescriptor * desc,const ArenaVector<ir::AstNode * > & properties,ir::Expression * propName,ir::ScriptFunction * func)435 void ParserImpl::ValidateClassSetter([[maybe_unused]] ClassElementDescriptor *desc,
436 [[maybe_unused]] const ArenaVector<ir::AstNode *> &properties,
437 [[maybe_unused]] ir::Expression *propName, ir::ScriptFunction *func)
438 {
439 ValidateGetterSetter(ir::MethodDefinitionKind::SET, func->Params().size());
440 if (func->ReturnTypeAnnotation() != nullptr) {
441 LogError(diagnostic::SETTER_NO_RETURN_TYPE);
442 }
443 }
444
ValidateClassGetter(ClassElementDescriptor * desc,const ArenaVector<ir::AstNode * > & properties,ir::Expression * propName,ir::ScriptFunction * func)445 void ParserImpl::ValidateClassGetter([[maybe_unused]] ClassElementDescriptor *desc,
446 [[maybe_unused]] const ArenaVector<ir::AstNode *> &properties,
447 [[maybe_unused]] ir::Expression *propName, ir::ScriptFunction *func)
448 {
449 ValidateGetterSetter(ir::MethodDefinitionKind::GET, func->Params().size());
450 }
451
ParseClassMethod(ClassElementDescriptor * desc,const ArenaVector<ir::AstNode * > & properties,ir::Expression * propName,lexer::SourcePosition * propEnd)452 ir::MethodDefinition *ParserImpl::ParseClassMethod(ClassElementDescriptor *desc,
453 const ArenaVector<ir::AstNode *> &properties,
454 ir::Expression *propName, lexer::SourcePosition *propEnd)
455 {
456 if (desc->methodKind != ir::MethodDefinitionKind::SET &&
457 (desc->newStatus & ParserStatus::CONSTRUCTOR_FUNCTION) == 0) {
458 desc->newStatus |= ParserStatus::NEED_RETURN_TYPE;
459 }
460
461 ir::ScriptFunction *func = ParseFunction(desc->newStatus);
462
463 auto *funcExpr = AllocNode<ir::FunctionExpression>(func);
464 ES2PANDA_ASSERT(funcExpr != nullptr);
465 funcExpr->SetRange(func->Range());
466
467 if (desc->methodKind == ir::MethodDefinitionKind::SET) {
468 ValidateClassSetter(desc, properties, propName, func);
469 } else if (desc->methodKind == ir::MethodDefinitionKind::GET) {
470 ValidateClassGetter(desc, properties, propName, func);
471 }
472
473 *propEnd = func->End();
474 func->AddFlag(ir::ScriptFunctionFlags::METHOD);
475
476 auto *ident = !propName->IsArrowFunctionExpression() && !propName->IsFunctionExpression()
477 ? propName->Clone(Allocator(), nullptr)->AsExpression()
478 : propName;
479 auto *method = AllocNode<ir::MethodDefinition>(desc->methodKind, ident, funcExpr, desc->modifiers, Allocator(),
480 desc->isComputed);
481 ES2PANDA_ASSERT(method != nullptr);
482 method->SetRange(funcExpr->Range());
483
484 return method;
485 }
486
ParseClassProperty(ClassElementDescriptor * desc,const ArenaVector<ir::AstNode * > & properties,ir::Expression * propName,ir::TypeNode * typeAnnotation)487 ir::ClassElement *ParserImpl::ParseClassProperty(ClassElementDescriptor *desc,
488 const ArenaVector<ir::AstNode *> &properties, ir::Expression *propName,
489 ir::TypeNode *typeAnnotation)
490 {
491 ES2PANDA_ASSERT(propName != nullptr);
492 lexer::SourcePosition propEnd = propName->End();
493 ir::ClassElement *property = nullptr;
494
495 if (desc->classMethod) {
496 if ((desc->modifiers & ir::ModifierFlags::DECLARE) != 0) {
497 LogError(diagnostic::DECLARE_MODIFIER_ON_INVALID_CLASS_ELEMENT);
498 }
499
500 property = ParseClassMethod(desc, properties, propName, &propEnd);
501 ES2PANDA_ASSERT(property != nullptr);
502 property->SetRange({desc->propStart, propEnd});
503 return property;
504 }
505
506 ir::Expression *value = nullptr;
507
508 if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
509 lexer_->NextToken(); // eat equals
510
511 if (InAmbientContext() || (desc->modifiers & ir::ModifierFlags::DECLARE) != 0) {
512 LogError(diagnostic::INITIALIZERS_IN_AMBIENT_CONTEXTS);
513 }
514
515 value = ParseExpression();
516 propEnd = value->End();
517 }
518
519 property =
520 AllocNode<ir::ClassProperty>(propName, value, typeAnnotation, desc->modifiers, Allocator(), desc->isComputed);
521 ES2PANDA_ASSERT(property != nullptr);
522 property->SetRange({desc->propStart, propEnd});
523
524 return property;
525 }
526
CheckClassGeneratorMethod(ClassElementDescriptor * desc,char32_t * nextCp)527 void ParserImpl::CheckClassGeneratorMethod(ClassElementDescriptor *desc, char32_t *nextCp)
528 {
529 if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_MULTIPLY) {
530 return;
531 }
532
533 desc->isGenerator = true;
534 lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
535 *nextCp = lexer_->Lookahead();
536 }
537
ValidatePrivateIdentifier()538 bool ParserImpl::ValidatePrivateIdentifier()
539 {
540 size_t iterIdx = lexer_->GetToken().Start().index;
541 lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
542
543 if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT ||
544 (lexer_->GetToken().Start().index - iterIdx > 1)) {
545 LogError(diagnostic::UNEXPECTED_TOKEN_IN_PRIVATE);
546 return false;
547 }
548
549 return true;
550 }
551
ConsumeClassPrivateIdentifier(ClassElementDescriptor * desc,char32_t * nextCp)552 void ParserImpl::ConsumeClassPrivateIdentifier(ClassElementDescriptor *desc, char32_t *nextCp)
553 {
554 if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_HASH_MARK) {
555 return;
556 }
557
558 desc->isPrivateIdent = true;
559 ValidatePrivateIdentifier();
560 *nextCp = lexer_->Lookahead();
561 }
562
AddPrivateElement(const ir::ClassElement * elem)563 void ParserImpl::AddPrivateElement(const ir::ClassElement *elem)
564 {
565 if (!classPrivateContext_.AddElement(elem)) {
566 LogError(diagnostic::PRIVATE_FIELD_REDEC);
567 }
568 }
569
ParseClassStaticBlock()570 ir::ClassElement *ParserImpl::ParseClassStaticBlock()
571 {
572 const lexer::SourcePosition &startPos = lexer_->GetToken().Start();
573
574 lexer_->NextToken(); // eat 'static'
575
576 SavedParserContext context(this, ParserStatus::ALLOW_SUPER | ParserStatus::STATIC_BLOCK);
577 context_.Status() &= ~(ParserStatus::ASYNC_FUNCTION | ParserStatus::GENERATOR_FUNCTION);
578
579 lexer_->NextToken(); // eat '{'
580
581 ArenaVector<ir::Expression *> params(Allocator()->Adapter());
582
583 ArenaVector<ir::Statement *> statements = ParseStatementList();
584
585 // redundant check -> we have it in parse statements
586 // we even do not consume '}' after
587 ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_BRACE, false);
588
589 auto *body = AllocNode<ir::BlockStatement>(Allocator(), std::move(statements));
590 // clang-format off
591 auto *func = AllocNode<ir::ScriptFunction>(
592 Allocator(), ir::ScriptFunction::ScriptFunctionData {
593 body, ir::FunctionSignature(nullptr, std::move(params), nullptr),
594 ir::ScriptFunctionFlags::EXPRESSION | ir::ScriptFunctionFlags::STATIC_BLOCK,
595 ir::ModifierFlags::STATIC, context_.GetLanguage()});
596 // clang-format on
597
598 auto *funcExpr = AllocNode<ir::FunctionExpression>(func);
599 auto *staticBlock = AllocNode<ir::ClassStaticBlock>(funcExpr, Allocator());
600 ES2PANDA_ASSERT(staticBlock != nullptr);
601 staticBlock->SetRange({startPos, lexer_->GetToken().End()});
602
603 lexer_->NextToken(); // eat '}'
604
605 return staticBlock;
606 }
607
ParseClassElement(const ArenaVector<ir::AstNode * > & properties,ir::ClassDefinitionModifiers modifiers,ir::ModifierFlags flags)608 ir::AstNode *ParserImpl::ParseClassElement(const ArenaVector<ir::AstNode *> &properties,
609 ir::ClassDefinitionModifiers modifiers,
610 [[maybe_unused]] ir::ModifierFlags flags)
611 {
612 if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_STATIC &&
613 lexer_->Lookahead() == lexer::LEX_CHAR_LEFT_BRACE) {
614 return ParseClassStaticBlock();
615 }
616
617 ClassElementDescriptor desc(Allocator());
618
619 desc.methodKind = ir::MethodDefinitionKind::METHOD;
620 desc.newStatus = ParserStatus::ALLOW_SUPER;
621 desc.hasSuperClass = (modifiers & ir::ClassDefinitionModifiers::HAS_SUPER) != 0U;
622 desc.propStart = lexer_->GetToken().Start();
623 desc.modifiers = ParseModifiers();
624
625 char32_t nextCp = lexer_->Lookahead();
626 CheckClassGeneratorMethod(&desc, &nextCp);
627 ParseClassAccessor(&desc, &nextCp);
628
629 if ((desc.modifiers & ir::ModifierFlags::STATIC) == 0) {
630 context_.Status() |= ParserStatus::ALLOW_THIS_TYPE;
631 }
632
633 ir::Expression *propName = ParseClassKey(&desc);
634 ValidateClassMethodStart(&desc, nullptr);
635 ir::ClassElement *property = ParseClassProperty(&desc, properties, propName, nullptr);
636
637 if (property != nullptr && lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SEMI_COLON &&
638 lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE &&
639 (lexer_->GetToken().Flags() & lexer::TokenFlags::NEW_LINE) == 0 &&
640 !(property->IsMethodDefinition() &&
641 property->AsMethodDefinition()->Value()->AsFunctionExpression()->Function()->Body() != nullptr)) {
642 // test exists for js extension only
643 LogExpectedToken(lexer::TokenType::PUNCTUATOR_SEMI_COLON);
644 }
645
646 if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) {
647 lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
648 }
649
650 context_.Status() &= ~ParserStatus::ALLOW_THIS_TYPE;
651
652 // if Id() is nullptr, ParseClassKey has logged an error
653 if (desc.isPrivateIdent && property != nullptr && property->Id() != nullptr) {
654 AddPrivateElement(property);
655 }
656
657 return property;
658 }
659
BuildImplicitConstructor(ir::ClassDefinitionModifiers modifiers,const lexer::SourcePosition & startLoc)660 ir::MethodDefinition *ParserImpl::BuildImplicitConstructor(ir::ClassDefinitionModifiers modifiers,
661 const lexer::SourcePosition &startLoc)
662 {
663 ArenaVector<ir::Expression *> params(Allocator()->Adapter());
664 ArenaVector<ir::Statement *> statements(Allocator()->Adapter());
665
666 if ((modifiers & ir::ClassDefinitionModifiers::HAS_SUPER) != 0U) {
667 util::StringView argsStr = "args";
668 params.push_back(AllocNode<ir::SpreadElement>(ir::AstNodeType::REST_ELEMENT, Allocator(),
669 AllocNode<ir::Identifier>(argsStr, Allocator())));
670 ArenaVector<ir::Expression *> callArgs(Allocator()->Adapter());
671 auto *superExpr = AllocNode<ir::SuperExpression>();
672 callArgs.push_back(AllocNode<ir::SpreadElement>(ir::AstNodeType::SPREAD_ELEMENT, Allocator(),
673 AllocNode<ir::Identifier>(argsStr, Allocator())));
674
675 auto *callExpr = AllocNode<ir::CallExpression>(superExpr, std::move(callArgs), nullptr, false);
676 statements.push_back(AllocNode<ir::ExpressionStatement>(callExpr));
677 }
678
679 auto *body = AllocNode<ir::BlockStatement>(Allocator(), std::move(statements));
680 auto *func = AllocNode<ir::ScriptFunction>(
681 Allocator(), ir::ScriptFunction::ScriptFunctionData {body,
682 ir::FunctionSignature(nullptr, std::move(params), nullptr),
683 ir::ScriptFunctionFlags::CONSTRUCTOR |
684 ir::ScriptFunctionFlags::IMPLICIT_SUPER_CALL_NEEDED,
685 {},
686 context_.GetLanguage()});
687
688 auto *funcExpr = AllocNode<ir::FunctionExpression>(func);
689 auto *key = AllocNode<ir::Identifier>("constructor", Allocator());
690
691 if ((modifiers & ir::ClassDefinitionModifiers::SET_CTOR_ID) != 0U) {
692 ES2PANDA_ASSERT(key != nullptr);
693 func->SetIdent(key->Clone(Allocator(), nullptr));
694 }
695
696 auto *ctor = AllocNode<ir::MethodDefinition>(ir::MethodDefinitionKind::CONSTRUCTOR, key, funcExpr,
697 ir::ModifierFlags::NONE, Allocator(), false);
698 ES2PANDA_ASSERT(ctor != nullptr);
699 const auto rangeImplicitContstuctor = lexer::SourceRange(startLoc, startLoc);
700 ctor->IterateRecursively(
701 [&rangeImplicitContstuctor](ir::AstNode *node) -> void { node->SetRange(rangeImplicitContstuctor); });
702
703 return ctor;
704 }
705
CreateImplicitConstructor(ir::MethodDefinition * & ctor,ArenaVector<ir::AstNode * > & properties,ir::ClassDefinitionModifiers modifiers,ir::ModifierFlags flags,const lexer::SourcePosition & startLoc)706 void ParserImpl::CreateImplicitConstructor(ir::MethodDefinition *&ctor,
707 [[maybe_unused]] ArenaVector<ir::AstNode *> &properties,
708 ir::ClassDefinitionModifiers modifiers, ir::ModifierFlags flags,
709 const lexer::SourcePosition &startLoc)
710 {
711 if (ctor != nullptr) {
712 return;
713 }
714
715 ctor = BuildImplicitConstructor(modifiers, startLoc);
716 if ((flags & ir::ModifierFlags::DECLARE) != 0) {
717 ES2PANDA_ASSERT(ctor != nullptr);
718 auto *ctorFunc = ctor->Function();
719 ES2PANDA_ASSERT(ctorFunc != nullptr);
720 ctorFunc->AddFlag(ir::ScriptFunctionFlags::EXTERNAL);
721 }
722 }
723
ParseClassIdent(ir::ClassDefinitionModifiers modifiers)724 ir::Identifier *ParserImpl::ParseClassIdent(ir::ClassDefinitionModifiers modifiers)
725 {
726 if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) {
727 return ExpectIdentifier();
728 }
729
730 auto idRequired =
731 static_cast<ir::ClassDefinitionModifiers>(modifiers & ir::ClassDefinitionModifiers::DECLARATION_ID_REQUIRED);
732
733 if (idRequired == ir::ClassDefinitionModifiers::DECLARATION_ID_REQUIRED) {
734 LogError(diagnostic::UNEXPECTED_TOKEN_ID);
735 return AllocBrokenExpression(Lexer()->GetToken().Loc());
736 }
737
738 return nullptr;
739 }
740
CheckClassElement(ir::AstNode * property,ir::MethodDefinition * & ctor,ArenaVector<ir::AstNode * > & properties)741 bool ParserImpl::CheckClassElement(ir::AstNode *property, ir::MethodDefinition *&ctor,
742 [[maybe_unused]] ArenaVector<ir::AstNode *> &properties)
743 {
744 if (!property->IsMethodDefinition()) {
745 return false;
746 }
747
748 ir::MethodDefinition *def = property->AsMethodDefinition();
749 if (!def->IsConstructor()) {
750 return false;
751 }
752
753 if (ctor != nullptr) {
754 LogError(diagnostic::MULTIPLE_CONSTRUCTOR_IMPLEMENTATIONS, {}, property->Start());
755 }
756 ctor = def;
757
758 return true;
759 }
760
ParseSuperClassReference()761 ir::Expression *ParserImpl::ParseSuperClassReference()
762 {
763 if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_EXTENDS) {
764 lexer_->NextToken();
765 return ParseLeftHandSideExpression();
766 }
767
768 return nullptr;
769 }
770
ParseSuperClass()771 std::tuple<ir::Expression *, ir::TSTypeParameterInstantiation *> ParserImpl::ParseSuperClass()
772 {
773 return {ParseSuperClassReference(), nullptr};
774 }
775
776 // NOLINTNEXTLINE(google-default-arguments)
ParseClassDefinition(ir::ClassDefinitionModifiers modifiers,ir::ModifierFlags flags)777 ir::ClassDefinition *ParserImpl::ParseClassDefinition(ir::ClassDefinitionModifiers modifiers, ir::ModifierFlags flags)
778 {
779 ExpectToken(lexer::TokenType::KEYW_CLASS);
780
781 ir::Identifier *identNode = ParseClassIdent(modifiers);
782
783 if (identNode == nullptr && (modifiers & ir::ClassDefinitionModifiers::DECLARATION) != 0U) {
784 LogError(diagnostic::UNEXPECTED_TOKEN_ID);
785 return nullptr; // ir::ClassDefinition
786 }
787
788 varbinder::PrivateBinding privateBinding(Allocator(), classId_++);
789
790 // Parse SuperClass
791 auto [superClass, superTypeParams] = ParseSuperClass();
792
793 if (superClass != nullptr) {
794 modifiers |= ir::ClassDefinitionModifiers::HAS_SUPER;
795 }
796
797 // test exists for js extension only
798 ExpectToken(lexer::TokenType::PUNCTUATOR_LEFT_BRACE, false);
799
800 auto [ctor, properties, bodyRange] = ParseClassBody(modifiers, flags);
801
802 ArenaVector<ir::TSClassImplements *> implements(Allocator()->Adapter());
803 auto *classDefinition =
804 AllocNode<ir::ClassDefinition>(identNode, nullptr, superTypeParams, std::move(implements), ctor, superClass,
805 std::move(properties), modifiers, flags, GetContext().GetLanguage());
806 ES2PANDA_ASSERT(classDefinition != nullptr);
807 classDefinition->SetInternalName(privateBinding.View());
808
809 classDefinition->SetRange(bodyRange);
810
811 return classDefinition;
812 }
813
ParseClassBody(ir::ClassDefinitionModifiers modifiers,ir::ModifierFlags flags)814 ParserImpl::ClassBody ParserImpl::ParseClassBody(ir::ClassDefinitionModifiers modifiers, ir::ModifierFlags flags)
815 {
816 auto savedCtx = SavedStatusContext<ParserStatus::IN_CLASS_BODY>(&context_);
817
818 lexer::SourcePosition startLoc = lexer_->GetToken().Start();
819 const auto startOfInnerBody = lexer_->GetToken().End();
820 lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
821
822 ir::MethodDefinition *ctor = nullptr;
823 ArenaVector<ir::AstNode *> properties(Allocator()->Adapter());
824
825 SavedClassPrivateContext classContext(this);
826
827 if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_FORMAT &&
828 lexer_->Lookahead() == static_cast<char32_t>(ARRAY_FORMAT_NODE)) {
829 properties = std::move(ParseAstNodesArrayFormatPlaceholder());
830 if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) {
831 // NOTE(schernykh): add info about LoC
832 LOG(FATAL, ES2PANDA) << "Unexpected " << lexer::TokenToString(lexer_->GetToken().Type())
833 << ", expected '}'.";
834 }
835 } else {
836 while (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE &&
837 lexer_->GetToken().Type() != lexer::TokenType::EOS) {
838 if (lexer_->TryEatTokenType(lexer::TokenType::PUNCTUATOR_SEMI_COLON)) {
839 continue;
840 }
841
842 util::ErrorRecursionGuard infiniteLoopBlocker(Lexer());
843 ir::AstNode *property = ParseClassElement(properties, modifiers, flags);
844 if (property == nullptr) {
845 continue;
846 }
847
848 if (property->IsBrokenStatement()) { // Error processing.
849 continue;
850 }
851
852 if (CheckClassElement(property, ctor, properties)) {
853 continue;
854 }
855
856 properties.push_back(property);
857 }
858 }
859
860 CreateImplicitConstructor(ctor, properties, modifiers, flags, startOfInnerBody);
861 ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_BRACE);
862
863 lexer::SourcePosition endLoc = lexer_->GetToken().End();
864 return {ctor, std::move(properties), lexer::SourceRange {startLoc, endLoc}};
865 }
866
ValidateRestParameter(ir::Expression * param)867 void ParserImpl::ValidateRestParameter(ir::Expression *param)
868 {
869 if (!param->IsIdentifier()) {
870 context_.Status() |= ParserStatus::HAS_COMPLEX_PARAM;
871 if (!param->IsRestElement()) {
872 return;
873 }
874 if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
875 // for now test exists for js extension only
876 LogError(diagnostic::REST_PARAM_NOT_LAST);
877
878 lexer_->GetToken().SetTokenType(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS);
879 }
880 }
881 }
882
ValidateBreakLabel(util::StringView label)883 bool ParserImpl::ValidateBreakLabel(util::StringView label)
884 {
885 return context_.FindLabel(label) != nullptr;
886 }
887
ValidateContinueLabel(util::StringView label)888 bool ParserImpl::ValidateContinueLabel(util::StringView label)
889 {
890 const ParserContext *labelCtx = context_.FindLabel(label);
891 return labelCtx != nullptr && ((labelCtx->Status() & ParserStatus::IN_ITERATION) != 0);
892 }
893
ParseFunctionParams()894 ArenaVector<ir::Expression *> ParserImpl::ParseFunctionParams()
895 {
896 ExpectToken(lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS);
897
898 ArenaVector<ir::Expression *> params(Allocator()->Adapter());
899
900 auto parseFunc = [this, ¶ms]() {
901 ir::Expression *parameter = ParseFunctionParameter();
902 if (parameter == nullptr) {
903 return false;
904 }
905 bool seenOptional = false;
906 for (auto const param : params) {
907 if (param->IsETSParameterExpression() && param->AsETSParameterExpression()->IsOptional()) {
908 seenOptional = true;
909 break;
910 }
911 }
912
913 if (seenOptional && !(parameter->IsETSParameterExpression() &&
914 (parameter->AsETSParameterExpression()->IsOptional() ||
915 parameter->AsETSParameterExpression()->RestParameter() != nullptr))) {
916 LogError(diagnostic::REQUIRED_PARAM_AFTER_OPTIONAL, {}, parameter->Start());
917 }
918
919 if (parameter->IsETSParameterExpression() && parameter->AsETSParameterExpression()->Ident()->IsReceiver() &&
920 !params.empty()) {
921 LogError(diagnostic::FUNC_PARAM_THIS_FIRST);
922 return false;
923 }
924
925 ValidateRestParameter(parameter);
926 params.push_back(parameter);
927 return true;
928 };
929
930 if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_FORMAT &&
931 lexer_->Lookahead() == static_cast<char32_t>(ARRAY_FORMAT_NODE)) {
932 params = std::move(ParseExpressionsArrayFormatPlaceholder());
933 } else {
934 ParseList(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS, lexer::NextTokenFlags::NONE, parseFunc, nullptr,
935 true);
936 }
937
938 return params;
939 }
940
CreateParameterThis(ir::TypeNode * typeAnnotation)941 ir::Expression *ParserImpl::CreateParameterThis([[maybe_unused]] ir::TypeNode *typeAnnotation)
942 {
943 LogError(diagnostic::UNEXPECTED_TOKEN_ID_FUN);
944 return AllocBrokenExpression(Lexer()->GetToken().Loc());
945 }
946
ParseFunctionBody(const ArenaVector<ir::Expression * > & params,ParserStatus newStatus,ParserStatus contextStatus)947 std::tuple<bool, ir::BlockStatement *, lexer::SourcePosition, bool> ParserImpl::ParseFunctionBody(
948 // CC-OFFNXT(G.FMT.06-CPP) project code style
949 [[maybe_unused]] const ArenaVector<ir::Expression *> ¶ms, [[maybe_unused]] ParserStatus newStatus,
950 [[maybe_unused]] ParserStatus contextStatus)
951 {
952 if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
953 LogExpectedToken(lexer::TokenType::PUNCTUATOR_LEFT_BRACE);
954 }
955
956 ir::BlockStatement *body = ParseBlockStatement();
957 ES2PANDA_ASSERT(body != nullptr);
958
959 return {true, body, body->End(), false};
960 }
961
ParseFunctionSignature(ParserStatus status)962 FunctionSignature ParserImpl::ParseFunctionSignature(ParserStatus status)
963 {
964 ir::TSTypeParameterDeclaration *typeParamDecl = ParseFunctionTypeParameters();
965
966 if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) {
967 auto parameter = (status & ParserStatus::ARROW_FUNCTION) != 0 ? ParseFunctionParameter() : nullptr;
968 if (parameter != nullptr) {
969 ArenaVector<ir::Expression *> param(Allocator()->Adapter());
970 param.push_back(parameter);
971 auto res = ir::FunctionSignature(typeParamDecl, std::move(param), nullptr, false);
972 return {std::move(res), ir::ScriptFunctionFlags::NONE};
973 }
974 LogExpectedToken(lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS);
975 }
976
977 FunctionParameterContext funcParamContext(&context_);
978
979 auto params = ParseFunctionParams();
980
981 ir::TypeNode *returnTypeAnnotation = nullptr;
982 bool hasReceiver = !params.empty() && params[0]->IsETSParameterExpression() &&
983 params[0]->AsETSParameterExpression()->Ident()->IsReceiver();
984 if (hasReceiver) {
985 SavedParserContext contextAfterParseParams(this, GetContext().Status() | ParserStatus::HAS_RECEIVER);
986 returnTypeAnnotation = ParseFunctionReturnType(status);
987 } else {
988 returnTypeAnnotation = ParseFunctionReturnType(status);
989 }
990
991 if (GetContext().IsExtensionAccessor() && !hasReceiver) {
992 LogError(diagnostic::EXTENSION_ACCESSOR_RECEIVER);
993 }
994
995 ir::ScriptFunctionFlags throwMarker = ParseFunctionThrowMarker(true);
996
997 auto res = ir::FunctionSignature(typeParamDecl, std::move(params), returnTypeAnnotation, hasReceiver);
998 return {std::move(res), throwMarker};
999 }
1000
ParseFunction(ParserStatus newStatus)1001 ir::ScriptFunction *ParserImpl::ParseFunction(ParserStatus newStatus)
1002 {
1003 FunctionContext functionContext(this, newStatus | ParserStatus::FUNCTION | ParserStatus::ALLOW_NEW_TARGET);
1004
1005 lexer::SourcePosition startLoc = lexer_->GetToken().Start();
1006
1007 auto [signature, throw_marker] = ParseFunctionSignature(newStatus);
1008
1009 auto [letDeclare, body, endLoc, isOverload] = ParseFunctionBody(signature.Params(), newStatus, context_.Status());
1010
1011 if (isOverload) {
1012 functionContext.AddFlag(ir::ScriptFunctionFlags::OVERLOAD);
1013 }
1014
1015 functionContext.AddFlag(throw_marker);
1016 auto *funcNode = AllocNode<ir::ScriptFunction>(
1017 Allocator(),
1018 ir::ScriptFunction::ScriptFunctionData {body,
1019 std::move(signature), // CC-OFFNXT(G.FMT.02-CPP) project code style
1020 functionContext.Flags(), // CC-OFFNXT(G.FMT.02-CPP) project code style
1021 {}, // CC-OFFNXT(G.FMT.02-CPP) project code style
1022 context_.GetLanguage()}); // CC-OFF(G.FMT.02-CPP) project code style
1023 ES2PANDA_ASSERT(funcNode != nullptr);
1024
1025 funcNode->SetRange({startLoc, endLoc});
1026
1027 return funcNode;
1028 }
1029
ParseSpreadElement(ExpressionParseFlags flags)1030 ir::SpreadElement *ParserImpl::ParseSpreadElement(ExpressionParseFlags flags)
1031 {
1032 ES2PANDA_ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD);
1033 lexer::SourcePosition startLocation = lexer_->GetToken().Start();
1034 bool inPattern = (flags & ExpressionParseFlags::MUST_BE_PATTERN) != 0;
1035 lexer_->NextToken();
1036
1037 ir::Expression *argument {};
1038 if (inPattern) {
1039 argument = ParsePatternElement(ExpressionParseFlags::IN_REST);
1040 if ((flags & ExpressionParseFlags::OBJECT_PATTERN) != 0 && !argument->IsIdentifier()) {
1041 LogError(diagnostic::RESTPARAM_ID_IN_DEC_CONTEXT);
1042 }
1043 } else {
1044 argument = ParseExpression(flags);
1045 }
1046
1047 if (inPattern && argument->IsAssignmentExpression()) {
1048 LogError(diagnostic::RESTPARAM_INIT);
1049 }
1050
1051 auto nodeType = inPattern ? ir::AstNodeType::REST_ELEMENT : ir::AstNodeType::SPREAD_ELEMENT;
1052 auto *spreadElementNode = AllocNode<ir::SpreadElement>(nodeType, Allocator(), argument);
1053 ES2PANDA_ASSERT(spreadElementNode != nullptr);
1054 spreadElementNode->SetRange({startLocation, argument->End()});
1055 return spreadElementNode;
1056 }
1057
CheckRestrictedBinding()1058 void ParserImpl::CheckRestrictedBinding()
1059 {
1060 ES2PANDA_ASSERT(lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT);
1061 CheckRestrictedBinding(lexer_->GetToken().KeywordType());
1062 }
1063
CheckRestrictedBinding(lexer::TokenType keywordType)1064 void ParserImpl::CheckRestrictedBinding(lexer::TokenType keywordType)
1065 {
1066 if (keywordType == lexer::TokenType::KEYW_ARGUMENTS || keywordType == lexer::TokenType::KEYW_EVAL) {
1067 LogError(diagnostic::EVAL_OR_ARGUMENTS_IN_STRICT_MODE, {}, lexer_->GetToken().Start());
1068 }
1069 }
1070
CheckRestrictedBinding(const util::StringView & ident,const lexer::SourcePosition & pos)1071 void ParserImpl::CheckRestrictedBinding(const util::StringView &ident, const lexer::SourcePosition &pos)
1072 {
1073 if (ident.Is("eval") || ident.Is("arguments")) {
1074 LogError(diagnostic::EVAL_OR_ARGUMENTS_IN_STRICT_MODE, {}, pos);
1075 }
1076 }
1077
ParseFunctionParameter()1078 ir::Expression *ParserImpl::ParseFunctionParameter()
1079 {
1080 ConvertThisKeywordToIdentIfNecessary();
1081
1082 if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) {
1083 CheckRestrictedBinding();
1084 }
1085
1086 return ParsePatternElement(ExpressionParseFlags::NO_OPTS, true);
1087 }
1088
ValidateLvalueAssignmentTarget(ir::Expression * node)1089 void ParserImpl::ValidateLvalueAssignmentTarget(ir::Expression *node)
1090 {
1091 switch (node->Type()) {
1092 case ir::AstNodeType::IDENTIFIER: {
1093 CheckRestrictedBinding(node->AsIdentifier()->Name(), node->Start());
1094 break;
1095 }
1096 case ir::AstNodeType::MEMBER_EXPRESSION: {
1097 break;
1098 }
1099 default: {
1100 LogError(diagnostic::INVALID_LEFT_SIDE_IN_ASSIGNMENT);
1101 }
1102 }
1103 }
1104
ValidateAssignmentTarget(ExpressionParseFlags flags,ir::Expression * node)1105 void ParserImpl::ValidateAssignmentTarget(ExpressionParseFlags flags, ir::Expression *node)
1106 {
1107 switch (node->Type()) {
1108 case ir::AstNodeType::ARRAY_PATTERN:
1109 case ir::AstNodeType::OBJECT_PATTERN: {
1110 break;
1111 }
1112 case ir::AstNodeType::ARRAY_EXPRESSION:
1113 case ir::AstNodeType::OBJECT_EXPRESSION: {
1114 if ((flags & ExpressionParseFlags::POTENTIALLY_IN_PATTERN) != 0) {
1115 return;
1116 }
1117
1118 [[fallthrough]];
1119 }
1120 default: {
1121 return ValidateLvalueAssignmentTarget(node);
1122 }
1123 }
1124 }
1125
ValidateArrowParameterBindings(const ir::Expression * node)1126 void ParserImpl::ValidateArrowParameterBindings(const ir::Expression *node)
1127 {
1128 switch (node->Type()) {
1129 case ir::AstNodeType::IDENTIFIER: {
1130 CheckRestrictedBinding(node->AsIdentifier()->Name(), node->Start());
1131 break;
1132 }
1133 case ir::AstNodeType::OMITTED_EXPRESSION: {
1134 break;
1135 }
1136 case ir::AstNodeType::REST_ELEMENT: {
1137 ValidateArrowParameterBindings(node->AsRestElement()->Argument());
1138 break;
1139 }
1140 case ir::AstNodeType::PROPERTY: {
1141 break;
1142 }
1143 case ir::AstNodeType::OBJECT_PATTERN: {
1144 const auto &props = node->AsObjectPattern()->Properties();
1145
1146 for (auto *it : props) {
1147 ValidateArrowParameterBindings(it);
1148 }
1149 break;
1150 }
1151 case ir::AstNodeType::ARRAY_PATTERN: {
1152 const auto &elements = node->AsArrayPattern()->Elements();
1153
1154 for (auto *it : elements) {
1155 ValidateArrowParameterBindings(it);
1156 }
1157 break;
1158 }
1159 case ir::AstNodeType::ASSIGNMENT_PATTERN: {
1160 ValidateArrowParameterBindings(node->AsAssignmentPattern()->Left());
1161 // CC-OFFNXT(G.FMT.06-CPP) project code style
1162 break;
1163 }
1164 default: {
1165 LogError(diagnostic::UNEXPECTED_ARROWPARAM_ELEMENT);
1166 }
1167 }
1168 }
1169
LogParameterModifierError(ir::ModifierFlags status)1170 void ParserImpl::LogParameterModifierError(ir::ModifierFlags status)
1171 {
1172 LogError(diagnostic::PARAM_MODIFIER_CANNOT_APPEAR_ON_PARAMETER,
1173 {(status & ir::ModifierFlags::STATIC) != 0 ? "static"
1174 : (status & ir::ModifierFlags::ASYNC) != 0 ? "async"
1175 : "declare"},
1176 lexer_->GetToken().Start());
1177 }
1178
ParseIdentifierFormatPlaceholder(std::optional<NodeFormatType> nodeFormat)1179 ir::Identifier *ParserImpl::ParseIdentifierFormatPlaceholder([[maybe_unused]] std::optional<NodeFormatType> nodeFormat)
1180 {
1181 // NOTE(schernykh): add info about LoC
1182 LOG(FATAL, ES2PANDA) << "Format placeholder with identifier is not supported";
1183 return nullptr;
1184 }
1185
ParseStatementFormatPlaceholder()1186 ir::Statement *ParserImpl::ParseStatementFormatPlaceholder()
1187 {
1188 // NOTE(schernykh): add info about LoC
1189 LOG(FATAL, ES2PANDA) << "Statement with format placeholder is not supported";
1190 return nullptr;
1191 }
1192
ParseTypeParametersFormatPlaceholder()1193 ir::AstNode *ParserImpl::ParseTypeParametersFormatPlaceholder()
1194 {
1195 // NOTE(schernykh): add info about LoC
1196 LOG(FATAL, ES2PANDA) << "Format placeholder with type parameter(s) is not supported";
1197 return nullptr;
1198 }
1199
ParseStatementsArrayFormatPlaceholder()1200 ArenaVector<ir::Statement *> &ParserImpl::ParseStatementsArrayFormatPlaceholder()
1201 {
1202 // NOTE(schernykh): add info about LoC
1203 LOG(FATAL, ES2PANDA) << "Format placeholder from statements array is not supported";
1204 ES2PANDA_UNREACHABLE();
1205 }
1206
ParseAstNodesArrayFormatPlaceholder()1207 ArenaVector<ir::AstNode *> &ParserImpl::ParseAstNodesArrayFormatPlaceholder()
1208 {
1209 // NOTE(schernykh): add info about LoC
1210 LOG(FATAL, ES2PANDA) << "Format placeholder from AST nodes is not supported";
1211 ES2PANDA_UNREACHABLE();
1212 }
1213
ParseExpressionsArrayFormatPlaceholder()1214 ArenaVector<ir::Expression *> &ParserImpl::ParseExpressionsArrayFormatPlaceholder()
1215 {
1216 // NOTE(schernykh): add info about LoC
1217 LOG(FATAL, ES2PANDA) << "Format placeholder from expressions array is not supported";
1218 ES2PANDA_UNREACHABLE();
1219 }
1220
ParseSymbolIteratorIdentifier() const1221 util::StringView ParserImpl::ParseSymbolIteratorIdentifier() const noexcept
1222 {
1223 // Duplicate check - just in case of improper call!
1224 if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) {
1225 return util::StringView {};
1226 }
1227
1228 lexer_->NextToken();
1229 if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT || !lexer_->GetToken().Ident().Is("Symbol")) {
1230 return util::StringView {};
1231 }
1232
1233 lexer_->NextToken();
1234 if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_PERIOD) {
1235 return util::StringView {};
1236 }
1237
1238 lexer_->NextToken();
1239 if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT || !lexer_->GetToken().Ident().Is("iterator")) {
1240 return util::StringView {};
1241 }
1242
1243 lexer_->NextToken();
1244 if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) {
1245 return util::StringView {};
1246 }
1247
1248 // Just replace '[Symbol.iterator]` identifier with the standard '$_iterator' name.
1249 return util::StringView {compiler::Signatures::ITERATOR_METHOD};
1250 }
1251
ExpectIdentifier(bool isReference,bool isUserDefinedType,TypeAnnotationParsingOptions options)1252 ir::Identifier *ParserImpl::ExpectIdentifier([[maybe_unused]] bool isReference, bool isUserDefinedType,
1253 TypeAnnotationParsingOptions options)
1254 {
1255 auto const &token = lexer_->GetToken();
1256 auto const tokenType = token.Type();
1257 if (tokenType == lexer::TokenType::PUNCTUATOR_FORMAT) {
1258 if (auto *ident = ParseIdentifierFormatPlaceholder(std::nullopt); ident != nullptr) {
1259 return ident;
1260 }
1261 }
1262
1263 auto const &tokenStart = token.Start();
1264 if (token.IsPredefinedType() && !util::Helpers::IsStdLib(program_) &&
1265 ((options & TypeAnnotationParsingOptions::ADD_TYPE_PARAMETER_BINDING) == 0)) {
1266 LogError(diagnostic::PREDEFINED_TYPE_AS_IDENTIFIER, {token.Ident()}, tokenStart);
1267 lexer_->NextToken();
1268 return AllocBrokenExpression(tokenStart);
1269 }
1270
1271 if (token.IsDefinableTypeName() && isUserDefinedType) {
1272 LogError(diagnostic::NOT_ALLOWED_USER_DEFINED_TYPE);
1273 }
1274
1275 util::StringView tokenName {};
1276
1277 if (tokenType == lexer::TokenType::LITERAL_IDENT) {
1278 tokenName = token.Ident();
1279 } else if (tokenType == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) {
1280 // Special case for processing of special '[Symbol.iterator]` identifier using in stdlib.
1281 tokenName = ParseSymbolIteratorIdentifier();
1282 }
1283
1284 if (tokenName.Empty()) {
1285 if ((options & TypeAnnotationParsingOptions::REPORT_ERROR) == 0) {
1286 return nullptr;
1287 }
1288 LogError(diagnostic::IDENTIFIER_EXPECTED_HERE, {TokenToString(tokenType)}, tokenStart);
1289 lexer_->NextToken();
1290 return AllocBrokenExpression(tokenStart);
1291 }
1292
1293 auto *ident = AllocNode<ir::Identifier>(tokenName, Allocator());
1294 ES2PANDA_ASSERT(ident != nullptr);
1295 // NOTE: here actual token can be changed!
1296 ident->SetRange({tokenStart, lexer_->GetToken().End()});
1297 lexer_->NextToken();
1298 return ident;
1299 }
1300
ExpectToken(lexer::TokenType tokenType,bool consumeToken)1301 void ParserImpl::ExpectToken(lexer::TokenType tokenType, bool consumeToken)
1302 {
1303 auto const &token = lexer_->GetToken();
1304 auto const actualType = token.Type();
1305 if (actualType == tokenType) {
1306 if (consumeToken) {
1307 lexer_->NextToken();
1308 }
1309 return;
1310 }
1311
1312 if (tokenType != lexer::TokenType::LITERAL_IDENT) {
1313 LogError(diagnostic::EXPECTED_PARAM_GOT_PARAM, {TokenToString(tokenType), TokenToString(actualType)});
1314 } else {
1315 LogError(diagnostic::UNEXPECTED_TOKEN_ID);
1316 }
1317
1318 if (!consumeToken) {
1319 return;
1320 }
1321
1322 if (!lexer::Token::IsPunctuatorToken(actualType)) {
1323 return;
1324 }
1325
1326 auto savedPos = lexer_->Save();
1327 lexer_->NextToken();
1328 if (lexer_->GetToken().Type() == tokenType) {
1329 lexer_->NextToken();
1330 return;
1331 }
1332
1333 lexer_->Rewind(savedPos);
1334 }
1335
LogUnexpectedToken(lexer::TokenType tokenType)1336 void ParserImpl::LogUnexpectedToken(lexer::TokenType tokenType)
1337 {
1338 LogError(diagnostic::UNEXPECTED_TOKEN_PARAM, {TokenToString(tokenType)});
1339 }
1340
LogUnexpectedToken(lexer::Token const & token)1341 void ParserImpl::LogUnexpectedToken(lexer::Token const &token)
1342 {
1343 if (token.ToString() != ERROR_LITERAL) {
1344 LogError(diagnostic::UNEXPECTED_TOKEN_PARAM, {token.ToString()});
1345 }
1346 }
1347
LogExpectedToken(lexer::TokenType tokenType)1348 void ParserImpl::LogExpectedToken(lexer::TokenType tokenType)
1349 {
1350 if (tokenType != lexer::TokenType::LITERAL_IDENT && tokenType != lexer::TokenType::LITERAL_STRING) {
1351 LogError(diagnostic::UNEXPECTED_TOKEN_EXPECTED_PARAM, {TokenToString(tokenType)});
1352 } else if (tokenType == lexer::TokenType::LITERAL_IDENT) {
1353 LogError(diagnostic::UNEXPECTED_TOKEN_ID);
1354 lexer_->GetToken().SetTokenStr(ERROR_LITERAL);
1355 } else if (tokenType == lexer::TokenType::LITERAL_STRING) {
1356 LogError(diagnostic::UNEXPECTED_TOKEN_STRING_LITERAL);
1357 lexer_->GetToken().SetTokenStr(ERROR_LITERAL);
1358 }
1359 lexer_->GetToken().SetTokenType(tokenType);
1360 }
1361
LogSyntaxError(std::string_view errorMessage,const lexer::SourcePosition & pos)1362 void ParserImpl::LogSyntaxError(std::string_view errorMessage, const lexer::SourcePosition &pos)
1363 {
1364 diagnosticEngine_.LogSyntaxError(errorMessage, pos);
1365 }
1366
LogSyntaxError(std::string_view const errorMessage)1367 void ParserImpl::LogSyntaxError(std::string_view const errorMessage)
1368 {
1369 diagnosticEngine_.LogSyntaxError(errorMessage, lexer_->GetToken().Start());
1370 }
1371
LogSyntaxError(const util::DiagnosticMessageParams & list)1372 void ParserImpl::LogSyntaxError(const util::DiagnosticMessageParams &list)
1373 {
1374 diagnosticEngine_.LogSyntaxError(list, lexer_->GetToken().Start());
1375 }
1376
LogSyntaxError(const util::DiagnosticMessageParams & list,const lexer::SourcePosition & pos)1377 void ParserImpl::LogSyntaxError(const util::DiagnosticMessageParams &list, const lexer::SourcePosition &pos)
1378 {
1379 diagnosticEngine_.LogSyntaxError(list, pos);
1380 }
1381
LogError(const diagnostic::DiagnosticKind & diagnostic,const util::DiagnosticMessageParams & diagnosticParams,const lexer::SourcePosition & pos)1382 void ParserImpl::LogError(const diagnostic::DiagnosticKind &diagnostic,
1383 const util::DiagnosticMessageParams &diagnosticParams, const lexer::SourcePosition &pos)
1384 {
1385 diagnosticEngine_.LogDiagnostic(diagnostic, diagnosticParams, pos);
1386 }
1387
LogError(const diagnostic::DiagnosticKind & diagnostic,const util::DiagnosticMessageParams & diagnosticParams)1388 void ParserImpl::LogError(const diagnostic::DiagnosticKind &diagnostic,
1389 const util::DiagnosticMessageParams &diagnosticParams)
1390 {
1391 LogError(diagnostic, diagnosticParams, lexer_->GetToken().Start());
1392 }
1393
GetPositionForDiagnostic() const1394 lexer::SourcePosition ParserImpl::GetPositionForDiagnostic() const
1395 {
1396 return Lexer()->GetToken().Start();
1397 }
1398
CheckModuleAsModifier()1399 bool ParserImpl::CheckModuleAsModifier()
1400 {
1401 if (lexer_->GetToken().KeywordType() != lexer::TokenType::KEYW_AS) {
1402 return false;
1403 }
1404
1405 if ((lexer_->GetToken().Flags() & lexer::TokenFlags::HAS_ESCAPE) != 0U) {
1406 LogError(diagnostic::ESCAPE_SEQUENCES_IN_AS);
1407 }
1408
1409 return true;
1410 }
1411
ParseList(std::optional<lexer::TokenType> termToken,lexer::NextTokenFlags flags,const std::function<bool ()> & parseElement,lexer::SourcePosition * sourceEnd,bool allowTrailingSep)1412 bool ParserImpl::ParseList(std::optional<lexer::TokenType> termToken, lexer::NextTokenFlags flags,
1413 const std::function<bool()> &parseElement, lexer::SourcePosition *sourceEnd,
1414 bool allowTrailingSep)
1415 {
1416 bool success = true;
1417 auto sep = lexer::TokenType::PUNCTUATOR_COMMA;
1418 while (Lexer()->GetToken().Type() != termToken && Lexer()->GetToken().Type() != lexer::TokenType::EOS) {
1419 // ErrorRecursionGuard is not feasible because we can break without consuming any tokens
1420 auto savedPos = lexer_->Save();
1421 auto elemSuccess = parseElement();
1422 bool hasSep = false;
1423 if (Lexer()->GetToken().Type() == sep) {
1424 Lexer()->NextToken(flags);
1425 hasSep = true;
1426 }
1427 if (!elemSuccess) {
1428 // list element is invalid
1429 success = false;
1430 if (savedPos == lexer_->Save()) {
1431 lexer_->NextToken();
1432 }
1433 continue;
1434 }
1435 if (termToken == Lexer()->GetToken().Type() || (!termToken.has_value() && !hasSep)) {
1436 if (hasSep && !allowTrailingSep) {
1437 LogError(diagnostic::TRAILING_COMMA_NOT_ALLOWED);
1438 }
1439 break;
1440 }
1441 if (hasSep) {
1442 continue;
1443 }
1444 if (termToken.has_value()) {
1445 LogError(diagnostic::UNEXPECTED_TOKEN_EXPECTED_PARAM_OR_PARAM,
1446 {lexer::TokenToString(sep), lexer::TokenToString(termToken.value())});
1447 } else {
1448 LogExpectedToken(sep);
1449 }
1450 // comma or terminator not found
1451 return false;
1452 }
1453 if (termToken) {
1454 if (sourceEnd != nullptr) {
1455 *sourceEnd = Lexer()->GetToken().End();
1456 }
1457 ExpectToken(termToken.value());
1458 }
1459 return success;
1460 }
1461
AllocBrokenExpression(const lexer::SourcePosition & pos)1462 ir::Identifier *ParserImpl::AllocBrokenExpression(const lexer::SourcePosition &pos)
1463 {
1464 return AllocBrokenExpression({pos, pos});
1465 }
1466
AllocBrokenExpression(const lexer::SourceRange & range)1467 ir::Identifier *ParserImpl::AllocBrokenExpression(const lexer::SourceRange &range)
1468 {
1469 auto *node = AllocNode<ir::Identifier>(Allocator());
1470 ES2PANDA_ASSERT(node != nullptr);
1471 node->SetRange(range);
1472 return node;
1473 }
1474
AllocBrokenType(const lexer::SourcePosition & pos)1475 ir::TypeNode *ParserImpl::AllocBrokenType(const lexer::SourcePosition &pos)
1476 {
1477 return AllocBrokenType({pos, pos});
1478 }
1479
AllocBrokenType(const lexer::SourceRange & range)1480 ir::TypeNode *ParserImpl::AllocBrokenType(const lexer::SourceRange &range)
1481 {
1482 auto node = AllocNode<ir::BrokenTypeNode>(Allocator());
1483 ES2PANDA_ASSERT(node != nullptr);
1484 node->SetRange(range);
1485 return node;
1486 }
1487
1488 } // namespace ark::es2panda::parser
1489