From 226a820ba25fa744e93ec8889830597e84bb97fa Mon Sep 17 00:00:00 2001 From: q66 Date: Wed, 17 Aug 2016 03:57:53 +0100 Subject: [PATCH] clean up cs_vm.cc --- cs_vm.cc | 2244 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 1352 insertions(+), 892 deletions(-) diff --git a/cs_vm.cc b/cs_vm.cc index d2a2239..3ff0d59 100644 --- a/cs_vm.cc +++ b/cs_vm.cc @@ -8,27 +8,33 @@ namespace cscript { -ostd::ConstCharRange cs_debug_line(CsState &cs, - ostd::ConstCharRange p, - ostd::ConstCharRange fmt, - ostd::CharRange buf) { - if (cs.src_str.empty()) return fmt; +ostd::ConstCharRange cs_debug_line( + CsState &cs, ostd::ConstCharRange p, ostd::ConstCharRange fmt, + ostd::CharRange buf +) { + if (cs.src_str.empty()) { + return fmt; + } ostd::Size num = 1; ostd::ConstCharRange line(cs.src_str); for (;;) { ostd::ConstCharRange end = ostd::find(line, '\n'); - if (!end.empty()) + if (!end.empty()) { line = ostd::slice_until(line, end); + } if (&p[0] >= &line[0] && &p[0] <= &line[line.size()]) { ostd::CharRange r(buf); - if (!cs.src_file.empty()) + if (!cs.src_file.empty()) { ostd::format(r, "%s:%d: %s", cs.src_file, num, fmt); - else + } else { ostd::format(r, "%d: %s", num, fmt); + } r.put('\0'); return buf; } - if (end.empty()) break; + if (end.empty()) { + break; + } line = end; line.pop_front(); ++num; @@ -37,54 +43,62 @@ ostd::ConstCharRange cs_debug_line(CsState &cs, } void cs_debug_alias(CsState &cs) { - if (!cs.dbgalias) return; + if (!cs.dbgalias) { + return; + } int total = 0, depth = 0; - for (IdentLink *l = cs.stack; l != &cs.noalias; l = l->next) total++; + for (IdentLink *l = cs.stack; l != &cs.noalias; l = l->next) { + total++; + } for (IdentLink *l = cs.stack; l != &cs.noalias; l = l->next) { Ident *id = l->id; ++depth; - if (depth < cs.dbgalias) + if (depth < cs.dbgalias) { ostd::err.writefln(" %d) %s", total - depth + 1, id->name); - else if (l->next == &cs.noalias) - ostd::err.writefln(depth == cs.dbgalias ? " %d) %s" - : " ..%d) %s", - total - depth + 1, id->name); + } else if (l->next == &cs.noalias) { + ostd::err.writefln( + depth == cs.dbgalias ? " %d) %s" : " ..%d) %s", + total - depth + 1, id->name + ); + } } } static void bcode_ref(ostd::Uint32 *code) { - if (!code) return; - switch (*code & CODE_OP_MASK) { - case CODE_START: + if (!code) { + return; + } + if ((*code & CODE_OP_MASK) == CODE_START) { bcode_incr(code); return; } switch (code[-1]&CODE_OP_MASK) { - case CODE_START: - bcode_incr(&code[-1]); - break; - case CODE_OFFSET: - code -= ostd::Ptrdiff(code[-1] >> 8); - bcode_incr(code); - break; + case CODE_START: + bcode_incr(&code[-1]); + break; + case CODE_OFFSET: + code -= ostd::Ptrdiff(code[-1] >> 8); + bcode_incr(code); + break; } } static void bcode_unref(ostd::Uint32 *code) { - if (!code) return; - switch (*code & CODE_OP_MASK) { - case CODE_START: + if (!code) { + return; + } + if ((*code & CODE_OP_MASK) == CODE_START) { bcode_decr(code); return; } switch (code[-1]&CODE_OP_MASK) { - case CODE_START: - bcode_decr(&code[-1]); - break; - case CODE_OFFSET: - code -= ostd::Ptrdiff(code[-1] >> 8); - bcode_decr(code); - break; + case CODE_START: + bcode_decr(&code[-1]); + break; + case CODE_OFFSET: + code -= ostd::Ptrdiff(code[-1] >> 8); + bcode_decr(code); + break; } } @@ -126,12 +140,15 @@ static inline ostd::Uint32 const *forcecode(CsState &cs, TaggedValue &v) { static inline void forcecond(CsState &cs, TaggedValue &v) { switch (v.get_type()) { - case VAL_STR: - case VAL_MACRO: - case VAL_CSTR: - if (v.s[0]) forcecode(cs, v); - else v.set_int(0); - break; + case VAL_STR: + case VAL_MACRO: + case VAL_CSTR: + if (v.s[0]) { + forcecode(cs, v); + } else { + v.set_int(0); + } + break; } } @@ -144,60 +161,70 @@ static ostd::Uint32 emptyblock[VAL_ANY][2] = { static inline void force_arg(TaggedValue &v, int type) { switch (type) { - case RET_STR: - if (v.get_type() != VAL_STR) v.force_str(); - break; - case RET_INT: - if (v.get_type() != VAL_INT) v.force_int(); - break; - case RET_FLOAT: - if (v.get_type() != VAL_FLOAT) v.force_float(); - break; + case RET_STR: + if (v.get_type() != VAL_STR) { + v.force_str(); + } + break; + case RET_INT: + if (v.get_type() != VAL_INT) { + v.force_int(); + } + break; + case RET_FLOAT: + if (v.get_type() != VAL_FLOAT) { + v.force_float(); + } + break; } } static inline void free_args(TaggedValue *args, int &oldnum, int newnum) { - for (int i = newnum; i < oldnum; i++) args[i].cleanup(); + for (int i = newnum; i < oldnum; i++) { + args[i].cleanup(); + } oldnum = newnum; } -static ostd::Uint32 const *skipcode(ostd::Uint32 const *code, TaggedValue *result = nullptr) { +static ostd::Uint32 const *skipcode( + ostd::Uint32 const *code, TaggedValue *result = nullptr +) { int depth = 0; for (;;) { ostd::Uint32 op = *code++; switch (op & 0xFF) { - case CODE_MACRO: - case CODE_VAL|RET_STR: { - ostd::Uint32 len = op >> 8; - code += len / sizeof(ostd::Uint32) + 1; - continue; - } - case CODE_BLOCK: - case CODE_JUMP: - case CODE_JUMP_TRUE: - case CODE_JUMP_FALSE: - case CODE_JUMP_RESULT_TRUE: - case CODE_JUMP_RESULT_FALSE: { - ostd::Uint32 len = op >> 8; - code += len; - continue; - } - case CODE_ENTER: - case CODE_ENTER_RESULT: - ++depth; - continue; - case CODE_EXIT|RET_NULL: - case CODE_EXIT|RET_STR: - case CODE_EXIT|RET_INT: - case CODE_EXIT|RET_FLOAT: - if (depth <= 0) { - if (result) { - force_arg(*result, op & CODE_RET_MASK); - } - return code; + case CODE_MACRO: + case CODE_VAL | RET_STR: { + ostd::Uint32 len = op >> 8; + code += len / sizeof(ostd::Uint32) + 1; + continue; } - --depth; - continue; + case CODE_BLOCK: + case CODE_JUMP: + case CODE_JUMP_TRUE: + case CODE_JUMP_FALSE: + case CODE_JUMP_RESULT_TRUE: + case CODE_JUMP_RESULT_FALSE: { + ostd::Uint32 len = op >> 8; + code += len; + continue; + } + case CODE_ENTER: + case CODE_ENTER_RESULT: + ++depth; + continue; + case CODE_EXIT | RET_NULL: + case CODE_EXIT | RET_STR: + case CODE_EXIT | RET_INT: + case CODE_EXIT | RET_FLOAT: + if (depth <= 0) { + if (result) { + force_arg(*result, op & CODE_RET_MASK); + } + return code; + } + --depth; + continue; } } } @@ -230,123 +257,290 @@ void TaggedValue::copy_arg(TaggedValue &r) const { } } -static inline void callcommand(CsState &cs, Ident *id, TaggedValue *args, TaggedValue &res, int numargs, bool lookup = false) { +static inline void callcommand( + CsState &cs, Ident *id, TaggedValue *args, TaggedValue &res, int numargs, + bool lookup = false +) { int i = -1, fakeargs = 0; bool rep = false; - for (char const *fmt = id->cargs; *fmt; fmt++) switch (*fmt) { - case 'i': - if (++i >= numargs) { - if (rep) break; - args[i].set_int(0); - fakeargs++; - } else args[i].force_int(); - break; - case 'b': - if (++i >= numargs) { - if (rep) break; - args[i].set_int(CsIntMin); - fakeargs++; - } else args[i].force_int(); - break; - case 'f': - if (++i >= numargs) { - if (rep) break; - args[i].set_float(0.0f); - fakeargs++; - } else args[i].force_float(); - break; - case 'F': - if (++i >= numargs) { - if (rep) break; - args[i].set_float(args[i - 1].get_float()); - fakeargs++; - } else args[i].force_float(); - break; - case 'S': - if (++i >= numargs) { - if (rep) break; - args[i].set_str(""); - fakeargs++; - } else args[i].force_str(); - break; - case 's': - if (++i >= numargs) { - if (rep) break; - args[i].set_cstr(""); - fakeargs++; - } else args[i].force_str(); - break; - case 'T': - case 't': - if (++i >= numargs) { - if (rep) break; - args[i].set_null(); - fakeargs++; + for (char const *fmt = id->cargs; *fmt; fmt++) { + switch (*fmt) { + case 'i': + if (++i >= numargs) { + if (rep) { + break; + } + args[i].set_int(0); + fakeargs++; + } else { + args[i].force_int(); + } + break; + case 'b': + if (++i >= numargs) { + if (rep) { + break; + } + args[i].set_int(CsIntMin); + fakeargs++; + } else { + args[i].force_int(); + } + break; + case 'f': + if (++i >= numargs) { + if (rep) { + break; + } + args[i].set_float(0.0f); + fakeargs++; + } else { + args[i].force_float(); + } + break; + case 'F': + if (++i >= numargs) { + if (rep) { + break; + } + args[i].set_float(args[i - 1].get_float()); + fakeargs++; + } else { + args[i].force_float(); + } + break; + case 'S': + if (++i >= numargs) { + if (rep) { + break; + } + args[i].set_str(""); + fakeargs++; + } else { + args[i].force_str(); + } + break; + case 's': + if (++i >= numargs) { + if (rep) { + break; + } + args[i].set_cstr(""); + fakeargs++; + } else { + args[i].force_str(); + } + break; + case 'T': + case 't': + if (++i >= numargs) { + if (rep) { + break; + } + args[i].set_null(); + fakeargs++; + } + break; + case 'E': + if (++i >= numargs) { + if (rep) { + break; + } + args[i].set_null(); + fakeargs++; + } else { + forcecond(cs, args[i]); + } + break; + case 'e': + if (++i >= numargs) { + if (rep) { + break; + } + args[i].set_code( + reinterpret_cast(emptyblock[VAL_NULL] + 1) + ); + fakeargs++; + } else { + forcecode(cs, args[i]); + } + break; + case 'r': + if (++i >= numargs) { + if (rep) { + break; + } + args[i].set_ident(cs.dummy); + fakeargs++; + } else { + cs.force_ident(args[i]); + } + break; + case '$': + if (++i < numargs) { + args[i].cleanup(); + } + args[i].set_ident(id); + break; + case 'N': + if (++i < numargs) { + args[i].cleanup(); + } + args[i].set_int(CsInt(lookup ? -1 : i - fakeargs)); + break; + case 'C': { + i = ostd::max(i + 1, numargs); + auto buf = ostd::appender(); + cscript::util::tvals_concat(buf, ostd::iter(args, i), " "); + TaggedValue tv; + tv.set_mstr(buf.get().iter()); + id->cb_cftv(TvalRange(&tv, 1), res); + goto cleanup; } - break; - case 'E': - if (++i >= numargs) { - if (rep) break; - args[i].set_null(); - fakeargs++; - } else forcecond(cs, args[i]); - break; - case 'e': - if (++i >= numargs) { - if (rep) break; - args[i].set_code(reinterpret_cast(emptyblock[VAL_NULL] + 1)); - fakeargs++; - } else forcecode(cs, args[i]); - break; - case 'r': - if (++i >= numargs) { - if (rep) break; - args[i].set_ident(cs.dummy); - fakeargs++; - } else cs.force_ident(args[i]); - break; - case '$': - if (++i < numargs) args[i].cleanup(); - args[i].set_ident(id); - break; - case 'N': - if (++i < numargs) args[i].cleanup(); - args[i].set_int(CsInt(lookup ? -1 : i - fakeargs)); - break; - case 'C': { - i = ostd::max(i + 1, numargs); - auto buf = ostd::appender(); - cscript::util::tvals_concat(buf, ostd::iter(args, i), " "); - TaggedValue tv; - tv.set_mstr(buf.get().iter()); - id->cb_cftv(TvalRange(&tv, 1), res); - goto cleanup; - } - case 'V': - i = ostd::max(i + 1, numargs); - id->cb_cftv(ostd::iter(args, i), res); - goto cleanup; - case '1': - case '2': - case '3': - case '4': - if (i + 1 < numargs) { - fmt -= *fmt - '0' + 1; - rep = true; - } - break; + case 'V': + i = ostd::max(i + 1, numargs); + id->cb_cftv(ostd::iter(args, i), res); + goto cleanup; + case '1': + case '2': + case '3': + case '4': + if (i + 1 < numargs) { + fmt -= *fmt - '0' + 1; + rep = true; + } + break; } + } ++i; id->cb_cftv(TvalRange(args, i), res); cleanup: - for (ostd::Size k = 0; k < ostd::Size(i); ++k) args[k].cleanup(); - for (; i < numargs; i++) args[i].cleanup(); + for (ostd::Size k = 0; k < ostd::Size(i); ++k) { + args[k].cleanup(); + } + for (; i < numargs; i++) { + args[i].cleanup(); + } +} + +static ostd::Uint32 const *runcode( + CsState &cs, ostd::Uint32 const *code, TaggedValue &result +); + +static inline void cs_call_alias( + CsState &cs, Ident *id, TaggedValue *args, TaggedValue &result, + int callargs, int &nargs, int offset, int skip, ostd::Uint32 op +) { + IdentStack argstack[MaxArguments]; + for(int i = 0; i < callargs; i++) { + cs.identmap[i]->push_arg(args[offset + i], argstack[i], false); + } + int oldargs = cs.numargs; + cs.numargs = callargs; + int oldflags = cs.identflags; + cs.identflags |= id->flags&IDF_OVERRIDDEN; + IdentLink aliaslink = { + id, cs.stack, (1<code) { + id->code = reinterpret_cast(compilecode(cs, id->get_str())); + } + ostd::Uint32 *codep = reinterpret_cast(id->code); + bcode_incr(codep); + runcode(cs, codep+1, (result)); + bcode_decr(codep); + cs.stack = aliaslink.next; + cs.identflags = oldflags; + for (int i = 0; i < callargs; i++) { + cs.identmap[i]->pop_arg(); + } + int argmask = aliaslink.usedargs & (~0 << callargs); + for (; argmask; ++callargs) { + if (argmask & (1 << callargs)) { + cs.identmap[callargs]->pop_arg(); + argmask &= ~(1 << callargs); + } + } + force_arg(result, op & CODE_RET_MASK); + cs.numargs = oldargs; + nargs = offset - skip; } static constexpr int MaxRunDepth = 255; static thread_local int rundepth = 0; -static ostd::Uint32 const *runcode(CsState &cs, ostd::Uint32 const *code, TaggedValue &result) { +static inline Ident *cs_get_lookup_id(CsState &cs, ostd::Uint32 op) { + Ident *id = cs.identmap[op >> 8]; + if (id->flags & IDF_UNKNOWN) { + cs_debug_code(cs, "unknown alias lookup: %s", id->name); + } + return id; +} + +static inline Ident *cs_get_lookuparg_id(CsState &cs, ostd::Uint32 op) { + Ident *id = cs.identmap[op >> 8]; + if (!(cs.stack->usedargs&(1<index))) { + return nullptr; + } + return id; +} + +static inline int cs_get_lookupu_type( + CsState &cs, TaggedValue &arg, Ident *&id, ostd::Uint32 op +) { + if ( + arg.get_type() != VAL_STR && + arg.get_type() != VAL_MACRO && + arg.get_type() != VAL_CSTR + ) { + return -2; /* default case */ + } + id = cs.idents.at(arg.s); + if (id) { + switch(id->type) { + case ID_ALIAS: + if (id->flags & IDF_UNKNOWN) { + break; + } + arg.cleanup(); + if ( + (id->index < MaxArguments) && + !(cs.stack->usedargs & (1 << id->index)) + ) { + return ID_UNKNOWN; + } + return ID_ALIAS; + case ID_SVAR: + arg.cleanup(); + return ID_SVAR; + case ID_IVAR: + arg.cleanup(); + return ID_IVAR; + case ID_FVAR: + arg.cleanup(); + return ID_FVAR; + case ID_COMMAND: { + arg.cleanup(); + arg.set_null(); + TaggedValue buf[MaxArguments]; + callcommand(cs, id, buf, arg, 0, true); + force_arg(arg, op & CODE_RET_MASK); + return -2; /* ignore */ + } + default: + arg.cleanup(); + return ID_UNKNOWN; + } + } + cs_debug_code(cs, "unknown alias lookup: %s", arg.s); + arg.cleanup(); + return ID_UNKNOWN; +} + +static ostd::Uint32 const *runcode( + CsState &cs, ostd::Uint32 const *code, TaggedValue &result +) { result.set_null(); if (rundepth >= MaxRunDepth) { cs_debug_code(cs, "exceeded recursion limit"); @@ -358,682 +552,930 @@ static ostd::Uint32 const *runcode(CsState &cs, ostd::Uint32 const *code, Tagged for (;;) { ostd::Uint32 op = *code++; switch (op & 0xFF) { - case CODE_START: - case CODE_OFFSET: - continue; + case CODE_START: + case CODE_OFFSET: + continue; -#define RETOP(op, val) \ - case op: \ - result.cleanup(); \ - val; \ - continue; + case CODE_NULL | RET_NULL: + result.cleanup(); + result.set_null(); + continue; + case CODE_NULL | RET_STR: + result.cleanup(); + result.set_str(""); + continue; + case CODE_NULL | RET_INT: + result.cleanup(); + result.set_int(0); + continue; + case CODE_NULL | RET_FLOAT: + result.cleanup(); + result.set_float(0.0f); + continue; - RETOP(CODE_NULL | RET_NULL, result.set_null()) - RETOP(CODE_NULL | RET_STR, result.set_str("")) - RETOP(CODE_NULL | RET_INT, result.set_int(0)) - RETOP(CODE_NULL | RET_FLOAT, result.set_float(0.0f)) + case CODE_FALSE | RET_STR: + result.cleanup(); + result.set_str("0"); + continue; + case CODE_FALSE | RET_NULL: + case CODE_FALSE | RET_INT: + result.cleanup(); + result.set_int(0); + continue; + case CODE_FALSE | RET_FLOAT: + result.cleanup(); + result.set_float(0.0f); + continue; - RETOP(CODE_FALSE | RET_STR, result.set_str("0")) - case CODE_FALSE|RET_NULL: - RETOP(CODE_FALSE | RET_INT, result.set_int(0)) - RETOP(CODE_FALSE | RET_FLOAT, result.set_float(0.0f)) + case CODE_TRUE | RET_STR: + result.cleanup(); + result.set_str("1"); + continue; + case CODE_TRUE | RET_NULL: + case CODE_TRUE | RET_INT: + result.cleanup(); + result.set_int(1); + continue; + case CODE_TRUE | RET_FLOAT: + result.cleanup(); + result.set_float(1.0f); + continue; - RETOP(CODE_TRUE | RET_STR, result.set_str("1")) - case CODE_TRUE|RET_NULL: - RETOP(CODE_TRUE | RET_INT, result.set_int(1)) - RETOP(CODE_TRUE | RET_FLOAT, result.set_float(1.0f)) - -#define RETPOP(op, val) \ - RETOP(op, { --numargs; val; args[numargs].cleanup(); }) - - RETPOP(CODE_NOT | RET_STR, result.set_str(args[numargs].get_bool() ? "0" : "1")) - case CODE_NOT|RET_NULL: - RETPOP(CODE_NOT | RET_INT, result.set_int(args[numargs].get_bool() ? 0 : 1)) - RETPOP(CODE_NOT | RET_FLOAT, result.set_float(args[numargs].get_bool() ? 0.0f : 1.0f)) + case CODE_NOT | RET_STR: + result.cleanup(); + --numargs; + result.set_str(args[numargs].get_bool() ? "0" : "1"); + args[numargs].cleanup(); + continue; + case CODE_NOT | RET_NULL: + case CODE_NOT | RET_INT: + result.cleanup(); + --numargs; + result.set_int(!args[numargs].get_bool()); + args[numargs].cleanup(); + continue; + case CODE_NOT | RET_FLOAT: + result.cleanup(); + --numargs; + result.set_float(CsFloat(!args[numargs].get_bool())); + args[numargs].cleanup(); + continue; case CODE_POP: - args[--numargs].cleanup(); - continue; - case CODE_ENTER: - code = runcode(cs, code, args[numargs++]); - continue; - case CODE_ENTER_RESULT: - result.cleanup(); - code = runcode(cs, code, result); - continue; - case CODE_EXIT|RET_STR: - case CODE_EXIT|RET_INT: - case CODE_EXIT|RET_FLOAT: - force_arg(result, op & CODE_RET_MASK); - /* fallthrough */ - case CODE_EXIT|RET_NULL: - goto exit; - case CODE_RESULT_ARG|RET_STR: - case CODE_RESULT_ARG|RET_INT: - case CODE_RESULT_ARG|RET_FLOAT: - force_arg(result, op & CODE_RET_MASK); - /* fallthrough */ - case CODE_RESULT_ARG|RET_NULL: - args[numargs++] = result; - result.set_null(); - continue; - case CODE_PRINT: - cs.print_var(cs.identmap[op >> 8]); - continue; - - case CODE_LOCAL: { - result.cleanup(); - int numlocals = op >> 8, offset = numargs - numlocals; - IdentStack locals[MaxArguments]; - for (int i = 0; i < numlocals; ++i) args[offset + i].id->push_alias(locals[i]); - code = runcode(cs, code, result); - for (int i = offset; i < numargs; i++) args[i].id->pop_alias(); - goto exit; - } - - case CODE_DOARGS|RET_NULL: - case CODE_DOARGS|RET_STR: - case CODE_DOARGS|RET_INT: - case CODE_DOARGS|RET_FLOAT: - if (cs.stack != &cs.noalias) { - cs_do_args(cs, [&]() { - result.cleanup(); - cs.run_ret(args[--numargs].code, result); - args[numargs].cleanup(); - force_arg(result, op & CODE_RET_MASK); - }); + args[--numargs].cleanup(); continue; - } - /* fallthrough */ - case CODE_DO|RET_NULL: - case CODE_DO|RET_STR: - case CODE_DO|RET_INT: - case CODE_DO|RET_FLOAT: - result.cleanup(); - cs.run_ret(args[--numargs].code, result); - args[numargs].cleanup(); - force_arg(result, op & CODE_RET_MASK); - continue; - - case CODE_JUMP: { - ostd::Uint32 len = op >> 8; - code += len; - continue; - } - case CODE_JUMP_TRUE: { - ostd::Uint32 len = op >> 8; - if (args[--numargs].get_bool()) code += len; - args[numargs].cleanup(); - continue; - } - case CODE_JUMP_FALSE: { - ostd::Uint32 len = op >> 8; - if (!args[--numargs].get_bool()) code += len; - args[numargs].cleanup(); - continue; - } - case CODE_JUMP_RESULT_TRUE: { - ostd::Uint32 len = op >> 8; - result.cleanup(); - --numargs; - if (args[numargs].get_type() == VAL_CODE) { - cs.run_ret(args[numargs].code, result); - args[numargs].cleanup(); - } else result = args[numargs]; - if (result.get_bool()) code += len; - continue; - } - case CODE_JUMP_RESULT_FALSE: { - ostd::Uint32 len = op >> 8; - result.cleanup(); - --numargs; - if (args[numargs].get_type() == VAL_CODE) { - cs.run_ret(args[numargs].code, result); - args[numargs].cleanup(); - } else result = args[numargs]; - if (!result.get_bool()) code += len; - continue; - } - - case CODE_MACRO: { - ostd::Uint32 len = op >> 8; - args[numargs++].set_macro(reinterpret_cast(code), len); - code += len / sizeof(ostd::Uint32) + 1; - continue; - } - - case CODE_VAL|RET_STR: { - ostd::Uint32 len = op >> 8; - args[numargs++].set_str(ostd::ConstCharRange(reinterpret_cast(code), len)); - code += len / sizeof(ostd::Uint32) + 1; - continue; - } - case CODE_VALI|RET_STR: { - char s[4] = { char((op >> 8) & 0xFF), char((op >> 16) & 0xFF), char((op >> 24) & 0xFF), '\0' }; - args[numargs++].set_str(s); - continue; - } - case CODE_VAL|RET_NULL: - case CODE_VALI|RET_NULL: - args[numargs++].set_null(); - continue; - case CODE_VAL|RET_INT: - args[numargs++].set_int(CsInt(*code++)); - continue; - case CODE_VALI|RET_INT: - args[numargs++].set_int(CsInt(op) >> 8); - continue; - case CODE_VAL|RET_FLOAT: - args[numargs++].set_float(*reinterpret_cast(code++)); - continue; - case CODE_VALI|RET_FLOAT: - args[numargs++].set_float(CsFloat(CsInt(op) >> 8)); - continue; - - case CODE_DUP|RET_NULL: - args[numargs - 1].get_val(args[numargs]); - numargs++; - continue; - case CODE_DUP|RET_INT: - args[numargs].set_int(args[numargs - 1].get_int()); - numargs++; - continue; - case CODE_DUP|RET_FLOAT: - args[numargs].set_float(args[numargs - 1].get_float()); - numargs++; - continue; - case CODE_DUP|RET_STR: - args[numargs].set_str(ostd::move(args[numargs - 1].get_str())); - numargs++; - continue; - - case CODE_FORCE|RET_STR: - args[numargs - 1].force_str(); - continue; - case CODE_FORCE|RET_INT: - args[numargs - 1].force_int(); - continue; - case CODE_FORCE|RET_FLOAT: - args[numargs - 1].force_float(); - continue; - - case CODE_RESULT|RET_NULL: - result.cleanup(); - result = args[--numargs]; - continue; - case CODE_RESULT|RET_STR: - case CODE_RESULT|RET_INT: - case CODE_RESULT|RET_FLOAT: - result.cleanup(); - result = args[--numargs]; - force_arg(result, op & CODE_RET_MASK); - continue; - - case CODE_EMPTY|RET_NULL: - args[numargs++].set_code(reinterpret_cast(emptyblock[VAL_NULL] + 1)); - break; - case CODE_EMPTY|RET_STR: - args[numargs++].set_code(reinterpret_cast(emptyblock[VAL_STR] + 1)); - break; - case CODE_EMPTY|RET_INT: - args[numargs++].set_code(reinterpret_cast(emptyblock[VAL_INT] + 1)); - break; - case CODE_EMPTY|RET_FLOAT: - args[numargs++].set_code(reinterpret_cast(emptyblock[VAL_FLOAT] + 1)); - break; - case CODE_BLOCK: { - ostd::Uint32 len = op >> 8; - args[numargs++].set_code(reinterpret_cast(code + 1)); - code += len; - continue; - } - case CODE_COMPILE: { - TaggedValue &arg = args[numargs - 1]; - GenState gs(cs); - switch (arg.get_type()) { - case VAL_INT: - gs.code.reserve(8); - gs.code.push(CODE_START); - gs.gen_int(arg.i); - gs.code.push(CODE_RESULT); - gs.code.push(CODE_EXIT); - break; - case VAL_FLOAT: - gs.code.reserve(8); - gs.code.push(CODE_START); - gs.gen_float(arg.f); - gs.code.push(CODE_RESULT); - gs.code.push(CODE_EXIT); - break; - case VAL_STR: - case VAL_MACRO: - case VAL_CSTR: - gs.code.reserve(64); - gs.gen_main(arg.s); - arg.cleanup(); - break; - default: - gs.code.reserve(8); - gs.code.push(CODE_START); - gs.gen_null(); - gs.code.push(CODE_RESULT); - gs.code.push(CODE_EXIT); - break; - } - arg.set_code(reinterpret_cast(gs.code.disown() + 1)); - continue; - } - case CODE_COND: { - TaggedValue &arg = args[numargs - 1]; - switch (arg.get_type()) { - case VAL_STR: - case VAL_MACRO: - case VAL_CSTR: - if (arg.s[0]) { - GenState gs(cs); - gs.code.reserve(64); - gs.gen_main(arg.s); - arg.cleanup(); - arg.set_code(reinterpret_cast(gs.code.disown() + 1)); - } else arg.force_null(); - break; - } - continue; - } - - case CODE_IDENT: - args[numargs++].set_ident(cs.identmap[op >> 8]); - continue; - case CODE_IDENTARG: { - Ident *id = cs.identmap[op >> 8]; - if (!(cs.stack->usedargs & (1 << id->index))) { - id->push_arg(null_value, cs.stack->argstack[id->index], false); - cs.stack->usedargs |= 1 << id->index; - } - args[numargs++].set_ident(id); - continue; - } - case CODE_IDENTU: { - TaggedValue &arg = args[numargs - 1]; - Ident *id = arg.get_type() == VAL_STR || arg.get_type() == VAL_MACRO || arg.get_type() == VAL_CSTR ? cs.new_ident(ostd::ConstCharRange(arg.cstr, arg.len)) : cs.dummy; - if (id->index < MaxArguments && !(cs.stack->usedargs & (1 << id->index))) { - id->push_arg(null_value, cs.stack->argstack[id->index], false); - cs.stack->usedargs |= 1 << id->index; - } - arg.cleanup(); - arg.set_ident(id); - continue; - } - - case CODE_LOOKUPU|RET_STR: -#define LOOKUPU(aval, sval, ival, fval, nval) { \ - TaggedValue &arg = args[numargs-1]; \ - if(arg.get_type() != VAL_STR && arg.get_type() != VAL_MACRO && arg.get_type() != VAL_CSTR) continue; \ - Ident *id = cs.idents.at(arg.s); \ - if(id) switch(id->type) \ - { \ - case ID_ALIAS: \ - if(id->flags&IDF_UNKNOWN) break; \ - arg.cleanup(); \ - if(id->index < MaxArguments && !(cs.stack->usedargs&(1<index))) { nval; continue; } \ - aval; \ - continue; \ - case ID_SVAR: arg.cleanup(); sval; continue; \ - case ID_IVAR: arg.cleanup(); ival; continue; \ - case ID_FVAR: arg.cleanup(); fval; continue; \ - case ID_COMMAND: \ - { \ - arg.cleanup(); \ - arg.set_null(); \ - TaggedValue buf[MaxArguments]; \ - callcommand(cs, id, buf, arg, 0, true); \ - force_arg(arg, op&CODE_RET_MASK); \ - continue; \ - } \ - default: arg.cleanup(); nval; continue; \ - } \ - cs_debug_code(cs, "unknown alias lookup: %s", arg.s); \ - arg.cleanup(); \ - nval; \ - continue; \ - } - LOOKUPU(arg.set_str(ostd::move(id->get_str())), - arg.set_str(*id->storage.sp), - arg.set_str(ostd::move(intstr(*id->storage.ip))), - arg.set_str(ostd::move(floatstr(*id->storage.fp))), - arg.set_str("")); - case CODE_LOOKUP|RET_STR: -#define LOOKUP(aval) { \ - Ident *id = cs.identmap[op>>8]; \ - if(id->flags&IDF_UNKNOWN) cs_debug_code(cs, "unknown alias lookup: %s", id->name); \ - aval; \ - continue; \ - } - LOOKUP(args[numargs++].set_str(ostd::move(id->get_str()))); - case CODE_LOOKUPARG|RET_STR: -#define LOOKUPARG(aval, nval) { \ - Ident *id = cs.identmap[op>>8]; \ - if(!(cs.stack->usedargs&(1<index))) { nval; continue; } \ - aval; \ - continue; \ - } - LOOKUPARG(args[numargs++].set_str(ostd::move(id->get_str())), args[numargs++].set_str("")); - case CODE_LOOKUPU|RET_INT: - LOOKUPU(arg.set_int(id->get_int()), - arg.set_int(cs_parse_int(*id->storage.sp)), - arg.set_int(*id->storage.ip), - arg.set_int(CsInt(*id->storage.fp)), - arg.set_int(0)); - case CODE_LOOKUP|RET_INT: - LOOKUP(args[numargs++].set_int(id->get_int())); - case CODE_LOOKUPARG|RET_INT: - LOOKUPARG(args[numargs++].set_int(id->get_int()), args[numargs++].set_int(0)); - case CODE_LOOKUPU|RET_FLOAT: - LOOKUPU(arg.set_float(id->get_float()), - arg.set_float(cs_parse_float(*id->storage.sp)), - arg.set_float(CsFloat(*id->storage.ip)), - arg.set_float(*id->storage.fp), - arg.set_float(0.0f)); - case CODE_LOOKUP|RET_FLOAT: - LOOKUP(args[numargs++].set_float(id->get_float())); - case CODE_LOOKUPARG|RET_FLOAT: - LOOKUPARG(args[numargs++].set_float(id->get_float()), args[numargs++].set_float(0.0f)); - case CODE_LOOKUPU|RET_NULL: - LOOKUPU(id->get_val(arg), - arg.set_str(*id->storage.sp), - arg.set_int(*id->storage.ip), - arg.set_float(*id->storage.fp), - arg.set_null()); - case CODE_LOOKUP|RET_NULL: - LOOKUP(id->get_val(args[numargs++])); - case CODE_LOOKUPARG|RET_NULL: - LOOKUPARG(id->get_val(args[numargs++]), args[numargs++].set_null()); - - case CODE_LOOKUPMU|RET_STR: - LOOKUPU(id->get_cstr(arg), - arg.set_cstr(*id->storage.sp), - arg.set_str(ostd::move(intstr(*id->storage.ip))), - arg.set_str(ostd::move(floatstr(*id->storage.fp))), - arg.set_cstr("")); - case CODE_LOOKUPM|RET_STR: - LOOKUP(id->get_cstr(args[numargs++])); - case CODE_LOOKUPMARG|RET_STR: - LOOKUPARG(id->get_cstr(args[numargs++]), args[numargs++].set_cstr("")); - case CODE_LOOKUPMU|RET_NULL: - LOOKUPU(id->get_cval(arg), - arg.set_cstr(*id->storage.sp), - arg.set_int(*id->storage.ip), - arg.set_float(*id->storage.fp), - arg.set_null()); - case CODE_LOOKUPM|RET_NULL: - LOOKUP(id->get_cval(args[numargs++])); - case CODE_LOOKUPMARG|RET_NULL: - LOOKUPARG(id->get_cval(args[numargs++]), args[numargs++].set_null()); - - case CODE_SVAR|RET_STR: - case CODE_SVAR|RET_NULL: - args[numargs++].set_str(*cs.identmap[op >> 8]->storage.sp); - continue; - case CODE_SVAR|RET_INT: - args[numargs++].set_int(cs_parse_int(*cs.identmap[op >> 8]->storage.sp)); - continue; - case CODE_SVAR|RET_FLOAT: - args[numargs++].set_float(cs_parse_float(*cs.identmap[op >> 8]->storage.sp)); - continue; - case CODE_SVARM: - args[numargs++].set_cstr(*cs.identmap[op >> 8]->storage.sp); - continue; - case CODE_SVAR1: - cs.set_var_str_checked(cs.identmap[op >> 8], args[--numargs].s); - args[numargs].cleanup(); - continue; - - case CODE_IVAR|RET_INT: - case CODE_IVAR|RET_NULL: - args[numargs++].set_int(*cs.identmap[op >> 8]->storage.ip); - continue; - case CODE_IVAR|RET_STR: - args[numargs++].set_str(ostd::move(intstr(*cs.identmap[op >> 8]->storage.ip))); - continue; - case CODE_IVAR|RET_FLOAT: - args[numargs++].set_float(CsFloat(*cs.identmap[op >> 8]->storage.ip)); - continue; - case CODE_IVAR1: - cs.set_var_int_checked(cs.identmap[op >> 8], args[--numargs].i); - continue; - case CODE_IVAR2: - numargs -= 2; - cs.set_var_int_checked(cs.identmap[op >> 8], (args[numargs].i << 16) | (args[numargs + 1].i << 8)); - continue; - case CODE_IVAR3: - numargs -= 3; - cs.set_var_int_checked(cs.identmap[op >> 8], (args[numargs].i << 16) | (args[numargs + 1].i << 8) | args[numargs + 2].i); - continue; - - case CODE_FVAR|RET_FLOAT: - case CODE_FVAR|RET_NULL: - args[numargs++].set_float(*cs.identmap[op >> 8]->storage.fp); - continue; - case CODE_FVAR|RET_STR: - args[numargs++].set_str(ostd::move(floatstr(*cs.identmap[op >> 8]->storage.fp))); - continue; - case CODE_FVAR|RET_INT: - args[numargs++].set_int(int(*cs.identmap[op >> 8]->storage.fp)); - continue; - case CODE_FVAR1: - cs.set_var_float_checked(cs.identmap[op >> 8], args[--numargs].f); - continue; - - case CODE_COM|RET_NULL: - case CODE_COM|RET_STR: - case CODE_COM|RET_FLOAT: - case CODE_COM|RET_INT: { - Ident *id = cs.identmap[op >> 8]; - int offset = numargs - id->numargs; - result.force_null(); - id->cb_cftv(TvalRange(args + offset, id->numargs), result); - force_arg(result, op & CODE_RET_MASK); - free_args(args, numargs, offset); - continue; - } - - case CODE_COMV|RET_NULL: - case CODE_COMV|RET_STR: - case CODE_COMV|RET_FLOAT: - case CODE_COMV|RET_INT: { - Ident *id = cs.identmap[op >> 13]; - int callargs = (op >> 8) & 0x1F, offset = numargs - callargs; - result.force_null(); - id->cb_cftv(ostd::iter(&args[offset], callargs), result); - force_arg(result, op & CODE_RET_MASK); - free_args(args, numargs, offset); - continue; - } - case CODE_COMC|RET_NULL: - case CODE_COMC|RET_STR: - case CODE_COMC|RET_FLOAT: - case CODE_COMC|RET_INT: { - Ident *id = cs.identmap[op >> 13]; - int callargs = (op >> 8) & 0x1F, offset = numargs - callargs; - result.force_null(); - { - auto buf = ostd::appender(); - cscript::util::tvals_concat(buf, ostd::iter(&args[offset], callargs), " "); - TaggedValue tv; - tv.set_mstr(buf.get().iter()); - id->cb_cftv(TvalRange(&tv, 1), result); - } - force_arg(result, op & CODE_RET_MASK); - free_args(args, numargs, offset); - continue; - } - - case CODE_CONC|RET_NULL: - case CODE_CONC|RET_STR: - case CODE_CONC|RET_FLOAT: - case CODE_CONC|RET_INT: - case CODE_CONCW|RET_NULL: - case CODE_CONCW|RET_STR: - case CODE_CONCW|RET_FLOAT: - case CODE_CONCW|RET_INT: { - int numconc = op >> 8; - auto buf = ostd::appender(); - cscript::util::tvals_concat(buf, ostd::iter(&args[numargs - numconc], numconc), ((op & CODE_OP_MASK) == CODE_CONC) ? " " : ""); - free_args(args, numargs, numargs - numconc); - args[numargs].set_mstr(buf.get().iter()); - buf.get().disown(); - force_arg(args[numargs], op & CODE_RET_MASK); - numargs++; - continue; - } - - case CODE_CONCM|RET_NULL: - case CODE_CONCM|RET_STR: - case CODE_CONCM|RET_FLOAT: - case CODE_CONCM|RET_INT: { - int numconc = op >> 8; - auto buf = ostd::appender(); - cscript::util::tvals_concat(buf, ostd::iter(&args[numargs - numconc], numconc)); - free_args(args, numargs, numargs - numconc); - result.set_mstr(buf.get().iter()); - buf.get().disown(); - force_arg(result, op & CODE_RET_MASK); - continue; - } - - case CODE_ALIAS: - cs.identmap[op >> 8]->set_alias(cs, args[--numargs]); - continue; - case CODE_ALIASARG: - cs.identmap[op >> 8]->set_arg(cs, args[--numargs]); - continue; - case CODE_ALIASU: - numargs -= 2; - cs.set_alias(args[numargs].get_str(), args[numargs + 1]); - args[numargs].cleanup(); - continue; - -#define SKIPARGS(offset) offset - case CODE_CALL|RET_NULL: - case CODE_CALL|RET_STR: - case CODE_CALL|RET_FLOAT: - case CODE_CALL|RET_INT: { -#define FORCERESULT { \ - free_args(args, numargs, SKIPARGS(offset)); \ - force_arg(result, op&CODE_RET_MASK); \ - continue; \ - } -#define CALLALIAS(cs, result) { \ - IdentStack argstack[MaxArguments]; \ - for(int i = 0; i < callargs; i++) \ - (cs).identmap[i]->push_arg(args[offset + i], argstack[i], false); \ - int oldargs = (cs).numargs; \ - (cs).numargs = callargs; \ - int oldflags = (cs).identflags; \ - (cs).identflags |= id->flags&IDF_OVERRIDDEN; \ - IdentLink aliaslink = { id, (cs).stack, (1<code) id->code = reinterpret_cast(compilecode(cs, id->get_str())); \ - ostd::Uint32 *codep = reinterpret_cast(id->code); \ - bcode_incr(codep); \ - runcode((cs), codep+1, (result)); \ - bcode_decr(codep); \ - (cs).stack = aliaslink.next; \ - (cs).identflags = oldflags; \ - for(int i = 0; i < callargs; i++) \ - (cs).identmap[i]->pop_arg(); \ - for(int argmask = aliaslink.usedargs&(~0<pop_arg(); argmask &= ~(1<> 13]; - int callargs = (op >> 8) & 0x1F, offset = numargs - callargs; - if (id->flags & IDF_UNKNOWN) { - cs_debug_code(cs, "unknown command: %s", id->name); - FORCERESULT; - } - CALLALIAS(cs, result); - continue; - } - case CODE_CALLARG|RET_NULL: - case CODE_CALLARG|RET_STR: - case CODE_CALLARG|RET_FLOAT: - case CODE_CALLARG|RET_INT: { - result.force_null(); - Ident *id = cs.identmap[op >> 13]; - int callargs = (op >> 8) & 0x1F, offset = numargs - callargs; - if (!(cs.stack->usedargs & (1 << id->index))) FORCERESULT; - CALLALIAS(cs, result); - continue; - } -#undef SKIPARGS - -#define SKIPARGS(offset) offset-1 - case CODE_CALLU|RET_NULL: - case CODE_CALLU|RET_STR: - case CODE_CALLU|RET_FLOAT: - case CODE_CALLU|RET_INT: { - int callargs = op >> 8, offset = numargs - callargs; - TaggedValue &idarg = args[offset - 1]; - if (idarg.get_type() != VAL_STR && idarg.get_type() != VAL_MACRO && idarg.get_type() != VAL_CSTR) { -litval: + case CODE_ENTER: + code = runcode(cs, code, args[numargs++]); + continue; + case CODE_ENTER_RESULT: result.cleanup(); - result = idarg; - force_arg(result, op & CODE_RET_MASK); - while (--numargs >= offset) args[numargs].cleanup(); - continue; - } - Ident *id = cs.idents.at(idarg.s); - if (!id) { -noid: - if (cs_check_num(idarg.s)) goto litval; - cs_debug_code(cs, "unknown command: %s", idarg.s); - result.force_null(); - FORCERESULT; - } - result.force_null(); - switch (id->type) { - default: - if (!id->cb_cftv) FORCERESULT; - /* fallthrough */ - case ID_COMMAND: - idarg.cleanup(); - callcommand(cs, id, &args[offset], result, callargs); - force_arg(result, op & CODE_RET_MASK); - numargs = offset - 1; - continue; - case ID_LOCAL: { - IdentStack locals[MaxArguments]; - idarg.cleanup(); - for (ostd::Size j = 0; j < ostd::Size(callargs); ++j) cs.force_ident(args[offset + j])->push_alias(locals[j]); code = runcode(cs, code, result); - for (ostd::Size j = 0; j < ostd::Size(callargs); ++j) args[offset + j].id->pop_alias(); + continue; + case CODE_EXIT | RET_STR: + case CODE_EXIT | RET_INT: + case CODE_EXIT | RET_FLOAT: + force_arg(result, op & CODE_RET_MASK); + /* fallthrough */ + case CODE_EXIT | RET_NULL: + goto exit; + case CODE_RESULT_ARG | RET_STR: + case CODE_RESULT_ARG | RET_INT: + case CODE_RESULT_ARG | RET_FLOAT: + force_arg(result, op & CODE_RET_MASK); + /* fallthrough */ + case CODE_RESULT_ARG | RET_NULL: + args[numargs++] = result; + result.set_null(); + continue; + case CODE_PRINT: + cs.print_var(cs.identmap[op >> 8]); + continue; + + case CODE_LOCAL: { + result.cleanup(); + int numlocals = op >> 8, offset = numargs - numlocals; + IdentStack locals[MaxArguments]; + for (int i = 0; i < numlocals; ++i) { + args[offset + i].id->push_alias(locals[i]); + } + code = runcode(cs, code, result); + for (int i = offset; i < numargs; i++) { + args[i].id->pop_alias(); + } goto exit; } - case ID_IVAR: - if (callargs <= 0) cs.print_var(id); - else cs.set_var_int_checked(id, ostd::iter(&args[offset], callargs)); - FORCERESULT; - case ID_FVAR: - if (callargs <= 0) cs.print_var(id); - else cs.set_var_float_checked(id, args[offset].force_float()); - FORCERESULT; - case ID_SVAR: - if (callargs <= 0) cs.print_var(id); - else cs.set_var_str_checked(id, args[offset].force_str()); - FORCERESULT; - case ID_ALIAS: - if (id->index < MaxArguments && !(cs.stack->usedargs & (1 << id->index))) FORCERESULT; - if (id->get_valtype() == VAL_NULL) goto noid; - idarg.cleanup(); - CALLALIAS(cs, result); + + case CODE_DOARGS | RET_NULL: + case CODE_DOARGS | RET_STR: + case CODE_DOARGS | RET_INT: + case CODE_DOARGS | RET_FLOAT: + if (cs.stack != &cs.noalias) { + cs_do_args(cs, [&]() { + result.cleanup(); + cs.run_ret(args[--numargs].code, result); + args[numargs].cleanup(); + force_arg(result, op & CODE_RET_MASK); + }); + continue; + } + /* fallthrough */ + case CODE_DO | RET_NULL: + case CODE_DO | RET_STR: + case CODE_DO | RET_INT: + case CODE_DO | RET_FLOAT: + result.cleanup(); + cs.run_ret(args[--numargs].code, result); + args[numargs].cleanup(); + force_arg(result, op & CODE_RET_MASK); + continue; + + case CODE_JUMP: { + ostd::Uint32 len = op >> 8; + code += len; continue; } - } -#undef SKIPARGS + case CODE_JUMP_TRUE: { + ostd::Uint32 len = op >> 8; + if (args[--numargs].get_bool()) { + code += len; + } + args[numargs].cleanup(); + continue; + } + case CODE_JUMP_FALSE: { + ostd::Uint32 len = op >> 8; + if (!args[--numargs].get_bool()) { + code += len; + } + args[numargs].cleanup(); + continue; + } + case CODE_JUMP_RESULT_TRUE: { + ostd::Uint32 len = op >> 8; + result.cleanup(); + --numargs; + if (args[numargs].get_type() == VAL_CODE) { + cs.run_ret(args[numargs].code, result); + args[numargs].cleanup(); + } else { + result = args[numargs]; + } + if (result.get_bool()) { + code += len; + } + continue; + } + case CODE_JUMP_RESULT_FALSE: { + ostd::Uint32 len = op >> 8; + result.cleanup(); + --numargs; + if (args[numargs].get_type() == VAL_CODE) { + cs.run_ret(args[numargs].code, result); + args[numargs].cleanup(); + } else { + result = args[numargs]; + } + if (!result.get_bool()) { + code += len; + } + continue; + } + + case CODE_MACRO: { + ostd::Uint32 len = op >> 8; + args[numargs++].set_macro( + reinterpret_cast(code), len + ); + code += len / sizeof(ostd::Uint32) + 1; + continue; + } + + case CODE_VAL | RET_STR: { + ostd::Uint32 len = op >> 8; + args[numargs++].set_str(ostd::ConstCharRange( + reinterpret_cast(code), len + )); + code += len / sizeof(ostd::Uint32) + 1; + continue; + } + case CODE_VALI | RET_STR: { + char s[4] = { + char((op >> 8) & 0xFF), + char((op >> 16) & 0xFF), + char((op >> 24) & 0xFF), '\0' + }; + args[numargs++].set_str(s); + continue; + } + case CODE_VAL | RET_NULL: + case CODE_VALI | RET_NULL: + args[numargs++].set_null(); + continue; + case CODE_VAL | RET_INT: + args[numargs++].set_int(CsInt(*code++)); + continue; + case CODE_VALI | RET_INT: + args[numargs++].set_int(CsInt(op) >> 8); + continue; + case CODE_VAL | RET_FLOAT: + args[numargs++].set_float( + *reinterpret_cast(code++) + ); + continue; + case CODE_VALI | RET_FLOAT: + args[numargs++].set_float(CsFloat(CsInt(op) >> 8)); + continue; + + case CODE_DUP | RET_NULL: + args[numargs - 1].get_val(args[numargs]); + numargs++; + continue; + case CODE_DUP | RET_INT: + args[numargs].set_int(args[numargs - 1].get_int()); + numargs++; + continue; + case CODE_DUP | RET_FLOAT: + args[numargs].set_float(args[numargs - 1].get_float()); + numargs++; + continue; + case CODE_DUP | RET_STR: + args[numargs].set_str(ostd::move(args[numargs - 1].get_str())); + numargs++; + continue; + + case CODE_FORCE | RET_STR: + args[numargs - 1].force_str(); + continue; + case CODE_FORCE | RET_INT: + args[numargs - 1].force_int(); + continue; + case CODE_FORCE | RET_FLOAT: + args[numargs - 1].force_float(); + continue; + + case CODE_RESULT | RET_NULL: + result.cleanup(); + result = args[--numargs]; + continue; + case CODE_RESULT | RET_STR: + case CODE_RESULT | RET_INT: + case CODE_RESULT | RET_FLOAT: + result.cleanup(); + result = args[--numargs]; + force_arg(result, op & CODE_RET_MASK); + continue; + + case CODE_EMPTY | RET_NULL: + args[numargs++].set_code( + reinterpret_cast(emptyblock[VAL_NULL] + 1) + ); + break; + case CODE_EMPTY | RET_STR: + args[numargs++].set_code( + reinterpret_cast(emptyblock[VAL_STR] + 1) + ); + break; + case CODE_EMPTY | RET_INT: + args[numargs++].set_code( + reinterpret_cast(emptyblock[VAL_INT] + 1) + ); + break; + case CODE_EMPTY | RET_FLOAT: + args[numargs++].set_code( + reinterpret_cast(emptyblock[VAL_FLOAT] + 1) + ); + break; + case CODE_BLOCK: { + ostd::Uint32 len = op >> 8; + args[numargs++].set_code( + reinterpret_cast(code + 1) + ); + code += len; + continue; + } + case CODE_COMPILE: { + TaggedValue &arg = args[numargs - 1]; + GenState gs(cs); + switch (arg.get_type()) { + case VAL_INT: + gs.code.reserve(8); + gs.code.push(CODE_START); + gs.gen_int(arg.i); + gs.code.push(CODE_RESULT); + gs.code.push(CODE_EXIT); + break; + case VAL_FLOAT: + gs.code.reserve(8); + gs.code.push(CODE_START); + gs.gen_float(arg.f); + gs.code.push(CODE_RESULT); + gs.code.push(CODE_EXIT); + break; + case VAL_STR: + case VAL_MACRO: + case VAL_CSTR: + gs.code.reserve(64); + gs.gen_main(arg.s); + arg.cleanup(); + break; + default: + gs.code.reserve(8); + gs.code.push(CODE_START); + gs.gen_null(); + gs.code.push(CODE_RESULT); + gs.code.push(CODE_EXIT); + break; + } + arg.set_code( + reinterpret_cast(gs.code.disown() + 1) + ); + continue; + } + case CODE_COND: { + TaggedValue &arg = args[numargs - 1]; + switch (arg.get_type()) { + case VAL_STR: + case VAL_MACRO: + case VAL_CSTR: + if (arg.s[0]) { + GenState gs(cs); + gs.code.reserve(64); + gs.gen_main(arg.s); + arg.cleanup(); + arg.set_code(reinterpret_cast( + gs.code.disown() + 1 + )); + } else { + arg.force_null(); + } + break; + } + continue; + } + + case CODE_IDENT: + args[numargs++].set_ident(cs.identmap[op >> 8]); + continue; + case CODE_IDENTARG: { + Ident *id = cs.identmap[op >> 8]; + if (!(cs.stack->usedargs & (1 << id->index))) { + id->push_arg(null_value, cs.stack->argstack[id->index], false); + cs.stack->usedargs |= 1 << id->index; + } + args[numargs++].set_ident(id); + continue; + } + case CODE_IDENTU: { + TaggedValue &arg = args[numargs - 1]; + Ident *id = cs.dummy; + if ( + arg.get_type() == VAL_STR || + arg.get_type() == VAL_MACRO || + arg.get_type() == VAL_CSTR + ) { + id = cs.new_ident(ostd::ConstCharRange(arg.cstr, arg.len)); + } + if (id->index < MaxArguments && !(cs.stack->usedargs & (1 << id->index))) { + id->push_arg(null_value, cs.stack->argstack[id->index], false); + cs.stack->usedargs |= 1 << id->index; + } + arg.cleanup(); + arg.set_ident(id); + continue; + } + + case CODE_LOOKUPU | RET_STR: { + Ident *id = nullptr; + TaggedValue &arg = args[numargs - 1]; + switch (cs_get_lookupu_type(cs, arg, id, op)) { + case ID_ALIAS: + arg.set_str(ostd::move(id->get_str())); + continue; + case ID_SVAR: + arg.set_str(*id->storage.sp); + continue; + case ID_IVAR: + arg.set_str(ostd::move(intstr(*id->storage.ip))); + continue; + case ID_FVAR: + arg.set_str(ostd::move(floatstr(*id->storage.fp))); + continue; + case ID_UNKNOWN: + arg.set_str(""); + continue; + default: + continue; + } + } + case CODE_LOOKUP | RET_STR: + args[numargs++].set_str( + ostd::move(cs_get_lookup_id(cs, op)->get_str()) + ); + continue; + case CODE_LOOKUPARG | RET_STR: { + Ident *id = cs_get_lookuparg_id(cs, op); + if (!id) { + args[numargs++].set_str(""); + } else { + args[numargs++].set_str(ostd::move(id->get_str())); + } + continue; + } + case CODE_LOOKUPU | RET_INT: { + Ident *id = nullptr; + TaggedValue &arg = args[numargs - 1]; + switch (cs_get_lookupu_type(cs, arg, id, op)) { + case ID_ALIAS: + arg.set_int(id->get_int()); + continue; + case ID_SVAR: + arg.set_int(cs_parse_int(*id->storage.sp)); + continue; + case ID_IVAR: + arg.set_int(*id->storage.ip); + continue; + case ID_FVAR: + arg.set_int(CsInt(*id->storage.fp)); + continue; + case ID_UNKNOWN: + arg.set_int(0); + continue; + default: + continue; + } + } + case CODE_LOOKUP | RET_INT: + args[numargs++].set_int( + cs_get_lookup_id(cs, op)->get_int() + ); + continue; + case CODE_LOOKUPARG | RET_INT: { + Ident *id = cs_get_lookuparg_id(cs, op); + if (!id) { + args[numargs++].set_int(0); + } else { + args[numargs++].set_int(id->get_int()); + } + continue; + } + case CODE_LOOKUPU | RET_FLOAT: { + Ident *id = nullptr; + TaggedValue &arg = args[numargs - 1]; + switch (cs_get_lookupu_type(cs, arg, id, op)) { + case ID_ALIAS: + arg.set_float(id->get_float()); + continue; + case ID_SVAR: + arg.set_float(cs_parse_float(*id->storage.sp)); + continue; + case ID_IVAR: + arg.set_float(CsFloat(*id->storage.ip)); + continue; + case ID_FVAR: + arg.set_float(*id->storage.fp); + continue; + case ID_UNKNOWN: + arg.set_float(CsFloat(0)); + continue; + default: + continue; + } + } + case CODE_LOOKUP | RET_FLOAT: + args[numargs++].set_float( + cs_get_lookup_id(cs, op)->get_float() + ); + continue; + case CODE_LOOKUPARG | RET_FLOAT: { + Ident *id = cs_get_lookuparg_id(cs, op); + if (!id) { + args[numargs++].set_float(CsFloat(0)); + } else { + args[numargs++].set_float(id->get_float()); + } + continue; + } + case CODE_LOOKUPU | RET_NULL: { + Ident *id = nullptr; + TaggedValue &arg = args[numargs - 1]; + switch (cs_get_lookupu_type(cs, arg, id, op)) { + case ID_ALIAS: + id->get_val(arg); + continue; + case ID_SVAR: + arg.set_str(*id->storage.sp); + continue; + case ID_IVAR: + arg.set_int(*id->storage.ip); + continue; + case ID_FVAR: + arg.set_float(*id->storage.fp); + continue; + case ID_UNKNOWN: + arg.set_null(); + continue; + default: + continue; + } + } + case CODE_LOOKUP | RET_NULL: + cs_get_lookup_id(cs, op)->get_val(args[numargs++]); + continue; + case CODE_LOOKUPARG | RET_NULL: { + Ident *id = cs_get_lookuparg_id(cs, op); + if (!id) { + args[numargs++].set_null(); + } else { + id->get_val(args[numargs++]); + } + continue; + } + + case CODE_LOOKUPMU | RET_STR: { + Ident *id = nullptr; + TaggedValue &arg = args[numargs - 1]; + switch (cs_get_lookupu_type(cs, arg, id, op)) { + case ID_ALIAS: + id->get_cstr(arg); + continue; + case ID_SVAR: + arg.set_cstr(*id->storage.sp); + continue; + case ID_IVAR: + arg.set_str(ostd::move(intstr(*id->storage.ip))); + continue; + case ID_FVAR: + arg.set_str(ostd::move(floatstr(*id->storage.fp))); + continue; + case ID_UNKNOWN: + arg.set_cstr(""); + continue; + default: + continue; + } + } + case CODE_LOOKUPM | RET_STR: + cs_get_lookup_id(cs, op)->get_cstr(args[numargs++]); + continue; + case CODE_LOOKUPMARG | RET_STR: { + Ident *id = cs_get_lookuparg_id(cs, op); + if (!id) { + args[numargs++].set_cstr(""); + } else { + id->get_cstr(args[numargs++]); + } + continue; + } + case CODE_LOOKUPMU | RET_NULL: { + Ident *id = nullptr; + TaggedValue &arg = args[numargs - 1]; + switch (cs_get_lookupu_type(cs, arg, id, op)) { + case ID_ALIAS: + id->get_cval(arg); + continue; + case ID_SVAR: + arg.set_cstr(*id->storage.sp); + continue; + case ID_IVAR: + arg.set_int(*id->storage.ip); + continue; + case ID_FVAR: + arg.set_float(*id->storage.fp); + continue; + case ID_UNKNOWN: + arg.set_null(); + continue; + default: + continue; + } + } + case CODE_LOOKUPM | RET_NULL: + cs_get_lookup_id(cs, op)->get_cval(args[numargs++]); + continue; + case CODE_LOOKUPMARG | RET_NULL: { + Ident *id = cs_get_lookuparg_id(cs, op); + if (!id) { + args[numargs++].set_null(); + } else { + id->get_cval(args[numargs++]); + } + continue; + } + + case CODE_SVAR | RET_STR: + case CODE_SVAR | RET_NULL: + args[numargs++].set_str(*cs.identmap[op >> 8]->storage.sp); + continue; + case CODE_SVAR | RET_INT: + args[numargs++].set_int(cs_parse_int( + *cs.identmap[op >> 8]->storage.sp) + ); + continue; + case CODE_SVAR | RET_FLOAT: + args[numargs++].set_float( + cs_parse_float(*cs.identmap[op >> 8]->storage.sp) + ); + continue; + case CODE_SVARM: + args[numargs++].set_cstr(*cs.identmap[op >> 8]->storage.sp); + continue; + case CODE_SVAR1: + cs.set_var_str_checked(cs.identmap[op >> 8], args[--numargs].s); + args[numargs].cleanup(); + continue; + + case CODE_IVAR | RET_INT: + case CODE_IVAR | RET_NULL: + args[numargs++].set_int(*cs.identmap[op >> 8]->storage.ip); + continue; + case CODE_IVAR | RET_STR: + args[numargs++].set_str( + ostd::move(intstr(*cs.identmap[op >> 8]->storage.ip)) + ); + continue; + case CODE_IVAR | RET_FLOAT: + args[numargs++].set_float( + CsFloat(*cs.identmap[op >> 8]->storage.ip) + ); + continue; + case CODE_IVAR1: + cs.set_var_int_checked(cs.identmap[op >> 8], args[--numargs].i); + continue; + case CODE_IVAR2: + numargs -= 2; + cs.set_var_int_checked( + cs.identmap[op >> 8], + (args[numargs].i << 16) | (args[numargs + 1].i << 8)); + continue; + case CODE_IVAR3: + numargs -= 3; + cs.set_var_int_checked( + cs.identmap[op >> 8], + (args[numargs].i << 16) + | (args[numargs + 1].i << 8) + | args[numargs + 2].i); + continue; + + case CODE_FVAR | RET_FLOAT: + case CODE_FVAR | RET_NULL: + args[numargs++].set_float(*cs.identmap[op >> 8]->storage.fp); + continue; + case CODE_FVAR | RET_STR: + args[numargs++].set_str( + ostd::move(floatstr(*cs.identmap[op >> 8]->storage.fp)) + ); + continue; + case CODE_FVAR | RET_INT: + args[numargs++].set_int(int(*cs.identmap[op >> 8]->storage.fp)); + continue; + case CODE_FVAR1: + cs.set_var_float_checked(cs.identmap[op >> 8], args[--numargs].f); + continue; + + case CODE_COM | RET_NULL: + case CODE_COM | RET_STR: + case CODE_COM | RET_FLOAT: + case CODE_COM | RET_INT: { + Ident *id = cs.identmap[op >> 8]; + int offset = numargs - id->numargs; + result.force_null(); + id->cb_cftv(TvalRange(args + offset, id->numargs), result); + force_arg(result, op & CODE_RET_MASK); + free_args(args, numargs, offset); + continue; + } + + case CODE_COMV | RET_NULL: + case CODE_COMV | RET_STR: + case CODE_COMV | RET_FLOAT: + case CODE_COMV | RET_INT: { + Ident *id = cs.identmap[op >> 13]; + int callargs = (op >> 8) & 0x1F, offset = numargs - callargs; + result.force_null(); + id->cb_cftv(ostd::iter(&args[offset], callargs), result); + force_arg(result, op & CODE_RET_MASK); + free_args(args, numargs, offset); + continue; + } + case CODE_COMC | RET_NULL: + case CODE_COMC | RET_STR: + case CODE_COMC | RET_FLOAT: + case CODE_COMC | RET_INT: { + Ident *id = cs.identmap[op >> 13]; + int callargs = (op >> 8) & 0x1F, offset = numargs - callargs; + result.force_null(); + { + auto buf = ostd::appender(); + cscript::util::tvals_concat( + buf, ostd::iter(&args[offset], callargs), " " + ); + TaggedValue tv; + tv.set_mstr(buf.get().iter()); + id->cb_cftv(TvalRange(&tv, 1), result); + } + force_arg(result, op & CODE_RET_MASK); + free_args(args, numargs, offset); + continue; + } + + case CODE_CONC | RET_NULL: + case CODE_CONC | RET_STR: + case CODE_CONC | RET_FLOAT: + case CODE_CONC | RET_INT: + case CODE_CONCW | RET_NULL: + case CODE_CONCW | RET_STR: + case CODE_CONCW | RET_FLOAT: + case CODE_CONCW | RET_INT: { + int numconc = op >> 8; + auto buf = ostd::appender(); + cscript::util::tvals_concat( + buf, ostd::iter(&args[numargs - numconc], numconc), + ((op & CODE_OP_MASK) == CODE_CONC) ? " " : "" + ); + free_args(args, numargs, numargs - numconc); + args[numargs].set_mstr(buf.get().iter()); + buf.get().disown(); + force_arg(args[numargs], op & CODE_RET_MASK); + numargs++; + continue; + } + + case CODE_CONCM | RET_NULL: + case CODE_CONCM | RET_STR: + case CODE_CONCM | RET_FLOAT: + case CODE_CONCM | RET_INT: { + int numconc = op >> 8; + auto buf = ostd::appender(); + cscript::util::tvals_concat( + buf, ostd::iter(&args[numargs - numconc], numconc) + ); + free_args(args, numargs, numargs - numconc); + result.set_mstr(buf.get().iter()); + buf.get().disown(); + force_arg(result, op & CODE_RET_MASK); + continue; + } + + case CODE_ALIAS: + cs.identmap[op >> 8]->set_alias(cs, args[--numargs]); + continue; + case CODE_ALIASARG: + cs.identmap[op >> 8]->set_arg(cs, args[--numargs]); + continue; + case CODE_ALIASU: + numargs -= 2; + cs.set_alias(args[numargs].get_str(), args[numargs + 1]); + args[numargs].cleanup(); + continue; + + case CODE_CALL | RET_NULL: + case CODE_CALL | RET_STR: + case CODE_CALL | RET_FLOAT: + case CODE_CALL | RET_INT: { + result.force_null(); + Ident *id = cs.identmap[op >> 13]; + int callargs = (op >> 8) & 0x1F, offset = numargs - callargs; + if (id->flags & IDF_UNKNOWN) { + cs_debug_code(cs, "unknown command: %s", id->name); + free_args(args, numargs, offset); + force_arg(result, op & CODE_RET_MASK); + continue; + } + cs_call_alias( + cs, id, args, result, callargs, numargs, offset, 0, op + ); + continue; + } + case CODE_CALLARG | RET_NULL: + case CODE_CALLARG | RET_STR: + case CODE_CALLARG | RET_FLOAT: + case CODE_CALLARG | RET_INT: { + result.force_null(); + Ident *id = cs.identmap[op >> 13]; + int callargs = (op >> 8) & 0x1F, offset = numargs - callargs; + if (!(cs.stack->usedargs & (1 << id->index))) { + free_args(args, numargs, offset); + force_arg(result, op & CODE_RET_MASK); + continue; + } + cs_call_alias( + cs, id, args, result, callargs, numargs, offset, 0, op + ); + continue; + } + + case CODE_CALLU | RET_NULL: + case CODE_CALLU | RET_STR: + case CODE_CALLU | RET_FLOAT: + case CODE_CALLU | RET_INT: { + int callargs = op >> 8, offset = numargs - callargs; + TaggedValue &idarg = args[offset - 1]; + if ( + idarg.get_type() != VAL_STR && + idarg.get_type() != VAL_MACRO && + idarg.get_type() != VAL_CSTR + ) { +litval: + result.cleanup(); + result = idarg; + force_arg(result, op & CODE_RET_MASK); + while (--numargs >= offset) { + args[numargs].cleanup(); + } + continue; + } + Ident *id = cs.idents.at(idarg.s); + if (!id) { +noid: + if (cs_check_num(idarg.s)) { + goto litval; + } + cs_debug_code(cs, "unknown command: %s", idarg.s); + result.force_null(); + free_args(args, numargs, offset - 1); + force_arg(result, op & CODE_RET_MASK); + continue; + } + result.force_null(); + switch (id->type) { + default: + if (!id->cb_cftv) { + free_args(args, numargs, offset - 1); + force_arg(result, op & CODE_RET_MASK); + continue; + } + /* fallthrough */ + case ID_COMMAND: + idarg.cleanup(); + callcommand(cs, id, &args[offset], result, callargs); + force_arg(result, op & CODE_RET_MASK); + numargs = offset - 1; + continue; + case ID_LOCAL: { + IdentStack locals[MaxArguments]; + idarg.cleanup(); + for (ostd::Size j = 0; j < ostd::Size(callargs); ++j) { + cs.force_ident( + args[offset + j] + )->push_alias(locals[j]); + } + code = runcode(cs, code, result); + for (ostd::Size j = 0; j < ostd::Size(callargs); ++j) { + args[offset + j].id->pop_alias(); + } + goto exit; + } + case ID_IVAR: + if (callargs <= 0) { + cs.print_var(id); + } else { + cs.set_var_int_checked( + id, ostd::iter(&args[offset], callargs) + ); + } + free_args(args, numargs, offset - 1); + force_arg(result, op & CODE_RET_MASK); + continue; + case ID_FVAR: + if (callargs <= 0) { + cs.print_var(id); + } else { + cs.set_var_float_checked( + id, args[offset].force_float() + ); + } + free_args(args, numargs, offset - 1); + force_arg(result, op & CODE_RET_MASK); + continue; + case ID_SVAR: + if (callargs <= 0) { + cs.print_var(id); + } else { + cs.set_var_str_checked(id, args[offset].force_str()); + } + free_args(args, numargs, offset - 1); + force_arg(result, op & CODE_RET_MASK); + continue; + case ID_ALIAS: + if ( + id->index < MaxArguments && + !(cs.stack->usedargs & (1 << id->index)) + ) { + free_args(args, numargs, offset - 1); + force_arg(result, op & CODE_RET_MASK); + continue; + } + if (id->get_valtype() == VAL_NULL) { + goto noid; + } + idarg.cleanup(); + cs_call_alias( + cs, id, args, result, callargs, numargs, + offset, 1, op + ); + continue; + } + } } } exit: @@ -1051,8 +1493,9 @@ void CsState::run_ret(ostd::ConstCharRange code, TaggedValue &ret) { /* FIXME range */ gs.gen_main(code.data(), VAL_ANY); runcode(*this, gs.code.data() + 1, ret); - if (int(gs.code[0]) >= 0x100) + if (int(gs.code[0]) >= 0x100) { gs.code.disown(); + } } /* TODO */ @@ -1060,45 +1503,61 @@ void CsState::run_ret(Ident *id, TvalRange args, TaggedValue &ret) { int nargs = int(args.size()); ret.set_null(); ++rundepth; - if (rundepth > MaxRunDepth) cs_debug_code(*this, "exceeded recursion limit"); - else if (id) switch (id->type) { - default: - if (!id->cb_cftv) break; - /* fallthrough */ - case ID_COMMAND: - if (nargs < id->numargs) { - TaggedValue buf[MaxArguments]; - memcpy(buf, args.data(), args.size() * sizeof(TaggedValue)); - callcommand(*this, id, buf, ret, nargs, false); - } else callcommand(*this, id, args.data(), ret, nargs, false); - nargs = 0; - break; - case ID_IVAR: - if (args.empty()) print_var(id); - else set_var_int_checked(id, args); - break; - case ID_FVAR: - if (args.empty()) print_var(id); - else set_var_float_checked(id, args[0].force_float()); - break; - case ID_SVAR: - if (args.empty()) print_var(id); - else set_var_str_checked(id, args[0].force_str()); - break; - case ID_ALIAS: - if (id->index < MaxArguments && !(stack->usedargs & (1 << id->index))) break; - if (id->get_valtype() == VAL_NULL) break; -#define callargs nargs -#define offset 0 -#define op RET_NULL -#define SKIPARGS(offset) offset - CALLALIAS(*this, ret); -#undef callargs -#undef offset -#undef op -#undef SKIPARGS - break; + if (rundepth > MaxRunDepth) { + cs_debug_code(*this, "exceeded recursion limit"); + } else if (id) { + switch (id->type) { + default: + if (!id->cb_cftv) { + break; + } + /* fallthrough */ + case ID_COMMAND: + if (nargs < id->numargs) { + TaggedValue buf[MaxArguments]; + memcpy(buf, args.data(), args.size() * sizeof(TaggedValue)); + callcommand(*this, id, buf, ret, nargs, false); + } else { + callcommand(*this, id, args.data(), ret, nargs, false); + } + nargs = 0; + break; + case ID_IVAR: + if (args.empty()) { + print_var(id); + } else { + set_var_int_checked(id, args); + } + break; + case ID_FVAR: + if (args.empty()) { + print_var(id); + } else { + set_var_float_checked(id, args[0].force_float()); + } + break; + case ID_SVAR: + if (args.empty()) { + print_var(id); + } else { + set_var_str_checked(id, args[0].force_str()); + } + break; + case ID_ALIAS: + if (id->index < MaxArguments) { + if (!(stack->usedargs & (1 << id->index))) { + break; + } + } + if (id->get_valtype() == VAL_NULL) { + break; + } + cs_call_alias( + *this, id, args.data(), ret, nargs, nargs, 0, 0, RET_NULL + ); + break; } + } free_args(args.data(), nargs, 0); --rundepth; } @@ -1205,8 +1664,9 @@ bool CsState::run_file(ostd::ConstCharRange fname) { ostd::Size len; ostd::FileStream f(fname, ostd::StreamMode::read); - if (!f.is_open()) + if (!f.is_open()) { return false; + } len = f.size(); buf = ostd::make_box(len + 1);