diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/map/script.cpp | 707 | ||||
-rw-r--r-- | src/map/script.hpp | 109 | ||||
-rw-r--r-- | src/sexpr/variant.tcc | 2 | ||||
-rw-r--r-- | src/sexpr/variant_test.cpp | 36 |
4 files changed, 480 insertions, 374 deletions
diff --git a/src/map/script.cpp b/src/map/script.cpp index b378321..f890adf 100644 --- a/src/map/script.cpp +++ b/src/map/script.cpp @@ -82,7 +82,7 @@ constexpr bool DEBUG_RUN = false; struct str_data_t { - ByteCode type; + StringCode type; RString strs; int backpatch; int label_; @@ -166,21 +166,20 @@ extern BuiltinFunction builtin_functions[]; static InternPool variable_names; -enum class ByteCode : uint8_t + +template<class D> +bool first_type_is_any() { - // types and specials - NOP, POS, INT, PARAM_, FUNC_, STR, ARG, - VARIABLE, EOL, RETINFO, + return false; +} - // unary and binary operators - LOR, LAND, LE, LT, GE, GT, EQ, NE, - XOR, OR, AND, ADD, SUB, MUL, DIV, MOD, - NEG, LNOT, NOT, R_SHIFT, L_SHIFT, +template<class D, class F, class... R> +constexpr +bool first_type_is_any() +{ + return std::is_same<D, F>::value || first_type_is_any<D, R...>(); +} - // additions - // needed because FUNC is used for the actual call - FUNC_REF, -}; static str_data_t *search_strp(XString p) @@ -196,7 +195,7 @@ str_data_t *add_strp(XString p) RString p2 = p; str_data_t *datum = str_datam.init(p2); - datum->type = ByteCode::NOP; + datum->type = StringCode::NOP; datum->strs = p2; datum->backpatch = -1; datum->label_ = -1; @@ -246,13 +245,13 @@ void ScriptBuffer::add_scriptl(str_data_t *ld) switch (ld->type) { - case ByteCode::POS: + case StringCode::POS: add_scriptc(ByteCode::POS); add_scriptb(static_cast<uint8_t>(ld->label_)); add_scriptb(static_cast<uint8_t>(ld->label_ >> 8)); add_scriptb(static_cast<uint8_t>(ld->label_ >> 16)); break; - case ByteCode::NOP: + case StringCode::NOP: // need to set backpatch, because it might become a label later add_scriptc(ByteCode::VARIABLE); ld->backpatch = script_buf.size(); @@ -260,17 +259,17 @@ void ScriptBuffer::add_scriptl(str_data_t *ld) add_scriptb(static_cast<uint8_t>(backpatch >> 8)); add_scriptb(static_cast<uint8_t>(backpatch >> 16)); break; - case ByteCode::INT: + case StringCode::INT: add_scripti(ld->val); break; - case ByteCode::FUNC_: + case StringCode::FUNC: add_scriptc(ByteCode::FUNC_REF); add_scriptb(static_cast<uint8_t>(ld->val)); add_scriptb(static_cast<uint8_t>(ld->val >> 8)); add_scriptb(static_cast<uint8_t>(ld->val >> 16)); break; - case ByteCode::PARAM_: - add_scriptc(ByteCode::PARAM_); + case StringCode::PARAM: + add_scriptc(ByteCode::PARAM); add_scriptb(static_cast<uint8_t>(ld->val)); add_scriptb(static_cast<uint8_t>(ld->val >> 8)); add_scriptb(static_cast<uint8_t>(ld->val >> 16)); @@ -288,7 +287,7 @@ void ScriptBuffer::set_label(str_data_t *ld, int pos_) { int next; - ld->type = ByteCode::POS; + ld->type = StringCode::POS; ld->label_ = pos_; for (int i = ld->backpatch; i >= 0 && i != 0x00ffffff; i = next) { @@ -482,7 +481,7 @@ ZString::iterator ScriptBuffer::parse_simpleexpr(ZString::iterator p) parse_cmd_if++; p = p2; - if (ld->type != ByteCode::FUNC_ && *p == '[') + if (ld->type != StringCode::FUNC && *p == '[') { // array(name[i] => getelementofarray(name,i) ) add_scriptl(search_strp("getelementofarray"_s)); @@ -496,7 +495,7 @@ ZString::iterator ScriptBuffer::parse_simpleexpr(ZString::iterator p) exit(1); } p++; - add_scriptc(ByteCode::FUNC_); + add_scriptc(ByteCode::FUNC); } else add_scriptl(ld); @@ -543,7 +542,7 @@ ZString::iterator ScriptBuffer::parse_subexpr(ZString::iterator p, int limit) (op = ByteCode::MUL, opl = 7, len = 1, *p == '*') || (op = ByteCode::DIV, opl = 7, len = 1, *p == '/') || (op = ByteCode::MOD, opl = 7, len = 1, *p == '%') || - (op = ByteCode::FUNC_, opl = 8, len = 1, *p == '(') || + (op = ByteCode::FUNC, opl = 8, len = 1, *p == '(') || (op = ByteCode::LAND, opl = 1, len = 2, *p == '&' && p[1] == '&') || (op = ByteCode::AND, opl = 5, len = 1, *p == '&') || (op = ByteCode::LOR, opl = 0, len = 2, *p == '|' && p[1] == '|') || @@ -559,13 +558,13 @@ ZString::iterator ScriptBuffer::parse_subexpr(ZString::iterator p, int limit) (op = ByteCode::LT, opl = 2, len = 1, *p == '<')) && opl > limit) { p += len; - if (op == ByteCode::FUNC_) + if (op == ByteCode::FUNC) { int i = 0; str_data_t *funcp = parse_cmdp; ZString::iterator plist[128]; - if (funcp->type != ByteCode::FUNC_) + if (funcp->type != StringCode::FUNC) { disp_error_message("expect function"_s, tmpp); exit(0); @@ -595,7 +594,7 @@ ZString::iterator ScriptBuffer::parse_subexpr(ZString::iterator p, int limit) } p++; - if (funcp->type == ByteCode::FUNC_ + if (funcp->type == StringCode::FUNC && script_config.warn_func_mismatch_paramnum) { ZString arg = builtin_functions[funcp->val].arg; @@ -667,10 +666,9 @@ ZString::iterator ScriptBuffer::parse_line(ZString::iterator p, bool *can_step) p = skip_space(p); str_data_t *cmd = parse_cmdp; - if (cmd->type != ByteCode::FUNC_) + if (cmd->type != StringCode::FUNC) { disp_error_message("expect command"_s, p2); -// exit(0); } { @@ -713,9 +711,9 @@ ZString::iterator ScriptBuffer::parse_line(ZString::iterator p, bool *can_step) disp_error_message("need ';'"_s, p); exit(1); } - add_scriptc(ByteCode::FUNC_); + add_scriptc(ByteCode::FUNC); - if (cmd->type == ByteCode::FUNC_ + if (cmd->type == StringCode::FUNC && script_config.warn_cmd_mismatch_paramnum) { ZString arg = builtin_functions[cmd->val].arg; @@ -748,7 +746,7 @@ void add_builtin_functions(void) for (int i = 0; builtin_functions[i].func; i++) { str_data_t *n = add_strp(builtin_functions[i].name); - n->type = ByteCode::FUNC_; + n->type = StringCode::FUNC; n->val = i; } } @@ -806,7 +804,7 @@ bool read_constdb(ZString filename) continue; } str_data_t *n = add_strp(name); - n->type = type ? ByteCode::PARAM_ : ByteCode::INT; + n->type = type ? StringCode::PARAM : StringCode::INT; n->val = val; } return rv; @@ -832,15 +830,15 @@ void ScriptBuffer::parse_script(ZString src, int line, bool implicit_end) add_builtin_functions(); } first = 0; - LABEL_NEXTLINE_.type = ByteCode::NOP; + LABEL_NEXTLINE_.type = StringCode::NOP; LABEL_NEXTLINE_.backpatch = -1; LABEL_NEXTLINE_.label_ = -1; for (auto& pair : str_datam) { str_data_t& dit = pair.second; - if (dit.type == ByteCode::POS || dit.type == ByteCode::VARIABLE) + if (dit.type == StringCode::POS || dit.type == StringCode::VARIABLE) { - dit.type = ByteCode::NOP; + dit.type = StringCode::NOP; dit.backpatch = -1; dit.label_ = -1; } @@ -876,8 +874,8 @@ void ScriptBuffer::parse_script(ZString src, int line, bool implicit_end) ZString::iterator tmpp = skip_word(p); XString str(&*p, &*tmpp, nullptr); str_data_t *ld = add_strp(str); - bool e1 = ld->type != ByteCode::NOP; - bool e2 = ld->type == ByteCode::POS; + bool e1 = ld->type != StringCode::NOP; + bool e2 = ld->type == StringCode::POS; bool e3 = ld->label_ != -1; assert (e1 == e2 && e2 == e3); if (e3) @@ -901,7 +899,7 @@ void ScriptBuffer::parse_script(ZString src, int line, bool implicit_end) add_scriptc(ByteCode::EOL); set_label(&LABEL_NEXTLINE_, script_buf.size()); - LABEL_NEXTLINE_.type = ByteCode::NOP; + LABEL_NEXTLINE_.type = StringCode::NOP; LABEL_NEXTLINE_.backpatch = -1; LABEL_NEXTLINE_.label_ = -1; } @@ -916,9 +914,9 @@ void ScriptBuffer::parse_script(ZString src, int line, bool implicit_end) for (auto& pair : str_datam) { str_data_t& sit = pair.second; - if (sit.type == ByteCode::NOP) + if (sit.type == StringCode::NOP) { - sit.type = ByteCode::VARIABLE; + sit.type = StringCode::VARIABLE; sit.label_ = 0; // anything but -1. Shouldn't matter, but helps asserts. size_t pool_index = variable_names.intern(sit.strs); for (int next, j = sit.backpatch; j >= 0 && j != 0x00ffffff; j = next) @@ -999,76 +997,82 @@ dumb_ptr<map_session_data> script_rid2sd(ScriptState *st) static void get_val(dumb_ptr<map_session_data> sd, struct script_data *data) { - if (data->type == ByteCode::PARAM_) + MATCH (*data) { - if (sd == nullptr) - PRINTF("get_val error param SP::%d\n"_fmt, data->u.reg.sp()); - data->type = ByteCode::INT; - if (sd) - data->u.numi = pc_readparam(sd, data->u.reg.sp()); - } - else if (data->type == ByteCode::VARIABLE) - { - ZString name_ = variable_names.outtern(data->u.reg.base()); - VarName name = stringish<VarName>(name_); - char prefix = name.front(); - char postfix = name.back(); - - if (prefix != '$') + CASE (const ScriptDataParam&, u) { if (sd == nullptr) - PRINTF("get_val error name?:%s\n"_fmt, name); + PRINTF("get_val error param SP::%d\n"_fmt, u.reg.sp()); + int numi = 0; + if (sd) + numi = pc_readparam(sd, u.reg.sp()); + *data = ScriptDataInt{numi}; } - if (postfix == '$') + CASE (const ScriptDataVariable&, u) { - data->type = ByteCode::STR; - if (prefix == '@') + ZString name_ = variable_names.outtern(u.reg.base()); + VarName name = stringish<VarName>(name_); + char prefix = name.front(); + char postfix = name.back(); + + if (prefix != '$') { - if (sd) - data->u.str = dumb_string::copys(pc_readregstr(sd, data->u.reg)); + if (sd == nullptr) + PRINTF("get_val error name?:%s\n"_fmt, name); } - else if (prefix == '$') + if (postfix == '$') { - RString *s = mapregstr_db.search(data->u.reg); - data->u.str = s ? dumb_string::copys(*s) : dumb_string(); + dumb_string str; + if (prefix == '@') + { + if (sd) + str = dumb_string::copys(pc_readregstr(sd, u.reg)); + } + else if (prefix == '$') + { + RString *s = mapregstr_db.search(u.reg); + str = s ? dumb_string::copys(*s) : dumb_string(); + } + else + { + PRINTF("script: get_val: illegal scope string variable.\n"_fmt); + str = dumb_string::copys("!!ERROR!!"_s); + } + if (!str) + str = dumb_string::copys(""_s); + *data = ScriptDataStr{str}; } else { - PRINTF("script: get_val: illegal scope string variable.\n"_fmt); - data->u.str = dumb_string::copys("!!ERROR!!"_s); - } - if (!data->u.str) - data->u.str = dumb_string::copys(""_s); - } - else - { - data->type = ByteCode::INT; - if (prefix == '@') - { - if (sd) - data->u.numi = pc_readreg(sd, data->u.reg); - } - else if (prefix == '$') - { - data->u.numi = mapreg_db.get(data->u.reg); - } - else if (prefix == '#') - { - if (name[1] == '#') + int numi = 0; + if (prefix == '@') { if (sd) - data->u.numi = pc_readaccountreg2(sd, name); + numi = pc_readreg(sd, u.reg); + } + else if (prefix == '$') + { + numi = mapreg_db.get(u.reg); + } + else if (prefix == '#') + { + if (name[1] == '#') + { + if (sd) + numi = pc_readaccountreg2(sd, name); + } + else + { + if (sd) + numi = pc_readaccountreg(sd, name); + } } else { if (sd) - data->u.numi = pc_readaccountreg(sd, name); + numi = pc_readglobalreg(sd, name); } - } - else - { - if (sd) - data->u.numi = pc_readglobalreg(sd, name); + *data = ScriptDataInt{numi}; } } } @@ -1088,9 +1092,7 @@ void get_val(ScriptState *st, struct script_data *data) static struct script_data get_val2(ScriptState *st, SIR reg) { - struct script_data dat; - dat.type = ByteCode::VARIABLE; - dat.u.reg = reg; + struct script_data dat = ScriptDataVariable{reg}; get_val(st, &dat); return dat; } @@ -1100,16 +1102,15 @@ struct script_data get_val2(ScriptState *st, SIR reg) *------------------------------------------ */ static -void set_reg(dumb_ptr<map_session_data> sd, ByteCode type, SIR reg, struct script_data vd) +void set_reg(dumb_ptr<map_session_data> sd, VariableCode type, SIR reg, struct script_data vd) { - if (type == ByteCode::PARAM_) + if (type == VariableCode::PARAM) { - assert (vd.type == ByteCode::INT); - int val = vd.u.numi; + int val = vd.get_if<ScriptDataInt>()->numi; pc_setparam(sd, reg.sp(), val); return; } - assert (type == ByteCode::VARIABLE); + assert (type == VariableCode::VARIABLE); ZString name_ = variable_names.outtern(reg.base()); VarName name = stringish<VarName>(name_); @@ -1118,7 +1119,7 @@ void set_reg(dumb_ptr<map_session_data> sd, ByteCode type, SIR reg, struct scrip if (postfix == '$') { - dumb_string str = vd.u.str; + dumb_string str = vd.get_if<ScriptDataStr>()->str; if (prefix == '@') { pc_setregstr(sd, reg, str.str()); @@ -1134,8 +1135,7 @@ void set_reg(dumb_ptr<map_session_data> sd, ByteCode type, SIR reg, struct scrip } else { - // 数値 - int val = vd.u.numi; + int val = vd.get_if<ScriptDataInt>()->numi; if (prefix == '@') { pc_setreg(sd, reg, val); @@ -1159,20 +1159,16 @@ void set_reg(dumb_ptr<map_session_data> sd, ByteCode type, SIR reg, struct scrip } static -void set_reg(dumb_ptr<map_session_data> sd, ByteCode type, SIR reg, int id) +void set_reg(dumb_ptr<map_session_data> sd, VariableCode type, SIR reg, int id) { - struct script_data vd; - vd.type = ByteCode::INT; - vd.u.numi = id; + struct script_data vd = ScriptDataInt{id}; set_reg(sd, type, reg, vd); } static -void set_reg(dumb_ptr<map_session_data> sd, ByteCode type, SIR reg, dumb_string zd) +void set_reg(dumb_ptr<map_session_data> sd, VariableCode type, SIR reg, dumb_string zd) { - struct script_data vd; - vd.type = ByteCode::STR; - vd.u.str = zd; + struct script_data vd = ScriptDataStr{zd}; set_reg(sd, type, reg, vd); } @@ -1184,14 +1180,13 @@ static __attribute__((warn_unused_result)) dumb_string conv_str(ScriptState *st, struct script_data *data) { get_val(st, data); - assert (data->type != ByteCode::RETINFO); - if (data->type == ByteCode::INT) + assert (!data->is<ScriptDataRetInfo>()); + if (auto *u = data->get_if<ScriptDataInt>()) { - AString buf = STRPRINTF("%d"_fmt, data->u.numi); - data->type = ByteCode::STR; - data->u.str = dumb_string::copys(buf); + AString buf = STRPRINTF("%d"_fmt, u->numi); + *data = ScriptDataStr{dumb_string::copys(buf)}; } - return data->u.str; + return data->get_if<ScriptDataStr>()->str; } /*========================================== @@ -1202,106 +1197,87 @@ static __attribute__((warn_unused_result)) int conv_num(ScriptState *st, struct script_data *data) { get_val(st, data); - assert (data->type != ByteCode::RETINFO); - if (data->type == ByteCode::STR) + assert (!data->is<ScriptDataRetInfo>()); + if (auto *u = data->get_if<ScriptDataStr>()) { - dumb_string p = data->u.str; - data->u.numi = atoi(p.c_str()); + dumb_string p = u->str; + *data = ScriptDataInt{atoi(p.c_str())}; p.delete_(); - data->type = ByteCode::INT; } - return data->u.numi; + // TODO see if I also need to return for other types? + return data->get_if<ScriptDataInt>()->numi; } static __attribute__((warn_unused_result)) const ScriptBuffer *conv_script(ScriptState *st, struct script_data *data) { get_val(st, data); - assert (data->type == ByteCode::RETINFO); - return data->u.script; + return data->get_if<ScriptDataRetInfo>()->script; } -/*========================================== - * スタックへ数値をプッシュ - *------------------------------------------ - */ + +template<class T> static -void push_int(struct script_stack *stack, ByteCode type, int val) +void push_int(struct script_stack *stack, int val) { - assert (type == ByteCode::POS || type == ByteCode::INT || type == ByteCode::ARG || type == ByteCode::FUNC_REF); + static_assert(first_type_is_any<T, ScriptDataPos, ScriptDataInt, ScriptDataArg, ScriptDataFuncRef>(), "not int type"); - script_data nsd {}; - nsd.type = type; - nsd.u.numi = val; + script_data nsd = T{.numi= val}; stack->stack_datav.push_back(nsd); } +template<class T> static -void push_reg(struct script_stack *stack, ByteCode type, SIR reg) +void push_reg(struct script_stack *stack, SIR reg) { - assert (type == ByteCode::PARAM_ || type == ByteCode::VARIABLE); + static_assert(first_type_is_any<T, ScriptDataParam, ScriptDataVariable>(), "not reg type"); - script_data nsd {}; - nsd.type = type; - nsd.u.reg = reg; + script_data nsd = T{.reg= reg}; stack->stack_datav.push_back(nsd); } +template<class T> static -void push_script(struct script_stack *stack, ByteCode type, const ScriptBuffer *code) +void push_script(struct script_stack *stack, const ScriptBuffer *code) { - assert (type == ByteCode::RETINFO); + static_assert(first_type_is_any<T, ScriptDataRetInfo>(), "not scriptbuf type"); - script_data nsd {}; - nsd.type = type; - nsd.u.script = code; + script_data nsd = T{.script= code}; stack->stack_datav.push_back(nsd); } -/*========================================== - * スタックへ文字列をプッシュ - *------------------------------------------ - */ +template<class T> static -void push_str(struct script_stack *stack, ByteCode type, dumb_string str) +void push_str(struct script_stack *stack, dumb_string str) { - assert (type == ByteCode::STR); + static_assert(first_type_is_any<T, ScriptDataStr>(), "not str type"); - script_data nsd {}; - nsd.type = type; - nsd.u.str = str; + script_data nsd = T{.str= str}; stack->stack_datav.push_back(nsd); } -/*========================================== - * スタックへ複製をプッシュ - *------------------------------------------ - */ static void push_copy(struct script_stack *stack, int pos_) { script_data csd = stack->stack_datav[pos_]; - if (csd.type == ByteCode::STR) - csd.u.str = csd.u.str.dup(); + if (auto *u = csd.get_if<ScriptDataStr>()) + u->str = u->str.dup(); stack->stack_datav.push_back(csd); } -/*========================================== - * スタックからポップ - *------------------------------------------ - */ static void pop_stack(struct script_stack *stack, int start, int end) { for (int i = start; i < end; i++) { - if (stack->stack_datav[i].type == ByteCode::STR) - stack->stack_datav[i].u.str.delete_(); + if (auto *u = stack->stack_datav[i].get_if<ScriptDataStr>()) + u->str.delete_(); } auto it = stack->stack_datav.begin(); stack->stack_datav.erase(it + start, it + end); } + #define AARGO2(n) (st->stack->stack_datav[st->start + (n)]) #define HARGO2(n) (st->end > st->start + (n)) @@ -1326,7 +1302,7 @@ void builtin_mes(ScriptState *st) static void builtin_goto(ScriptState *st) { - if (AARGO2(2).type != ByteCode::POS) + if (!AARGO2(2).is<ScriptDataPos>()) { PRINTF("script: goto: not label !\n"_fmt); st->state = ScriptEndState::END; @@ -1356,10 +1332,10 @@ void builtin_callfunc(ScriptState *st) push_copy(st->stack, i); #endif - push_int(st->stack, ByteCode::INT, j); // 引数の数をプッシュ - push_int(st->stack, ByteCode::INT, st->defsp); // 現在の基準スタックポインタをプッシュ - push_int(st->stack, ByteCode::INT, st->scriptp.pos); // 現在のスクリプト位置をプッシュ - push_script(st->stack, ByteCode::RETINFO, st->scriptp.code); // 現在のスクリプトをプッシュ + push_int<ScriptDataInt>(st->stack, j); // 引数の数をプッシュ + push_int<ScriptDataInt>(st->stack, st->defsp); // 現在の基準スタックポインタをプッシュ + push_int<ScriptDataInt>(st->stack, st->scriptp.pos); // 現在のスクリプト位置をプッシュ + push_script<ScriptDataRetInfo>(st->stack, st->scriptp.code); // 現在のスクリプトをプッシュ st->scriptp = ScriptPointer(scr, 0); st->defsp = st->start + 4 + j; @@ -1387,10 +1363,10 @@ void builtin_callsub(ScriptState *st) push_copy(st->stack, i); #endif - push_int(st->stack, ByteCode::INT, j); // 引数の数をプッシュ - push_int(st->stack, ByteCode::INT, st->defsp); // 現在の基準スタックポインタをプッシュ - push_int(st->stack, ByteCode::INT, st->scriptp.pos); // 現在のスクリプト位置をプッシュ - push_script(st->stack, ByteCode::RETINFO, st->scriptp.code); // 現在のスクリプトをプッシュ + push_int<ScriptDataInt>(st->stack, j); // 引数の数をプッシュ + push_int<ScriptDataInt>(st->stack, st->defsp); // 現在の基準スタックポインタをプッシュ + push_int<ScriptDataInt>(st->stack, st->scriptp.pos); // 現在のスクリプト位置をプッシュ + push_script<ScriptDataRetInfo>(st->stack, st->scriptp.code); // 現在のスクリプトをプッシュ st->scriptp.pos = pos_; st->defsp = st->start + 4 + j; @@ -1490,12 +1466,12 @@ void builtin_menu(ScriptState *st) if (sd->npc_menu > 0 && sd->npc_menu <= menu_choices) { int arg_index = (sd->npc_menu - 1) * 2 + 1; - if (AARGO2(arg_index + 2).type != ByteCode::POS) + if (!AARGO2(arg_index + 2).is<ScriptDataPos>()) { st->state = ScriptEndState::END; return; } - st->scriptp.pos = conv_num(st, &AARGO2(arg_index + 2)); + st->scriptp.pos = AARGO2(arg_index + 2).get_if<ScriptDataPos>()->numi; st->state = ScriptEndState::GOTO; } } @@ -1514,12 +1490,12 @@ void builtin_rand(ScriptState *st) int max = conv_num(st, &AARGO2(3)); if (min > max) std::swap(max, min); - push_int(st->stack, ByteCode::INT, random_::in(min, max)); + push_int<ScriptDataInt>(st->stack, random_::in(min, max)); } else { int range = conv_num(st, &AARGO2(2)); - push_int(st->stack, ByteCode::INT, range <= 0 ? 0 : random_::to(range)); + push_int<ScriptDataInt>(st->stack, range <= 0 ? 0 : random_::to(range)); } } @@ -1540,7 +1516,7 @@ void builtin_isat(ScriptState *st) if (!sd) return; - push_int(st->stack, ByteCode::INT, + push_int<ScriptDataInt>(st->stack, (x == sd->bl_x) && (y == sd->bl_y) && (str == sd->bl_m->name_)); } @@ -1663,10 +1639,9 @@ void builtin_input(ScriptState *st) { dumb_ptr<map_session_data> sd = nullptr; script_data& scrd = AARGO2(2); - ByteCode type = scrd.type; - assert (type == ByteCode::VARIABLE); + assert (scrd.is<ScriptDataVariable>()); - SIR reg = scrd.u.reg; + SIR reg = scrd.get_if<ScriptDataVariable>()->reg; ZString name = variable_names.outtern(reg.base()); // char prefix = name.front(); char postfix = name.back(); @@ -1678,7 +1653,7 @@ void builtin_input(ScriptState *st) sd->state.menu_or_input = 0; if (postfix == '$') { - set_reg(sd, type, reg, dumb_string::copys(sd->npc_str)); + set_reg(sd, VariableCode::VARIABLE, reg, dumb_string::copys(sd->npc_str)); } else { @@ -1691,7 +1666,7 @@ void builtin_input(ScriptState *st) builtin_close(st); //** close } - set_reg(sd, type, reg, sd->npc_amount); + set_reg(sd, VariableCode::VARIABLE, reg, sd->npc_amount); } } else @@ -1722,7 +1697,7 @@ void builtin_if (ScriptState *st) // 関数名をコピー push_copy(st->stack, st->start + 3); // 間に引数マーカを入れて - push_int(st->stack, ByteCode::ARG, 0); + push_int<ScriptDataArg>(st->stack, 0); // 残りの引数をコピー for (i = st->start + 4; i < st->end; i++) { @@ -1739,21 +1714,22 @@ static void builtin_set(ScriptState *st) { dumb_ptr<map_session_data> sd = nullptr; - SIR reg = AARGO2(2).u.reg; - if (AARGO2(2).type == ByteCode::PARAM_) + if (auto *u = AARGO2(2).get_if<ScriptDataParam>()) { + SIR reg = u->reg; sd = script_rid2sd(st); int val = conv_num(st, &AARGO2(3)); - set_reg(sd, ByteCode::PARAM_, reg, val); + set_reg(sd, VariableCode::PARAM, reg, val); return; } + + SIR reg = AARGO2(2).get_if<ScriptDataVariable>()->reg; + ZString name = variable_names.outtern(reg.base()); char prefix = name.front(); char postfix = name.back(); - assert (AARGO2(2).type == ByteCode::VARIABLE); - if (prefix != '$') sd = script_rid2sd(st); @@ -1761,13 +1737,13 @@ void builtin_set(ScriptState *st) { // 文字列 dumb_string str = conv_str(st, &AARGO2(3)); - set_reg(sd, ByteCode::VARIABLE, reg, str); + set_reg(sd, VariableCode::VARIABLE, reg, str); } else { // 数値 int val = conv_num(st, &AARGO2(3)); - set_reg(sd, ByteCode::VARIABLE, reg, val); + set_reg(sd, VariableCode::VARIABLE, reg, val); } } @@ -1780,8 +1756,7 @@ static void builtin_setarray(ScriptState *st) { dumb_ptr<map_session_data> sd = nullptr; - assert (AARGO2(2).type == ByteCode::VARIABLE); - SIR reg = AARGO2(2).u.reg; + SIR reg = AARGO2(2).get_if<ScriptDataVariable>()->reg; ZString name = variable_names.outtern(reg.base()); char prefix = name.front(); char postfix = name.back(); @@ -1797,9 +1772,9 @@ void builtin_setarray(ScriptState *st) for (int j = 0, i = st->start + 3; i < st->end && j < 256; i++, j++) { if (postfix == '$') - set_reg(sd, ByteCode::VARIABLE, reg.iplus(j), conv_str(st, &AARGO2(i - st->start))); + set_reg(sd, VariableCode::VARIABLE, reg.iplus(j), conv_str(st, &AARGO2(i - st->start))); else - set_reg(sd, ByteCode::VARIABLE, reg.iplus(j), conv_num(st, &AARGO2(i - st->start))); + set_reg(sd, VariableCode::VARIABLE, reg.iplus(j), conv_num(st, &AARGO2(i - st->start))); } } @@ -1811,8 +1786,7 @@ static void builtin_cleararray(ScriptState *st) { dumb_ptr<map_session_data> sd = nullptr; - assert (AARGO2(2).type == ByteCode::VARIABLE); - SIR reg = AARGO2(2).u.reg; + SIR reg = AARGO2(2).get_if<ScriptDataVariable>()->reg; ZString name = variable_names.outtern(reg.base()); char prefix = name.front(); char postfix = name.back(); @@ -1829,9 +1803,9 @@ void builtin_cleararray(ScriptState *st) for (int i = 0; i < sz; i++) { if (postfix == '$') - set_reg(sd, ByteCode::VARIABLE, reg.iplus(i), conv_str(st, &AARGO2(3))); + set_reg(sd, VariableCode::VARIABLE, reg.iplus(i), conv_str(st, &AARGO2(3))); else - set_reg(sd, ByteCode::VARIABLE, reg.iplus(i), conv_num(st, &AARGO2(3))); + set_reg(sd, VariableCode::VARIABLE, reg.iplus(i), conv_num(st, &AARGO2(3))); } } @@ -1841,15 +1815,28 @@ void builtin_cleararray(ScriptState *st) *------------------------------------------ */ static -int getarraysize(ScriptState *st, SIR reg, bool is_string) +int getarraysize(ScriptState *st, SIR reg) { int i = reg.index(), c = i; for (; i < 256; i++) { - // This is obviously not what was intended struct script_data vd = get_val2(st, reg.iplus(i)); - if (is_string ? bool(vd.u.str[0]) : bool(vd.u.numi)) - c = i; + MATCH (vd) + { + CASE (const ScriptDataStr&, u) + { + if (u.str[0]) + c = i; + continue; + } + CASE (const ScriptDataInt&, u) + { + if (u.numi) + c = i; + continue; + } + } + abort(); } return c + 1; } @@ -1857,11 +1844,9 @@ int getarraysize(ScriptState *st, SIR reg, bool is_string) static void builtin_getarraysize(ScriptState *st) { - assert (AARGO2(2).type == ByteCode::VARIABLE); - SIR reg = AARGO2(2).u.reg; + SIR reg = AARGO2(2).get_if<ScriptDataVariable>()->reg; ZString name = variable_names.outtern(reg.base()); char prefix = name.front(); - char postfix = name.back(); if (prefix != '$' && prefix != '@') { @@ -1869,7 +1854,7 @@ void builtin_getarraysize(ScriptState *st) return; } - push_int(st->stack, ByteCode::INT, getarraysize(st, reg, postfix == '$')); + push_int<ScriptDataInt>(st->stack, getarraysize(st, reg)); } /*========================================== @@ -1879,25 +1864,25 @@ void builtin_getarraysize(ScriptState *st) static void builtin_getelementofarray(ScriptState *st) { - if (AARGO2(2).type == ByteCode::VARIABLE) + if (auto *u = AARGO2(2).get_if<ScriptDataVariable>()) { int i = conv_num(st, &AARGO2(3)); if (i > 255 || i < 0) { PRINTF("script: getelementofarray (operator[]): param2 illegal number %d\n"_fmt, i); - push_int(st->stack, ByteCode::INT, 0); + push_int<ScriptDataInt>(st->stack, 0); } else { - push_reg(st->stack, ByteCode::VARIABLE, - AARGO2(2).u.reg.iplus(i)); + push_reg<ScriptDataVariable>(st->stack, + u->reg.iplus(i)); } } else { PRINTF("script: getelementofarray (operator[]): param1 not name !\n"_fmt); - push_int(st->stack, ByteCode::INT, 0); + push_int<ScriptDataInt>(st->stack, 0); } } @@ -1932,7 +1917,7 @@ void builtin_countitem(ScriptState *st) data = &AARGO2(2); get_val(st, data); - if (data->type == ByteCode::STR) + if (data->is<ScriptDataStr>()) { ZString name = ZString(conv_str(st, data)); struct item_data *item_data = itemdb_searchname(name); @@ -1955,7 +1940,7 @@ void builtin_countitem(ScriptState *st) if (battle_config.error_log) PRINTF("wrong item ID : countitem (%i)\n"_fmt, nameid); } - push_int(st->stack, ByteCode::INT, count); + push_int<ScriptDataInt>(st->stack, count); } @@ -1975,7 +1960,7 @@ void builtin_checkweight(ScriptState *st) data = &AARGO2(2); get_val(st, data); - if (data->type == ByteCode::STR) + if (data->is<ScriptDataStr>()) { ZString name = ZString(conv_str(st, data)); struct item_data *item_data = itemdb_searchname(name); @@ -1989,17 +1974,17 @@ void builtin_checkweight(ScriptState *st) if (amount <= 0 || !nameid) { //if get wrong item ID or amount<=0, don't count weight of non existing items - push_int(st->stack, ByteCode::INT, 0); + push_int<ScriptDataInt>(st->stack, 0); return; } if (itemdb_weight(nameid) * amount + sd->weight > sd->max_weight) { - push_int(st->stack, ByteCode::INT, 0); + push_int<ScriptDataInt>(st->stack, 0); } else { - push_int(st->stack, ByteCode::INT, 1); + push_int<ScriptDataInt>(st->stack, 1); } } @@ -2020,7 +2005,7 @@ void builtin_getitem(ScriptState *st) data = &AARGO2(2); get_val(st, data); - if (data->type == ByteCode::STR) + if (data->is<ScriptDataStr>()) { ZString name = ZString(conv_str(st, data)); struct item_data *item_data = itemdb_searchname(name); @@ -2073,7 +2058,7 @@ void builtin_makeitem(ScriptState *st) data = &AARGO2(2); get_val(st, data); - if (data->type == ByteCode::STR) + if (data->is<ScriptDataStr>()) { ZString name = ZString(conv_str(st, data)); struct item_data *item_data = itemdb_searchname(name); @@ -2119,7 +2104,7 @@ void builtin_delitem(ScriptState *st) data = &AARGO2(2); get_val(st, data); - if (data->type == ByteCode::STR) + if (data->is<ScriptDataStr>()) { ZString name = ZString(conv_str(st, data)); struct item_data *item_data = itemdb_searchname(name); @@ -2176,11 +2161,11 @@ void builtin_readparam(ScriptState *st) if (sd == nullptr) { - push_int(st->stack, ByteCode::INT, -1); + push_int<ScriptDataInt>(st->stack, -1); return; } - push_int(st->stack, ByteCode::INT, pc_readparam(sd, type)); + push_int<ScriptDataInt>(st->stack, pc_readparam(sd, type)); } @@ -2201,17 +2186,17 @@ void builtin_getcharid(ScriptState *st) sd = script_rid2sd(st); if (sd == nullptr) { - push_int(st->stack, ByteCode::INT, -1); + push_int<ScriptDataInt>(st->stack, -1); return; } if (num == 0) - push_int(st->stack, ByteCode::INT, unwrap<CharId>(sd->status_key.char_id)); + push_int<ScriptDataInt>(st->stack, unwrap<CharId>(sd->status_key.char_id)); if (num == 1) - push_int(st->stack, ByteCode::INT, unwrap<PartyId>(sd->status.party_id)); + push_int<ScriptDataInt>(st->stack, unwrap<PartyId>(sd->status.party_id)); if (num == 2) - push_int(st->stack, ByteCode::INT, 0/*guild_id*/); + push_int<ScriptDataInt>(st->stack, 0/*guild_id*/); if (num == 3) - push_int(st->stack, ByteCode::INT, unwrap<AccountId>(sd->status_key.account_id)); + push_int<ScriptDataInt>(st->stack, unwrap<AccountId>(sd->status_key.account_id)); } /*========================================== @@ -2244,20 +2229,20 @@ void builtin_strcharinfo(ScriptState *st) if (num == 0) { dumb_string buf = dumb_string::copys(sd->status_key.name.to__actual()); - push_str(st->stack, ByteCode::STR, buf); + push_str<ScriptDataStr>(st->stack, buf); } if (num == 1) { dumb_string buf = builtin_getpartyname_sub(sd->status.party_id); if (buf) - push_str(st->stack, ByteCode::STR, buf); + push_str<ScriptDataStr>(st->stack, buf); else - push_str(st->stack, ByteCode::STR, dumb_string::copys(""_s)); + push_str<ScriptDataStr>(st->stack, dumb_string::copys(""_s)); } if (num == 2) { // was: guild name - push_str(st->stack, ByteCode::STR, dumb_string::copys(""_s)); + push_str<ScriptDataStr>(st->stack, dumb_string::copys(""_s)); } } @@ -2303,13 +2288,13 @@ void builtin_getequipid(ScriptState *st) { item = sd->inventory_data[i]; if (item) - push_int(st->stack, ByteCode::INT, unwrap<ItemNameId>(item->nameid)); + push_int<ScriptDataInt>(st->stack, unwrap<ItemNameId>(item->nameid)); else - push_int(st->stack, ByteCode::INT, 0); + push_int<ScriptDataInt>(st->stack, 0); } else { - push_int(st->stack, ByteCode::INT, -1); + push_int<ScriptDataInt>(st->stack, -1); } } @@ -2341,7 +2326,7 @@ void builtin_getequipname(ScriptState *st) { buf = STRPRINTF("%s-[%s]"_fmt, pos_str[num - 1], pos_str[10]); } - push_str(st->stack, ByteCode::STR, dumb_string::copys(buf)); + push_str<ScriptDataStr>(st->stack, dumb_string::copys(buf)); } @@ -2434,7 +2419,7 @@ static void builtin_getskilllv(ScriptState *st) { SkillID id = SkillID(conv_num(st, &AARGO2(2))); - push_int(st->stack, ByteCode::INT, pc_checkskill(script_rid2sd(st), id)); + push_int<ScriptDataInt>(st->stack, pc_checkskill(script_rid2sd(st), id)); } /*========================================== @@ -2444,7 +2429,7 @@ void builtin_getskilllv(ScriptState *st) static void builtin_getgmlevel(ScriptState *st) { - push_int(st->stack, ByteCode::INT, pc_isGM(script_rid2sd(st)).get_all_bits()); + push_int<ScriptDataInt>(st->stack, pc_isGM(script_rid2sd(st)).get_all_bits()); } /*========================================== @@ -2469,7 +2454,7 @@ void builtin_getopt2(ScriptState *st) sd = script_rid2sd(st); - push_int(st->stack, ByteCode::INT, static_cast<uint16_t>(sd->opt2)); + push_int<ScriptDataInt>(st->stack, static_cast<uint16_t>(sd->opt2)); } @@ -2530,18 +2515,18 @@ void builtin_gettimetick(ScriptState *st) /* Asgard Version */ case 1: { struct tm t = TimeT::now(); - push_int(st->stack, ByteCode::INT, + push_int<ScriptDataInt>(st->stack, t.tm_hour * 3600 + t.tm_min * 60 + t.tm_sec); break; } /* Seconds since Unix epoch. */ case 2: - push_int(st->stack, ByteCode::INT, static_cast<time_t>(TimeT::now())); + push_int<ScriptDataInt>(st->stack, static_cast<time_t>(TimeT::now())); break; /* System tick(unsigned int, and yes, it will wrap). */ case 0: default: - push_int(st->stack, ByteCode::INT, gettick().time_since_epoch().count()); + push_int<ScriptDataInt>(st->stack, gettick().time_since_epoch().count()); break; } } @@ -2563,28 +2548,28 @@ void builtin_gettime(ScriptState *st) /* Asgard Version */ switch (type) { case 1: //Sec(0~59) - push_int(st->stack, ByteCode::INT, t.tm_sec); + push_int<ScriptDataInt>(st->stack, t.tm_sec); break; case 2: //Min(0~59) - push_int(st->stack, ByteCode::INT, t.tm_min); + push_int<ScriptDataInt>(st->stack, t.tm_min); break; case 3: //Hour(0~23) - push_int(st->stack, ByteCode::INT, t.tm_hour); + push_int<ScriptDataInt>(st->stack, t.tm_hour); break; case 4: //WeekDay(0~6) - push_int(st->stack, ByteCode::INT, t.tm_wday); + push_int<ScriptDataInt>(st->stack, t.tm_wday); break; case 5: //MonthDay(01~31) - push_int(st->stack, ByteCode::INT, t.tm_mday); + push_int<ScriptDataInt>(st->stack, t.tm_mday); break; case 6: //Month(01~12) - push_int(st->stack, ByteCode::INT, t.tm_mon + 1); + push_int<ScriptDataInt>(st->stack, t.tm_mon + 1); break; case 7: //Year(20xx) - push_int(st->stack, ByteCode::INT, t.tm_year + 1900); + push_int<ScriptDataInt>(st->stack, t.tm_year + 1900); break; default: //(format error) - push_int(st->stack, ByteCode::INT, -1); + push_int<ScriptDataInt>(st->stack, -1); break; } } @@ -2851,7 +2836,7 @@ void builtin_getnpctimer(ScriptState *st) val = nd->scr.timer_eventv.size(); break; } - push_int(st->stack, ByteCode::INT, val); + push_int<ScriptDataInt>(st->stack, val); } /*========================================== @@ -2945,7 +2930,7 @@ void builtin_getusers(ScriptState *st) val = map_getusers(); break; } - push_int(st->stack, ByteCode::INT, val); + push_int<ScriptDataInt>(st->stack, val); } /*========================================== @@ -2959,10 +2944,10 @@ void builtin_getmapusers(ScriptState *st) map_local *m = map_mapname2mapid(str); if (m == nullptr) { - push_int(st->stack, ByteCode::INT, -1); + push_int<ScriptDataInt>(st->stack, -1); return; } - push_int(st->stack, ByteCode::INT, m->users); + push_int<ScriptDataInt>(st->stack, m->users); } /*========================================== @@ -3004,7 +2989,7 @@ void builtin_getareausers(ScriptState *st) map_local *m = map_mapname2mapid(str); if (m == nullptr) { - push_int(st->stack, ByteCode::INT, -1); + push_int<ScriptDataInt>(st->stack, -1); return; } map_foreachinarea(std::bind(living ? builtin_getareausers_living_sub: builtin_getareausers_sub, ph::_1, &users), @@ -3012,7 +2997,7 @@ void builtin_getareausers(ScriptState *st) x0, y0, x1, y1, BL::PC); - push_int(st->stack, ByteCode::INT, users); + push_int<ScriptDataInt>(st->stack, users); } /*========================================== @@ -3057,7 +3042,7 @@ void builtin_getareadropitem(ScriptState *st) data = &AARGO2(7); get_val(st, data); - if (data->type == ByteCode::STR) + if (data->is<ScriptDataStr>()) { ZString name = ZString(conv_str(st, data)); struct item_data *item_data = itemdb_searchname(name); @@ -3073,7 +3058,7 @@ void builtin_getareadropitem(ScriptState *st) map_local *m = map_mapname2mapid(str); if (m == nullptr) { - push_int(st->stack, ByteCode::INT, -1); + push_int<ScriptDataInt>(st->stack, -1); return; } if (delitems) @@ -3089,7 +3074,7 @@ void builtin_getareadropitem(ScriptState *st) x1, y1, BL::ITEM); - push_int(st->stack, ByteCode::INT, amount); + push_int<ScriptDataInt>(st->stack, amount); } /*========================================== @@ -3162,7 +3147,7 @@ void builtin_sc_check(ScriptState *st) StatusChange type = StatusChange(conv_num(st, &AARGO2(2))); bl = map_id2bl(st->rid); - push_int(st->stack, ByteCode::INT, skill_status_change_active(bl, type)); + push_int<ScriptDataInt>(st->stack, skill_status_change_active(bl, type)); } @@ -3212,7 +3197,7 @@ static void builtin_attachrid(ScriptState *st) { st->rid = wrap<BlockId>(conv_num(st, &AARGO2(2))); - push_int(st->stack, ByteCode::INT, (map_id2sd(st->rid) != nullptr)); + push_int<ScriptDataInt>(st->stack, (map_id2sd(st->rid) != nullptr)); } /*========================================== @@ -3232,7 +3217,7 @@ void builtin_detachrid(ScriptState *st) static void builtin_isloggedin(ScriptState *st) { - push_int(st->stack, ByteCode::INT, + push_int<ScriptDataInt>(st->stack, map_id2sd(wrap<BlockId>(conv_num(st, &AARGO2(2)))) != nullptr); } @@ -3276,7 +3261,7 @@ void builtin_getmapflag(ScriptState *st) r = m->flag.get(mf); } - push_int(st->stack, ByteCode::INT, r); + push_int<ScriptDataInt>(st->stack, r); } static @@ -3413,7 +3398,7 @@ void builtin_mobcount(ScriptState *st) // Added by RoVeRT map_local *m = map_mapname2mapid(mapname); if (m == nullptr) { - push_int(st->stack, ByteCode::INT, -1); + push_int<ScriptDataInt>(st->stack, -1); return; } map_foreachinarea(std::bind(builtin_mobcount_sub, ph::_1, event, &c), @@ -3422,7 +3407,7 @@ void builtin_mobcount(ScriptState *st) // Added by RoVeRT m->xs, m->ys, BL::MOB); - push_int(st->stack, ByteCode::INT, (c - 1)); + push_int<ScriptDataInt>(st->stack, (c - 1)); } @@ -3435,10 +3420,10 @@ void builtin_marriage(ScriptState *st) if (sd == nullptr || p_sd == nullptr || pc_marriage(sd, p_sd) < 0) { - push_int(st->stack, ByteCode::INT, 0); + push_int<ScriptDataInt>(st->stack, 0); return; } - push_int(st->stack, ByteCode::INT, 1); + push_int<ScriptDataInt>(st->stack, 1); } static @@ -3452,11 +3437,11 @@ void builtin_divorce(ScriptState *st) if (sd == nullptr || pc_divorce(sd) < 0) { - push_int(st->stack, ByteCode::INT, 0); + push_int<ScriptDataInt>(st->stack, 0); return; } - push_int(st->stack, ByteCode::INT, 1); + push_int<ScriptDataInt>(st->stack, 1); } /*========================================== @@ -3471,7 +3456,7 @@ void builtin_getitemname(ScriptState *st) data = &AARGO2(2); get_val(st, data); - if (data->type == ByteCode::STR) + if (data->is<ScriptDataStr>()) { ZString name = ZString(conv_str(st, data)); i_data = itemdb_searchname(name); @@ -3488,7 +3473,7 @@ void builtin_getitemname(ScriptState *st) else item_name = dumb_string::copys("Unknown Item"_s); - push_str(st->stack, ByteCode::STR, item_name); + push_str<ScriptDataStr>(st->stack, item_name); } static @@ -3500,7 +3485,7 @@ void builtin_getspellinvocation(ScriptState *st) if (!invocation) invocation = "..."_s; - push_str(st->stack, ByteCode::STR, dumb_string::copys(invocation)); + push_str<ScriptDataStr>(st->stack, dumb_string::copys(invocation)); } static @@ -3508,7 +3493,7 @@ void builtin_getpartnerid2(ScriptState *st) { dumb_ptr<map_session_data> sd = script_rid2sd(st); - push_int(st->stack, ByteCode::INT, unwrap<CharId>(sd->status.partner_id)); + push_int<ScriptDataInt>(st->stack, unwrap<CharId>(sd->status.partner_id)); } /*========================================== @@ -3650,7 +3635,7 @@ void builtin_misceffect(ScriptState *st) get_val(st, sdata); - if (sdata->type == ByteCode::STR) + if (sdata->is<ScriptDataStr>()) name = stringish<CharName>(ZString(conv_str(st, sdata))); else id = wrap<BlockId>(conv_num(st, sdata)); @@ -3895,7 +3880,7 @@ void builtin_getlook(ScriptState *st) break; } - push_int(st->stack, ByteCode::INT, val); + push_int<ScriptDataInt>(st->stack, val); } /*========================================== @@ -3919,14 +3904,14 @@ void builtin_getsavepoint(ScriptState *st) case 0: { dumb_string mapname = dumb_string::copys(sd->status.save_point.map_); - push_str(st->stack, ByteCode::STR, mapname); + push_str<ScriptDataStr>(st->stack, mapname); } break; case 1: - push_int(st->stack, ByteCode::INT, x); + push_int<ScriptDataInt>(st->stack, x); break; case 2: - push_int(st->stack, ByteCode::INT, y); + push_int<ScriptDataInt>(st->stack, y); break; } } @@ -3986,7 +3971,7 @@ void builtin_isin(ScriptState *st) if (!sd) return; - push_int(st->stack, ByteCode::INT, + push_int<ScriptDataInt>(st->stack, (sd->bl_x >= x1 && sd->bl_x <= x2) && (sd->bl_y >= y1 && sd->bl_y <= y2) && (str == sd->bl_m->name_)); @@ -4023,7 +4008,7 @@ void builtin_isdead(ScriptState *st) { dumb_ptr<map_session_data> sd = script_rid2sd(st); - push_int(st->stack, ByteCode::INT, pc_isdead(sd)); + push_int<ScriptDataInt>(st->stack, pc_isdead(sd)); } /*======================================== @@ -4060,7 +4045,7 @@ void builtin_getx(ScriptState *st) { dumb_ptr<map_session_data> sd = script_rid2sd(st); - push_int(st->stack, ByteCode::INT, sd->bl_x); + push_int<ScriptDataInt>(st->stack, sd->bl_x); } /*============================ @@ -4072,7 +4057,7 @@ void builtin_gety(ScriptState *st) { dumb_ptr<map_session_data> sd = script_rid2sd(st); - push_int(st->stack, ByteCode::INT, sd->bl_y); + push_int<ScriptDataInt>(st->stack, sd->bl_y); } /* @@ -4083,7 +4068,7 @@ void builtin_getmap(ScriptState *st) { dumb_ptr<map_session_data> sd = script_rid2sd(st); - push_str(st->stack, ByteCode::STR, dumb_string::copys(sd->bl_m->name_)); + push_str<ScriptDataStr>(st->stack, dumb_string::copys(sd->bl_m->name_)); } static @@ -4143,8 +4128,8 @@ int pop_val(ScriptState *st) script_data& back = st->stack->stack_datav.back(); get_val(st, &back); int rv = 0; - if (back.type == ByteCode::INT) - rv = back.u.numi; + if (auto *u = back.get_if<ScriptDataInt>()) + rv = u->numi; st->stack->stack_datav.pop_back(); return rv; } @@ -4152,7 +4137,7 @@ int pop_val(ScriptState *st) static bool isstr(struct script_data& c) { - return c.type == ByteCode::STR; + return c.is<ScriptDataStr>(); } /*========================================== @@ -4171,7 +4156,7 @@ void op_add(ScriptState *st) if (!(isstr(back) || isstr(back1))) { - back1.u.numi += back.u.numi; + back1.get_if<ScriptDataInt>()->numi += back.get_if<ScriptDataInt>()->numi; } else { @@ -4180,12 +4165,11 @@ void op_add(ScriptState *st) MString buf; buf += ZString(sb1); buf += ZString(sb); - if (back1.type == ByteCode::STR) - back1.u.str.delete_(); - if (back.type == ByteCode::STR) - back.u.str.delete_(); - back1.type = ByteCode::STR; - back1.u.str = dumb_string::copys(AString(buf)); + if (auto *u = back1.get_if<ScriptDataStr>()) + u->str.delete_(); + if (auto *u = back.get_if<ScriptDataStr>()) + u->str.delete_(); + back1 = ScriptDataStr{.str= dumb_string::copys(AString(buf))}; } } @@ -4225,7 +4209,7 @@ void op_2str(ScriptState *st, ByteCode op, dumb_string s1_, dumb_string s2_) break; } - push_int(st->stack, ByteCode::INT, a); + push_int<ScriptDataInt>(st->stack, a); } /*========================================== @@ -4289,7 +4273,7 @@ void op_2num(ScriptState *st, ByteCode op, int i1, int i2) i1 = i1 << i2; break; } - push_int(st->stack, ByteCode::INT, i1); + push_int<ScriptDataInt>(st->stack, i1); } /*========================================== @@ -4310,22 +4294,20 @@ void op_2(ScriptState *st, ByteCode op) if (isstr(d1) && isstr(d2)) { // ss => op_2str - op_2str(st, op, d1.u.str, d2.u.str); - if (d1.type == ByteCode::STR) - d1.u.str.delete_(); - if (d2.type == ByteCode::STR) - d2.u.str.delete_(); + op_2str(st, op, d1.get_if<ScriptDataStr>()->str, d2.get_if<ScriptDataStr>()->str); + d1.get_if<ScriptDataStr>()->str.delete_(); + d2.get_if<ScriptDataStr>()->str.delete_(); } else if (!(isstr(d1) || isstr(d2))) { // ii => op_2num - op_2num(st, op, d1.u.numi, d2.u.numi); + op_2num(st, op, d1.get_if<ScriptDataInt>()->numi, d2.get_if<ScriptDataInt>()->numi); } else { // si,is => error PRINTF("script: op_2: int&str, str&int not allow.\n"_fmt); - push_int(st->stack, ByteCode::INT, 0); + push_int<ScriptDataInt>(st->stack, 0); } } @@ -4350,7 +4332,7 @@ void op_1num(ScriptState *st, ByteCode op) i1 = !i1; break; } - push_int(st->stack, ByteCode::INT, i1); + push_int<ScriptDataInt>(st->stack, i1); } /*========================================== @@ -4361,7 +4343,7 @@ void run_func(ScriptState *st) { size_t end_sp = st->stack->stack_datav.size(); size_t start_sp = end_sp - 1; - while (st->stack->stack_datav[start_sp].type != ByteCode::ARG) + while (!st->stack->stack_datav[start_sp].is<ScriptDataArg>()) { start_sp--; if (start_sp == 0) @@ -4377,13 +4359,13 @@ void run_func(ScriptState *st) st->start = start_sp; st->end = end_sp; - size_t func = st->stack->stack_datav[st->start].u.numi; - if (st->stack->stack_datav[st->start].type != ByteCode::FUNC_REF) + if (!st->stack->stack_datav[st->start].is<ScriptDataFuncRef>()) { PRINTF("run_func: not function and command! \n"_fmt); st->state = ScriptEndState::END; return; } + size_t func = st->stack->stack_datav[st->start].get_if<ScriptDataFuncRef>()->numi; if (DEBUG_RUN && battle_config.etc_log) { @@ -4392,34 +4374,52 @@ void run_func(ScriptState *st) PRINTF("stack dump :"_fmt); for (script_data& d : st->stack->stack_datav) { - switch (d.type) + MATCH (d) { - case ByteCode::INT: - PRINTF(" int(%d)"_fmt, d.u.numi); + CASE (const ScriptDataInt&, u) + { + PRINTF(" int(%d)"_fmt, u.numi); break; - case ByteCode::RETINFO: - PRINTF(" retinfo(%p)"_fmt, static_cast<const void *>(d.u.script)); + } + CASE (const ScriptDataRetInfo&, u) + { + PRINTF(" retinfo(%p)"_fmt, static_cast<const void *>(u.script)); break; - case ByteCode::PARAM_: - PRINTF(" param(%d)"_fmt, d.u.reg.sp()); + } + CASE (const ScriptDataParam&, u) + { + PRINTF(" param(%d)"_fmt, u.reg.sp()); break; - case ByteCode::VARIABLE: - PRINTF(" name(%s)[%d]"_fmt, variable_names.outtern(d.u.reg.base()), d.u.reg.index()); + } + CASE (const ScriptDataVariable&, u) + { + PRINTF(" name(%s)[%d]"_fmt, variable_names.outtern(u.reg.base()), u.reg.index()); break; - case ByteCode::ARG: + } + CASE (const ScriptDataArg&, u) + { + (void)u; PRINTF(" arg"_fmt); break; - case ByteCode::POS: - PRINTF(" pos(%d)"_fmt, d.u.numi); + } + CASE (const ScriptDataPos&, u) + { + (void)u; + PRINTF(" pos(%d)"_fmt, u.numi); break; - case ByteCode::STR: - PRINTF(" str(%s)"_fmt, d.u.str); + } + CASE (const ScriptDataStr&, u) + { + (void)u; + PRINTF(" str(%s)"_fmt, u.str); break; - case ByteCode::FUNC_REF: - PRINTF(" func(%s)"_fmt, builtin_functions[d.u.numi].name); + } + CASE (const ScriptDataFuncRef&, u) + { + (void)u; + PRINTF(" func(%s)"_fmt, builtin_functions[u.numi].name); break; - default: - PRINTF(" %d,%d"_fmt, d.type, d.u.numi); + } } } PRINTF("\n"_fmt); @@ -4435,7 +4435,7 @@ void run_func(ScriptState *st) pop_stack(st->stack, st->defsp, start_sp); // 復帰に邪魔なスタック削除 if (st->defsp < 4 - || st->stack->stack_datav[st->defsp - 1].type != ByteCode::RETINFO) + || !st->stack->stack_datav[st->defsp - 1].is<ScriptDataRetInfo>()) { PRINTF("script:run_func (return) return without callfunc or callsub!\n"_fmt); st->state = ScriptEndState::END; @@ -4476,7 +4476,7 @@ void dump_script(const ScriptBuffer *script) case ByteCode::POS: case ByteCode::VARIABLE: case ByteCode::FUNC_REF: - case ByteCode::PARAM_: + case ByteCode::PARAM: { int arg = 0; arg |= static_cast<uint8_t>(scriptp.pop()) << 0; @@ -4493,7 +4493,7 @@ void dump_script(const ScriptBuffer *script) case ByteCode::FUNC_REF: PRINTF("FUNC_REF %s"_fmt, builtin_functions[arg].name); break; - case ByteCode::PARAM_: + case ByteCode::PARAM: PRINTF("PARAM SP::#%d (sorry)"_fmt, arg); break; } @@ -4505,8 +4505,8 @@ void dump_script(const ScriptBuffer *script) case ByteCode::STR: PRINTF("STR \"%s\""_fmt, scriptp.pops()); break; - case ByteCode::FUNC_: - PRINTF("FUNC_"_fmt); + case ByteCode::FUNC: + PRINTF("FUNC"_fmt); break; case ByteCode::ADD: @@ -4607,23 +4607,23 @@ void run_script_main(ScriptState *st, const ScriptBuffer *rootscript) case ByteCode::EOL: if (stack->stack_datav.size() != st->defsp) { - if (battle_config.error_log) + if (true) PRINTF("stack.sp (%zu) != default (%d)\n"_fmt, stack->stack_datav.size(), st->defsp); - stack->stack_datav.resize(st->defsp); + abort(); } rerun_pos = st->scriptp.pos; break; case ByteCode::INT: // synthesized! - push_int(stack, ByteCode::INT, get_num(&st->scriptp)); + push_int<ScriptDataInt>(stack, get_num(&st->scriptp)); break; case ByteCode::POS: case ByteCode::VARIABLE: case ByteCode::FUNC_REF: - case ByteCode::PARAM_: + case ByteCode::PARAM: // Note that these 3 have *very* different meanings, // despite being encoded similarly. { @@ -4634,28 +4634,28 @@ void run_script_main(ScriptState *st, const ScriptBuffer *rootscript) switch(c) { case ByteCode::POS: - push_int(stack, ByteCode::POS, arg); + push_int<ScriptDataPos>(stack, arg); break; case ByteCode::VARIABLE: - push_reg(stack, ByteCode::VARIABLE, SIR::from(arg)); + push_reg<ScriptDataVariable>(stack, SIR::from(arg)); break; case ByteCode::FUNC_REF: - push_int(stack, ByteCode::FUNC_REF, arg); + push_int<ScriptDataFuncRef>(stack, arg); break; - case ByteCode::PARAM_: + case ByteCode::PARAM: SP arg_sp = static_cast<SP>(arg); - push_reg(stack, ByteCode::PARAM_, SIR::from(arg_sp)); + push_reg<ScriptDataParam>(stack, SIR::from(arg_sp)); break; } } break; case ByteCode::ARG: - push_int(stack, ByteCode::ARG, 0); + push_int<ScriptDataArg>(stack, 0); break; case ByteCode::STR: - push_str(stack, ByteCode::STR, dumb_string::copys(st->scriptp.pops())); + push_str<ScriptDataStr>(stack, dumb_string::copys(st->scriptp.pops())); break; - case ByteCode::FUNC_: + case ByteCode::FUNC: run_func(st); if (st->state == ScriptEndState::GOTO) { @@ -5073,24 +5073,22 @@ void set_script_var_i(dumb_ptr<map_session_data> sd, VarName var, int e, int val { size_t k = variable_names.intern(var); SIR reg = SIR::from(k, e); - set_reg(sd, ByteCode::VARIABLE, reg, val); + set_reg(sd, VariableCode::VARIABLE, reg, val); } void set_script_var_s(dumb_ptr<map_session_data> sd, VarName var, int e, XString val) { size_t k = variable_names.intern(var); SIR reg = SIR::from(k, e); - set_reg(sd, ByteCode::VARIABLE, reg, dumb_string::copys(val)); + set_reg(sd, VariableCode::VARIABLE, reg, dumb_string::copys(val)); } int get_script_var_i(dumb_ptr<map_session_data> sd, VarName var, int e) { size_t k = variable_names.intern(var); SIR reg = SIR::from(k, e); - struct script_data dat; - dat.type = ByteCode::VARIABLE; - dat.u.reg = reg; + struct script_data dat = ScriptDataVariable{.reg= reg}; get_val(sd, &dat); - if (dat.type == ByteCode::INT) - return dat.u.numi; + if (auto *u = dat.get_if<ScriptDataInt>()) + return u->numi; PRINTF("Warning: you lied about the type and I'm too lazy to fix it!"_fmt); return 0; } @@ -5098,12 +5096,11 @@ ZString get_script_var_s(dumb_ptr<map_session_data> sd, VarName var, int e) { size_t k = variable_names.intern(var); SIR reg = SIR::from(k, e); - struct script_data dat; - dat.type = ByteCode::VARIABLE; - dat.u.reg = reg; + struct script_data dat = ScriptDataVariable{.reg= reg}; get_val(sd, &dat); - if (dat.type == ByteCode::STR) - return dat.u.str; + if (auto *u = dat.get_if<ScriptDataStr>()) + // this is almost certainly a memory leak after CONSTSTR removal + return u->str; PRINTF("Warning: you lied about the type and I can't fix it!"_fmt); return ZString(); } diff --git a/src/map/script.hpp b/src/map/script.hpp index ee9a5a9..77ffaa1 100644 --- a/src/map/script.hpp +++ b/src/map/script.hpp @@ -33,6 +33,8 @@ #include "../generic/db.hpp" #include "../generic/dumb_ptr.hpp" +#include "../sexpr/variant.hpp" + #include "../mmo/ids.hpp" #include "clif.t.hpp" @@ -41,7 +43,35 @@ namespace tmwa { -enum class ByteCode : uint8_t; +enum class VariableCode : uint8_t +{ + PARAM, + VARIABLE, +}; + +enum class StringCode : uint8_t +{ + NOP, POS, INT, PARAM, FUNC, + VARIABLE, +}; + +enum class ByteCode : uint8_t +{ + // types and specials + // Note that 'INT' is synthetic, and does not occur in the data stream + NOP, POS, INT, PARAM, FUNC, STR, ARG, + VARIABLE, EOL, + + // unary and binary operators + LOR, LAND, LE, LT, GE, GT, EQ, NE, + XOR, OR, AND, ADD, SUB, MUL, DIV, MOD, + NEG, LNOT, NOT, R_SHIFT, L_SHIFT, + + // additions + // needed because FUNC is used for the actual call + FUNC_REF, +}; + struct str_data_t; class ScriptBuffer @@ -123,23 +153,68 @@ public: friend bool operator < (SIR l, SIR r) { return l.impl < r.impl; } }; -struct script_data +struct ScriptDataPos { - ByteCode type; - union uu - { - SIR reg; - int numi; - dumb_string str; - // Not a ScriptPointer - pos is stored in a separate slot, - // to avoid exploding the struct for everyone. - const ScriptBuffer *script; - - uu() { memset(this, '\0', sizeof(*this)); } - ~uu() = default; - uu(const uu&) = default; - uu& operator = (const uu&) = default; - } u; + int numi; +}; +struct ScriptDataInt +{ + int numi; +}; +struct ScriptDataParam +{ + SIR reg; +}; +struct ScriptDataStr +{ + dumb_string str; +}; +struct ScriptDataArg +{ + int numi; +}; +struct ScriptDataVariable +{ + SIR reg; +}; +struct ScriptDataRetInfo +{ + // Not a ScriptPointer - pos is stored in a separate slot, + // to avoid exploding the struct for everyone. + const ScriptBuffer *script; +}; +struct ScriptDataFuncRef +{ + int numi; +}; + +using ScriptDataVariantBase = Variant< + ScriptDataPos, + ScriptDataInt, + ScriptDataParam, + ScriptDataStr, + ScriptDataArg, + ScriptDataVariable, + ScriptDataRetInfo, + ScriptDataFuncRef +>; +struct script_data : ScriptDataVariantBase +{ + script_data() = delete; + // TODO see if I can delete the copy ctor/assign instead of defaulting + script_data(script_data&&) = default; + script_data(const script_data&) = default /*delete*/; + script_data& operator = (script_data&&) = default; + script_data& operator = (const script_data&) = default /*delete*/; + + script_data(ScriptDataPos v) : ScriptDataVariantBase(std::move(v)) {} + script_data(ScriptDataInt v) : ScriptDataVariantBase(std::move(v)) {} + script_data(ScriptDataParam v) : ScriptDataVariantBase(std::move(v)) {} + script_data(ScriptDataStr v) : ScriptDataVariantBase(std::move(v)) {} + script_data(ScriptDataArg v) : ScriptDataVariantBase(std::move(v)) {} + script_data(ScriptDataVariable v) : ScriptDataVariantBase(std::move(v)) {} + script_data(ScriptDataRetInfo v) : ScriptDataVariantBase(std::move(v)) {} + script_data(ScriptDataFuncRef v) : ScriptDataVariantBase(std::move(v)) {} }; struct script_stack diff --git a/src/sexpr/variant.tcc b/src/sexpr/variant.tcc index a2ab7c0..1f7df03 100644 --- a/src/sexpr/variant.tcc +++ b/src/sexpr/variant.tcc @@ -228,7 +228,7 @@ namespace sexpr Variant<D, T...>& Variant<D, T...>::operator = (const Variant& r) { if (state == r.state) - apply(Void(), CopyAssign<D, T...>(this), r); + apply(Void(), CopyAssign<D, T...>(&data), r); else { do_destruct(); diff --git a/src/sexpr/variant_test.cpp b/src/sexpr/variant_test.cpp index 5a75780..bc378aa 100644 --- a/src/sexpr/variant_test.cpp +++ b/src/sexpr/variant_test.cpp @@ -115,9 +115,43 @@ TEST(variant, match) } } -TEST(variant, copymove) +TEST(variant, copymove1) { sexpr::Variant<Qux> moveonly(Qux(3)); (void)moveonly; } + +TEST(variant, copymove2) +{ + struct Move + { + Move() = default; + Move(Move&&) = default; + Move(const Move&) = delete; + Move& operator = (Move&&) = default; + Move& operator = (const Move&) = delete; + ~Move() = default; + }; + struct Copy + { + Copy() = default; + Copy(Copy&&) = default; + Copy(const Copy&) = default; + Copy& operator = (Copy&&) = default; + Copy& operator = (const Copy&) = default; + ~Copy() = default; + }; + + using VarMv = sexpr::Variant<Move>; + using VarCp = sexpr::Variant<Copy>; + + VarMv mv1; + VarMv mv3 = std::move(mv1); + mv1 = std::move(mv3); + VarCp cp1; + VarCp cp2 = cp1; + VarCp cp3 = std::move(cp1); + cp1 = cp2; + cp1 = std::move(cp3); +} } // namespace tmwa |