• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 #include "lateInitialization.h"
17 
18 #include <sstream>
19 
20 #include "checker/ETSchecker.h"
21 #include "compiler/lowering/util.h"
22 #include "ir/ets/etsUnionType.h"
23 
24 namespace ark::es2panda::compiler {
25 
26 using AstNodePtr = ir::AstNode *;
27 
TransformerClassProperty(public_lib::Context * ctx,ir::ClassProperty * property)28 ir::ClassProperty *TransformerClassProperty(public_lib::Context *ctx, ir::ClassProperty *property)
29 {
30     auto checker = ctx->checker->AsETSChecker();
31     auto allocator = ctx->allocator;
32     // Note: This code will be excluded after primitive type refactoring
33     if (property->TsType()->IsETSPrimitiveType()) {
34         return property;
35     }
36 
37     auto annotationType = checker->CreateETSUnionType({property->TsType(), checker->GlobalETSUndefinedType()});
38     auto typeAnnotation = allocator->New<ir::OpaqueTypeNode>(annotationType, allocator);
39     ES2PANDA_ASSERT(typeAnnotation);
40     typeAnnotation->SetParent(property);
41     typeAnnotation->SetTsType(annotationType);
42     property->SetTypeAnnotation(typeAnnotation);
43     property->SetTsType(annotationType);
44     property->Key()->Variable()->SetTsType(annotationType);
45     return property;
46 }
47 
TransformerMemberExpression(ir::MemberExpression * memberExpr,public_lib::Context * ctx)48 static ir::AstNode *TransformerMemberExpression(ir::MemberExpression *memberExpr, public_lib::Context *ctx)
49 {
50     auto checker = ctx->checker->AsETSChecker();
51     auto parser = ctx->parser->AsETSParser();
52     auto varbinder = ctx->checker->VarBinder()->AsETSBinder();
53     auto allocator = ctx->Allocator();
54     auto originalType = memberExpr->TsType();
55     // Note: This code will be excluded after primitive type refactoring
56     if (originalType->IsETSPrimitiveType()) {
57         return memberExpr;
58     }
59 
60     auto parent = memberExpr->Parent();
61     if (parent->IsAssignmentExpression() && parent->AsAssignmentExpression()->Left() == memberExpr &&
62         parent->AsAssignmentExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
63         auto maybeBoxType = checker->MaybeBoxType(originalType);
64         memberExpr->SetTsType(maybeBoxType);
65         parent->AsAssignmentExpression()->SetTsType(maybeBoxType);
66         return memberExpr;
67     }
68 
69     ArenaVector<ir::Statement *> blockStatements(allocator->Adapter());
70     std::stringstream ss;
71     auto name = GenName(allocator);
72     auto *typeNode = allocator->New<ir::OpaqueTypeNode>(originalType, allocator);
73 
74     blockStatements.push_back(parser->CreateFormattedStatement("let @@I1 = @@E2", name, memberExpr));
75     ss << "if (@@I1 === undefined) { throw new NullPointerError(); }";
76     blockStatements.push_back(parser->CreateFormattedStatement(ss.str(), name));
77     blockStatements.push_back(parser->CreateFormattedStatement("@@I1 as @@T2", name, typeNode));
78     auto *res = util::NodeAllocator::ForceSetParent<ir::BlockExpression>(allocator, std::move(blockStatements));
79     ES2PANDA_ASSERT(res);
80     res->SetParent(parent);
81     Recheck(ctx->phaseManager, varbinder, checker, res);
82 
83     return res;
84 }
85 
PerformForModule(public_lib::Context * ctx,parser::Program * program)86 bool LateInitializationConvert::PerformForModule(public_lib::Context *ctx, parser::Program *program)
87 {
88     program->Ast()->TransformChildrenRecursively(
89         [ctx](ir::AstNode *node) -> AstNodePtr {
90             if (node->IsClassProperty() && node->IsDefinite()) {
91                 return TransformerClassProperty(ctx, node->AsClassProperty());
92             }
93             return node;
94         },
95         Name());
96 
97     program->Ast()->TransformChildrenRecursively(
98         [ctx](ir::AstNode *node) -> AstNodePtr {
99             if (node->IsMemberExpression()) {
100                 auto property = node->AsMemberExpression()->Property();
101                 if (!(property->IsIdentifier() && property->AsIdentifier()->Variable() != nullptr)) {
102                     return node;
103                 }
104                 auto decl = property->AsIdentifier()->Variable()->Declaration();
105                 if (decl != nullptr && decl->Node() != nullptr && decl->Node()->IsClassProperty() &&
106                     decl->Node()->IsDefinite()) {
107                     return TransformerMemberExpression(node->AsMemberExpression(), ctx);
108                 }
109             }
110             return node;
111         },
112         Name());
113 
114     return true;
115 }
116 }  // namespace ark::es2panda::compiler
117