1/**
2 * Copyright (c) 2021 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 "lexenv.h"
17
18#include <binder/variable.h>
19#include <compiler/core/compilerContext.h>
20#include <compiler/core/envScope.h>
21#include <compiler/core/pandagen.h>
22#include <ir/base/classDefinition.h>
23#include <ir/base/scriptFunction.h>
24#include <ir/expressions/identifier.h>
25
26namespace panda::es2panda::compiler {
27
28// Helpers
29
30static bool CheckTdz(const ir::AstNode *node)
31{
32    return node->IsIdentifier() && node->AsIdentifier()->IsTdz();
33}
34
35static void CheckConstAssignment(PandaGen *pg, const ir::AstNode *node, binder::Variable *variable)
36{
37    if (!variable->Declaration()->IsConstDecl()) {
38        return;
39    }
40
41    pg->ThrowConstAssignment(node, variable->Name());
42}
43
44// VirtualLoadVar
45
46static void ExpandLoadLexVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result)
47{
48    /**
49     *  Instruction ldsendableclass is generated when use sendable class inside itself, except static initializer.
50     *  Because static initializer is not defined with instruction definesendableclass.
51     */
52    auto decl = result.variable->Declaration();
53    if (decl->IsSendableClassDecl()) {
54        auto classDef = decl->Node()->AsClassDefinition();
55        if (classDef == util::Helpers::GetContainingSendableClass(node) &&
56            !util::Helpers::IsChildScope(classDef->StaticInitializer()->Function()->Scope(), pg->TopScope())) {
57            pg->LoadSendableClass(node, result.lexLevel);
58            return;
59        }
60    }
61
62    auto *local = result.variable->AsLocalVariable();
63    if (local->InSendableEnv()) {
64        pg->LoadSendableVar(node, result.sendableLevel, local->LexIdx());
65    } else {
66        pg->LoadLexicalVar(node, result.lexLevel, local->LexIdx(), result.variable->Name());
67    }
68
69    if (decl->IsLetOrConstOrClassDecl()) {
70        pg->ThrowUndefinedIfHole(node, result.variable->Name());
71    }
72}
73
74static void ExpandLoadNormalVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result)
75{
76    auto *local = result.variable->AsLocalVariable();
77
78    if (CheckTdz(node)) {
79        pg->LoadConst(node, Constant::JS_HOLE);
80        pg->ThrowUndefinedIfHole(node, local->Name());
81    } else {
82        pg->LoadAccumulator(node, local->Vreg());
83    }
84}
85
86void VirtualLoadVar::Expand(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result)
87{
88    if (result.variable->LexicalBound()) {
89        ExpandLoadLexVar(pg, node, result);
90    } else {
91        ExpandLoadNormalVar(pg, node, result);
92    }
93}
94
95// VirtualStoreVar
96
97static void ExpandStoreLexVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDecl)
98{
99    binder::LocalVariable *local = result.variable->AsLocalVariable();
100
101    const auto *decl = result.variable->Declaration();
102
103    if (decl->IsLetOrConstOrClassDecl() && !isDecl) {
104        RegScope rs(pg);
105
106        VReg valueReg = pg->AllocReg();
107        pg->StoreAccumulator(node, valueReg);
108
109        ExpandLoadLexVar(pg, node, result);
110
111        if (decl->IsConstDecl()) {
112            pg->ThrowConstAssignment(node, local->Name());
113        }
114
115        pg->LoadAccumulator(node, valueReg);
116    }
117
118    if (local->InSendableEnv()) {
119        pg->StoreSendableVar(node, result.sendableLevel, local->LexIdx());
120        return;
121    }
122    pg->StoreLexicalVar(node, result.lexLevel, local->LexIdx(), local);
123}
124
125static void ExpandStoreNormalVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result,
126                                 bool isDecl)
127{
128    auto *local = result.variable->AsLocalVariable();
129    VReg localReg = local->Vreg();
130
131    if (!isDecl) {
132        if (CheckTdz(node)) {
133            pg->LoadConst(node, Constant::JS_HOLE);
134            pg->ThrowUndefinedIfHole(node, local->Name());
135        }
136
137        CheckConstAssignment(pg, node, local);
138    }
139
140    pg->StoreAccumulator(node, localReg);
141}
142
143void VirtualStoreVar::Expand(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDecl)
144{
145    if (result.variable->LexicalBound()) {
146        ExpandStoreLexVar(pg, node, result, isDecl);
147    } else {
148        ExpandStoreNormalVar(pg, node, result, isDecl);
149    }
150}
151
152}  // namespace panda::es2panda::compiler
153