drop cubescript.cc, move parsing stuff from cs_std to cs_parser
parent
7139370990
commit
b3b4624af1
|
@ -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;
|
||||
}
|
||||
|
|
204
src/cs_parser.cc
204
src/cs_parser.cc
|
@ -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() {
|
||||
|
|
|
@ -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
|
286
src/cs_state.cc
286
src/cs_state.cc
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
183
src/cs_std.cc
183
src/cs_std.cc
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <cubescript/cubescript.hh>
|
||||
#include "cs_vm.hh"
|
||||
#include "cs_std.hh"
|
||||
#include "cs_parser.hh"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <cubescript/cubescript.hh>
|
||||
#include "cs_std.hh"
|
||||
#include "cs_parser.hh"
|
||||
|
||||
namespace cscript {
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
|
Loading…
Reference in New Issue