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 "lexenv.h"
17
18#include "varbinder/variable.h"
19#include "compiler/core/envScope.h"
20#include "compiler/core/pandagen.h"
21#include "compiler/core/moduleContext.h"
22#include "ir/expressions/identifier.h"
23
24namespace ark::es2panda::compiler {
25// Helpers
26
27static bool CheckTdz(const ir::AstNode *node)
28{
29    return node->IsIdentifier() && node->AsIdentifier()->IsTdz();
30}
31
32static void CheckConstAssignment(PandaGen *pg, const ir::AstNode *node, varbinder::Variable *variable)
33{
34    if (!variable->Declaration()->IsConstDecl()) {
35        return;
36    }
37
38    pg->ThrowConstAssignment(node, variable->Name());
39}
40
41// VirtualLoadVar
42
43static void ExpandLoadLexVar(PandaGen *pg, const ir::AstNode *node, const varbinder::ConstScopeFindResult &result)
44{
45    if (result.variable->Declaration()->IsVarDecl()) {
46        pg->LoadLexicalVar(node, result.lexLevel, result.variable->AsLocalVariable()->LexIdx());
47    } else {
48        pg->LoadLexical(node, result.name, result.lexLevel, result.variable->AsLocalVariable()->LexIdx());
49    }
50}
51
52static void ExpandLoadNormalVar(PandaGen *pg, const ir::AstNode *node, const varbinder::ConstScopeFindResult &result)
53{
54    auto *local = result.variable->AsLocalVariable();
55
56    if (CheckTdz(node)) {
57        pg->ThrowTdz(node, local->Name());
58    } else {
59        pg->LoadAccumulator(node, local->Vreg());
60    }
61}
62
63void VirtualLoadVar::Expand(PandaGen *pg, const ir::AstNode *node, const varbinder::ConstScopeFindResult &result)
64{
65    if (result.variable->LexicalBound()) {
66        ExpandLoadLexVar(pg, node, result);
67    } else {
68        ExpandLoadNormalVar(pg, node, result);
69    }
70}
71
72// VirtualStoreVar
73
74static void StoreLocalExport(PandaGen *pg, const ir::AstNode *node, varbinder::Variable *variable)
75{
76    if (!variable->HasFlag(varbinder::VariableFlags::LOCAL_EXPORT) || !pg->Scope()->IsModuleScope()) {
77        return;
78    }
79
80    auto range = pg->Scope()->AsModuleScope()->LocalExports().equal_range(variable);
81
82    for (auto it = range.first; it != range.second; ++it) {
83        if (it->second != "default") {
84            pg->StoreModuleVar(node, it->second);
85        }
86    }
87}
88
89static void ExpandStoreLexVar(PandaGen *pg, const ir::AstNode *node, const varbinder::ConstScopeFindResult &result,
90                              bool isDecl)
91{
92    varbinder::LocalVariable *local = result.variable->AsLocalVariable();
93
94    const auto *decl = result.variable->Declaration();
95
96    if (decl->IsLetOrConstDecl() && !isDecl) {
97        if (decl->IsConstDecl()) {
98            pg->ThrowConstAssignment(node, local->Name());
99        }
100
101        pg->StoreLexical(node, result.name, result.lexLevel, local->LexIdx());
102    } else {
103        pg->StoreLexicalVar(node, result.lexLevel, local->LexIdx());
104    }
105
106    StoreLocalExport(pg, node, local);
107}
108
109static void ExpandStoreNormalVar(PandaGen *pg, const ir::AstNode *node, const varbinder::ConstScopeFindResult &result,
110                                 bool isDecl)
111{
112    auto *local = result.variable->AsLocalVariable();
113    VReg localReg = local->Vreg();
114
115    if (!isDecl) {
116        if (CheckTdz(node)) {
117            pg->ThrowTdz(node, local->Name());
118        }
119
120        CheckConstAssignment(pg, node, local);
121    }
122
123    pg->StoreAccumulator(node, localReg);
124    StoreLocalExport(pg, node, local);
125}
126
127void VirtualStoreVar::Expand(PandaGen *pg, const ir::AstNode *node, const varbinder::ConstScopeFindResult &result,
128                             bool isDecl)
129{
130    if (result.variable->LexicalBound()) {
131        ExpandStoreLexVar(pg, node, result, isDecl);
132    } else {
133        ExpandStoreNormalVar(pg, node, result, isDecl);
134    }
135}
136}  // namespace ark::es2panda::compiler
137