forked from OctaForge/libcubescript
re-expose command and add hints/completion for now at least with linenoise
parent
0ff65e5ed4
commit
6aca518614
4
Makefile
4
Makefile
|
@ -29,8 +29,8 @@ $(LIBCS_LIB): $(LIBCS_OBJ)
|
||||||
|
|
||||||
repl: $(LIBCS_LIB) tools/repl.cc tools/linenoise.cc tools/linenoise.hh
|
repl: $(LIBCS_LIB) tools/repl.cc tools/linenoise.cc tools/linenoise.hh
|
||||||
$(CXX) $(CXXFLAGS) $(LIBCS_CXXFLAGS) $(LDFLAGS) \
|
$(CXX) $(CXXFLAGS) $(LIBCS_CXXFLAGS) $(LDFLAGS) \
|
||||||
-Itools -DCS_REPL_USE_LINENOISE tools/linenoise.cc \
|
-Itools -DCS_REPL_USE_LINENOISE -DCS_REPL_HAS_COMPLETE -DCS_REPL_HAS_HINTS \
|
||||||
tools/repl.cc -o repl $(LIBCS_LIB)
|
tools/linenoise.cc tools/repl.cc -o repl $(LIBCS_LIB)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(LIBCS_LIB) $(LIBCS_OBJ)
|
rm -f $(LIBCS_LIB) $(LIBCS_OBJ)
|
||||||
|
|
12
cs_gen.cc
12
cs_gen.cc
|
@ -517,9 +517,9 @@ lookupid:
|
||||||
if (prevargs >= MaxResults) {
|
if (prevargs >= MaxResults) {
|
||||||
gs.code.push(CODE_ENTER);
|
gs.code.push(CODE_ENTER);
|
||||||
}
|
}
|
||||||
char const *fmt = static_cast<Command *>(id)->cargs;
|
auto fmt = static_cast<CsCommand *>(id)->get_args();
|
||||||
for (; *fmt; fmt++) {
|
for (char c: fmt) {
|
||||||
switch (*fmt) {
|
switch (c) {
|
||||||
case 'S':
|
case 'S':
|
||||||
gs.gen_str();
|
gs.gen_str();
|
||||||
numargs++;
|
numargs++;
|
||||||
|
@ -1204,8 +1204,8 @@ noid:
|
||||||
case ID_COMMAND: {
|
case ID_COMMAND: {
|
||||||
int comtype = CODE_COM, fakeargs = 0;
|
int comtype = CODE_COM, fakeargs = 0;
|
||||||
bool rep = false;
|
bool rep = false;
|
||||||
char const *fmt = static_cast<Command *>(id)->cargs;
|
auto fmt = static_cast<CsCommand *>(id)->get_args();
|
||||||
for (; *fmt; fmt++) {
|
for (; !fmt.empty(); ++fmt) {
|
||||||
switch (*fmt) {
|
switch (*fmt) {
|
||||||
case 'S':
|
case 'S':
|
||||||
case 's':
|
case 's':
|
||||||
|
@ -1223,7 +1223,7 @@ noid:
|
||||||
ostd::ConstCharRange(), *fmt == 's'
|
ostd::ConstCharRange(), *fmt == 's'
|
||||||
);
|
);
|
||||||
fakeargs++;
|
fakeargs++;
|
||||||
} else if (!fmt[1]) {
|
} else if (fmt.size() == 1) {
|
||||||
int numconc = 1;
|
int numconc = 1;
|
||||||
while ((numargs + numconc) < MaxArguments) {
|
while ((numargs + numconc) < MaxArguments) {
|
||||||
more = compilearg(
|
more = compilearg(
|
||||||
|
|
28
cs_vm.cc
28
cs_vm.cc
|
@ -74,7 +74,7 @@ static inline bool cs_has_cmd_cb(CsIdent *id) {
|
||||||
if (!id->is_command() && !id->is_special()) {
|
if (!id->is_command() && !id->is_special()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Command *cb = static_cast<Command *>(id);
|
CsCommand *cb = static_cast<CsCommand *>(id);
|
||||||
return !!cb->cb_cftv;
|
return !!cb->cb_cftv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,12 +347,12 @@ void CsValue::copy_arg(CsValue &r) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void callcommand(
|
static inline void callcommand(
|
||||||
CsState &cs, Command *id, CsValue *args, CsValue &res, int numargs,
|
CsState &cs, CsCommand *id, CsValue *args, CsValue &res, int numargs,
|
||||||
bool lookup = false
|
bool lookup = false
|
||||||
) {
|
) {
|
||||||
int i = -1, fakeargs = 0;
|
int i = -1, fakeargs = 0;
|
||||||
bool rep = false;
|
bool rep = false;
|
||||||
for (char const *fmt = id->cargs; *fmt; fmt++) {
|
for (auto fmt = id->get_args(); !fmt.empty(); ++fmt) {
|
||||||
switch (*fmt) {
|
switch (*fmt) {
|
||||||
case 'i':
|
case 'i':
|
||||||
if (++i >= numargs) {
|
if (++i >= numargs) {
|
||||||
|
@ -611,7 +611,7 @@ static inline int cs_get_lookupu_type(
|
||||||
arg.cleanup();
|
arg.cleanup();
|
||||||
arg.set_null();
|
arg.set_null();
|
||||||
CsValue buf[MaxArguments];
|
CsValue buf[MaxArguments];
|
||||||
callcommand(cs, static_cast<Command *>(id), buf, arg, 0, true);
|
callcommand(cs, static_cast<CsCommand *>(id), buf, arg, 0, true);
|
||||||
force_arg(arg, op & CODE_RET_MASK);
|
force_arg(arg, op & CODE_RET_MASK);
|
||||||
return -2; /* ignore */
|
return -2; /* ignore */
|
||||||
}
|
}
|
||||||
|
@ -1381,10 +1381,12 @@ static ostd::Uint32 *runcode(CsState &cs, ostd::Uint32 *code, CsValue &result) {
|
||||||
case CODE_COM | RET_STR:
|
case CODE_COM | RET_STR:
|
||||||
case CODE_COM | RET_FLOAT:
|
case CODE_COM | RET_FLOAT:
|
||||||
case CODE_COM | RET_INT: {
|
case CODE_COM | RET_INT: {
|
||||||
Command *id = static_cast<Command *>(cs.identmap[op >> 8]);
|
CsCommand *id = static_cast<CsCommand *>(cs.identmap[op >> 8]);
|
||||||
int offset = numargs - id->numargs;
|
int offset = numargs - id->get_num_args();
|
||||||
result.force_null();
|
result.force_null();
|
||||||
id->cb_cftv(CsValueRange(args + offset, id->numargs), result);
|
id->cb_cftv(
|
||||||
|
CsValueRange(args + offset, id->get_num_args()), result
|
||||||
|
);
|
||||||
force_arg(result, op & CODE_RET_MASK);
|
force_arg(result, op & CODE_RET_MASK);
|
||||||
free_args(args, numargs, offset);
|
free_args(args, numargs, offset);
|
||||||
continue;
|
continue;
|
||||||
|
@ -1394,7 +1396,7 @@ static ostd::Uint32 *runcode(CsState &cs, ostd::Uint32 *code, CsValue &result) {
|
||||||
case CODE_COMV | RET_STR:
|
case CODE_COMV | RET_STR:
|
||||||
case CODE_COMV | RET_FLOAT:
|
case CODE_COMV | RET_FLOAT:
|
||||||
case CODE_COMV | RET_INT: {
|
case CODE_COMV | RET_INT: {
|
||||||
Command *id = static_cast<Command *>(cs.identmap[op >> 13]);
|
CsCommand *id = static_cast<CsCommand *>(cs.identmap[op >> 13]);
|
||||||
int callargs = (op >> 8) & 0x1F, offset = numargs - callargs;
|
int callargs = (op >> 8) & 0x1F, offset = numargs - callargs;
|
||||||
result.force_null();
|
result.force_null();
|
||||||
id->cb_cftv(ostd::iter(&args[offset], callargs), result);
|
id->cb_cftv(ostd::iter(&args[offset], callargs), result);
|
||||||
|
@ -1406,7 +1408,7 @@ static ostd::Uint32 *runcode(CsState &cs, ostd::Uint32 *code, CsValue &result) {
|
||||||
case CODE_COMC | RET_STR:
|
case CODE_COMC | RET_STR:
|
||||||
case CODE_COMC | RET_FLOAT:
|
case CODE_COMC | RET_FLOAT:
|
||||||
case CODE_COMC | RET_INT: {
|
case CODE_COMC | RET_INT: {
|
||||||
Command *id = static_cast<Command *>(cs.identmap[op >> 13]);
|
CsCommand *id = static_cast<CsCommand *>(cs.identmap[op >> 13]);
|
||||||
int callargs = (op >> 8) & 0x1F, offset = numargs - callargs;
|
int callargs = (op >> 8) & 0x1F, offset = numargs - callargs;
|
||||||
result.force_null();
|
result.force_null();
|
||||||
{
|
{
|
||||||
|
@ -1559,7 +1561,7 @@ noid:
|
||||||
case ID_COMMAND:
|
case ID_COMMAND:
|
||||||
idarg.cleanup();
|
idarg.cleanup();
|
||||||
callcommand(
|
callcommand(
|
||||||
cs, static_cast<Command *>(id), &args[offset],
|
cs, static_cast<CsCommand *>(id), &args[offset],
|
||||||
result, callargs
|
result, callargs
|
||||||
);
|
);
|
||||||
force_arg(result, op & CODE_RET_MASK);
|
force_arg(result, op & CODE_RET_MASK);
|
||||||
|
@ -1673,16 +1675,16 @@ void CsState::run_ret(CsIdent *id, CsValueRange args, CsValue &ret) {
|
||||||
}
|
}
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case CsIdentType::command:
|
case CsIdentType::command:
|
||||||
if (nargs < static_cast<Command *>(id)->numargs) {
|
if (nargs < static_cast<CsCommand *>(id)->get_num_args()) {
|
||||||
CsValue buf[MaxArguments];
|
CsValue buf[MaxArguments];
|
||||||
memcpy(buf, args.data(), args.size() * sizeof(CsValue));
|
memcpy(buf, args.data(), args.size() * sizeof(CsValue));
|
||||||
callcommand(
|
callcommand(
|
||||||
*this, static_cast<Command *>(id), buf, ret,
|
*this, static_cast<CsCommand *>(id), buf, ret,
|
||||||
nargs, false
|
nargs, false
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
callcommand(
|
callcommand(
|
||||||
*this, static_cast<Command *>(id), args.data(),
|
*this, static_cast<CsCommand *>(id), args.data(),
|
||||||
ret, nargs, false
|
ret, nargs, false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
12
cs_vm.hh
12
cs_vm.hh
|
@ -37,18 +37,6 @@ static inline int cs_vtype_to_int(CsValueType v) {
|
||||||
return cs_valtypet[int(v)];
|
return cs_valtypet[int(v)];
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Command: CsIdent {
|
|
||||||
char *cargs;
|
|
||||||
ostd::Uint32 argmask;
|
|
||||||
int numargs;
|
|
||||||
CmdFunc cb_cftv;
|
|
||||||
|
|
||||||
Command(
|
|
||||||
int type, ostd::ConstCharRange name, ostd::ConstCharRange args,
|
|
||||||
ostd::Uint32 argmask, int numargs, CmdFunc func
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
CODE_START = 0,
|
CODE_START = 0,
|
||||||
CODE_OFFSET,
|
CODE_OFFSET,
|
||||||
|
|
|
@ -96,13 +96,12 @@ CsAlias::CsAlias(ostd::ConstCharRange name, CsValue const &v, int fl):
|
||||||
p_acode(nullptr), p_astack(nullptr), p_val(v)
|
p_acode(nullptr), p_astack(nullptr), p_val(v)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Command::Command(
|
CsCommand::CsCommand(
|
||||||
int tp, ostd::ConstCharRange name, ostd::ConstCharRange args,
|
int tp, ostd::ConstCharRange name, ostd::ConstCharRange args,
|
||||||
ostd::Uint32 amask, int nargs, CmdFunc f
|
int nargs, CmdFunc f
|
||||||
):
|
):
|
||||||
CsIdent(CsIdentType::command, name, 0),
|
CsIdent(CsIdentType::command, name, 0),
|
||||||
cargs(cs_dup_ostr(args)),
|
p_cargs(cs_dup_ostr(args)), p_numargs(nargs), cb_cftv(ostd::move(f))
|
||||||
argmask(amask), numargs(nargs), cb_cftv(ostd::move(f))
|
|
||||||
{
|
{
|
||||||
p_type = tp;
|
p_type = tp;
|
||||||
}
|
}
|
||||||
|
@ -129,6 +128,20 @@ bool CsIdent::is_command() const {
|
||||||
return get_type() == CsIdentType::command;
|
return get_type() == CsIdentType::command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CsCommand *CsIdent::get_command() {
|
||||||
|
if (!is_command()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return static_cast<CsCommand *>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
CsCommand const *CsIdent::get_command() const {
|
||||||
|
if (!is_command()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return static_cast<CsCommand const *>(this);
|
||||||
|
}
|
||||||
|
|
||||||
bool CsIdent::is_special() const {
|
bool CsIdent::is_special() const {
|
||||||
return get_type() == CsIdentType::special;
|
return get_type() == CsIdentType::special;
|
||||||
}
|
}
|
||||||
|
@ -273,7 +286,7 @@ CsState::~CsState() {
|
||||||
a->get_value().force_null();
|
a->get_value().force_null();
|
||||||
a->clean_code();
|
a->clean_code();
|
||||||
} else if (i->is_command() || i->is_special()) {
|
} else if (i->is_command() || i->is_special()) {
|
||||||
delete[] static_cast<Command *>(i)->cargs;
|
delete[] static_cast<CsCommand *>(i)->p_cargs;
|
||||||
}
|
}
|
||||||
delete i;
|
delete i;
|
||||||
}
|
}
|
||||||
|
@ -1102,7 +1115,6 @@ static bool cs_add_command(
|
||||||
CsState &cs, ostd::ConstCharRange name, ostd::ConstCharRange args,
|
CsState &cs, ostd::ConstCharRange name, ostd::ConstCharRange args,
|
||||||
CmdFunc func, int type = ID_COMMAND
|
CmdFunc func, int type = ID_COMMAND
|
||||||
) {
|
) {
|
||||||
ostd::Uint32 argmask = 0;
|
|
||||||
int nargs = 0;
|
int nargs = 0;
|
||||||
for (ostd::ConstCharRange fmt(args); !fmt.empty(); ++fmt) {
|
for (ostd::ConstCharRange fmt(args); !fmt.empty(); ++fmt) {
|
||||||
switch (*fmt) {
|
switch (*fmt) {
|
||||||
|
@ -1114,18 +1126,12 @@ static bool cs_add_command(
|
||||||
case 'T':
|
case 'T':
|
||||||
case 'E':
|
case 'E':
|
||||||
case 'N':
|
case 'N':
|
||||||
case 'D':
|
|
||||||
if (nargs < MaxArguments) {
|
|
||||||
nargs++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'S':
|
case 'S':
|
||||||
case 's':
|
case 's':
|
||||||
case 'e':
|
case 'e':
|
||||||
case 'r':
|
case 'r':
|
||||||
case '$':
|
case '$':
|
||||||
if (nargs < MaxArguments) {
|
if (nargs < MaxArguments) {
|
||||||
argmask |= 1 << nargs;
|
|
||||||
nargs++;
|
nargs++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1134,7 +1140,7 @@ static bool cs_add_command(
|
||||||
case '3':
|
case '3':
|
||||||
case '4':
|
case '4':
|
||||||
if (nargs < MaxArguments) {
|
if (nargs < MaxArguments) {
|
||||||
fmt.push_front_n(fmt.front() - '0' + 1);
|
fmt.push_front_n(*fmt - '0' + 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'C':
|
case 'C':
|
||||||
|
@ -1148,7 +1154,7 @@ static bool cs_add_command(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cs.add_ident<Command>(type, name, args, argmask, nargs, ostd::move(func));
|
cs.add_ident<CsCommand>(type, name, args, nargs, ostd::move(func));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,7 @@ struct CsIvar;
|
||||||
struct CsFvar;
|
struct CsFvar;
|
||||||
struct CsSvar;
|
struct CsSvar;
|
||||||
struct CsAlias;
|
struct CsAlias;
|
||||||
|
struct CsCommand;
|
||||||
|
|
||||||
struct OSTD_EXPORT CsIdent {
|
struct OSTD_EXPORT CsIdent {
|
||||||
friend struct CsState;
|
friend struct CsState;
|
||||||
|
@ -151,6 +152,9 @@ struct OSTD_EXPORT CsIdent {
|
||||||
CsAlias const *get_alias() const;
|
CsAlias const *get_alias() const;
|
||||||
|
|
||||||
bool is_command() const;
|
bool is_command() const;
|
||||||
|
CsCommand *get_command();
|
||||||
|
CsCommand const *get_command() const;
|
||||||
|
|
||||||
bool is_special() const;
|
bool is_special() const;
|
||||||
|
|
||||||
bool is_var() const;
|
bool is_var() const;
|
||||||
|
@ -291,6 +295,30 @@ private:
|
||||||
CsValue p_val;
|
CsValue p_val;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using CmdFunc = ostd::Function<void(CsValueRange, CsValue &)>;
|
||||||
|
|
||||||
|
struct CsCommand: CsIdent {
|
||||||
|
friend struct CsState;
|
||||||
|
|
||||||
|
ostd::ConstCharRange get_args() const {
|
||||||
|
return p_cargs;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_num_args() const {
|
||||||
|
return p_numargs;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *p_cargs;
|
||||||
|
int p_numargs;
|
||||||
|
CmdFunc cb_cftv;
|
||||||
|
|
||||||
|
private:
|
||||||
|
CsCommand(
|
||||||
|
int type, ostd::ConstCharRange name, ostd::ConstCharRange args,
|
||||||
|
int numargs, CmdFunc func
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
struct CsIdentLink {
|
struct CsIdentLink {
|
||||||
CsIdent *id;
|
CsIdent *id;
|
||||||
CsIdentLink *next;
|
CsIdentLink *next;
|
||||||
|
@ -306,8 +334,6 @@ enum {
|
||||||
CS_LIB_ALL = 0b1111
|
CS_LIB_ALL = 0b1111
|
||||||
};
|
};
|
||||||
|
|
||||||
using CmdFunc = ostd::Function<void(CsValueRange, CsValue &)>;
|
|
||||||
|
|
||||||
struct OSTD_EXPORT CsState {
|
struct OSTD_EXPORT CsState {
|
||||||
CsMap<ostd::ConstCharRange, CsIdent *> idents;
|
CsMap<ostd::ConstCharRange, CsIdent *> idents;
|
||||||
CsVector<CsIdent *> identmap;
|
CsVector<CsIdent *> identmap;
|
||||||
|
|
|
@ -1,18 +1,66 @@
|
||||||
#ifdef CS_REPL_USE_LINENOISE
|
#ifdef CS_REPL_USE_LINENOISE
|
||||||
|
#ifdef OSTD_PLATFORM_POSIX
|
||||||
#ifndef CS_REPL_HAS_EDIT
|
#ifndef CS_REPL_HAS_EDIT
|
||||||
#define CS_REPL_HAS_EDIT
|
#define CS_REPL_HAS_EDIT
|
||||||
/* use the bundled linenoise library, default */
|
/* use the bundled linenoise library, default */
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
#include <ostd/string.hh>
|
#include <ostd/string.hh>
|
||||||
#include <ostd/maybe.hh>
|
#include <ostd/maybe.hh>
|
||||||
|
|
||||||
#include "linenoise.hh"
|
#include "linenoise.hh"
|
||||||
|
|
||||||
|
#ifdef CS_REPL_HAS_COMPLETE
|
||||||
|
static void ln_complete(char const *buf, linenoiseCompletions *lc) {
|
||||||
|
ostd::ConstCharRange cmd = get_complete_cmd(buf);
|
||||||
|
for (auto id: gcs->identmap.iter()) {
|
||||||
|
if (!id->is_command()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ostd::ConstCharRange idname = id->get_name();
|
||||||
|
if (idname.size() <= cmd.size()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (idname.slice(0, cmd.size()) == cmd) {
|
||||||
|
linenoiseAddCompletion(lc, idname.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CS_REPL_HAS_COMPLETE */
|
||||||
|
|
||||||
|
#ifdef CS_REPL_HAS_HINTS
|
||||||
|
static char *ln_hint(char const *buf, int *color, int *bold) {
|
||||||
|
CsCommand *cmd = get_hint_cmd(buf);
|
||||||
|
if (!cmd) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
ostd::String args = " [";
|
||||||
|
fill_cmd_args(args, cmd->get_args());
|
||||||
|
args += ']';
|
||||||
|
*color = 35;
|
||||||
|
*bold = 1;
|
||||||
|
char *ret = new char[args.size() + 1];
|
||||||
|
memcpy(ret, args.data(), args.size() + 1);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ln_hint_free(void *hint) {
|
||||||
|
delete[] static_cast<char *>(hint);
|
||||||
|
}
|
||||||
|
#endif /* CS_REPL_HAS_HINTS */
|
||||||
|
|
||||||
static void init_lineedit(ostd::ConstCharRange) {
|
static void init_lineedit(ostd::ConstCharRange) {
|
||||||
/* sensible default history size */
|
/* sensible default history size */
|
||||||
linenoiseHistorySetMaxLen(1000);
|
linenoiseHistorySetMaxLen(1000);
|
||||||
|
#ifdef CS_REPL_HAS_COMPLETE
|
||||||
|
linenoiseSetCompletionCallback(ln_complete);
|
||||||
|
#endif
|
||||||
|
#ifdef CS_REPL_HAS_HINTS
|
||||||
|
linenoiseSetHintsCallback(ln_hint);
|
||||||
|
linenoiseSetFreeHintsCallback(ln_hint_free);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static ostd::Maybe<ostd::String> read_line(CsSvar *pr) {
|
static ostd::Maybe<ostd::String> read_line(CsSvar *pr) {
|
||||||
|
@ -36,3 +84,4 @@ static void add_history(ostd::ConstCharRange line) {
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
133
tools/repl.cc
133
tools/repl.cc
|
@ -25,6 +25,138 @@ static bool stdin_is_tty() {
|
||||||
|
|
||||||
/* line editing support */
|
/* line editing support */
|
||||||
|
|
||||||
|
CsState *gcs = nullptr;
|
||||||
|
|
||||||
|
#ifdef CS_REPL_HAS_COMPLETE
|
||||||
|
static ostd::ConstCharRange get_complete_cmd(ostd::ConstCharRange buf) {
|
||||||
|
ostd::ConstCharRange not_allowed = "\"/;()[] \t\r\n\0";
|
||||||
|
ostd::ConstCharRange found = ostd::find_one_of(buf, not_allowed);
|
||||||
|
while (!found.empty()) {
|
||||||
|
++found;
|
||||||
|
buf = found;
|
||||||
|
found = ostd::find_one_of(found, not_allowed);
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
#endif /* CS_REPL_HAS_COMPLETE */
|
||||||
|
|
||||||
|
#ifdef CS_REPL_HAS_HINTS
|
||||||
|
|
||||||
|
static inline ostd::ConstCharRange get_arg_type(char arg) {
|
||||||
|
switch (arg) {
|
||||||
|
case 'i':
|
||||||
|
return "int";
|
||||||
|
case 'b':
|
||||||
|
return "int_min";
|
||||||
|
case 'f':
|
||||||
|
return "float";
|
||||||
|
case 'F':
|
||||||
|
return "float_prev";
|
||||||
|
case 't':
|
||||||
|
return "any";
|
||||||
|
case 'T':
|
||||||
|
return "any_m";
|
||||||
|
case 'E':
|
||||||
|
return "cond";
|
||||||
|
case 'N':
|
||||||
|
return "numargs";
|
||||||
|
case 'S':
|
||||||
|
return "str_m";
|
||||||
|
case 's':
|
||||||
|
return "str";
|
||||||
|
case 'e':
|
||||||
|
return "block";
|
||||||
|
case 'r':
|
||||||
|
return "ident";
|
||||||
|
case '$':
|
||||||
|
return "self";
|
||||||
|
}
|
||||||
|
return "illegal";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fill_cmd_args(ostd::String &writer, ostd::ConstCharRange args) {
|
||||||
|
char variadic = '\0';
|
||||||
|
int nrep = 0;
|
||||||
|
if (!args.empty() && ((args.back() == 'V') || (args.back() == 'C'))) {
|
||||||
|
variadic = args.back();
|
||||||
|
args.pop_back();
|
||||||
|
if (!args.empty() && isdigit(args.back())) {
|
||||||
|
nrep = args.back() - '0';
|
||||||
|
args.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (args.empty()) {
|
||||||
|
if (variadic == 'C') {
|
||||||
|
writer += "concat(...)";
|
||||||
|
} else if (variadic == 'V') {
|
||||||
|
writer += "...";
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int norep = int(args.size()) - nrep;
|
||||||
|
if (norep > 0) {
|
||||||
|
for (int i = 0; i < norep; ++i) {
|
||||||
|
if (i != 0) {
|
||||||
|
writer += ", ";
|
||||||
|
}
|
||||||
|
writer += get_arg_type(*args);
|
||||||
|
++args;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (variadic) {
|
||||||
|
if (norep > 0) {
|
||||||
|
writer += ", ";
|
||||||
|
}
|
||||||
|
if (variadic == 'C') {
|
||||||
|
writer += "concat(";
|
||||||
|
}
|
||||||
|
if (!args.empty()) {
|
||||||
|
if (args.size() > 1) {
|
||||||
|
writer += '{';
|
||||||
|
}
|
||||||
|
for (ostd::Size i = 0; i < args.size(); ++i) {
|
||||||
|
if (i) {
|
||||||
|
writer += ", ";
|
||||||
|
}
|
||||||
|
writer += get_arg_type(args[i]);
|
||||||
|
}
|
||||||
|
if (args.size() > 1) {
|
||||||
|
writer += '}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer += "...";
|
||||||
|
if (variadic == 'C') {
|
||||||
|
writer += ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static CsCommand *get_hint_cmd(ostd::ConstCharRange buf) {
|
||||||
|
ostd::ConstCharRange nextchars = "([;";
|
||||||
|
auto lp = ostd::find_one_of(buf, nextchars);
|
||||||
|
if (!lp.empty()) {
|
||||||
|
CsCommand *cmd = get_hint_cmd(buf + 1);
|
||||||
|
if (cmd) {
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!buf.empty() && isspace(buf.front())) {
|
||||||
|
++buf;
|
||||||
|
}
|
||||||
|
ostd::ConstCharRange spaces = " \t\r\n";
|
||||||
|
ostd::ConstCharRange s = ostd::find_one_of(buf, spaces);
|
||||||
|
if (!s.empty()) {
|
||||||
|
buf = ostd::slice_until(buf, s);
|
||||||
|
}
|
||||||
|
if (!buf.empty()) {
|
||||||
|
auto cmd = gcs->get_ident(buf);
|
||||||
|
return cmd ? cmd->get_command() : nullptr;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CS_REPL_HAS_HINTS */
|
||||||
|
|
||||||
#include "tools/edit_linenoise.hh"
|
#include "tools/edit_linenoise.hh"
|
||||||
#include "tools/edit_libedit.hh"
|
#include "tools/edit_libedit.hh"
|
||||||
#include "tools/edit_readline.hh"
|
#include "tools/edit_readline.hh"
|
||||||
|
@ -72,6 +204,7 @@ static void do_tty(CsState &cs) {
|
||||||
|
|
||||||
int main(int, char **argv) {
|
int main(int, char **argv) {
|
||||||
CsState cs;
|
CsState cs;
|
||||||
|
gcs = &cs;
|
||||||
cs.init_libs();
|
cs.init_libs();
|
||||||
if (stdin_is_tty()) {
|
if (stdin_is_tty()) {
|
||||||
init_lineedit(argv[0]);
|
init_lineedit(argv[0]);
|
||||||
|
|
Loading…
Reference in New Issue