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