libcubescript/cubescript.hh

609 lines
15 KiB
C++
Raw Normal View History

2015-09-10 19:53:43 +02:00
#ifndef CUBESCRIPT_HH
#define CUBESCRIPT_HH
#include <stdio.h>
#include <stdlib.h>
2016-03-17 22:21:45 +01:00
#include <ostd/platform.hh>
2015-08-08 18:13:19 +02:00
#include <ostd/types.hh>
#include <ostd/string.hh>
2015-08-08 18:13:19 +02:00
#include <ostd/vector.hh>
#include <ostd/keyset.hh>
2015-08-08 18:13:19 +02:00
#include <ostd/range.hh>
#include <ostd/utility.hh>
2015-08-07 03:11:53 +02:00
#include <ostd/maybe.hh>
2015-08-08 18:13:19 +02:00
#include <ostd/io.hh>
#include <ostd/functional.hh>
2015-08-08 17:13:46 +02:00
namespace cscript {
enum {
VAL_NULL = 0, VAL_INT, VAL_FLOAT, VAL_STR,
VAL_ANY, VAL_CODE, VAL_MACRO, VAL_IDENT, VAL_CSTR,
VAL_CANY, VAL_WORD, VAL_POP, VAL_COND
};
enum {
2015-08-11 23:16:20 +02:00
ID_UNKNOWN = -1, ID_VAR, ID_FVAR, ID_SVAR, ID_COMMAND, ID_ALIAS,
ID_LOCAL, ID_DO, ID_DOARGS, ID_IF, ID_RESULT, ID_NOT, ID_AND, ID_OR
};
enum {
IDF_PERSIST = 1 << 0,
IDF_OVERRIDE = 1 << 1,
IDF_HEX = 1 << 2,
IDF_READONLY = 1 << 3,
IDF_OVERRIDDEN = 1 << 4,
IDF_UNKNOWN = 1 << 5,
IDF_ARG = 1 << 6
};
2016-08-06 20:12:38 +02:00
struct Bytecode;
2016-08-06 19:38:05 +02:00
struct OSTD_EXPORT BytecodeRef {
2016-08-07 22:39:27 +02:00
BytecodeRef():
p_code(nullptr)
{}
2016-08-06 20:12:38 +02:00
BytecodeRef(Bytecode *v);
2016-08-06 19:38:05 +02:00
BytecodeRef(BytecodeRef const &v);
2016-08-07 22:39:27 +02:00
BytecodeRef(BytecodeRef &&v):
p_code(v.p_code)
{
v.p_code = nullptr;
}
2015-12-20 00:28:12 +01:00
2016-08-06 19:38:05 +02:00
~BytecodeRef();
2016-08-06 19:38:05 +02:00
BytecodeRef &operator=(BytecodeRef const &v);
BytecodeRef &operator=(BytecodeRef &&v);
2015-12-20 00:28:12 +01:00
operator bool() const { return p_code != nullptr; }
2016-08-06 20:12:38 +02:00
operator Bytecode *() const { return p_code; }
2015-12-20 00:28:12 +01:00
private:
2016-08-06 20:12:38 +02:00
Bytecode *p_code;
2015-12-20 00:28:12 +01:00
};
2016-08-06 20:12:38 +02:00
OSTD_EXPORT bool code_is_empty(Bytecode const *code);
struct Ident;
struct IdentValue {
union {
int i; /* ID_VAR, VAL_INT */
float f; /* ID_FVAR, VAL_FLOAT */
2016-08-06 20:12:38 +02:00
Bytecode const *code; /* VAL_CODE */
Ident *id; /* VAL_IDENT */
2016-08-01 22:46:50 +02:00
char *s; /* ID_SVAR, VAL_STR */
2016-07-17 19:50:40 +02:00
char const *cstr; /* VAL_CSTR */
};
2016-08-01 22:46:50 +02:00
ostd::Size len;
};
2016-03-17 22:21:45 +01:00
struct OSTD_EXPORT TaggedValue: IdentValue {
friend struct Ident;
2015-08-13 22:48:03 +02:00
int get_type() const {
2016-08-01 22:35:42 +02:00
return p_type;
2015-08-13 22:48:03 +02:00
}
void set_int(int val) {
2015-08-13 22:48:03 +02:00
p_type = VAL_INT;
i = val;
}
void set_float(float val) {
2015-08-13 22:48:03 +02:00
p_type = VAL_FLOAT;
f = val;
}
2016-07-13 19:46:35 +02:00
void set_str(ostd::String val) {
ostd::CharRange cr = val.iter();
val.disown();
set_mstr(cr);
}
void set_null() {
2015-08-13 22:48:03 +02:00
p_type = VAL_NULL;
i = 0;
}
2016-08-06 20:12:38 +02:00
void set_code(Bytecode const *val) {
2015-08-13 22:48:03 +02:00
p_type = VAL_CODE;
code = val;
}
void set_cstr(ostd::ConstCharRange val) {
2016-08-01 22:35:42 +02:00
p_type = VAL_CSTR;
2016-08-01 22:46:50 +02:00
len = val.size();
cstr = val.data();
}
2016-07-13 19:46:35 +02:00
void set_mstr(ostd::CharRange val) {
2016-08-01 22:35:42 +02:00
p_type = VAL_STR;
2016-08-01 22:46:50 +02:00
len = val.size();
2016-07-13 19:46:35 +02:00
s = val.data();
}
void set_ident(Ident *val) {
2015-08-13 22:48:03 +02:00
p_type = VAL_IDENT;
id = val;
}
2015-08-08 02:40:29 +02:00
void set(TaggedValue &tv) {
*this = tv;
2015-08-13 22:48:03 +02:00
tv.p_type = VAL_NULL;
2015-08-08 02:40:29 +02:00
}
2016-07-13 20:24:26 +02:00
ostd::String get_str() const;
ostd::ConstCharRange get_strr() const;
int get_int() const;
float get_float() const;
2016-08-06 20:12:38 +02:00
Bytecode *get_code() const;
2016-08-01 22:35:42 +02:00
Ident *get_ident() const;
void get_val(TaggedValue &r) const;
bool get_bool() const;
void force_null();
float force_float();
int force_int();
ostd::ConstCharRange force_str();
bool code_is_empty() const;
void cleanup();
2016-08-04 00:03:44 +02:00
void copy_arg(TaggedValue &r) const;
2015-08-13 22:48:03 +02:00
private:
int p_type;
};
using TvalRange = ostd::PointerRange<TaggedValue>;
struct IdentStack {
IdentValue val;
int valtype;
IdentStack *next;
};
union IdentValuePtr {
2015-08-13 22:08:57 +02:00
int *ip; /* ID_VAR */
float *fp; /* ID_FVAR */
char **sp; /* ID_SVAR */
};
struct CsState;
using VarCb = ostd::Function<void(Ident &)>;
using CmdFunc = ostd::Function<void(TvalRange)>;
2016-03-17 22:21:45 +01:00
struct OSTD_EXPORT Ident {
ostd::byte type; /* ID_something */
union {
2016-07-13 20:24:26 +02:00
int valtype; /* ID_ALIAS */
int numargs; /* ID_COMMAND */
};
ostd::ushort flags;
int index;
ostd::String name;
union {
struct { /* ID_VAR, ID_FVAR, ID_SVAR */
union {
struct { /* ID_VAR */
int minval, maxval;
};
struct { /* ID_FVAR */
float minvalf, maxvalf;
};
};
IdentValuePtr storage;
IdentValue overrideval;
};
struct { /* ID_ALIAS */
2016-08-06 20:12:38 +02:00
Bytecode *code;
IdentValue val;
IdentStack *stack;
};
struct { /* ID_COMMAND */
char *args;
2015-08-08 00:37:54 +02:00
ostd::Uint32 argmask;
};
};
2016-08-01 02:10:21 +02:00
VarCb cb_var;
2016-08-01 20:17:13 +02:00
CmdFunc cb_cftv;
2015-08-11 23:16:20 +02:00
Ident(): type(ID_UNKNOWN) {}
/* ID_VAR */
2016-08-07 22:39:27 +02:00
Ident(
int t, ostd::ConstCharRange n, int m, int x, int *s,
VarCb f = VarCb(), int flags = 0
);
2015-08-11 23:16:20 +02:00
/* ID_FVAR */
2016-08-07 22:39:27 +02:00
Ident(
int t, ostd::ConstCharRange n, float m, float x, float *s,
VarCb f = VarCb(), int flags = 0
);
2015-08-11 23:16:20 +02:00
/* ID_SVAR */
2016-08-07 22:39:27 +02:00
Ident(
int t, ostd::ConstCharRange n, char **s, VarCb f = VarCb(),
int flags = 0
);
2015-08-11 23:16:20 +02:00
/* ID_ALIAS */
2015-08-11 23:16:20 +02:00
Ident(int t, ostd::ConstCharRange n, char *a, int flags);
Ident(int t, ostd::ConstCharRange n, int a, int flags);
Ident(int t, ostd::ConstCharRange n, float a, int flags);
Ident(int t, ostd::ConstCharRange n, int flags);
2016-07-17 19:50:40 +02:00
Ident(int t, ostd::ConstCharRange n, TaggedValue const &v, int flags);
2015-08-11 23:16:20 +02:00
/* ID_COMMAND */
2016-08-07 22:39:27 +02:00
Ident(
int t, ostd::ConstCharRange n, ostd::ConstCharRange args,
ostd::Uint32 argmask, int numargs, CmdFunc f = CmdFunc(),
int flags = 0
);
void changed() {
2016-08-07 22:39:27 +02:00
if (cb_var) {
cb_var(*this);
}
}
2016-07-17 19:50:40 +02:00
void set_value(TaggedValue const &v) {
2016-08-01 22:35:42 +02:00
valtype = v.get_type();
val = v;
}
2016-07-17 19:50:40 +02:00
void set_value(IdentStack const &v) {
valtype = v.valtype;
val = v.val;
}
2015-08-11 22:41:12 +02:00
void force_null() {
2016-08-01 22:46:50 +02:00
if (valtype == VAL_STR) {
2015-08-11 22:41:12 +02:00
delete[] val.s;
2016-08-01 22:46:50 +02:00
val.s = nullptr;
val.len = 0;
}
valtype = VAL_NULL;
}
float get_float() const;
int get_int() const;
2016-07-13 20:24:26 +02:00
ostd::String get_str() const;
ostd::ConstCharRange get_strr() const;
void get_val(TaggedValue &r) const;
2015-08-11 22:41:12 +02:00
void get_cstr(TaggedValue &v) const;
void get_cval(TaggedValue &v) const;
ostd::ConstCharRange get_key() const {
return name.iter();
}
void clean_code();
2015-08-07 00:02:56 +02:00
2016-07-17 19:50:40 +02:00
void push_arg(TaggedValue const &v, IdentStack &st, bool um = true);
2015-08-07 00:02:56 +02:00
void pop_arg();
void undo_arg(IdentStack &st);
2016-07-17 19:50:40 +02:00
void redo_arg(IdentStack const &st);
2015-08-07 00:16:02 +02:00
void push_alias(IdentStack &st);
void pop_alias();
2015-08-07 00:38:22 +02:00
void set_arg(CsState &cs, TaggedValue &v);
void set_alias(CsState &cs, TaggedValue &v);
int get_valtype() const {
2016-08-01 22:35:42 +02:00
return valtype;
}
};
2015-08-06 22:43:36 +02:00
struct IdentLink {
Ident *id;
IdentLink *next;
int usedargs;
IdentStack *argstack;
};
2016-03-17 22:21:45 +01:00
struct OSTD_EXPORT CsState {
ostd::Keyset<Ident> idents;
ostd::Vector<Ident *> identmap;
Ident *dummy = nullptr;
TaggedValue *result = nullptr;
2016-07-27 19:52:01 +02:00
IdentLink noalias;
2015-08-06 22:43:36 +02:00
IdentLink *stack = &noalias;
ostd::ConstCharRange src_file;
ostd::ConstCharRange src_str;
int identflags = 0;
2015-08-06 22:43:36 +02:00
int nodebug = 0;
int numargs = 0;
int dbgalias = 4;
CsState();
~CsState();
void clear_override(Ident &id);
void clear_overrides();
template<typename ...A>
Ident *add_ident(A &&...args) {
Ident &def = idents.emplace(ostd::forward<A>(args)...).first.front();
def.index = identmap.size();
return identmap.push(&def);
}
2015-08-13 20:51:15 +02:00
Ident *new_ident(ostd::ConstCharRange name, int flags = IDF_UNKNOWN);
Ident *force_ident(TaggedValue &v);
Ident *get_ident(ostd::ConstCharRange name) {
return idents.at(name);
}
bool have_ident(ostd::ConstCharRange name) {
return idents.at(name) != nullptr;
}
bool reset_var(ostd::ConstCharRange name);
void touch_var(ostd::ConstCharRange name);
2016-08-07 22:39:27 +02:00
bool add_command(
ostd::ConstCharRange name, ostd::ConstCharRange args,
CmdFunc func, int type = ID_COMMAND, int flags = 0
);
2015-10-11 17:59:36 +02:00
2016-08-06 20:12:38 +02:00
ostd::String run_str(Bytecode const *code);
2015-08-06 02:44:13 +02:00
ostd::String run_str(ostd::ConstCharRange code);
ostd::String run_str(Ident *id, TvalRange args);
2016-08-06 20:12:38 +02:00
int run_int(Bytecode const *code);
int run_int(ostd::ConstCharRange code);
int run_int(Ident *id, TvalRange args);
2016-08-06 20:12:38 +02:00
float run_float(Bytecode const *code);
float run_float(ostd::ConstCharRange code);
float run_float(Ident *id, TvalRange args);
2016-08-06 20:12:38 +02:00
bool run_bool(Bytecode const *code);
bool run_bool(ostd::ConstCharRange code);
bool run_bool(Ident *id, TvalRange args);
2015-08-06 03:07:16 +02:00
2016-08-06 20:12:38 +02:00
void run_ret(Bytecode const *code, TaggedValue &ret);
2016-02-29 01:56:53 +01:00
void run_ret(ostd::ConstCharRange code, TaggedValue &ret);
void run_ret(Ident *id, TvalRange args, TaggedValue &ret);
2015-08-07 22:04:31 +02:00
2016-08-06 20:12:38 +02:00
void run_ret(Bytecode const *code) {
2015-08-07 22:04:31 +02:00
run_ret(code, *result);
}
void run_ret(ostd::ConstCharRange code) {
run_ret(code, *result);
}
void run_ret(Ident *id, TvalRange args) {
2015-08-07 22:04:31 +02:00
run_ret(id, args, *result);
}
2015-09-12 17:21:40 +02:00
bool run_file(ostd::ConstCharRange fname);
2015-08-06 22:43:36 +02:00
2015-08-07 00:38:22 +02:00
void set_alias(ostd::ConstCharRange name, TaggedValue &v);
2015-08-07 03:11:53 +02:00
2016-08-07 22:39:27 +02:00
void set_var_int(
ostd::ConstCharRange name, int v,
bool dofunc = true, bool doclamp = true
);
void set_var_float(
ostd::ConstCharRange name, float v,
bool dofunc = true, bool doclamp = true
);
void set_var_str(
ostd::ConstCharRange name, ostd::ConstCharRange v, bool dofunc = true
);
2015-08-07 03:11:53 +02:00
2015-08-07 03:44:51 +02:00
void set_var_int_checked(Ident *id, int v);
void set_var_int_checked(Ident *id, TvalRange args);
2015-08-07 03:44:51 +02:00
void set_var_float_checked(Ident *id, float v);
void set_var_str_checked(Ident *id, ostd::ConstCharRange v);
2015-08-07 03:11:53 +02:00
ostd::Maybe<int> get_var_int(ostd::ConstCharRange name);
ostd::Maybe<float> get_var_float(ostd::ConstCharRange name);
ostd::Maybe<ostd::String> get_var_str(ostd::ConstCharRange name);
ostd::Maybe<int> get_var_min_int(ostd::ConstCharRange name);
ostd::Maybe<int> get_var_max_int(ostd::ConstCharRange name);
ostd::Maybe<float> get_var_min_float(ostd::ConstCharRange name);
ostd::Maybe<float> get_var_max_float(ostd::ConstCharRange name);
2016-07-13 20:24:26 +02:00
ostd::Maybe<ostd::String> get_alias(ostd::ConstCharRange name);
2015-08-07 22:38:57 +02:00
void print_var(Ident *id);
void print_var_int(Ident *id, int i);
void print_var_float(Ident *id, float f);
void print_var_str(Ident *id, ostd::ConstCharRange s);
};
2016-02-28 23:21:28 +01:00
enum {
CS_LIB_IO = 1 << 0,
CS_LIB_MATH = 1 << 1,
CS_LIB_STRING = 1 << 2,
CS_LIB_LIST = 1 << 3,
CS_LIB_ALL = 0b1111
2016-02-28 23:21:28 +01:00
};
2016-03-17 22:21:45 +01:00
OSTD_EXPORT void init_libs(CsState &cs, int libs = CS_LIB_ALL);
2015-08-08 17:06:18 +02:00
inline bool check_alias(Ident *id) {
return id && (id->type == ID_ALIAS);
}
2016-03-17 22:21:45 +01:00
struct OSTD_EXPORT StackedValue: TaggedValue {
Ident *id;
2016-03-04 22:28:41 +01:00
StackedValue(Ident *idv = nullptr):
2016-08-07 22:39:27 +02:00
TaggedValue(), id(idv), p_stack(), p_pushed(false)
{}
~StackedValue() {
pop();
}
2015-12-16 20:05:28 +01:00
bool alias(CsState &cs, ostd::ConstCharRange name) {
id = cs.new_ident(name);
return check_alias(id);
}
bool push() {
2016-08-07 22:39:27 +02:00
if (p_pushed || !id) {
return false;
}
2015-08-14 00:18:48 +02:00
id->push_arg(*this, p_stack);
p_pushed = true;
return true;
}
bool pop() {
2016-08-07 22:39:27 +02:00
if (!p_pushed || !id) {
return false;
}
id->pop_arg();
2015-08-14 00:18:48 +02:00
p_pushed = false;
return true;
}
2015-08-14 00:18:48 +02:00
private:
IdentStack p_stack;
bool p_pushed;
};
2015-08-08 17:06:18 +02:00
namespace util {
template<typename R>
inline ostd::Size escape_string(R &&writer, ostd::ConstCharRange str) {
ostd::Size ret = 2;
writer.put('"');
2016-08-07 22:39:27 +02:00
for (; !str.empty(); str.pop_front()) {
switch (str.front()) {
case '\n':
ret += writer.put_n("^n", 2);
break;
case '\t':
ret += writer.put_n("^t", 2);
break;
case '\f':
ret += writer.put_n("^f", 2);
break;
case '"':
ret += writer.put_n("^\"", 2);
break;
case '^':
ret += writer.put_n("^^", 2);
break;
default:
ret += writer.put(str.front());
break;
}
2015-08-08 17:06:18 +02:00
}
writer.put('"');
return ret;
}
2015-08-08 18:07:01 +02:00
2015-08-11 03:18:53 +02:00
template<typename R>
inline ostd::Size unescape_string(R &&writer, ostd::ConstCharRange str) {
ostd::Size ret = 0;
for (; !str.empty(); str.pop_front()) {
if (str.front() == '^') {
str.pop_front();
2016-08-07 22:39:27 +02:00
if (str.empty()) {
2015-08-11 03:18:53 +02:00
break;
2016-08-07 22:39:27 +02:00
}
2015-08-11 03:18:53 +02:00
switch (str.front()) {
2016-08-07 22:39:27 +02:00
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;
2015-08-11 03:18:53 +02:00
}
} else {
ret += writer.put(str.front());
}
}
return ret;
}
2015-08-13 01:16:52 +02:00
ostd::Size list_length(ostd::ConstCharRange s);
2016-08-07 22:39:27 +02:00
ostd::Maybe<ostd::String> list_index(
ostd::ConstCharRange s, ostd::Size idx
);
ostd::Vector<ostd::String> list_explode(
ostd::ConstCharRange s, ostd::Size limit = -1
);
template<typename R>
inline ostd::Ptrdiff format_int(R &&writer, int val) {
return ostd::format(ostd::forward<R>(writer), "%d", val);
}
template<typename R>
inline ostd::Ptrdiff format_float(R &&writer, int val) {
return ostd::format(
ostd::forward<R>(writer), (val == int(val)) ? "%.1f" : "%.7g", val
);
}
template<typename R>
inline ostd::Size tvals_concat(
R &&writer, TvalRange vals,
ostd::ConstCharRange sep = ostd::ConstCharRange()
) {
ostd::Size ret = 0;
for (ostd::Size i = 0; i < vals.size(); ++i) {
auto s = ostd::appender<ostd::String>();
switch (vals[i].get_type()) {
case VAL_INT: {
auto r = format_int(ostd::forward<R>(writer), vals[i].i);
if (r > 0) {
ret += ostd::Size(r);
}
break;
}
case VAL_FLOAT: {
auto r = format_float(ostd::forward<R>(writer), vals[i].i);
if (r > 0) {
ret += ostd::Size(r);
}
break;
}
case VAL_STR:
case VAL_CSTR:
case VAL_MACRO:
ret += writer.put_n(vals[i].s, vals[i].len);
break;
default:
break;
}
if (i == (vals.size() - 1)) {
break;
}
ret += writer.put_n(sep.data(), sep.size());
}
return ret;
}
2016-03-06 22:51:11 +01:00
} /* namespace util */
2015-08-08 17:13:46 +02:00
2015-09-10 19:53:43 +02:00
} /* namespace cscript */
2016-02-07 22:22:39 +01:00
#endif /* CUBESCRIPT_HH */