• 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 "util.h"
17 #include <algorithm>
18 #include <cstddef>
19 #include <functional>
20 #include <ostream>
21 #include <string>
22 #include "macros.h"
23 
24 static es2panda_Impl *g_implPtr = nullptr;
25 
GetImpl()26 es2panda_Impl *GetImpl()
27 {
28     if (g_implPtr != nullptr) {
29         return g_implPtr;
30     }
31 
32     std::string soName = ark::os::library_loader::DYNAMIC_LIBRARY_PREFIX + std::string("es2panda-public") +
33                          ark::os::library_loader::DYNAMIC_LIBRARY_SUFFIX;
34     auto libraryRes = ark::os::library_loader::Load(soName);
35     if (!libraryRes.HasValue()) {
36         std::cout << "Error in load lib" << std::endl;
37         return nullptr;
38     }
39 
40     auto library = std::move(libraryRes.Value());
41     auto getImpl = ark::os::library_loader::ResolveSymbol(library, "es2panda_GetImpl");
42     if (!getImpl.HasValue()) {
43         std::cout << "Error in load func get g_implPtr" << std::endl;
44         return nullptr;
45     }
46 
47     auto getImplFunc = reinterpret_cast<const es2panda_Impl *(*)(int)>(getImpl.Value());
48     if (getImplFunc != nullptr) {
49         g_implPtr = const_cast<es2panda_Impl *>(getImplFunc(ES2PANDA_LIB_VERSION));
50         return g_implPtr;
51     }
52     return nullptr;
53 }
54 
CheckForErrors(const std::string & stateName,es2panda_Context * context)55 void CheckForErrors(const std::string &stateName, es2panda_Context *context)
56 {
57     if (g_implPtr->ContextState(context) == ES2PANDA_STATE_ERROR) {
58         std::cout << "PROCEED TO " << stateName << " ERROR" << std::endl;
59         std::cout << g_implPtr->ContextErrorMessage(context) << std::endl;
60     } else {
61         std::cout << "PROCEED TO " << stateName << " SUCCESS" << std::endl;
62     }
63 }
64 
CreateIdentifierFromString(es2panda_Context * context,const std::string_view & name)65 es2panda_AstNode *CreateIdentifierFromString(es2panda_Context *context, const std::string_view &name)
66 {
67     auto impl = GetImpl();
68     auto *memForName = static_cast<char *>(impl->AllocMemory(context, name.size() + 1, 1));
69     std::copy_n(name.data(), name.size() + 1, memForName);
70     auto *identifier = impl->CreateIdentifier1(context, memForName);
71     return identifier;
72 }
73 
AppendStatementToProgram(es2panda_Context * context,es2panda_AstNode * program,es2panda_AstNode * newStatement)74 void AppendStatementToProgram(es2panda_Context *context, es2panda_AstNode *program, es2panda_AstNode *newStatement)
75 {
76     auto impl = GetImpl();
77     size_t sizeOfStatements = 0;
78     auto *statements = impl->BlockStatementStatements(context, program, &sizeOfStatements);
79     auto **newStatements =
80         static_cast<es2panda_AstNode **>(impl->AllocMemory(context, sizeOfStatements + 1, sizeof(es2panda_AstNode *)));
81     for (size_t i = 0; i < sizeOfStatements; i++) {
82         newStatements[i] = statements[i];
83     }
84     newStatements[sizeOfStatements] = newStatement;
85     impl->BlockStatementSetStatements(context, program, newStatements, sizeOfStatements + 1);
86     impl->AstNodeSetParent(context, newStatement, program);
87 }
88 
PrependStatementToProgram(es2panda_Context * context,es2panda_AstNode * program,es2panda_AstNode * newStatement)89 void PrependStatementToProgram(es2panda_Context *context, es2panda_AstNode *program, es2panda_AstNode *newStatement)
90 {
91     auto impl = GetImpl();
92     size_t sizeOfStatements = 0;
93     auto *statements = impl->BlockStatementStatements(context, program, &sizeOfStatements);
94     auto **newStatements =
95         static_cast<es2panda_AstNode **>(impl->AllocMemory(context, sizeOfStatements + 1, sizeof(es2panda_AstNode *)));
96     for (size_t i = 0; i < sizeOfStatements; i++) {
97         newStatements[i + 1] = statements[i];
98     }
99     newStatements[0] = newStatement;
100     impl->BlockStatementSetStatements(context, program, newStatements, sizeOfStatements + 1);
101     impl->AstNodeSetParent(context, newStatement, program);
102 }
103 
GetPhaseName(es2panda_ContextState state)104 static const char *GetPhaseName(es2panda_ContextState state)
105 {
106     switch (state) {
107         case ES2PANDA_STATE_NEW:
108             return "NEW";
109         case ES2PANDA_STATE_PARSED:
110             return "PARSE";
111         case ES2PANDA_STATE_BOUND:
112             return "BOUND";
113         case ES2PANDA_STATE_CHECKED:
114             return "CHECKED";
115         case ES2PANDA_STATE_LOWERED:
116             return "LOWERED";
117         case ES2PANDA_STATE_ASM_GENERATED:
118             return "ASM";
119         case ES2PANDA_STATE_BIN_GENERATED:
120             return "BIN";
121         case ES2PANDA_STATE_ERROR:
122             return "ERROR";
123         default:
124             return "NON_VALID_STATE";
125     }
126 }
127 
IsAllowedStage(es2panda_ContextState state)128 static bool IsAllowedStage(es2panda_ContextState state)
129 {
130     switch (state) {
131         case ES2PANDA_STATE_NEW:
132             return false;
133         case ES2PANDA_STATE_ERROR:
134             return false;
135         default:
136             return true;
137     }
138 }
139 
DestroyTest(es2panda_Context * context,es2panda_Config * config,const int exitCode)140 static int DestroyTest(es2panda_Context *context, es2panda_Config *config, const int exitCode)
141 {
142     g_implPtr->DestroyContext(context);
143     g_implPtr->DestroyConfig(config);
144     return exitCode;
145 }
146 
RunAllStagesWithTestFunction(ProccedToStatePluginTestData & data)147 int RunAllStagesWithTestFunction(ProccedToStatePluginTestData &data)
148 {
149     if (data.argc < MIN_ARGC) {
150         return INVALID_ARGC_ERROR_CODE;
151     }
152 
153     if (GetImpl() == nullptr) {
154         return NULLPTR_IMPL_ERROR_CODE;
155     }
156     *data.impl = GetImpl();
157     std::cout << "LOAD SUCCESS" << std::endl;
158     const char **args = const_cast<const char **>(&(data.argv[1]));
159     auto config = g_implPtr->CreateConfig(data.argc - 1, args);
160     es2panda_Context *context = nullptr;
161     if (data.fromSource) {
162         context = g_implPtr->CreateContextFromString(config, data.source.data(), data.argv[data.argc - 1]);
163     } else {
164         context = g_implPtr->CreateContextFromFile(config, data.argv[data.argc - 1]);
165     }
166     if (context == nullptr) {
167         std::cerr << "FAILED TO CREATE CONTEXT" << std::endl;
168         return NULLPTR_CONTEXT_ERROR_CODE;
169     }
170 
171     for (auto [testStage, _] : data.testFunctions) {
172         if (!IsAllowedStage(testStage)) {
173             return DestroyTest(context, config, TEST_ERROR_CODE);
174         }
175     }
176 
177     for (auto state = ES2PANDA_STATE_PARSED; state <= ES2PANDA_STATE_BIN_GENERATED;
178          state = static_cast<es2panda_ContextState>(state + 1)) {
179         if (!IsAllowedStage(state)) {
180             continue;
181         }
182         g_implPtr->ProceedToState(context, state);
183         CheckForErrors(GetPhaseName(state), context);
184         for (const auto &testFunc : data.testFunctions[state]) {
185             if (!testFunc(context)) {
186                 return DestroyTest(context, config, TEST_ERROR_CODE);
187             }
188         }
189         if (state == data.exitAfterState) {
190             break;
191         }
192     }
193 
194     int result = g_implPtr->ContextState(context) == ES2PANDA_STATE_ERROR ? PROCEED_ERROR_CODE : 0;
195     return DestroyTest(context, config, result);
196 }
197 
Test(es2panda_Context * context,es2panda_Impl * impl,int stage,const std::function<bool (es2panda_Context *,es2panda_AstNode *)> & handle)198 int Test(es2panda_Context *context, es2panda_Impl *impl, int stage,
199          const std::function<bool(es2panda_Context *, es2panda_AstNode *)> &handle)
200 {
201     impl->ProceedToState(context, ES2PANDA_STATE_PARSED);
202     CheckForErrors("PARSE", context);
203     es2panda_AstNode *ast = impl->ProgramAst(context, impl->ContextProgram(context));
204     if (ast == nullptr) {
205         return TEST_ERROR_CODE;
206     }
207     switch (stage) {
208         case ES2PANDA_STATE_PARSED: {
209             break;
210         }
211         case ES2PANDA_STATE_BOUND: {
212             impl->ProceedToState(context, ES2PANDA_STATE_BOUND);
213             CheckForErrors("BOUND", context);
214             break;
215         }
216         case ES2PANDA_STATE_CHECKED: {
217             impl->ProceedToState(context, ES2PANDA_STATE_CHECKED);
218             CheckForErrors("CHECKED", context);
219             break;
220         }
221         case ES2PANDA_STATE_LOWERED: {
222             impl->ProceedToState(context, ES2PANDA_STATE_LOWERED);
223             CheckForErrors("LOWERED", context);
224             break;
225         }
226         default: {
227             UNREACHABLE();
228         }
229     }
230     if (impl->ContextState(context) == ES2PANDA_STATE_ERROR) {
231         return PROCEED_ERROR_CODE;
232     }
233     if (!handle(context, ast)) {
234         return TEST_ERROR_CODE;
235     }
236     if (stage == ES2PANDA_STATE_BOUND) {
237         impl->AstNodeRebind(context, ast);
238     } else if (stage == ES2PANDA_STATE_CHECKED || stage == ES2PANDA_STATE_LOWERED) {
239         impl->AstNodeRecheck(context, ast);
240     }
241     impl->ProceedToState(context, ES2PANDA_STATE_BIN_GENERATED);
242     CheckForErrors("BIN", context);
243     if (impl->ContextState(context) == ES2PANDA_STATE_ERROR) {
244         return PROCEED_ERROR_CODE;
245     }
246     impl->DestroyContext(context);
247     return 0;
248 }
249