• 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 <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