diff --git a/src/cs_gen.cc b/src/cs_gen.cc index 95d1693..3393389 100644 --- a/src/cs_gen.cc +++ b/src/cs_gen.cc @@ -1,6 +1,7 @@ #include #include "cs_vm.hh" #include "cs_std.hh" +#include "cs_parser.hh" #include @@ -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; } diff --git a/src/cs_parser.cc b/src/cs_parser.cc index 0512794..d54532c 100644 --- a/src/cs_parser.cc +++ b/src/cs_parser.cc @@ -1,5 +1,8 @@ #include +#include +#include + #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 +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 +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(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(beg, end, endstr, ret)) { + p_set_end(orig, end, endstr); + return ret; + } + goto done; + } + } + if (!parse_gen_float(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() { diff --git a/src/cs_parser.hh b/src/cs_parser.hh new file mode 100644 index 0000000..e73ebc8 --- /dev/null +++ b/src/cs_parser.hh @@ -0,0 +1,17 @@ +#ifndef LIBCUBESCRIPT_PARSER_HH +#define LIBCUBESCRIPT_PARSER_HH + +#include + +#include + +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 diff --git a/src/cs_state.cc b/src/cs_state.cc index 137657c..0724bfc 100644 --- a/src/cs_state.cc +++ b/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(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(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(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( + *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(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_state::get_idents() { + return std::span{ + p_state->identmap.data(), + p_state->identmap.size() + }; +} + +LIBCUBESCRIPT_EXPORT std::span cs_state::get_idents() const { + auto ptr = const_cast(p_state->identmap.data()); + return std::span{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_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_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_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(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(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(id), v.get_int()); + break; + case cs_ident_type::FVAR: + set_var_float_checked(static_cast(id), v.get_float()); + break; + case cs_ident_type::SVAR: + set_var_str_checked(static_cast(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( + *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_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(id); + a.clean_code(); + a.get_value().set_str(""); + break; + } + case cs_ident_type::IVAR: { + cs_ivar_impl &iv = static_cast(id); + iv.set_value(iv.p_overrideval); + iv.changed(*this); + break; + } + case cs_ident_type::FVAR: { + cs_fvar_impl &fv = static_cast(id); + fv.set_value(fv.p_overrideval); + fv.changed(*this); + break; + } + case cs_ident_type::SVAR: { + cs_svar_impl &sv = static_cast(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 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; } diff --git a/src/cs_std.cc b/src/cs_std.cc deleted file mode 100644 index ca28d3e..0000000 --- a/src/cs_std.cc +++ /dev/null @@ -1,183 +0,0 @@ -#include -#include - -#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 -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 -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(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(beg, end, endstr, ret)) { - p_set_end(orig, end, endstr); - return ret; - } - goto done; - } - } - if (!parse_gen_float(beg, end, endstr, ret)) { - p_set_end(orig, end, endstr); - return ret; - } -done: - if (neg) { - return -ret; - } - return ret; -} - -} /* namespace cscript */ diff --git a/src/cs_std.hh b/src/cs_std.hh index d9333da..fa803c5 100644 --- a/src/cs_std.hh +++ b/src/cs_std.hh @@ -120,11 +120,6 @@ struct cs_charbuf: cs_valbuf { } }; -/* 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 diff --git a/src/cs_val.cc b/src/cs_val.cc index 03b7153..8336dcf 100644 --- a/src/cs_val.cc +++ b/src/cs_val.cc @@ -1,6 +1,7 @@ #include #include "cs_vm.hh" #include "cs_std.hh" +#include "cs_parser.hh" #include diff --git a/src/cs_vm.cc b/src/cs_vm.cc index d7defe3..c625763 100644 --- a/src/cs_vm.cc +++ b/src/cs_vm.cc @@ -1,6 +1,7 @@ #include #include "cs_vm.hh" #include "cs_std.hh" +#include "cs_parser.hh" #include #include @@ -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(); diff --git a/src/cs_vm.hh b/src/cs_vm.hh index 94e7495..401cb9c 100644 --- a/src/cs_vm.hh +++ b/src/cs_vm.hh @@ -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); diff --git a/src/cubescript.cc b/src/cubescript.cc deleted file mode 100644 index 898d71a..0000000 --- a/src/cubescript.cc +++ /dev/null @@ -1,291 +0,0 @@ -#include -#include "cs_vm.hh" - -#include - -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(id); - a.clean_code(); - a.get_value().set_str(""); - break; - } - case cs_ident_type::IVAR: { - cs_ivar_impl &iv = static_cast(id); - iv.set_value(iv.p_overrideval); - iv.changed(*this); - break; - } - case cs_ident_type::FVAR: { - cs_fvar_impl &fv = static_cast(id); - fv.set_value(fv.p_overrideval); - fv.changed(*this); - break; - } - case cs_ident_type::SVAR: { - cs_svar_impl &sv = static_cast(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(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( - *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(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_state::get_idents() { - return std::span{ - p_state->identmap.data(), - p_state->identmap.size() - }; -} - -LIBCUBESCRIPT_EXPORT std::span cs_state::get_idents() const { - auto ptr = const_cast(p_state->identmap.data()); - return std::span{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_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_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_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(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(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(id), v.get_int()); - break; - case cs_ident_type::FVAR: - set_var_float_checked(static_cast(id), v.get_float()); - break; - case cs_ident_type::SVAR: - set_var_str_checked(static_cast(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( - *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_strref{p_state, name}, cs_strref{p_state, args}, nargs, - std::move(func) - ); - add_ident(cmd, cmd); - return cmd; -} - -} /* namespace cscript */ diff --git a/src/lib_list.cc b/src/lib_list.cc index 3790d70..becbc6e 100644 --- a/src/lib_list.cc +++ b/src/lib_list.cc @@ -3,6 +3,7 @@ #include #include "cs_std.hh" +#include "cs_parser.hh" namespace cscript { diff --git a/src/meson.build b/src/meson.build index cfcccca..84a42ec 100644 --- a/src/meson.build +++ b/src/meson.build @@ -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',