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 <algorithm>
17 #include <cstddef>
18 #include <cstring>
19 #include <iostream>
20 #include <iterator>
21 #include <ostream>
22 #include <string>
23 #include "test/unit/plugin/util.h"
24 #include "public/es2panda_lib.h"
25
26 // NOLINTBEGIN
27 /*
28 * Covered C API List:
29 * AstNodeDumpEtsSrcConst
30 * AstNodeDumpJSONConst
31 * AstNodeForEach
32 * AstNodeIterateConst
33 * AstNodeRebind
34 * AstNodeSetParent
35 * BlockStatementSetStatements
36 * ContextErrorMessage
37 * ContextProgram
38 * ContextState
39 * CreateConfig
40 * CreateContextFromString
41 * CreateIdentifier1
42 * CreateVariableDeclarator1
43 * DestroyConfig
44 * DestroyContext
45 * FunctionDeclarationFunction
46 * IdentifierName
47 * IsFunctionDeclaration
48 * IsVariableDeclaration
49 * IsVariableDeclarator
50 * ProceedToState
51 * ProgramAst
52 * ScriptFunctionBody
53 * ScriptFunctionId
54 * UpdateVariableDeclaration
55 * VariableDeclarationDeclaratorsConst
56 * VariableDeclaratorId
57 * VariableDeclaratorIdConst
58 * VariableDeclaratorInit
59 */
60
61 static std::string expectResStr(R"(
62 {
63 "type": "Program",
64 "statements": [
65 {
66 "type": "FunctionDeclaration",
67 "function": {
68 "type": "ScriptFunction",
69 "id": {
70 "type": "Identifier",
71 "name": "main",
72 "decorators": []
73 },
74 "generator": false,
75 "async": false,
76 "expression": false,
77 "params": [],
78 "body": {
79 "type": "BlockStatement",
80 "statements": [
81 {
82 "type": "VariableDeclaration",
83 "declarations": [
84 {
85 "type": "VariableDeclarator",
86 "id": {
87 "type": "Identifier",
88 "name": "newVar",
89 "decorators": []
90 },
91 "init": {
92 "type": "NumberLiteral",
93 "value": 5
94 }
95 }
96 ],
97 "kind": "let"
98 }
99 ]
100 }
101 }
102 }
103 ]
104 }
105 )");
106 static es2panda_Impl *g_impl = nullptr;
107 static auto source = std::string("function main() { \nlet a = 5;\n }");
108
109 static es2panda_AstNode *letStatement = nullptr;
110 static es2panda_AstNode *mainScriptFunc = nullptr;
111 static es2panda_Context *g_ctx = nullptr;
112
113 es2panda_AstNode *parNode = nullptr;
114 es2panda_Context *newCtx = nullptr;
115
FindLet(es2panda_AstNode * ast)116 static void FindLet(es2panda_AstNode *ast)
117 {
118 if (!g_impl->IsVariableDeclaration(ast)) {
119 g_impl->AstNodeIterateConst(g_ctx, ast, FindLet);
120 return;
121 }
122 letStatement = ast;
123 }
124
FindMainDef(es2panda_AstNode * ast)125 static void FindMainDef(es2panda_AstNode *ast)
126 {
127 if (!g_impl->IsFunctionDeclaration(ast)) {
128 g_impl->AstNodeIterateConst(g_ctx, ast, FindMainDef);
129 return;
130 }
131 auto scriptFunc = g_impl->FunctionDeclarationFunction(g_ctx, ast);
132 if (scriptFunc == nullptr ||
133 std::string("main") != g_impl->IdentifierName(g_ctx, g_impl->ScriptFunctionId(g_ctx, scriptFunc))) {
134 return;
135 }
136 mainScriptFunc = scriptFunc;
137 }
138
changeParent(es2panda_AstNode * child)139 static void changeParent(es2panda_AstNode *child)
140 {
141 g_impl->AstNodeSetParent(newCtx, child, parNode);
142 }
143
SetRightParent(es2panda_AstNode * node,void * arg)144 static void SetRightParent(es2panda_AstNode *node, void *arg)
145 {
146 es2panda_Context *context = static_cast<es2panda_Context *>(arg);
147 newCtx = context;
148 parNode = node;
149 g_impl->AstNodeIterateConst(context, node, changeParent);
150 }
151
152 /*
153 * update variableDeclaration name
154 */
UpdateAst(es2panda_Context * context,es2panda_AstNode * ast)155 static bool UpdateAst(es2panda_Context *context, es2panda_AstNode *ast)
156 {
157 auto mainFuncBody = g_impl->ScriptFunctionBody(context, mainScriptFunc);
158 size_t n = 0;
159 es2panda_AstNode *varIdent = g_impl->CreateIdentifier1(context, const_cast<char *>("newVar"));
160 auto declarator = g_impl->CreateVariableDeclarator1(
161 context, Es2pandaVariableDeclaratorFlag::VARIABLE_DECLARATOR_FLAG_LET, varIdent,
162 g_impl->VariableDeclaratorInit(context,
163 g_impl->VariableDeclarationDeclaratorsConst(context, letStatement, &n)[0]));
164
165 auto updateDeclaration = g_impl->UpdateVariableDeclaration(
166 context, letStatement, Es2pandaVariableDeclarationKind::VARIABLE_DECLARATION_KIND_LET, &declarator, 1);
167 es2panda_AstNode *newMainStatements[1] = {updateDeclaration};
168 g_impl->BlockStatementSetStatements(context, mainFuncBody, newMainStatements, 1U);
169 g_impl->AstNodeForEach(ast, SetRightParent, context);
170
171 const char *errMessage = g_impl->ContextErrorMessage(context);
172 if (!errMessage) {
173 std::cout << "The errMessage is nullptr." << std::endl;
174 return false;
175 }
176
177 g_impl->AstNodeIterateConst(context, ast, FindLet);
178 size_t declaratorLen = 0;
179 es2panda_AstNode **declarators = g_impl->VariableDeclarationDeclaratorsConst(context, letStatement, &declaratorLen);
180 if (declaratorLen != 1) {
181 std::cout << "Fail to get declartors." << std::endl;
182 return false;
183 }
184
185 char *astStr = g_impl->AstNodeDumpJSONConst(context, ast);
186 expectResStr = expectResStr.erase(0, 1);
187 expectResStr = expectResStr.erase(expectResStr.length() - 1, 1);
188 if (strcmp(expectResStr.c_str(), astStr) != 0) {
189 std::cout << "Dumping ast has wrong result." << std::endl;
190 return false;
191 }
192 es2panda_AstNode *varDeclInit = g_impl->VariableDeclaratorInit(context, declarators[0]);
193 if (!varDeclInit) {
194 std::cout << "The varDeclInit is nullptr." << std::endl;
195 return false;
196 }
197 std::string res1(g_impl->AstNodeDumpEtsSrcConst(context, varDeclInit));
198 if (res1.find("5") == std::string::npos) {
199 std::cout << "Fail to find given variabledeclaration init value." << std::endl;
200 return false;
201 }
202 std::string res2(g_impl->AstNodeDumpEtsSrcConst(context, letStatement));
203 return (res2.find("newVar") != std::string::npos);
204 }
205
206 /*
207 * "function main() { \nlet a = 5;\n }"
208 * is changed to
209 * "function main() { \nlet newVar = 5;\n }"
210 */
Handle(es2panda_Context * context,es2panda_AstNode * ast)211 static bool Handle(es2panda_Context *context, [[maybe_unused]] es2panda_AstNode *ast)
212 {
213 g_impl->AstNodeIterateConst(context, ast, FindLet);
214 g_impl->AstNodeIterateConst(context, ast, FindMainDef);
215 if (mainScriptFunc == nullptr || letStatement == nullptr) {
216 return false;
217 }
218
219 size_t declaratorLen = 0;
220 es2panda_AstNode **declarators = g_impl->VariableDeclarationDeclaratorsConst(context, letStatement, &declaratorLen);
221 if (declaratorLen != 1) {
222 std::cout << "Fail to get declartors." << std::endl;
223 return false;
224 }
225
226 es2panda_AstNode *varDeclNode = declarators[0];
227 if (!varDeclNode) {
228 std::cout << "The declaratorsElement is nullptr. " << std::endl;
229 return false;
230 }
231
232 if (!g_impl->IsVariableDeclarator(varDeclNode)) {
233 std::cout << "The varDeclNode is not variable declaration." << std::endl;
234 return false;
235 }
236
237 const es2panda_AstNode *varDeclIDConst = g_impl->VariableDeclaratorIdConst(context, varDeclNode);
238 if (!varDeclIDConst) {
239 std::cout << "The varDeclIDConst is nullptr." << std::endl;
240 return false;
241 }
242 es2panda_AstNode *varDeclID = g_impl->VariableDeclaratorId(context, varDeclNode);
243 if (!varDeclID) {
244 std::cout << "The varDeclID is nullptr." << std::endl;
245 return false;
246 }
247
248 if (strcmp(g_impl->IdentifierName(context, varDeclID), const_cast<char *>("a")) != 0) {
249 std::cout << "The varDeclNode is not the expected node." << std::endl;
250 return false;
251 }
252
253 return UpdateAst(context, ast);
254 }
255
main(int argc,char ** argv)256 int main(int argc, char **argv)
257 {
258 if (argc < MIN_ARGC) {
259 return INVALID_ARGC_ERROR_CODE;
260 }
261
262 if (GetImpl() == nullptr) {
263 return NULLPTR_IMPL_ERROR_CODE;
264 }
265
266 g_impl = GetImpl();
267 const char **args = const_cast<const char **>(&(argv[1]));
268 auto config = g_impl->CreateConfig(argc - 1, args);
269 g_ctx = g_impl->CreateContextFromString(config, source.data(), argv[argc - 1]);
270 if (g_ctx == nullptr) {
271 std::cerr << "Fail to create context." << std::endl;
272 return NULLPTR_CONTEXT_ERROR_CODE;
273 }
274 int retCode = Test(g_ctx, g_impl, ES2PANDA_STATE_PARSED, Handle);
275 if (retCode != 0) {
276 std::cerr << "Fail to execute on AfterParse phase" << std::endl;
277 g_impl->DestroyConfig(config);
278 return retCode;
279 }
280
281 g_impl->DestroyConfig(config);
282
283 return 0;
284 }
285 // NOLINTEND
286