13af6ab5fSopenharmony_ci/** 23af6ab5fSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd. 33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License. 53af6ab5fSopenharmony_ci * You may obtain a copy of the License at 63af6ab5fSopenharmony_ci * 73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 83af6ab5fSopenharmony_ci * 93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and 133af6ab5fSopenharmony_ci * limitations under the License. 143af6ab5fSopenharmony_ci */ 153af6ab5fSopenharmony_ci 163af6ab5fSopenharmony_ci#include "unaryExpression.h" 173af6ab5fSopenharmony_ci 183af6ab5fSopenharmony_ci#include <binder/variable.h> 193af6ab5fSopenharmony_ci#include <compiler/core/pandagen.h> 203af6ab5fSopenharmony_ci#include <typescript/checker.h> 213af6ab5fSopenharmony_ci#include <ir/astDump.h> 223af6ab5fSopenharmony_ci#include <ir/expressions/identifier.h> 233af6ab5fSopenharmony_ci#include <ir/expressions/literals/bigIntLiteral.h> 243af6ab5fSopenharmony_ci#include <ir/expressions/literals/numberLiteral.h> 253af6ab5fSopenharmony_ci#include <ir/expressions/memberExpression.h> 263af6ab5fSopenharmony_ci 273af6ab5fSopenharmony_cinamespace panda::es2panda::ir { 283af6ab5fSopenharmony_ci 293af6ab5fSopenharmony_civoid UnaryExpression::Iterate(const NodeTraverser &cb) const 303af6ab5fSopenharmony_ci{ 313af6ab5fSopenharmony_ci cb(argument_); 323af6ab5fSopenharmony_ci} 333af6ab5fSopenharmony_ci 343af6ab5fSopenharmony_civoid UnaryExpression::Dump(ir::AstDumper *dumper) const 353af6ab5fSopenharmony_ci{ 363af6ab5fSopenharmony_ci dumper->Add({{"type", "UnaryExpression"}, {"operator", operator_}, {"prefix", true}, {"argument", argument_}}); 373af6ab5fSopenharmony_ci} 383af6ab5fSopenharmony_ci 393af6ab5fSopenharmony_civoid UnaryExpression::Compile(compiler::PandaGen *pg) const 403af6ab5fSopenharmony_ci{ 413af6ab5fSopenharmony_ci switch (operator_) { 423af6ab5fSopenharmony_ci case lexer::TokenType::KEYW_DELETE: { 433af6ab5fSopenharmony_ci if (argument_->IsIdentifier()) { 443af6ab5fSopenharmony_ci binder::ScopeFindResult result = pg->Scope()->Find(argument_->AsIdentifier()->Name()); 453af6ab5fSopenharmony_ci if (!result.variable || (result.scope->IsGlobalScope() && result.variable->IsGlobalVariable())) { 463af6ab5fSopenharmony_ci compiler::RegScope rs(pg); 473af6ab5fSopenharmony_ci compiler::VReg variable = pg->AllocReg(); 483af6ab5fSopenharmony_ci compiler::VReg global = pg->AllocReg(); 493af6ab5fSopenharmony_ci 503af6ab5fSopenharmony_ci pg->LoadConst(this, compiler::Constant::JS_GLOBAL); 513af6ab5fSopenharmony_ci pg->StoreAccumulator(this, global); 523af6ab5fSopenharmony_ci 533af6ab5fSopenharmony_ci pg->LoadAccumulatorString(this, argument_->AsIdentifier()->Name()); 543af6ab5fSopenharmony_ci pg->StoreAccumulator(this, variable); 553af6ab5fSopenharmony_ci 563af6ab5fSopenharmony_ci pg->DeleteObjProperty(this, global, variable); 573af6ab5fSopenharmony_ci } else { 583af6ab5fSopenharmony_ci // Otherwise it is a local variable which can't be deleted and we just 593af6ab5fSopenharmony_ci // return false. 603af6ab5fSopenharmony_ci pg->LoadConst(this, compiler::Constant::JS_FALSE); 613af6ab5fSopenharmony_ci } 623af6ab5fSopenharmony_ci } else if (argument_->IsMemberExpression()) { 633af6ab5fSopenharmony_ci compiler::RegScope rs(pg); 643af6ab5fSopenharmony_ci compiler::VReg object = pg->AllocReg(); 653af6ab5fSopenharmony_ci 663af6ab5fSopenharmony_ci argument_->AsMemberExpression()->CompileObject(pg, object); 673af6ab5fSopenharmony_ci compiler::Operand prop = argument_->AsMemberExpression()->CompileKey(pg); 683af6ab5fSopenharmony_ci 693af6ab5fSopenharmony_ci pg->DeleteObjProperty(this, object, prop); 703af6ab5fSopenharmony_ci } else { 713af6ab5fSopenharmony_ci // compile the delete operand. 723af6ab5fSopenharmony_ci argument_->Compile(pg); 733af6ab5fSopenharmony_ci // Deleting any value or a result of an expression returns True. 743af6ab5fSopenharmony_ci pg->LoadConst(this, compiler::Constant::JS_TRUE); 753af6ab5fSopenharmony_ci } 763af6ab5fSopenharmony_ci break; 773af6ab5fSopenharmony_ci } 783af6ab5fSopenharmony_ci case lexer::TokenType::KEYW_TYPEOF: { 793af6ab5fSopenharmony_ci if (argument_->IsIdentifier()) { 803af6ab5fSopenharmony_ci const ir::Identifier *ident = argument_->AsIdentifier(); 813af6ab5fSopenharmony_ci 823af6ab5fSopenharmony_ci binder::ScopeFindResult res = pg->Scope()->Find(ident->Name()); 833af6ab5fSopenharmony_ci if (!res.variable && !pg->isDebuggerEvaluateExpressionMode()) { 843af6ab5fSopenharmony_ci compiler::RegScope rs(pg); 853af6ab5fSopenharmony_ci compiler::VReg global = pg->AllocReg(); 863af6ab5fSopenharmony_ci 873af6ab5fSopenharmony_ci pg->LoadConst(this, compiler::Constant::JS_GLOBAL); 883af6ab5fSopenharmony_ci pg->StoreAccumulator(this, global); 893af6ab5fSopenharmony_ci pg->LoadObjByName(this, global, ident->Name()); 903af6ab5fSopenharmony_ci } else if (!res.variable && pg->isDebuggerEvaluateExpressionMode()) { 913af6ab5fSopenharmony_ci // false: typeof an undeclared variable will return undefined 923af6ab5fSopenharmony_ci pg->LoadObjByNameViaDebugger(this, ident->Name(), false); 933af6ab5fSopenharmony_ci } else { 943af6ab5fSopenharmony_ci pg->LoadVar(ident, res); 953af6ab5fSopenharmony_ci } 963af6ab5fSopenharmony_ci } else { 973af6ab5fSopenharmony_ci argument_->Compile(pg); 983af6ab5fSopenharmony_ci } 993af6ab5fSopenharmony_ci 1003af6ab5fSopenharmony_ci pg->TypeOf(this); 1013af6ab5fSopenharmony_ci break; 1023af6ab5fSopenharmony_ci } 1033af6ab5fSopenharmony_ci case lexer::TokenType::KEYW_VOID: { 1043af6ab5fSopenharmony_ci argument_->Compile(pg); 1053af6ab5fSopenharmony_ci pg->LoadConst(this, compiler::Constant::JS_UNDEFINED); 1063af6ab5fSopenharmony_ci break; 1073af6ab5fSopenharmony_ci } 1083af6ab5fSopenharmony_ci default: { 1093af6ab5fSopenharmony_ci argument_->Compile(pg); 1103af6ab5fSopenharmony_ci 1113af6ab5fSopenharmony_ci compiler::RegScope rs(pg); 1123af6ab5fSopenharmony_ci compiler::VReg operandReg = pg->AllocReg(); 1133af6ab5fSopenharmony_ci pg->StoreAccumulator(this, operandReg); 1143af6ab5fSopenharmony_ci pg->Unary(this, operator_, operandReg); 1153af6ab5fSopenharmony_ci break; 1163af6ab5fSopenharmony_ci } 1173af6ab5fSopenharmony_ci } 1183af6ab5fSopenharmony_ci} 1193af6ab5fSopenharmony_ci 1203af6ab5fSopenharmony_cichecker::Type *UnaryExpression::Check(checker::Checker *checker) const 1213af6ab5fSopenharmony_ci{ 1223af6ab5fSopenharmony_ci checker::Type *operandType = argument_->Check(checker); 1233af6ab5fSopenharmony_ci 1243af6ab5fSopenharmony_ci if (operator_ == lexer::TokenType::KEYW_TYPEOF) { 1253af6ab5fSopenharmony_ci return operandType; 1263af6ab5fSopenharmony_ci } 1273af6ab5fSopenharmony_ci 1283af6ab5fSopenharmony_ci if (operator_ == lexer::TokenType::KEYW_DELETE) { 1293af6ab5fSopenharmony_ci checker::Type *propType = argument_->Check(checker); 1303af6ab5fSopenharmony_ci 1313af6ab5fSopenharmony_ci if (!argument_->IsMemberExpression()) { 1323af6ab5fSopenharmony_ci checker->ThrowTypeError("The operand of a delete operator must be a property reference.", 1333af6ab5fSopenharmony_ci argument_->Start()); 1343af6ab5fSopenharmony_ci } 1353af6ab5fSopenharmony_ci 1363af6ab5fSopenharmony_ci const ir::MemberExpression *memberArg = argument_->AsMemberExpression(); 1373af6ab5fSopenharmony_ci 1383af6ab5fSopenharmony_ci if (memberArg->Property()->IsTSPrivateIdentifier() || memberArg->Property()->IsPrivateIdentifier()) { 1393af6ab5fSopenharmony_ci checker->ThrowTypeError("The operand of a delete operator cannot be a private identifier.", 1403af6ab5fSopenharmony_ci argument_->Start()); 1413af6ab5fSopenharmony_ci } 1423af6ab5fSopenharmony_ci 1433af6ab5fSopenharmony_ci ASSERT(propType->Variable()); 1443af6ab5fSopenharmony_ci 1453af6ab5fSopenharmony_ci if (propType->Variable()->HasFlag(binder::VariableFlags::READONLY)) { 1463af6ab5fSopenharmony_ci checker->ThrowTypeError("The operand of a delete operator cannot be a readonly property.", 1473af6ab5fSopenharmony_ci argument_->Start()); 1483af6ab5fSopenharmony_ci } 1493af6ab5fSopenharmony_ci 1503af6ab5fSopenharmony_ci if (!propType->Variable()->HasFlag(binder::VariableFlags::OPTIONAL)) { 1513af6ab5fSopenharmony_ci checker->ThrowTypeError("The operand of a delete operator must be a optional.", argument_->Start()); 1523af6ab5fSopenharmony_ci } 1533af6ab5fSopenharmony_ci 1543af6ab5fSopenharmony_ci return checker->GlobalBooleanType(); 1553af6ab5fSopenharmony_ci } 1563af6ab5fSopenharmony_ci 1573af6ab5fSopenharmony_ci if (argument_->IsLiteral()) { 1583af6ab5fSopenharmony_ci const ir::Literal *lit = argument_->AsLiteral(); 1593af6ab5fSopenharmony_ci 1603af6ab5fSopenharmony_ci if (lit->IsNumberLiteral()) { 1613af6ab5fSopenharmony_ci auto numberValue = lit->AsNumberLiteral()->Number<double>(); 1623af6ab5fSopenharmony_ci if (operator_ == lexer::TokenType::PUNCTUATOR_PLUS) { 1633af6ab5fSopenharmony_ci return checker->CreateNumberLiteralType(numberValue); 1643af6ab5fSopenharmony_ci } 1653af6ab5fSopenharmony_ci 1663af6ab5fSopenharmony_ci if (operator_ == lexer::TokenType::PUNCTUATOR_MINUS) { 1673af6ab5fSopenharmony_ci return checker->CreateNumberLiteralType(-numberValue); 1683af6ab5fSopenharmony_ci } 1693af6ab5fSopenharmony_ci } else if (lit->IsBigIntLiteral() && operator_ == lexer::TokenType::PUNCTUATOR_MINUS) { 1703af6ab5fSopenharmony_ci return checker->CreateBigintLiteralType(lit->AsBigIntLiteral()->Str(), true); 1713af6ab5fSopenharmony_ci } 1723af6ab5fSopenharmony_ci } 1733af6ab5fSopenharmony_ci 1743af6ab5fSopenharmony_ci switch (operator_) { 1753af6ab5fSopenharmony_ci case lexer::TokenType::PUNCTUATOR_PLUS: 1763af6ab5fSopenharmony_ci case lexer::TokenType::PUNCTUATOR_MINUS: 1773af6ab5fSopenharmony_ci case lexer::TokenType::PUNCTUATOR_TILDE: { 1783af6ab5fSopenharmony_ci checker->CheckNonNullType(operandType, Start()); 1793af6ab5fSopenharmony_ci // TODO(aszilagyi): check Symbol like types 1803af6ab5fSopenharmony_ci 1813af6ab5fSopenharmony_ci if (operator_ == lexer::TokenType::PUNCTUATOR_PLUS) { 1823af6ab5fSopenharmony_ci if (checker::Checker::MaybeTypeOfKind(operandType, checker::TypeFlag::BIGINT_LIKE)) { 1833af6ab5fSopenharmony_ci checker->ThrowTypeError({"Operator '+' cannot be applied to type '", operandType, "'"}, Start()); 1843af6ab5fSopenharmony_ci } 1853af6ab5fSopenharmony_ci 1863af6ab5fSopenharmony_ci return checker->GlobalNumberType(); 1873af6ab5fSopenharmony_ci } 1883af6ab5fSopenharmony_ci 1893af6ab5fSopenharmony_ci return checker->GetUnaryResultType(operandType); 1903af6ab5fSopenharmony_ci } 1913af6ab5fSopenharmony_ci case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: { 1923af6ab5fSopenharmony_ci checker->CheckTruthinessOfType(operandType, Start()); 1933af6ab5fSopenharmony_ci auto facts = operandType->GetTypeFacts(); 1943af6ab5fSopenharmony_ci if (facts & checker::TypeFacts::TRUTHY) { 1953af6ab5fSopenharmony_ci return checker->GlobalFalseType(); 1963af6ab5fSopenharmony_ci } 1973af6ab5fSopenharmony_ci 1983af6ab5fSopenharmony_ci if (facts & checker::TypeFacts::FALSY) { 1993af6ab5fSopenharmony_ci return checker->GlobalTrueType(); 2003af6ab5fSopenharmony_ci } 2013af6ab5fSopenharmony_ci 2023af6ab5fSopenharmony_ci return checker->GlobalBooleanType(); 2033af6ab5fSopenharmony_ci } 2043af6ab5fSopenharmony_ci default: { 2053af6ab5fSopenharmony_ci UNREACHABLE(); 2063af6ab5fSopenharmony_ci } 2073af6ab5fSopenharmony_ci } 2083af6ab5fSopenharmony_ci 2093af6ab5fSopenharmony_ci return nullptr; 2103af6ab5fSopenharmony_ci} 2113af6ab5fSopenharmony_ci 2123af6ab5fSopenharmony_civoid UnaryExpression::UpdateSelf(const NodeUpdater &cb, [[maybe_unused]] binder::Binder *binder) 2133af6ab5fSopenharmony_ci{ 2143af6ab5fSopenharmony_ci argument_ = std::get<ir::AstNode *>(cb(argument_))->AsExpression(); 2153af6ab5fSopenharmony_ci} 2163af6ab5fSopenharmony_ci 2173af6ab5fSopenharmony_ci} // namespace panda::es2panda::ir 218