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 30namespace ark { 31class PandArgParser; 32class PandaArg; 33} // namespace ark 34 35namespace ark::es2panda::util { 36enum class OptionFlags : uint32_t { 37 DEFAULT = 0U, 38 PARSE_ONLY = 1U << 0U, 39 PARSE_MODULE = 1U << 1U, 40 SIZE_STAT = 1U << 2U, 41}; 42 43constexpr int MAX_OPT_LEVEL = 2; 44 45inline 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 52inline 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 59template <class T> 60T BaseName(T const &path) 61{ 62 return path.substr(path.find_last_of(ark::os::file::File::GetPathDelim()) + 1); 63} 64 65class Options { 66public: 67 Options(); 68 NO_COPY_SEMANTIC(Options); 69 NO_MOVE_SEMANTIC(Options); 70 ~Options(); 71 72 bool Parse(int argc, const char **argv); 73 74 es2panda::ScriptExtension Extension() const 75 { 76 return extension_; 77 } 78 79 const es2panda::CompilerOptions &CompilerOptions() const 80 { 81 return compilerOptions_; 82 } 83 84 void SetCompilerOptions(const es2panda::CompilerOptions &options) 85 { 86 compilerOptions_ = options; 87 } 88 89 const std::string &ParserInput() const 90 { 91 return parserInput_; 92 } 93 94 const std::string &CompilerOutput() const 95 { 96 return compilerOutput_; 97 } 98 99 void SetCompilerOutput(const std::string &compilerOutput) 100 { 101 compilerOutput_ = compilerOutput; 102 } 103 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 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 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 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 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 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 239 const std::string &SourceFile() const 240 { 241 return sourceFile_; 242 } 243 244 const std::string &ErrorMsg() const 245 { 246 return errorMsg_; 247 } 248 249 int OptLevel() const 250 { 251 return optLevel_; 252 } 253 254 int ThreadCount() const 255 { 256 return threadCount_; 257 } 258 259 bool ParseModule() const 260 { 261 return (options_ & OptionFlags::PARSE_MODULE) != 0; 262 } 263 264 bool ParseOnly() const 265 { 266 return (options_ & OptionFlags::PARSE_ONLY) != 0; 267 } 268 269 bool SizeStat() const 270 { 271 return (options_ & OptionFlags::SIZE_STAT) != 0; 272 } 273 274 bool IsDynamic() const 275 { 276 return extension_ != es2panda::ScriptExtension::ETS; 277 } 278 279 bool ListFiles() const 280 { 281 return listFiles_; 282 } 283 284 bool ListPhases() const 285 { 286 return listPhases_; 287 } 288 289private: 290 es2panda::ScriptExtension extension_ {es2panda::ScriptExtension::JS}; 291 OptionFlags options_ {OptionFlags::DEFAULT}; 292 es2panda::CompilerOptions compilerOptions_ {}; 293 ark::PandArgParser *argparser_; 294 std::string parserInput_; 295 std::string compilerOutput_; 296 std::string result_; 297 std::string sourceFile_; 298 std::string errorMsg_; 299 int optLevel_ {0}; 300 int threadCount_ {0}; 301 bool listFiles_ {false}; 302 bool listPhases_ {false}; 303 util::LogLevel logLevel_ {util::LogLevel::ERROR}; 304}; 305} // namespace ark::es2panda::util 306 307#endif // UTIL_OPTIONS_H 308