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