drop cubescript.cc, move parsing stuff from cs_std to cs_parser

master
Daniel Kolesa 2021-03-23 22:17:25 +01:00
parent 7139370990
commit b3b4624af1
12 changed files with 503 additions and 495 deletions

View File

@ -1,6 +1,7 @@
#include <cubescript/cubescript.hh>
#include "cs_vm.hh"
#include "cs_std.hh"
#include "cs_parser.hh"
#include <ctype.h>
@ -1310,7 +1311,7 @@ noid:
idname.push_back('\0');
cs_ident *id = gs.cs.get_ident(idname.str_term());
if (!id) {
if (!cs_check_num(idname.str_term())) {
if (is_valid_name(idname.str_term())) {
gs.gen_str(idname.str_term());
goto noid;
}

View File

@ -1,5 +1,8 @@
#include <cubescript/cubescript.hh>
#include <cmath>
#include <cctype>
#include "cs_std.hh"
namespace cscript {
@ -51,10 +54,10 @@ LIBCUBESCRIPT_EXPORT char const *cs_parse_string(
end:
nlines = nl;
if ((beg == end) || (*beg != '\"')) {
throw cs_error(
throw cs_error{
cs, "unfinished string '%s'",
std::string_view{orig, std::size_t(beg - orig)}
);
};
}
return ++beg;
}
@ -89,7 +92,7 @@ LIBCUBESCRIPT_EXPORT char const *cs_parse_word(
it, std::size_t(end - it)
});
if ((it == end) || (*it != ']')) {
throw cs_error(cs, "missing \"]\"");
throw cs_error{cs, "missing \"]\""};
}
break;
case '(':
@ -98,7 +101,7 @@ LIBCUBESCRIPT_EXPORT char const *cs_parse_word(
it, std::size_t(end - it)
});
if ((it == end) || (*it != ')')) {
throw cs_error(cs, "missing \")\"");
throw cs_error{cs, "missing \")\""};
}
break;
case ']':
@ -109,6 +112,199 @@ LIBCUBESCRIPT_EXPORT char const *cs_parse_word(
return it;
}
static inline char const *p_skip_white(char const *beg, char const *end) {
while ((beg != end) && isspace(*beg)) {
++beg;
}
return beg;
}
static inline void p_set_end(
char const *nbeg, char const *nend, std::string_view *end
) {
if (!end) {
return;
}
*end = std::string_view{nbeg, nend};
}
/* this function assumes the input is definitely a hex digit */
static inline cs_int p_hexd_to_int(char c) {
if (c >= 97) { /* a-f */
return (c - 'a') + 10;
} else if (c >= 65) { /* A-F */
return (c - 'A') + 10;
}
/* 0-9 */
return c - '0';
}
static inline bool p_check_neg(char const *&input) {
bool neg = (*input == '-');
if (neg || (*input == '+')) {
++input;
}
return neg;
}
cs_int parse_int(std::string_view input, std::string_view *endstr) {
char const *beg = input.begin();
char const *end = input.end();
char const *orig = beg;
beg = p_skip_white(beg, end);
if (beg == end) {
p_set_end(orig, end, endstr);
return cs_int(0);
}
bool neg = p_check_neg(beg);
cs_int ret = 0;
char const *past = beg;
if ((end - beg) >= 2) {
std::string_view pfx = std::string_view{beg, 2};
if ((pfx == "0x") || (pfx == "0X")) {
beg += 2;
past = beg;
while ((past != end) && std::isxdigit(*past)) {
ret = ret * 16 + p_hexd_to_int(*past++);
}
goto done;
} else if ((pfx == "0b") || (pfx == "0B")) {
beg += 2;
past = beg;
while ((past != end) && ((*past == '0') || (*past == '1'))) {
ret = ret * 2 + (*past++ - '0');
}
goto done;
}
}
while ((past != end) && std::isdigit(*past)) {
ret = ret * 10 + (*past++ - '0');
}
done:
p_set_end((past == beg) ? orig : past, end, endstr);
if (neg) {
return -ret;
}
return ret;
}
template<bool Hex, char e1 = Hex ? 'p' : 'e', char e2 = Hex ? 'P' : 'E'>
static inline bool p_read_exp(char const *&beg, char const *end, cs_int &fn) {
if (beg == end) {
return true;
}
if ((*beg != e1) && (*beg != e2)) {
return true;
}
if (++beg == end) {
return false;
}
bool neg = p_check_neg(beg);
if ((beg == end) || !std::isdigit(*beg)) {
return false;
}
cs_int exp = 0;
while ((beg != end) && std::isdigit(*beg)) {
exp = exp * 10 + (*beg++ - '0');
}
if (neg) {
exp = -exp;
}
fn += exp;
return true;
}
template<bool Hex>
static inline bool parse_gen_float(
char const *&beg, char const *end, std::string_view *endstr, cs_float &ret
) {
auto read_digits = [&beg, end](double r, cs_int &n) {
while (
(beg != end) &&
(Hex ? std::isxdigit(*beg) : std::isdigit(*beg))
) {
if (Hex) {
r = r * 16.0 + double(p_hexd_to_int(*beg));
} else {
r = r * 10.0 + double(*beg - '0');
}
++n;
++beg;
}
return r;
};
cs_int wn = 0, fn = 0;
double r = read_digits(0.0, wn);
if ((beg != end) && (*beg == '.')) {
++beg;
r = read_digits(r, fn);
}
if (!wn && !fn) {
return false;
}
fn = -fn;
p_set_end(beg, end, endstr); /* we have a valid number until here */
if (p_read_exp<Hex>(beg, end, fn)) {
p_set_end(beg, end, endstr);
}
if (Hex) {
ret = cs_float(ldexp(r, fn * 4));
} else {
ret = cs_float(r * pow(10, fn));
}
return true;
}
cs_float parse_float(std::string_view input, std::string_view *endstr) {
char const *beg = input.begin();
char const *end = input.end();
char const *orig = beg;
beg = p_skip_white(beg, end);
if (beg == end) {
p_set_end(orig, end, endstr);
return cs_float(0);
}
bool neg = p_check_neg(beg);
cs_float ret = cs_float(0);
if ((end - beg) >= 2) {
std::string_view pfx = std::string_view{beg, 2};
if ((pfx == "0x") || (pfx == "0X")) {
beg += 2;
if (!parse_gen_float<true>(beg, end, endstr, ret)) {
p_set_end(orig, end, endstr);
return ret;
}
goto done;
}
}
if (!parse_gen_float<false>(beg, end, endstr, ret)) {
p_set_end(orig, end, endstr);
return ret;
}
done:
if (neg) {
return -ret;
}
return ret;
}
bool is_valid_name(std::string_view s) {
/* names cannot start with numbers (clashes with numeric literals) */
if (std::isdigit(s[0])) {
return false;
}
switch (s[0]) {
/* more numeric literal clashes */
case '+':
case '-':
return std::isdigit(s[1]) || ((s[1] == '.') && std::isdigit(s[2]));
case '.':
return std::isdigit(s[1]) != 0;
/* other than that a name can be mostly anything */
default:
return true;
}
}
/* list parser public implementation */
LIBCUBESCRIPT_EXPORT bool cs_list_parser::parse() {

17
src/cs_parser.hh 100644
View File

@ -0,0 +1,17 @@
#ifndef LIBCUBESCRIPT_PARSER_HH
#define LIBCUBESCRIPT_PARSER_HH
#include <cubescript/cubescript.hh>
#include <string_view>
namespace cscript {
cs_int parse_int(std::string_view input, std::string_view *end = nullptr);
cs_float parse_float(std::string_view input, std::string_view *end = nullptr);
bool is_valid_name(std::string_view input);
} /* namespace cscript */
#endif

View File

@ -4,6 +4,7 @@
#include "cs_state.hh"
#include "cs_strman.hh"
#include "cs_vm.hh" // FIXME, only Max Arguments
#include "cs_parser.hh"
namespace cscript {
@ -156,18 +157,18 @@ cs_state::cs_state(cs_alloc_cb func, void *data):
p = new_command("break", "", [](auto &cs, auto, auto &) {
if (cs.is_in_loop()) {
throw CsBreakException();
throw CsBreakException{};
} else {
throw cs_error(cs, "no loop to break");
throw cs_error{cs, "no loop to break"};
}
});
static_cast<cs_command_impl *>(p)->p_type = ID_BREAK;
p = new_command("continue", "", [](auto &cs, auto, auto &) {
if (cs.is_in_loop()) {
throw CsContinueException();
throw CsContinueException{};
} else {
throw cs_error(cs, "no loop to continue");
throw cs_error{cs, "no loop to continue"};
}
});
static_cast<cs_command_impl *>(p)->p_type = ID_CONTINUE;
@ -230,10 +231,283 @@ LIBCUBESCRIPT_EXPORT cs_vprint_cb const &cs_state::get_var_printer() const {
return p_state->varprintf;
}
LIBCUBESCRIPT_EXPORT void cs_state::print_var(cs_var const &v) const {
if (p_state->varprintf) {
p_state->varprintf(*this, v);
}
}
LIBCUBESCRIPT_EXPORT void *cs_state::alloc(void *ptr, size_t os, size_t ns) {
return p_state->alloc(ptr, os, ns);
}
LIBCUBESCRIPT_EXPORT cs_ident *cs_state::add_ident(
cs_ident *id, cs_ident_impl *impl
) {
if (!id) {
return nullptr;
}
id->p_impl = impl;
p_state->idents[id->get_name()] = id;
static_cast<cs_ident_impl *>(impl)->p_index = p_state->identmap.size();
p_state->identmap.push_back(id);
return p_state->identmap.back();
}
LIBCUBESCRIPT_EXPORT cs_ident *cs_state::new_ident(
std::string_view name, int flags
) {
cs_ident *id = get_ident(name);
if (!id) {
if (!is_valid_name(name)) {
throw cs_error{
*this, "number %s is not a valid identifier name", name.data()
};
}
auto *inst = p_state->create<cs_alias_impl>(
*this, cs_strref{p_state, name}, flags
);
id = add_ident(inst, inst);
}
return id;
}
LIBCUBESCRIPT_EXPORT cs_ident *cs_state::force_ident(cs_value &v) {
switch (v.get_type()) {
case cs_value_type::IDENT:
return v.get_ident();
case cs_value_type::STRING: {
cs_ident *id = new_ident(v.get_str());
v.set_ident(id);
return id;
}
default:
break;
}
v.set_ident(p_state->identmap[DummyIdx]);
return p_state->identmap[DummyIdx];
}
LIBCUBESCRIPT_EXPORT cs_ident *cs_state::get_ident(std::string_view name) {
auto id = p_state->idents.find(name);
if (id != p_state->idents.end()) {
return id->second;
}
return nullptr;
}
LIBCUBESCRIPT_EXPORT cs_alias *cs_state::get_alias(std::string_view name) {
auto id = get_ident(name);
if (!id || !id->is_alias()) {
return nullptr;
}
return static_cast<cs_alias *>(id);
}
LIBCUBESCRIPT_EXPORT bool cs_state::have_ident(std::string_view name) {
return p_state->idents.find(name) != p_state->idents.end();
}
LIBCUBESCRIPT_EXPORT std::span<cs_ident *> cs_state::get_idents() {
return std::span<cs_ident *>{
p_state->identmap.data(),
p_state->identmap.size()
};
}
LIBCUBESCRIPT_EXPORT std::span<cs_ident const *> cs_state::get_idents() const {
auto ptr = const_cast<cs_ident const **>(p_state->identmap.data());
return std::span<cs_ident const *>{ptr, p_state->identmap.size()};
}
LIBCUBESCRIPT_EXPORT cs_ivar *cs_state::new_ivar(
std::string_view n, cs_int m, cs_int x, cs_int v, cs_var_cb f, int flags
) {
auto *iv = p_state->create<cs_ivar_impl>(
cs_strref{p_state, n}, m, x, v, std::move(f), flags
);
add_ident(iv, iv);
return iv;
}
LIBCUBESCRIPT_EXPORT cs_fvar *cs_state::new_fvar(
std::string_view n, cs_float m, cs_float x, cs_float v,
cs_var_cb f, int flags
) {
auto *fv = p_state->create<cs_fvar_impl>(
cs_strref{p_state, n}, m, x, v, std::move(f), flags
);
add_ident(fv, fv);
return fv;
}
LIBCUBESCRIPT_EXPORT cs_svar *cs_state::new_svar(
std::string_view n, std::string_view v, cs_var_cb f, int flags
) {
auto *sv = p_state->create<cs_svar_impl>(
cs_strref{p_state, n}, cs_strref{p_state, v},
cs_strref{p_state, ""}, std::move(f), flags
);
add_ident(sv, sv);
return sv;
}
LIBCUBESCRIPT_EXPORT void cs_state::reset_var(std::string_view name) {
cs_ident *id = get_ident(name);
if (!id) {
throw cs_error{*this, "variable %s does not exist", name.data()};
}
if (id->get_flags() & CS_IDF_READONLY) {
throw cs_error{*this, "variable %s is read only", name.data()};
}
clear_override(*id);
}
LIBCUBESCRIPT_EXPORT void cs_state::touch_var(std::string_view name) {
cs_ident *id = get_ident(name);
if (id && id->is_var()) {
static_cast<cs_var_impl *>(id->p_impl)->changed(*this);
}
}
LIBCUBESCRIPT_EXPORT void cs_state::set_alias(
std::string_view name, cs_value v
) {
cs_ident *id = get_ident(name);
if (id) {
switch (id->get_type()) {
case cs_ident_type::ALIAS: {
cs_alias_impl *a = static_cast<cs_alias_impl *>(id);
if (a->get_index() < MaxArguments) {
a->set_arg(*this, v);
} else {
a->set_alias(*this, v);
}
return;
}
case cs_ident_type::IVAR:
set_var_int_checked(static_cast<cs_ivar *>(id), v.get_int());
break;
case cs_ident_type::FVAR:
set_var_float_checked(static_cast<cs_fvar *>(id), v.get_float());
break;
case cs_ident_type::SVAR:
set_var_str_checked(static_cast<cs_svar *>(id), v.get_str());
break;
default:
throw cs_error{
*this, "cannot redefine builtin %s with an alias",
id->get_name().data()
};
}
} else if (!is_valid_name(name)) {
throw cs_error{*this, "cannot alias invalid name '%s'", name.data()};
} else {
auto *a = p_state->create<cs_alias_impl>(
*this, cs_strref{p_state, name}, std::move(v), identflags
);
add_ident(a, a);
}
}
LIBCUBESCRIPT_EXPORT cs_command *cs_state::new_command(
std::string_view name, std::string_view args, cs_command_cb func
) {
int nargs = 0;
for (auto fmt = args.begin(); fmt != args.end(); ++fmt) {
switch (*fmt) {
case 'i':
case 'b':
case 'f':
case 'F':
case 't':
case 'T':
case 'E':
case 'N':
case 's':
case 'e':
case 'r':
case '$':
if (nargs < MaxArguments) {
++nargs;
}
break;
case '1':
case '2':
case '3':
case '4':
if (nargs < (*fmt - '0')) {
return nullptr;
}
if ((args.end() - fmt) != 2) {
return nullptr;
}
if ((fmt[1] != 'C') && (fmt[1] != 'V')) {
return nullptr;
}
if (nargs < MaxArguments) {
fmt -= *fmt - '0' + 1;
}
break;
case 'C':
case 'V':
if ((fmt + 1) != args.end()) {
return nullptr;
}
break;
default:
return nullptr;
}
}
auto *cmd = p_state->create<cs_command_impl>(
cs_strref{p_state, name}, cs_strref{p_state, args}, nargs,
std::move(func)
);
add_ident(cmd, cmd);
return cmd;
}
LIBCUBESCRIPT_EXPORT void cs_state::clear_override(cs_ident &id) {
if (!(id.get_flags() & CS_IDF_OVERRIDDEN)) {
return;
}
switch (id.get_type()) {
case cs_ident_type::ALIAS: {
cs_alias_impl &a = static_cast<cs_alias_impl &>(id);
a.clean_code();
a.get_value().set_str("");
break;
}
case cs_ident_type::IVAR: {
cs_ivar_impl &iv = static_cast<cs_ivar_impl &>(id);
iv.set_value(iv.p_overrideval);
iv.changed(*this);
break;
}
case cs_ident_type::FVAR: {
cs_fvar_impl &fv = static_cast<cs_fvar_impl &>(id);
fv.set_value(fv.p_overrideval);
fv.changed(*this);
break;
}
case cs_ident_type::SVAR: {
cs_svar_impl &sv = static_cast<cs_svar_impl &>(id);
sv.set_value(sv.p_overrideval);
sv.changed(*this);
break;
}
default:
break;
}
id.p_impl->p_flags &= ~CS_IDF_OVERRIDDEN;
}
LIBCUBESCRIPT_EXPORT void cs_state::clear_overrides() {
for (auto &p: p_state->idents) {
clear_override(*(p.second));
}
}
template<typename SF>
inline void cs_override_var(cs_state &cs, cs_var *v, int &vflags, SF sf) {
if ((cs.identflags & CS_IDF_OVERRIDDEN) || (vflags & CS_IDF_OVERRIDE)) {
@ -454,10 +728,10 @@ cs_float cs_clamp_fvar(cs_state &cs, cs_fvar *fv, cs_float v) {
cs_value vmin{cs}, vmax{cs};
vmin.set_float(fv->get_val_min());
vmax.set_float(fv->get_val_max());
throw cs_error(
throw cs_error{
cs, "valid range for '%s' is %s..%s", fv->get_name().data(),
vmin.force_str(), vmax.force_str()
);
};
return v;
}

View File

@ -1,183 +0,0 @@
#include <cmath>
#include <cctype>
#include "cs_std.hh"
namespace cscript {
static inline char const *p_skip_white(char const *beg, char const *end) {
while ((beg != end) && isspace(*beg)) {
++beg;
}
return beg;
}
static inline void p_set_end(
char const *nbeg, char const *nend, std::string_view *end
) {
if (!end) {
return;
}
*end = std::string_view{nbeg, nend};
}
/* this function assumes the input is definitely a hex digit */
static inline cs_int p_hexd_to_int(char c) {
if (c >= 97) { /* a-f */
return (c - 'a') + 10;
} else if (c >= 65) { /* A-F */
return (c - 'A') + 10;
}
/* 0-9 */
return c - '0';
}
static inline bool p_check_neg(char const *&input) {
bool neg = (*input == '-');
if (neg || (*input == '+')) {
++input;
}
return neg;
}
cs_int parse_int(std::string_view input, std::string_view *endstr) {
char const *beg = input.begin();
char const *end = input.end();
char const *orig = beg;
beg = p_skip_white(beg, end);
if (beg == end) {
p_set_end(orig, end, endstr);
return cs_int(0);
}
bool neg = p_check_neg(beg);
cs_int ret = 0;
char const *past = beg;
if ((end - beg) >= 2) {
std::string_view pfx = std::string_view{beg, 2};
if ((pfx == "0x") || (pfx == "0X")) {
beg += 2;
past = beg;
while ((past != end) && std::isxdigit(*past)) {
ret = ret * 16 + p_hexd_to_int(*past++);
}
goto done;
} else if ((pfx == "0b") || (pfx == "0B")) {
beg += 2;
past = beg;
while ((past != end) && ((*past == '0') || (*past == '1'))) {
ret = ret * 2 + (*past++ - '0');
}
goto done;
}
}
while ((past != end) && std::isdigit(*past)) {
ret = ret * 10 + (*past++ - '0');
}
done:
p_set_end((past == beg) ? orig : past, end, endstr);
if (neg) {
return -ret;
}
return ret;
}
template<bool Hex, char e1 = Hex ? 'p' : 'e', char e2 = Hex ? 'P' : 'E'>
static inline bool p_read_exp(char const *&beg, char const *end, cs_int &fn) {
if (beg == end) {
return true;
}
if ((*beg != e1) && (*beg != e2)) {
return true;
}
if (++beg == end) {
return false;
}
bool neg = p_check_neg(beg);
if ((beg == end) || !std::isdigit(*beg)) {
return false;
}
cs_int exp = 0;
while ((beg != end) && std::isdigit(*beg)) {
exp = exp * 10 + (*beg++ - '0');
}
if (neg) {
exp = -exp;
}
fn += exp;
return true;
}
template<bool Hex>
static inline bool parse_gen_float(
char const *&beg, char const *end, std::string_view *endstr, cs_float &ret
) {
auto read_digits = [&beg, end](double r, cs_int &n) {
while (
(beg != end) &&
(Hex ? std::isxdigit(*beg) : std::isdigit(*beg))
) {
if (Hex) {
r = r * 16.0 + double(p_hexd_to_int(*beg));
} else {
r = r * 10.0 + double(*beg - '0');
}
++n;
++beg;
}
return r;
};
cs_int wn = 0, fn = 0;
double r = read_digits(0.0, wn);
if ((beg != end) && (*beg == '.')) {
++beg;
r = read_digits(r, fn);
}
if (!wn && !fn) {
return false;
}
fn = -fn;
p_set_end(beg, end, endstr); /* we have a valid number until here */
if (p_read_exp<Hex>(beg, end, fn)) {
p_set_end(beg, end, endstr);
}
if (Hex) {
ret = cs_float(ldexp(r, fn * 4));
} else {
ret = cs_float(r * pow(10, fn));
}
return true;
}
cs_float parse_float(std::string_view input, std::string_view *endstr) {
char const *beg = input.begin();
char const *end = input.end();
char const *orig = beg;
beg = p_skip_white(beg, end);
if (beg == end) {
p_set_end(orig, end, endstr);
return cs_float(0);
}
bool neg = p_check_neg(beg);
cs_float ret = cs_float(0);
if ((end - beg) >= 2) {
std::string_view pfx = std::string_view{beg, 2};
if ((pfx == "0x") || (pfx == "0X")) {
beg += 2;
if (!parse_gen_float<true>(beg, end, endstr, ret)) {
p_set_end(orig, end, endstr);
return ret;
}
goto done;
}
}
if (!parse_gen_float<false>(beg, end, endstr, ret)) {
p_set_end(orig, end, endstr);
return ret;
}
done:
if (neg) {
return -ret;
}
return ret;
}
} /* namespace cscript */

View File

@ -120,11 +120,6 @@ struct cs_charbuf: cs_valbuf<char> {
}
};
/* literal parsing */
cs_int parse_int(std::string_view input, std::string_view *end = nullptr);
cs_float parse_float(std::string_view input, std::string_view *end = nullptr);
} /* namespace cscript */
#endif

View File

@ -1,6 +1,7 @@
#include <cubescript/cubescript.hh>
#include "cs_vm.hh"
#include "cs_std.hh"
#include "cs_parser.hh"
#include <cmath>

View File

@ -1,6 +1,7 @@
#include <cubescript/cubescript.hh>
#include "cs_vm.hh"
#include "cs_std.hh"
#include "cs_parser.hh"
#include <cstdio>
#include <limits>
@ -1262,7 +1263,7 @@ litval:
cs_ident *id = cs.get_ident(idn);
if (!id) {
noid:
if (cs_check_num(idn)) {
if (!is_valid_name(idn)) {
goto litval;
}
result.force_none();

View File

@ -187,8 +187,6 @@ struct cs_gen_state {
void skip_comments();
};
bool cs_check_num(std::string_view s);
void bcode_ref(uint32_t *code);
void bcode_unref(uint32_t *code);

View File

@ -1,291 +0,0 @@
#include <cubescript/cubescript.hh>
#include "cs_vm.hh"
#include <iterator>
namespace cscript {
bool cs_check_num(std::string_view s) {
if (isdigit(s[0])) {
return true;
}
switch (s[0]) {
case '+':
case '-':
return isdigit(s[1]) || ((s[1] == '.') && isdigit(s[2]));
case '.':
return isdigit(s[1]) != 0;
default:
return false;
}
}
LIBCUBESCRIPT_EXPORT void cs_state::clear_override(cs_ident &id) {
if (!(id.get_flags() & CS_IDF_OVERRIDDEN)) {
return;
}
switch (id.get_type()) {
case cs_ident_type::ALIAS: {
cs_alias_impl &a = static_cast<cs_alias_impl &>(id);
a.clean_code();
a.get_value().set_str("");
break;
}
case cs_ident_type::IVAR: {
cs_ivar_impl &iv = static_cast<cs_ivar_impl &>(id);
iv.set_value(iv.p_overrideval);
iv.changed(*this);
break;
}
case cs_ident_type::FVAR: {
cs_fvar_impl &fv = static_cast<cs_fvar_impl &>(id);
fv.set_value(fv.p_overrideval);
fv.changed(*this);
break;
}
case cs_ident_type::SVAR: {
cs_svar_impl &sv = static_cast<cs_svar_impl &>(id);
sv.set_value(sv.p_overrideval);
sv.changed(*this);
break;
}
default:
break;
}
id.p_impl->p_flags &= ~CS_IDF_OVERRIDDEN;
}
LIBCUBESCRIPT_EXPORT void cs_state::clear_overrides() {
for (auto &p: p_state->idents) {
clear_override(*(p.second));
}
}
LIBCUBESCRIPT_EXPORT cs_ident *cs_state::add_ident(
cs_ident *id, cs_ident_impl *impl
) {
if (!id) {
return nullptr;
}
id->p_impl = impl;
p_state->idents[id->get_name()] = id;
static_cast<cs_ident_impl *>(impl)->p_index = p_state->identmap.size();
p_state->identmap.push_back(id);
return p_state->identmap.back();
}
LIBCUBESCRIPT_EXPORT cs_ident *cs_state::new_ident(std::string_view name, int flags) {
cs_ident *id = get_ident(name);
if (!id) {
if (cs_check_num(name)) {
throw cs_error(
*this, "number %s is not a valid identifier name", name.data()
);
}
auto *inst = p_state->create<cs_alias_impl>(
*this, cs_strref{p_state, name}, flags
);
id = add_ident(inst, inst);
}
return id;
}
LIBCUBESCRIPT_EXPORT cs_ident *cs_state::force_ident(cs_value &v) {
switch (v.get_type()) {
case cs_value_type::IDENT:
return v.get_ident();
case cs_value_type::STRING: {
cs_ident *id = new_ident(v.get_str());
v.set_ident(id);
return id;
}
default:
break;
}
v.set_ident(p_state->identmap[DummyIdx]);
return p_state->identmap[DummyIdx];
}
LIBCUBESCRIPT_EXPORT cs_ident *cs_state::get_ident(std::string_view name) {
auto id = p_state->idents.find(name);
if (id != p_state->idents.end()) {
return id->second;
}
return nullptr;
}
LIBCUBESCRIPT_EXPORT cs_alias *cs_state::get_alias(std::string_view name) {
auto id = get_ident(name);
if (!id || !id->is_alias()) {
return nullptr;
}
return static_cast<cs_alias *>(id);
}
LIBCUBESCRIPT_EXPORT bool cs_state::have_ident(std::string_view name) {
return p_state->idents.find(name) != p_state->idents.end();
}
LIBCUBESCRIPT_EXPORT std::span<cs_ident *> cs_state::get_idents() {
return std::span<cs_ident *>{
p_state->identmap.data(),
p_state->identmap.size()
};
}
LIBCUBESCRIPT_EXPORT std::span<cs_ident const *> cs_state::get_idents() const {
auto ptr = const_cast<cs_ident const **>(p_state->identmap.data());
return std::span<cs_ident const *>{ptr, p_state->identmap.size()};
}
LIBCUBESCRIPT_EXPORT cs_ivar *cs_state::new_ivar(
std::string_view n, cs_int m, cs_int x, cs_int v, cs_var_cb f, int flags
) {
auto *iv = p_state->create<cs_ivar_impl>(
cs_strref{p_state, n}, m, x, v, std::move(f), flags
);
add_ident(iv, iv);
return iv;
}
LIBCUBESCRIPT_EXPORT cs_fvar *cs_state::new_fvar(
std::string_view n, cs_float m, cs_float x, cs_float v, cs_var_cb f, int flags
) {
auto *fv = p_state->create<cs_fvar_impl>(
cs_strref{p_state, n}, m, x, v, std::move(f), flags
);
add_ident(fv, fv);
return fv;
}
LIBCUBESCRIPT_EXPORT cs_svar *cs_state::new_svar(
std::string_view n, std::string_view v, cs_var_cb f, int flags
) {
auto *sv = p_state->create<cs_svar_impl>(
cs_strref{p_state, n}, cs_strref{p_state, v},
cs_strref{p_state, ""}, std::move(f), flags
);
add_ident(sv, sv);
return sv;
}
LIBCUBESCRIPT_EXPORT void cs_state::reset_var(std::string_view name) {
cs_ident *id = get_ident(name);
if (!id) {
throw cs_error(*this, "variable %s does not exist", name.data());
}
if (id->get_flags() & CS_IDF_READONLY) {
throw cs_error(*this, "variable %s is read only", name.data());
}
clear_override(*id);
}
LIBCUBESCRIPT_EXPORT void cs_state::touch_var(std::string_view name) {
cs_ident *id = get_ident(name);
if (id && id->is_var()) {
static_cast<cs_var_impl *>(id->p_impl)->changed(*this);
}
}
LIBCUBESCRIPT_EXPORT void cs_state::set_alias(std::string_view name, cs_value v) {
cs_ident *id = get_ident(name);
if (id) {
switch (id->get_type()) {
case cs_ident_type::ALIAS: {
cs_alias_impl *a = static_cast<cs_alias_impl *>(id);
if (a->get_index() < MaxArguments) {
a->set_arg(*this, v);
} else {
a->set_alias(*this, v);
}
return;
}
case cs_ident_type::IVAR:
set_var_int_checked(static_cast<cs_ivar *>(id), v.get_int());
break;
case cs_ident_type::FVAR:
set_var_float_checked(static_cast<cs_fvar *>(id), v.get_float());
break;
case cs_ident_type::SVAR:
set_var_str_checked(static_cast<cs_svar *>(id), v.get_str());
break;
default:
throw cs_error(
*this, "cannot redefine builtin %s with an alias",
id->get_name().data()
);
}
} else if (cs_check_num(name)) {
throw cs_error(*this, "cannot alias number %s", name.data());
} else {
auto *a = p_state->create<cs_alias_impl>(
*this, cs_strref{p_state, name}, std::move(v), identflags
);
add_ident(a, a);
}
}
LIBCUBESCRIPT_EXPORT void cs_state::print_var(cs_var const &v) const {
if (p_state->varprintf) {
p_state->varprintf(*this, v);
}
}
LIBCUBESCRIPT_EXPORT cs_command *cs_state::new_command(
std::string_view name, std::string_view args, cs_command_cb func
) {
int nargs = 0;
for (auto fmt = args.begin(); fmt != args.end(); ++fmt) {
switch (*fmt) {
case 'i':
case 'b':
case 'f':
case 'F':
case 't':
case 'T':
case 'E':
case 'N':
case 's':
case 'e':
case 'r':
case '$':
if (nargs < MaxArguments) {
++nargs;
}
break;
case '1':
case '2':
case '3':
case '4':
if (nargs < (*fmt - '0')) {
return nullptr;
}
if ((args.end() - fmt) != 2) {
return nullptr;
}
if ((fmt[1] != 'C') && (fmt[1] != 'V')) {
return nullptr;
}
if (nargs < MaxArguments) {
fmt -= *fmt - '0' + 1;
}
break;
case 'C':
case 'V':
if ((fmt + 1) != args.end()) {
return nullptr;
}
break;
default:
return nullptr;
}
}
auto *cmd = p_state->create<cs_command_impl>(
cs_strref{p_state, name}, cs_strref{p_state, args}, nargs,
std::move(func)
);
add_ident(cmd, cmd);
return cmd;
}
} /* namespace cscript */

View File

@ -3,6 +3,7 @@
#include <cubescript/cubescript.hh>
#include "cs_std.hh"
#include "cs_parser.hh"
namespace cscript {

View File

@ -10,11 +10,9 @@ libcubescript_src = [
'cs_ident.cc',
'cs_parser.cc',
'cs_state.cc',
'cs_std.cc',
'cs_strman.cc',
'cs_val.cc',
'cs_vm.cc',
'cubescript.cc',
'lib_base.cc',
'lib_list.cc',
'lib_math.cc',