return refs for new_*var and new_ident (guarantee valid result)

master
Daniel Kolesa 2021-04-05 19:52:13 +02:00
parent 1a68dd1c25
commit 8c8aa26c20
12 changed files with 239 additions and 242 deletions

View File

@ -8,14 +8,17 @@
#include "callable.hh"
#include "ident.hh"
#include "value.hh"
namespace cubescript {
struct state;
using alloc_func = void *(*)(void *, void *, size_t, size_t);
using hook_func = internal::callable<void, struct state &>;
using command_func = internal::callable<
void, struct state &, std::span<struct any_value>, struct any_value &
void, state &, std::span<any_value>, any_value &
>;
enum {
@ -68,19 +71,19 @@ struct LIBCUBESCRIPT_EXPORT state {
void clear_override(ident &id);
void clear_overrides();
integer_var *new_ivar(
integer_var &new_ivar(
std::string_view n, integer_type v, bool read_only = false,
var_type vtp = var_type::DEFAULT
);
float_var *new_fvar(
float_var &new_fvar(
std::string_view n, float_type v, bool read_only = false,
var_type vtp = var_type::DEFAULT
);
string_var *new_svar(
string_var &new_svar(
std::string_view n, std::string_view v, bool read_only = false,
var_type vtp = var_type::DEFAULT
);
ident *new_ident(std::string_view n);
ident &new_ident(std::string_view n);
void reset_var(std::string_view name);
void touch_var(std::string_view name);

View File

@ -114,7 +114,7 @@ struct LIBCUBESCRIPT_EXPORT any_value {
integer_type force_int();
std::string_view force_str();
bcode_ref force_code(state &cs);
ident *force_ident(state &cs);
ident &force_ident(state &cs);
private:
template<typename T>

View File

@ -238,154 +238,152 @@ static void compilelookup(codegen_state &gs, int ltype) {
if (lookup.empty()) goto invalid;
lookup.push_back('\0');
lookupid:
ident *id = gs.ts.istate->new_ident(
ident &id = gs.ts.istate->new_ident(
*gs.ts.pstate, lookup.str_term(), IDENT_FLAG_UNKNOWN
);
if (id) {
switch (id->get_type()) {
case ident_type::IVAR:
gs.code.push_back(
BC_INST_IVAR | ret_code(ltype, BC_RET_INT) |
(id->get_index() << 8)
);
switch (ltype) {
case VAL_POP:
gs.code.pop_back();
break;
case VAL_CODE:
gs.code.push_back(BC_INST_COMPILE);
break;
case VAL_IDENT:
gs.code.push_back(BC_INST_IDENT_U);
break;
}
return;
case ident_type::FVAR:
gs.code.push_back(
BC_INST_FVAR | ret_code(ltype, BC_RET_FLOAT) |
(id->get_index() << 8)
);
switch (ltype) {
case VAL_POP:
gs.code.pop_back();
break;
case VAL_CODE:
gs.code.push_back(BC_INST_COMPILE);
break;
case VAL_IDENT:
gs.code.push_back(BC_INST_IDENT_U);
break;
}
return;
case ident_type::SVAR:
switch (ltype) {
case VAL_POP:
return;
default:
gs.code.push_back(
BC_INST_SVAR | ret_code(ltype, BC_RET_STRING) |
(id->get_index() << 8)
);
break;
}
goto done;
case ident_type::ALIAS:
switch (ltype) {
case VAL_POP:
return;
case VAL_COND:
gs.code.push_back(
BC_INST_LOOKUP | (id->get_index() << 8)
);
break;
default:
gs.code.push_back(
BC_INST_LOOKUP |
ret_code(ltype, BC_RET_STRING) |
(id->get_index() << 8)
);
break;
}
goto done;
case ident_type::COMMAND: {
std::uint32_t comtype = BC_INST_COM, numargs = 0;
auto fmt = static_cast<command_impl *>(id)->get_args();
for (char c: fmt) {
switch (c) {
case 's':
gs.gen_str(std::string_view{});
numargs++;
break;
case 'i':
gs.gen_int();
numargs++;
break;
case 'b':
gs.gen_int(std::numeric_limits<integer_type>::min());
numargs++;
break;
case 'f':
gs.gen_float();
numargs++;
break;
case 'F':
gs.code.push_back(BC_INST_DUP | BC_RET_FLOAT);
numargs++;
break;
case 'E':
case 't':
gs.gen_null();
numargs++;
break;
case 'e':
compileblock(gs);
numargs++;
break;
case 'r':
gs.gen_ident();
numargs++;
break;
case '$':
gs.gen_ident(id);
numargs++;
break;
case 'N':
gs.gen_int(-1);
numargs++;
break;
case 'C':
comtype = BC_INST_COM_C;
goto compilecomv;
case 'V':
comtype = BC_INST_COM_V;
goto compilecomv;
case '1':
case '2':
case '3':
case '4':
break;
}
}
gs.code.push_back(
comtype | ret_code(ltype) | (id->get_index() << 8)
);
gs.code.push_back(
BC_INST_RESULT_ARG | ret_code(ltype)
);
goto done;
compilecomv:
gs.code.push_back(
comtype | ret_code(ltype) | (id->get_index() << 8)
);
gs.code.push_back(numargs);
gs.code.push_back(
BC_INST_RESULT_ARG | ret_code(ltype)
);
goto done;
switch (id.get_type()) {
case ident_type::IVAR:
gs.code.push_back(
BC_INST_IVAR | ret_code(ltype, BC_RET_INT) |
(id.get_index() << 8)
);
switch (ltype) {
case VAL_POP:
gs.code.pop_back();
break;
case VAL_CODE:
gs.code.push_back(BC_INST_COMPILE);
break;
case VAL_IDENT:
gs.code.push_back(BC_INST_IDENT_U);
break;
}
default:
goto invalid;
return;
case ident_type::FVAR:
gs.code.push_back(
BC_INST_FVAR | ret_code(ltype, BC_RET_FLOAT) |
(id.get_index() << 8)
);
switch (ltype) {
case VAL_POP:
gs.code.pop_back();
break;
case VAL_CODE:
gs.code.push_back(BC_INST_COMPILE);
break;
case VAL_IDENT:
gs.code.push_back(BC_INST_IDENT_U);
break;
}
return;
case ident_type::SVAR:
switch (ltype) {
case VAL_POP:
return;
default:
gs.code.push_back(
BC_INST_SVAR | ret_code(ltype, BC_RET_STRING) |
(id.get_index() << 8)
);
break;
}
goto done;
case ident_type::ALIAS:
switch (ltype) {
case VAL_POP:
return;
case VAL_COND:
gs.code.push_back(
BC_INST_LOOKUP | (id.get_index() << 8)
);
break;
default:
gs.code.push_back(
BC_INST_LOOKUP |
ret_code(ltype, BC_RET_STRING) |
(id.get_index() << 8)
);
break;
}
goto done;
case ident_type::COMMAND: {
std::uint32_t comtype = BC_INST_COM, numargs = 0;
auto fmt = static_cast<command_impl &>(id).get_args();
for (char c: fmt) {
switch (c) {
case 's':
gs.gen_str(std::string_view{});
numargs++;
break;
case 'i':
gs.gen_int();
numargs++;
break;
case 'b':
gs.gen_int(std::numeric_limits<integer_type>::min());
numargs++;
break;
case 'f':
gs.gen_float();
numargs++;
break;
case 'F':
gs.code.push_back(BC_INST_DUP | BC_RET_FLOAT);
numargs++;
break;
case 'E':
case 't':
gs.gen_null();
numargs++;
break;
case 'e':
compileblock(gs);
numargs++;
break;
case 'r':
gs.gen_ident();
numargs++;
break;
case '$':
gs.gen_ident(id);
numargs++;
break;
case 'N':
gs.gen_int(-1);
numargs++;
break;
case 'C':
comtype = BC_INST_COM_C;
goto compilecomv;
case 'V':
comtype = BC_INST_COM_V;
goto compilecomv;
case '1':
case '2':
case '3':
case '4':
break;
}
}
gs.code.push_back(
comtype | ret_code(ltype) | (id.get_index() << 8)
);
gs.code.push_back(
BC_INST_RESULT_ARG | ret_code(ltype)
);
goto done;
compilecomv:
gs.code.push_back(
comtype | ret_code(ltype) | (id.get_index() << 8)
);
gs.code.push_back(numargs);
gs.code.push_back(
BC_INST_RESULT_ARG | ret_code(ltype)
);
goto done;
}
default:
goto invalid;
}
gs.gen_str(lookup.str_term());
break;
@ -512,28 +510,26 @@ static bool compileblocksub(codegen_state &gs) {
}
lookup.push_back('\0');
lookupid:
ident *id = gs.ts.istate->new_ident(
ident &id = gs.ts.istate->new_ident(
*gs.ts.pstate, lookup.str_term(), IDENT_FLAG_UNKNOWN
);
if (id) {
switch (id->get_type()) {
case ident_type::IVAR:
gs.code.push_back(BC_INST_IVAR | (id->get_index() << 8));
goto done;
case ident_type::FVAR:
gs.code.push_back(BC_INST_FVAR | (id->get_index() << 8));
goto done;
case ident_type::SVAR:
gs.code.push_back(BC_INST_SVAR | (id->get_index() << 8));
goto done;
case ident_type::ALIAS:
gs.code.push_back(
BC_INST_LOOKUP | (id->get_index() << 8)
);
goto done;
default:
break;
}
switch (id.get_type()) {
case ident_type::IVAR:
gs.code.push_back(BC_INST_IVAR | (id.get_index() << 8));
goto done;
case ident_type::FVAR:
gs.code.push_back(BC_INST_FVAR | (id.get_index() << 8));
goto done;
case ident_type::SVAR:
gs.code.push_back(BC_INST_SVAR | (id.get_index() << 8));
goto done;
case ident_type::ALIAS:
gs.code.push_back(
BC_INST_LOOKUP | (id.get_index() << 8)
);
goto done;
default:
break;
}
gs.gen_str(lookup.str_term());
gs.code.push_back(BC_INST_LOOKUP_U);
@ -800,7 +796,7 @@ static bool compilearg(
}
static void compile_cmd(
codegen_state &gs, command_impl *id, ident *self, bool &more, int rettype,
codegen_state &gs, command_impl *id, ident &self, bool &more, int rettype,
std::uint32_t limit = 0
) {
std::uint32_t comtype = BC_INST_COM, numargs = 0, numcargs = 0, fakeargs = 0;
@ -1189,47 +1185,45 @@ static void compilestatements(codegen_state &gs, int rettype, int brak) {
gs.next_char();
if (!idname.empty()) {
idname.push_back('\0');
ident *id = gs.ts.istate->new_ident(
ident &id = gs.ts.istate->new_ident(
*gs.ts.pstate, idname.str_term(), IDENT_FLAG_UNKNOWN
);
if (id) {
switch (id->get_type()) {
case ident_type::ALIAS:
more = compilearg(gs, VAL_ANY);
if (!more) {
gs.gen_str();
}
gs.code.push_back(
BC_INST_ALIAS | (id->get_index() << 8)
);
goto endstatement;
case ident_type::IVAR: {
auto *hid = gs.ts.istate->cmd_ivar;
compile_cmd(
gs, static_cast<command_impl *>(hid),
id, more, rettype, 1
);
goto endstatement;
switch (id.get_type()) {
case ident_type::ALIAS:
more = compilearg(gs, VAL_ANY);
if (!more) {
gs.gen_str();
}
case ident_type::FVAR: {
auto *hid = gs.ts.istate->cmd_fvar;
compile_cmd(
gs, static_cast<command_impl *>(hid),
id, more, rettype, 1
);
goto endstatement;
}
case ident_type::SVAR: {
auto *hid = gs.ts.istate->cmd_svar;
compile_cmd(
gs, static_cast<command_impl *>(hid),
id, more, rettype, 1
);
goto endstatement;
}
default:
break;
gs.code.push_back(
BC_INST_ALIAS | (id.get_index() << 8)
);
goto endstatement;
case ident_type::IVAR: {
auto *hid = gs.ts.istate->cmd_ivar;
compile_cmd(
gs, static_cast<command_impl *>(hid),
id, more, rettype, 1
);
goto endstatement;
}
case ident_type::FVAR: {
auto *hid = gs.ts.istate->cmd_fvar;
compile_cmd(
gs, static_cast<command_impl *>(hid),
id, more, rettype, 1
);
goto endstatement;
}
case ident_type::SVAR: {
auto *hid = gs.ts.istate->cmd_svar;
compile_cmd(
gs, static_cast<command_impl *>(hid),
id, more, rettype, 1
);
goto endstatement;
}
default:
break;
}
gs.gen_str(idname.str_term());
}
@ -1285,7 +1279,7 @@ noid:
break;
case ID_COMMAND:
compile_cmd(
gs, static_cast<command_impl *>(id), id, more,
gs, static_cast<command_impl *>(id), *id, more,
rettype
);
break;
@ -1332,7 +1326,7 @@ noid:
auto *hid = gs.ts.istate->cmd_ivar;
compile_cmd(
gs, static_cast<command_impl *>(hid),
id, more, rettype
*id, more, rettype
);
break;
}
@ -1340,7 +1334,7 @@ noid:
auto *hid = gs.ts.istate->cmd_fvar;
compile_cmd(
gs, static_cast<command_impl *>(hid),
id, more, rettype
*id, more, rettype
);
break;
}
@ -1348,7 +1342,7 @@ noid:
auto *hid = gs.ts.istate->cmd_svar;
compile_cmd(
gs, static_cast<command_impl *>(hid),
id, more, rettype
*id, more, rettype
);
break;
}

View File

@ -103,12 +103,12 @@ struct codegen_state {
void gen_float(std::string_view word);
void gen_ident(ident *id) {
code.push_back(BC_INST_IDENT | (id->get_index() << 8));
void gen_ident(ident &id) {
code.push_back(BC_INST_IDENT | (id.get_index() << 8));
}
void gen_ident() {
gen_ident(ts.istate->id_dummy);
gen_ident(*ts.istate->id_dummy);
}
void gen_ident(std::string_view word) {

View File

@ -55,7 +55,7 @@ ident *internal_state::add_ident(ident *id, ident_impl *impl) {
return identmap.back();
}
ident *internal_state::new_ident(state &cs, std::string_view name, int flags) {
ident &internal_state::new_ident(state &cs, std::string_view name, int flags) {
ident *id = get_ident(name);
if (!id) {
if (!is_valid_name(name)) {
@ -68,7 +68,7 @@ ident *internal_state::new_ident(state &cs, std::string_view name, int flags) {
);
id = add_ident(inst, inst);
}
return id;
return *id;
}
ident *internal_state::get_ident(std::string_view name) const {
@ -120,10 +120,10 @@ state::state(alloc_func func, void *data) {
);
}
statep->id_dummy = statep->new_ident(*this, "//dummy", IDENT_FLAG_UNKNOWN);
statep->id_dummy = &statep->new_ident(*this, "//dummy", IDENT_FLAG_UNKNOWN);
statep->ivar_numargs = new_ivar("numargs", 0, true);
statep->ivar_dbgalias = new_ivar("dbgalias", 4);
statep->ivar_numargs = &new_ivar("numargs", 0, true);
statep->ivar_dbgalias = &new_ivar("dbgalias", 4);
/* default handlers for variables */
@ -415,7 +415,7 @@ static void var_name_check(
}
}
LIBCUBESCRIPT_EXPORT integer_var *state::new_ivar(
LIBCUBESCRIPT_EXPORT integer_var &state::new_ivar(
std::string_view n, integer_type v, bool read_only, var_type vtp
) {
auto *iv = p_tstate->istate->create<ivar_impl>(
@ -429,10 +429,10 @@ LIBCUBESCRIPT_EXPORT integer_var *state::new_ivar(
throw;
}
p_tstate->istate->add_ident(iv, iv);
return iv;
return *iv;
}
LIBCUBESCRIPT_EXPORT float_var *state::new_fvar(
LIBCUBESCRIPT_EXPORT float_var &state::new_fvar(
std::string_view n, float_type v, bool read_only, var_type vtp
) {
auto *fv = p_tstate->istate->create<fvar_impl>(
@ -446,10 +446,10 @@ LIBCUBESCRIPT_EXPORT float_var *state::new_fvar(
throw;
}
p_tstate->istate->add_ident(fv, fv);
return fv;
return *fv;
}
LIBCUBESCRIPT_EXPORT string_var *state::new_svar(
LIBCUBESCRIPT_EXPORT string_var &state::new_svar(
std::string_view n, std::string_view v, bool read_only, var_type vtp
) {
auto *sv = p_tstate->istate->create<svar_impl>(
@ -463,10 +463,10 @@ LIBCUBESCRIPT_EXPORT string_var *state::new_svar(
throw;
}
p_tstate->istate->add_ident(sv, sv);
return sv;
return *sv;
}
LIBCUBESCRIPT_EXPORT ident *state::new_ident(std::string_view n) {
LIBCUBESCRIPT_EXPORT ident &state::new_ident(std::string_view n) {
return p_tstate->istate->new_ident(*this, n, IDENT_FLAG_UNKNOWN);
}

View File

@ -69,7 +69,7 @@ struct internal_state {
~internal_state();
ident *add_ident(ident *id, ident_impl *impl);
ident *new_ident(state &cs, std::string_view name, int flags);
ident &new_ident(state &cs, std::string_view name, int flags);
ident *get_ident(std::string_view name) const;
void *alloc(void *ptr, size_t os, size_t ns);

View File

@ -269,17 +269,17 @@ bcode_ref any_value::force_code(state &cs) {
return bcode_ref{bc};
}
ident *any_value::force_ident(state &cs) {
ident &any_value::force_ident(state &cs) {
switch (get_type()) {
case value_type::IDENT:
return csv_get<ident *>(&p_stor);
return *csv_get<ident *>(&p_stor);
default:
break;
}
auto *id = state_p{cs}.ts().istate->new_ident(
auto &id = state_p{cs}.ts().istate->new_ident(
cs, get_str(), IDENT_FLAG_UNKNOWN
);
set_ident(id);
set_ident(&id);
return id;
}

View File

@ -768,7 +768,7 @@ std::uint32_t *vm_exec(
any_value &arg = args.back();
ident *id = ts.istate->id_dummy;
if (arg.get_type() == value_type::STRING) {
id = ts.istate->new_ident(
id = &ts.istate->new_ident(
cs, arg.get_str(), IDENT_FLAG_UNKNOWN
);
}
@ -1121,7 +1121,7 @@ noid:
std::size_t idstsz = ts.idstack.size();
for (size_t j = 0; j < size_t(callargs); ++j) {
push_alias(
ts, args[offset + j].force_ident(cs),
ts, &args[offset + j].force_ident(cs),
ts.idstack.emplace_back(*ts.pstate)
);
}

View File

@ -7,10 +7,10 @@
inline void init_lineedit(cs::state &, std::string_view) {
}
inline std::optional<std::string> read_line(cs::state &, cs::string_var *pr) {
inline std::optional<std::string> read_line(cs::state &, cs::string_var &pr) {
std::string lbuf;
char buf[512];
printf("%s", pr->get_value().data());
printf("%s", pr.get_value().data());
std::fflush(stdout);
while (fgets(buf, sizeof(buf), stdin)) {
lbuf += static_cast<char const *>(buf);

View File

@ -50,9 +50,9 @@ inline void init_lineedit(cs::state &cs, std::string_view) {
linenoise::SetHintsCallback(ln_hint);
}
inline std::optional<std::string> read_line(cs::state &, cs::string_var *pr) {
inline std::optional<std::string> read_line(cs::state &, cs::string_var &pr) {
std::string line;
auto quit = linenoise::Readline(pr->get_value().data(), line);
auto quit = linenoise::Readline(pr.get_value().data(), line);
if (quit) {
/* linenoise traps ctrl-c, detect it and let the user exit */
if (errno == EAGAIN) {

View File

@ -65,8 +65,8 @@ inline void init_lineedit(cs::state &cs, std::string_view) {
rl_redisplay_function = ln_hint;
}
inline std::optional<std::string> read_line(cs::state &, cs::string_var *pr) {
auto line = readline(pr->get_value().data());
inline std::optional<std::string> read_line(cs::state &, cs::string_var &pr) {
auto line = readline(pr.get_value().data());
if (!line) {
return std::string();
}

View File

@ -277,8 +277,8 @@ static bool do_call(cs::state &cs, std::string_view line, bool file = false) {
}
static void do_tty(cs::state &cs) {
auto prompt = cs.new_svar("PROMPT", "> ");
auto prompt2 = cs.new_svar("PROMPT2", ">> ");
auto &prompt = cs.new_svar("PROMPT", "> ");
auto &prompt2 = cs.new_svar("PROMPT2", ">> ");
bool do_exit = false;
cs.new_command("quit", "", [&do_exit](auto &, auto, auto &) {