using new cli parser

This commit is contained in:
ValKmjolnir 2024-06-02 00:33:21 +08:00
parent 40a53a4224
commit 2c6a0fd84d
5 changed files with 83 additions and 68 deletions

View File

@ -1,7 +1,26 @@
#include "cli/cli.h"
#include <iostream>
namespace nasal::cli {
cli_config parse(const std::vector<std::string>& args) {
cli_config result;
for(const auto& arg : args) {
if (cli_options.count(arg)) {
result.options.insert(cli_options.at(arg));
} else if (!result.input_file_path.length()) {
result.input_file_path = arg;
} else {
result.nasal_vm_args.push_back(arg);
}
}
if (result.input_file_path.length() && result.options.empty()) {
result.options.insert(option::cli_execute);
}
return result;
}
}

View File

@ -3,6 +3,8 @@
#include <cstring>
#include <sstream>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace nasal::cli {
@ -16,7 +18,7 @@ enum class option {
cli_show_symbol,
cli_execute,
cli_show_execute_time,
cli_show_detail_info,
cli_detail_info,
cli_show_referenced_file,
cli_debug_mode,
cli_profile,
@ -24,9 +26,17 @@ enum class option {
cli_limit_mode
};
using config = std::unordered_map<option, std::string>;
struct cli_config {
std::string input_file_path = "";
std::unordered_set<option> options = {};
std::vector<std::string> nasal_vm_args = {};
const std::unordered_map<std::string, option> options = {
bool has(option opt) const {
return options.count(opt);
}
};
const std::unordered_map<std::string, option> cli_options = {
{"-h", option::cli_help},
{"--help", option::cli_help},
{"-v", option::cli_version},
@ -44,6 +54,8 @@ const std::unordered_map<std::string, option> options = {
{"--exec", option::cli_execute},
{"-t", option::cli_show_execute_time},
{"--time", option::cli_show_execute_time},
{"-d", option::cli_detail_info},
{"--detail", option::cli_detail_info},
{"-f", option::cli_show_referenced_file},
{"--ref-file", option::cli_show_referenced_file},
{"-dbg", option::cli_debug_mode},
@ -53,4 +65,6 @@ const std::unordered_map<std::string, option> options = {
{"--limit", option::cli_limit_mode}
};
cli_config parse(const std::vector<std::string>&);
}

View File

@ -119,10 +119,8 @@ void err() {
std::exit(1);
}
void execute(const std::string& file,
const std::vector<std::string>& argv,
const u32 cmd) {
void execute(const nasal::cli::cli_config& config) {
using option = nasal::cli::option;
using clk = std::chrono::high_resolution_clock;
const auto den = clk::duration::period::den;
@ -132,17 +130,17 @@ void execute(const std::string& file,
nasal::codegen gen;
// lexer scans file to get tokens
lex.scan(file).chkerr();
lex.scan(config.input_file_path).chkerr();
// parser gets lexer's token list to compile
parse.compile(lex).chkerr();
if (cmd&VM_RAW_AST) {
if (config.has(option::cli_view_raw_ast)) {
nasal::ast_dumper().dump(parse.tree());
}
// linker gets parser's ast and load import files to this ast
ld.link(parse, cmd&VM_DETAIL).chkerr();
if (cmd&VM_REF_FILE) {
ld.link(parse, config.has(option::cli_detail_info)).chkerr();
if (config.has(option::cli_show_referenced_file)) {
if (ld.get_file_list().size()) {
std::cout << "referenced file(s):\n";
}
@ -154,34 +152,43 @@ void execute(const std::string& file,
// optimizer does simple optimization on ast
auto opt = std::make_unique<nasal::optimizer>();
opt->do_optimization(parse.tree());
if (cmd&VM_AST) {
if (config.has(option::cli_view_ast)) {
nasal::ast_dumper().dump(parse.tree());
}
// code generator gets parser's ast and import file list to generate code
gen.compile(parse, ld, false, cmd&VM_LIMIT).chkerr();
if (cmd&VM_CODE) {
gen.compile(parse, ld, false, config.has(option::cli_limit_mode)).chkerr();
if (config.has(option::cli_view_code)) {
gen.print(std::cout);
}
if (cmd&VM_SYMINFO) {
if (config.has(option::cli_show_symbol)) {
gen.symbol_dump(std::cout);
}
// run
const auto start = clk::now();
if (cmd&VM_DEBUG) {
if (config.has(option::cli_debug_mode)) {
auto debugger = std::make_unique<nasal::dbg>();
debugger->run(gen, ld, argv, cmd&VM_PROFILE, cmd&VM_PROF_ALL);
} else if (cmd&VM_TIME || cmd&VM_EXEC) {
debugger->run(
gen,
ld,
config.nasal_vm_args,
config.has(option::cli_profile),
config.has(option::cli_profile_all)
);
} else if (config.has(option::cli_show_execute_time) ||
config.has(option::cli_detail_info) ||
config.has(option::cli_limit_mode) ||
config.has(option::cli_execute)) {
auto runtime = std::make_unique<nasal::vm>();
runtime->set_detail_report_info(cmd&VM_DETAIL);
runtime->set_limit_mode_flag(cmd&VM_LIMIT);
runtime->run(gen, ld, argv);
runtime->set_detail_report_info(config.has(option::cli_detail_info));
runtime->set_limit_mode_flag(config.has(option::cli_limit_mode));
runtime->run(gen, ld, config.nasal_vm_args);
}
// get running time
const auto end = clk::now();
if (cmd&VM_TIME) {
if (config.has(option::cli_show_execute_time)) {
std::clog << "process exited after ";
std::clog << static_cast<f64>((end-start).count())/den << "s.\n\n";
}
@ -194,18 +201,20 @@ i32 main(i32 argc, const char* argv[]) {
return 0;
}
// the first argument is the executable itself, ignore it
const auto config = nasal::cli::parse({argv+1, argv+argc});
// run directly or show help
if (argc==2) {
std::string s(argv[1]);
if (s=="-h" || s=="--help") {
if (config.has(nasal::cli::option::cli_help)) {
std::clog << help;
} else if (s=="-v" || s=="--version") {
} else if (config.has(nasal::cli::option::cli_version)) {
std::clog << version;
} else if (s=="-r" || s=="--repl") {
} else if (config.has(nasal::cli::option::cli_repl_mode)) {
auto repl = std::make_unique<nasal::repl::repl>();
repl->execute();
} else if (s[0]!='-') {
execute(s, {}, VM_EXEC);
} else if (config.input_file_path.size()) {
execute(config);
} else {
err();
}
@ -213,45 +222,6 @@ i32 main(i32 argc, const char* argv[]) {
}
// execute with arguments
const std::unordered_map<std::string, u32> command_list = {
{"--raw-ast", VM_RAW_AST},
{"--ast", VM_AST},
{"-a", VM_AST},
{"--code", VM_CODE},
{"-c", VM_CODE},
{"--symbol", VM_SYMINFO},
{"-s", VM_SYMINFO},
{"--exec", VM_EXEC},
{"-e", VM_EXEC},
{"--time", VM_TIME|VM_EXEC},
{"-t", VM_TIME|VM_EXEC},
{"--detail", VM_DETAIL|VM_EXEC},
{"-d", VM_DETAIL|VM_EXEC},
{"--debug", VM_DEBUG},
{"-dbg", VM_DEBUG},
{"--prof", VM_PROFILE},
{"--prof-all", VM_PROF_ALL},
{"-f", VM_REF_FILE},
{"--ref-file", VM_REF_FILE},
{"--limit", VM_LIMIT|VM_EXEC}
};
u32 commands = 0;
std::string filename = "";
std::vector<std::string> vm_argv;
for(i32 i = 1; i<argc; ++i) {
if (command_list.count(argv[i])) {
commands |= command_list.at(argv[i]);
} else if (!filename.length()) {
filename = argv[i];
} else {
vm_argv.push_back(argv[i]);
}
}
if (!filename.length()) {
err();
}
execute(filename, vm_argv, commands? commands:VM_EXEC);
execute(config);
return 0;
}

View File

@ -75,6 +75,11 @@ void lexer::open(const std::string& file) {
return;
}
if (file.empty()) {
err.err("lexer", "empty input file");
err.chkerr();
}
// check file exsits and it is a regular file
if (!fs::is_regular(file)) {
err.err("lexer", "<"+file+"> is not a regular file");

View File

@ -1,3 +1,7 @@
use std.runtime;
runtime.windows.set_utf8_output();
var table_character_set = [
"─", "━", "│", "┃", "╌", "╍", "╎", "╏", "┄", "┅",
"┆", "┇", "┈", "┉", "┊", "┋", "┌", "┍", "┎", "┏",
@ -83,6 +87,9 @@ var choice = func(above_block_char,
append(possible, bcs);
}
}
if (!size(possible)) {
return " ";
}
func() {
if (vecindex(possible, " ")!=nil) {