void SuFunction::dotParams(Value self) { SuInstance* ob = val_cast<SuInstance*>(self); if (!ob) return; Value* args = GETSP() - nparams + 1; for (int i = 0; i < nparams; ++i) if (flags[i] & DOT) { auto name = symstr(locals[i]); if (flags[i] & PUB) { char* s = STRDUPA(name); *s = toupper(*s); name = s; } else // private name = CATSTR3(className, "_", name); ob->putdata(name, args[i]); } }
char* Func::params() const { OstreamStr out; out << "("; short j = 0; for (int i = 0; i < nparams; ++i) { if (i != 0) out << ","; if (i == nparams - rest) out << "@"; if (flags && (flags[i] & DYN)) out << "_"; out << symstr(locals[i]); if (i >= nparams - ndefaults - rest && i < nparams - rest) out << "=" << literals[j++]; } out << ")"; return out.str(); }
SuBlock(Frame* f, int p, int fi, int n) : frame(f), fn(f->fn), pc(p), first(fi), persisted(false) { verify(frame->fn); // i.e. not a primitive if (n != BLOCK_REST) nparams = n; else { nparams = 1; rest = true; } literals = frame->fn->literals; locals = frame->fn->locals + first; // strip '_' prefix off params (first time) // if compile used a different way to hide block params this wouldn't be needed for (int i = 0; i < nparams; ++i) { auto s = symstr(locals[i]); if (*s != '_') break ; // already stripped previously locals[i] = ::symnum(s + 1); } }
static void make_peekdata_ops(peekdata_data& dt, const std::string& s) { std::auto_ptr<peekdata_ops> pops(new peekdata_ops()); std::string tok; for (size_t i = 0; i < s.size(); ++i) { char ch = s[i]; if (ch == ',') { pops->opsrcs.push_back(tok); tok.clear(); } else { tok.push_back(ch); } } pops->opsrcs.push_back(tok); for (size_t i = 0; i < pops->opsrcs.size(); ++i) { const std::string& src = pops->opsrcs[i]; if (src.empty()) { dt.err = "invalid op [" + src + "]"; return; } peekdata_op *op = 0; if (src == "add") { op = new peekdata_op_binop<std::plus<unsigned long>, false>(); } else if (src == "sub") { op = new peekdata_op_binop<std::minus<unsigned long>, false>(); } else if (src == "mul") { op = new peekdata_op_binop<std::multiplies<unsigned long>, false>(); } else if (src == "div") { op = new peekdata_op_binop<std::divides<unsigned long>, true>(); } else if (src == "mod") { op = new peekdata_op_binop<std::modulus<unsigned long>, true>(); } else if (src == "and") { op = new peekdata_op_binop<std::bit_and<unsigned long>, false>(); } else if (src == "or") { op = new peekdata_op_binop<std::bit_or<unsigned long>, false>(); } else if (src == "xor") { op = new peekdata_op_binop<std::bit_xor<unsigned long>, false>(); } else if (src == "land") { op = new peekdata_op_binop<std::logical_and<unsigned long>, false>(); } else if (src == "lor") { op = new peekdata_op_binop<std::logical_or<unsigned long>, false>(); } else if (src == "eq") { op = new peekdata_op_binop<std::equal_to<unsigned long>, false>(); } else if (src == "ne") { op = new peekdata_op_binop<std::not_equal_to<unsigned long>, false>(); } else if (src == "gt") { op = new peekdata_op_binop<std::greater<unsigned long>, false>(); } else if (src == "ge") { op = new peekdata_op_binop<std::greater_equal<unsigned long>, false>(); } else if (src == "lt") { op = new peekdata_op_binop<std::less<unsigned long>, false>(); } else if (src == "le") { op = new peekdata_op_binop<std::less_equal<unsigned long>, false>(); } else if (src.substr(0, 4) == "outd") { op = new peekdata_op_out_decimal(read_longval(src, 4)); } else if (src.substr(0, 4) == "outh") { op = new peekdata_op_out_hexadecimal(read_longval(src, 4)); } else if (src.substr(0, 4) == "outs") { op = new peekdata_op_out_string(read_longval(src, 4)); } else if (src.substr(0, 5) == "outsz") { op = new peekdata_op_out_nulterm_string(read_longval(src, 5)); } else if (src.substr(0, 5) == "ind") { op = new peekdata_op_in_decimal(read_longval(src, 3)); } else if (src.substr(0, 5) == "inh") { op = new peekdata_op_in_hexadecimal(read_longval(src, 3)); } else if (src.substr(0, 2) == "ld") { op = new peekdata_op_peek(strtoul(src.c_str() + 2, 0, 0)); } else if (src.substr(0, 2) == "cp") { op = new peekdata_op_copy(strtoul(src.c_str() + 2, 0, 0)); } else if (src.substr(0, 2) == "po") { op = new peekdata_op_pop(strtoul(src.c_str() + 2, 0, 0)); } else if (src[0] == 'j') { op = new peekdata_op_jmp<false>(strtol(src.c_str() + 1, 0, 0)); } else if (src.substr(0, 2) == "cj") { op = new peekdata_op_jmp<true>(strtol(src.c_str() + 2, 0, 0)); } else if (src[0] >= '0' && src[0] <= '9') { op = new peekdata_op_ulong(strtoul(src.c_str(), 0, 0)); } else if (src[0] == '@') { std::string symstr(src.c_str() + 1); dt.syms[symstr]; op = new peekdata_op_sym(symstr); } else if (src == "tr") { dt.trace_flag = true; } else if (src.substr(0, 4) == "elim") { dt.exec_limit = strtoul(src.c_str() + 4, 0, 0); } else if (src.substr(0, 4) == "slim") { dt.string_limit = strtoul(src.c_str() + 4, 0, 0); } else { dt.err = "invalid op [" + src + "]"; } if (op != 0) { pops->ops.push_back(op); } } dt.ops = pops; }
void Func::args(short nargs, short nargnames, short* argnames, int each) { Value* args = GETSP() - nargs + 1; short unamed = nargs - nargnames - (each == -1 ? 0 : 1); short i, j; if (!rest && unamed > nparams) except("too many arguments to " << this); verify(!rest || nparams == 1); // rest must be only param verify(each == -1 || nargs == 1); // each must be only arg if (nparams > nargs) // expand stack (before filling it) SETSP(GETSP() + nparams - nargs); if (each != -1 && rest) { args[0] = args[0].object()->slice(each); } else if (rest) { // put args into object SuObject* ob = new SuObject(); // un-named for (i = 0; i < unamed; ++i) ob->add(args[i]); // named for (j = 0; i < nargs; ++i, ++j) ob->put(symbol(argnames[j]), args[i]); args[0] = ob; } else if (each != -1) { SuObject* ob = args[0].object(); if (ob->vecsize() > nparams + each) except("too many arguments to " << this << " vecsize " << ob->vecsize() << " each " << each << " nparams " << nparams); // un-named members for (i = 0; i < nparams; ++i) args[i] = ob->get(i + each); // named members verify(locals); for (i = 0; i < nparams; ++i) if (Value x = ob->get(symbol(locals[i]))) args[i] = x; } else if (nargnames > 0) { // shuffle named args to match params const int maxargnames = 100; Value tmp[maxargnames]; // move named args aside verify(nargnames < maxargnames); for (i = 0; i < nargnames; ++i) tmp[i] = args[unamed + i]; // initialized remaining params for (i = unamed; i < nparams; ++i) args[i] = Value(); // fill in params with named args verify(locals); for (i = 0; i < nparams; ++i) for (j = 0; j < nargnames; ++j) if (locals[i] == argnames[j]) args[i] = tmp[j]; } else { // initialized remaining params for (i = unamed; i < nparams; ++i) args[i] = Value(); } // fill in dynamic implicits if (flags) { for (i = 0; i < nparams; ++i) if (!args[i] && (flags[i] & DYN)) { int sn = ::symnum(CATSTRA("_", symstr(locals[i]))); args[i] = dynamic(sn); } } // fill in defaults if (ndefaults > 0) { verify(literals); for (j = nparams - ndefaults, i = 0; i < ndefaults; ++i, ++j) if (!args[j]) args[j] = literals[i]; } if (nargs > nparams) // shrink stack (after processing args) SETSP(GETSP() + nparams - nargs); // check that all parameters now have values verify(locals); for (i = 0; i < nparams; ++i) if (!args[i]) except("missing argument(s) to " << this); }
int SuFunction::disasm1(Ostream& out, int ci) { verify(locals); verify(literals); out << "\t\t\t\t\t" << setw(3) << ci << " "; short op = code[ci++]; // out << hex << setw(3) << op << " " << dec; out << opcodes[op] << " "; if (op == I_SUPER) { out << globals(TARGET(ci)); ci += 2; } else if (op == I_EACH) out << (int) code[ci++]; else if (op == I_BLOCK) { out << ci + 2 + TARGET(ci); ci += 2; int first = code[ci++]; int nargs = code[ci++]; for (int i = 0; i < nargs; ++i) out << " " << 1 + symstr(locals[first + i]); } else if (op == I_PUSH_INT) { out << TARGET(ci); ci += 2; } else if (op < 16 || op == I_BOOL) ; else if (op < I_PUSH) { switch (op & 0xf0) { case I_PUSH_LITERAL: out << literals[op & 15]; break; case I_PUSH_AUTO: out << symstr(locals[op & 15]); break; case I_EQ_AUTO: case I_EQ_AUTO_POP: out << symstr(locals[op & 7]); break; case I_CALL_GLOBAL: out << globals(TARGET(ci)) << " " << (op & 7); ci += 2; break; case I_CALL_MEM: case I_CALL_MEM_SELF: out << mem(ci) << " " << (op & 7); break; default: break; } } else if ((op & 0xf8) == I_PUSH) { switch (op & 7) { case LITERAL: out << literals[varint(code, ci)]; break; case AUTO: case DYNAMIC: out << symstr(locals[code[ci++]]); break; case MEM: case MEM_SELF: out << mem(ci); break; case GLOBAL: out << globals(TARGET(ci)); ci += 2; break; default: break; } } else if ((op & 0xf8) == I_CALL) { switch (op & 7) { case AUTO: case DYNAMIC: out << symstr(locals[code[ci++]]); break; case MEM: case MEM_SELF: out << mem(ci); ci += 2; break; case GLOBAL: out << globals(TARGET(ci)); ci += 2; break; default: break; } out << " " << (short) code[ci++]; short nargnames = code[ci++]; out << " " << nargnames; for (int i = 0; i < nargnames; ++i) { out << " " << symstr(TARGET(ci)); ci += 2; } } else if ((op & 0xf8) == I_JUMP || op == I_TRY || op == I_CATCH) { out << ci + 2 + TARGET(ci); ci += 2; if (op == I_TRY) out << " " << literals[varint(code, ci)]; } else if (I_ADDEQ <= op && op < I_ADD) { switch ((op & 0x70) >> 4) { case AUTO: case DYNAMIC: out << symstr(locals[code[ci++]]); break; case MEM: case MEM_SELF: out << mem(ci); break; default: break; } } out << "\n"; return ci; }