• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024-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 "es2panda_lib.h"
17 #include <cstring>
18 #include <cstdint>
19 
20 #include "util/diagnostic.h"
21 #include "varbinder/varbinder.h"
22 #include "varbinder/scope.h"
23 #include "public/public.h"
24 #include "generated/signatures.h"
25 #include "es2panda.h"
26 #include "varbinder/ETSBinder.h"
27 #include "checker/ETSAnalyzer.h"
28 #include "checker/ETSchecker.h"
29 #include "compiler/core/compileQueue.h"
30 #include "compiler/core/compilerImpl.h"
31 #include "compiler/core/ETSCompiler.h"
32 #include "compiler/core/ETSemitter.h"
33 #include "compiler/core/ETSGen.h"
34 #include "compiler/core/regSpiller.h"
35 #include "compiler/lowering/phase.h"
36 #include "ir/astNode.h"
37 #include "ir/expressions/arrowFunctionExpression.h"
38 #include "ir/ts/tsAsExpression.h"
39 #include "ir/expressions/assignmentExpression.h"
40 #include "ir/expressions/binaryExpression.h"
41 #include "ir/statements/blockStatement.h"
42 #include "ir/expressions/callExpression.h"
43 #include "ir/base/classProperty.h"
44 #include "ir/ets/etsFunctionType.h"
45 #include "ir/statements/ifStatement.h"
46 #include "ir/base/methodDefinition.h"
47 #include "ir/ets/etsNewClassInstanceExpression.h"
48 #include "ir/ets/etsNewArrayInstanceExpression.h"
49 #include "ir/ets/etsNewMultiDimArrayInstanceExpression.h"
50 #include "parser/ETSparser.h"
51 #include "parser/context/parserContext.h"
52 #include "parser/program/program.h"
53 #include "util/generateBin.h"
54 #include "util/options.h"
55 #include "compiler/lowering/util.h"
56 #include "generated/es2panda_lib/es2panda_lib_include.inc"
57 #include "declgen_ets2ts/declgenEts2Ts.h"
58 
59 // NOLINTBEGIN
60 
61 namespace ark::es2panda::public_lib {
62 
63 struct TokenTypeToStr {
64     lexer::TokenType token;
65     char const *str;
66 };
67 
StrToToken(TokenTypeToStr const * table,char const * str)68 __attribute__((unused)) lexer::TokenType StrToToken(TokenTypeToStr const *table, char const *str)
69 {
70     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
71     for (auto *tp = table; tp->str != nullptr; tp++) {
72         if (strcmp(str, tp->str) == 0) {
73             return tp->token;
74         }
75     }
76     ES2PANDA_UNREACHABLE();
77 }
78 
TokenToStr(TokenTypeToStr const * table,lexer::TokenType token)79 __attribute__((unused)) char const *TokenToStr(TokenTypeToStr const *table, lexer::TokenType token)
80 {
81     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
82     for (auto *tp = table; tp->str != nullptr; tp++) {
83         if (tp->token == token) {
84             return tp->str;
85         }
86     }
87     ES2PANDA_UNREACHABLE();
88 }
89 
StringViewToCString(ArenaAllocator * allocator,std::string_view const utf8)90 char *StringViewToCString(ArenaAllocator *allocator, std::string_view const utf8)
91 {
92     // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic, readability-simplify-subscript-expr)
93     if (!utf8.empty() && (utf8.back() == '\0')) {
94         // Avoid superfluous allocation.
95         return const_cast<char *>(utf8.data());
96     }
97     char *res = reinterpret_cast<char *>(allocator->Alloc(utf8.size() + 1));
98     if (!utf8.empty()) {
99         [[maybe_unused]] auto err = memmove_s(res, utf8.size() + 1, utf8.cbegin(), utf8.size());
100         ES2PANDA_ASSERT(err == EOK);
101     }
102     res[utf8.size()] = '\0';
103     return res;
104     // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic, readability-simplify-subscript-expr)
105 }
106 
StringViewToCString(ArenaAllocator * allocator,util::StringView const sv)107 __attribute__((unused)) char *StringViewToCString(ArenaAllocator *allocator, util::StringView const sv)
108 {
109     return StringViewToCString(allocator, sv.Utf8());
110 }
111 
StdStringToCString(ArenaAllocator * allocator,std::string str)112 __attribute__((unused)) char *StdStringToCString(ArenaAllocator *allocator, std::string str)
113 {
114     // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic, readability-simplify-subscript-expr)
115     char *res = reinterpret_cast<char *>(allocator->Alloc(str.length() + 1));
116     [[maybe_unused]] auto err = memcpy_s(res, str.length() + 1, str.c_str(), str.length() + 1);
117     ES2PANDA_ASSERT(err == EOK);
118     return res;
119     // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic, readability-simplify-subscript-expr)
120 }
121 
UStringToCString(ArenaAllocator * allocator,util::UString const sv)122 __attribute__((unused)) char *UStringToCString(ArenaAllocator *allocator, util::UString const sv)
123 {
124     return StringViewToCString(allocator, sv.View());
125 }
126 
EnumMemberResultToEs2pandaVariant(ArenaAllocator * allocator,varbinder::EnumMemberResult variant)127 __attribute__((unused)) es2panda_variantDoubleCharArrayBool EnumMemberResultToEs2pandaVariant(
128     ArenaAllocator *allocator, varbinder::EnumMemberResult variant)
129 {
130     // NOLINTBEGIN(cppcoreguidelines-pro-type-union-access)
131     // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic, readability-simplify-subscript-expr)
132     es2panda_variantDoubleCharArrayBool es2panda_variant;
133     es2panda_variant.index = static_cast<int>(variant.index());
134     switch (es2panda_variant.index) {
135         case es2panda_variantIndex::CAPI_DOUBLE:
136             es2panda_variant.variant.d = std::get<double>(variant);
137             break;
138         case es2panda_variantIndex::CAPI_CHAR:
139             es2panda_variant.variant.c = StringViewToCString(allocator, std::get<util::StringView>(variant));
140             break;
141         case es2panda_variantIndex::CAPI_BOOL:
142             es2panda_variant.variant.b = std::get<bool>(variant);
143             break;
144         default:
145             break;
146     }
147     return es2panda_variant;
148     // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic, readability-simplify-subscript-expr)
149     // NOLINTEND(cppcoreguidelines-pro-type-union-access)
150 }
151 
DynamicImportDataToE2pPtr(ArenaAllocator * allocator,const varbinder::DynamicImportData * dynamicImportData)152 __attribute__((unused)) es2panda_DynamicImportData *DynamicImportDataToE2pPtr(
153     ArenaAllocator *allocator, const varbinder::DynamicImportData *dynamicImportData)
154 {
155     auto import = reinterpret_cast<const es2panda_AstNode *>(dynamicImportData->import);
156     auto specifier = reinterpret_cast<const es2panda_AstNode *>(dynamicImportData->specifier);
157     auto variable = reinterpret_cast<es2panda_Variable *>(dynamicImportData->variable);
158     auto es2pandaDynamicImportData = allocator->New<es2panda_DynamicImportData>();
159     es2pandaDynamicImportData->import = import;
160     es2pandaDynamicImportData->specifier = specifier;
161     es2pandaDynamicImportData->variable = variable;
162     return es2pandaDynamicImportData;
163 }
164 
DynamicImportDataToE2p(const varbinder::DynamicImportData dynamicImportData)165 __attribute__((unused)) es2panda_DynamicImportData DynamicImportDataToE2p(
166     const varbinder::DynamicImportData dynamicImportData)
167 {
168     auto import = reinterpret_cast<const es2panda_AstNode *>(dynamicImportData.import);
169     auto specifier = reinterpret_cast<const es2panda_AstNode *>(dynamicImportData.specifier);
170     auto variable = reinterpret_cast<es2panda_Variable *>(dynamicImportData.variable);
171     es2panda_DynamicImportData es2pandaDynamicImportData;
172     es2pandaDynamicImportData.import = import;
173     es2pandaDynamicImportData.specifier = specifier;
174     es2pandaDynamicImportData.variable = variable;
175     return es2pandaDynamicImportData;
176 }
177 
OverloadInfoToE2pPtr(ArenaAllocator * allocator,const ir::OverloadInfo * overloadInfo)178 __attribute__((unused)) es2panda_OverloadInfo *OverloadInfoToE2pPtr(ArenaAllocator *allocator,
179                                                                     const ir::OverloadInfo *overloadInfo)
180 {
181     auto es2pandaOverloadInfo = allocator->New<es2panda_OverloadInfo>();
182     es2pandaOverloadInfo->minArg = overloadInfo->minArg;
183     es2pandaOverloadInfo->maxArg = overloadInfo->maxArg;
184     es2pandaOverloadInfo->needHelperOverload = overloadInfo->needHelperOverload;
185     es2pandaOverloadInfo->isDeclare = overloadInfo->isDeclare;
186     es2pandaOverloadInfo->hasRestVar = overloadInfo->hasRestVar;
187     es2pandaOverloadInfo->returnVoid = overloadInfo->returnVoid;
188     return es2pandaOverloadInfo;
189 }
190 
OverloadInfoToE2p(const ir::OverloadInfo overloadInfo)191 __attribute__((unused)) es2panda_OverloadInfo OverloadInfoToE2p(const ir::OverloadInfo overloadInfo)
192 {
193     es2panda_OverloadInfo es2pandaOverloadInfo;
194     es2pandaOverloadInfo.minArg = overloadInfo.minArg;
195     es2pandaOverloadInfo.maxArg = overloadInfo.maxArg;
196     es2pandaOverloadInfo.needHelperOverload = overloadInfo.needHelperOverload;
197     es2pandaOverloadInfo.isDeclare = overloadInfo.isDeclare;
198     es2pandaOverloadInfo.hasRestVar = overloadInfo.hasRestVar;
199     es2pandaOverloadInfo.returnVoid = overloadInfo.returnVoid;
200     return es2pandaOverloadInfo;
201 }
202 
JsDocRecordToE2p(const es2panda_JsDocRecord * jsDocRecord)203 __attribute__((unused)) ir::JsDocRecord JsDocRecordToE2p(const es2panda_JsDocRecord *jsDocRecord)
204 {
205     return ir::JsDocRecord(jsDocRecord->name, jsDocRecord->param, jsDocRecord->comment);
206 }
207 
JsDocRecordFromE2p(ArenaAllocator * allocator,const ir::JsDocRecord & jsDocRecord)208 __attribute__((unused)) es2panda_JsDocRecord *JsDocRecordFromE2p(ArenaAllocator *allocator,
209                                                                  const ir::JsDocRecord &jsDocRecord)
210 {
211     es2panda_JsDocRecord *res = allocator->New<es2panda_JsDocRecord>();
212     res->name = StringViewToCString(allocator, jsDocRecord.name);
213     res->param = StringViewToCString(allocator, jsDocRecord.param);
214     res->comment = StringViewToCString(allocator, jsDocRecord.comment);
215     return res;
216 }
217 
JsDocInfoFromE2p(ArenaAllocator * allocator,const ir::JsDocInfo & jsDocInfo)218 __attribute__((unused)) es2panda_JsDocInfo *JsDocInfoFromE2p(ArenaAllocator *allocator, const ir::JsDocInfo &jsDocInfo)
219 {
220     size_t jsDocInfoLen = jsDocInfo.size();
221     es2panda_JsDocInfo *res = allocator->New<es2panda_JsDocInfo>();
222     res->len = jsDocInfoLen;
223     res->strings = allocator->New<char *[]>(jsDocInfoLen);
224     res->jsDocRecords = allocator->New<es2panda_JsDocRecord *[]>(jsDocInfoLen);
225     size_t i = 0;
226     for (const auto &[key, value] : jsDocInfo) {
227         res->strings[i] = StringViewToCString(allocator, key);
228         res->jsDocRecords[i] = JsDocRecordFromE2p(allocator, value);
229         ++i;
230     };
231     return res;
232 }
233 
ArenaStrdup(ArenaAllocator * allocator,char const * src)234 __attribute__((unused)) char const *ArenaStrdup(ArenaAllocator *allocator, char const *src)
235 {
236     size_t len = strlen(src);
237     char *res = reinterpret_cast<char *>(allocator->Alloc(len + 1));
238     [[maybe_unused]] auto err = memmove_s(res, len + 1, src, len);
239     ES2PANDA_ASSERT(err == EOK);
240 
241     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
242     res[len] = '\0';
243     return res;
244 }
245 
CreateConfig(int args,char const * const * argv)246 extern "C" es2panda_Config *CreateConfig(int args, char const *const *argv)
247 {
248     mem::MemConfig::Initialize(0, 0, COMPILER_SIZE, 0, 0, 0);
249     PoolManager::Initialize(PoolType::MMAP);
250     auto diagnosticEngine = new util::DiagnosticEngine();
251     auto *options = new util::Options(argv[0], *diagnosticEngine);
252     if (!options->Parse(Span(argv, args))) {
253         return nullptr;
254     }
255     ark::Logger::ComponentMask mask {};
256     mask.set(ark::Logger::Component::ES2PANDA);
257     ark::Logger::InitializeStdLogging(options->LogLevel(), mask);
258 
259     auto *res = new ConfigImpl;
260     res->options = options;
261     res->diagnosticEngine = diagnosticEngine;
262     return reinterpret_cast<es2panda_Config *>(res);
263 }
264 
DestroyConfig(es2panda_Config * config)265 extern "C" void DestroyConfig(es2panda_Config *config)
266 {
267     PoolManager::Finalize();
268     mem::MemConfig::Finalize();
269 
270     auto *cfg = reinterpret_cast<ConfigImpl *>(config);
271     if (cfg == nullptr) {
272         return;
273     }
274 
275     delete cfg->options;
276     cfg->diagnosticEngine->FlushDiagnostic();
277     delete cfg->diagnosticEngine;
278     delete cfg;
279 }
280 
GetAllErrorMessages(es2panda_Context * context)281 extern "C" __attribute__((unused)) char const *GetAllErrorMessages(es2panda_Context *context)
282 {
283     auto *ctx = reinterpret_cast<Context *>(context);
284     ES2PANDA_ASSERT(ctx != nullptr);
285     ES2PANDA_ASSERT(ctx->config != nullptr);
286     ES2PANDA_ASSERT(ctx->allocator != nullptr);
287     auto *cfg = reinterpret_cast<ConfigImpl *>(ctx->config);
288     ES2PANDA_ASSERT(cfg != nullptr);
289     ES2PANDA_ASSERT(cfg->diagnosticEngine != nullptr);
290     auto allMessages = cfg->diagnosticEngine->PrintAndFlushErrorDiagnostic();
291     size_t bufferSize = allMessages.length() + 1;
292     char *cStringMessages = reinterpret_cast<char *>(ctx->allocator->Alloc(bufferSize));
293     [[maybe_unused]] auto err = memcpy_s(cStringMessages, bufferSize, allMessages.c_str(), bufferSize);
294     ES2PANDA_ASSERT(err == EOK);
295     return cStringMessages;
296 }
297 
ConfigGetOptions(es2panda_Config * config)298 extern "C" const es2panda_Options *ConfigGetOptions(es2panda_Config *config)
299 {
300     auto options = reinterpret_cast<ConfigImpl *>(config)->options;
301     return reinterpret_cast<const es2panda_Options *>(options);
302 }
303 
CompileJob(public_lib::Context * context,varbinder::FunctionScope * scope,compiler::ProgramElement * programElement)304 static void CompileJob(public_lib::Context *context, varbinder::FunctionScope *scope,
305                        compiler::ProgramElement *programElement)
306 {
307     compiler::StaticRegSpiller regSpiller;
308     ArenaAllocator allocator {SpaceType::SPACE_TYPE_COMPILER, nullptr, true};
309     compiler::ETSCompiler astCompiler {};
310     compiler::ETSGen cg {&allocator, &regSpiller, context, std::make_tuple(scope, programElement, &astCompiler)};
311     compiler::ETSFunctionEmitter funcEmitter {&cg, programElement};
312     funcEmitter.Generate();
313 }
314 
InitializeContext(Context * res)315 static void InitializeContext(Context *res)
316 {
317     res->phaseManager = new compiler::PhaseManager(ScriptExtension::ETS, res->allocator);
318     res->queue = new compiler::CompileQueue(res->config->options->GetThread());
319 
320     auto *varbinder = res->allocator->New<varbinder::ETSBinder>(res->allocator);
321     res->parserProgram = res->allocator->New<parser::Program>(res->allocator, varbinder);
322     res->parser = new parser::ETSParser(res->parserProgram, *res->config->options, *res->diagnosticEngine,
323                                         parser::ParserStatus::NO_OPTS);
324     res->parser->SetContext(res);
325 
326     res->checker = res->allocator->New<checker::ETSChecker>(*res->diagnosticEngine, res->allocator);
327     res->analyzer = res->allocator->New<checker::ETSAnalyzer>(res->checker);
328     res->checker->SetAnalyzer(res->analyzer);
329 
330     varbinder->SetProgram(res->parserProgram);
331     varbinder->SetContext(res);
332     res->codeGenCb = CompileJob;
333     res->emitter = new compiler::ETSEmitter(res);
334     res->program = nullptr;
335     res->state = ES2PANDA_STATE_NEW;
336 }
337 
InitContext(es2panda_Config * config)338 static Context *InitContext(es2panda_Config *config)
339 {
340     auto *cfg = reinterpret_cast<ConfigImpl *>(config);
341     auto *res = new Context;
342 
343     if (cfg == nullptr) {
344         res->errorMessage = "Config is nullptr.";
345         res->state = ES2PANDA_STATE_ERROR;
346         return res;
347     }
348 
349     if (cfg->options->GetExtension() != ScriptExtension::ETS) {
350         res->errorMessage = "Invalid extension. Plugin API supports only ETS.";
351         res->state = ES2PANDA_STATE_ERROR;
352         res->diagnosticEngine = cfg->diagnosticEngine;
353         return res;
354     }
355 
356     res->config = cfg;
357     res->diagnosticEngine = cfg->diagnosticEngine;
358     return res;
359 }
360 
CreateContext(es2panda_Config * config,std::string && source,const char * fileName)361 __attribute__((unused)) static es2panda_Context *CreateContext(es2panda_Config *config, std::string &&source,
362                                                                const char *fileName)
363 {
364     auto res = InitContext(config);
365     if (res->state == ES2PANDA_STATE_ERROR) {
366         return reinterpret_cast<es2panda_Context *>(res);
367     }
368     auto *cfg = reinterpret_cast<ConfigImpl *>(config);
369 
370     res->input = std::move(source);
371     res->sourceFileName = fileName;
372     res->sourceFile = new SourceFile(res->sourceFileName, res->input, cfg->options->IsModule());
373     res->allocator = new ArenaAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true);
374     res->queue = new compiler::CompileQueue(cfg->options->GetThread());
375 
376     auto *varbinder = res->allocator->New<varbinder::ETSBinder>(res->allocator);
377     res->parserProgram = new parser::Program(res->allocator, varbinder);
378     res->diagnosticEngine = cfg->diagnosticEngine;
379     res->parser =
380         new parser::ETSParser(res->parserProgram, *cfg->options, *cfg->diagnosticEngine, parser::ParserStatus::NO_OPTS);
381     res->parser->SetContext(res);
382     res->checker = new checker::ETSChecker(*res->diagnosticEngine);
383     res->isolatedDeclgenChecker = new checker::IsolatedDeclgenChecker(*res->diagnosticEngine, *(res->parserProgram));
384     res->analyzer = new checker::ETSAnalyzer(res->checker);
385     res->checker->SetAnalyzer(res->analyzer);
386 
387     varbinder->SetProgram(res->parserProgram);
388 
389     varbinder->SetContext(res);
390     res->codeGenCb = CompileJob;
391     res->phaseManager = new compiler::PhaseManager(ScriptExtension::ETS, res->allocator);
392     res->emitter = new compiler::ETSEmitter(res);
393     res->program = nullptr;
394     res->state = ES2PANDA_STATE_NEW;
395     return reinterpret_cast<es2panda_Context *>(res);
396 }
397 
CreateContextFromFile(es2panda_Config * config,char const * sourceFileName)398 extern "C" __attribute__((unused)) es2panda_Context *CreateContextFromFile(es2panda_Config *config,
399                                                                            char const *sourceFileName)
400 {
401     std::ifstream inputStream;
402     inputStream.open(sourceFileName);
403     if (inputStream.fail()) {
404         auto *res = new Context;
405         res->errorMessage = "Failed to open file: ";
406         res->errorMessage.append(sourceFileName);
407         return reinterpret_cast<es2panda_Context *>(res);
408     }
409     std::stringstream ss;
410     ss << inputStream.rdbuf();
411     if (inputStream.fail()) {
412         auto *res = new Context;
413         res->errorMessage = "Failed to read file: ";
414         res->errorMessage.append(sourceFileName);
415         return reinterpret_cast<es2panda_Context *>(res);
416     }
417     return CreateContext(config, ss.str(), sourceFileName);
418 }
419 
CreateContextFromMultiFile(es2panda_Config * config,char const * sourceFileNames)420 extern "C" __attribute__((unused)) es2panda_Context *CreateContextFromMultiFile(es2panda_Config *config,
421                                                                                 char const *sourceFileNames)
422 {
423     return CreateContext(config, "", sourceFileNames);
424 }
425 
CreateContextFromString(es2panda_Config * config,const char * source,char const * fileName)426 extern "C" __attribute__((unused)) es2panda_Context *CreateContextFromString(es2panda_Config *config,
427                                                                              const char *source, char const *fileName)
428 {
429     // NOTE: gogabr. avoid copying source.
430     return CreateContext(config, std::string(source), fileName);
431 }
432 
CreateContextGenerateAbcForExternalSourceFiles(es2panda_Config * config,int fileNamesCount,char const * const * fileNames)433 extern __attribute__((unused)) es2panda_Context *CreateContextGenerateAbcForExternalSourceFiles(
434     es2panda_Config *config, int fileNamesCount, char const *const *fileNames)
435 {
436     auto res = InitContext(config);
437     if (res->state == ES2PANDA_STATE_ERROR) {
438         return reinterpret_cast<es2panda_Context *>(res);
439     }
440     auto *cfg = reinterpret_cast<ConfigImpl *>(config);
441 
442     ES2PANDA_ASSERT(cfg->options->IsSimultaneous());
443     for (size_t i = 0; i < static_cast<size_t>(fileNamesCount); ++i) {
444         const char *cName = *(fileNames + i);
445         std::string fileName(cName);
446         res->sourceFileNames.emplace_back(std::move(fileName));
447     }
448 
449     res->input = "";
450     res->sourceFileName = "";
451     res->sourceFile = new SourceFile(res->sourceFileName, res->input, cfg->options->IsModule());
452     res->allocator = new ArenaAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true);
453 
454     InitializeContext(res);
455     return reinterpret_cast<es2panda_Context *>(res);
456 }
457 
Parse(Context * ctx)458 __attribute__((unused)) static Context *Parse(Context *ctx)
459 {
460     if (ctx->state != ES2PANDA_STATE_NEW) {
461         ctx->state = ES2PANDA_STATE_ERROR;
462         ctx->errorMessage = "Bad state at entry to Parse, needed NEW";
463         return ctx;
464     }
465 
466     if (ctx->config->options->IsSimultaneous()) {
467         parser::ETSParser::AddGenExtenralSourceToParseList(ctx);
468         std::unordered_set<std::string> sourceFileNamesSet(ctx->sourceFileNames.begin(), ctx->sourceFileNames.end());
469         ctx->MarkGenAbcForExternal(sourceFileNamesSet, ctx->parserProgram->ExternalSources());
470     } else {
471         ctx->parser->ParseScript(*ctx->sourceFile,
472                                  ctx->config->options->GetCompilationMode() == CompilationMode::GEN_STD_LIB);
473     }
474     ctx->state = ES2PANDA_STATE_PARSED;
475     return ctx;
476 }
477 
SetProgramGenAbc(Context * ctx,const char * path)478 __attribute__((unused)) static bool SetProgramGenAbc(Context *ctx, const char *path)
479 {
480     util::StringView pathView(path);
481     public_lib::Context *context = reinterpret_cast<public_lib::Context *>(ctx);
482     for (auto &[_, extPrograms] : context->externalSources) {
483         (void)_;
484         for (auto *prog : extPrograms) {
485             if (prog->AbsoluteName() == pathView) {
486                 prog->SetGenAbcForExternalSources();
487                 return true;
488             }
489         }
490     }
491     return false;
492 }
493 
Bind(Context * ctx)494 __attribute__((unused)) static Context *Bind(Context *ctx)
495 {
496     if (ctx->state < ES2PANDA_STATE_PARSED) {
497         ctx = Parse(ctx);
498     }
499     if (ctx->state == ES2PANDA_STATE_ERROR) {
500         return ctx;
501     }
502 
503     ES2PANDA_ASSERT(ctx->state == ES2PANDA_STATE_PARSED);
504     while (auto phase = ctx->phaseManager->NextPhase()) {
505         if (phase->Name() == "plugins-after-bind") {
506             break;
507         }
508         phase->Apply(ctx, ctx->parserProgram);
509     }
510     ctx->state = ES2PANDA_STATE_BOUND;
511     return ctx;
512 }
513 
Check(Context * ctx)514 __attribute__((unused)) static Context *Check(Context *ctx)
515 {
516     if (ctx->state < ES2PANDA_STATE_PARSED) {
517         ctx = Parse(ctx);
518     }
519 
520     if (ctx->state == ES2PANDA_STATE_ERROR) {
521         return ctx;
522     }
523 
524     ES2PANDA_ASSERT(ctx->state >= ES2PANDA_STATE_PARSED && ctx->state < ES2PANDA_STATE_CHECKED);
525     while (auto phase = ctx->phaseManager->NextPhase()) {
526         if (phase->Name() == "plugins-after-check") {
527             break;
528         }
529         phase->Apply(ctx, ctx->parserProgram);
530     }
531     ctx->state = !ctx->diagnosticEngine->IsAnyError() ? ES2PANDA_STATE_CHECKED : ES2PANDA_STATE_ERROR;
532     return ctx;
533 }
534 
Lower(Context * ctx)535 __attribute__((unused)) static Context *Lower(Context *ctx)
536 {
537     if (ctx->state < ES2PANDA_STATE_CHECKED) {
538         ctx = Check(ctx);
539     }
540 
541     if (ctx->state == ES2PANDA_STATE_ERROR) {
542         return ctx;
543     }
544 
545     ES2PANDA_ASSERT(ctx->state == ES2PANDA_STATE_CHECKED);
546     while (auto phase = ctx->phaseManager->NextPhase()) {
547         phase->Apply(ctx, ctx->parserProgram);
548     }
549     ctx->state = !ctx->diagnosticEngine->IsAnyError() ? ES2PANDA_STATE_LOWERED : ES2PANDA_STATE_ERROR;
550     return ctx;
551 }
552 
GenerateAsm(Context * ctx)553 __attribute__((unused)) static Context *GenerateAsm(Context *ctx)
554 {
555     if (ctx->state < ES2PANDA_STATE_LOWERED) {
556         ctx = Lower(ctx);
557     }
558 
559     if (ctx->state == ES2PANDA_STATE_ERROR) {
560         return ctx;
561     }
562 
563     ES2PANDA_ASSERT(ctx->state == ES2PANDA_STATE_LOWERED);
564 
565     auto *emitter = ctx->emitter;
566     emitter->GenAnnotation();
567 
568     // Handle context literals.
569     uint32_t index = 0;
570     for (const auto &buff : ctx->contextLiterals) {
571         emitter->AddLiteralBuffer(buff, index++);
572     }
573 
574     emitter->LiteralBufferIndex() += ctx->contextLiterals.size();
575 
576     /* Main thread can also be used instead of idling */
577     ctx->queue->Schedule(ctx);
578     ctx->queue->Consume();
579     ctx->queue->Wait([emitter](compiler::CompileJob *job) { emitter->AddProgramElement(job->GetProgramElement()); });
580     ES2PANDA_ASSERT(ctx->program == nullptr);
581     ctx->program = emitter->Finalize(ctx->config->options->IsDumpDebugInfo(), compiler::Signatures::ETS_GLOBAL);
582     ctx->state = !ctx->diagnosticEngine->IsAnyError() ? ES2PANDA_STATE_ASM_GENERATED : ES2PANDA_STATE_ERROR;
583     return ctx;
584 }
585 
GenerateBin(Context * ctx)586 __attribute__((unused)) Context *GenerateBin(Context *ctx)
587 {
588     if (ctx->state < ES2PANDA_STATE_ASM_GENERATED) {
589         ctx = GenerateAsm(ctx);
590     }
591 
592     if (ctx->state == ES2PANDA_STATE_ERROR) {
593         return ctx;
594     }
595 
596     ES2PANDA_ASSERT(ctx->state == ES2PANDA_STATE_ASM_GENERATED);
597 
598     ES2PANDA_ASSERT(ctx->program != nullptr);
599     util::GenerateProgram(ctx->program, *ctx->config->options,
600                           [ctx](const diagnostic::DiagnosticKind &kind, const util::DiagnosticMessageParams &params) {
601                               ctx->diagnosticEngine->LogDiagnostic(kind, params);
602                           });
603     ctx->state = !ctx->diagnosticEngine->IsAnyError() ? ES2PANDA_STATE_BIN_GENERATED : ES2PANDA_STATE_ERROR;
604     return ctx;
605 }
606 
ProceedToState(es2panda_Context * context,es2panda_ContextState state)607 extern "C" __attribute__((unused)) es2panda_Context *ProceedToState(es2panda_Context *context,
608                                                                     es2panda_ContextState state)
609 {
610     auto *ctx = reinterpret_cast<Context *>(context);
611     switch (state) {
612         case ES2PANDA_STATE_NEW:
613             break;
614         case ES2PANDA_STATE_PARSED:
615             ctx = Parse(ctx);
616             break;
617         case ES2PANDA_STATE_BOUND:
618             ctx = Bind(ctx);
619             break;
620         case ES2PANDA_STATE_CHECKED:
621             ctx = Check(ctx);
622             break;
623         case ES2PANDA_STATE_LOWERED:
624             ctx = Lower(ctx);
625             break;
626         case ES2PANDA_STATE_ASM_GENERATED:
627             ctx = GenerateAsm(ctx);
628             break;
629         case ES2PANDA_STATE_BIN_GENERATED:
630             ctx = GenerateBin(ctx);
631             break;
632         default:
633             ctx->errorMessage = "It does not make sense to request stage";
634             ctx->state = ES2PANDA_STATE_ERROR;
635             break;
636     }
637     return reinterpret_cast<es2panda_Context *>(ctx);
638 }
639 
DestroyContext(es2panda_Context * context)640 extern "C" __attribute__((unused)) void DestroyContext(es2panda_Context *context)
641 {
642     auto *ctx = reinterpret_cast<Context *>(context);
643     delete ctx->program;
644     delete ctx->emitter;
645     delete ctx->analyzer;
646     delete ctx->checker;
647     delete ctx->parser;
648     delete ctx->parserProgram;
649     delete ctx->queue;
650     delete ctx->allocator;
651     delete ctx->sourceFile;
652     delete ctx->phaseManager;
653     delete ctx;
654 }
655 
ContextState(es2panda_Context * context)656 extern "C" __attribute__((unused)) es2panda_ContextState ContextState(es2panda_Context *context)
657 {
658     auto *s = reinterpret_cast<Context *>(context);
659     return s->state;
660 }
661 
ContextErrorMessage(es2panda_Context * context)662 extern "C" __attribute__((unused)) char const *ContextErrorMessage(es2panda_Context *context)
663 {
664     auto *s = reinterpret_cast<Context *>(context);
665     return s->errorMessage.c_str();
666 }
667 
ContextProgram(es2panda_Context * context)668 extern "C" __attribute__((unused)) es2panda_Program *ContextProgram(es2panda_Context *context)
669 {
670     auto *ctx = reinterpret_cast<Context *>(context);
671     return reinterpret_cast<es2panda_Program *>(ctx->parserProgram);
672 }
673 
674 using ExternalSourceEntry = std::pair<char *, ArenaVector<parser::Program *> *>;
675 
ExternalSourcesToE2p(ArenaAllocator * allocator,const parser::Program::ExternalSource & externalSources,size_t * lenP)676 __attribute__((unused)) static es2panda_ExternalSource **ExternalSourcesToE2p(
677     ArenaAllocator *allocator, const parser::Program::ExternalSource &externalSources, size_t *lenP)
678 {
679     auto *vec = allocator->New<ArenaVector<ExternalSourceEntry *>>(allocator->Adapter());
680 
681     for (auto &[e_name, e_programs] : externalSources) {
682         vec->push_back(allocator->New<ExternalSourceEntry>(StringViewToCString(allocator, e_name),
683                                                            const_cast<ArenaVector<parser::Program *> *>(&e_programs)));
684     }
685 
686     *lenP = vec->size();
687     return reinterpret_cast<es2panda_ExternalSource **>(vec->data());
688 }
689 
ExternalSourceName(es2panda_ExternalSource * eSource)690 extern "C" __attribute__((unused)) char const *ExternalSourceName(es2panda_ExternalSource *eSource)
691 {
692     auto *entry = reinterpret_cast<ExternalSourceEntry *>(eSource);
693     return entry->first;
694 }
695 
ExternalSourcePrograms(es2panda_ExternalSource * eSource,size_t * lenP)696 extern "C" __attribute__((unused)) es2panda_Program **ExternalSourcePrograms(es2panda_ExternalSource *eSource,
697                                                                              size_t *lenP)
698 {
699     auto *entry = reinterpret_cast<ExternalSourceEntry *>(eSource);
700     *lenP = entry->second->size();
701     return reinterpret_cast<es2panda_Program **>(entry->second->data());
702 }
703 
AstNodeForEach(es2panda_AstNode * ast,void (* func)(es2panda_AstNode *,void *),void * arg)704 extern "C" void AstNodeForEach(es2panda_AstNode *ast, void (*func)(es2panda_AstNode *, void *), void *arg)
705 {
706     auto *node = reinterpret_cast<ir::AstNode *>(ast);
707     func(ast, arg);
708     node->IterateRecursively([=](ir::AstNode *child) { func(reinterpret_cast<es2panda_AstNode *>(child), arg); });
709 }
710 
711 #define SET_NUMBER_LITERAL_IMPL(name, type)                                        \
712     extern "C" bool NumberLiteralSet##name(es2panda_AstNode *node, type new_value) \
713     {                                                                              \
714         auto &n = reinterpret_cast<ir::NumberLiteral *>(node)->Number();           \
715         if (!n.Is##name()) {                                                       \
716             /* CC-OFFNXT(G.PRE.05) function gen */                                 \
717             return false;                                                          \
718         }                                                                          \
719         n.SetValue<type>(std::move(new_value));                                    \
720         /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. */        \
721         return true;                                                               \
722     }
723 
SET_NUMBER_LITERAL_IMPL(Int,int32_t)724 SET_NUMBER_LITERAL_IMPL(Int, int32_t)
725 SET_NUMBER_LITERAL_IMPL(Long, int64_t)
726 SET_NUMBER_LITERAL_IMPL(Double, double)
727 SET_NUMBER_LITERAL_IMPL(Float, float)
728 
729 #undef SET_NUMBER_LITERAL_IMPL
730 
731 template <typename T>
732 es2panda_AstNode *CreateNumberLiteral(es2panda_Context *ctx, T value)
733 {
734     auto number = ark::es2panda::lexer::Number(value);
735     auto allocator = reinterpret_cast<Context *>(ctx)->allocator;
736     auto node = allocator->New<ir::NumberLiteral>(number);
737     return reinterpret_cast<es2panda_AstNode *>(node);
738 }
739 
740 template <typename T>
UpdateNumberLiteral(es2panda_Context * ctx,es2panda_AstNode * original,T value)741 es2panda_AstNode *UpdateNumberLiteral(es2panda_Context *ctx, es2panda_AstNode *original, T value)
742 {
743     auto number = ark::es2panda::lexer::Number(value);
744     auto allocator = reinterpret_cast<Context *>(ctx)->allocator;
745     auto node = allocator->New<ir::NumberLiteral>(number);
746     auto *e2pOriginal = reinterpret_cast<ir::AstNode *>(original);
747     node->SetOriginalNode(e2pOriginal);
748     node->SetParent(e2pOriginal->Parent());
749     node->SetRange(e2pOriginal->Range());
750     return reinterpret_cast<es2panda_AstNode *>(node);
751 }
752 
NumberLiteralStrConst(es2panda_Context * context,es2panda_AstNode * classInstance)753 extern "C" const char *NumberLiteralStrConst(es2panda_Context *context, es2panda_AstNode *classInstance)
754 {
755     auto str = reinterpret_cast<const ir::NumberLiteral *>(classInstance)->Str();
756     return StringViewToCString(reinterpret_cast<Context *>(context)->allocator, str);
757 }
758 
AllocMemory(es2panda_Context * context,size_t numberOfElements,size_t sizeOfElement)759 extern "C" void *AllocMemory(es2panda_Context *context, size_t numberOfElements, size_t sizeOfElement)
760 {
761     auto *allocator = reinterpret_cast<Context *>(context)->allocator;
762     void *ptr = allocator->Alloc(numberOfElements * sizeOfElement);
763     return ptr;
764 }
765 
CreateSourcePosition(es2panda_Context * context,size_t index,size_t line)766 extern "C" es2panda_SourcePosition *CreateSourcePosition(es2panda_Context *context, size_t index, size_t line)
767 {
768     auto *allocator = reinterpret_cast<Context *>(context)->allocator;
769     return reinterpret_cast<es2panda_SourcePosition *>(
770         allocator->New<lexer::SourcePosition>(index, line, reinterpret_cast<Context *>(context)->parserProgram));
771 }
772 
CreateSourceRange(es2panda_Context * context,es2panda_SourcePosition * start,es2panda_SourcePosition * end)773 extern "C" es2panda_SourceRange *CreateSourceRange(es2panda_Context *context, es2panda_SourcePosition *start,
774                                                    es2panda_SourcePosition *end)
775 {
776     auto *allocator = reinterpret_cast<Context *>(context)->allocator;
777     auto startE2p = *(reinterpret_cast<lexer::SourcePosition *>(start));
778     auto endE2p = *(reinterpret_cast<lexer::SourcePosition *>(end));
779     return reinterpret_cast<es2panda_SourceRange *>(allocator->New<lexer::SourceRange>(startE2p, endE2p));
780 }
781 
CreateDiagnosticKind(es2panda_Context * context,const char * dmessage,es2panda_PluginDiagnosticType etype)782 extern "C" const es2panda_DiagnosticKind *CreateDiagnosticKind(es2panda_Context *context, const char *dmessage,
783                                                                es2panda_PluginDiagnosticType etype)
784 {
785     auto ctx = reinterpret_cast<Context *>(context);
786     auto id = ctx->config->diagnosticKindStorage.size() + 1;
787     auto type = util::DiagnosticType::SUGGESTION;
788     if (etype == ES2PANDA_PLUGIN_WARNING) {
789         type = util::DiagnosticType::PLUGIN_WARNING;
790     } else if (etype == ES2PANDA_PLUGIN_ERROR) {
791         type = util::DiagnosticType::PLUGIN_ERROR;
792     }
793     ctx->config->diagnosticKindStorage.emplace_back(type, id, dmessage);
794     return reinterpret_cast<const es2panda_DiagnosticKind *>(&ctx->config->diagnosticKindStorage.back());
795 }
796 
CreateDiagnosticInfo(es2panda_Context * context,const es2panda_DiagnosticKind * kind,const char ** args,size_t argc)797 extern "C" es2panda_DiagnosticInfo *CreateDiagnosticInfo(es2panda_Context *context, const es2panda_DiagnosticKind *kind,
798                                                          const char **args, size_t argc)
799 {
800     auto *allocator = reinterpret_cast<Context *>(context)->allocator;
801     auto diagnosticInfo = allocator->New<es2panda_DiagnosticInfo>();
802     diagnosticInfo->kind = kind;
803     diagnosticInfo->args = args;
804     diagnosticInfo->argc = argc;
805     return diagnosticInfo;
806 }
807 
CreateSuggestionInfo(es2panda_Context * context,const es2panda_DiagnosticKind * kind,const char ** args,size_t argc,const char * substitutionCode)808 extern "C" es2panda_SuggestionInfo *CreateSuggestionInfo(es2panda_Context *context, const es2panda_DiagnosticKind *kind,
809                                                          const char **args, size_t argc, const char *substitutionCode)
810 {
811     auto *allocator = reinterpret_cast<Context *>(context)->allocator;
812     auto suggestionInfo = allocator->New<es2panda_SuggestionInfo>();
813     suggestionInfo->kind = kind;
814     suggestionInfo->args = args;
815     suggestionInfo->argc = argc;
816     suggestionInfo->substitutionCode = substitutionCode;
817     return suggestionInfo;
818 }
819 
LogDiagnosticWithSuggestion(es2panda_Context * context,const es2panda_DiagnosticInfo * diagnosticInfo,const es2panda_SuggestionInfo * suggestionInfo,es2panda_SourceRange * range)820 extern "C" void LogDiagnosticWithSuggestion(es2panda_Context *context, const es2panda_DiagnosticInfo *diagnosticInfo,
821                                             const es2panda_SuggestionInfo *suggestionInfo, es2panda_SourceRange *range)
822 {
823     auto ctx = reinterpret_cast<Context *>(context);
824     auto diagnostickind = reinterpret_cast<const diagnostic::DiagnosticKind *>(diagnosticInfo->kind);
825     auto suggestionkind = reinterpret_cast<const diagnostic::DiagnosticKind *>(suggestionInfo->kind);
826     util::DiagnosticMessageParams diagnosticParams;
827     for (size_t i = 0; i < diagnosticInfo->argc; ++i) {
828         diagnosticParams.push_back(diagnosticInfo->args[i]);
829     }
830 
831     std::vector<std::string> suggestionParams;
832 
833     for (size_t i = 0; i < suggestionInfo->argc; ++i) {
834         suggestionParams.push_back(suggestionInfo->args[i]);
835     }
836 
837     auto *allocator = reinterpret_cast<Context *>(context)->allocator;
838     auto E2pRange = reinterpret_cast<lexer::SourceRange *>(range);
839     auto posE2p = allocator->New<lexer::SourcePosition>(E2pRange->start);
840     auto suggestion = ctx->diagnosticEngine->CreateSuggestion(suggestionkind, suggestionParams,
841                                                               suggestionInfo->substitutionCode, E2pRange);
842     ctx->diagnosticEngine->LogDiagnostic(*diagnostickind, diagnosticParams, *posE2p, suggestion);
843 }
844 
LogDiagnostic(es2panda_Context * context,const es2panda_DiagnosticKind * ekind,const char ** args,size_t argc,es2panda_SourcePosition * pos)845 extern "C" void LogDiagnostic(es2panda_Context *context, const es2panda_DiagnosticKind *ekind, const char **args,
846                               size_t argc, es2panda_SourcePosition *pos)
847 {
848     auto ctx = reinterpret_cast<Context *>(context);
849     auto kind = reinterpret_cast<const diagnostic::DiagnosticKind *>(ekind);
850     util::DiagnosticMessageParams params;
851     for (size_t i = 0; i < argc; ++i) {
852         params.push_back(args[i]);
853     }
854     auto posE2p = reinterpret_cast<lexer::SourcePosition *>(pos);
855     ctx->diagnosticEngine->LogDiagnostic(*kind, params, *posE2p);
856 }
857 
GetDiagnostics(es2panda_Context * context,size_t etype)858 const es2panda_DiagnosticStorage *GetDiagnostics(es2panda_Context *context, size_t etype)
859 {
860     auto ctx = reinterpret_cast<Context *>(context);
861     auto type = static_cast<util::DiagnosticType>(etype);
862     return reinterpret_cast<const es2panda_DiagnosticStorage *>(&ctx->diagnosticEngine->GetDiagnosticStorage(type));
863 }
864 
GetSemanticErrors(es2panda_Context * context)865 extern "C" const es2panda_DiagnosticStorage *GetSemanticErrors(es2panda_Context *context)
866 {
867     return GetDiagnostics(context, util::DiagnosticType::SEMANTIC);
868 }
869 
GetSyntaxErrors(es2panda_Context * context)870 extern "C" const es2panda_DiagnosticStorage *GetSyntaxErrors(es2panda_Context *context)
871 {
872     return GetDiagnostics(context, util::DiagnosticType::SYNTAX);
873 }
874 
GetPluginErrors(es2panda_Context * context)875 extern "C" const es2panda_DiagnosticStorage *GetPluginErrors(es2panda_Context *context)
876 {
877     return GetDiagnostics(context, util::DiagnosticType::PLUGIN_ERROR);
878 }
879 
GetPluginWarnings(es2panda_Context * context)880 extern "C" const es2panda_DiagnosticStorage *GetPluginWarnings(es2panda_Context *context)
881 {
882     return GetDiagnostics(context, util::DiagnosticType::PLUGIN_WARNING);
883 }
884 
GetWarnings(es2panda_Context * context)885 extern "C" const es2panda_DiagnosticStorage *GetWarnings(es2panda_Context *context)
886 {
887     return GetDiagnostics(context, util::DiagnosticType::WARNING);
888 }
889 
IsAnyError(es2panda_Context * context)890 extern "C" bool IsAnyError(es2panda_Context *context)
891 {
892     return reinterpret_cast<Context *>(context)->diagnosticEngine->IsAnyError();
893 }
894 
SourcePositionIndex(es2panda_Context * context,es2panda_SourcePosition * position)895 extern "C" size_t SourcePositionIndex([[maybe_unused]] es2panda_Context *context, es2panda_SourcePosition *position)
896 {
897     return reinterpret_cast<lexer::SourcePosition *>(position)->index;
898 }
899 
SourcePositionLine(es2panda_Context * context,es2panda_SourcePosition * position)900 extern "C" size_t SourcePositionLine([[maybe_unused]] es2panda_Context *context, es2panda_SourcePosition *position)
901 {
902     return reinterpret_cast<lexer::SourcePosition *>(position)->line;
903 }
904 
SourceRangeStart(es2panda_Context * context,es2panda_SourceRange * range)905 extern "C" es2panda_SourcePosition *SourceRangeStart([[maybe_unused]] es2panda_Context *context,
906                                                      es2panda_SourceRange *range)
907 {
908     auto *allocator = reinterpret_cast<Context *>(context)->allocator;
909     auto E2pRange = reinterpret_cast<lexer::SourceRange *>(range);
910     return reinterpret_cast<es2panda_SourcePosition *>(allocator->New<lexer::SourcePosition>(E2pRange->start));
911 }
912 
SourceRangeEnd(es2panda_Context * context,es2panda_SourceRange * range)913 extern "C" es2panda_SourcePosition *SourceRangeEnd([[maybe_unused]] es2panda_Context *context,
914                                                    es2panda_SourceRange *range)
915 {
916     auto *allocator = reinterpret_cast<Context *>(context)->allocator;
917     auto E2pRange = reinterpret_cast<lexer::SourceRange *>(range);
918     return reinterpret_cast<es2panda_SourcePosition *>(allocator->New<lexer::SourcePosition>(E2pRange->end));
919 }
920 
AstNodeFindNearestScope(es2panda_Context * ctx,es2panda_AstNode * node)921 extern "C" es2panda_Scope *AstNodeFindNearestScope([[maybe_unused]] es2panda_Context *ctx, es2panda_AstNode *node)
922 {
923     auto E2pNode = reinterpret_cast<ir::AstNode *>(node);
924     return reinterpret_cast<es2panda_Scope *>(compiler::NearestScope(E2pNode));
925 }
926 
AstNodeRebind(es2panda_Context * ctx,es2panda_AstNode * node)927 extern "C" es2panda_Scope *AstNodeRebind(es2panda_Context *ctx, es2panda_AstNode *node)
928 {
929     auto E2pNode = reinterpret_cast<ir::AstNode *>(node);
930     auto context = reinterpret_cast<Context *>(ctx);
931     auto varbinder = context->parserProgram->VarBinder()->AsETSBinder();
932     auto phaseManager = context->phaseManager;
933     if (E2pNode->IsScriptFunction() ||
934         E2pNode->FindChild([](ir::AstNode *n) { return n->IsScriptFunction(); }) != nullptr) {
935         while (!E2pNode->IsProgram()) {
936             E2pNode = E2pNode->Parent();
937         }
938     }
939     return reinterpret_cast<es2panda_Scope *>(compiler::Rebind(phaseManager, varbinder, E2pNode));
940 }
941 
AstNodeRecheck(es2panda_Context * ctx,es2panda_AstNode * node)942 extern "C" void AstNodeRecheck(es2panda_Context *ctx, es2panda_AstNode *node)
943 {
944     auto E2pNode = reinterpret_cast<ir::AstNode *>(node);
945     auto context = reinterpret_cast<Context *>(ctx);
946     auto varbinder = context->parserProgram->VarBinder()->AsETSBinder();
947     auto checker = context->checker->AsETSChecker();
948     auto phaseManager = context->phaseManager;
949     if (E2pNode->IsScriptFunction() ||
950         E2pNode->FindChild([](ir::AstNode *n) { return n->IsScriptFunction(); }) != nullptr) {
951         while (!E2pNode->IsProgram()) {
952             E2pNode = E2pNode->Parent();
953         }
954     }
955     compiler::Recheck(phaseManager, varbinder, checker, E2pNode);
956     context->state = !context->diagnosticEngine->IsAnyError() ? ES2PANDA_STATE_CHECKED : ES2PANDA_STATE_ERROR;
957     return;
958 }
959 
960 #include "generated/es2panda_lib/es2panda_lib_impl.inc"
961 
Es2pandaEnumFromString(es2panda_Context * ctx,const char * str)962 extern "C" Es2pandaEnum Es2pandaEnumFromString([[maybe_unused]] es2panda_Context *ctx, const char *str)
963 {
964     return IrToE2pEnum(es2panda::util::gen::ast_verifier::FromString(str));
965 }
966 
Es2pandaEnumToString(es2panda_Context * ctx,Es2pandaEnum id)967 extern "C" char *Es2pandaEnumToString(es2panda_Context *ctx, Es2pandaEnum id)
968 {
969     auto *allocator = reinterpret_cast<Context *>(ctx)->allocator;
970     return StringViewToCString(allocator, es2panda::util::gen::ast_verifier::ToString(E2pToIrEnum(id)));
971 }
972 
DeclarationFromIdentifier(es2panda_Context * ctx,es2panda_AstNode * node)973 extern "C" es2panda_AstNode *DeclarationFromIdentifier([[maybe_unused]] es2panda_Context *ctx, es2panda_AstNode *node)
974 {
975     auto E2pNode = reinterpret_cast<ir::Identifier *>(node);
976     return reinterpret_cast<es2panda_AstNode *>(compiler::DeclarationFromIdentifier(E2pNode));
977 }
978 
FirstDeclarationByNameFromNode(es2panda_Context * ctx,const es2panda_AstNode * node,const char * name)979 extern "C" es2panda_AstNode *FirstDeclarationByNameFromNode([[maybe_unused]] es2panda_Context *ctx,
980                                                             const es2panda_AstNode *node, const char *name)
981 {
982     if (node == nullptr) {
983         return nullptr;
984     }
985 
986     util::StringView nameE2p {name};
987     ir::AstNode *res = reinterpret_cast<const ir::AstNode *>(node)->FindChild([&nameE2p](const ir::AstNode *ast) {
988         if (ast != nullptr && ast->IsMethodDefinition() && ast->AsMethodDefinition()->Key() != nullptr &&
989             ast->AsMethodDefinition()->Key()->IsIdentifier() &&
990             ast->AsMethodDefinition()->Key()->AsIdentifier()->Name() == nameE2p) {
991             return true;
992         }
993 
994         return false;
995     });
996 
997     return reinterpret_cast<es2panda_AstNode *>(res);
998 }
999 
FirstDeclarationByNameFromProgram(es2panda_Context * ctx,const es2panda_Program * program,const char * name)1000 extern "C" es2panda_AstNode *FirstDeclarationByNameFromProgram([[maybe_unused]] es2panda_Context *ctx,
1001                                                                const es2panda_Program *program, const char *name)
1002 {
1003     if (program == nullptr) {
1004         return nullptr;
1005     }
1006 
1007     auto programE2p = reinterpret_cast<const parser::Program *>(program);
1008     es2panda_AstNode *res =
1009         FirstDeclarationByNameFromNode(ctx, reinterpret_cast<const es2panda_AstNode *>(programE2p->Ast()), name);
1010     if (res != nullptr) {
1011         return res;
1012     }
1013 
1014     for (const auto &ext_source : programE2p->DirectExternalSources()) {
1015         for (const auto *ext_program : ext_source.second) {
1016             if (ext_program != nullptr) {
1017                 res = FirstDeclarationByNameFromNode(
1018                     ctx, reinterpret_cast<const es2panda_AstNode *>(ext_program->Ast()), name);
1019             }
1020             if (res != nullptr) {
1021                 return res;
1022             }
1023         }
1024     }
1025 
1026     return nullptr;
1027 }
1028 
AllDeclarationsByNameFromNodeHelper(ArenaAllocator * const allocator,const ir::AstNode * node,const util::StringView & name)1029 static ArenaSet<ir::AstNode *> AllDeclarationsByNameFromNodeHelper(ArenaAllocator *const allocator,
1030                                                                    const ir::AstNode *node,
1031                                                                    const util::StringView &name)
1032 {
1033     auto result = ArenaSet<ir::AstNode *> {allocator->Adapter()};
1034 
1035     if (node == nullptr) {
1036         return result;
1037     }
1038 
1039     node->IterateRecursively([&result, &name](ir::AstNode *ast) {
1040         if (ast != nullptr && ast->IsMethodDefinition() && ast->AsMethodDefinition()->Key() != nullptr &&
1041             ast->AsMethodDefinition()->Key()->IsIdentifier() &&
1042             ast->AsMethodDefinition()->Key()->AsIdentifier()->Name() == name) {
1043             result.insert(ast);
1044         }
1045     });
1046 
1047     return result;
1048 }
1049 
AllDeclarationsByNameFromNode(es2panda_Context * ctx,const es2panda_AstNode * node,const char * name,size_t * declsLen)1050 extern "C" es2panda_AstNode **AllDeclarationsByNameFromNode([[maybe_unused]] es2panda_Context *ctx,
1051                                                             const es2panda_AstNode *node, const char *name,
1052                                                             size_t *declsLen)
1053 {
1054     util::StringView nameE2p {name};
1055     auto nodeE2p = reinterpret_cast<const ir::AstNode *>(node);
1056     auto allocator = reinterpret_cast<Context *>(ctx)->allocator;
1057     auto result = AllDeclarationsByNameFromNodeHelper(allocator, nodeE2p, nameE2p);
1058     *declsLen = result.size();
1059     auto apiRes = allocator->New<es2panda_AstNode *[]>(*declsLen);
1060     size_t i = 0;
1061     for (auto elem : result) {
1062         auto toPush = reinterpret_cast<es2panda_AstNode *>(elem);
1063         apiRes[i++] = toPush;
1064     };
1065     return apiRes;
1066 }
1067 
AllDeclarationsByNameFromProgram(es2panda_Context * ctx,const es2panda_Program * program,const char * name,size_t * declsLen)1068 extern "C" es2panda_AstNode **AllDeclarationsByNameFromProgram([[maybe_unused]] es2panda_Context *ctx,
1069                                                                const es2panda_Program *program, const char *name,
1070                                                                size_t *declsLen)
1071 {
1072     auto allocator = reinterpret_cast<Context *>(ctx)->allocator;
1073     if (program == nullptr) {
1074         *declsLen = 0;
1075         return allocator->New<es2panda_AstNode *[]>(0);
1076     }
1077 
1078     util::StringView nameE2p {name};
1079     auto programE2p = reinterpret_cast<const parser::Program *>(program);
1080     auto result = ArenaSet<ir::AstNode *> {allocator->Adapter()};
1081 
1082     ArenaSet<ir::AstNode *> res = AllDeclarationsByNameFromNodeHelper(allocator, programE2p->Ast(), nameE2p);
1083     result.insert(res.begin(), res.end());
1084 
1085     for (const auto &ext_source : programE2p->DirectExternalSources()) {
1086         for (const auto *ext_program : ext_source.second) {
1087             if (ext_program != nullptr) {
1088                 res = AllDeclarationsByNameFromNodeHelper(allocator, ext_program->Ast(), nameE2p);
1089                 result.insert(res.begin(), res.end());
1090             }
1091         }
1092     }
1093 
1094     *declsLen = result.size();
1095     auto apiRes = allocator->New<es2panda_AstNode *[]>(*declsLen);
1096     size_t i = 0;
1097     for (auto elem : result) {
1098         auto toPush = reinterpret_cast<es2panda_AstNode *>(elem);
1099         apiRes[i++] = toPush;
1100     };
1101 
1102     return apiRes;
1103 }
1104 
GenerateTsDeclarationsFromContext(es2panda_Context * ctx,const char * outputDeclEts,const char * outputEts,bool exportAll,const char * recordFile)1105 extern "C" __attribute__((unused)) int GenerateTsDeclarationsFromContext(es2panda_Context *ctx,
1106                                                                          const char *outputDeclEts,
1107                                                                          const char *outputEts, bool exportAll,
1108                                                                          const char *recordFile)
1109 {
1110     auto *ctxImpl = reinterpret_cast<Context *>(ctx);
1111     auto *checker = reinterpret_cast<ark::es2panda::checker::ETSChecker *>(ctxImpl->checker);
1112 
1113     ark::es2panda::declgen_ets2ts::DeclgenOptions declgenOptions;
1114     declgenOptions.exportAll = exportAll;
1115     declgenOptions.outputDeclEts = outputDeclEts ? outputDeclEts : "";
1116     declgenOptions.outputEts = outputEts ? outputEts : "";
1117     declgenOptions.recordFile = recordFile ? recordFile : "";
1118 
1119     return ark::es2panda::declgen_ets2ts::GenerateTsDeclarations(checker, ctxImpl->parserProgram, declgenOptions) ? 0
1120                                                                                                                   : 1;
1121 }
1122 
1123 // Will be removed after binary import support is fully implemented.
GenerateStaticDeclarationsFromContext(es2panda_Context * ctx,const char * outputPath)1124 extern "C" __attribute__((unused)) int GenerateStaticDeclarationsFromContext(es2panda_Context *ctx,
1125                                                                              const char *outputPath)
1126 {
1127     auto *ctxImpl = reinterpret_cast<Context *>(ctx);
1128     if (ctxImpl->state != ES2PANDA_STATE_CHECKED) {
1129         return 1;
1130     }
1131     compiler::HandleGenerateDecl(*ctxImpl->parserProgram, *ctxImpl->diagnosticEngine, outputPath, false);
1132 
1133     return ctxImpl->diagnosticEngine->IsAnyError() ? 1 : 0;
1134 }
1135 
InsertETSImportDeclarationAndParse(es2panda_Context * context,es2panda_Program * program,es2panda_AstNode * importDeclaration)1136 extern "C" void InsertETSImportDeclarationAndParse(es2panda_Context *context, es2panda_Program *program,
1137                                                    es2panda_AstNode *importDeclaration)
1138 {
1139     auto *ctx = reinterpret_cast<Context *>(context);
1140     auto *parserProgram = reinterpret_cast<parser::Program *>(program);
1141     auto *importDeclE2p = reinterpret_cast<ir::ETSImportDeclaration *>(importDeclaration);
1142     importDeclE2p->AddAstNodeFlags(ir::AstNodeFlags::NOCLEANUP);
1143 
1144     parserProgram->Ast()->Statements().insert(parserProgram->Ast()->Statements().begin(), importDeclE2p);
1145     importDeclE2p->SetParent(parserProgram->Ast());
1146 
1147     ctx->parser->AsETSParser()->AddExternalSource(ctx->parser->AsETSParser()->ParseSources());
1148 
1149     for ([[maybe_unused]] auto *specific : importDeclE2p->Specifiers()) {
1150         ES2PANDA_ASSERT(specific->Parent() != nullptr);
1151     }
1152 }
1153 
1154 es2panda_Impl g_impl = {
1155     ES2PANDA_LIB_VERSION,
1156 
1157     CreateConfig,
1158     DestroyConfig,
1159     GetAllErrorMessages,
1160     ConfigGetOptions,
1161     CreateContextFromFile,
1162     CreateContextFromString,
1163     CreateContextGenerateAbcForExternalSourceFiles,
1164     ProceedToState,
1165     DestroyContext,
1166     ContextState,
1167     ContextErrorMessage,
1168     ContextProgram,
1169     ExternalSourceName,
1170     ExternalSourcePrograms,
1171     AstNodeForEach,
1172     NumberLiteralSetInt,
1173     NumberLiteralSetLong,
1174     NumberLiteralSetDouble,
1175     NumberLiteralSetFloat,
1176     CreateNumberLiteral<int32_t>,
1177     UpdateNumberLiteral<int32_t>,
1178     CreateNumberLiteral<int64_t>,
1179     UpdateNumberLiteral<int64_t>,
1180     CreateNumberLiteral<double>,
1181     UpdateNumberLiteral<double>,
1182     CreateNumberLiteral<float>,
1183     UpdateNumberLiteral<float>,
1184     NumberLiteralStrConst,
1185     AllocMemory,
1186     CreateSourcePosition,
1187     CreateSourceRange,
1188     SourcePositionIndex,
1189     SourcePositionLine,
1190     SourceRangeStart,
1191     SourceRangeEnd,
1192     CreateDiagnosticKind,
1193     CreateDiagnosticInfo,
1194     CreateSuggestionInfo,
1195     LogDiagnosticWithSuggestion,
1196     LogDiagnostic,
1197     GetSemanticErrors,
1198     GetSyntaxErrors,
1199     GetPluginErrors,
1200     GetWarnings,
1201     IsAnyError,
1202     AstNodeFindNearestScope,
1203     AstNodeRebind,
1204     AstNodeRecheck,
1205     Es2pandaEnumFromString,
1206     Es2pandaEnumToString,
1207     DeclarationFromIdentifier,
1208     FirstDeclarationByNameFromNode,
1209     FirstDeclarationByNameFromProgram,
1210     AllDeclarationsByNameFromNode,
1211     AllDeclarationsByNameFromProgram,
1212     GenerateTsDeclarationsFromContext,
1213     InsertETSImportDeclarationAndParse,
1214     GenerateStaticDeclarationsFromContext,
1215 
1216 #include "generated/es2panda_lib/es2panda_lib_list.inc"
1217 
1218 };
1219 
1220 }  // namespace ark::es2panda::public_lib
1221 
es2panda_GetImpl(int version)1222 extern "C" es2panda_Impl const *es2panda_GetImpl(int version)
1223 {
1224     if (version != ES2PANDA_LIB_VERSION) {
1225         return nullptr;
1226     }
1227     return &ark::es2panda::public_lib::g_impl;
1228 }
1229 
1230 // NOLINTEND
1231