libcubescript/lib_base.cc

367 lines
11 KiB
C++

#include "cubescript.hh"
#include "cs_private.hh"
namespace cscript {
static void cs_init_lib_base_var(CsState &cs) {
cs.add_command("nodebug", "e", [&cs](TvalRange args) {
++cs.nodebug;
cs.run_ret(args[0].get_code());
--cs.nodebug;
});
cs.add_command("push", "rTe", [&cs](TvalRange args) {
Ident *id = args[0].get_ident();
if (id->type != ID_ALIAS || id->index < MaxArguments) return;
IdentStack stack;
TaggedValue &v = args[1];
id->push_arg(v, stack);
v.set_null();
cs.run_ret(args[2].get_code());
id->pop_arg();
});
cs.add_command("local", nullptr, nullptr, ID_LOCAL);
cs.add_command("resetvar", "s", [&cs](TvalRange args) {
cs.result->set_int(cs.reset_var(args[0].get_strr()));
});
cs.add_command("alias", "sT", [&cs](TvalRange args) {
TaggedValue &v = args[1];
cs.set_alias(args[0].get_strr(), v);
v.set_null();
});
cs.add_command("getvarmin", "s", [&cs](TvalRange args) {
cs.result->set_int(cs.get_var_min_int(args[0].get_strr()).value_or(0));
});
cs.add_command("getvarmax", "s", [&cs](TvalRange args) {
cs.result->set_int(cs.get_var_max_int(args[0].get_strr()).value_or(0));
});
cs.add_command("getfvarmin", "s", [&cs](TvalRange args) {
cs.result->set_float(cs.get_var_min_float(args[0].get_strr()).value_or(0.0f));
});
cs.add_command("getfvarmax", "s", [&cs](TvalRange args) {
cs.result->set_float(cs.get_var_max_float(args[0].get_strr()).value_or(0.0f));
});
cs.add_command("identexists", "s", [&cs](TvalRange args) {
cs.result->set_int(cs.have_ident(args[0].get_strr()));
});
cs.add_command("getalias", "s", [&cs](TvalRange args) {
cs.result->set_str(ostd::move(cs.get_alias(args[0].get_strr()).value_or("")));
});
}
void cs_init_lib_io(CsState &cs) {
cs.add_command("exec", "sb", [&cs](TvalRange args) {
auto file = args[0].get_strr();
bool ret = cs.run_file(file);
if (!ret) {
if (args[1].get_int())
ostd::err.writefln("could not run file \"%s\"", file);
cs.result->set_int(0);
} else
cs.result->set_int(1);
});
cs.add_command("echo", "C", [](TvalRange args) {
ostd::writeln(args[0].get_strr());
});
}
static void cs_init_lib_base_loops(CsState &cs);
void cs_init_lib_base(CsState &cs) {
cs.add_command("do", "e", [&cs](TvalRange args) {
cs.run_ret(args[0].get_code());
}, ID_DO);
cs.add_command("doargs", "e", [&cs](TvalRange args) {
if (cs.stack != &cs.noalias)
cs_do_args(cs, [&]() { cs.run_ret(args[0].get_code()); });
else
cs.run_ret(args[0].get_code());
}, ID_DOARGS);
cs.add_command("if", "tee", [&cs](TvalRange args) {
cs.run_ret((args[0].get_bool() ? args[1] : args[2]).get_code());
}, ID_IF);
cs.add_command("result", "T", [&cs](TvalRange args) {
TaggedValue &v = args[0];
*cs.result = v;
v.set_null();
}, ID_RESULT);
cs.add_command("!", "t", [&cs](TvalRange args) {
cs.result->set_int(!args[0].get_bool());
}, ID_NOT);
cs.add_command("&&", "E1V", [&cs](TvalRange args) {
if (args.empty())
cs.result->set_int(1);
else for (ostd::Size i = 0; i < args.size(); ++i) {
if (i) cs.result->cleanup();
if (args[i].get_type() == VAL_CODE)
cs.run_ret(args[i].code);
else
*cs.result = args[i];
if (!cs.result->get_bool()) break;
}
}, ID_AND);
cs.add_command("||", "E1V", [&cs](TvalRange args) {
if (args.empty())
cs.result->set_int(0);
else for (ostd::Size i = 0; i < args.size(); ++i) {
if (i) cs.result->cleanup();
if (args[i].get_type() == VAL_CODE)
cs.run_ret(args[i].code);
else
*cs.result = args[i];
if (cs.result->get_bool()) break;
}
}, ID_OR);
cs.add_command("?", "tTT", [&cs](TvalRange args) {
cs.result->set(args[0].get_bool() ? args[1] : args[2]);
});
cs.add_command("cond", "ee2V", [&cs](TvalRange args) {
for (ostd::Size i = 0; i < args.size(); i += 2) {
if ((i + 1) < args.size()) {
if (cs.run_bool(args[i].code)) {
cs.run_ret(args[i + 1].code);
break;
}
} else {
cs.run_ret(args[i].code);
break;
}
}
});
#define CS_CMD_CASE(name, fmt, type, acc, compare) \
cs.add_command(name, fmt "te2V", [&cs](TvalRange args) { \
type val = ostd::move(acc); \
ostd::Size i; \
for (i = 1; (i + 1) < args.size(); i += 2) { \
if (compare) { \
cs.run_ret(args[i + 1].code); \
return; \
} \
} \
});
CS_CMD_CASE("case", "i", int, args[0].get_int(),
((args[i].get_type() == VAL_NULL) ||
(args[i].get_int() == val)));
CS_CMD_CASE("casef", "f", float, args[0].get_float(),
((args[i].get_type() == VAL_NULL) ||
(args[i].get_float() == val)));
CS_CMD_CASE("cases", "s", ostd::String, args[0].get_str(),
((args[i].get_type() == VAL_NULL) ||
(args[i].get_str() == val)));
#undef CS_CMD_CASE
cs.add_command("pushif", "rTe", [&cs](TvalRange args) {
Ident *id = args[0].get_ident();
TaggedValue &v = args[1];
ostd::Uint32 *code = args[2].get_code();
if ((id->type != ID_ALIAS) || (id->index < MaxArguments))
return;
if (v.get_bool()) {
IdentStack stack;
id->push_arg(v, stack);
v.set_null();
cs.run_ret(code);
id->pop_arg();
}
});
cs_init_lib_base_loops(cs);
cs_init_lib_base_var(cs);
}
static inline void cs_set_iter(Ident &id, int i, IdentStack &stack) {
if (id.stack == &stack) {
if (id.get_valtype() != VAL_INT) {
if (id.get_valtype() == VAL_STR) {
delete[] id.val.s;
id.val.s = nullptr;
id.val.len = 0;
}
id.clean_code();
id.valtype = VAL_INT;
}
id.val.i = i;
return;
}
TaggedValue v;
v.set_int(i);
id.push_arg(v, stack);
}
static inline void cs_do_loop(CsState &cs, Ident &id, int offset, int n,
int step, ostd::Uint32 *cond, ostd::Uint32 *body) {
if (n <= 0 || (id.type != ID_ALIAS))
return;
IdentStack stack;
for (int i = 0; i < n; ++i) {
cs_set_iter(id, offset + i * step, stack);
if (cond && !cs.run_bool(cond)) break;
cs.run_int(body);
}
id.pop_arg();
}
static inline void cs_loop_conc(CsState &cs, Ident &id, int offset, int n,
int step, ostd::Uint32 *body, bool space) {
if (n <= 0 || id.type != ID_ALIAS)
return;
IdentStack stack;
ostd::Vector<char> s;
for (int i = 0; i < n; ++i) {
cs_set_iter(id, offset + i * step, stack);
TaggedValue v;
cs.run_ret(body, v);
ostd::String vstr = ostd::move(v.get_str());
if (space && i) s.push(' ');
s.push_n(vstr.data(), vstr.size());
v.cleanup();
}
if (n > 0) id.pop_arg();
s.push('\0');
ostd::Size len = s.size() - 1;
cs.result->set_mstr(ostd::CharRange(s.disown(), len));
}
static void cs_init_lib_base_loops(CsState &cs) {
cs.add_command("loop", "rie", [&cs](TvalRange args) {
cs_do_loop(
cs, *args[0].get_ident(), 0, args[1].get_int(), 1, nullptr,
args[2].get_code()
);
});
cs.add_command("loop+", "riie", [&cs](TvalRange args) {
cs_do_loop(
cs, *args[0].get_ident(), args[1].get_int(), args[2].get_int(), 1,
nullptr, args[3].get_code()
);
});
cs.add_command("loop*", "riie", [&cs](TvalRange args) {
cs_do_loop(
cs, *args[0].get_ident(), 0, args[1].get_int(), args[2].get_int(),
nullptr, args[3].get_code()
);
});
cs.add_command("loop+*", "riiie", [&cs](TvalRange args) {
cs_do_loop(
cs, *args[0].get_ident(), args[1].get_int(), args[3].get_int(),
args[2].get_int(), nullptr, args[4].get_code()
);
});
cs.add_command("loopwhile", "riee", [&cs](TvalRange args) {
cs_do_loop(
cs, *args[0].get_ident(), 0, args[1].get_int(), 1,
args[2].get_code(), args[3].get_code()
);
});
cs.add_command("loopwhile+", "riiee", [&cs](TvalRange args) {
cs_do_loop(
cs, *args[0].get_ident(), args[1].get_int(), args[2].get_int(), 1,
args[3].get_code(), args[4].get_code()
);
});
cs.add_command("loopwhile*", "riiee", [&cs](TvalRange args) {
cs_do_loop(
cs, *args[0].get_ident(), 0, args[2].get_int(), args[1].get_int(),
args[3].get_code(), args[4].get_code()
);
});
cs.add_command("loopwhile+*", "riiiee", [&cs](TvalRange args) {
cs_do_loop(
cs, *args[0].get_ident(), args[1].get_int(), args[3].get_int(),
args[2].get_int(), args[4].get_code(), args[5].get_code()
);
});
cs.add_command("while", "ee", [&cs](TvalRange args) {
ostd::Uint32 *cond = args[0].get_code(), *body = args[1].get_code();
while (cs.run_bool(cond)) {
cs.run_int(body);
}
});
cs.add_command("loopconcat", "rie", [&cs](TvalRange args) {
cs_loop_conc(
cs, *args[0].get_ident(), 0, args[1].get_int(), 1,
args[2].get_code(), true
);
});
cs.add_command("loopconcat+", "riie", [&cs](TvalRange args) {
cs_loop_conc(
cs, *args[0].get_ident(), args[1].get_int(), args[2].get_int(), 1,
args[3].get_code(), true
);
});
cs.add_command("loopconcat*", "riie", [&cs](TvalRange args) {
cs_loop_conc(
cs, *args[0].get_ident(), 0, args[2].get_int(), args[1].get_int(),
args[3].get_code(), true
);
});
cs.add_command("loopconcat+*", "riiie", [&cs](TvalRange args) {
cs_loop_conc(
cs, *args[0].get_ident(), args[1].get_int(), args[3].get_int(),
args[2].get_int(), args[4].get_code(), true
);
});
cs.add_command("loopconcatword", "rie", [&cs](TvalRange args) {
cs_loop_conc(
cs, *args[0].get_ident(), 0, args[1].get_int(), 1,
args[2].get_code(), false
);
});
cs.add_command("loopconcatword+", "riie", [&cs](TvalRange args) {
cs_loop_conc(
cs, *args[0].get_ident(), args[1].get_int(), args[2].get_int(), 1,
args[3].get_code(), false
);
});
cs.add_command("loopconcatword*", "riie", [&cs](TvalRange args) {
cs_loop_conc(
cs, *args[0].get_ident(), 0, args[2].get_int(), args[1].get_int(),
args[3].get_code(), false
);
});
cs.add_command("loopconcatword+*", "riiie", [&cs](TvalRange args) {
cs_loop_conc(
cs, *args[0].get_ident(), args[1].get_int(), args[3].get_int(),
args[2].get_int(), args[4].get_code(), false
);
});
}
} /* namespace cscript */