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 "ETSparser.h" 17#include "ETSNolintParser.h" 18#include <utility> 19 20#include "macros.h" 21#include "parser/parserFlags.h" 22#include "parser/parserStatusContext.h" 23#include "util/helpers.h" 24#include "util/language.h" 25#include "utils/arena_containers.h" 26#include "varbinder/varbinder.h" 27#include "varbinder/ETSBinder.h" 28#include "lexer/lexer.h" 29#include "lexer/ETSLexer.h" 30#include "checker/types/ets/etsEnumType.h" 31#include "ir/astNode.h" 32#include "ir/base/classDefinition.h" 33#include "ir/base/decorator.h" 34#include "ir/base/catchClause.h" 35#include "ir/base/classProperty.h" 36#include "ir/base/scriptFunction.h" 37#include "ir/base/methodDefinition.h" 38#include "ir/base/classStaticBlock.h" 39#include "ir/base/spreadElement.h" 40#include "ir/expressions/identifier.h" 41#include "ir/expressions/functionExpression.h" 42#include "ir/statements/functionDeclaration.h" 43#include "ir/statements/expressionStatement.h" 44#include "ir/statements/classDeclaration.h" 45#include "ir/statements/variableDeclarator.h" 46#include "ir/statements/variableDeclaration.h" 47#include "ir/expressions/dummyNode.h" 48#include "ir/expressions/callExpression.h" 49#include "ir/expressions/thisExpression.h" 50#include "ir/expressions/typeofExpression.h" 51#include "ir/expressions/memberExpression.h" 52#include "ir/expressions/updateExpression.h" 53#include "ir/expressions/arrowFunctionExpression.h" 54#include "ir/expressions/unaryExpression.h" 55#include "ir/expressions/yieldExpression.h" 56#include "ir/expressions/awaitExpression.h" 57#include "ir/expressions/literals/nullLiteral.h" 58#include "ir/expressions/literals/numberLiteral.h" 59#include "ir/expressions/literals/stringLiteral.h" 60#include "ir/expressions/literals/undefinedLiteral.h" 61#include "ir/module/importDeclaration.h" 62#include "ir/module/importDefaultSpecifier.h" 63#include "ir/module/importSpecifier.h" 64#include "ir/module/exportSpecifier.h" 65#include "ir/module/exportNamedDeclaration.h" 66#include "ir/statements/assertStatement.h" 67#include "ir/statements/blockStatement.h" 68#include "ir/statements/ifStatement.h" 69#include "ir/statements/labelledStatement.h" 70#include "ir/statements/switchStatement.h" 71#include "ir/statements/throwStatement.h" 72#include "ir/statements/tryStatement.h" 73#include "ir/statements/whileStatement.h" 74#include "ir/statements/forOfStatement.h" 75#include "ir/statements/doWhileStatement.h" 76#include "ir/statements/breakStatement.h" 77#include "ir/statements/debuggerStatement.h" 78#include "ir/ets/etsLaunchExpression.h" 79#include "ir/ets/etsClassLiteral.h" 80#include "ir/ets/etsPrimitiveType.h" 81#include "ir/ets/etsPackageDeclaration.h" 82#include "ir/ets/etsReExportDeclaration.h" 83#include "ir/ets/etsWildcardType.h" 84#include "ir/ets/etsNewArrayInstanceExpression.h" 85#include "ir/ets/etsTuple.h" 86#include "ir/ets/etsFunctionType.h" 87#include "ir/ets/etsNewClassInstanceExpression.h" 88#include "ir/ets/etsNewMultiDimArrayInstanceExpression.h" 89#include "ir/ets/etsScript.h" 90#include "ir/ets/etsTypeReference.h" 91#include "ir/ets/etsTypeReferencePart.h" 92#include "ir/ets/etsNullishTypes.h" 93#include "ir/ets/etsUnionType.h" 94#include "ir/ets/etsImportSource.h" 95#include "ir/ets/etsImportDeclaration.h" 96#include "ir/ets/etsStructDeclaration.h" 97#include "ir/ets/etsParameterExpression.h" 98#include "ir/module/importNamespaceSpecifier.h" 99#include "ir/ts/tsAsExpression.h" 100#include "ir/ts/tsInterfaceDeclaration.h" 101#include "ir/ts/tsEnumDeclaration.h" 102#include "ir/ts/tsTypeParameterInstantiation.h" 103#include "ir/ts/tsInterfaceBody.h" 104#include "ir/ts/tsImportEqualsDeclaration.h" 105#include "ir/ts/tsArrayType.h" 106#include "ir/ts/tsQualifiedName.h" 107#include "ir/ts/tsTypeReference.h" 108#include "ir/ts/tsTypeParameter.h" 109#include "ir/ts/tsInterfaceHeritage.h" 110#include "ir/ts/tsFunctionType.h" 111#include "ir/ts/tsClassImplements.h" 112#include "ir/ts/tsEnumMember.h" 113#include "ir/ts/tsTypeAliasDeclaration.h" 114#include "ir/ts/tsTypeParameterDeclaration.h" 115#include "ir/ts/tsNonNullExpression.h" 116#include "ir/ts/tsThisType.h" 117#include "generated/signatures.h" 118 119namespace ark::es2panda::parser { 120class FunctionContext; 121 122using namespace std::literals::string_literals; 123 124// NOLINTNEXTLINE(google-default-arguments) 125ir::Statement *ETSParser::ParseEnumDeclaration(bool isConst, bool isStatic) 126{ 127 ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::KEYW_ENUM); 128 129 if ((GetContext().Status() & parser::ParserStatus::FUNCTION) != 0U) { 130 ThrowSyntaxError("Local enum declaration support is not yet implemented."); 131 } 132 133 lexer::SourcePosition enumStart = Lexer()->GetToken().Start(); 134 Lexer()->NextToken(); // eat enum keyword 135 136 auto *key = ExpectIdentifier(false, true); 137 138 auto *declNode = ParseEnumMembers(key, enumStart, isConst, isStatic); 139 140 return declNode; 141} 142 143ir::Statement *ETSParser::ParsePotentialConstEnum(VariableParsingFlags flags) 144{ 145 if ((flags & VariableParsingFlags::CONST) == 0) { 146 ThrowSyntaxError("Variable declaration expected."); 147 } 148 149 return ParseEnumDeclaration(true); 150} 151 152// NOLINTBEGIN(cert-err58-cpp) 153static std::string const DUPLICATE_ENUM_VALUE = "Duplicate enum initialization value "s; 154static std::string const INVALID_ENUM_TYPE = "Invalid enum initialization type"s; 155static std::string const INVALID_ENUM_VALUE = "Invalid enum initialization value"s; 156static std::string const MISSING_COMMA_IN_ENUM = "Missing comma between enum constants"s; 157static std::string const TRAILING_COMMA_IN_ENUM = "Trailing comma is not allowed in enum constant list"s; 158// NOLINTEND(cert-err58-cpp) 159 160// Helper for ETSParser::ParseEnumMembers() 161bool ETSParser::IsStringEnum() 162{ 163 // Get the underlying type of enum (number or string). It is defined from the first element ONLY! 164 Lexer()->NextToken(); 165 auto tokenType = Lexer()->GetToken().Type(); 166 while (tokenType != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE && tokenType != lexer::TokenType::PUNCTUATOR_COMMA) { 167 if (tokenType == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { 168 Lexer()->NextToken(); 169 if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_STRING) { 170 return true; 171 } 172 } 173 Lexer()->NextToken(); 174 tokenType = Lexer()->GetToken().Type(); 175 } 176 return false; 177} 178 179ir::TSEnumDeclaration *ETSParser::ParseEnumMembers(ir::Identifier *const key, const lexer::SourcePosition &enumStart, 180 const bool isConst, const bool isStatic) 181{ 182 if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { 183 ThrowSyntaxError("'{' expected"); 184 } 185 186 Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); // eat '{' 187 188 if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { 189 ThrowSyntaxError("An enum must have at least one enum constant"); 190 } 191 192 // Get the underlying type of enum (number or string). It is defined from the first element ONLY! 193 auto const pos = Lexer()->Save(); 194 const bool stringTypeEnum = IsStringEnum(); 195 Lexer()->Rewind(pos); 196 197 ArenaVector<ir::AstNode *> members(Allocator()->Adapter()); 198 199 if (stringTypeEnum) { 200 ParseStringEnum(members); 201 } else { 202 ParseNumberEnum(members); 203 } 204 205 auto *const enumDeclaration = AllocNode<ir::TSEnumDeclaration>( 206 Allocator(), key, std::move(members), 207 ir::TSEnumDeclaration::ConstructorFlags {isConst, isStatic, InAmbientContext()}); 208 enumDeclaration->SetRange({enumStart, Lexer()->GetToken().End()}); 209 210 Lexer()->NextToken(); // eat '}' 211 212 return enumDeclaration; 213} 214 215void ETSParser::ParseNumberEnum(ArenaVector<ir::AstNode *> &members) 216{ 217 checker::ETSIntEnumType::ValueType currentValue {}; 218 219 // Lambda to parse enum member (maybe with initializer) 220 auto const parseMember = [this, &members, ¤tValue]() { 221 auto *const ident = ExpectIdentifier(false, true); 222 223 ir::NumberLiteral *ordinal; 224 lexer::SourcePosition endLoc; 225 226 if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { 227 // Case when user explicitly set the value for enumeration constant 228 229 bool minusSign = false; 230 231 Lexer()->NextToken(); 232 if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PLUS) { 233 Lexer()->NextToken(); 234 } else if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MINUS) { 235 minusSign = true; 236 Lexer()->NextToken(); 237 } 238 239 if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_NUMBER) { 240 ThrowSyntaxError(INVALID_ENUM_TYPE); 241 } 242 243 ordinal = ParseNumberLiteral()->AsNumberLiteral(); 244 if (minusSign) { 245 ordinal->Number().Negate(); 246 } 247 if (!ordinal->Number().CanGetValue<checker::ETSIntEnumType::ValueType>()) { 248 ThrowSyntaxError(INVALID_ENUM_VALUE); 249 } 250 251 currentValue = ordinal->Number().GetValue<checker::ETSIntEnumType::ValueType>(); 252 253 endLoc = ordinal->End(); 254 } else { 255 // Default enumeration constant value. Equal to 0 for the first item and = previous_value + 1 for all 256 // the others. 257 258 ordinal = AllocNode<ir::NumberLiteral>(lexer::Number(currentValue)); 259 260 endLoc = ident->End(); 261 } 262 263 auto *const member = AllocNode<ir::TSEnumMember>(ident, ordinal); 264 member->SetRange({ident->Start(), endLoc}); 265 members.emplace_back(member); 266 267 ++currentValue; 268 }; 269 270 parseMember(); 271 272 while (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { 273 if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COMMA) { 274 ThrowSyntaxError(MISSING_COMMA_IN_ENUM); 275 } 276 277 Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); // eat ',' 278 279 if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { 280 break; 281 } 282 283 parseMember(); 284 } 285} 286 287void ETSParser::ParseStringEnum(ArenaVector<ir::AstNode *> &members) 288{ 289 // Lambda to parse enum member (maybe with initializer) 290 auto const parseMember = [this, &members]() { 291 auto *const ident = ExpectIdentifier(); 292 293 ir::StringLiteral *itemValue; 294 295 if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { 296 // Case when user explicitly set the value for enumeration constant 297 298 Lexer()->NextToken(); 299 if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_STRING) { 300 ThrowSyntaxError(INVALID_ENUM_TYPE); 301 } 302 303 itemValue = ParseStringLiteral(); 304 } else { 305 // Default item value is not allowed for string type enumerations! 306 ThrowSyntaxError("All items of string-type enumeration should be explicitly initialized."); 307 } 308 309 auto *const member = AllocNode<ir::TSEnumMember>(ident, itemValue); 310 member->SetRange({ident->Start(), itemValue->End()}); 311 members.emplace_back(member); 312 }; 313 314 parseMember(); 315 316 while (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { 317 if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COMMA) { 318 ThrowSyntaxError(MISSING_COMMA_IN_ENUM); 319 } 320 321 Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); // eat ',' 322 323 if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { 324 ThrowSyntaxError(TRAILING_COMMA_IN_ENUM); 325 } 326 327 parseMember(); 328 } 329} 330 331} // namespace ark::es2panda::parser 332