forked from OctaForge/libcubescript
815 lines
22 KiB
C++
815 lines
22 KiB
C++
#ifndef LIBCUBESCRIPT_CUBESCRIPT_HH
|
|
#define LIBCUBESCRIPT_CUBESCRIPT_HH
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <optional>
|
|
#include <functional>
|
|
#include <type_traits>
|
|
|
|
#include "cubescript_conf.hh"
|
|
|
|
#include <ostd/platform.hh>
|
|
#include <ostd/types.hh>
|
|
#include <ostd/string.hh>
|
|
#include <ostd/vector.hh>
|
|
#include <ostd/range.hh>
|
|
#include <ostd/utility.hh>
|
|
#include <ostd/io.hh>
|
|
#include <ostd/format.hh>
|
|
|
|
namespace cscript {
|
|
|
|
using cs_string = std::string;
|
|
|
|
static_assert(std::is_integral_v<cs_int>, "cs_int must be integral");
|
|
static_assert(std::is_signed_v<cs_int>, "cs_int must be signed");
|
|
static_assert(std::is_floating_point_v<cs_float>, "cs_float must be floating point");
|
|
|
|
struct cs_internal_error: std::runtime_error {
|
|
using std::runtime_error::runtime_error;
|
|
};
|
|
|
|
enum {
|
|
CS_IDF_PERSIST = 1 << 0,
|
|
CS_IDF_OVERRIDE = 1 << 1,
|
|
CS_IDF_HEX = 1 << 2,
|
|
CS_IDF_READONLY = 1 << 3,
|
|
CS_IDF_OVERRIDDEN = 1 << 4,
|
|
CS_IDF_UNKNOWN = 1 << 5,
|
|
CS_IDF_ARG = 1 << 6
|
|
};
|
|
|
|
struct cs_bcode;
|
|
|
|
struct OSTD_EXPORT cs_bcode_ref {
|
|
cs_bcode_ref():
|
|
p_code(nullptr)
|
|
{}
|
|
cs_bcode_ref(cs_bcode *v);
|
|
cs_bcode_ref(cs_bcode_ref const &v);
|
|
cs_bcode_ref(cs_bcode_ref &&v):
|
|
p_code(v.p_code)
|
|
{
|
|
v.p_code = nullptr;
|
|
}
|
|
|
|
~cs_bcode_ref();
|
|
|
|
cs_bcode_ref &operator=(cs_bcode_ref const &v);
|
|
cs_bcode_ref &operator=(cs_bcode_ref &&v);
|
|
|
|
operator bool() const { return p_code != nullptr; }
|
|
operator cs_bcode *() const { return p_code; }
|
|
|
|
private:
|
|
cs_bcode *p_code;
|
|
};
|
|
|
|
OSTD_EXPORT bool cs_code_is_empty(cs_bcode *code);
|
|
|
|
enum class cs_value_type {
|
|
Null = 0, Int, Float, String, Cstring, Code, Macro, Ident
|
|
};
|
|
|
|
struct OSTD_EXPORT cs_value {
|
|
cs_value();
|
|
~cs_value();
|
|
|
|
cs_value(cs_value const &);
|
|
cs_value(cs_value &&);
|
|
|
|
cs_value &operator=(cs_value const &v);
|
|
cs_value &operator=(cs_value &&v);
|
|
|
|
cs_value_type get_type() const;
|
|
|
|
void set_int(cs_int val);
|
|
void set_float(cs_float val);
|
|
void set_str(cs_string val);
|
|
void set_null();
|
|
void set_code(cs_bcode *val);
|
|
void set_cstr(ostd::ConstCharRange val);
|
|
void set_ident(cs_ident *val);
|
|
void set_macro(ostd::ConstCharRange val);
|
|
|
|
cs_string get_str() const;
|
|
ostd::ConstCharRange get_strr() const;
|
|
cs_int get_int() const;
|
|
cs_float get_float() const;
|
|
cs_bcode *get_code() const;
|
|
cs_ident *get_ident() const;
|
|
void get_val(cs_value &r) const;
|
|
|
|
bool get_bool() const;
|
|
|
|
void force_null();
|
|
cs_float force_float();
|
|
cs_int force_int();
|
|
ostd::ConstCharRange force_str();
|
|
|
|
bool code_is_empty() const;
|
|
|
|
private:
|
|
std::aligned_union_t<1, cs_int, cs_float, void *> p_stor;
|
|
size_t p_len;
|
|
cs_value_type p_type;
|
|
};
|
|
|
|
struct cs_ident_stack {
|
|
cs_value val_s;
|
|
cs_ident_stack *next;
|
|
};
|
|
|
|
struct cs_shared_state;
|
|
struct cs_error;
|
|
struct cs_gen_state;
|
|
|
|
enum class cs_ident_type {
|
|
Ivar = 0, Fvar, Svar, Command, Alias, Special
|
|
};
|
|
|
|
struct cs_var;
|
|
struct cs_ivar;
|
|
struct cs_fvar;
|
|
struct cs_svar;
|
|
struct cs_alias;
|
|
struct cs_command;
|
|
|
|
struct OSTD_EXPORT cs_ident {
|
|
friend struct cs_state;
|
|
friend struct cs_shared_state;
|
|
|
|
cs_ident() = delete;
|
|
cs_ident(cs_ident const &) = delete;
|
|
cs_ident(cs_ident &&) = delete;
|
|
|
|
/* trigger destructors for all inherited members properly */
|
|
virtual ~cs_ident() {};
|
|
|
|
cs_ident &operator=(cs_ident const &) = delete;
|
|
cs_ident &operator=(cs_ident &&) = delete;
|
|
|
|
cs_ident_type get_type() const;
|
|
ostd::ConstCharRange get_name() const;
|
|
int get_flags() const;
|
|
int get_index() const;
|
|
|
|
bool is_alias() const;
|
|
cs_alias *get_alias();
|
|
cs_alias const *get_alias() const;
|
|
|
|
bool is_command() const;
|
|
cs_command *get_command();
|
|
cs_command const *get_command() const;
|
|
|
|
bool is_special() const;
|
|
|
|
bool is_var() const;
|
|
cs_var *get_var();
|
|
cs_var const *get_var() const;
|
|
|
|
bool is_ivar() const;
|
|
cs_ivar *get_ivar();
|
|
cs_ivar const *get_ivar() const;
|
|
|
|
bool is_fvar() const;
|
|
cs_fvar *get_fvar();
|
|
cs_fvar const *get_fvar() const;
|
|
|
|
bool is_svar() const;
|
|
cs_svar *get_svar();
|
|
cs_svar const *get_svar() const;
|
|
|
|
int get_type_raw() const {
|
|
return p_type;
|
|
}
|
|
|
|
protected:
|
|
cs_ident(cs_ident_type tp, ostd::ConstCharRange name, int flags = 0);
|
|
|
|
cs_string p_name;
|
|
/* represents the cs_ident_type above, but internally it has a wider variety
|
|
* of values, so it's an int here (maps to an internal enum)
|
|
*/
|
|
int p_type, p_flags;
|
|
|
|
private:
|
|
int p_index = -1;
|
|
};
|
|
|
|
struct OSTD_EXPORT cs_var: cs_ident {
|
|
friend struct cs_state;
|
|
friend struct cs_shared_state;
|
|
|
|
protected:
|
|
cs_var(cs_ident_type tp, ostd::ConstCharRange name, cs_var_cb func, int flags = 0);
|
|
|
|
private:
|
|
cs_var_cb cb_var;
|
|
|
|
virtual cs_string to_printable() const = 0;
|
|
|
|
void changed(cs_state &cs) {
|
|
if (cb_var) {
|
|
cb_var(cs, *this);
|
|
}
|
|
}
|
|
};
|
|
|
|
struct OSTD_EXPORT cs_ivar: cs_var {
|
|
friend struct cs_state;
|
|
friend struct cs_shared_state;
|
|
|
|
cs_int get_val_min() const;
|
|
cs_int get_val_max() const;
|
|
|
|
cs_int get_value() const;
|
|
void set_value(cs_int val);
|
|
|
|
cs_string to_printable() const final;
|
|
|
|
private:
|
|
cs_ivar(
|
|
ostd::ConstCharRange n, cs_int m, cs_int x, cs_int v, cs_var_cb f, int flags
|
|
);
|
|
|
|
cs_int p_storage, p_minval, p_maxval, p_overrideval;
|
|
};
|
|
|
|
struct OSTD_EXPORT cs_fvar: cs_var {
|
|
friend struct cs_state;
|
|
friend struct cs_shared_state;
|
|
|
|
cs_float get_val_min() const;
|
|
cs_float get_val_max() const;
|
|
|
|
cs_float get_value() const;
|
|
void set_value(cs_float val);
|
|
|
|
cs_string to_printable() const final;
|
|
|
|
private:
|
|
cs_fvar(
|
|
ostd::ConstCharRange n, cs_float m, cs_float x, cs_float v,
|
|
cs_var_cb f, int flags
|
|
);
|
|
|
|
cs_float p_storage, p_minval, p_maxval, p_overrideval;
|
|
};
|
|
|
|
struct OSTD_EXPORT cs_svar: cs_var {
|
|
friend struct cs_state;
|
|
friend struct cs_shared_state;
|
|
|
|
ostd::ConstCharRange get_value() const;
|
|
void set_value(cs_string val);
|
|
|
|
cs_string to_printable() const final;
|
|
|
|
private:
|
|
cs_svar(ostd::ConstCharRange n, cs_string v, cs_var_cb f, int flags);
|
|
|
|
cs_string p_storage, p_overrideval;
|
|
};
|
|
|
|
struct OSTD_EXPORT cs_alias: cs_ident {
|
|
friend struct cs_state;
|
|
friend struct cs_shared_state;
|
|
friend struct cs_aliasInternal;
|
|
|
|
cs_value const &get_value() const {
|
|
return p_val;
|
|
}
|
|
|
|
cs_value &get_value() {
|
|
return p_val;
|
|
}
|
|
|
|
void get_cstr(cs_value &v) const;
|
|
void get_cval(cs_value &v) const;
|
|
private:
|
|
cs_alias(ostd::ConstCharRange n, cs_string a, int flags);
|
|
cs_alias(ostd::ConstCharRange n, cs_int a, int flags);
|
|
cs_alias(ostd::ConstCharRange n, cs_float a, int flags);
|
|
cs_alias(ostd::ConstCharRange n, int flags);
|
|
cs_alias(ostd::ConstCharRange n, cs_value v, int flags);
|
|
|
|
cs_bcode *p_acode;
|
|
cs_ident_stack *p_astack;
|
|
cs_value p_val;
|
|
};
|
|
|
|
struct cs_command: cs_ident {
|
|
friend struct cs_state;
|
|
friend struct cs_shared_state;
|
|
friend struct cs_cmd_internal;
|
|
|
|
ostd::ConstCharRange get_args() const;
|
|
int get_num_args() const;
|
|
|
|
private:
|
|
cs_command(
|
|
ostd::ConstCharRange name, ostd::ConstCharRange args,
|
|
int numargs, cs_command_cb func
|
|
);
|
|
|
|
cs_string p_cargs;
|
|
cs_command_cb p_cb_cftv;
|
|
int p_numargs;
|
|
};
|
|
|
|
struct cs_identLink;
|
|
|
|
enum {
|
|
CsLibMath = 1 << 0,
|
|
CsLibString = 1 << 1,
|
|
CsLibList = 1 << 2,
|
|
CsLibAll = 0b111
|
|
};
|
|
|
|
enum class CsLoopState {
|
|
Normal = 0, Break, Continue
|
|
};
|
|
|
|
static inline void *cs_default_alloc(void *, void *p, size_t, size_t ns) {
|
|
if (!ns) {
|
|
delete[] static_cast<unsigned char *>(p);
|
|
return nullptr;
|
|
}
|
|
return new unsigned char[ns];
|
|
}
|
|
|
|
struct OSTD_EXPORT cs_state {
|
|
friend struct cs_error;
|
|
friend struct cs_gen_state;
|
|
|
|
cs_shared_state *p_state;
|
|
cs_identLink *p_callstack = nullptr;
|
|
|
|
int identflags = 0;
|
|
|
|
cs_state(cs_alloc_cb func = cs_default_alloc, void *data = nullptr);
|
|
virtual ~cs_state();
|
|
|
|
cs_hook_cb set_call_hook(cs_hook_cb func);
|
|
cs_hook_cb const &get_call_hook() const;
|
|
cs_hook_cb &get_call_hook();
|
|
|
|
void init_libs(int libs = CsLibAll);
|
|
|
|
void clear_override(cs_ident &id);
|
|
void clear_overrides();
|
|
|
|
cs_ident *new_ident(ostd::ConstCharRange name, int flags = CS_IDF_UNKNOWN);
|
|
cs_ident *force_ident(cs_value &v);
|
|
|
|
cs_ivar *new_ivar(
|
|
ostd::ConstCharRange n, cs_int m, cs_int x, cs_int v,
|
|
cs_var_cb f = cs_var_cb(), int flags = 0
|
|
);
|
|
cs_fvar *new_fvar(
|
|
ostd::ConstCharRange n, cs_float m, cs_float x, cs_float v,
|
|
cs_var_cb f = cs_var_cb(), int flags = 0
|
|
);
|
|
cs_svar *new_svar(
|
|
ostd::ConstCharRange n, cs_string v,
|
|
cs_var_cb f = cs_var_cb(), int flags = 0
|
|
);
|
|
|
|
cs_command *new_command(
|
|
ostd::ConstCharRange name, ostd::ConstCharRange args, cs_command_cb func
|
|
);
|
|
|
|
cs_ident *get_ident(ostd::ConstCharRange name);
|
|
cs_alias *get_alias(ostd::ConstCharRange name);
|
|
bool have_ident(ostd::ConstCharRange name);
|
|
|
|
cs_ident_r get_idents();
|
|
cs_const_ident_r get_idents() const;
|
|
|
|
void reset_var(ostd::ConstCharRange name);
|
|
void touch_var(ostd::ConstCharRange name);
|
|
|
|
cs_string run_str(cs_bcode *code);
|
|
cs_string run_str(ostd::ConstCharRange code);
|
|
cs_string run_str(cs_ident *id, cs_value_r args);
|
|
|
|
cs_int run_int(cs_bcode *code);
|
|
cs_int run_int(ostd::ConstCharRange code);
|
|
cs_int run_int(cs_ident *id, cs_value_r args);
|
|
|
|
cs_float run_float(cs_bcode *code);
|
|
cs_float run_float(ostd::ConstCharRange code);
|
|
cs_float run_float(cs_ident *id, cs_value_r args);
|
|
|
|
bool run_bool(cs_bcode *code);
|
|
bool run_bool(ostd::ConstCharRange code);
|
|
bool run_bool(cs_ident *id, cs_value_r args);
|
|
|
|
void run(cs_bcode *code, cs_value &ret);
|
|
void run(ostd::ConstCharRange code, cs_value &ret);
|
|
void run(cs_ident *id, cs_value_r args, cs_value &ret);
|
|
|
|
void run(cs_bcode *code);
|
|
void run(ostd::ConstCharRange code);
|
|
void run(cs_ident *id, cs_value_r args);
|
|
|
|
CsLoopState run_loop(cs_bcode *code, cs_value &ret);
|
|
CsLoopState run_loop(cs_bcode *code);
|
|
|
|
bool is_in_loop() const {
|
|
return p_inloop;
|
|
}
|
|
|
|
std::optional<cs_string> run_file_str(ostd::ConstCharRange fname);
|
|
std::optional<cs_int> run_file_int(ostd::ConstCharRange fname);
|
|
std::optional<cs_float> run_file_float(ostd::ConstCharRange fname);
|
|
std::optional<bool> run_file_bool(ostd::ConstCharRange fname);
|
|
bool run_file(ostd::ConstCharRange fname, cs_value &ret);
|
|
bool run_file(ostd::ConstCharRange fname);
|
|
|
|
void set_alias(ostd::ConstCharRange name, cs_value v);
|
|
|
|
void set_var_int(
|
|
ostd::ConstCharRange name, cs_int v,
|
|
bool dofunc = true, bool doclamp = true
|
|
);
|
|
void set_var_float(
|
|
ostd::ConstCharRange name, cs_float v,
|
|
bool dofunc = true, bool doclamp = true
|
|
);
|
|
void set_var_str(
|
|
ostd::ConstCharRange name, ostd::ConstCharRange v, bool dofunc = true
|
|
);
|
|
|
|
void set_var_int_checked(cs_ivar *iv, cs_int v);
|
|
void set_var_int_checked(cs_ivar *iv, cs_value_r args);
|
|
void set_var_float_checked(cs_fvar *fv, cs_float v);
|
|
void set_var_str_checked(cs_svar *fv, ostd::ConstCharRange v);
|
|
|
|
std::optional<cs_int> get_var_int(ostd::ConstCharRange name);
|
|
std::optional<cs_float> get_var_float(ostd::ConstCharRange name);
|
|
std::optional<cs_string> get_var_str(ostd::ConstCharRange name);
|
|
|
|
std::optional<cs_int> get_var_min_int(ostd::ConstCharRange name);
|
|
std::optional<cs_int> get_var_max_int(ostd::ConstCharRange name);
|
|
|
|
std::optional<cs_float> get_var_min_float(ostd::ConstCharRange name);
|
|
std::optional<cs_float> get_var_max_float(ostd::ConstCharRange name);
|
|
|
|
std::optional<cs_string> get_alias_val(ostd::ConstCharRange name);
|
|
|
|
virtual void print_var(cs_var *v);
|
|
|
|
private:
|
|
cs_ident *add_ident(cs_ident *id);
|
|
|
|
void *alloc(void *ptr, size_t olds, size_t news);
|
|
|
|
cs_gen_state *p_pstate = nullptr;
|
|
int p_inloop = 0;
|
|
|
|
char p_errbuf[512];
|
|
|
|
cs_hook_cb p_callhook;
|
|
};
|
|
|
|
struct cs_stack_state_node {
|
|
cs_stack_state_node const *next;
|
|
cs_ident const *id;
|
|
int index;
|
|
};
|
|
|
|
struct cs_stack_state {
|
|
cs_stack_state() = delete;
|
|
cs_stack_state(cs_state &cs, cs_stack_state_node *nd = nullptr, bool gap = false);
|
|
cs_stack_state(cs_stack_state const &) = delete;
|
|
cs_stack_state(cs_stack_state &&st);
|
|
~cs_stack_state();
|
|
|
|
cs_stack_state &operator=(cs_stack_state const &) = delete;
|
|
cs_stack_state &operator=(cs_stack_state &&);
|
|
|
|
cs_stack_state_node const *get() const;
|
|
bool gap() const;
|
|
|
|
private:
|
|
cs_state &p_state;
|
|
cs_stack_state_node *p_node;
|
|
bool p_gap;
|
|
};
|
|
|
|
struct cs_error {
|
|
friend struct cs_state;
|
|
|
|
cs_error() = delete;
|
|
cs_error(cs_error const &) = delete;
|
|
cs_error(cs_error &&v):
|
|
p_errmsg(v.p_errmsg), p_stack(std::move(v.p_stack))
|
|
{}
|
|
|
|
ostd::ConstCharRange what() const {
|
|
return p_errmsg;
|
|
}
|
|
|
|
cs_stack_state &get_stack() {
|
|
return p_stack;
|
|
}
|
|
|
|
cs_stack_state const &get_stack() const {
|
|
return p_stack;
|
|
}
|
|
|
|
cs_error(cs_state &cs, ostd::ConstCharRange msg):
|
|
p_errmsg(), p_stack(cs)
|
|
{
|
|
p_errmsg = save_msg(cs, msg);
|
|
p_stack = save_stack(cs);
|
|
}
|
|
|
|
template<typename ...A>
|
|
cs_error(cs_state &cs, ostd::ConstCharRange msg, A &&...args):
|
|
p_errmsg(), p_stack(cs)
|
|
{
|
|
try {
|
|
char fbuf[512];
|
|
auto ret = ostd::format(
|
|
ostd::CharRange(fbuf, fbuf + sizeof(fbuf)), msg,
|
|
std::forward<A>(args)...
|
|
);
|
|
p_errmsg = save_msg(cs, ostd::CharRange(fbuf, fbuf + ret));
|
|
} catch (...) {
|
|
p_errmsg = save_msg(cs, msg);
|
|
}
|
|
p_stack = save_stack(cs);
|
|
}
|
|
|
|
private:
|
|
cs_stack_state save_stack(cs_state &cs);
|
|
ostd::ConstCharRange save_msg(cs_state &cs, ostd::ConstCharRange v);
|
|
|
|
ostd::ConstCharRange p_errmsg;
|
|
cs_stack_state p_stack;
|
|
};
|
|
|
|
struct OSTD_EXPORT cs_stacked_value: cs_value {
|
|
cs_stacked_value(cs_ident *id = nullptr);
|
|
~cs_stacked_value();
|
|
|
|
cs_stacked_value(cs_stacked_value const &) = delete;
|
|
cs_stacked_value(cs_stacked_value &&) = delete;
|
|
|
|
cs_stacked_value &operator=(cs_stacked_value const &) = delete;
|
|
cs_stacked_value &operator=(cs_stacked_value &&v) = delete;
|
|
|
|
cs_stacked_value &operator=(cs_value const &v);
|
|
cs_stacked_value &operator=(cs_value &&v);
|
|
|
|
bool set_alias(cs_ident *id);
|
|
cs_alias *get_alias() const;
|
|
bool has_alias() const;
|
|
|
|
bool push();
|
|
bool pop();
|
|
|
|
private:
|
|
cs_alias *p_a;
|
|
cs_ident_stack p_stack;
|
|
bool p_pushed;
|
|
};
|
|
|
|
namespace util {
|
|
template<typename R>
|
|
inline size_t escape_string(R &&writer, ostd::ConstCharRange str) {
|
|
size_t ret = 2;
|
|
writer.put('"');
|
|
for (; !str.empty(); str.pop_front()) {
|
|
switch (str.front()) {
|
|
case '\n':
|
|
ret += ostd::range_put_n(writer, "^n", 2);
|
|
break;
|
|
case '\t':
|
|
ret += ostd::range_put_n(writer, "^t", 2);
|
|
break;
|
|
case '\f':
|
|
ret += ostd::range_put_n(writer, "^f", 2);
|
|
break;
|
|
case '"':
|
|
ret += ostd::range_put_n(writer, "^\"", 2);
|
|
break;
|
|
case '^':
|
|
ret += ostd::range_put_n(writer, "^^", 2);
|
|
break;
|
|
default:
|
|
ret += writer.put(str.front());
|
|
break;
|
|
}
|
|
}
|
|
writer.put('"');
|
|
return ret;
|
|
}
|
|
|
|
template<typename R>
|
|
inline size_t unescape_string(R &&writer, ostd::ConstCharRange str) {
|
|
size_t ret = 0;
|
|
for (; !str.empty(); str.pop_front()) {
|
|
if (str.front() == '^') {
|
|
str.pop_front();
|
|
if (str.empty()) {
|
|
break;
|
|
}
|
|
switch (str.front()) {
|
|
case 'n':
|
|
ret += writer.put('\n');
|
|
break;
|
|
case 't':
|
|
ret += writer.put('\r');
|
|
break;
|
|
case 'f':
|
|
ret += writer.put('\f');
|
|
break;
|
|
case '"':
|
|
ret += writer.put('"');
|
|
break;
|
|
case '^':
|
|
ret += writer.put('^');
|
|
break;
|
|
default:
|
|
ret += writer.put(str.front());
|
|
break;
|
|
}
|
|
} else if (str.front() == '\\') {
|
|
str.pop_front();
|
|
if (str.empty()) {
|
|
break;
|
|
}
|
|
char c = str.front();
|
|
if ((c == '\r') || (c == '\n')) {
|
|
if (!str.empty() && (c == '\r') && (str.front() == '\n')) {
|
|
str.pop_front();
|
|
}
|
|
continue;
|
|
}
|
|
ret += writer.put('\\');
|
|
} else {
|
|
ret += writer.put(str.front());
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
OSTD_EXPORT ostd::ConstCharRange parse_string(
|
|
cs_state &cs, ostd::ConstCharRange str, size_t &nlines
|
|
);
|
|
|
|
inline ostd::ConstCharRange parse_string(
|
|
cs_state &cs, ostd::ConstCharRange str
|
|
) {
|
|
size_t nlines;
|
|
return parse_string(cs, str, nlines);
|
|
}
|
|
|
|
OSTD_EXPORT ostd::ConstCharRange parse_word(
|
|
cs_state &cs, ostd::ConstCharRange str
|
|
);
|
|
|
|
struct OSTD_EXPORT ListParser {
|
|
ListParser() = delete;
|
|
ListParser(cs_state &cs, ostd::ConstCharRange src):
|
|
p_state(cs), p_input(src)
|
|
{}
|
|
|
|
void skip();
|
|
bool parse();
|
|
size_t count();
|
|
|
|
template<typename R>
|
|
size_t get_item(R &&writer) const {
|
|
if (!p_quote.empty() && (*p_quote == '"')) {
|
|
return unescape_string(std::forward<R>(writer), p_item);
|
|
} else {
|
|
return ostd::range_put_n(writer, p_item.data(), p_item.size());
|
|
}
|
|
}
|
|
|
|
cs_string get_item() const {
|
|
auto app = ostd::appender<cs_string>();
|
|
get_item(app);
|
|
return std::move(app.get());
|
|
}
|
|
|
|
ostd::ConstCharRange &get_raw_item(bool quoted = false) {
|
|
return quoted ? p_quote : p_item;
|
|
}
|
|
|
|
ostd::ConstCharRange const &get_raw_item(bool quoted = false) const {
|
|
return quoted ? p_quote : p_item;
|
|
}
|
|
|
|
ostd::ConstCharRange &get_input() {
|
|
return p_input;
|
|
}
|
|
|
|
private:
|
|
ostd::ConstCharRange p_quote = ostd::ConstCharRange();
|
|
ostd::ConstCharRange p_item = ostd::ConstCharRange();
|
|
cs_state &p_state;
|
|
ostd::ConstCharRange p_input;
|
|
};
|
|
|
|
template<typename R>
|
|
inline std::size_t format_int(R &&writer, cs_int val) {
|
|
try {
|
|
return ostd::format(std::forward<R>(writer), IntFormat, val);
|
|
} catch (ostd::format_error const &e) {
|
|
throw cs_internal_error{e.what()};
|
|
}
|
|
}
|
|
|
|
template<typename R>
|
|
inline std::size_t format_float(R &&writer, cs_float val) {
|
|
try {
|
|
return ostd::format(
|
|
std::forward<R>(writer),
|
|
(val == cs_int(val)) ? RoundFloatFormat : FloatFormat, val
|
|
);
|
|
} catch (ostd::format_error const &e) {
|
|
throw cs_internal_error{e.what()};
|
|
}
|
|
}
|
|
|
|
template<typename R>
|
|
inline size_t tvals_concat(
|
|
R &&writer, cs_value_r vals,
|
|
ostd::ConstCharRange sep = ostd::ConstCharRange()
|
|
) {
|
|
size_t ret = 0;
|
|
for (size_t i = 0; i < vals.size(); ++i) {
|
|
auto s = ostd::appender<cs_string>();
|
|
switch (vals[i].get_type()) {
|
|
case cs_value_type::Int: {
|
|
auto r = format_int(
|
|
std::forward<R>(writer), vals[i].get_int()
|
|
);
|
|
if (r > 0) {
|
|
ret += size_t(r);
|
|
}
|
|
break;
|
|
}
|
|
case cs_value_type::Float: {
|
|
auto r = format_float(
|
|
std::forward<R>(writer), vals[i].get_float()
|
|
);
|
|
if (r > 0) {
|
|
ret += size_t(r);
|
|
}
|
|
break;
|
|
}
|
|
case cs_value_type::String:
|
|
case cs_value_type::Cstring:
|
|
case cs_value_type::Macro: {
|
|
auto sv = vals[i].get_strr();
|
|
ret += ostd::range_put_n(writer, sv.data(), sv.size());
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
if (i == (vals.size() - 1)) {
|
|
break;
|
|
}
|
|
ret += ostd::range_put_n(writer, sep.data(), sep.size());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
template<typename R>
|
|
inline size_t print_stack(R &&writer, cs_stack_state const &st) {
|
|
size_t ret = 0;
|
|
auto nd = st.get();
|
|
while (nd) {
|
|
try {
|
|
ret += ostd::format(
|
|
writer,
|
|
((nd->index == 1) && st.gap())
|
|
? " ..%d) %s" : " %d) %s",
|
|
nd->index, nd->id->get_name()
|
|
);
|
|
} catch (ostd::format_error const &e) {
|
|
throw cs_internal_error{e.what()};
|
|
}
|
|
nd = nd->next;
|
|
if (nd) {
|
|
ret += writer.put('\n');
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
} /* namespace util */
|
|
|
|
} /* namespace cscript */
|
|
|
|
#endif /* LIBCUBESCRIPT_CUBESCRIPT_HH */
|