• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "varbinder/varbinder.h"
21 #include "varbinder/scope.h"
22 #include "public/public.h"
23 #include "generated/signatures.h"
24 #include "es2panda.h"
25 #include "varbinder/ETSBinder.h"
26 #include "checker/ETSAnalyzer.h"
27 #include "checker/ETSchecker.h"
28 #include "compiler/core/compileQueue.h"
29 #include "compiler/core/ETSCompiler.h"
30 #include "compiler/core/ETSemitter.h"
31 #include "compiler/core/ETSGen.h"
32 #include "compiler/core/regSpiller.h"
33 #include "compiler/lowering/phase.h"
34 #include "compiler/lowering/checkerPhase.h"
35 #include "compiler/lowering/scopesInit/scopesInitPhase.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 "generated/es2panda_lib/es2panda_lib_include.inc"
56 
57 // NOLINTBEGIN
58 
59 namespace ark::es2panda::public_lib {
60 
61 struct TokenTypeToStr {
62     lexer::TokenType token;
63     char const *str;
64 };
65 
StrToToken(TokenTypeToStr const * table,char const * str)66 __attribute__((unused)) lexer::TokenType StrToToken(TokenTypeToStr const *table, char const *str)
67 {
68     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
69     for (auto *tp = table; tp->str != nullptr; tp++) {
70         if (strcmp(str, tp->str) == 0) {
71             return tp->token;
72         }
73     }
74     UNREACHABLE();
75 }
76 
TokenToStr(TokenTypeToStr const * table,lexer::TokenType token)77 __attribute__((unused)) char const *TokenToStr(TokenTypeToStr const *table, lexer::TokenType token)
78 {
79     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
80     for (auto *tp = table; tp->str != nullptr; tp++) {
81         if (tp->token == token) {
82             return tp->str;
83         }
84     }
85     UNREACHABLE();
86 }
87 
StringViewToCString(ArenaAllocator * allocator,util::StringView const sv)88 __attribute__((unused)) char *StringViewToCString(ArenaAllocator *allocator, util::StringView const sv)
89 {
90     // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic, readability-simplify-subscript-expr)
91     std::string_view utf8 = sv.Utf8();
92     if (utf8.data()[utf8.size()] == '\0') {
93         // Avoid superfluous allocation.
94         return const_cast<char *>(utf8.data());
95     }
96     char *res = reinterpret_cast<char *>(allocator->Alloc(utf8.size() + 1));
97     [[maybe_unused]] auto err = memmove_s(res, utf8.size() + 1, utf8.cbegin(), utf8.size());
98     ASSERT(err == EOK);
99     res[utf8.size()] = '\0';
100     return res;
101     // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic, readability-simplify-subscript-expr)
102 }
103 
StringViewToCString(ArenaAllocator * allocator,std::string_view const utf8)104 char *StringViewToCString(ArenaAllocator *allocator, std::string_view const utf8)
105 {
106     // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic, readability-simplify-subscript-expr)
107     if (utf8.data()[utf8.size()] == '\0') {
108         // Avoid superfluous allocation.
109         return const_cast<char *>(utf8.data());
110     }
111     char *res = reinterpret_cast<char *>(allocator->Alloc(utf8.size() + 1));
112     [[maybe_unused]] auto err = memmove_s(res, utf8.size() + 1, utf8.cbegin(), utf8.size());
113     ASSERT(err == EOK);
114     res[utf8.size()] = '\0';
115     return res;
116     // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic, readability-simplify-subscript-expr)
117 }
118 
StdStringToCString(ArenaAllocator * allocator,std::string str)119 __attribute__((unused)) char *StdStringToCString(ArenaAllocator *allocator, std::string str)
120 {
121     // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic, readability-simplify-subscript-expr)
122     char *res = reinterpret_cast<char *>(allocator->Alloc(str.length() + 1));
123     [[maybe_unused]] auto err = memcpy_s(res, str.length() + 1, str.c_str(), str.length() + 1);
124     ASSERT(err == EOK);
125     return res;
126     // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic, readability-simplify-subscript-expr)
127 }
128 
UStringToCString(ArenaAllocator * allocator,util::UString const sv)129 __attribute__((unused)) char *UStringToCString(ArenaAllocator *allocator, util::UString const sv)
130 {
131     return StringViewToCString(allocator, sv.View());
132 }
133 
EnumMemberResultToEs2pandaVariant(ArenaAllocator * allocator,varbinder::EnumMemberResult variant)134 __attribute__((unused)) es2panda_variantDoubleCharArrayBool EnumMemberResultToEs2pandaVariant(
135     ArenaAllocator *allocator, varbinder::EnumMemberResult variant)
136 {
137     // NOLINTBEGIN(cppcoreguidelines-pro-type-union-access)
138     // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic, readability-simplify-subscript-expr)
139     es2panda_variantDoubleCharArrayBool es2panda_variant;
140     es2panda_variant.index = variant.index();
141     switch (es2panda_variant.index) {
142         case es2panda_variantIndex::DOUBLE:
143             es2panda_variant.variant.d = std::get<double>(variant);
144             break;
145         case es2panda_variantIndex::CHAR:
146             es2panda_variant.variant.c = StringViewToCString(allocator, std::get<util::StringView>(variant));
147             break;
148         case es2panda_variantIndex::BOOL:
149             es2panda_variant.variant.b = std::get<bool>(variant);
150             break;
151         default:
152             break;
153     }
154     return es2panda_variant;
155     // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic, readability-simplify-subscript-expr)
156     // NOLINTEND(cppcoreguidelines-pro-type-union-access)
157 }
158 
DynamicImportDataToE2p(ArenaAllocator * allocator,const varbinder::DynamicImportData * dynamicImportData)159 __attribute__((unused)) es2panda_DynamicImportData *DynamicImportDataToE2p(
160     ArenaAllocator *allocator, const varbinder::DynamicImportData *dynamicImportData)
161 {
162     auto import = reinterpret_cast<const es2panda_AstNode *>(dynamicImportData->import);
163     auto specifier = reinterpret_cast<const es2panda_AstNode *>(dynamicImportData->specifier);
164     auto variable = reinterpret_cast<es2panda_Variable *>(dynamicImportData->variable);
165     auto es2pandaDynamicImportData = allocator->New<es2panda_DynamicImportData>();
166     es2pandaDynamicImportData->import = import;
167     es2pandaDynamicImportData->specifier = specifier;
168     es2pandaDynamicImportData->variable = variable;
169     return es2pandaDynamicImportData;
170 }
171 
DynamicImportDataToE2p(const varbinder::DynamicImportData dynamicImportData)172 __attribute__((unused)) es2panda_DynamicImportData DynamicImportDataToE2p(
173     const varbinder::DynamicImportData dynamicImportData)
174 {
175     auto import = reinterpret_cast<const es2panda_AstNode *>(dynamicImportData.import);
176     auto specifier = reinterpret_cast<const es2panda_AstNode *>(dynamicImportData.specifier);
177     auto variable = reinterpret_cast<es2panda_Variable *>(dynamicImportData.variable);
178     es2panda_DynamicImportData es2pandaDynamicImportData;
179     es2pandaDynamicImportData.import = import;
180     es2pandaDynamicImportData.specifier = specifier;
181     es2pandaDynamicImportData.variable = variable;
182     return es2pandaDynamicImportData;
183 }
184 
ArenaStrdup(ArenaAllocator * allocator,char const * src)185 __attribute__((unused)) char const *ArenaStrdup(ArenaAllocator *allocator, char const *src)
186 {
187     size_t len = strlen(src);
188     char *res = reinterpret_cast<char *>(allocator->Alloc(len + 1));
189     [[maybe_unused]] auto err = memmove_s(res, len + 1, src, len);
190     ASSERT(err == EOK);
191 
192     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
193     res[len] = '\0';
194     return res;
195 }
196 
CreateConfig(int args,char const ** argv)197 extern "C" es2panda_Config *CreateConfig(int args, char const **argv)
198 {
199     constexpr auto COMPILER_SIZE = 256_MB;
200 
201     mem::MemConfig::Initialize(0, 0, COMPILER_SIZE, 0, 0, 0);
202     PoolManager::Initialize(PoolType::MMAP);
203 
204     auto *options = new util::Options();
205     if (!options->Parse(args, argv)) {
206         // NOTE: gogabr. report option errors properly.
207         std::cerr << options->ErrorMsg() << std::endl;
208         return nullptr;
209     }
210     Logger::ComponentMask mask {};
211     mask.set(Logger::Component::ES2PANDA);
212     Logger::InitializeStdLogging(Logger::LevelFromString(options->LogLevel()), mask);
213 
214     auto *res = new ConfigImpl;
215     res->options = options;
216     return reinterpret_cast<es2panda_Config *>(res);
217 }
218 
DestroyConfig(es2panda_Config * config)219 extern "C" void DestroyConfig(es2panda_Config *config)
220 {
221     PoolManager::Finalize();
222     mem::MemConfig::Finalize();
223 
224     auto *cfg = reinterpret_cast<ConfigImpl *>(config);
225     if (cfg == nullptr) {
226         return;
227     }
228 
229     delete cfg->options;
230     delete cfg;
231 }
232 
CompileJob(public_lib::Context * context,varbinder::FunctionScope * scope,compiler::ProgramElement * programElement)233 static void CompileJob(public_lib::Context *context, varbinder::FunctionScope *scope,
234                        compiler::ProgramElement *programElement)
235 {
236     compiler::StaticRegSpiller regSpiller;
237     ArenaAllocator allocator {SpaceType::SPACE_TYPE_COMPILER, nullptr, true};
238     compiler::ETSCompiler astCompiler {};
239     compiler::ETSGen cg {&allocator, &regSpiller, context, std::make_tuple(scope, programElement, &astCompiler)};
240     compiler::ETSFunctionEmitter funcEmitter {&cg, programElement};
241     funcEmitter.Generate();
242 }
243 
CreateContext(es2panda_Config * config,std::string const && source,std::string const && fileName)244 __attribute__((unused)) static es2panda_Context *CreateContext(es2panda_Config *config, std::string const &&source,
245                                                                std::string const &&fileName)
246 {
247     auto *cfg = reinterpret_cast<ConfigImpl *>(config);
248     auto *res = new Context;
249     res->input = source;
250     res->sourceFileName = fileName;
251     res->config = cfg;
252 
253     try {
254         res->sourceFile = new SourceFile(res->sourceFileName, res->input, cfg->options->ParseModule());
255         res->allocator = new ArenaAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true);
256         res->queue = new compiler::CompileQueue(cfg->options->ThreadCount());
257 
258         auto *varbinder = res->allocator->New<varbinder::ETSBinder>(res->allocator);
259         res->parserProgram = new parser::Program(res->allocator, varbinder);
260         res->parserProgram->MarkEntry();
261         res->parser =
262             new parser::ETSParser(res->parserProgram, cfg->options->CompilerOptions(), parser::ParserStatus::NO_OPTS);
263         res->checker = new checker::ETSChecker();
264         res->checker->ErrorLogger()->SetOstream(nullptr);
265         res->analyzer = new checker::ETSAnalyzer(res->checker);
266         res->checker->SetAnalyzer(res->analyzer);
267 
268         varbinder->SetProgram(res->parserProgram);
269 
270         varbinder->SetContext(res);
271         res->codeGenCb = CompileJob;
272         res->phases = compiler::GetPhaseList(ScriptExtension::ETS);
273         res->currentPhase = 0;
274         res->emitter = new compiler::ETSEmitter(res);
275         res->program = nullptr;
276         res->state = ES2PANDA_STATE_NEW;
277     } catch (Error &e) {
278         std::stringstream ss;
279         ss << e.TypeString() << ": " << e.Message() << "[" << e.File() << ":" << e.Line() << "," << e.Col() << "]";
280         res->errorMessage = ss.str();
281         res->state = ES2PANDA_STATE_ERROR;
282     }
283     return reinterpret_cast<es2panda_Context *>(res);
284 }
285 
CreateContextFromFile(es2panda_Config * config,char const * sourceFileName)286 extern "C" __attribute__((unused)) es2panda_Context *CreateContextFromFile(es2panda_Config *config,
287                                                                            char const *sourceFileName)
288 {
289     std::ifstream inputStream;
290     inputStream.open(sourceFileName);
291     if (inputStream.fail()) {
292         auto *res = new Context;
293         res->errorMessage = "Failed to open file: ";
294         res->errorMessage.append(sourceFileName);
295         return reinterpret_cast<es2panda_Context *>(res);
296     }
297     std::stringstream ss;
298     ss << inputStream.rdbuf();
299     if (inputStream.fail()) {
300         auto *res = new Context;
301         res->errorMessage = "Failed to read file: ";
302         res->errorMessage.append(sourceFileName);
303         return reinterpret_cast<es2panda_Context *>(res);
304     }
305     return CreateContext(config, ss.str(), sourceFileName);
306 }
307 
CreateContextFromString(es2panda_Config * config,char const * source,char const * fileName)308 extern "C" __attribute__((unused)) es2panda_Context *CreateContextFromString(es2panda_Config *config,
309                                                                              char const *source, char const *fileName)
310 {
311     // NOTE: gogabr. avoid copying source.
312     return CreateContext(config, source, fileName);
313 }
314 
Parse(Context * ctx)315 __attribute__((unused)) static Context *Parse(Context *ctx)
316 {
317     if (ctx->state != ES2PANDA_STATE_NEW) {
318         ctx->state = ES2PANDA_STATE_ERROR;
319         ctx->errorMessage = "Bad state at entry to Parse, needed NEW";
320         return ctx;
321     }
322     auto handleError = [ctx](Error const &e) {
323         std::stringstream ss;
324         ss << e.TypeString() << ": " << e.Message() << "[" << e.File() << ":" << e.Line() << "," << e.Col() << "]";
325         ctx->errorMessage = ss.str();
326         ctx->state = ES2PANDA_STATE_ERROR;
327     };
328 
329     try {
330         ctx->parser->ParseScript(*ctx->sourceFile, ctx->config->options->CompilerOptions().compilationMode ==
331                                                        CompilationMode::GEN_STD_LIB);
332         ctx->state = ES2PANDA_STATE_PARSED;
333         if (ctx->parser->ErrorLogger()->IsAnyError()) {
334             handleError(ctx->parser->ErrorLogger()->Log()[0]);
335         }
336     } catch (Error &e) {
337         std::stringstream ss;
338         ss << e.TypeString() << ": " << e.Message() << "[" << e.File() << ":" << e.Line() << "," << e.Col() << "]";
339         ctx->errorMessage = ss.str();
340         ctx->state = ES2PANDA_STATE_ERROR;
341     }
342 
343     return ctx;
344 }
345 
InitScopes(Context * ctx)346 __attribute__((unused)) static Context *InitScopes(Context *ctx)
347 {
348     // NOTE: Remove duplicated code in all phases
349     if (ctx->state < ES2PANDA_STATE_PARSED) {
350         ctx = Parse(ctx);
351     }
352     if (ctx->state == ES2PANDA_STATE_ERROR) {
353         return ctx;
354     }
355 
356     ASSERT(ctx->state == ES2PANDA_STATE_PARSED);
357 
358     try {
359         do {
360             if (ctx->currentPhase >= ctx->phases.size()) {
361                 break;
362             }
363             ctx->phases[ctx->currentPhase]->Apply(ctx, ctx->parserProgram);
364         } while (ctx->phases[ctx->currentPhase++]->Name() != compiler::ScopesInitPhase::NAME);
365         ctx->state = ES2PANDA_STATE_SCOPE_INITED;
366     } catch (Error &e) {
367         std::stringstream ss;
368         ss << e.TypeString() << ": " << e.Message() << "[" << e.File() << ":" << e.Line() << "," << e.Col() << "]";
369         ctx->errorMessage = ss.str();
370         ctx->state = ES2PANDA_STATE_ERROR;
371     }
372     return ctx;
373 }
374 
Check(Context * ctx)375 __attribute__((unused)) static Context *Check(Context *ctx)
376 {
377     if (ctx->state < ES2PANDA_STATE_PARSED) {
378         ctx = Parse(ctx);
379     }
380 
381     if (ctx->state == ES2PANDA_STATE_ERROR) {
382         return ctx;
383     }
384 
385     ASSERT(ctx->state >= ES2PANDA_STATE_PARSED && ctx->state < ES2PANDA_STATE_CHECKED);
386 
387     auto handleError = [ctx](Error const &e) {
388         std::stringstream ss;
389         ss << e.TypeString() << ": " << e.Message() << "[" << e.File() << ":" << e.Line() << "," << e.Col() << "]";
390         ctx->errorMessage = ss.str();
391         ctx->state = ES2PANDA_STATE_ERROR;
392     };
393 
394     try {
395         do {
396             if (ctx->currentPhase >= ctx->phases.size()) {
397                 break;
398             }
399 
400             ctx->phases[ctx->currentPhase]->Apply(ctx, ctx->parserProgram);
401         } while (ctx->phases[ctx->currentPhase++]->Name() != compiler::CheckerPhase::NAME);
402         if (ctx->checker->ErrorLogger()->IsAnyError()) {
403             handleError(ctx->checker->ErrorLogger()->Log()[0]);
404         } else if (ctx->parser->ErrorLogger()->IsAnyError()) {
405             handleError(ctx->parser->ErrorLogger()->Log()[0]);
406         } else {
407             ctx->state = ES2PANDA_STATE_CHECKED;
408         }
409     } catch (Error &e) {
410         handleError(e);
411     }
412     return ctx;
413 }
414 
Lower(Context * ctx)415 __attribute__((unused)) static Context *Lower(Context *ctx)
416 {
417     if (ctx->state < ES2PANDA_STATE_CHECKED) {
418         ctx = Check(ctx);
419     }
420 
421     if (ctx->state == ES2PANDA_STATE_ERROR) {
422         return ctx;
423     }
424 
425     ASSERT(ctx->state == ES2PANDA_STATE_CHECKED);
426 
427     try {
428         while (ctx->currentPhase < ctx->phases.size()) {
429             ctx->phases[ctx->currentPhase++]->Apply(ctx, ctx->parserProgram);
430         }
431 
432         ctx->state = ES2PANDA_STATE_LOWERED;
433     } catch (Error &e) {
434         std::stringstream ss;
435         ss << e.TypeString() << ": " << e.Message() << "[" << e.File() << ":" << e.Line() << "," << e.Col() << "]";
436         ctx->errorMessage = ss.str();
437         ctx->state = ES2PANDA_STATE_ERROR;
438     }
439 
440     return ctx;
441 }
442 
GenerateAsm(Context * ctx)443 __attribute__((unused)) static Context *GenerateAsm(Context *ctx)
444 {
445     if (ctx->state < ES2PANDA_STATE_LOWERED) {
446         ctx = Lower(ctx);
447     }
448 
449     if (ctx->state == ES2PANDA_STATE_ERROR) {
450         return ctx;
451     }
452 
453     ASSERT(ctx->state == ES2PANDA_STATE_LOWERED);
454 
455     auto *emitter = ctx->emitter;
456     try {
457         emitter->GenAnnotation();
458 
459         // Handle context literals.
460         uint32_t index = 0;
461         for (const auto &buff : ctx->contextLiterals) {
462             emitter->AddLiteralBuffer(buff, index++);
463         }
464 
465         emitter->LiteralBufferIndex() += ctx->contextLiterals.size();
466 
467         /* Main thread can also be used instead of idling */
468         ctx->queue->Schedule(ctx);
469         ctx->queue->Consume();
470         ctx->queue->Wait(
471             [emitter](compiler::CompileJob *job) { emitter->AddProgramElement(job->GetProgramElement()); });
472         ASSERT(ctx->program == nullptr);
473         ctx->program =
474             emitter->Finalize(ctx->config->options->CompilerOptions().dumpDebugInfo, compiler::Signatures::ETS_GLOBAL);
475 
476         ctx->state = ES2PANDA_STATE_ASM_GENERATED;
477     } catch (Error &e) {
478         std::stringstream ss;
479         ss << e.TypeString() << ": " << e.Message() << "[" << e.File() << ":" << e.Line() << "," << e.Col() << "]";
480         ctx->errorMessage = ss.str();
481         ctx->state = ES2PANDA_STATE_ERROR;
482     }
483     return ctx;
484 }
485 
GenerateBin(Context * ctx)486 __attribute__((unused)) Context *GenerateBin(Context *ctx)
487 {
488     if (ctx->state < ES2PANDA_STATE_ASM_GENERATED) {
489         ctx = GenerateAsm(ctx);
490     }
491 
492     if (ctx->state == ES2PANDA_STATE_ERROR) {
493         return ctx;
494     }
495 
496     ASSERT(ctx->state == ES2PANDA_STATE_ASM_GENERATED);
497 
498     try {
499         ASSERT(ctx->program != nullptr);
500         util::GenerateProgram(ctx->program, ctx->config->options,
501                               [ctx](const std::string &str) { ctx->errorMessage = str; });
502 
503         ctx->state = ES2PANDA_STATE_BIN_GENERATED;
504     } catch (Error &e) {
505         std::stringstream ss;
506         ss << e.TypeString() << ": " << e.Message() << "[" << e.File() << ":" << e.Line() << "," << e.Col() << "]";
507         ctx->errorMessage = ss.str();
508         ctx->state = ES2PANDA_STATE_ERROR;
509     }
510     return ctx;
511 }
512 
ProceedToState(es2panda_Context * context,es2panda_ContextState state)513 extern "C" __attribute__((unused)) es2panda_Context *ProceedToState(es2panda_Context *context,
514                                                                     es2panda_ContextState state)
515 {
516     auto *ctx = reinterpret_cast<Context *>(context);
517     switch (state) {
518         case ES2PANDA_STATE_NEW:
519             break;
520         case ES2PANDA_STATE_PARSED:
521             ctx = Parse(ctx);
522             break;
523         case ES2PANDA_STATE_SCOPE_INITED:
524             ctx = InitScopes(ctx);
525             break;
526         case ES2PANDA_STATE_CHECKED:
527             ctx = Check(ctx);
528             break;
529         case ES2PANDA_STATE_LOWERED:
530             ctx = Lower(ctx);
531             break;
532         case ES2PANDA_STATE_ASM_GENERATED:
533             ctx = GenerateAsm(ctx);
534             break;
535         case ES2PANDA_STATE_BIN_GENERATED:
536             ctx = GenerateBin(ctx);
537             break;
538         default:
539             ctx->errorMessage = "It does not make sense to request stage";
540             ctx->state = ES2PANDA_STATE_ERROR;
541             break;
542     }
543     return reinterpret_cast<es2panda_Context *>(ctx);
544 }
545 
DestroyContext(es2panda_Context * context)546 extern "C" __attribute__((unused)) void DestroyContext(es2panda_Context *context)
547 {
548     auto *ctx = reinterpret_cast<Context *>(context);
549     delete ctx->program;
550     delete ctx->emitter;
551     delete ctx->analyzer;
552     delete ctx->checker;
553     delete ctx->parser;
554     delete ctx->parserProgram;
555     delete ctx->queue;
556     delete ctx->allocator;
557     delete ctx->sourceFile;
558     delete ctx;
559 }
560 
ContextState(es2panda_Context * context)561 extern "C" __attribute__((unused)) es2panda_ContextState ContextState(es2panda_Context *context)
562 {
563     auto *s = reinterpret_cast<Context *>(context);
564     return s->state;
565 }
566 
ContextErrorMessage(es2panda_Context * context)567 extern "C" __attribute__((unused)) char const *ContextErrorMessage(es2panda_Context *context)
568 {
569     auto *s = reinterpret_cast<Context *>(context);
570     return s->errorMessage.c_str();
571 }
572 
ContextProgram(es2panda_Context * context)573 extern "C" __attribute__((unused)) es2panda_Program *ContextProgram(es2panda_Context *context)
574 {
575     auto *ctx = reinterpret_cast<Context *>(context);
576     return reinterpret_cast<es2panda_Program *>(ctx->parserProgram);
577 }
578 
ProgramAst(es2panda_Program * program)579 extern "C" __attribute__((unused)) es2panda_AstNode *ProgramAst(es2panda_Program *program)
580 {
581     auto *pgm = reinterpret_cast<parser::Program *>(program);
582     return reinterpret_cast<es2panda_AstNode *>(pgm->Ast());
583 }
584 
585 using ExternalSourceEntry = std::pair<char const *, ArenaVector<parser::Program *> *>;
586 
ProgramExternalSources(es2panda_Program * program,size_t * lenP)587 extern "C" __attribute__((unused)) es2panda_ExternalSource **ProgramExternalSources(es2panda_Program *program,
588                                                                                     size_t *lenP)
589 {
590     auto *pgm = reinterpret_cast<parser::Program *>(program);
591     auto *allocator = pgm->VarBinder()->Allocator();
592     auto *vec = allocator->New<ArenaVector<ExternalSourceEntry *>>(allocator->Adapter());
593 
594     for (auto &[e_name, e_programs] : pgm->ExternalSources()) {
595         vec->push_back(allocator->New<ExternalSourceEntry>(StringViewToCString(allocator, e_name), &e_programs));
596     }
597 
598     *lenP = vec->size();
599     return reinterpret_cast<es2panda_ExternalSource **>(vec->data());
600 }
601 
ExternalSourceName(es2panda_ExternalSource * eSource)602 extern "C" __attribute__((unused)) char const *ExternalSourceName(es2panda_ExternalSource *eSource)
603 {
604     auto *entry = reinterpret_cast<ExternalSourceEntry *>(eSource);
605     return entry->first;
606 }
607 
ExternalSourcePrograms(es2panda_ExternalSource * eSource,size_t * lenP)608 extern "C" __attribute__((unused)) es2panda_Program **ExternalSourcePrograms(es2panda_ExternalSource *eSource,
609                                                                              size_t *lenP)
610 {
611     auto *entry = reinterpret_cast<ExternalSourceEntry *>(eSource);
612     *lenP = entry->second->size();
613     return reinterpret_cast<es2panda_Program **>(entry->second->data());
614 }
615 
AstNodeForEach(es2panda_AstNode * ast,void (* func)(es2panda_AstNode *,void *),void * arg)616 extern "C" void AstNodeForEach(es2panda_AstNode *ast, void (*func)(es2panda_AstNode *, void *), void *arg)
617 {
618     auto *node = reinterpret_cast<ir::AstNode *>(ast);
619     func(ast, arg);
620     node->IterateRecursively([=](ir::AstNode *child) { func(reinterpret_cast<es2panda_AstNode *>(child), arg); });
621 }
622 
623 #define SET_NUMBER_LITERAL_IMPL(name, type)                                        \
624     extern "C" bool SetNumberLiteral##name(es2panda_AstNode *node, type new_value) \
625     {                                                                              \
626         auto &n = reinterpret_cast<ir::NumberLiteral *>(node)->Number();           \
627         if (!n.Is##name()) {                                                       \
628             /* CC-OFFNXT(G.PRE.05) function gen */                                 \
629             return false;                                                          \
630         }                                                                          \
631         n.SetValue<type>(std::move(new_value));                                    \
632         /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. */        \
633         return true;                                                               \
634     }
635 
SET_NUMBER_LITERAL_IMPL(Int,int32_t)636 SET_NUMBER_LITERAL_IMPL(Int, int32_t)
637 SET_NUMBER_LITERAL_IMPL(Long, int64_t)
638 SET_NUMBER_LITERAL_IMPL(Double, double)
639 SET_NUMBER_LITERAL_IMPL(Float, float)
640 
641 #undef SET_NUMBER_LITERAL_IMPL
642 
643 extern "C" void *AllocMemory(es2panda_Context *context, size_t numberOfElements, size_t sizeOfElement)
644 {
645     auto *allocator = reinterpret_cast<Context *>(context)->allocator;
646     void *ptr = allocator->Alloc(numberOfElements * sizeOfElement);
647     return ptr;
648 }
649 
CreateSourcePosition(es2panda_Context * context,size_t index,size_t line)650 extern "C" es2panda_SourcePosition *CreateSourcePosition(es2panda_Context *context, size_t index, size_t line)
651 {
652     auto *allocator = reinterpret_cast<Context *>(context)->allocator;
653     return reinterpret_cast<es2panda_SourcePosition *>(allocator->New<lexer::SourcePosition>(index, line));
654 }
655 
CreateSourceRange(es2panda_Context * context,es2panda_SourcePosition * start,es2panda_SourcePosition * end)656 extern "C" es2panda_SourceRange *CreateSourceRange(es2panda_Context *context, es2panda_SourcePosition *start,
657                                                    es2panda_SourcePosition *end)
658 {
659     auto *allocator = reinterpret_cast<Context *>(context)->allocator;
660     auto startE2p = *(reinterpret_cast<lexer::SourcePosition *>(start));
661     auto endE2p = *(reinterpret_cast<lexer::SourcePosition *>(end));
662     return reinterpret_cast<es2panda_SourceRange *>(allocator->New<lexer::SourceRange>(startE2p, endE2p));
663 }
664 
SourcePositionIndex(es2panda_Context * context,es2panda_SourcePosition * position)665 extern "C" size_t SourcePositionIndex([[maybe_unused]] es2panda_Context *context, es2panda_SourcePosition *position)
666 {
667     return reinterpret_cast<lexer::SourcePosition *>(position)->index;
668 }
669 
SourcePositionLine(es2panda_Context * context,es2panda_SourcePosition * position)670 extern "C" size_t SourcePositionLine([[maybe_unused]] es2panda_Context *context, es2panda_SourcePosition *position)
671 {
672     return reinterpret_cast<lexer::SourcePosition *>(position)->line;
673 }
674 
SourceRangeStart(es2panda_Context * context,es2panda_SourceRange * range)675 extern "C" es2panda_SourcePosition *SourceRangeStart([[maybe_unused]] es2panda_Context *context,
676                                                      es2panda_SourceRange *range)
677 {
678     auto *allocator = reinterpret_cast<Context *>(context)->allocator;
679     auto E2pRange = reinterpret_cast<lexer::SourceRange *>(range);
680     return reinterpret_cast<es2panda_SourcePosition *>(allocator->New<lexer::SourcePosition>(E2pRange->start));
681 }
682 
SourceRangeEnd(es2panda_Context * context,es2panda_SourceRange * range)683 extern "C" es2panda_SourcePosition *SourceRangeEnd([[maybe_unused]] es2panda_Context *context,
684                                                    es2panda_SourceRange *range)
685 {
686     auto *allocator = reinterpret_cast<Context *>(context)->allocator;
687     auto E2pRange = reinterpret_cast<lexer::SourceRange *>(range);
688     return reinterpret_cast<es2panda_SourcePosition *>(allocator->New<lexer::SourcePosition>(E2pRange->end));
689 }
690 
691 #include "generated/es2panda_lib/es2panda_lib_impl.inc"
692 
693 es2panda_Impl g_impl = {
694     ES2PANDA_LIB_VERSION,
695 
696     CreateConfig,
697     DestroyConfig,
698     CreateContextFromFile,
699     CreateContextFromString,
700     ProceedToState,
701     DestroyContext,
702     ContextState,
703     ContextErrorMessage,
704     ContextProgram,
705     ProgramAst,
706     ProgramExternalSources,
707     ExternalSourceName,
708     ExternalSourcePrograms,
709     AstNodeForEach,
710     SetNumberLiteralInt,
711     SetNumberLiteralLong,
712     SetNumberLiteralDouble,
713     SetNumberLiteralFloat,
714     AllocMemory,
715     CreateSourcePosition,
716     CreateSourceRange,
717     SourcePositionIndex,
718     SourcePositionLine,
719     SourceRangeStart,
720     SourceRangeEnd,
721 
722 #include "generated/es2panda_lib/es2panda_lib_list.inc"
723 
724 };
725 
726 }  // namespace ark::es2panda::public_lib
727 
es2panda_GetImpl(int version)728 extern "C" es2panda_Impl const *es2panda_GetImpl(int version)
729 {
730     if (version != ES2PANDA_LIB_VERSION) {
731         return nullptr;
732     }
733     return &ark::es2panda::public_lib::g_impl;
734 }
735 
736 // NOLINTEND
737