1 /**
2 * Copyright (c) 2021-2025 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 #ifndef ES2PANDA_VARBINDER_VARBINDER_H
17 #define ES2PANDA_VARBINDER_VARBINDER_H
18
19 #include "lexer/token/sourceLocation.h"
20 #include "varbinder/scope.h"
21
22 namespace ark::es2panda::parser {
23 class Program;
24 enum class ScriptKind;
25 } // namespace ark::es2panda::parser
26
27 namespace ark::es2panda::ir {
28 class AstNode;
29 class BlockStatement;
30 class CatchClause;
31 class ClassDefinition;
32 class Expression;
33 class ForUpdateStatement;
34 class Identifier;
35 class ScriptFunction;
36 class Statement;
37 class VariableDeclarator;
38 class TSFunctionType;
39 class ThisExpression;
40 class MemberExpression;
41 class ClassStaticBlock;
42 class Identifier;
43 class TSTypeAliasDeclaration;
44 class ClassProperty;
45 } // namespace ark::es2panda::ir
46
47 namespace ark::es2panda::public_lib {
48 struct Context;
49 } // namespace ark::es2panda::public_lib
50
51 namespace ark::es2panda::varbinder {
52 class ETSBinder;
53
54 class VarBinder {
55 public:
VarBinder(ArenaAllocator * allocator)56 explicit VarBinder(ArenaAllocator *allocator) : allocator_(allocator), functionScopes_(allocator_->Adapter()) {}
57
58 VarBinder() = delete;
59 NO_COPY_SEMANTIC(VarBinder);
60 NO_MOVE_SEMANTIC(VarBinder);
61 virtual ~VarBinder() = default;
62
63 void InitTopScope();
64 virtual void IdentifierAnalysis();
65
66 template <typename T, typename... Args>
67 T *AddDecl(const lexer::SourcePosition &pos, Args &&...args);
68
69 template <typename T, typename... Args>
70 T *AddTsDecl(const lexer::SourcePosition &pos, Args &&...args);
71
72 template <typename T, typename... Args>
73 std::tuple<T *, varbinder::Variable *> NewVarDecl(const lexer::SourcePosition &pos, Args &&...args);
74
75 Variable *AddParamDecl(ir::Expression *param);
76
SetProgram(parser::Program * program)77 void SetProgram(parser::Program *program) noexcept
78 {
79 program_ = program;
80 }
81
Program()82 [[nodiscard]] parser::Program *Program() noexcept
83 {
84 return program_;
85 }
86
Program()87 [[nodiscard]] const parser::Program *Program() const
88 {
89 ES2PANDA_ASSERT(program_);
90 return program_;
91 }
92
SetContext(public_lib::Context * context)93 void SetContext(public_lib::Context *context)
94 {
95 context_ = context;
96 }
97
GetContext()98 [[nodiscard]] public_lib::Context *GetContext() const
99 {
100 ES2PANDA_ASSERT(context_);
101 return context_;
102 }
103
SetGenStdLib(bool genStdLib)104 void SetGenStdLib(bool genStdLib) noexcept
105 {
106 genStdLib_ = genStdLib;
107 }
108
IsGenStdLib()109 [[nodiscard]] bool IsGenStdLib() noexcept
110 {
111 return genStdLib_;
112 }
113
GetScope()114 [[nodiscard]] Scope *GetScope() const noexcept
115 {
116 return scope_;
117 }
118
ResetAllScopes(GlobalScope * topScope,VariableScope * varScope,Scope * scope)119 void ResetAllScopes(GlobalScope *topScope, VariableScope *varScope, Scope *scope) noexcept
120 {
121 topScope_ = topScope;
122 varScope_ = varScope;
123 scope_ = scope;
124 }
125
ResetTopScope(GlobalScope * topScope)126 void ResetTopScope(GlobalScope *topScope)
127 {
128 ES2PANDA_ASSERT(topScope_ == scope_);
129 topScope_ = topScope;
130 varScope_ = topScope_;
131 scope_ = topScope_;
132 }
133
TopScope()134 [[nodiscard]] GlobalScope *TopScope() const noexcept
135 {
136 return topScope_;
137 }
138
VarScope()139 [[nodiscard]] VariableScope *VarScope() const noexcept
140 {
141 return varScope_;
142 }
143
IsETSBinder()144 [[nodiscard]] bool IsETSBinder() const noexcept
145 {
146 return Extension() == ScriptExtension::ETS;
147 }
148
AsETSBinder()149 [[nodiscard]] const ETSBinder *AsETSBinder() const
150 {
151 ES2PANDA_ASSERT(Extension() == ScriptExtension::ETS);
152 return reinterpret_cast<const ETSBinder *>(this);
153 }
154
AsETSBinder()155 [[nodiscard]] ETSBinder *AsETSBinder()
156 {
157 ES2PANDA_ASSERT(Extension() == ScriptExtension::ETS);
158 return reinterpret_cast<ETSBinder *>(this);
159 }
160
161 void ThrowPrivateFieldMismatch(const lexer::SourcePosition &pos, const util::StringView &name) const;
162 void ThrowRedeclaration(const lexer::SourcePosition &pos, const util::StringView &name, DeclType declType) const;
163 void ThrowLocalRedeclaration(const lexer::SourcePosition &pos, const util::StringView &name) const;
164 void ThrowUnresolvableType(const lexer::SourcePosition &pos, const util::StringView &name) const;
165 void ThrowTDZ(const lexer::SourcePosition &pos, const util::StringView &name) const;
166 void ThrowInvalidCapture(const lexer::SourcePosition &pos, const util::StringView &name) const;
ThrowError(const lexer::SourcePosition & pos,const diagnostic::DiagnosticKind & kind)167 void ThrowError(const lexer::SourcePosition &pos, const diagnostic::DiagnosticKind &kind) const
168 {
169 ThrowError(pos, kind, util::DiagnosticMessageParams {});
170 }
171 virtual void ThrowError(const lexer::SourcePosition &pos, const diagnostic::DiagnosticKind &kind,
172 const util::DiagnosticMessageParams ¶ms) const;
173 virtual bool IsGlobalIdentifier(const util::StringView &str) const;
174
175 void PropagateDirectEval() const;
176
177 template <typename T>
178 friend class LexicalScope;
179
Allocator()180 [[nodiscard]] ArenaAllocator *Allocator() const noexcept
181 {
182 return allocator_;
183 }
184
Functions()185 [[nodiscard]] const ArenaVector<FunctionScope *> &Functions() const noexcept
186 {
187 return functionScopes_;
188 }
189
Functions()190 [[nodiscard]] ArenaVector<FunctionScope *> &Functions() noexcept
191 {
192 return functionScopes_;
193 }
194
Extension()195 [[nodiscard]] virtual ScriptExtension Extension() const noexcept
196 {
197 return ScriptExtension::JS;
198 }
199
BindingOptions()200 [[nodiscard]] virtual ResolveBindingOptions BindingOptions() const noexcept
201 {
202 return ResolveBindingOptions::BINDINGS;
203 }
204
205 LocalVariable *AddMandatoryParam(const std::string_view &name);
206
207 inline static constexpr std::string_view const FUNCTION_ARGUMENTS = "arguments";
208 inline static constexpr std::string_view const MANDATORY_PARAM_FUNC = "=f";
209 inline static constexpr std::string_view const MANDATORY_PARAM_NEW_TARGET = "=nt";
210 inline static constexpr std::string_view const MANDATORY_PARAM_THIS = "=t";
211
212 inline static constexpr std::uint32_t const MANDATORY_PARAM_FUNC_REG = 0U;
213 inline static constexpr std::uint32_t const MANDATORY_PARAMS_NUMBER = 3U;
214
215 inline static constexpr std::string_view const LEXICAL_MANDATORY_PARAM_FUNC = "!f";
216 inline static constexpr std::string_view const LEXICAL_MANDATORY_PARAM_NEW_TARGET = "!nt";
217 inline static constexpr std::string_view const LEXICAL_MANDATORY_PARAM_THIS = "!t";
218
219 inline static constexpr std::string_view const LEXICAL_CONTEXT_PARAM = "=eval";
220 inline static constexpr std::string_view const MAIN = "main";
221 inline static constexpr std::uint32_t const LEXICAL_CONTEXT_PARAM_REG = MANDATORY_PARAMS_NUMBER;
222 inline static constexpr std::string_view const STAR_IMPORT = "*";
223
224 void ResolveReferenceDoWhileHelper(ir::AstNode *childNode);
225 void ResolveReferenceWhileHelper(ir::AstNode *childNode);
226 void ResolveReference(ir::AstNode *childNode);
227
228 protected:
229 template <size_t N>
230 using MandatoryParams = std::array<std::string_view, N>;
231
232 static constexpr MandatoryParams<MANDATORY_PARAMS_NUMBER> FUNCTION_MANDATORY_PARAMS = {
233 MANDATORY_PARAM_FUNC, MANDATORY_PARAM_NEW_TARGET, MANDATORY_PARAM_THIS};
234
235 static constexpr MandatoryParams<MANDATORY_PARAMS_NUMBER + 1> EVAL_SCRIPT_MANDATORY_PARAMS = {
236 MANDATORY_PARAM_FUNC, MANDATORY_PARAM_NEW_TARGET, MANDATORY_PARAM_THIS, LEXICAL_CONTEXT_PARAM};
237
238 static constexpr MandatoryParams<MANDATORY_PARAMS_NUMBER> ARROW_MANDATORY_PARAMS = {
239 MANDATORY_PARAM_FUNC, LEXICAL_MANDATORY_PARAM_NEW_TARGET, LEXICAL_MANDATORY_PARAM_THIS};
240
241 static constexpr MandatoryParams<MANDATORY_PARAMS_NUMBER> CTOR_ARROW_MANDATORY_PARAMS = {
242 LEXICAL_MANDATORY_PARAM_FUNC, LEXICAL_MANDATORY_PARAM_NEW_TARGET, LEXICAL_MANDATORY_PARAM_THIS};
243
244 void LookUpMandatoryReferences(const FunctionScope *funcScope, bool needLexicalFuncObj);
245 template <size_t N>
246 void AddMandatoryParams(const MandatoryParams<N> ¶ms);
247 void AddMandatoryParams();
248 void LookupReference(const util::StringView &name);
249 void InstantiateArguments();
250 [[nodiscard]] bool InstantiateArgumentsImpl(Scope **scope, Scope *iter, const ir::AstNode *node);
251 void InstantiatePrivateContext(const ir::Identifier *ident) const;
252 void BuildVarDeclarator(ir::VariableDeclarator *varDecl);
253 void BuildVarDeclaratorId(ir::AstNode *childNode);
254 void BuildForUpdateLoop(ir::ForUpdateStatement *forUpdateStmt);
255 void BuildForInOfLoop(varbinder::LoopScope *loopScope, ir::AstNode *left, ir::Expression *right,
256 ir::Statement *body);
257 void BuildCatchClause(ir::CatchClause *catchClauseStmt);
258 void BuildTypeAliasDeclaration(ir::TSTypeAliasDeclaration *const typeAliasDecl);
259 void ResolveReferences(const ir::AstNode *parent);
260 void VisitScriptFunctionWithPotentialTypeParams(ir::ScriptFunction *func);
261 void VisitScriptFunction(ir::ScriptFunction *func);
262 [[nodiscard]] util::StringView BuildFunctionName(util::StringView name, uint32_t idx);
263
264 void AddCompilableFunctionScope(varbinder::FunctionScope *funcScope);
265
266 void InitializeClassBinding(ir::ClassDefinition *classDef);
267 void InitializeClassIdent(ir::ClassDefinition *classDef);
268
269 virtual void LookupIdentReference(ir::Identifier *ident);
HandleCustomNodes(ir::AstNode * childNode)270 virtual void HandleCustomNodes(ir::AstNode *childNode)
271 {
272 ResolveReferences(childNode);
273 }
BuildSignatureDeclarationBaseParams(ir::AstNode * typeNode)274 virtual void BuildSignatureDeclarationBaseParams([[maybe_unused]] ir::AstNode *typeNode) {};
275 virtual void BuildClassDefinition(ir::ClassDefinition *classDef);
276 virtual void BuildClassProperty(const ir::ClassProperty *prop);
277 [[nodiscard]] virtual bool BuildInternalName(ir::ScriptFunction *scriptFunc);
278 virtual void AddCompilableFunction(ir::ScriptFunction *func);
279
CleanUp()280 virtual void CleanUp()
281 {
282 topScope_ = nullptr;
283 scope_ = nullptr;
284 varScope_ = nullptr;
285 functionScopes_.clear();
286 }
287
288 private:
289 parser::Program *program_ {};
290 ArenaAllocator *allocator_ {};
291 public_lib::Context *context_ {};
292 GlobalScope *topScope_ {};
293 Scope *scope_ {};
294 VariableScope *varScope_ {};
295 ArenaVector<FunctionScope *> functionScopes_;
296 ResolveBindingOptions bindingOptions_ {};
297 bool genStdLib_ {false};
298 };
299
300 template <typename T>
301 class LexicalScope {
302 public:
303 template <typename... Args>
LexicalScope(VarBinder * varbinder,Args &&...args)304 explicit LexicalScope(VarBinder *varbinder, Args &&...args)
305 : LexicalScope(
306 varbinder->Allocator()->New<T>(varbinder->Allocator(), varbinder->scope_, std::forward<Args>(args)...),
307 varbinder)
308 {
309 }
310
GetScope()311 T *GetScope() const
312 {
313 return scope_;
314 }
315
~LexicalScope()316 ~LexicalScope()
317 {
318 ES2PANDA_ASSERT(varbinder_);
319 varbinder_->scope_ = prevScope_;
320 varbinder_->varScope_ = prevVarScope_;
321 }
322
323 [[nodiscard]] static LexicalScope<T> Enter(VarBinder *varbinder, T *scope, bool checkEval = true)
324 {
325 LexicalScope<T> lexScope(scope, varbinder);
326 if (!checkEval || varbinder->Extension() == ScriptExtension::TS) {
327 return lexScope;
328 }
329
330 // NOLINTNEXTLINE(readability-braces-around-statements)
331 if constexpr (std::is_same_v<T, FunctionParamScope>) {
332 varbinder->varScope_ = scope->GetFunctionScope();
333 varbinder->varScope_->CheckDirectEval(varbinder->context_);
334 // NOLINTNEXTLINE(readability-braces-around-statements,readability-misleading-indentation)
335 } else if constexpr (std::is_same_v<T, FunctionScope>) {
336 varbinder->varScope_ = scope;
337 varbinder->varScope_->CheckDirectEval(varbinder->context_);
338 // NOLINTNEXTLINE(readability-braces-around-statements,readability-misleading-indentation)
339 } else if constexpr (std::is_same_v<T, LoopScope>) {
340 if (scope->IsLoopScope()) {
341 varbinder->varScope_ = scope;
342 varbinder->varScope_->CheckDirectEval(varbinder->context_);
343 }
344 // NOLINTNEXTLINE(readability-braces-around-statements,readability-misleading-indentation)
345 } else if constexpr (std::is_same_v<T, LoopDeclarationScope>) {
346 if (scope->IsLoopDeclarationScope()) {
347 varbinder->varScope_ = scope;
348 varbinder->varScope_->CheckDirectEval(varbinder->context_);
349 }
350 }
351
352 return lexScope;
353 }
354
355 DEFAULT_MOVE_SEMANTIC(LexicalScope);
356
357 private:
358 NO_COPY_SEMANTIC(LexicalScope);
359
LexicalScope(T * scope,VarBinder * varbinder)360 explicit LexicalScope(T *scope, VarBinder *varbinder)
361 : varbinder_(varbinder), scope_(scope), prevScope_(varbinder->scope_), prevVarScope_(varbinder->varScope_)
362 {
363 varbinder_->scope_ = scope_;
364 }
365
366 VarBinder *varbinder_ {};
367 T *scope_ {};
368 Scope *prevScope_ {};
369 VariableScope *prevVarScope_ {};
370 };
371
372 template <size_t N>
AddMandatoryParams(const MandatoryParams<N> & params)373 void VarBinder::AddMandatoryParams(const MandatoryParams<N> ¶ms)
374 {
375 ES2PANDA_ASSERT(scope_->IsFunctionVariableScope());
376
377 auto scopeCtx = LexicalScope<FunctionParamScope>::Enter(this, scope_->AsFunctionVariableScope()->ParamScope());
378
379 for (auto iter = params.rbegin(); iter != params.rend(); ++iter) {
380 AddMandatoryParam(*iter);
381 }
382 }
383
384 template <typename T, typename... Args>
AddTsDecl(const lexer::SourcePosition & pos,Args &&...args)385 T *VarBinder::AddTsDecl(const lexer::SourcePosition &pos, Args &&...args)
386 {
387 T *decl = Allocator()->New<T>(std::forward<Args>(args)...);
388
389 if (scope_->AddTsDecl(Allocator(), decl, Extension()) == nullptr) {
390 ThrowRedeclaration(pos, decl->Name(), decl->Type());
391 }
392
393 return decl;
394 }
395
396 template <typename T, typename... Args>
AddDecl(const lexer::SourcePosition & pos,Args &&...args)397 T *VarBinder::AddDecl(const lexer::SourcePosition &pos, Args &&...args)
398 {
399 T *decl = Allocator()->New<T>(std::forward<Args>(args)...);
400
401 if (scope_->AddDecl(Allocator(), decl, Extension()) == nullptr) {
402 ThrowRedeclaration(pos, decl->Name(), decl->Type());
403 }
404
405 return decl;
406 }
407
408 template <typename T, typename... Args>
NewVarDecl(const lexer::SourcePosition & pos,Args &&...args)409 std::tuple<T *, varbinder::Variable *> VarBinder::NewVarDecl(const lexer::SourcePosition &pos, Args &&...args)
410 {
411 T *decl = Allocator()->New<T>(std::forward<Args>(args)...);
412 auto *allocator = Allocator();
413 auto extension = Extension();
414 varbinder::Variable *var = scope_->AddDecl(allocator, decl, extension);
415
416 if (var == nullptr) {
417 ThrowRedeclaration(pos, decl->Name(), decl->Type());
418 var = scope_->FindLocal(decl->Name(), ResolveBindingOptions::BINDINGS);
419 }
420
421 ES2PANDA_ASSERT(var != nullptr);
422 return {decl, var};
423 }
424 } // namespace ark::es2panda::varbinder
425 #endif
426