From 522be08eb07534c4faff0e18ac49e6befe4253ad Mon Sep 17 00:00:00 2001 From: q66 Date: Wed, 7 Sep 2016 22:46:22 +0200 Subject: [PATCH] more feature complete REPL --- tools/edit_libedit.hh | 57 ------------- tools/repl.cc | 180 +++++++++++++++++++++++++++++++++++------- 2 files changed, 150 insertions(+), 87 deletions(-) delete mode 100644 tools/edit_libedit.hh diff --git a/tools/edit_libedit.hh b/tools/edit_libedit.hh deleted file mode 100644 index 39df8d55..00000000 --- a/tools/edit_libedit.hh +++ /dev/null @@ -1,57 +0,0 @@ -#ifdef CS_REPL_USE_LIBEDIT -#ifndef CS_REPL_HAS_EDIT -#define CS_REPL_HAS_EDIT -/* use the NetBSD libedit library */ - -#include -#include - -#include - -static EditLine *els = nullptr; -static History *elh = nullptr; - -static char *el_prompt(EditLine *el) { - void *prompt = nullptr; - el_get(el, EL_CLIENTDATA, &prompt); - if (!prompt) { - return const_cast(""); - } - return const_cast(static_cast(prompt)->get_value().data()); -} - -static void init_lineedit(ostd::ConstCharRange progname) { - els = el_init(progname.data(), stdin, stdout, stderr); - elh = history_init(); - - /* init history with reasonable size */ - HistEvent ev; - history(elh, &ev, H_SETSIZE, 1000); - el_set(els, EL_HIST, history, elh); - - el_set(els, EL_PROMPT, el_prompt); -} - -static ostd::Maybe read_line(CsSvar *pr) { - int count; - el_set(els, EL_CLIENTDATA, static_cast(pr)); - auto line = el_gets(els, &count); - if (count > 0) { - ostd::String ret = line; - /* libedit keeps the trailing \n */ - ret.resize(ret.size() - 1); - return ostd::move(ret); - } else if (!count) { - return ostd::String(); - } - return ostd::nothing; -} - -static void add_history(ostd::ConstCharRange line) { - HistEvent ev; - /* backed by ostd::String so it's terminated */ - history(elh, &ev, H_ENTER, line.data()); -} - -#endif -#endif diff --git a/tools/repl.cc b/tools/repl.cc index dae27f49..565bac9b 100644 --- a/tools/repl.cc +++ b/tools/repl.cc @@ -9,7 +9,7 @@ using namespace cscript; -ostd::ConstCharRange version = "CubeScript 0.0.1 (REPL mode)"; +ostd::ConstCharRange version = "CubeScript 0.0.1"; /* util */ @@ -43,7 +43,6 @@ static ostd::ConstCharRange get_complete_cmd(ostd::ConstCharRange buf) { #endif /* CS_REPL_HAS_COMPLETE */ #ifdef CS_REPL_HAS_HINTS - static inline ostd::ConstCharRange get_arg_type(char arg) { switch (arg) { case 'i': @@ -156,14 +155,33 @@ static CsCommand *get_hint_cmd(ostd::ConstCharRange buf) { } return nullptr; } - #endif /* CS_REPL_HAS_HINTS */ #include "tools/edit_linenoise.hh" -#include "tools/edit_libedit.hh" #include "tools/edit_readline.hh" #include "tools/edit_fallback.hh" +/* usage */ + +void print_usage(ostd::ConstCharRange progname, bool err) { + auto &s = err ? ostd::err : ostd::out; + s.writeln( + "Usage: ", progname, " [options] [file]\n" + "Options:\n" + " -e str run string \"str\"\n" + " -i enter interactive mode after the above\n" + " -v show version information\n" + " -h show this message\n" + " -- stop handling options\n" + " - execute stdin and stop handling options" + ); + s.flush(); +} + +void print_version() { + ostd::writeln(version); +} + struct InterruptedException { }; @@ -178,11 +196,17 @@ static void do_sigint(int n) { } } -static void do_call(CsState &cs, ostd::ConstCharRange line) { +static void do_call(CsState &cs, ostd::ConstCharRange line, bool file = false) { CsValue ret; signal(SIGINT, do_sigint); try { - cs.run(line, ret); + if (file) { + if (!cs.run_file(line, ret)) { + ostd::err.writeln("cannot read file: ", line); + } + } else { + cs.run(line, ret); + } } catch (InterruptedException) { signal(SIGINT, SIG_DFL); ostd::writeln(""); @@ -203,24 +227,7 @@ static void do_tty(CsState &cs) { do_exit = true; }); - cs.new_command("exec", "sb", [&cs](CsValueRange args, CsValue &res) { - auto file = args[0].get_strr(); - bool ret = cs.run_file(file); - if (!ret) { - if (args[1].get_int()) { - cs.get_err().writefln("could not run file \"%s\"", file); - } - res.set_int(0); - } else { - res.set_int(1); - } - }); - - cs.new_command("echo", "C", [&cs](CsValueRange args, CsValue &) { - cs.get_out().writeln(args[0].get_strr()); - }); - - ostd::writeln(version); + ostd::writeln(version, " (REPL mode)"); for (;;) { auto line = read_line(prompt); if (!line) { @@ -246,14 +253,127 @@ static void do_tty(CsState &cs) { } } -int main(int, char **argv) { +int main(int argc, char **argv) { CsState cs; gcs = &cs; cs.init_libs(); - if (stdin_is_tty()) { - init_lineedit(argv[0]); - do_tty(cs); - } else { - ostd::err.writeln("Only interactive mode is supported for now."); + + cs.new_command("exec", "sb", [&cs](auto args, auto &res) { + auto file = args[0].get_strr(); + bool ret = cs.run_file(file); + if (!ret) { + if (args[1].get_int()) { + cs.get_err().writefln("could not run file \"%s\"", file); + } + res.set_int(0); + } else { + res.set_int(1); + } + }); + + cs.new_command("echo", "C", [&cs](auto args, auto &) { + cs.get_out().writeln(args[0].get_strr()); + }); + + int firstarg = 0; + bool has_inter = false, has_ver = false, has_help = false, has_str = false; + for (int i = 1; i < argc; ++i) { + if (argv[i][0] != '-') { + firstarg = i; + goto endargs; + } + switch (argv[i][1]) { + case '-': + if (argv[i][2] != '\0') { + firstarg = -1; + goto endargs; + } + firstarg = (argv[i + 1] != nullptr) ? (i + 1) : 0; + goto endargs; + case '\0': + firstarg = i; + goto endargs; + case 'i': + if (argv[i][2] != '\0') { + firstarg = -1; + goto endargs; + } + has_inter = true; + break; + case 'v': + if (argv[i][2] != '\0') { + firstarg = -1; + goto endargs; + } + has_ver = true; + break; + case 'h': + if (argv[i][2] != '\0') { + firstarg = -1; + goto endargs; + } + has_help = true; + break; + case 'e': + has_str = true; + if (argv[i][2] == '\0') { + ++i; + if (!argv[i]) { + firstarg = -1; + goto endargs; + } + } + break; + default: + firstarg = -1; + goto endargs; + } + } +endargs: + if (firstarg < 0) { + print_usage(argv[0], true); + return 1; + } + if (has_ver && !has_inter) { + print_version(); + } + if (has_help) { + print_usage(argv[0], false); + return 0; + } + for (int i = 1; i < ((firstarg > 0) ? firstarg : argc); ++i) { + switch (argv[i][1]) { + case 'e': { + auto str = argv[i] + 2; + if (*str == '\0') { + str = argv[++i]; + } + do_call(cs, str); + break; + } + } + } + if (firstarg) { + do_call(cs, argv[firstarg], true); + } + if (!firstarg && !has_str && !has_ver) { + if (stdin_is_tty()) { + init_lineedit(argv[0]); + do_tty(cs); + return 0; + } else { + ostd::String str; + for (char c = '\0'; (c = ostd::in.getchar()) != EOF;) { + str += c; + } + do_call(cs, str); + } + } + if (has_inter) { + if (stdin_is_tty()) { + init_lineedit(argv[0]); + do_tty(cs); + } + return 0; } }