From 7314afa686ab4601f884ae28dc31e324d76be0a4 Mon Sep 17 00:00:00 2001 From: gavin1012_hw Date: Mon, 18 Jul 2022 14:54:23 +0800 Subject: [PATCH] Support test262 cases and fix hap compilation Signed-off-by: gavin1012_hw Change-Id: I5f46f9c644612b460f3f5772909d5aca11f66df7 --- es2panda/binder/binder.cpp | 35 ++++++-- es2panda/binder/binder.h | 6 ++ es2panda/binder/declaration.h | 15 ++++ es2panda/binder/scope.cpp | 2 +- es2panda/binder/variableFlags.h | 1 + es2panda/compiler/base/lexenv.cpp | 2 +- es2panda/compiler/core/pandagen.cpp | 67 +++++++++++++- es2panda/compiler/core/pandagen.h | 8 +- es2panda/ir/base/classDefinition.cpp | 2 +- es2panda/ir/expressions/chainExpression.cpp | 87 ++++++++++++++++++- es2panda/ir/expressions/chainExpression.h | 7 ++ .../ir/expressions/literals/bigIntLiteral.cpp | 3 +- es2panda/parser/expressionParser.cpp | 3 + es2panda/parser/parserImpl.h | 2 + es2panda/parser/statementParser.cpp | 71 ++++++++++----- es2panda/util/ustring.h | 5 ++ 16 files changed, 279 insertions(+), 37 deletions(-) diff --git a/es2panda/binder/binder.cpp b/es2panda/binder/binder.cpp index d2a8b2ad39..630a23e89f 100644 --- a/es2panda/binder/binder.cpp +++ b/es2panda/binder/binder.cpp @@ -80,7 +80,7 @@ void Binder::IdentifierAnalysis() ASSERT(program_->Ast()); ASSERT(scope_ == topScope_); - BuildFunction(topScope_, "main"); + BuildFunction(topScope_, MAIN_FUNC_NAME); ResolveReferences(program_->Ast()); AddMandatoryParams(); } @@ -151,23 +151,44 @@ void Binder::LookupIdentReference(ir::Identifier *ident) return; } - if (res.variable->Declaration()->IsLetOrConstDecl() && !res.variable->HasFlag(VariableFlags::INITIALIZED)) { + if (res.variable->Declaration()->IsLetOrConstOrClassDecl() && !res.variable->HasFlag(VariableFlags::INITIALIZED)) { ident->SetTdz(); } ident->SetVariable(res.variable); } -void Binder::BuildFunction(FunctionScope *funcScope, util::StringView name) +util::StringView Binder::BuildFunctionName(FunctionScope *funcScope, util::StringView name) { - uint32_t idx = functionScopes_.size(); - functionScopes_.push_back(funcScope); + // the first functionScope is for func_main_0 + if ((functionScopes_.size() == 1) && (name == MAIN_FUNC_NAME)) { + return name; + } + bool funcNameWithoutDot = name.Find(".") == std::string::npos; + bool funcNameWithoutBackslash = name.Find("\\") == std::string::npos; + + if (name != ANONYMOUS_FUNC_NAME && name != MAIN_FUNC_NAME && funcNameWithoutDot && funcNameWithoutBackslash + && std::find(functionNames_.begin(), functionNames_.end(), name) == functionNames_.end()) { + functionNames_.push_back(name); + return name; + } std::stringstream ss; - ss << "func_" << name << "_" << std::to_string(idx); + uint32_t idx = functionNameIndex_++; + ss << "#" << std::to_string(idx) << "#"; + if (funcNameWithoutDot && funcNameWithoutBackslash) { + ss << name; + } util::UString internalName(ss.str(), Allocator()); + return internalName.View(); +} + +void Binder::BuildFunction(FunctionScope *funcScope, util::StringView name) +{ + functionScopes_.push_back(funcScope); - funcScope->BindName(name, internalName.View()); + util::StringView internalName = BuildFunctionName(funcScope, name); + funcScope->BindName(name, internalName); } void Binder::BuildScriptFunction(Scope *outerScope, const ir::ScriptFunction *scriptFunc) diff --git a/es2panda/binder/binder.h b/es2panda/binder/binder.h index 28f4b038d2..98d03ed65b 100644 --- a/es2panda/binder/binder.h +++ b/es2panda/binder/binder.h @@ -104,6 +104,9 @@ public: static constexpr std::string_view LEXICAL_MANDATORY_PARAM_NEW_TARGET = "!nt"; static constexpr std::string_view LEXICAL_MANDATORY_PARAM_THIS = "!t"; + static constexpr std::string_view MAIN_FUNC_NAME = "func_main_0"; + static constexpr std::string_view ANONYMOUS_FUNC_NAME = ""; + private: using MandatoryParams = std::array; @@ -119,6 +122,7 @@ private: void AddMandatoryParam(const std::string_view &name); void AddMandatoryParams(const MandatoryParams ¶ms); void AddMandatoryParams(); + util::StringView BuildFunctionName(FunctionScope *funcScope, util::StringView name); void BuildFunction(FunctionScope *funcScope, util::StringView name); void BuildScriptFunction(Scope *outerScope, const ir::ScriptFunction *scriptFunc); void BuildClassDefinition(ir::ClassDefinition *classDef); @@ -138,6 +142,8 @@ private: GlobalScope *topScope_ {}; Scope *scope_ {}; ArenaVector functionScopes_; + std::vector functionNames_; + size_t functionNameIndex_ {1}; }; template diff --git a/es2panda/binder/declaration.h b/es2panda/binder/declaration.h index ab65a7579a..bbce7191c0 100644 --- a/es2panda/binder/declaration.h +++ b/es2panda/binder/declaration.h @@ -82,6 +82,11 @@ public: return IsLetDecl() || IsConstDecl(); } + bool IsLetOrConstOrClassDecl() const + { + return IsLetDecl() || IsConstDecl() || IsClassDecl(); + } + protected: explicit Decl(util::StringView name) : name_(name) {} @@ -234,6 +239,16 @@ public: } }; +class ClassDecl : public Decl { +public: + explicit ClassDecl(util::StringView name) : Decl(name) {} + + DeclType Type() const override + { + return DeclType::CLASS; + } +}; + class ParameterDecl : public Decl { public: explicit ParameterDecl(util::StringView name) : Decl(name) {} diff --git a/es2panda/binder/scope.cpp b/es2panda/binder/scope.cpp index 402bdd7a0c..e044f66c46 100644 --- a/es2panda/binder/scope.cpp +++ b/es2panda/binder/scope.cpp @@ -444,7 +444,7 @@ void LoopDeclarationScope::ConvertToVariableScope(ArenaAllocator *allocator) } for (auto &[name, var] : bindings_) { - if (!var->LexicalBound() || !var->Declaration()->IsLetOrConstDecl()) { + if (!var->LexicalBound() || !var->Declaration()->IsLetOrConstOrClassDecl()) { continue; } diff --git a/es2panda/binder/variableFlags.h b/es2panda/binder/variableFlags.h index dee8b14757..3a7f3a7138 100644 --- a/es2panda/binder/variableFlags.h +++ b/es2panda/binder/variableFlags.h @@ -24,6 +24,7 @@ namespace panda::es2panda::binder { _(VAR, VarDecl) \ _(LET, LetDecl) \ _(CONST, ConstDecl) \ + _(CLASS, ClassDecl) \ _(FUNC, FunctionDecl) \ _(PARAM, ParameterDecl) \ _(IMPORT, ImportDecl) \ diff --git a/es2panda/compiler/base/lexenv.cpp b/es2panda/compiler/base/lexenv.cpp index f3410f06c2..0ca34ca25e 100644 --- a/es2panda/compiler/base/lexenv.cpp +++ b/es2panda/compiler/base/lexenv.cpp @@ -91,7 +91,7 @@ static void ExpandStoreLexVar(PandaGen *pg, const ir::AstNode *node, const binde const auto *decl = result.variable->Declaration(); - if (decl->IsLetOrConstDecl() && !isDecl) { + if (decl->IsLetOrConstOrClassDecl() && !isDecl) { RegScope rs(pg); VReg valueReg = pg->AllocReg(); diff --git a/es2panda/compiler/core/pandagen.cpp b/es2panda/compiler/core/pandagen.cpp index 7cf1bb96f5..b51bad41ce 100644 --- a/es2panda/compiler/core/pandagen.cpp +++ b/es2panda/compiler/core/pandagen.cpp @@ -159,11 +159,12 @@ void PandaGen::CopyFunctionArguments(const ir::AstNode *node) { FrontAllocator fa(this); VReg targetReg = totalRegs_; + VReg destReg = topScope_->ParamScope()->Params().size() + 1; for (const auto *param : topScope_->ParamScope()->Params()) { if (param->LexicalBound()) { LoadAccumulator(node, targetReg++); - StoreLexicalVar(node, 0, param->LexIdx()); + StoreLexicalVar(node, 0, param->LexIdx(), destReg); } else { ra_.Emit(node, param->Vreg(), targetReg++); } @@ -222,6 +223,14 @@ void PandaGen::LoadVar(const ir::Identifier *node, const binder::ScopeFindResult } ASSERT(var->IsLocalVariable()); + + if (var->Declaration()->IsLetOrConstDecl()) { + if (result.scope->IsGlobalScope()) { + TryLoadGlobalByName(node, result.name); + return; + } + } + LoadAccFromLexEnv(node, result); } @@ -245,6 +254,22 @@ void PandaGen::StoreVar(const ir::AstNode *node, const binder::ScopeFindResult & } ASSERT(var->IsLocalVariable()); + + if (isDeclaration && var->Declaration()->IsLetOrConstDecl()) { + if (result.scope->IsGlobalScope()) { + if (var->Declaration()->IsLetDecl()) { + StLetToGlobalRecord(node, var->Name()); + } else { + StConstToGlobalRecord(node, var->Name()); + } + return; + } + } + if (var->Declaration()->IsLetOrConstDecl() && result.scope->IsGlobalScope()) { + TryStoreGlobalByName(node, var->Name()); + return; + } + StoreAccToLexEnv(node, result, isDeclaration); } @@ -455,6 +480,13 @@ void PandaGen::LoadAccumulatorInt(const ir::AstNode *node, size_t num) sa_.Emit(node, static_cast(num)); } +void PandaGen::LoadAccumulatorBigInt(const ir::AstNode *node, const util::StringView &num) +{ + util::StringView bigIntValue = num.Substr(0, num.Length()-1); + sa_.Emit(node, bigIntValue); + strings_.insert(bigIntValue); +} + void PandaGen::StoreConst(const ir::AstNode *node, VReg reg, Constant id) { LoadConst(node, id); @@ -804,6 +836,7 @@ void PandaGen::BranchIfNotUndefined(const ir::AstNode *node, Label *target) void PandaGen::BranchIfTrue(const ir::AstNode *node, Label *target) { + sa_.Emit(node); sa_.Emit(node, target); } @@ -815,6 +848,13 @@ void PandaGen::BranchIfNotTrue(const ir::AstNode *node, Label *target) void PandaGen::BranchIfFalse(const ir::AstNode *node, Label *target) { + sa_.Emit(node); + sa_.Emit(node, target); +} + +void PandaGen::BranchIfNotFalse(const ir::AstNode *node, Label *target) +{ + sa_.Emit(node); sa_.Emit(node, target); } @@ -1438,11 +1478,14 @@ void PandaGen::LoadLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t sa_.Emit(node, level, slot); } -void PandaGen::StoreLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot) +void PandaGen::StoreLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot, VReg destVreg) { // TODO: need to reconsider this part RegScope rs(this); - VReg value = AllocReg(); + VReg value = destVreg; + if (destVreg == 0) { + value = AllocReg(); + } StoreAccumulator(node, value); ra_.Emit(node, level, slot, value); } @@ -1594,4 +1637,22 @@ VReg PandaGen::LoadPropertyKey(const ir::Expression *prop, bool isComputed) return propReg; } +void PandaGen::StLetToGlobalRecord(const ir::AstNode *node, const util::StringView &name) +{ + sa_.Emit(node, name); + strings_.insert(name); +} + +void PandaGen::StConstToGlobalRecord(const ir::AstNode *node, const util::StringView &name) +{ + sa_.Emit(node, name); + strings_.insert(name); +} + +void PandaGen::StClassToGlobalRecord(const ir::AstNode *node, const util::StringView &name) +{ + sa_.Emit(node, name); + strings_.insert(name); +} + } // namespace panda::es2panda::compiler diff --git a/es2panda/compiler/core/pandagen.h b/es2panda/compiler/core/pandagen.h index 77d127c423..30b670c412 100644 --- a/es2panda/compiler/core/pandagen.h +++ b/es2panda/compiler/core/pandagen.h @@ -208,6 +208,10 @@ public: void LoadVar(const ir::Identifier *node, const binder::ScopeFindResult &result); void StoreVar(const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDeclaration); + void StLetToGlobalRecord(const ir::AstNode *node, const util::StringView &name); + void StConstToGlobalRecord(const ir::AstNode *node, const util::StringView &name); + void StClassToGlobalRecord(const ir::AstNode *node, const util::StringView &name); + void StoreAccumulator(const ir::AstNode *node, VReg vreg); void LoadAccFromArgs(const ir::AstNode *node); void LoadObjProperty(const ir::AstNode *node, VReg obj, const Operand &prop); @@ -234,6 +238,7 @@ public: void LoadAccumulatorFloat(const ir::AstNode *node, double num); void LoadAccumulatorInt(const ir::AstNode *node, int32_t num); void LoadAccumulatorInt(const ir::AstNode *node, size_t num); + void LoadAccumulatorBigInt(const ir::AstNode *node, const util::StringView &num); void LoadConst(const ir::AstNode *node, Constant id); void StoreConst(const ir::AstNode *node, VReg reg, Constant id); @@ -255,6 +260,7 @@ public: void BranchIfTrue(const ir::AstNode *node, class Label *target); void BranchIfNotTrue(const ir::AstNode *node, class Label *target); void BranchIfFalse(const ir::AstNode *node, class Label *target); + void BranchIfNotFalse(const ir::AstNode *node, class Label *target); void EmitThrow(const ir::AstNode *node); void EmitRethrow(const ir::AstNode *node); @@ -347,7 +353,7 @@ public: void CopyLexEnv(const ir::AstNode *node); void NewLexEnv(const ir::AstNode *node, uint32_t num); void LoadLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot); - void StoreLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot); + void StoreLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot, VReg destVreg = 0); void ThrowIfSuperNotCorrectCall(const ir::AstNode *node, int64_t num); void ThrowUndefinedIfHole(const ir::AstNode *node, const util::StringView &name); diff --git a/es2panda/ir/base/classDefinition.cpp b/es2panda/ir/base/classDefinition.cpp index bd18a40d34..17dead742c 100644 --- a/es2panda/ir/base/classDefinition.cpp +++ b/es2panda/ir/base/classDefinition.cpp @@ -270,7 +270,7 @@ void ClassDefinition::Compile(compiler::PandaGen *pg) const int32_t bufIdx = CreateClassStaticProperties(pg, compiled); pg->DefineClassWithBuffer(this, ctorId, bufIdx, lexenv, baseReg); if (scope_->Parent()->IsGlobalScope() && ident_) { - pg->StoreGlobalLet(this, ident_->Name()); + pg->StClassToGlobalRecord(this, ident_->Name()); } pg->StoreAccumulator(this, classReg); InitializeClassName(pg); diff --git a/es2panda/ir/expressions/chainExpression.cpp b/es2panda/ir/expressions/chainExpression.cpp index 16e2b3a299..55e5ae7624 100644 --- a/es2panda/ir/expressions/chainExpression.cpp +++ b/es2panda/ir/expressions/chainExpression.cpp @@ -14,8 +14,11 @@ */ #include "chainExpression.h" +#include #include +#include +#include namespace panda::es2panda::ir { @@ -29,7 +32,89 @@ void ChainExpression::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "ChainExpression"}, {"expression", expression_}}); } -void ChainExpression::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void ChainExpression::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + const MemberExpression *memberExpr = nullptr; + if (this->GetExpression()->IsMemberExpression()) { + memberExpr = this->GetExpression()->AsMemberExpression(); + } else { + auto callExpr = this->GetExpression()->AsCallExpression(); + memberExpr = callExpr->Callee()->AsMemberExpression(); + } + compiler::Label *resultLabel = nullptr; + CompileLogical(pg, memberExpr, resultLabel); + this->GetExpression()->Compile(pg); + pg->SetLabel(this, resultLabel); +} + +void ChainExpression::CompileLogical(compiler::PandaGen *pg, const MemberExpression *memberExpr, + compiler::Label *&resultLabel) const +{ + compiler::RegScope rs(pg); + compiler::VReg falseReg = pg->AllocReg(); + compiler::VReg trueReg = pg->AllocReg(); + compiler::VReg nullReg = pg->AllocReg(); + compiler::VReg undefinedReg = pg->AllocReg(); + compiler::VReg objReg = pg->AllocReg(); + + pg->LoadConst(this, compiler::Constant::JS_FALSE); + pg->StoreAccumulator(this, falseReg); + pg->LoadConst(this, compiler::Constant::JS_TRUE); + pg->StoreAccumulator(this, trueReg); + pg->LoadConst(this, compiler::Constant::JS_NULL); + pg->StoreAccumulator(this, nullReg); + pg->LoadConst(this, compiler::Constant::JS_UNDEFINED); + pg->StoreAccumulator(this, undefinedReg); + + CheckMemberExpressionObjIfNull(pg, memberExpr, std::vector{objReg, trueReg, falseReg, nullReg}); + auto *isNullRes = pg->AllocLabel(); + pg->BranchIfNotFalse(this, isNullRes); + + CheckMemberExpressionObjIfUndefined(pg, memberExpr, + std::vector{objReg, trueReg, falseReg, undefinedReg}); + auto *isUndefinedRes = pg->AllocLabel(); + pg->BranchIfNotTrue(this, isUndefinedRes); + + pg->SetLabel(this, isNullRes); + pg->LoadAccumulatorInt(this, 0); + pg->LoadAccumulator(this, undefinedReg); + resultLabel = pg->AllocLabel(); + pg->Branch(this, resultLabel); + pg->SetLabel(this, isUndefinedRes); +} + +void ChainExpression::CheckMemberExpressionObjIfNull(compiler::PandaGen *pg, const MemberExpression *memberExpr, + std::vector regs) const +{ + auto *notNullLabel = pg->AllocLabel(); + auto *isNullLabel = pg->AllocLabel(); + + memberExpr->CompileObject(pg, regs[0]); + pg->LoadAccumulator(this, regs[3]); + pg->Condition(this, lexer::TokenType::PUNCTUATOR_STRICT_EQUAL, regs[0], notNullLabel); + pg->LoadAccumulator(this, regs[1]); + pg->Branch(this, isNullLabel); + pg->SetLabel(this, notNullLabel); + pg->LoadAccumulator(this, regs[2]); + pg->SetLabel(this, isNullLabel); +} + +void ChainExpression::CheckMemberExpressionObjIfUndefined(compiler::PandaGen *pg, const MemberExpression *memberExpr, + std::vector regs) const +{ + auto *notUndefinedLabel = pg->AllocLabel(); + auto *isUndefinedLabel = pg->AllocLabel(); + + memberExpr->CompileObject(pg, regs[0]); + pg->LoadAccumulatorInt(this, 0); + pg->LoadAccumulator(this, regs[3]); + pg->Condition(this, lexer::TokenType::PUNCTUATOR_STRICT_EQUAL, regs[0], notUndefinedLabel); + pg->LoadAccumulator(this, regs[1]); + pg->Branch(this, isUndefinedLabel); + pg->SetLabel(this, notUndefinedLabel); + pg->LoadAccumulator(this, regs[2]); + pg->SetLabel(this, isUndefinedLabel); +} checker::Type *ChainExpression::Check([[maybe_unused]] checker::Checker *checker) const { diff --git a/es2panda/ir/expressions/chainExpression.h b/es2panda/ir/expressions/chainExpression.h index 571d10c89b..3e8735bc6a 100644 --- a/es2panda/ir/expressions/chainExpression.h +++ b/es2panda/ir/expressions/chainExpression.h @@ -17,6 +17,7 @@ #define ES2PANDA_IR_EXPRESSION_CHAIN_EXPRESSION_H #include +#include namespace panda::es2panda::compiler { class PandaGen; @@ -44,6 +45,12 @@ public: void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; + void CompileLogical(compiler::PandaGen *pg, const MemberExpression *memberExpr, + compiler::Label *&resultLabel) const; + void CheckMemberExpressionObjIfNull(compiler::PandaGen *pg, const MemberExpression *memberExpr, + std::vector regs) const; + void CheckMemberExpressionObjIfUndefined(compiler::PandaGen *pg, const MemberExpression *memberExpr, + std::vector regs) const; checker::Type *Check([[maybe_unused]] checker::Checker *checker) const override; private: diff --git a/es2panda/ir/expressions/literals/bigIntLiteral.cpp b/es2panda/ir/expressions/literals/bigIntLiteral.cpp index 7d3a149f8f..3cc1dfab19 100644 --- a/es2panda/ir/expressions/literals/bigIntLiteral.cpp +++ b/es2panda/ir/expressions/literals/bigIntLiteral.cpp @@ -30,8 +30,7 @@ void BigIntLiteral::Dump(ir::AstDumper *dumper) const void BigIntLiteral::Compile(compiler::PandaGen *pg) const { - // TODO() - pg->Unimplemented(); + pg->LoadAccumulatorBigInt(this, src_); } checker::Type *BigIntLiteral::Check(checker::Checker *checker) const diff --git a/es2panda/parser/expressionParser.cpp b/es2panda/parser/expressionParser.cpp index 34bb768e91..d63a53776a 100644 --- a/es2panda/parser/expressionParser.cpp +++ b/es2panda/parser/expressionParser.cpp @@ -957,6 +957,9 @@ ir::Expression *ParserImpl::ParsePrimaryExpression(ExpressionParseFlags flags) return ParseImportExpression(); } case lexer::TokenType::LITERAL_IDENT: { + if (lexer_->GetToken().Ident().Is("yield")) { + ThrowSyntaxError("Identifier expected. 'yield' is a reserved word in strict mode."); + } auto *identNode = AllocNode(lexer_->GetToken().Ident(), Allocator()); identNode->SetReference(); identNode->SetRange(lexer_->GetToken().Loc()); diff --git a/es2panda/parser/parserImpl.h b/es2panda/parser/parserImpl.h index e73468a664..9648e8a592 100644 --- a/es2panda/parser/parserImpl.h +++ b/es2panda/parser/parserImpl.h @@ -390,6 +390,8 @@ private: void CheckFunctionDeclaration(StatementParsingFlags flags); void CheckLabelledFunction(const ir::Statement *node); + void CheckFunctionLocation(const ir::Statement *node); + void CheckLexerTokenType(); void CheckDeclare(); bool ParseDirective(ArenaVector *statements); diff --git a/es2panda/parser/statementParser.cpp b/es2panda/parser/statementParser.cpp index 2a06a84efb..a7d96a4533 100644 --- a/es2panda/parser/statementParser.cpp +++ b/es2panda/parser/statementParser.cpp @@ -501,7 +501,7 @@ ir::ClassDeclaration *ParserImpl::ParseClassDeclaration(bool idRequired, ArenaVe ir::ClassDefinition *classDefinition = ParseClassDefinition(true, idRequired, isDeclare, isAbstract); auto *decl = - Binder()->AddDecl(classDefinition->Ident()->Start(), classDefinition->Ident()->Name()); + Binder()->AddDecl(classDefinition->Ident()->Start(), classDefinition->Ident()->Name()); decl->BindNode(classDefinition); lexer::SourcePosition endLoc = classDefinition->End(); @@ -690,6 +690,31 @@ void ParserImpl::CheckFunctionDeclaration(StatementParsingFlags flags) } } +void ParserImpl::CheckFunctionLocation(const ir::Statement *node) +{ + if (node->IsFunctionDeclaration()) { + ThrowSyntaxError("In strict mode code, functions can only be declared at top level or inside a block."); + } +} + +void ParserImpl::CheckLexerTokenType() +{ + switch (lexer_->GetToken().Type()) { + case lexer::TokenType::KEYW_CONST: { + ThrowSyntaxError("The 'const' declarations can only be declared inside a block."); + } + case lexer::TokenType::KEYW_CLASS: { + ThrowSyntaxError("Class declaration not allowed in statement position."); + } + case lexer::TokenType::KEYW_LET: { + ThrowSyntaxError("The 'let' declarations can only be declared inside a block."); + } + default: { + return; + } + } +} + void ParserImpl::ConsumeSemicolon(ir::Statement *statement) { if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { @@ -790,11 +815,11 @@ ir::BreakStatement *ParserImpl::ParseBreakStatement() } lexer::SourcePosition startLoc = lexer_->GetToken().Start(); - lexer::SourcePosition endLoc = lexer_->GetToken().End(); lexer_->NextToken(); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON || - lexer_->GetToken().Type() == lexer::TokenType::EOS || lexer_->GetToken().NewLine()) { + lexer_->GetToken().Type() == lexer::TokenType::EOS || lexer_->GetToken().NewLine() || + lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { if (!allowBreak) { if (Extension() == ScriptExtension::JS) { ThrowSyntaxError("Illegal break statement"); @@ -808,24 +833,10 @@ ir::BreakStatement *ParserImpl::ParseBreakStatement() auto *breakStatement = AllocNode(); breakStatement->SetRange({startLoc, lexer_->GetToken().End()}); - lexer_->NextToken(); - return breakStatement; - } - - if (lexer_->GetToken().NewLine() || lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { - if (!allowBreak) { - if (Extension() == ScriptExtension::JS) { - ThrowSyntaxError("Illegal break statement"); - } - if (Extension() == ScriptExtension::TS) { - ThrowSyntaxError( - "A 'break' statement can only be used within an " - "enclosing iteration or switch statement"); - } + if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { + lexer_->NextToken(); } - auto *breakStatement = AllocNode(); - breakStatement->SetRange({startLoc, endLoc}); return breakStatement; } @@ -917,8 +928,9 @@ ir::DoWhileStatement *ParserImpl::ParseDoWhileStatement() lexer::SourcePosition startLoc = lexer_->GetToken().Start(); lexer_->NextToken(); + CheckLexerTokenType(); ir::Statement *body = ParseStatement(); - + CheckFunctionLocation(body); if (lexer_->GetToken().Type() != lexer::TokenType::KEYW_WHILE) { ThrowSyntaxError("Missing 'while' keyword in a 'DoWhileStatement'"); } @@ -1302,7 +1314,9 @@ ir::Statement *ParserImpl::ParseForStatement() } lexer_->NextToken(); + CheckLexerTokenType(); ir::Statement *bodyNode = ParseStatement(); + CheckFunctionLocation(bodyNode); lexer::SourcePosition endLoc = bodyNode->End(); ir::Statement *forStatement = nullptr; @@ -1341,18 +1355,22 @@ ir::IfStatement *ParserImpl::ParseIfStatement() } lexer_->NextToken(); + CheckLexerTokenType(); ir::Statement *consequent = ParseStatement(StatementParsingFlags::IF_ELSE | StatementParsingFlags::ALLOW_LEXICAL); if (Extension() == ScriptExtension::TS && consequent->IsEmptyStatement()) { ThrowSyntaxError("The body of an if statement cannot be the empty statement"); } + CheckFunctionLocation(consequent); endLoc = consequent->End(); ir::Statement *alternate = nullptr; if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_ELSE) { lexer_->NextToken(); // eat ELSE keyword + CheckLexerTokenType(); alternate = ParseStatement(StatementParsingFlags::IF_ELSE | StatementParsingFlags::ALLOW_LEXICAL); + CheckFunctionLocation(alternate); endLoc = alternate->End(); } @@ -1370,6 +1388,10 @@ ir::LabelledStatement *ParserImpl::ParseLabelledStatement(const lexer::LexerPosi ThrowSyntaxError("'await' is a reserved identifier in module code", pos.token.Start()); } + if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_YIELD) { + ThrowSyntaxError("Identifier expected. 'yield' is a reserved word in strict mode.", pos.token.Start()); + } + if (context_.FindLabel(actualLabel)) { ThrowSyntaxError("Label already declared", pos.token.Start()); } @@ -1816,6 +1838,13 @@ ir::Statement *ParserImpl::ParseVariableDeclaration(VariableParsingFlags flags, lexer_->NextToken(); } + if (lexer_->GetToken().Ident().Is("yield")) { + ThrowSyntaxError("Invalid use of 'yield' in strict mode."); + } + if ((flags & VariableParsingFlags::LET) && (lexer_->GetToken().Ident().Is("undefined"))) { + ThrowSyntaxError("Declaration name conflicts with built-in global identifier 'undefined'."); + } + if (Extension() == ScriptExtension::TS && lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_ENUM) { if (!(flags & VariableParsingFlags::CONST)) { ThrowSyntaxError("Variable declaration expected."); @@ -1867,8 +1896,10 @@ ir::WhileStatement *ParserImpl::ParseWhileStatement() } lexer_->NextToken(); + CheckLexerTokenType(); IterationContext iterCtx(&context_, Binder()); ir::Statement *body = ParseStatement(); + CheckFunctionLocation(body); lexer::SourcePosition endLoc = body->End(); auto *whileStatement = AllocNode(iterCtx.LexicalScope().GetScope(), test, body); diff --git a/es2panda/util/ustring.h b/es2panda/util/ustring.h index 1801234961..4114601087 100644 --- a/es2panda/util/ustring.h +++ b/es2panda/util/ustring.h @@ -109,6 +109,11 @@ public: return StringView(std::string_view(sv_.data() + begin, end - begin)); } + constexpr size_t Find(const char *str) + { + return sv_.find(str); + } + static bool IsHighSurrogate(char32_t cp) { return (cp >= Constants::SURROGATE_HIGH_MIN && cp < Constants::SURROGATE_HIGH_MAX); -- Gitee