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, ®Spiller, 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