• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-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 #ifndef ES2PANDA_UTIL_OPTIONS_H
17 #define ES2PANDA_UTIL_OPTIONS_H
18 
19 #include "libpandabase/os/file.h"
20 #include "es2panda.h"
21 #include "util/helpers.h"
22 #include "utils/pandargs.h"
23 #include "arktsconfig.h"
24 
25 #include <exception>
26 #include <fstream>
27 #include <iostream>
28 #include <variant>
29 
30 namespace ark {
31 class PandArgParser;
32 class PandaArg;
33 }  // namespace ark
34 
35 namespace ark::es2panda::util {
36 enum class OptionFlags : uint32_t {
37     DEFAULT = 0U,
38     PARSE_ONLY = 1U << 0U,
39     PARSE_MODULE = 1U << 1U,
40     SIZE_STAT = 1U << 2U,
41 };
42 
43 constexpr int MAX_OPT_LEVEL = 2;
44 
45 inline std::underlying_type_t<OptionFlags> operator&(OptionFlags a, OptionFlags b)
46 {
47     using Utype = std::underlying_type_t<OptionFlags>;
48     /* NOLINTNEXTLINE(hicpp-signed-bitwise) */
49     return static_cast<Utype>(static_cast<Utype>(a) & static_cast<Utype>(b));
50 }
51 
52 inline OptionFlags &operator|=(OptionFlags &a, OptionFlags b)
53 {
54     using Utype = std::underlying_type_t<OptionFlags>;
55     /* NOLINTNEXTLINE(hicpp-signed-bitwise) */
56     return a = static_cast<OptionFlags>(static_cast<Utype>(a) | static_cast<Utype>(b));
57 }
58 
59 template <class T>
BaseName(T const & path)60 T BaseName(T const &path)
61 {
62     return path.substr(path.find_last_of(ark::os::file::File::GetPathDelim()) + 1);
63 }
64 
65 class Options {
66 public:
67     Options();
68     NO_COPY_SEMANTIC(Options);
69     NO_MOVE_SEMANTIC(Options);
70     ~Options();
71 
72     bool Parse(int argc, const char **argv);
73 
Extension()74     es2panda::ScriptExtension Extension() const
75     {
76         return extension_;
77     }
78 
CompilerOptions()79     const es2panda::CompilerOptions &CompilerOptions() const
80     {
81         return compilerOptions_;
82     }
83 
SetCompilerOptions(const es2panda::CompilerOptions & options)84     void SetCompilerOptions(const es2panda::CompilerOptions &options)
85     {
86         compilerOptions_ = options;
87     }
88 
ParserInput()89     const std::string &ParserInput() const
90     {
91         return parserInput_;
92     }
93 
CompilerOutput()94     const std::string &CompilerOutput() const
95     {
96         return compilerOutput_;
97     }
98 
SetCompilerOutput(const std::string & compilerOutput)99     void SetCompilerOutput(const std::string &compilerOutput)
100     {
101         compilerOutput_ = compilerOutput;
102     }
103 
LogLevel()104     std::string_view LogLevel() const
105     {
106         switch (logLevel_) {
107             case util::LogLevel::DEBUG: {
108                 return "debug";
109             }
110             case util::LogLevel::INFO: {
111                 return "info";
112             }
113             case util::LogLevel::WARNING: {
114                 return "warning";
115             }
116             case util::LogLevel::ERROR: {
117                 return "error";
118             }
119             case util::LogLevel::FATAL: {
120                 return "fatal";
121             }
122             default: {
123                 UNREACHABLE();
124             }
125         }
126     }
127 
DetermineLogLevel(const ark::PandArg<std::string> & logLevel)128     void DetermineLogLevel(const ark::PandArg<std::string> &logLevel)
129     {
130         if (const auto logLevelStr = logLevel.GetValue(); !logLevelStr.empty()) {
131             if (logLevelStr == "debug") {
132                 logLevel_ = util::LogLevel::DEBUG;
133             } else if (logLevelStr == "info") {
134                 logLevel_ = util::LogLevel::INFO;
135             } else if (logLevelStr == "warning") {
136                 logLevel_ = util::LogLevel::WARNING;
137             } else if (logLevelStr == "error") {
138                 logLevel_ = util::LogLevel::ERROR;
139             } else if (logLevelStr == "fatal") {
140                 logLevel_ = util::LogLevel::FATAL;
141             } else {
142                 logLevel_ = util::LogLevel::INVALID;
143                 std::cerr << "Invalid log level: '" << logLevelStr
144                           << R"('. Possible values: ["debug", "info", "warning", "error", "fatal"])";
145             }
146         }
147     }
148 
DetermineExtension(const ark::PandArg<std::string> & inputExtension,const ark::PandArg<std::string> & arktsConfig,const es2panda::CompilationMode & compMode)149     void DetermineExtension(const ark::PandArg<std::string> &inputExtension,
150                             const ark::PandArg<std::string> &arktsConfig, const es2panda::CompilationMode &compMode)
151     {
152         std::string extension = inputExtension.GetValue();
153         std::string sourceFileExtension = sourceFile_.substr(sourceFile_.find_last_of('.') + 1);
154 
155         bool extensionIsEmpty = extension.empty();
156         if (!sourceFile_.empty() && !extensionIsEmpty && extension != sourceFileExtension) {
157             std::cerr << "Warning: Not matching extensions! Sourcefile: " << sourceFileExtension
158                       << ", Manual(used): " << extension << std::endl;
159         }
160         auto tempExtension = !extensionIsEmpty ? extension : sourceFileExtension;
161         if (tempExtension == "js") {
162             extension_ = es2panda::ScriptExtension::JS;
163 #ifndef PANDA_WITH_ECMASCRIPT
164             errorMsg_ = "js extension is not supported within current build";
165             extension_ = es2panda::ScriptExtension::INVALID;
166             return;
167 #endif
168         } else if (tempExtension == "ts") {
169             extension_ = es2panda::ScriptExtension::TS;
170         } else if (tempExtension == "as") {
171             extension_ = es2panda::ScriptExtension::AS;
172         } else if (tempExtension == "sts") {
173             extension_ = es2panda::ScriptExtension::ETS;
174 
175             std::ifstream inputStream(arktsConfig.GetValue());
176             if (inputStream.fail()) {
177                 errorMsg_ = "Failed to open arktsconfig: ";
178                 errorMsg_.append(arktsConfig.GetValue());
179                 extension_ = es2panda::ScriptExtension::INVALID;
180                 return;
181             }
182         } else if (extensionIsEmpty && (compMode == CompilationMode::PROJECT)) {
183             extension_ = es2panda::ScriptExtension::ETS;
184         } else {
185             if (!extensionIsEmpty) {
186                 errorMsg_ = "Invalid extension (available options: js, ts, as, sts)";
187             } else {
188                 errorMsg_ =
189                     "Unknown extension of sourcefile, set the extension manually or change the file format (available "
190                     "options: js, ts, as, sts)";
191             }
192             extension_ = es2panda::ScriptExtension::INVALID;
193             return;
194         }
195     }
196 
DetermineCompilationMode(const ark::PandArg<bool> & genStdLib,const ark::PandArg<std::string> & inputFile)197     CompilationMode DetermineCompilationMode(const ark::PandArg<bool> &genStdLib,
198                                              const ark::PandArg<std::string> &inputFile) const
199     {
200         return genStdLib.GetValue()           ? CompilationMode::GEN_STD_LIB
201                : inputFile.GetValue().empty() ? CompilationMode::PROJECT
202                                               : CompilationMode::SINGLE_FILE;
203     }
204 
AddOptionFlags(const ark::PandArg<bool> & opParseOnly,const ark::PandArg<bool> & opModule,const ark::PandArg<bool> & opSizeStat)205     void AddOptionFlags(const ark::PandArg<bool> &opParseOnly, const ark::PandArg<bool> &opModule,
206                         const ark::PandArg<bool> &opSizeStat)
207     {
208         if (opParseOnly.GetValue()) {
209             options_ |= OptionFlags::PARSE_ONLY;
210         }
211 
212         if (opModule.GetValue()) {
213             options_ |= OptionFlags::PARSE_MODULE;
214         }
215 
216         if (opSizeStat.GetValue()) {
217             options_ |= OptionFlags::SIZE_STAT;
218         }
219     }
220 
ParseArktsConfig(std::string_view path)221     std::optional<ArkTsConfig> ParseArktsConfig(std::string_view path)
222     {
223         auto config = ArkTsConfig {path};
224         if (!config.Parse()) {
225             errorMsg_ = "Invalid ArkTsConfig path: ";
226             errorMsg_.append(path);
227             return std::nullopt;
228         }
229         return std::make_optional(config);
230     }
231 
ProcessEtsSpecificOptions(std::string_view arktsConfigPath,const es2panda::CompilationMode & compMode)232     bool ProcessEtsSpecificOptions(std::string_view arktsConfigPath, const es2panda::CompilationMode &compMode)
233     {
234         if (extension_ != es2panda::ScriptExtension::ETS && compMode == CompilationMode::PROJECT) {
235             errorMsg_ = "Error: only --extension=sts is supported for project compilation mode.";
236             return false;
237         }
238 
239         if (extension_ != es2panda::ScriptExtension::ETS) {
240             return true;
241         }
242 
243         if (auto config = ParseArktsConfig(arktsConfigPath); config != std::nullopt) {
244             compilerOptions_.arktsConfig = std::make_shared<ArkTsConfig>(*config);
245         } else {
246             return false;
247         }
248 
249         return true;
250     }
251 
SourceFile()252     const std::string &SourceFile() const
253     {
254         return sourceFile_;
255     }
256 
ErrorMsg()257     const std::string &ErrorMsg() const
258     {
259         return errorMsg_;
260     }
261 
OptLevel()262     int OptLevel() const
263     {
264         return optLevel_;
265     }
266 
ThreadCount()267     int ThreadCount() const
268     {
269         return threadCount_;
270     }
271 
ParseModule()272     bool ParseModule() const
273     {
274         return (options_ & OptionFlags::PARSE_MODULE) != 0;
275     }
276 
ParseOnly()277     bool ParseOnly() const
278     {
279         return (options_ & OptionFlags::PARSE_ONLY) != 0;
280     }
281 
SizeStat()282     bool SizeStat() const
283     {
284         return (options_ & OptionFlags::SIZE_STAT) != 0;
285     }
286 
IsDynamic()287     bool IsDynamic() const
288     {
289         return extension_ != es2panda::ScriptExtension::ETS;
290     }
291 
ListFiles()292     bool ListFiles() const
293     {
294         return listFiles_;
295     }
296 
ListPhases()297     bool ListPhases() const
298     {
299         return listPhases_;
300     }
301 
302 private:
303     es2panda::ScriptExtension extension_ {es2panda::ScriptExtension::JS};
304     OptionFlags options_ {OptionFlags::DEFAULT};
305     es2panda::CompilerOptions compilerOptions_ {};
306     ark::PandArgParser *argparser_;
307     std::string parserInput_;
308     std::string compilerOutput_;
309     std::string result_;
310     std::string sourceFile_;
311     std::string errorMsg_;
312     int optLevel_ {0};
313     int threadCount_ {0};
314     bool listFiles_ {false};
315     bool listPhases_ {false};
316     util::LogLevel logLevel_ {util::LogLevel::ERROR};
317 };
318 }  // namespace ark::es2panda::util
319 
320 #endif  // UTIL_OPTIONS_H
321