1 /**
2 * Copyright (c) 2021-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 <iostream>
17 #include "public/es2panda_lib.h"
18 #include "public/public.h"
19 #include "declgenEts2Ts.h"
20
21 namespace ark::es2panda::declgen_ets2ts {
22
PrintUsage()23 static void PrintUsage()
24 {
25 std::cerr << "Usage: declgen_ets2ts [OPTIONS] [input]\n";
26 std::cerr << " --export-all Treat all top level statements as exported\n";
27 std::cerr << " --output-dets=[FILE] Path to output .d.ets file\n";
28 std::cerr << " --output-ets=[FILE] Path to output .ets file\n";
29 std::cerr << " --generate-decl:enable-isolated Generate isolated decl\n";
30 std::cerr << " --help Print this message and exit. Default: false\n";
31 std::cerr << "Tail arguments:\n";
32 std::cerr << "input: input file\n";
33 }
34
FilterArgs(Span<const char * const> args,int & newArgc,const char ** & newArgv)35 void FilterArgs(Span<const char *const> args, int &newArgc, const char **&newArgv)
36 {
37 ES2PANDA_ASSERT(args.size() > 1);
38 std::vector<const char *> filteredArgs;
39 filteredArgs.push_back(args[0]);
40 for (size_t i = 1; i < args.size(); ++i) {
41 if (std::strcmp(args[i], "--export-all") == 0 ||
42 std::strncmp(args[i], "--output-dets", std::strlen("--output-dets")) == 0 ||
43 std::strncmp(args[i], "--output-ets", std::strlen("--output-ets")) == 0) {
44 continue;
45 }
46 filteredArgs.push_back(args[i]);
47 }
48
49 newArgc = static_cast<int>(filteredArgs.size());
50 if (newArgc <= 0 || static_cast<size_t>(newArgc) > args.size()) {
51 return;
52 }
53 newArgv = new const char *[newArgc];
54 std::copy(filteredArgs.begin(), filteredArgs.end(), newArgv);
55 }
56
ParseOptions(Span<const char * const> args)57 static DeclgenOptions ParseOptions(Span<const char *const> args)
58 {
59 DeclgenOptions options;
60 for (size_t i = 1; i < args.size(); ++i) {
61 if (std::strcmp(args[i], "--export-all") == 0) {
62 options.exportAll = true;
63 } else if (std::strncmp(args[i], "--output-dets", std::strlen("--output-dets")) == 0 &&
64 std::strchr(args[i], '=') != nullptr) {
65 std::string arg = args[i];
66 options.outputDeclEts = arg.substr(std::strlen("--output-dets="));
67 } else if (std::strncmp(args[i], "--output-ets", std::strlen("--output-ets")) == 0 &&
68 std::strchr(args[i], '=') != nullptr) {
69 std::string arg = args[i];
70 options.outputEts = arg.substr(std::strlen("--output-ets="));
71 } else if (std::strcmp(args[i], "--generate-decl:enable-isolated") == 0) {
72 options.isIsolatedDeclgen = true;
73 }
74 }
75 return options;
76 }
77
DestroyContextAndConfig(const es2panda_Impl * impl,es2panda_Context * ctx,es2panda_Config * cfg,const char ** newArgv)78 static void DestroyContextAndConfig(const es2panda_Impl *impl, es2panda_Context *ctx, es2panda_Config *cfg,
79 const char **newArgv)
80 {
81 impl->DestroyContext(ctx);
82 impl->DestroyConfig(cfg);
83 delete[] newArgv;
84 }
85
Run(int argc,const char ** argv)86 static int Run(int argc, const char **argv)
87 {
88 Span<const char *const> args(argv, static_cast<size_t>(argc));
89 if (args.size() == 1 || std::strcmp(args[1], "--help") == 0) {
90 PrintUsage();
91 return 1;
92 }
93 auto declgenOptions = ParseOptions(args);
94 int newArgc = 0;
95 const char **newArgv = nullptr;
96 FilterArgs(args, newArgc, newArgv);
97 const auto *impl = es2panda_GetImpl(ES2PANDA_LIB_VERSION);
98 auto *cfg = impl->CreateConfig(newArgc, newArgv);
99 if (cfg == nullptr) {
100 return 1;
101 }
102 auto *cfgImpl = reinterpret_cast<ark::es2panda::public_lib::ConfigImpl *>(cfg);
103 auto parserInputCStr = cfgImpl->options->CStrParserInputContents().first;
104 es2panda_Context *ctx =
105 impl->CreateContextFromString(cfg, parserInputCStr, cfgImpl->options->SourceFileName().c_str());
106
107 auto *ctxImpl = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
108 auto *checker = reinterpret_cast<checker::ETSChecker *>(ctxImpl->checker);
109
110 auto *isolatedDeclgenChecker = reinterpret_cast<checker::IsolatedDeclgenChecker *>(ctxImpl->isolatedDeclgenChecker);
111 impl->ProceedToState(ctx, ES2PANDA_STATE_BOUND);
112 if (declgenOptions.isIsolatedDeclgen) {
113 isolatedDeclgenChecker->CheckBeforeChecker();
114 if (ctxImpl->diagnosticEngine->IsAnyError()) {
115 DestroyContextAndConfig(impl, ctx, cfg, newArgv);
116 return 1;
117 }
118 }
119
120 impl->ProceedToState(ctx, ES2PANDA_STATE_CHECKED);
121 if (declgenOptions.isIsolatedDeclgen) {
122 isolatedDeclgenChecker->CheckAfterChecker();
123 if (ctxImpl->diagnosticEngine->IsAnyError()) {
124 DestroyContextAndConfig(impl, ctx, cfg, newArgv);
125 return 1;
126 }
127 }
128
129 int res = 0;
130 if (!GenerateTsDeclarations(checker, ctxImpl->parserProgram, declgenOptions)) {
131 res = 1;
132 }
133
134 DestroyContextAndConfig(impl, ctx, cfg, newArgv);
135
136 return res;
137 }
138 } // namespace ark::es2panda::declgen_ets2ts
139
main(int argc,const char ** argv)140 int main(int argc, const char **argv)
141 {
142 return ark::es2panda::declgen_ets2ts::Run(argc, argv);
143 }
144