• 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 
CheckEtsSpecificOptions(const es2panda::CompilationMode & compMode,const ark::PandArg<std::string> & arktsConfig)221     bool CheckEtsSpecificOptions(const es2panda::CompilationMode &compMode,
222                                  const ark::PandArg<std::string> &arktsConfig)
223     {
224         if (extension_ != es2panda::ScriptExtension::ETS) {
225             if (compMode == CompilationMode::PROJECT) {
226                 errorMsg_ = "Error: only --extension=sts is supported for project compilation mode.";
227                 return false;
228             }
229         } else {
230             if (!compilerOptions_.arktsConfig->Parse()) {
231                 errorMsg_ = "Invalid ArkTsConfig: ";
232                 errorMsg_.append(arktsConfig.GetValue());
233                 return false;
234             }
235         }
236         return true;
237     }
238 
SourceFile()239     const std::string &SourceFile() const
240     {
241         return sourceFile_;
242     }
243 
ErrorMsg()244     const std::string &ErrorMsg() const
245     {
246         return errorMsg_;
247     }
248 
OptLevel()249     int OptLevel() const
250     {
251         return optLevel_;
252     }
253 
ThreadCount()254     int ThreadCount() const
255     {
256         return threadCount_;
257     }
258 
ParseModule()259     bool ParseModule() const
260     {
261         return (options_ & OptionFlags::PARSE_MODULE) != 0;
262     }
263 
ParseOnly()264     bool ParseOnly() const
265     {
266         return (options_ & OptionFlags::PARSE_ONLY) != 0;
267     }
268 
SizeStat()269     bool SizeStat() const
270     {
271         return (options_ & OptionFlags::SIZE_STAT) != 0;
272     }
273 
IsDynamic()274     bool IsDynamic() const
275     {
276         return extension_ != es2panda::ScriptExtension::ETS;
277     }
278 
ListFiles()279     bool ListFiles() const
280     {
281         return listFiles_;
282     }
283 
284 private:
285     es2panda::ScriptExtension extension_ {es2panda::ScriptExtension::JS};
286     OptionFlags options_ {OptionFlags::DEFAULT};
287     es2panda::CompilerOptions compilerOptions_ {};
288     ark::PandArgParser *argparser_;
289     std::string parserInput_;
290     std::string compilerOutput_;
291     std::string result_;
292     std::string sourceFile_;
293     std::string errorMsg_;
294     int optLevel_ {0};
295     int threadCount_ {0};
296     bool listFiles_ {false};
297     util::LogLevel logLevel_ {util::LogLevel::ERROR};
298 };
299 }  // namespace ark::es2panda::util
300 
301 #endif  // UTIL_OPTIONS_H
302