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 "parserImpl.h"
17#include "parserStatusContext.h"
18
19#include "varbinder/privateBinding.h"
20#include "ir/astNode.h"
21#include "ir/base/classDefinition.h"
22#include "ir/base/classProperty.h"
23#include "ir/base/classStaticBlock.h"
24#include "ir/base/methodDefinition.h"
25#include "ir/base/scriptFunction.h"
26#include "ir/base/spreadElement.h"
27#include "ir/expression.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/identifier.h"
33#include "ir/expressions/literals/bigIntLiteral.h"
34#include "ir/expressions/literals/numberLiteral.h"
35#include "ir/expressions/literals/stringLiteral.h"
36#include "ir/expressions/objectExpression.h"
37#include "ir/expressions/superExpression.h"
38#include "ir/module/exportNamedDeclaration.h"
39#include "ir/module/exportSpecifier.h"
40#include "ir/statements/blockStatement.h"
41#include "ir/statements/expressionStatement.h"
42#include "ir/statements/functionDeclaration.h"
43#include "lexer/lexer.h"
44#include "lexer/token/letters.h"
45#include "lexer/token/sourceLocation.h"
46
47using namespace std::literals::string_literals;
48
49namespace ark::es2panda::parser {
50ParserImpl::ParserImpl(Program *program, const CompilerOptions &options, ParserStatus status)
51    : program_(program), context_(program_, status), options_(options)
52{
53}
54
55std::unique_ptr<lexer::Lexer> ParserImpl::InitLexer(const SourceFile &sourceFile)
56{
57    program_->SetSource(sourceFile);
58    std::unique_ptr<lexer::Lexer> lexer = std::make_unique<lexer::Lexer>(&context_);
59    lexer_ = lexer.get();
60    return lexer;
61}
62
63void ParserImpl::ParseScript(const SourceFile &sourceFile, bool genStdLib)
64{
65    auto lexer = InitLexer(sourceFile);
66
67    if (sourceFile.isModule) {
68        context_.Status() |= (ParserStatus::MODULE);
69        ParseProgram(ScriptKind::MODULE);
70    } else if (genStdLib) {
71        ParseProgram(ScriptKind::STDLIB);
72    } else {
73        ParseProgram(ScriptKind::SCRIPT);
74    }
75}
76
77void ParserImpl::ParseProgram(ScriptKind kind)
78{
79    lexer::SourcePosition startLoc = lexer_->GetToken().Start();
80    lexer_->NextToken();
81    program_->SetKind(kind);
82
83    auto statements = ParseStatementList(StatementParsingFlags::STMT_GLOBAL_LEXICAL);
84
85    auto *blockStmt = AllocNode<ir::BlockStatement>(Allocator(), std::move(statements));
86    blockStmt->SetRange({startLoc, lexer_->GetToken().End()});
87
88    program_->SetAst(blockStmt);
89    program_->SetDeclarationModuleInfo();
90}
91
92bool ParserImpl::InAmbientContext()
93{
94    return (context_.Status() & ParserStatus::IN_AMBIENT_CONTEXT) != 0;
95}
96
97ExpressionParseFlags ParserImpl::CarryExpressionParserFlag(ExpressionParseFlags origin, ExpressionParseFlags carry)
98{
99    return static_cast<ExpressionParseFlags>(origin & carry);
100}
101
102ExpressionParseFlags ParserImpl::CarryPatternFlags(ExpressionParseFlags flags)
103{
104    return CarryExpressionParserFlag(flags, ExpressionParseFlags::POTENTIALLY_IN_PATTERN |
105                                                ExpressionParseFlags::OBJECT_PATTERN);
106}
107
108ir::ModifierFlags ParserImpl::GetAccessability(ir::ModifierFlags modifiers)
109{
110    if ((modifiers & ir::ModifierFlags::PUBLIC) != 0) {
111        return ir::ModifierFlags::PUBLIC;
112    }
113
114    if ((modifiers & ir::ModifierFlags::PRIVATE) != 0) {
115        return ir::ModifierFlags::PRIVATE;
116    }
117
118    if ((modifiers & ir::ModifierFlags::PROTECTED) != 0) {
119        return ir::ModifierFlags::PROTECTED;
120    }
121
122    if ((modifiers & ir::ModifierFlags::INTERNAL) != 0) {
123        return ir::ModifierFlags::INTERNAL;
124    }
125
126    return ir::ModifierFlags::NONE;
127}
128
129bool ParserImpl::IsModifierKind(const lexer::Token &token)
130{
131    switch (token.KeywordType()) {
132        case lexer::TokenType::KEYW_STATIC:
133        case lexer::TokenType::KEYW_ASYNC:
134            return true;
135        default:
136            break;
137    }
138
139    return false;
140}
141
142ir::ModifierFlags ParserImpl::ParseModifiers()
143{
144    ir::ModifierFlags resultStatus = ir::ModifierFlags::NONE;
145    ir::ModifierFlags prevStatus = ir::ModifierFlags::ALL;
146
147    while (IsModifierKind(lexer_->GetToken())) {
148        char32_t nextCp = lexer_->Lookahead();
149        if (nextCp == lexer::LEX_CHAR_LEFT_PAREN) {
150            return resultStatus;
151        }
152
153        lexer::TokenFlags tokenFlags = lexer_->GetToken().Flags();
154        if ((tokenFlags & lexer::TokenFlags::HAS_ESCAPE) != 0) {
155            ThrowSyntaxError("Keyword must not contain escaped characters");
156        }
157
158        ir::ModifierFlags actualStatus = ir::ModifierFlags::NONE;
159        ir::ModifierFlags nextStatus = ir::ModifierFlags::NONE;
160
161        switch (lexer_->GetToken().KeywordType()) {
162            case lexer::TokenType::KEYW_STATIC: {
163                actualStatus = ir::ModifierFlags::STATIC;
164                nextStatus = ir::ModifierFlags::ASYNC;
165                break;
166            }
167            case lexer::TokenType::KEYW_ASYNC: {
168                actualStatus = ir::ModifierFlags::ASYNC;
169                nextStatus = ir::ModifierFlags::NONE;
170                break;
171            }
172            default: {
173                break;
174            }
175        }
176
177        if (lexer_->Lookahead() == lexer::LEX_CHAR_COLON || lexer_->Lookahead() == lexer::LEX_CHAR_COMMA ||
178            lexer_->Lookahead() == lexer::LEX_CHAR_RIGHT_PAREN || lexer_->Lookahead() == lexer::LEX_CHAR_QUESTION ||
179            lexer_->Lookahead() == lexer::LEX_CHAR_RIGHT_BRACE || lexer_->Lookahead() == lexer::LEX_CHAR_LESS_THAN) {
180            break;
181        }
182
183        auto pos = lexer_->Save();
184        lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
185
186        if ((prevStatus & actualStatus) == 0) {
187            lexer_->Rewind(pos);
188            ThrowSyntaxError("Unexpected modifier");
189        }
190
191        if ((resultStatus & actualStatus) != 0) {
192            lexer_->Rewind(pos);
193            ThrowSyntaxError("Duplicated modifier is not allowed");
194        }
195
196        resultStatus |= actualStatus;
197        prevStatus = nextStatus;
198    }
199
200    return resultStatus;
201}
202
203void ParserImpl::CheckAccessorPair(const ArenaVector<ir::AstNode *> &properties, const ir::Expression *propName,
204                                   ir::MethodDefinitionKind methodKind, ir::ModifierFlags access)
205{
206    for (const auto &it : properties) {
207        if (!it->IsMethodDefinition() || it->AsMethodDefinition()->Kind() != methodKind) {
208            continue;
209        }
210
211        const ir::Expression *key = it->AsMethodDefinition()->Key();
212
213        if (key->Type() != propName->Type()) {
214            continue;
215        }
216
217        bool keyIsSame = false;
218
219        if (key->IsIdentifier()) {
220            const util::StringView &strName = propName->AsIdentifier()->Name();
221            const util::StringView &compareName = (key->AsIdentifier()->Name());
222
223            keyIsSame = strName == compareName;
224        } else if (key->IsNumberLiteral()) {
225            keyIsSame =
226                key->AsNumberLiteral()->Number().GetDouble() == propName->AsNumberLiteral()->Number().GetDouble();
227        } else if (key->IsStringLiteral()) {
228            keyIsSame = *key->AsStringLiteral() == *propName->AsStringLiteral();
229        }
230
231        if (!keyIsSame) {
232            continue;
233        }
234
235        ir::ModifierFlags getAccess;
236        ir::ModifierFlags setAccess;
237
238        if (methodKind == ir::MethodDefinitionKind::GET) {
239            setAccess = access;
240            getAccess = GetAccessability(it->Modifiers());
241        } else {
242            getAccess = access;
243            setAccess = GetAccessability(it->Modifiers());
244        }
245
246        if ((setAccess == ir::ModifierFlags::NONE && getAccess > ir::ModifierFlags::PUBLIC) ||
247            (setAccess != ir::ModifierFlags::NONE && getAccess > setAccess)) {
248            ThrowSyntaxError("A get accessor must be at least as accessible as the setter", key->Start());
249        }
250    }
251}
252
253void ParserImpl::ParseClassAccessor(ClassElementDescriptor *desc, char32_t *nextCp)
254{
255    ConsumeClassPrivateIdentifier(desc, nextCp);
256
257    if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
258        return;
259    }
260
261    auto keywordType = lexer_->GetToken().KeywordType();
262    if ((keywordType != lexer::TokenType::KEYW_GET && keywordType != lexer::TokenType::KEYW_SET) ||
263        (*nextCp == lexer::LEX_CHAR_EQUALS || *nextCp == lexer::LEX_CHAR_SEMICOLON ||
264         *nextCp == lexer::LEX_CHAR_LEFT_PAREN || *nextCp == lexer::LEX_CHAR_COLON ||
265         *nextCp == lexer::LEX_CHAR_LESS_THAN)) {
266        return;
267    }
268
269    ThrowIfPrivateIdent(desc, "Unexpected identifier");
270
271    if ((lexer_->GetToken().Flags() & lexer::TokenFlags::HAS_ESCAPE) != 0) {
272        ThrowSyntaxError("Keyword must not contain escaped characters");
273    }
274
275    desc->methodKind =
276        keywordType == lexer::TokenType::KEYW_GET ? ir::MethodDefinitionKind::GET : ir::MethodDefinitionKind::SET;
277    desc->methodStart = lexer_->GetToken().Start();
278
279    lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
280    ConsumeClassPrivateIdentifier(desc, nextCp);
281}
282
283void ParserImpl::ThrowIfPrivateIdent(ClassElementDescriptor *desc, const char *msg)
284{
285    if (desc->isPrivateIdent) {
286        ThrowSyntaxError(msg);
287    }
288}
289
290void ParserImpl::ThrowErrorIfStaticConstructor([[maybe_unused]] ir::ModifierFlags flags) {}
291
292void ParserImpl::ValidateClassKey(ClassElementDescriptor *desc)
293{
294    if (((desc->modifiers & ir::ModifierFlags::ASYNC) != 0 || desc->isGenerator) &&
295        (desc->methodKind == ir::MethodDefinitionKind::GET || desc->methodKind == ir::MethodDefinitionKind::SET)) {
296        ThrowSyntaxError("Invalid accessor");
297    }
298
299    const util::StringView &propNameStr = lexer_->GetToken().Ident();
300
301    if (propNameStr.Is("constructor")) {
302        if (lexer_->Lookahead() != lexer::LEX_CHAR_LEFT_PAREN) {
303            ThrowSyntaxError("Classes may not have a field named 'constructor'");
304        }
305
306        ThrowIfPrivateIdent(desc, "Private identifier can not be constructor");
307
308        if ((desc->modifiers & ir::ModifierFlags::STATIC) == 0) {
309            if ((desc->modifiers & ir::ModifierFlags::ASYNC) != 0 ||
310                desc->methodKind == ir::MethodDefinitionKind::GET ||
311                desc->methodKind == ir::MethodDefinitionKind::SET || desc->isGenerator) {
312                ThrowSyntaxError("Constructor can not be special method");
313            }
314
315            desc->methodKind = ir::MethodDefinitionKind::CONSTRUCTOR;
316            desc->methodStart = lexer_->GetToken().Start();
317            desc->newStatus |= ParserStatus::CONSTRUCTOR_FUNCTION;
318
319            if (desc->hasSuperClass) {
320                desc->newStatus |= ParserStatus::ALLOW_SUPER_CALL;
321            }
322        }
323
324        ThrowErrorIfStaticConstructor(desc->modifiers);
325    } else if (propNameStr.Is("prototype") && (desc->modifiers & ir::ModifierFlags::STATIC) != 0) {
326        ThrowSyntaxError("Classes may not have static property named prototype");
327    }
328}
329
330std::tuple<bool, bool, bool> ParserImpl::ParseComputedClassFieldOrIndexSignature(ir::Expression **propName)
331{
332    lexer_->NextToken();  // eat left square bracket
333
334    *propName = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA);
335
336    if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) {
337        ThrowSyntaxError("Unexpected token, expected ']'");
338    }
339
340    return {true, false, false};
341}
342
343ir::Expression *ParserImpl::ParseClassKey(ClassElementDescriptor *desc)
344{
345    ir::Expression *propName = nullptr;
346    if (lexer_->GetToken().IsKeyword()) {
347        lexer_->GetToken().SetTokenType(lexer::TokenType::LITERAL_IDENT);
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            propName->SetRange(lexer_->GetToken().Loc());
356            propName->AsIdentifier()->SetPrivate(desc->isPrivateIdent);
357            break;
358        }
359        case lexer::TokenType::LITERAL_STRING: {
360            ThrowIfPrivateIdent(desc, "Private identifier name can not be string");
361
362            if (lexer_->GetToken().Ident().Is("constructor")) {
363                ThrowSyntaxError("Classes may not have a field named 'constructor'");
364            }
365
366            if (lexer_->GetToken().Ident().Is("prototype") && (desc->modifiers & ir::ModifierFlags::STATIC) != 0) {
367                ThrowSyntaxError("Classes may not have a static property named 'prototype'");
368            }
369
370            propName = AllocNode<ir::StringLiteral>(lexer_->GetToken().String());
371            propName->SetRange(lexer_->GetToken().Loc());
372            break;
373        }
374        case lexer::TokenType::LITERAL_NUMBER: {
375            ThrowIfPrivateIdent(desc, "Private identifier name can not be number");
376
377            if ((lexer_->GetToken().Flags() & lexer::TokenFlags::NUMBER_BIGINT) != 0) {
378                propName = AllocNode<ir::BigIntLiteral>(lexer_->GetToken().BigInt());
379            } else {
380                propName = AllocNode<ir::NumberLiteral>(lexer_->GetToken().GetNumber());
381            }
382
383            propName->SetRange(lexer_->GetToken().Loc());
384            break;
385        }
386        case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: {
387            ThrowIfPrivateIdent(desc, "Unexpected character in private identifier");
388            std::tie(desc->isComputed, desc->invalidComputedProperty, desc->isIndexSignature) =
389                ParseComputedClassFieldOrIndexSignature(&propName);
390            break;
391        }
392        default: {
393            ThrowSyntaxError("Unexpected token in class property");
394        }
395    }
396
397    lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
398
399    return propName;
400}
401
402void ParserImpl::ValidateClassMethodStart(ClassElementDescriptor *desc, [[maybe_unused]] ir::TypeNode *typeAnnotation)
403{
404    if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) {
405        return;
406    }
407    desc->classMethod = true;
408
409    if ((desc->modifiers & ir::ModifierFlags::ASYNC) != 0) {
410        desc->newStatus |= ParserStatus::ASYNC_FUNCTION;
411    }
412
413    if (desc->isGenerator) {
414        desc->newStatus |= ParserStatus::GENERATOR_FUNCTION;
415    }
416}
417
418void ParserImpl::ValidateClassSetter([[maybe_unused]] ClassElementDescriptor *desc,
419                                     [[maybe_unused]] const ArenaVector<ir::AstNode *> &properties,
420                                     [[maybe_unused]] ir::Expression *propName, ir::ScriptFunction *func)
421{
422    if (func->Params().size() != 1) {
423        ThrowSyntaxError("Setter must have exactly one formal parameter");
424    }
425}
426
427void ParserImpl::ValidateClassGetter([[maybe_unused]] ClassElementDescriptor *desc,
428                                     [[maybe_unused]] const ArenaVector<ir::AstNode *> &properties,
429                                     [[maybe_unused]] ir::Expression *propName, ir::ScriptFunction *func)
430{
431    if (!func->Params().empty()) {
432        ThrowSyntaxError("Getter must not have formal parameters");
433    }
434}
435
436ir::MethodDefinition *ParserImpl::ParseClassMethod(ClassElementDescriptor *desc,
437                                                   const ArenaVector<ir::AstNode *> &properties,
438                                                   ir::Expression *propName, lexer::SourcePosition *propEnd)
439{
440    if (desc->methodKind != ir::MethodDefinitionKind::SET &&
441        (desc->newStatus & ParserStatus::CONSTRUCTOR_FUNCTION) == 0) {
442        desc->newStatus |= ParserStatus::NEED_RETURN_TYPE;
443    }
444
445    ir::ScriptFunction *func = ParseFunction(desc->newStatus);
446
447    auto *funcExpr = AllocNode<ir::FunctionExpression>(func);
448    funcExpr->SetRange(func->Range());
449
450    if (desc->methodKind == ir::MethodDefinitionKind::SET) {
451        ValidateClassSetter(desc, properties, propName, func);
452    } else if (desc->methodKind == ir::MethodDefinitionKind::GET) {
453        ValidateClassGetter(desc, properties, propName, func);
454    }
455
456    *propEnd = func->End();
457    func->AddFlag(ir::ScriptFunctionFlags::METHOD);
458
459    auto *ident = !propName->IsArrowFunctionExpression() && !propName->IsFunctionExpression()
460                      ? propName->Clone(Allocator(), nullptr)->AsExpression()
461                      : propName;
462    auto *method = AllocNode<ir::MethodDefinition>(desc->methodKind, ident, funcExpr, desc->modifiers, Allocator(),
463                                                   desc->isComputed);
464    method->SetRange(funcExpr->Range());
465
466    return method;
467}
468
469ir::ClassElement *ParserImpl::ParseClassProperty(ClassElementDescriptor *desc,
470                                                 const ArenaVector<ir::AstNode *> &properties, ir::Expression *propName,
471                                                 ir::TypeNode *typeAnnotation)
472{
473    lexer::SourcePosition propEnd = propName->End();
474    ir::ClassElement *property = nullptr;
475
476    if (desc->classMethod) {
477        if ((desc->modifiers & ir::ModifierFlags::DECLARE) != 0) {
478            ThrowSyntaxError("'declare modifier cannot appear on class elements of this kind.");
479        }
480
481        property = ParseClassMethod(desc, properties, propName, &propEnd);
482        property->SetRange({desc->propStart, propEnd});
483        return property;
484    }
485
486    ir::Expression *value = nullptr;
487
488    if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
489        lexer_->NextToken();  // eat equals
490
491        if (InAmbientContext() || (desc->modifiers & ir::ModifierFlags::DECLARE) != 0) {
492            ThrowSyntaxError("Initializers are not allowed in ambient contexts.");
493        }
494
495        value = ParseExpression();
496        propEnd = value->End();
497    }
498
499    property =
500        AllocNode<ir::ClassProperty>(propName, value, typeAnnotation, desc->modifiers, Allocator(), desc->isComputed);
501
502    property->SetRange({desc->propStart, propEnd});
503
504    return property;
505}
506
507void ParserImpl::CheckClassGeneratorMethod(ClassElementDescriptor *desc, char32_t *nextCp)
508{
509    if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_MULTIPLY) {
510        return;
511    }
512
513    desc->isGenerator = true;
514    lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
515    *nextCp = lexer_->Lookahead();
516}
517
518void ParserImpl::ValidatePrivateIdentifier()
519{
520    size_t iterIdx = lexer_->GetToken().Start().index;
521    lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
522
523    if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT ||
524        (lexer_->GetToken().Start().index - iterIdx > 1)) {
525        ThrowSyntaxError("Unexpected token in private field");
526    }
527}
528
529void ParserImpl::ConsumeClassPrivateIdentifier(ClassElementDescriptor *desc, char32_t *nextCp)
530{
531    if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_HASH_MARK) {
532        return;
533    }
534
535    desc->isPrivateIdent = true;
536    ValidatePrivateIdentifier();
537    *nextCp = lexer_->Lookahead();
538}
539
540void ParserImpl::AddPrivateElement(const ir::ClassElement *elem)
541{
542    if (!classPrivateContext_.AddElement(elem)) {
543        ThrowSyntaxError("Private field has already been declared");
544    }
545}
546
547ir::ClassElement *ParserImpl::ParseClassStaticBlock()
548{
549    const lexer::SourcePosition &startPos = lexer_->GetToken().Start();
550
551    lexer_->NextToken();  // eat 'static'
552
553    SavedParserContext context(this, ParserStatus::ALLOW_SUPER);
554    context_.Status() &= ~(ParserStatus::ASYNC_FUNCTION | ParserStatus::GENERATOR_FUNCTION);
555
556    lexer_->NextToken();  // eat '{'
557
558    ArenaVector<ir::Expression *> params(Allocator()->Adapter());
559
560    ArenaVector<ir::Statement *> statements = ParseStatementList();
561
562    if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) {
563        ThrowSyntaxError("Expected a '}'");
564    }
565
566    auto *body = AllocNode<ir::BlockStatement>(Allocator(), std::move(statements));
567    // clang-format off
568    auto *func = AllocNode<ir::ScriptFunction>(
569        Allocator(), ir::ScriptFunction::ScriptFunctionData {
570            body, ir::FunctionSignature(nullptr, std::move(params), nullptr),
571            ir::ScriptFunctionFlags::EXPRESSION | ir::ScriptFunctionFlags::STATIC_BLOCK,
572            ir::ModifierFlags::STATIC, false, context_.GetLanguage()});
573    // clang-format on
574
575    auto *funcExpr = AllocNode<ir::FunctionExpression>(func);
576    auto *staticBlock = AllocNode<ir::ClassStaticBlock>(funcExpr, Allocator());
577    staticBlock->SetRange({startPos, lexer_->GetToken().End()});
578
579    lexer_->NextToken();  // eat '}'
580
581    return staticBlock;
582}
583
584ir::AstNode *ParserImpl::ParseClassElement(const ArenaVector<ir::AstNode *> &properties,
585                                           ir::ClassDefinitionModifiers modifiers,
586                                           [[maybe_unused]] ir::ModifierFlags flags)
587{
588    if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_STATIC &&
589        lexer_->Lookahead() == lexer::LEX_CHAR_LEFT_BRACE) {
590        return ParseClassStaticBlock();
591    }
592
593    ClassElementDescriptor desc(Allocator());
594
595    desc.methodKind = ir::MethodDefinitionKind::METHOD;
596    desc.newStatus = ParserStatus::ALLOW_SUPER;
597    desc.hasSuperClass = (modifiers & ir::ClassDefinitionModifiers::HAS_SUPER) != 0U;
598    desc.propStart = lexer_->GetToken().Start();
599    desc.modifiers = ParseModifiers();
600
601    char32_t nextCp = lexer_->Lookahead();
602    CheckClassGeneratorMethod(&desc, &nextCp);
603    ParseClassAccessor(&desc, &nextCp);
604
605    if ((desc.modifiers & ir::ModifierFlags::STATIC) == 0) {
606        context_.Status() |= ParserStatus::ALLOW_THIS_TYPE;
607    }
608
609    ir::Expression *propName = ParseClassKey(&desc);
610    ValidateClassMethodStart(&desc, nullptr);
611    ir::ClassElement *property = ParseClassProperty(&desc, properties, propName, nullptr);
612
613    if (property != nullptr && lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SEMI_COLON &&
614        lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE &&
615        (lexer_->GetToken().Flags() & lexer::TokenFlags::NEW_LINE) == 0 &&
616        !(property->IsMethodDefinition() &&
617          property->AsMethodDefinition()->Value()->AsFunctionExpression()->Function()->Body() != nullptr)) {
618        ThrowSyntaxError("';' expected.");
619    }
620
621    if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) {
622        lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
623    }
624
625    context_.Status() &= ~ParserStatus::ALLOW_THIS_TYPE;
626
627    if (desc.isPrivateIdent) {
628        AddPrivateElement(property);
629    }
630
631    return property;
632}
633
634ir::MethodDefinition *ParserImpl::BuildImplicitConstructor(ir::ClassDefinitionModifiers modifiers,
635                                                           const lexer::SourcePosition &startLoc)
636{
637    ArenaVector<ir::Expression *> params(Allocator()->Adapter());
638    ArenaVector<ir::Statement *> statements(Allocator()->Adapter());
639
640    if ((modifiers & ir::ClassDefinitionModifiers::HAS_SUPER) != 0U) {
641        util::StringView argsStr = "args";
642        params.push_back(AllocNode<ir::SpreadElement>(ir::AstNodeType::REST_ELEMENT, Allocator(),
643                                                      AllocNode<ir::Identifier>(argsStr, Allocator())));
644        ArenaVector<ir::Expression *> callArgs(Allocator()->Adapter());
645        auto *superExpr = AllocNode<ir::SuperExpression>();
646        callArgs.push_back(AllocNode<ir::SpreadElement>(ir::AstNodeType::SPREAD_ELEMENT, Allocator(),
647                                                        AllocNode<ir::Identifier>(argsStr, Allocator())));
648
649        auto *callExpr = AllocNode<ir::CallExpression>(superExpr, std::move(callArgs), nullptr, false);
650        statements.push_back(AllocNode<ir::ExpressionStatement>(callExpr));
651    }
652
653    auto *body = AllocNode<ir::BlockStatement>(Allocator(), std::move(statements));
654    auto *func = AllocNode<ir::ScriptFunction>(
655        Allocator(), ir::ScriptFunction::ScriptFunctionData {body,
656                                                             ir::FunctionSignature(nullptr, std::move(params), nullptr),
657                                                             ir::ScriptFunctionFlags::CONSTRUCTOR |
658                                                                 ir::ScriptFunctionFlags::IMPLICIT_SUPER_CALL_NEEDED,
659                                                             {},
660                                                             false,
661                                                             context_.GetLanguage()});
662
663    auto *funcExpr = AllocNode<ir::FunctionExpression>(func);
664    auto *key = AllocNode<ir::Identifier>("constructor", Allocator());
665
666    if ((modifiers & ir::ClassDefinitionModifiers::SET_CTOR_ID) != 0U) {
667        func->SetIdent(key->Clone(Allocator(), nullptr));
668    }
669
670    auto *ctor = AllocNode<ir::MethodDefinition>(ir::MethodDefinitionKind::CONSTRUCTOR, key, funcExpr,
671                                                 ir::ModifierFlags::NONE, Allocator(), false);
672
673    ctor->SetRange({startLoc, lexer_->GetToken().End()});
674
675    return ctor;
676}
677
678void ParserImpl::CreateImplicitConstructor(ir::MethodDefinition *&ctor,
679                                           [[maybe_unused]] ArenaVector<ir::AstNode *> &properties,
680                                           ir::ClassDefinitionModifiers modifiers,
681                                           const lexer::SourcePosition &startLoc)
682{
683    if (ctor != nullptr) {
684        return;
685    }
686
687    ctor = BuildImplicitConstructor(modifiers, startLoc);
688}
689
690ir::Identifier *ParserImpl::ParseClassIdent(ir::ClassDefinitionModifiers modifiers)
691{
692    if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) {
693        return ExpectIdentifier();
694    }
695
696    auto idRequired =
697        static_cast<ir::ClassDefinitionModifiers>(modifiers & ir::ClassDefinitionModifiers::DECLARATION_ID_REQUIRED);
698
699    if (idRequired == ir::ClassDefinitionModifiers::DECLARATION_ID_REQUIRED) {
700        ThrowSyntaxError("Unexpected token, expected an identifier.");
701    }
702
703    return nullptr;
704}
705
706bool ParserImpl::CheckClassElement(ir::AstNode *property, ir::MethodDefinition *&ctor,
707                                   [[maybe_unused]] ArenaVector<ir::AstNode *> &properties)
708{
709    if (!property->IsMethodDefinition()) {
710        return false;
711    }
712
713    ir::MethodDefinition *def = property->AsMethodDefinition();
714    if (!def->IsConstructor()) {
715        return false;
716    }
717
718    if (ctor != nullptr) {
719        ThrowSyntaxError("Multiple constructor implementations are not allowed.", property->Start());
720    }
721    ctor = def;
722
723    return true;
724}
725
726ir::Expression *ParserImpl::ParseSuperClassReference()
727{
728    if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_EXTENDS) {
729        lexer_->NextToken();
730        return ParseLeftHandSideExpression();
731    }
732
733    return nullptr;
734}
735
736std::tuple<ir::Expression *, ir::TSTypeParameterInstantiation *> ParserImpl::ParseSuperClass()
737{
738    return {ParseSuperClassReference(), nullptr};
739}
740
741// NOLINTNEXTLINE(google-default-arguments)
742ir::ClassDefinition *ParserImpl::ParseClassDefinition(ir::ClassDefinitionModifiers modifiers, ir::ModifierFlags flags)
743{
744    lexer_->NextToken();
745
746    ir::Identifier *identNode = ParseClassIdent(modifiers);
747
748    if (identNode == nullptr && (modifiers & ir::ClassDefinitionModifiers::DECLARATION) != 0U) {
749        ThrowSyntaxError("Unexpected token, expected an identifier.");
750    }
751
752    varbinder::PrivateBinding privateBinding(Allocator(), classId_++);
753
754    // Parse SuperClass
755    auto [superClass, superTypeParams] = ParseSuperClass();
756
757    if (superClass != nullptr) {
758        modifiers |= ir::ClassDefinitionModifiers::HAS_SUPER;
759    }
760
761    ExpectToken(lexer::TokenType::PUNCTUATOR_LEFT_BRACE, false);
762
763    auto [ctor, properties, bodyRange] = ParseClassBody(modifiers, flags);
764
765    ArenaVector<ir::TSClassImplements *> implements(Allocator()->Adapter());
766    auto *classDefinition = AllocNode<ir::ClassDefinition>(
767        privateBinding.View(), identNode, nullptr, superTypeParams, std::move(implements), ctor, superClass,
768        std::move(properties), modifiers, flags, GetContext().GetLanguage());
769
770    classDefinition->SetRange(bodyRange);
771
772    return classDefinition;
773}
774
775ParserImpl::ClassBody ParserImpl::ParseClassBody(ir::ClassDefinitionModifiers modifiers, ir::ModifierFlags flags)
776{
777    auto savedCtx = SavedStatusContext<ParserStatus::IN_CLASS_BODY>(&context_);
778
779    lexer::SourcePosition startLoc = lexer_->GetToken().Start();
780    lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
781
782    ir::MethodDefinition *ctor = nullptr;
783    ArenaVector<ir::AstNode *> properties(Allocator()->Adapter());
784
785    SavedClassPrivateContext classContext(this);
786
787    if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_FORMAT &&
788        lexer_->Lookahead() == static_cast<char32_t>(ARRAY_FORMAT_NODE)) {
789        properties = std::move(ParseAstNodesArrayFormatPlaceholder());
790        if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) {
791            ThrowSyntaxError("Expected a '}'");
792        }
793    } else {
794        while (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE &&
795               lexer_->GetToken().Type() != lexer::TokenType::EOS) {
796            if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) {
797                lexer_->NextToken();
798                continue;
799            }
800
801            ir::AstNode *property = ParseClassElement(properties, modifiers, flags);
802            if (property == nullptr) {  // Error processing.
803                lexer_->NextToken();
804                continue;
805            }
806
807            if (CheckClassElement(property, ctor, properties)) {
808                continue;
809            }
810
811            properties.push_back(property);
812        }
813    }
814
815    lexer::SourcePosition endLoc = lexer_->GetToken().End();
816    CreateImplicitConstructor(ctor, properties, modifiers, endLoc);
817    lexer_->NextToken();
818
819    return {ctor, std::move(properties), lexer::SourceRange {startLoc, endLoc}};
820}
821
822void ParserImpl::ValidateRestParameter(ir::Expression *param)
823{
824    if (!param->IsIdentifier()) {
825        context_.Status() |= ParserStatus::HAS_COMPLEX_PARAM;
826        if (!param->IsRestElement()) {
827            return;
828        }
829
830        if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
831            ThrowSyntaxError("Rest parameter must be last formal parameter.");
832        }
833    }
834}
835
836bool ParserImpl::ValidateBreakLabel(util::StringView label)
837{
838    return context_.FindLabel(label) != nullptr;
839}
840
841bool ParserImpl::ValidateContinueLabel(util::StringView label)
842{
843    const ParserContext *labelCtx = context_.FindLabel(label);
844    return labelCtx != nullptr && ((labelCtx->Status() & ParserStatus::IN_ITERATION) != 0);
845}
846
847ArenaVector<ir::Expression *> ParserImpl::ParseFunctionParams()
848{
849    if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) {
850        lexer_->NextToken();  // eat '('
851    }
852
853    ArenaVector<ir::Expression *> params(Allocator()->Adapter());
854
855    if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_FORMAT &&
856        lexer_->Lookahead() == static_cast<char32_t>(ARRAY_FORMAT_NODE)) {
857        params = std::move(ParseExpressionsArrayFormatPlaceholder());
858    } else {
859        while (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
860            ir::Expression *parameter = ParseFunctionParameter();
861            if (parameter == nullptr) {  // Error processing.
862                continue;
863            }
864
865            ValidateRestParameter(parameter);
866            params.push_back(parameter);
867
868            if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) {
869                lexer_->NextToken();
870            } else if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
871                ThrowSyntaxError("Invalid token: comma or right parenthesis expected.");
872            }
873        }
874    }
875
876    ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS);
877    lexer_->NextToken();
878    return params;
879}
880
881ir::Expression *ParserImpl::CreateParameterThis([[maybe_unused]] util::StringView className)
882{
883    ThrowSyntaxError({"Unexpected token: ", className.Utf8()});
884}
885
886std::tuple<bool, ir::BlockStatement *, lexer::SourcePosition, bool> ParserImpl::ParseFunctionBody(
887    [[maybe_unused]] const ArenaVector<ir::Expression *> &params, [[maybe_unused]] ParserStatus newStatus,
888    [[maybe_unused]] ParserStatus contextStatus)
889{
890    if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
891        ThrowSyntaxError("Unexpected token, expected '{'");
892    }
893
894    ir::BlockStatement *body = ParseBlockStatement();
895
896    return {true, body, body->End(), false};
897}
898
899FunctionSignature ParserImpl::ParseFunctionSignature(ParserStatus status, ir::Identifier *className)
900{
901    ir::TSTypeParameterDeclaration *typeParamDecl = ParseFunctionTypeParameters();
902
903    if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) {
904        ThrowSyntaxError("Unexpected token, expected '('");
905    }
906
907    FunctionParameterContext funcParamContext(&context_);
908
909    ir::Expression *parameterThis = nullptr;
910    if (className != nullptr) {
911        const auto savedPos = Lexer()->Save();
912        lexer_->NextToken();  // eat '('
913        parameterThis = CreateParameterThis(className->Name());
914        Lexer()->Rewind(savedPos);
915    }
916
917    auto params = ParseFunctionParams();
918
919    if (className != nullptr) {
920        params.emplace(params.begin(), parameterThis);
921    }
922
923    ir::TypeNode *returnTypeAnnotation = ParseFunctionReturnType(status);
924    ir::ScriptFunctionFlags throwMarker = ParseFunctionThrowMarker(true);
925
926    auto res = ir::FunctionSignature(typeParamDecl, std::move(params), returnTypeAnnotation);
927    return {std::move(res), throwMarker};
928}
929
930ir::ScriptFunction *ParserImpl::ParseFunction(ParserStatus newStatus)
931{
932    FunctionContext functionContext(this, newStatus | ParserStatus::FUNCTION | ParserStatus::ALLOW_NEW_TARGET);
933
934    bool isDeclare = InAmbientContext();
935
936    lexer::SourcePosition startLoc = lexer_->GetToken().Start();
937
938    auto [signature, throw_marker] = ParseFunctionSignature(newStatus);
939
940    auto [letDeclare, body, endLoc, isOverload] = ParseFunctionBody(signature.Params(), newStatus, context_.Status());
941
942    if (isOverload) {
943        functionContext.AddFlag(ir::ScriptFunctionFlags::OVERLOAD);
944    }
945
946    functionContext.AddFlag(throw_marker);
947    auto *funcNode = AllocNode<ir::ScriptFunction>(
948        Allocator(),
949        ir::ScriptFunction::ScriptFunctionData {
950            body, std::move(signature), functionContext.Flags(), {}, isDeclare && letDeclare, context_.GetLanguage()});
951    funcNode->SetRange({startLoc, endLoc});
952
953    return funcNode;
954}
955
956ir::SpreadElement *ParserImpl::ParseSpreadElement(ExpressionParseFlags flags)
957{
958    ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD);
959    lexer::SourcePosition startLocation = lexer_->GetToken().Start();
960    bool inPattern = (flags & ExpressionParseFlags::MUST_BE_PATTERN) != 0;
961    lexer_->NextToken();
962
963    ir::Expression *argument {};
964    if (inPattern) {
965        argument = ParsePatternElement(ExpressionParseFlags::IN_REST);
966        if ((flags & ExpressionParseFlags::OBJECT_PATTERN) != 0 && !argument->IsIdentifier()) {
967            ThrowSyntaxError("RestParameter must be followed by an identifier in declaration contexts");
968        }
969    } else {
970        argument = ParseExpression(flags);
971    }
972
973    if (inPattern && argument->IsAssignmentExpression()) {
974        ThrowSyntaxError("RestParameter does not support an initializer");
975    }
976
977    auto nodeType = inPattern ? ir::AstNodeType::REST_ELEMENT : ir::AstNodeType::SPREAD_ELEMENT;
978    auto *spreadElementNode = AllocNode<ir::SpreadElement>(nodeType, Allocator(), argument);
979    spreadElementNode->SetRange({startLocation, argument->End()});
980    return spreadElementNode;
981}
982
983void ParserImpl::CheckRestrictedBinding() const
984{
985    ASSERT(lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT);
986    CheckRestrictedBinding(lexer_->GetToken().KeywordType());
987}
988
989void ParserImpl::CheckRestrictedBinding(lexer::TokenType keywordType) const
990{
991    if (keywordType == lexer::TokenType::KEYW_ARGUMENTS || keywordType == lexer::TokenType::KEYW_EVAL) {
992        ThrowSyntaxError(
993            "'eval' or 'arguments' can't be defined or assigned to "
994            "in strict mode code",
995            lexer_->GetToken().Start());
996    }
997}
998
999void ParserImpl::CheckRestrictedBinding(const util::StringView &ident, const lexer::SourcePosition &pos) const
1000{
1001    if (ident.Is("eval") || ident.Is("arguments")) {
1002        ThrowSyntaxError(
1003            "'eval' or 'arguments' can't be defined or assigned to "
1004            "in strict mode code",
1005            pos);
1006    }
1007}
1008
1009ir::Expression *ParserImpl::ParseFunctionParameter()
1010{
1011    ConvertThisKeywordToIdentIfNecessary();
1012
1013    if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) {
1014        CheckRestrictedBinding();
1015    }
1016
1017    return ParsePatternElement(ExpressionParseFlags::NO_OPTS, true);
1018}
1019
1020void ParserImpl::ValidateLvalueAssignmentTarget(ir::Expression *node)
1021{
1022    switch (node->Type()) {
1023        case ir::AstNodeType::IDENTIFIER: {
1024            CheckRestrictedBinding(node->AsIdentifier()->Name(), node->Start());
1025            break;
1026        }
1027        case ir::AstNodeType::MEMBER_EXPRESSION: {
1028            break;
1029        }
1030        default: {
1031            ThrowSyntaxError("Invalid left-hand side in assignment expression");
1032        }
1033    }
1034}
1035
1036void ParserImpl::ValidateAssignmentTarget(ExpressionParseFlags flags, ir::Expression *node)
1037{
1038    switch (node->Type()) {
1039        case ir::AstNodeType::ARRAY_PATTERN:
1040        case ir::AstNodeType::OBJECT_PATTERN: {
1041            break;
1042        }
1043        case ir::AstNodeType::ARRAY_EXPRESSION:
1044        case ir::AstNodeType::OBJECT_EXPRESSION: {
1045            if ((flags & ExpressionParseFlags::POTENTIALLY_IN_PATTERN) != 0) {
1046                return;
1047            }
1048
1049            [[fallthrough]];
1050        }
1051        default: {
1052            return ValidateLvalueAssignmentTarget(node);
1053        }
1054    }
1055}
1056
1057void ParserImpl::ValidateArrowParameterBindings(const ir::Expression *node)
1058{
1059    switch (node->Type()) {
1060        case ir::AstNodeType::IDENTIFIER: {
1061            CheckRestrictedBinding(node->AsIdentifier()->Name(), node->Start());
1062            break;
1063        }
1064        case ir::AstNodeType::OMITTED_EXPRESSION: {
1065            break;
1066        }
1067        case ir::AstNodeType::REST_ELEMENT: {
1068            ValidateArrowParameterBindings(node->AsRestElement()->Argument());
1069            break;
1070        }
1071        case ir::AstNodeType::PROPERTY: {
1072            break;
1073        }
1074        case ir::AstNodeType::OBJECT_PATTERN: {
1075            const auto &props = node->AsObjectPattern()->Properties();
1076
1077            for (auto *it : props) {
1078                ValidateArrowParameterBindings(it);
1079            }
1080            break;
1081        }
1082        case ir::AstNodeType::ARRAY_PATTERN: {
1083            const auto &elements = node->AsArrayPattern()->Elements();
1084
1085            for (auto *it : elements) {
1086                ValidateArrowParameterBindings(it);
1087            }
1088            break;
1089        }
1090        case ir::AstNodeType::ASSIGNMENT_PATTERN: {
1091            ValidateArrowParameterBindings(node->AsAssignmentPattern()->Left());
1092            break;
1093        }
1094        default: {
1095            ThrowSyntaxError("Unexpected ArrowParameter element");
1096        }
1097    }
1098}
1099
1100void ParserImpl::ThrowParameterModifierError(ir::ModifierFlags status) const
1101{
1102    ThrowSyntaxError({"'",
1103                      (status & ir::ModifierFlags::STATIC) != 0  ? "static"
1104                      : (status & ir::ModifierFlags::ASYNC) != 0 ? "async"
1105                                                                 : "declare",
1106                      "' modifier cannot appear on a parameter."},
1107                     lexer_->GetToken().Start());
1108}
1109
1110ir::Identifier *ParserImpl::ParseIdentifierFormatPlaceholder(
1111    [[maybe_unused]] std::optional<NodeFormatType> nodeFormat) const
1112{
1113    ThrowSyntaxError("Identifier expected.");
1114}
1115
1116ir::Statement *ParserImpl::ParseStatementFormatPlaceholder() const
1117{
1118    ThrowSyntaxError("Statement expected.");
1119}
1120
1121ir::AstNode *ParserImpl::ParseTypeParametersFormatPlaceholder() const
1122{
1123    ThrowSyntaxError("Type parameter(s) expected.");
1124}
1125
1126ArenaVector<ir::Statement *> &ParserImpl::ParseStatementsArrayFormatPlaceholder() const
1127{
1128    ThrowSyntaxError("ArenaVector of ir::Statement *'s expected.");
1129}
1130
1131ArenaVector<ir::AstNode *> &ParserImpl::ParseAstNodesArrayFormatPlaceholder() const
1132{
1133    ThrowSyntaxError("ArenaVector of ir::AstNode *'s expected.");
1134}
1135
1136ArenaVector<ir::Expression *> &ParserImpl::ParseExpressionsArrayFormatPlaceholder() const
1137{
1138    ThrowSyntaxError("ArenaVector of ir::Expression *'s expected.");
1139}
1140
1141util::StringView ParserImpl::ParseSymbolIteratorIdentifier() const noexcept
1142{
1143    // Duplicate check - just in case of improper call!
1144    if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) {
1145        return util::StringView {};
1146    }
1147
1148    lexer_->NextToken();
1149    if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT || !lexer_->GetToken().Ident().Is("Symbol")) {
1150        return util::StringView {};
1151    }
1152
1153    lexer_->NextToken();
1154    if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_PERIOD) {
1155        return util::StringView {};
1156    }
1157
1158    lexer_->NextToken();
1159    if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT || !lexer_->GetToken().Ident().Is("iterator")) {
1160        return util::StringView {};
1161    }
1162
1163    lexer_->NextToken();
1164    if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) {
1165        return util::StringView {};
1166    }
1167
1168    //  Just replace '[Symbol.iterator]` identifier with the standard '$_iterator' name.
1169    return util::StringView {compiler::Signatures::ITERATOR_METHOD};
1170}
1171
1172ir::Identifier *ParserImpl::ExpectIdentifier(bool isReference, bool isUserDefinedType)
1173{
1174    auto const &token = lexer_->GetToken();
1175    auto const tokenType = token.Type();
1176    if (tokenType == lexer::TokenType::PUNCTUATOR_FORMAT) {
1177        return ParseIdentifierFormatPlaceholder(std::nullopt);
1178    }
1179
1180    if (token.IsDefinableTypeName() && isUserDefinedType) {
1181        ThrowSyntaxError("Cannot be used as user-defined type.");
1182    }
1183
1184    auto const &tokenStart = token.Start();
1185    util::StringView tokenName {};
1186
1187    if (tokenType == lexer::TokenType::LITERAL_IDENT) {
1188        tokenName = token.Ident();
1189    } else if (tokenType == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) {
1190        // Special case for processing of special '[Symbol.iterator]` identifier using in stdlib.
1191        tokenName = ParseSymbolIteratorIdentifier();
1192    }
1193
1194    if (tokenName.Empty()) {
1195        LogSyntaxError({"Identifier expected, got '", TokenToString(tokenType), "'."}, tokenStart);
1196        return nullptr;  // Error processing.
1197    }
1198
1199    auto *ident = AllocNode<ir::Identifier>(tokenName, Allocator());
1200    ident->SetReference(isReference);
1201    //  NOTE: here actual token can be changed!
1202    ident->SetRange({tokenStart, lexer_->GetToken().End()});
1203
1204    lexer_->NextToken();
1205
1206    return ident;
1207}
1208
1209void ParserImpl::ExpectToken(lexer::TokenType tokenType, bool consumeToken)
1210{
1211    if (lexer_->GetToken().Type() == tokenType) {
1212        if (consumeToken) {
1213            lexer_->NextToken();
1214        }
1215        return;
1216    }
1217    ThrowExpectedToken(tokenType);
1218}
1219
1220void ParserImpl::ThrowUnexpectedToken(lexer::TokenType const tokenType) const
1221{
1222    ThrowSyntaxError("Unexpected token: '"s + TokenToString(tokenType) + "'."s);
1223}
1224
1225void ParserImpl::ThrowExpectedToken(lexer::TokenType const tokenType) const
1226{
1227    ThrowSyntaxError("Unexpected token, expected: '"s + TokenToString(tokenType) + "'."s);
1228}
1229
1230void ParserImpl::ThrowSyntaxError(std::string_view const errorMessage) const
1231{
1232    ThrowSyntaxError(errorMessage, lexer_->GetToken().Start());
1233}
1234
1235void ParserImpl::ThrowSyntaxError(std::initializer_list<std::string_view> list) const
1236{
1237    ThrowSyntaxError(list, lexer_->GetToken().Start());
1238}
1239
1240void ParserImpl::ThrowSyntaxError(std::initializer_list<std::string_view> list, const lexer::SourcePosition &pos) const
1241{
1242    std::stringstream ss;
1243
1244    for (const auto &it : list) {
1245        ss << it;
1246    }
1247
1248    std::string err = ss.str();
1249
1250    ThrowSyntaxError(std::string_view {err}, pos);
1251}
1252
1253void ParserImpl::ThrowSyntaxError(std::string_view errorMessage, const lexer::SourcePosition &pos) const
1254{
1255    lexer::LineIndex index(program_->SourceCode());
1256    lexer::SourceLocation loc = index.GetLocation(pos);
1257
1258    throw Error {ErrorType::SYNTAX, program_->SourceFilePath().Utf8(), errorMessage, loc.line, loc.col};
1259}
1260
1261void ParserImpl::LogExpectedToken(lexer::TokenType const tokenType)
1262{
1263    LogSyntaxError("Unexpected token, expected: '"s + TokenToString(tokenType) + "'."s);
1264    lexer_->GetToken().SetTokenType(tokenType);
1265}
1266
1267void ParserImpl::LogSyntaxError(std::string_view const errorMessage)
1268{
1269    LogSyntaxError(errorMessage, lexer_->GetToken().Start());
1270}
1271
1272void ParserImpl::LogSyntaxError(std::initializer_list<std::string_view> list)
1273{
1274    LogSyntaxError(list, lexer_->GetToken().Start());
1275}
1276
1277void ParserImpl::LogSyntaxError(std::initializer_list<std::string_view> list, const lexer::SourcePosition &pos)
1278{
1279    std::stringstream ss;
1280
1281    for (const auto &it : list) {
1282        ss << it;
1283    }
1284
1285    std::string err = ss.str();
1286
1287    LogSyntaxError(std::string_view {err}, pos);
1288}
1289
1290void ParserImpl::LogSyntaxError(std::string_view errorMessage, const lexer::SourcePosition &pos)
1291{
1292    lexer::LineIndex index(program_->SourceCode());
1293    lexer::SourceLocation loc = index.GetLocation(pos);
1294
1295    errorLogger_.WriteLog(
1296        Error {ErrorType::SYNTAX, program_->SourceFilePath().Utf8(), errorMessage, loc.line, loc.col});
1297}
1298
1299void ParserImpl::ThrowAllocationError(std::string_view message) const
1300{
1301    throw Error(ErrorType::GENERIC, program_->SourceFilePath().Utf8(), message);
1302}
1303
1304ScriptExtension ParserImpl::Extension() const
1305{
1306    return program_->Extension();
1307}
1308
1309bool ParserImpl::CheckModuleAsModifier()
1310{
1311    if (lexer_->GetToken().KeywordType() != lexer::TokenType::KEYW_AS) {
1312        return false;
1313    }
1314
1315    if ((lexer_->GetToken().Flags() & lexer::TokenFlags::HAS_ESCAPE) != 0U) {
1316        ThrowSyntaxError("Escape sequences are not allowed in 'as' keyword");
1317    }
1318
1319    return true;
1320}
1321
1322}  // namespace ark::es2panda::parser
1323