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 "callable.hh"
#include "ident.hh" #include "ident.hh"
#include "value.hh"
namespace cubescript { namespace cubescript {
struct state;
using alloc_func = void *(*)(void *, void *, size_t, size_t); using alloc_func = void *(*)(void *, void *, size_t, size_t);
using hook_func = internal::callable<void, struct state &>; using hook_func = internal::callable<void, struct state &>;
using command_func = internal::callable< 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 { enum {
@ -68,19 +71,19 @@ struct LIBCUBESCRIPT_EXPORT state {
void clear_override(ident &id); void clear_override(ident &id);
void clear_overrides(); void clear_overrides();
integer_var *new_ivar( integer_var &new_ivar(
std::string_view n, integer_type v, bool read_only = false, std::string_view n, integer_type v, bool read_only = false,
var_type vtp = var_type::DEFAULT 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, std::string_view n, float_type v, bool read_only = false,
var_type vtp = var_type::DEFAULT 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, std::string_view n, std::string_view v, bool read_only = false,
var_type vtp = var_type::DEFAULT 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 reset_var(std::string_view name);
void touch_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(); integer_type force_int();
std::string_view force_str(); std::string_view force_str();
bcode_ref force_code(state &cs); bcode_ref force_code(state &cs);
ident *force_ident(state &cs); ident &force_ident(state &cs);
private: private:
template<typename T> template<typename T>

View File

@ -238,154 +238,152 @@ static void compilelookup(codegen_state &gs, int ltype) {
if (lookup.empty()) goto invalid; if (lookup.empty()) goto invalid;
lookup.push_back('\0'); lookup.push_back('\0');
lookupid: lookupid:
ident *id = gs.ts.istate->new_ident( ident &id = gs.ts.istate->new_ident(
*gs.ts.pstate, lookup.str_term(), IDENT_FLAG_UNKNOWN *gs.ts.pstate, lookup.str_term(), IDENT_FLAG_UNKNOWN
); );
if (id) { switch (id.get_type()) {
switch (id->get_type()) { case ident_type::IVAR:
case ident_type::IVAR: gs.code.push_back(
gs.code.push_back( BC_INST_IVAR | ret_code(ltype, BC_RET_INT) |
BC_INST_IVAR | ret_code(ltype, BC_RET_INT) | (id.get_index() << 8)
(id->get_index() << 8) );
); switch (ltype) {
switch (ltype) { case VAL_POP:
case VAL_POP: gs.code.pop_back();
gs.code.pop_back(); break;
break; case VAL_CODE:
case VAL_CODE: gs.code.push_back(BC_INST_COMPILE);
gs.code.push_back(BC_INST_COMPILE); break;
break; case VAL_IDENT:
case VAL_IDENT: gs.code.push_back(BC_INST_IDENT_U);
gs.code.push_back(BC_INST_IDENT_U); break;
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;
} }
default: return;
goto invalid; 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()); gs.gen_str(lookup.str_term());
break; break;
@ -512,28 +510,26 @@ static bool compileblocksub(codegen_state &gs) {
} }
lookup.push_back('\0'); lookup.push_back('\0');
lookupid: lookupid:
ident *id = gs.ts.istate->new_ident( ident &id = gs.ts.istate->new_ident(
*gs.ts.pstate, lookup.str_term(), IDENT_FLAG_UNKNOWN *gs.ts.pstate, lookup.str_term(), IDENT_FLAG_UNKNOWN
); );
if (id) { switch (id.get_type()) {
switch (id->get_type()) { case ident_type::IVAR:
case ident_type::IVAR: gs.code.push_back(BC_INST_IVAR | (id.get_index() << 8));
gs.code.push_back(BC_INST_IVAR | (id->get_index() << 8)); goto done;
goto done; case ident_type::FVAR:
case ident_type::FVAR: gs.code.push_back(BC_INST_FVAR | (id.get_index() << 8));
gs.code.push_back(BC_INST_FVAR | (id->get_index() << 8)); goto done;
goto done; case ident_type::SVAR:
case ident_type::SVAR: gs.code.push_back(BC_INST_SVAR | (id.get_index() << 8));
gs.code.push_back(BC_INST_SVAR | (id->get_index() << 8)); goto done;
goto done; case ident_type::ALIAS:
case ident_type::ALIAS: gs.code.push_back(
gs.code.push_back( BC_INST_LOOKUP | (id.get_index() << 8)
BC_INST_LOOKUP | (id->get_index() << 8) );
); goto done;
goto done; default:
default: break;
break;
}
} }
gs.gen_str(lookup.str_term()); gs.gen_str(lookup.str_term());
gs.code.push_back(BC_INST_LOOKUP_U); gs.code.push_back(BC_INST_LOOKUP_U);
@ -800,7 +796,7 @@ static bool compilearg(
} }
static void compile_cmd( 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 limit = 0
) { ) {
std::uint32_t comtype = BC_INST_COM, numargs = 0, numcargs = 0, fakeargs = 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(); gs.next_char();
if (!idname.empty()) { if (!idname.empty()) {
idname.push_back('\0'); 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 *gs.ts.pstate, idname.str_term(), IDENT_FLAG_UNKNOWN
); );
if (id) { switch (id.get_type()) {
switch (id->get_type()) { case ident_type::ALIAS:
case ident_type::ALIAS: more = compilearg(gs, VAL_ANY);
more = compilearg(gs, VAL_ANY); if (!more) {
if (!more) { gs.gen_str();
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;
} }
case ident_type::FVAR: { gs.code.push_back(
auto *hid = gs.ts.istate->cmd_fvar; BC_INST_ALIAS | (id.get_index() << 8)
compile_cmd( );
gs, static_cast<command_impl *>(hid), goto endstatement;
id, more, rettype, 1 case ident_type::IVAR: {
); auto *hid = gs.ts.istate->cmd_ivar;
goto endstatement; compile_cmd(
} gs, static_cast<command_impl *>(hid),
case ident_type::SVAR: { id, more, rettype, 1
auto *hid = gs.ts.istate->cmd_svar; );
compile_cmd( goto endstatement;
gs, static_cast<command_impl *>(hid),
id, more, rettype, 1
);
goto endstatement;
}
default:
break;
} }
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()); gs.gen_str(idname.str_term());
} }
@ -1285,7 +1279,7 @@ noid:
break; break;
case ID_COMMAND: case ID_COMMAND:
compile_cmd( compile_cmd(
gs, static_cast<command_impl *>(id), id, more, gs, static_cast<command_impl *>(id), *id, more,
rettype rettype
); );
break; break;
@ -1332,7 +1326,7 @@ noid:
auto *hid = gs.ts.istate->cmd_ivar; auto *hid = gs.ts.istate->cmd_ivar;
compile_cmd( compile_cmd(
gs, static_cast<command_impl *>(hid), gs, static_cast<command_impl *>(hid),
id, more, rettype *id, more, rettype
); );
break; break;
} }
@ -1340,7 +1334,7 @@ noid:
auto *hid = gs.ts.istate->cmd_fvar; auto *hid = gs.ts.istate->cmd_fvar;
compile_cmd( compile_cmd(
gs, static_cast<command_impl *>(hid), gs, static_cast<command_impl *>(hid),
id, more, rettype *id, more, rettype
); );
break; break;
} }
@ -1348,7 +1342,7 @@ noid:
auto *hid = gs.ts.istate->cmd_svar; auto *hid = gs.ts.istate->cmd_svar;
compile_cmd( compile_cmd(
gs, static_cast<command_impl *>(hid), gs, static_cast<command_impl *>(hid),
id, more, rettype *id, more, rettype
); );
break; break;
} }

View File

@ -103,12 +103,12 @@ struct codegen_state {
void gen_float(std::string_view word); void gen_float(std::string_view word);
void gen_ident(ident *id) { void gen_ident(ident &id) {
code.push_back(BC_INST_IDENT | (id->get_index() << 8)); code.push_back(BC_INST_IDENT | (id.get_index() << 8));
} }
void gen_ident() { void gen_ident() {
gen_ident(ts.istate->id_dummy); gen_ident(*ts.istate->id_dummy);
} }
void gen_ident(std::string_view word) { 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(); 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); ident *id = get_ident(name);
if (!id) { if (!id) {
if (!is_valid_name(name)) { 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); id = add_ident(inst, inst);
} }
return id; return *id;
} }
ident *internal_state::get_ident(std::string_view name) const { 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_numargs = &new_ivar("numargs", 0, true);
statep->ivar_dbgalias = new_ivar("dbgalias", 4); statep->ivar_dbgalias = &new_ivar("dbgalias", 4);
/* default handlers for variables */ /* 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 std::string_view n, integer_type v, bool read_only, var_type vtp
) { ) {
auto *iv = p_tstate->istate->create<ivar_impl>( auto *iv = p_tstate->istate->create<ivar_impl>(
@ -429,10 +429,10 @@ LIBCUBESCRIPT_EXPORT integer_var *state::new_ivar(
throw; throw;
} }
p_tstate->istate->add_ident(iv, iv); 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 std::string_view n, float_type v, bool read_only, var_type vtp
) { ) {
auto *fv = p_tstate->istate->create<fvar_impl>( auto *fv = p_tstate->istate->create<fvar_impl>(
@ -446,10 +446,10 @@ LIBCUBESCRIPT_EXPORT float_var *state::new_fvar(
throw; throw;
} }
p_tstate->istate->add_ident(fv, fv); 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 std::string_view n, std::string_view v, bool read_only, var_type vtp
) { ) {
auto *sv = p_tstate->istate->create<svar_impl>( auto *sv = p_tstate->istate->create<svar_impl>(
@ -463,10 +463,10 @@ LIBCUBESCRIPT_EXPORT string_var *state::new_svar(
throw; throw;
} }
p_tstate->istate->add_ident(sv, sv); 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); return p_tstate->istate->new_ident(*this, n, IDENT_FLAG_UNKNOWN);
} }

View File

@ -69,7 +69,7 @@ struct internal_state {
~internal_state(); ~internal_state();
ident *add_ident(ident *id, ident_impl *impl); 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; ident *get_ident(std::string_view name) const;
void *alloc(void *ptr, size_t os, size_t ns); 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}; return bcode_ref{bc};
} }
ident *any_value::force_ident(state &cs) { ident &any_value::force_ident(state &cs) {
switch (get_type()) { switch (get_type()) {
case value_type::IDENT: case value_type::IDENT:
return csv_get<ident *>(&p_stor); return *csv_get<ident *>(&p_stor);
default: default:
break; 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 cs, get_str(), IDENT_FLAG_UNKNOWN
); );
set_ident(id); set_ident(&id);
return id; return id;
} }

View File

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

View File

@ -7,10 +7,10 @@
inline void init_lineedit(cs::state &, std::string_view) { 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; std::string lbuf;
char buf[512]; char buf[512];
printf("%s", pr->get_value().data()); printf("%s", pr.get_value().data());
std::fflush(stdout); std::fflush(stdout);
while (fgets(buf, sizeof(buf), stdin)) { while (fgets(buf, sizeof(buf), stdin)) {
lbuf += static_cast<char const *>(buf); 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); 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; std::string line;
auto quit = linenoise::Readline(pr->get_value().data(), line); auto quit = linenoise::Readline(pr.get_value().data(), line);
if (quit) { if (quit) {
/* linenoise traps ctrl-c, detect it and let the user exit */ /* linenoise traps ctrl-c, detect it and let the user exit */
if (errno == EAGAIN) { if (errno == EAGAIN) {

View File

@ -65,8 +65,8 @@ inline void init_lineedit(cs::state &cs, std::string_view) {
rl_redisplay_function = ln_hint; rl_redisplay_function = 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) {
auto line = readline(pr->get_value().data()); auto line = readline(pr.get_value().data());
if (!line) { if (!line) {
return std::string(); 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) { static void do_tty(cs::state &cs) {
auto prompt = cs.new_svar("PROMPT", "> "); auto &prompt = cs.new_svar("PROMPT", "> ");
auto prompt2 = cs.new_svar("PROMPT2", ">> "); auto &prompt2 = cs.new_svar("PROMPT2", ">> ");
bool do_exit = false; bool do_exit = false;
cs.new_command("quit", "", [&do_exit](auto &, auto, auto &) { cs.new_command("quit", "", [&do_exit](auto &, auto, auto &) {