1/**
2 * Copyright (c) 2022-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#include "options.h"
17
18#include "utils/pandargs.h"
19
20#include "arktsconfig.h"
21
22#include <random>
23#include <utility>
24
25#ifdef PANDA_WITH_BYTECODE_OPTIMIZER
26#include "bytecode_optimizer/bytecodeopt_options.h"
27#include "compiler/compiler_options.h"
28#endif
29
30namespace ark::es2panda::util {
31template <class T>
32T RemoveExtension(T const &filename)
33{
34    typename T::size_type const p(filename.find_last_of('.'));
35    return p > 0 && p != T::npos ? filename.substr(0, p) : filename;
36}
37
38// Options
39
40Options::Options() : argparser_(new ark::PandArgParser()) {}
41
42Options::~Options()
43{
44    delete argparser_;
45}
46
47static std::vector<std::string> SplitToStringVector(std::string const &str)
48{
49    std::vector<std::string> res;
50    std::string_view currStr {str};
51    auto ix = currStr.find(',');
52    while (ix != std::string::npos) {
53        if (ix != 0) {
54            res.emplace_back(currStr.substr(0, ix));
55        }
56        currStr = currStr.substr(ix + 1);
57        ix = currStr.find(',');
58    }
59
60    if (!currStr.empty()) {
61        res.emplace_back(currStr);
62    }
63    return res;
64}
65
66static std::unordered_set<std::string> SplitToStringSet(std::string const &str)
67{
68    std::vector<std::string> vec = SplitToStringVector(str);
69    std::unordered_set<std::string> res;
70    for (auto &elem : vec) {
71        res.emplace(elem);
72    }
73    return res;
74}
75
76// NOLINTNEXTLINE(modernize-avoid-c-arrays, hicpp-avoid-c-arrays)
77static void SplitArgs(int argc, const char *argv[], std::vector<std::string> &es2pandaArgs,
78                      std::vector<std::string> &bcoCompilerArgs, std::vector<std::string> &bytecodeoptArgs)
79{
80    constexpr std::string_view COMPILER_PREFIX = "--bco-compiler";
81    constexpr std::string_view OPTIMIZER_PREFIX = "--bco-optimizer";
82
83    enum class OptState { ES2PANDA, JIT_COMPILER, OPTIMIZER };
84    OptState optState = OptState::ES2PANDA;
85
86    std::unordered_map<OptState, std::vector<std::string> *> argsMap = {{OptState::ES2PANDA, &es2pandaArgs},
87                                                                        {OptState::JIT_COMPILER, &bcoCompilerArgs},
88                                                                        {OptState::OPTIMIZER, &bytecodeoptArgs}};
89
90    for (int i = 1; i < argc; i++) {
91        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
92        const char *argI = argv[i];
93        if (COMPILER_PREFIX == argI) {
94            optState = OptState::JIT_COMPILER;
95            continue;
96        }
97
98        if (OPTIMIZER_PREFIX == argI) {
99            optState = OptState::OPTIMIZER;
100            continue;
101        }
102
103        argsMap[optState]->emplace_back(argI);
104        optState = OptState::ES2PANDA;
105    }
106}
107
108template <class T>
109static bool ParseComponentArgs(const std::vector<std::string> &args, T &options)
110{
111    ark::PandArgParser parser;
112    options.AddOptions(&parser);
113    if (!parser.Parse(args)) {
114        std::cerr << parser.GetErrorString();
115        std::cerr << parser.GetHelpString();
116        return false;
117    }
118
119    if (auto optionsErr = options.Validate(); optionsErr) {
120        std::cerr << "Error: " << optionsErr.value().GetMessage() << std::endl;
121        return false;
122    }
123
124    return true;
125}
126
127static bool ParseBCOCompilerOptions([[maybe_unused]] const std::vector<std::string> &compilerArgs,
128                                    [[maybe_unused]] const std::vector<std::string> &bytecodeoptArgs)
129{
130#ifdef PANDA_WITH_BYTECODE_OPTIMIZER
131    if (!ParseComponentArgs(compilerArgs, ark::compiler::g_options)) {
132        return false;
133    }
134    if (!ParseComponentArgs(bytecodeoptArgs, ark::bytecodeopt::g_options)) {
135        return false;
136    }
137#endif
138
139    return true;
140}
141
142static inline bool ETSWarningsGroupSetter(const ark::PandArg<bool> &option)
143{
144    return !option.WasSet() || (option.WasSet() && option.GetValue());
145}
146
147static std::tuple<std::string_view, std::string_view, std::string_view> SplitPath(std::string_view path)
148{
149    std::string_view fileDirectory;
150    std::string_view fileBaseName = path;
151    auto lastDelimPos = fileBaseName.find_last_of(ark::os::file::File::GetPathDelim());
152    if (lastDelimPos != std::string_view::npos) {
153        ++lastDelimPos;
154        fileDirectory = fileBaseName.substr(0, lastDelimPos);
155        fileBaseName = fileBaseName.substr(lastDelimPos);
156    }
157
158    // Save all extensions.
159    std::string_view fileExtensions;
160    auto fileBaseNamePos = fileBaseName.find_first_of('.');
161    if (fileBaseNamePos > 0 && fileBaseNamePos != std::string_view::npos) {
162        fileExtensions = fileBaseName.substr(fileBaseNamePos);
163        fileBaseName = fileBaseName.substr(0, fileBaseNamePos);
164    }
165
166    return {fileDirectory, fileBaseName, fileExtensions};
167}
168
169/**
170 * @brief Generate evaluated expression wrapping code.
171 * @param sourceFilePath used for generating a unique package name.
172 * @param input expression source code file stream.
173 * @param output stream for generating expression wrapper.
174 */
175static void GenerateEvaluationWrapper(std::string_view sourceFilePath, std::ifstream &input, std::stringstream &output)
176{
177    static constexpr std::string_view EVAL_PREFIX = "eval_";
178    static constexpr std::string_view EVAL_SUFFIX = "_eval";
179
180    auto splittedPath = SplitPath(sourceFilePath);
181    auto fileBaseName = std::get<1>(splittedPath);
182
183    std::random_device rd;
184    std::stringstream ss;
185    ss << EVAL_PREFIX << fileBaseName << '_' << rd() << EVAL_SUFFIX;
186    auto methodName = ss.str();
187
188    output << "package " << methodName << "; class " << methodName << " { private static " << methodName << "() { "
189           << input.rdbuf() << " } }";
190}
191
192static auto constexpr DEFAULT_THREAD_COUNT = 0;
193
194struct AllArgs {
195    // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
196    ark::PandArg<bool> opHelp {"help", false, "Print this message and exit"};
197    ark::PandArg<bool> opVersion {"version", false, "Print message with version and exit"};
198
199    // parser
200    ark::PandArg<std::string> inputExtension {"extension", "",
201                                              "Parse the input as the given extension (options: js | ts | as | sts)"};
202    ark::PandArg<bool> opModule {"module", false, "Parse the input as module (JS only option)"};
203    ark::PandArg<bool> opParseOnly {"parse-only", false, "Parse the input only"};
204    ark::PandArg<bool> opDumpAst {"dump-ast", false, "Dump the parsed AST"};
205    ark::PandArg<bool> opDumpAstOnlySilent {"dump-ast-only-silent", false,
206                                            "Dump parsed AST with all dumpers available but don't print to stdout"};
207    ark::PandArg<bool> opDumpCheckedAst {"dump-dynamic-ast", false,
208                                         "Dump AST with synthetic nodes for dynamic languages"};
209    ark::PandArg<bool> opListFiles {"list-files", false, "Print names of files that are part of compilation"};
210
211    // compiler
212    ark::PandArg<bool> opDumpAssembly {"dump-assembly", false, "Dump pandasm"};
213    ark::PandArg<bool> opDebugInfo {"debug-info", false, "Compile with debug info"};
214    ark::PandArg<bool> opDumpDebugInfo {"dump-debug-info", false, "Dump debug info"};
215    ark::PandArg<int> opOptLevel {"opt-level", 0, "Compiler optimization level (options: 0 | 1 | 2)", 0, MAX_OPT_LEVEL};
216    ark::PandArg<bool> opEtsModule {"ets-module", false, "Compile the input as ets-module"};
217
218    // ETS-warnings
219    ark::PandArg<bool> opEtsEnableAll {"ets-warnings-all", false, "Show performance-related ets-warnings"};
220    ark::PandArg<bool> opEtsWerror {"ets-werror", false, "Treat all enabled performance-related ets-warnings as error"};
221    ark::PandArg<bool> opEtsSubsetWarnings {"ets-subset-warnings", false, "Show ETS-warnings that keep you in subset"};
222    ark::PandArg<bool> opEtsNonsubsetWarnings {"ets-nonsubset-warnings", false,
223                                               "Show ETS-warnings that do not keep you in subset"};
224    ark::PandArg<bool> opEtsSuggestFinal {"ets-suggest-final", false,
225                                          "Suggest final keyword warning - ETS non-subset warning"};
226    ark::PandArg<bool> opEtsProhibitTopLevelStatements {"ets-prohibit-top-level-statements", false,
227                                                        "Prohibit top-level statements - ETS subset Warning"};
228    ark::PandArg<bool> opEtsBoostEqualityStatement {"ets-boost-equality-statement", false,
229                                                    "Suggest boosting Equality Statements - ETS Subset Warning"};
230    ark::PandArg<bool> opEtsRemoveAsync {
231        "ets-remove-async", false, "Suggests replacing async functions with coroutines - ETS Non Subset Warnings"};
232    ark::PandArg<bool> opEtsRemoveLambda {"ets-remove-lambda", false,
233                                          "Suggestions to replace lambda with regular functions - ETS Subset Warning"};
234    ark::PandArg<bool> opEtsImplicitBoxingUnboxing {
235        "ets-implicit-boxing-unboxing", false,
236        "Check if a program contains implicit boxing or unboxing - ETS Subset Warning"};
237
238    ark::PandArg<bool> opDebuggerEvalMode {"debugger-eval-mode", false, "Compile given file in evaluation mode"};
239    ark::PandArg<uint64_t> opDebuggerEvalLine {
240        "debugger-eval-line", 0, "Debugger evaluation mode, line in the source file code where evaluate occurs."};
241    ark::PandArg<std::string> opDebuggerEvalSource {"debugger-eval-source", "",
242                                                    "Debugger evaluation mode, path to evaluation mode source file"};
243    ark::PandArg<std::string> opDebuggerEvalPandaFiles {
244        "debugger-eval-panda-files", "",
245        "Debugger evaluation mode, paths to evaluation mode (.abc) files, must be accessible"};
246
247    ark::PandArg<int> opThreadCount {"thread", DEFAULT_THREAD_COUNT, "Number of worker threads"};
248    ark::PandArg<bool> opSizeStat {"dump-size-stat", false, "Dump size statistics"};
249    ark::PandArg<std::string> outputFile {"output", "", "Compiler binary output (.abc)"};
250    ark::PandArg<std::string> logLevel {"log-level", "error", "Log-level"};
251    ark::PandArg<std::string> stdLib {"stdlib", "", "Path to standard library"};
252    ark::PandArg<bool> genStdLib {"gen-stdlib", false, "Gen standard library"};
253    ark::PandArg<std::string> plugins {"plugins", "", "Plugins"};
254    ark::PandArg<std::string> skipPhases {"skip-phases", "", "Phases to skip"};
255    ark::PandArg<std::string> verifierWarnings {
256        "verifier-warnings", "CheckInfiniteLoopForAll",
257        "Print errors and continue compilation if AST tree is incorrect. "
258        "Possible values: "
259        "NodeHasParentForAll,EveryChildHasValidParentForAll,VariableHasScopeForAll,NodeHasTypeForAll,"
260        "IdentifierHasVariableForAll,ArithmeticOperationValidForAll,SequenceExpressionHasLastTypeForAll, "
261        "CheckInfiniteLoopForAll,"
262        "ForLoopCorrectlyInitializedForAll,VariableHasEnclosingScopeForAll,ModifierAccessValidForAll,"
263        "ImportExportAccessValid,NodeHasSourceRangeForAll,EveryChildInParentRangeForAll,"
264        "ReferenceTypeAnnotationIsNullForAll,VariableNameIdentifierNameSameForAll,CheckAbstractMethodForAll,"
265        "GetterSetterValidationForAll,CheckScopeDeclarationForAll"};
266    ark::PandArg<std::string> verifierErrors {
267        "verifier-errors",
268        "ForLoopCorrectlyInitializedForAll,SequenceExpressionHasLastTypeForAll,NodeHasTypeForAll,NodeHasParentForAll,"
269        "EveryChildHasValidParentForAll,ModifierAccessValidForAll,ArithmeticOperationValidForAll,"
270        "VariableHasScopeForAll,IdentifierHasVariableForAll,VariableHasEnclosingScopeForAll,"
271        "ReferenceTypeAnnotationIsNullForAll,VariableNameIdentifierNameSameForAll,CheckAbstractMethodForAll,"
272        "GetterSetterValidationForAll,CheckScopeDeclarationForAll",
273        "Print errors and stop compilation if AST tree is incorrect. "
274        "Possible values: "
275        "NodeHasParentForAll,EveryChildHasValidParentForAll,VariableHasScopeForAll,NodeHasTypeForAll,"
276        "IdentifierHasVariableForAll,ArithmeticOperationValidForAll,SequenceExpressionHasLastTypeForAll,"
277        "CheckInfiniteLoopForAll,"
278        "ForLoopCorrectlyInitializedForAll,VariableHasEnclosingScopeForAll,ModifierAccessValidForAll,"
279        "ImportExportAccessValid,NodeHasSourceRangeForAll,EveryChildInParentRangeForAll,"
280        "ReferenceTypeAnnotationIsNullForAll,VariableNameIdentifierNameSameForAll,CheckAbstractMethodForAll,"
281        "GetterSetterValidationForAll,CheckScopeDeclarationForAll"};
282    ark::PandArg<bool> verifierAllChecks {
283        "verifier-all-checks", false,
284        "Run verifier checks on every phase, monotonically expanding them on every phase"};
285    ark::PandArg<bool> verifierFullProgram {"verifier-full-program", false,
286                                            "Analyze full program, including program AST and it's dependencies"};
287    ark::PandArg<std::string> dumpBeforePhases {"dump-before-phases", "",
288                                                "Generate program dump before running phases in the list"};
289    ark::PandArg<std::string> dumpEtsSrcBeforePhases {
290        "dump-ets-src-before-phases", "", "Generate program dump as ets source code before running phases in the list"};
291    ark::PandArg<std::string> dumpEtsSrcAfterPhases {
292        "dump-ets-src-after-phases", "", "Generate program dump as ets source code after running phases in the list"};
293    ark::PandArg<std::string> dumpAfterPhases {"dump-after-phases", "",
294                                               "Generate program dump after running phases in the list"};
295    ark::PandArg<bool> opListPhases {"list-phases", false, "Dump list of available phases"};
296
297    // tail arguments
298    ark::PandArg<std::string> inputFile {"input", "", "input file"};
299
300    ark::PandArg<std::string> arktsConfig;
301    // NOLINTEND(misc-non-private-member-variables-in-classes)
302
303    explicit AllArgs(const char *argv0)
304        : arktsConfig {"arktsconfig", ark::es2panda::JoinPaths(ark::es2panda::ParentPath(argv0), "arktsconfig.json"),
305                       "Path to arkts configuration file"}
306    {
307    }
308
309    bool ParseInputOutput(CompilationMode compilationMode, std::string &errorMsg, std::string &sourceFile,
310                          std::string &parserInput, std::string &compilerOutput) const
311    {
312        auto isDebuggerEvalMode = opDebuggerEvalMode.GetValue();
313        if (isDebuggerEvalMode && compilationMode != CompilationMode::SINGLE_FILE) {
314            errorMsg = "Error: When compiling with --debugger-eval-mode single input file must be provided";
315            return false;
316        }
317
318        sourceFile = inputFile.GetValue();
319        if (compilationMode == CompilationMode::SINGLE_FILE) {
320            std::ifstream inputStream(sourceFile.c_str());
321            if (inputStream.fail()) {
322                errorMsg = "Failed to open file: ";
323                errorMsg.append(sourceFile);
324                return false;
325            }
326
327            std::stringstream ss;
328            if (isDebuggerEvalMode) {
329                GenerateEvaluationWrapper(sourceFile, inputStream, ss);
330            } else {
331                ss << inputStream.rdbuf();
332            }
333            parserInput = ss.str();
334        }
335
336        if (!outputFile.GetValue().empty()) {
337            if (compilationMode == CompilationMode::PROJECT) {
338                errorMsg = "Error: When compiling in project mode --output key is not needed";
339                return false;
340            }
341            compilerOutput = outputFile.GetValue();
342        } else {
343            compilerOutput = RemoveExtension(BaseName(sourceFile)).append(".abc");
344        }
345
346        return true;
347    }
348
349    void BindArgs(ark::PandArgParser &argparser)
350    {
351        argparser.Add(&opHelp);
352        argparser.Add(&opVersion);
353        argparser.Add(&opModule);
354        argparser.Add(&opDumpAst);
355        argparser.Add(&opDumpAstOnlySilent);
356        argparser.Add(&opDumpCheckedAst);
357        argparser.Add(&opParseOnly);
358        argparser.Add(&opDumpAssembly);
359        argparser.Add(&opDebugInfo);
360        argparser.Add(&opDumpDebugInfo);
361
362        argparser.Add(&opOptLevel);
363        argparser.Add(&opEtsModule);
364        argparser.Add(&opThreadCount);
365        argparser.Add(&opSizeStat);
366        argparser.Add(&opListFiles);
367
368        argparser.Add(&inputExtension);
369        argparser.Add(&outputFile);
370        argparser.Add(&logLevel);
371        argparser.Add(&stdLib);
372        argparser.Add(&genStdLib);
373        argparser.Add(&plugins);
374        argparser.Add(&skipPhases);
375        argparser.Add(&verifierAllChecks);
376        argparser.Add(&verifierFullProgram);
377        argparser.Add(&verifierWarnings);
378        argparser.Add(&verifierErrors);
379        argparser.Add(&dumpBeforePhases);
380        argparser.Add(&dumpEtsSrcBeforePhases);
381        argparser.Add(&dumpAfterPhases);
382        argparser.Add(&dumpEtsSrcAfterPhases);
383        argparser.Add(&opListPhases);
384        argparser.Add(&arktsConfig);
385
386        argparser.Add(&opEtsEnableAll);
387        argparser.Add(&opEtsWerror);
388        argparser.Add(&opEtsSubsetWarnings);
389        argparser.Add(&opEtsNonsubsetWarnings);
390
391        // ETS-subset warnings
392        argparser.Add(&opEtsProhibitTopLevelStatements);
393        argparser.Add(&opEtsBoostEqualityStatement);
394        argparser.Add(&opEtsRemoveLambda);
395        argparser.Add(&opEtsImplicitBoxingUnboxing);
396
397        // ETS-non-subset warnings
398        argparser.Add(&opEtsSuggestFinal);
399        argparser.Add(&opEtsRemoveAsync);
400
401        AddDebuggerEvaluationOptions(argparser);
402
403        argparser.PushBackTail(&inputFile);
404        argparser.EnableTail();
405        argparser.EnableRemainder();
406    }
407
408    void InitCompilerOptions(es2panda::CompilerOptions &compilerOptions, CompilationMode compilationMode) const
409    {
410        compilerOptions.dumpAsm = opDumpAssembly.GetValue();
411        compilerOptions.dumpAst = opDumpAst.GetValue();
412        compilerOptions.opDumpAstOnlySilent = opDumpAstOnlySilent.GetValue();
413        compilerOptions.dumpCheckedAst = opDumpCheckedAst.GetValue();
414        compilerOptions.dumpDebugInfo = opDumpDebugInfo.GetValue();
415        compilerOptions.isDebug = opDebugInfo.GetValue();
416        compilerOptions.parseOnly = opParseOnly.GetValue();
417        compilerOptions.stdLib = stdLib.GetValue();
418        compilerOptions.isEtsModule = opEtsModule.GetValue();
419        compilerOptions.plugins = SplitToStringVector(plugins.GetValue());
420        compilerOptions.skipPhases = SplitToStringSet(skipPhases.GetValue());
421        compilerOptions.verifierFullProgram = verifierFullProgram.GetValue();
422        compilerOptions.verifierAllChecks = verifierAllChecks.GetValue();
423        compilerOptions.verifierWarnings = SplitToStringSet(verifierWarnings.GetValue());
424        compilerOptions.verifierErrors = SplitToStringSet(verifierErrors.GetValue());
425        compilerOptions.dumpBeforePhases = SplitToStringSet(dumpBeforePhases.GetValue());
426        compilerOptions.dumpEtsSrcBeforePhases = SplitToStringSet(dumpEtsSrcBeforePhases.GetValue());
427        compilerOptions.dumpAfterPhases = SplitToStringSet(dumpAfterPhases.GetValue());
428        compilerOptions.dumpEtsSrcAfterPhases = SplitToStringSet(dumpEtsSrcAfterPhases.GetValue());
429
430        // ETS-Warnings
431        compilerOptions.etsSubsetWarnings = opEtsSubsetWarnings.GetValue();
432        compilerOptions.etsWerror = opEtsWerror.GetValue();
433        compilerOptions.etsNonsubsetWarnings = opEtsNonsubsetWarnings.GetValue();
434        compilerOptions.etsEnableAll = opEtsEnableAll.GetValue();
435
436        if (compilerOptions.etsEnableAll || compilerOptions.etsSubsetWarnings) {
437            // Adding subset warnings
438            compilerOptions.etsProhibitTopLevelStatements = ETSWarningsGroupSetter(opEtsProhibitTopLevelStatements);
439            compilerOptions.etsBoostEqualityStatement = ETSWarningsGroupSetter(opEtsBoostEqualityStatement);
440            compilerOptions.etsRemoveLambda = ETSWarningsGroupSetter(opEtsRemoveLambda);
441            compilerOptions.etsImplicitBoxingUnboxing = ETSWarningsGroupSetter(opEtsImplicitBoxingUnboxing);
442        }
443
444        if (compilerOptions.etsEnableAll || compilerOptions.etsNonsubsetWarnings) {
445            // Adding non-subset warnings
446            compilerOptions.etsSuggestFinal = ETSWarningsGroupSetter(opEtsSuggestFinal);
447            compilerOptions.etsRemoveAsync = ETSWarningsGroupSetter(opEtsRemoveAsync);
448        }
449
450        if (!compilerOptions.etsEnableAll && !compilerOptions.etsSubsetWarnings &&
451            !compilerOptions.etsNonsubsetWarnings) {
452            // If no warnings groups enabled - check all if enabled
453            compilerOptions.etsSuggestFinal = opEtsSuggestFinal.GetValue();
454            compilerOptions.etsProhibitTopLevelStatements = opEtsProhibitTopLevelStatements.GetValue();
455            compilerOptions.etsBoostEqualityStatement = opEtsBoostEqualityStatement.GetValue();
456            compilerOptions.etsRemoveAsync = opEtsRemoveAsync.GetValue();
457            compilerOptions.etsRemoveLambda = opEtsRemoveLambda.GetValue();
458            compilerOptions.etsImplicitBoxingUnboxing = opEtsImplicitBoxingUnboxing.GetValue();
459        }
460
461        InitDebuggerEvaluationCompilerOptions(compilerOptions);
462
463        // Pushing enabled warnings to warning collection
464        PushingEnabledWarnings(compilerOptions);
465
466        compilerOptions.compilationMode = compilationMode;
467        compilerOptions.arktsConfig = std::make_shared<ark::es2panda::ArkTsConfig>(arktsConfig.GetValue());
468    }
469
470private:
471    static void PushingEnabledWarnings(es2panda::CompilerOptions &compilerOptions)
472    {
473        if (compilerOptions.etsSuggestFinal) {
474            compilerOptions.etsWarningCollection.push_back(ETSWarnings::SUGGEST_FINAL);
475        }
476        if (compilerOptions.etsProhibitTopLevelStatements) {
477            compilerOptions.etsWarningCollection.push_back(ETSWarnings::PROHIBIT_TOP_LEVEL_STATEMENTS);
478        }
479        if (compilerOptions.etsBoostEqualityStatement) {
480            compilerOptions.etsWarningCollection.push_back(ETSWarnings::BOOST_EQUALITY_STATEMENT);
481        }
482        if (compilerOptions.etsRemoveAsync) {
483            compilerOptions.etsWarningCollection.push_back(ETSWarnings::REMOVE_ASYNC_FUNCTIONS);
484        }
485        if (compilerOptions.etsRemoveLambda) {
486            compilerOptions.etsWarningCollection.push_back(ETSWarnings::REMOVE_LAMBDA);
487        }
488        if (compilerOptions.etsImplicitBoxingUnboxing) {
489            compilerOptions.etsWarningCollection.push_back(ETSWarnings::IMPLICIT_BOXING_UNBOXING);
490        }
491        if (!compilerOptions.etsWarningCollection.empty()) {
492            compilerOptions.etsHasWarnings = true;
493        }
494    }
495
496    void AddDebuggerEvaluationOptions(ark::PandArgParser &argparser)
497    {
498        argparser.Add(&opDebuggerEvalMode);
499        argparser.Add(&opDebuggerEvalLine);
500        argparser.Add(&opDebuggerEvalSource);
501        argparser.Add(&opDebuggerEvalPandaFiles);
502    }
503
504    void InitDebuggerEvaluationCompilerOptions(es2panda::CompilerOptions &compilerOptions) const
505    {
506        compilerOptions.debuggerEvalMode = opDebuggerEvalMode.GetValue();
507        if (compilerOptions.debuggerEvalMode) {
508            compilerOptions.debuggerEvalLine = opDebuggerEvalLine.GetValue();
509            compilerOptions.debuggerEvalSource = opDebuggerEvalSource.GetValue();
510            compilerOptions.debuggerEvalPandaFiles = SplitToStringVector(opDebuggerEvalPandaFiles.GetValue());
511        }
512    }
513};
514
515static std::string Usage(const ark::PandArgParser &argparser)
516{
517    std::stringstream ss;
518
519    ss << argparser.GetErrorString() << std::endl;
520    ss << "Usage: "
521       << "es2panda"
522       << " [OPTIONS] [input file] -- [arguments]" << std::endl;
523    ss << std::endl;
524    ss << "optional arguments:" << std::endl;
525    ss << argparser.GetHelpString() << std::endl;
526
527    ss << std::endl;
528    ss << "--bco-optimizer: Argument directly to bytecode optimizer can be passed after this prefix" << std::endl;
529    ss << "--bco-compiler: Argument directly to jit-compiler inside bytecode optimizer can be passed after this "
530          "prefix"
531       << std::endl;
532
533    return ss.str();
534}
535
536static std::string GetVersion()
537{
538    std::stringstream ss;
539
540    ss << std::endl;
541    ss << "  Es2panda Version " << ES2PANDA_VERSION << std::endl;
542
543#ifndef PANDA_PRODUCT_BUILD
544#ifdef ES2PANDA_DATE
545    ss << std::endl;
546    ss << "  Build date: ";
547    ss << ES2PANDA_DATE;
548#endif  // ES2PANDA_DATE
549#ifdef ES2PANDA_HASH
550    ss << std::endl;
551    ss << "  Last commit hash: ";
552    ss << ES2PANDA_HASH;
553    ss << std::endl;
554#endif  // ES2PANDA_HASH
555#endif  // PANDA_PRODUCT_BUILD
556
557    return ss.str();
558}
559
560bool Options::Parse(int argc, const char **argv)
561{
562    std::vector<std::string> es2pandaArgs;
563    std::vector<std::string> bcoCompilerArgs;
564    std::vector<std::string> bytecodeoptArgs;
565
566    SplitArgs(argc, argv, es2pandaArgs, bcoCompilerArgs, bytecodeoptArgs);
567    if (!ParseBCOCompilerOptions(bcoCompilerArgs, bytecodeoptArgs)) {
568        return false;
569    }
570
571    AllArgs allArgs(argv[0]);  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
572
573    allArgs.BindArgs(*argparser_);
574    if (!argparser_->Parse(es2pandaArgs) || allArgs.opHelp.GetValue()) {
575        errorMsg_ = Usage(*argparser_);
576        return false;
577    }
578
579    if (allArgs.opVersion.GetValue()) {
580        errorMsg_ = GetVersion();
581        return false;
582    }
583
584    // Determine compilation mode
585    auto compilationMode = DetermineCompilationMode(allArgs.genStdLib, allArgs.inputFile);
586    if (!allArgs.ParseInputOutput(compilationMode, errorMsg_, sourceFile_, parserInput_, compilerOutput_)) {
587        return false;
588    }
589
590    // Determine Extension
591    DetermineExtension(allArgs.inputExtension, allArgs.arktsConfig, compilationMode);
592    if (extension_ == es2panda::ScriptExtension::INVALID) {
593        return false;
594    }
595
596    if (extension_ != es2panda::ScriptExtension::JS && allArgs.opModule.GetValue()) {
597        errorMsg_ = "Error: --module is not supported for this extension.";
598        return false;
599    }
600
601    // Add Option Flags
602    AddOptionFlags(allArgs.opParseOnly, allArgs.opModule, allArgs.opSizeStat);
603
604    if ((allArgs.dumpEtsSrcBeforePhases.GetValue().size() + allArgs.dumpEtsSrcAfterPhases.GetValue().size() > 0) &&
605        extension_ != es2panda::ScriptExtension::ETS) {
606        errorMsg_ = "--dump-ets-src-* option is valid only with ETS extension";
607        return false;
608    }
609
610    DetermineLogLevel(allArgs.logLevel);
611    if (logLevel_ == util::LogLevel::INVALID) {
612        return false;
613    }
614
615    allArgs.InitCompilerOptions(compilerOptions_, compilationMode);
616    // Some additional checks for ETS extension
617    if (!CheckEtsSpecificOptions(compilationMode, allArgs.arktsConfig)) {
618        return false;
619    }
620
621    optLevel_ = allArgs.opOptLevel.GetValue();
622    threadCount_ = allArgs.opThreadCount.GetValue();
623    listFiles_ = allArgs.opListFiles.GetValue();
624    listPhases_ = allArgs.opListPhases.GetValue();
625
626    return true;
627}
628}  // namespace ark::es2panda::util
629