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, ®Spiller, 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 ¶ms) {
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