Implement "disassemble" function in stdlib

This commit is contained in:
Konstantin Nazarov 2024-10-06 19:27:05 +01:00
parent be4224a22b
commit a01a4d0574
Signed by: knazarov
GPG key ID: 4CFE0A42FA409C22
5 changed files with 129 additions and 47 deletions

View file

@ -376,6 +376,56 @@ Result<Value> Opcode::copy_value() const {
return Value(Opcode(TRY(_value.copy())));
}
Result<String> Opcode::to_string() const {
String res = TRY(String::create(""));
const char* name = opcode_name(opcode());
OpcodeType ot = opcode_type(opcode());
char buf[256];
switch (ot) {
case OpcodeType::Unknown:
return ERROR(TypeMismatch);
case OpcodeType::Reg0:
sprintf(buf, "%s", name);
break;
case OpcodeType::Reg0I:
sprintf(buf, "%s %ld", name, arg1().arg);
break;
case OpcodeType::Reg1:
sprintf(buf, "%s %s%ld", name, (arg1().is_const) ? "c" : "r", arg1().arg);
break;
case OpcodeType::Reg1I:
sprintf(buf, "%s %s%ld %ld", name, (arg1().is_const) ? "c" : "r",
arg1().arg, arg2().arg);
break;
case OpcodeType::Reg2:
sprintf(buf, "%s %s%ld %s%ld", name, (arg1().is_const) ? "c" : "r",
arg1().arg, (arg2().is_const) ? "c" : "r", arg2().arg);
break;
case OpcodeType::Reg2I:
sprintf(buf, "%s %s%ld %s%ld %ld", name, (arg1().is_const) ? "c" : "r",
arg1().arg, (arg2().is_const) ? "c" : "r", arg2().arg,
arg3().arg);
break;
case OpcodeType::Reg3:
sprintf(buf, "%s %s%ld %s%ld %s%ld", name, (arg1().is_const) ? "c" : "r",
arg1().arg, (arg2().is_const) ? "c" : "r", arg2().arg,
(arg3().is_const) ? "c" : "r", arg3().arg);
break;
case OpcodeType::Reg4:
sprintf(buf, "%s %s%ld %s%ld %s%ld %s%ld", name,
(arg1().is_const) ? "c" : "r", arg1().arg,
(arg2().is_const) ? "c" : "r", arg2().arg,
(arg3().is_const) ? "c" : "r", arg3().arg,
(arg4().is_const) ? "c" : "r", arg4().arg);
break;
}
res = TRY(res.concat(buf));
return res;
}
Result<Value> Function::copy_value() const {
return Value(Function(TRY(_value.copy())));
}
@ -947,6 +997,58 @@ Result<Array> Function::closure() const {
return Array::create((PodArray*)_value->closure.get());
}
Result<String> Function::disassemble() const {
auto code_arr = TRY(code());
auto constants_arr = TRY(constants());
auto closure_arr = TRY(closure());
auto res = TRY(String::create(""));
char buf[256];
auto constants_size = TRY(constants_arr.size());
if (constants_size > 0) {
res = TRY(res.concat("constants:\n"));
for (uint64_t i = 0; i < constants_size; ++i) {
sprintf(buf, " c%ld: ", i);
res = TRY(res.concat(buf));
auto val = TRY(constants_arr.get(i));
auto val_str = TRY(write_one(val));
res = TRY(res.concat(val_str));
res = TRY(res.concat("\n"));
}
res = TRY(res.concat("\n"));
}
auto closure_size = TRY(closure_arr.size());
if (closure_size > 0) {
res = TRY(res.concat("closure:\n"));
for (uint64_t i = 0; i < closure_size; ++i) {
sprintf(buf, " %ld: ", i);
res = TRY(res.concat(buf));
auto val = TRY(closure_arr.get(i));
auto val_str = TRY(write_one(val));
res = TRY(res.concat(val_str));
res = TRY(res.concat("\n"));
}
res = TRY(res.concat("\n"));
}
auto code_size = TRY(code_arr.size());
if (code_size > 0) {
res = TRY(res.concat("code:\n"));
for (uint64_t i = 0; i < code_size; ++i) {
res = TRY(res.concat(" "));
auto val = TRY(code_arr.get(i));
if (!val.is<Opcode>()) return ERROR(TypeMismatch);
auto val_str = TRY(val.to<Opcode>()->to_string());
res = TRY(res.concat(val_str));
res = TRY(res.concat("\n"));
}
}
return res;
}
Result<StdlibFunction> StdlibFunction::create(StdlibFunctionId fun_id) {
auto pod = TRY(arena_alloc<PodStdlibFunction>());
pod->fun_id = (uint64_t)fun_id;

View file

@ -981,6 +981,8 @@ class Opcode : public Object {
virtual Result<Value> copy_value() const final;
Result<Opcode> copy() const;
Result<String> to_string() const;
private:
GcRoot<PodOpcode> _value;
};
@ -1025,6 +1027,8 @@ class Function : public Object {
Result<Array> constants() const;
Result<Array> closure() const;
Result<String> disassemble() const;
virtual Result<Value> copy_value() const final;
Result<Function> copy() const;

View file

@ -532,6 +532,26 @@ Result<StackFrame> stdlib_deserialize(const StackFrame& stack) {
return res;
}
Result<StackFrame> stdlib_disassemble(const StackFrame& stack) {
auto stack_size = TRY(stack.size());
auto params = TRY(stack.get(0));
Array& params_array = *params.to<Array>();
auto size = TRY(params.size());
if (size != 1) return ERROR(ArgumentCountMismatch);
auto val = TRY(params.get(0));
if (!val.is<Function>()) return ERROR(TypeMismatch);
auto disassembled = Value(TRY(val.to<Function>()->disassemble()));
auto res = TRY(stack.set(0, disassembled));
res = TRY(res.ret(0));
return res;
}
#define STDLIB_FUNCTION(name, id) \
[(uint64_t)StdlibFunctionId::id] = {#name, StdlibFunctionId::id, \
stdlib_##name}
@ -558,6 +578,7 @@ static StdlibFunctionEntry function_entries[] = {
STDLIB_FUNCTION(guard, Guard),
STDLIB_FUNCTION(serialize, Serialize),
STDLIB_FUNCTION(deserialize, Deserialize),
STDLIB_FUNCTION(disassemble, Disassemble),
[(uint64_t)StdlibFunctionId::Max] = {0, StdlibFunctionId::Max,
stdlib_unknown},
};

View file

@ -26,6 +26,7 @@ enum class StdlibFunctionId : uint64_t {
Guard,
Serialize,
Deserialize,
Disassemble,
Max,
};

View file

@ -295,53 +295,7 @@ Result<String> Writer::write_dict(const Dict& val) {
Result<String> Writer::write_opcode(const Opcode& val) {
String res = TRY(String::create("#<opcode "));
const char* name = opcode_name(val.opcode());
OpcodeType ot = opcode_type(val.opcode());
char buf[256];
switch (ot) {
case OpcodeType::Unknown:
return ERROR(TypeMismatch);
case OpcodeType::Reg0:
sprintf(buf, "%s", name);
break;
case OpcodeType::Reg0I:
sprintf(buf, "%s %ld", name, val.arg1().arg);
break;
case OpcodeType::Reg1:
sprintf(buf, "%s %s%ld", name, (val.arg1().is_const) ? "c" : "r",
val.arg1().arg);
break;
case OpcodeType::Reg1I:
sprintf(buf, "%s %s%ld %ld", name, (val.arg1().is_const) ? "c" : "r",
val.arg1().arg, val.arg2().arg);
break;
case OpcodeType::Reg2:
sprintf(buf, "%s %s%ld %s%ld", name, (val.arg1().is_const) ? "c" : "r",
val.arg1().arg, (val.arg2().is_const) ? "c" : "r",
val.arg2().arg);
break;
case OpcodeType::Reg2I:
sprintf(buf, "%s %s%ld %s%ld %ld", name,
(val.arg1().is_const) ? "c" : "r", val.arg1().arg,
(val.arg2().is_const) ? "c" : "r", val.arg2().arg,
val.arg3().arg);
break;
case OpcodeType::Reg3:
sprintf(buf, "%s %s%ld %s%ld %s%ld", name,
(val.arg1().is_const) ? "c" : "r", val.arg1().arg,
(val.arg2().is_const) ? "c" : "r", val.arg2().arg,
(val.arg3().is_const) ? "c" : "r", val.arg3().arg);
break;
case OpcodeType::Reg4:
sprintf(buf, "%s %s%ld %s%ld %s%ld %s%ld", name,
(val.arg1().is_const) ? "c" : "r", val.arg1().arg,
(val.arg2().is_const) ? "c" : "r", val.arg2().arg,
(val.arg3().is_const) ? "c" : "r", val.arg3().arg,
(val.arg4().is_const) ? "c" : "r", val.arg4().arg);
break;
}
res = TRY(res.concat(buf));
res = TRY(res.concat(TRY(val.to_string())));
res = TRY(res.concat(">"));
return res;