* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "lexenv.h"
#include <compiler/core/pandagen.h>
#include <ir/base/classDefinition.h>
#include <ir/base/scriptFunction.h>
namespace panda::es2panda::compiler {
static bool CheckTdz(const ir::AstNode *node)
{
return node->IsIdentifier() && node->AsIdentifier()->IsTdz();
}
static void CheckConstAssignment(PandaGen *pg, const ir::AstNode *node, binder::Variable *variable)
{
if (!variable->Declaration()->IsConstDecl()) {
return;
}
pg->ThrowConstAssignment(node, variable->Name());
}
static void ExpandLoadLexVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result)
{
* Instruction ldsendableclass is generated when use sendable class inside itself, except static initializer.
* Because static initializer is not defined with instruction definesendableclass.
*/
auto decl = result.variable->Declaration();
if (decl->IsSendableClassDecl()) {
auto classDef = decl->Node()->AsClassDefinition();
if (classDef == util::Helpers::GetContainingSendableClass(node) &&
!util::Helpers::IsChildScope(classDef->StaticInitializer()->Function()->Scope(), pg->TopScope())) {
pg->LoadSendableClass(node, result.lexLevel);
return;
}
}
auto *local = result.variable->AsLocalVariable();
if (local->InSendableEnv()) {
pg->LoadSendableVar(node, result.sendableLevel, local->LexIdx());
} else {
pg->LoadLexicalVar(node, result.lexLevel, local->LexIdx(), result.variable->Name());
}
if (decl->IsLetOrConstOrClassDecl()) {
pg->ThrowUndefinedIfHole(node, result.variable->Name());
}
}
static void ExpandLoadNormalVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result)
{
auto *local = result.variable->AsLocalVariable();
if (CheckTdz(node)) {
pg->LoadConst(node, Constant::JS_HOLE);
pg->ThrowUndefinedIfHole(node, local->Name());
} else {
pg->LoadAccumulator(node, local->Vreg());
}
}
void VirtualLoadVar::Expand(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result)
{
if (result.variable->LexicalBound()) {
ExpandLoadLexVar(pg, node, result);
} else {
ExpandLoadNormalVar(pg, node, result);
}
}
static void ExpandStoreLexVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDecl)
{
binder::LocalVariable *local = result.variable->AsLocalVariable();
const auto *decl = result.variable->Declaration();
if (decl->IsLetOrConstOrClassDecl() && !isDecl) {
RegScope rs(pg);
VReg valueReg = pg->AllocReg();
pg->StoreAccumulator(node, valueReg);
ExpandLoadLexVar(pg, node, result);
if (decl->IsConstDecl()) {
pg->ThrowConstAssignment(node, local->Name());
}
pg->LoadAccumulator(node, valueReg);
}
if (local->InSendableEnv()) {
pg->StoreSendableVar(node, result.sendableLevel, local->LexIdx());
return;
}
pg->StoreLexicalVar(node, result.lexLevel, local->LexIdx(), local);
}
static void ExpandStoreNormalVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result,
bool isDecl)
{
auto *local = result.variable->AsLocalVariable();
VReg localReg = local->Vreg();
if (!isDecl) {
if (CheckTdz(node)) {
pg->LoadConst(node, Constant::JS_HOLE);
pg->ThrowUndefinedIfHole(node, local->Name());
}
CheckConstAssignment(pg, node, local);
}
pg->StoreAccumulator(node, localReg);
}
void VirtualStoreVar::Expand(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDecl)
{
if (result.variable->LexicalBound()) {
ExpandStoreLexVar(pg, node, result, isDecl);
} else {
ExpandStoreNormalVar(pg, node, result, isDecl);
}
}
}