[Decomp] Decompile gstring (#267)

* decompile gstring

* update

* Update code_status.md

* Update code_status.md

* decompile gstate

* add test for states, hope it passes

* also test throw and catch xmms

* update doc
This commit is contained in:
water111
2021-02-16 20:37:48 -05:00
committed by GitHub
parent aa9bcd07f4
commit f1a93886e7
29 changed files with 2505 additions and 396 deletions
+194
View File
@@ -285,6 +285,14 @@ goos::Object Break::to_form() const {
return pretty_print::build_list(forms);
}
std::string EmptyVtx::to_string() const {
return "empty";
}
goos::Object EmptyVtx::to_form() const {
return pretty_print::build_list("empty");
}
ControlFlowGraph::ControlFlowGraph() {
// allocate the entry and exit vertices.
m_entry = alloc<EntryVtx>();
@@ -1100,6 +1108,7 @@ bool ControlFlowGraph::find_cond_w_else() {
}
if (!is_found_after(else_block, b0)) {
;
return true;
}
@@ -1228,6 +1237,185 @@ bool ControlFlowGraph::find_cond_w_else() {
return found;
}
bool ControlFlowGraph::find_cond_w_empty_else() {
bool found = false;
for_each_top_level_vtx([&](CfgVtx* vtx) {
// determine where the "else" block would be
auto* c0 = vtx; // first condition
auto* b0 = c0->next; // first body
if (!b0) {
return true;
}
// printf("cwe try %s %s\n", c0->to_string().c_str(), b0->to_string().c_str());
// first condition should have the _option_ to fall through to first body
if (c0->succ_ft != b0 || c0->end_branch.kind != CfgVtx::DelaySlotKind::NOP) {
return true;
}
// first body MUST unconditionally jump to else
if (b0->succ_ft || b0->end_branch.branch_likely ||
b0->end_branch.kind != CfgVtx::DelaySlotKind::NOP) {
return true;
}
if (b0->pred.size() != 1) {
return true;
}
assert(b0->end_branch.has_branch);
assert(b0->end_branch.branch_always);
assert(b0->succ_branch);
// TODO - check what's in the delay slot!
auto* end_block = b0->succ_branch;
if (!end_block) {
return true;
}
if (!is_found_after(end_block, b0)) {
return true;
}
auto* else_block = end_block->prev;
if (!else_block) {
return true;
}
if (else_block != b0) {
return true;
} else {
else_block = end_block;
}
if (else_block->succ_branch) {
return true;
}
assert(!else_block->end_branch.has_branch);
std::vector<CondWithElse::Entry> entries = {{c0, b0}};
auto* prev_condition = c0;
auto* prev_body = b0;
// loop to try to grab all the cases up to the else, or reject if the inside is not sufficiently
// compact or if this is not actually a cond with else Note, we are responsible for checking the
// branch of prev_condition, but not the fallthrough
while (true) {
auto* next = prev_body->next;
if (next == else_block) {
// TODO - check what's in the delay slot!
// we're done!
// check the prev_condition, prev_body blocks properly go to the else/end_block
// prev_condition should jump to else:
if (prev_condition->succ_branch != else_block || prev_condition->end_branch.branch_likely ||
prev_condition->end_branch.kind != CfgVtx::DelaySlotKind::NOP) {
return true;
}
// prev_body should jump to end
if (prev_body->succ_branch != end_block ||
prev_body->end_branch.kind != CfgVtx::DelaySlotKind::NOP) {
return true;
}
break;
} else {
auto* c = next;
auto* b = c->next;
if (!c || !b) {
;
return true;
};
// attempt to add another
if (c->pred.size() != 1) {
return true;
}
if (b->pred.size() != 1) {
return true;
}
// how to get to cond
if (prev_condition->succ_branch != c || prev_condition->end_branch.branch_likely ||
prev_condition->end_branch.kind != CfgVtx::DelaySlotKind::NOP) {
return true;
}
if (prev_body->end_branch.kind != CfgVtx::DelaySlotKind::NOP) {
return true;
}
if (c->succ_ft != b) {
return true; // condition should have the option to fall through if matched
}
// TODO - check what's in the delay slot!
if (c->end_branch.branch_likely) {
return true; // otherwise should go to next with a non-likely branch
}
if (b->succ_ft || b->end_branch.branch_likely) {
return true; // body should go straight to else
}
if (b->succ_branch != end_block) {
return true;
}
entries.emplace_back(c, b);
prev_body = b;
prev_condition = c;
}
}
// now we need to add it
// printf("got cwe\n");
auto new_cwe = alloc<CondWithElse>();
// link x <-> new_cwe
for (auto* npred : c0->pred) {
npred->replace_succ_and_check(c0, new_cwe);
}
new_cwe->pred = c0->pred;
new_cwe->prev = c0->prev;
if (new_cwe->prev) {
new_cwe->prev->next = new_cwe;
}
lg::error("There is a very strange control flow here, please check it manually.");
// link new_cwe <-> end
std::vector<CfgVtx*> to_replace;
// to_replace.push_back(else_block);
to_replace.push_back(entries.back().condition);
for (const auto& x : entries) {
to_replace.push_back(x.body);
}
end_block->replace_preds_with_and_check(to_replace, new_cwe);
new_cwe->succ_ft = end_block;
new_cwe->next = end_block;
end_block->prev = new_cwe;
// new_cwe->else_vtx = else_block;
new_cwe->else_vtx = alloc<EmptyVtx>();
new_cwe->entries = std::move(entries);
new_cwe->else_vtx->parent_claim(new_cwe);
for (const auto& x : new_cwe->entries) {
x.body->parent_claim(new_cwe);
x.condition->parent_claim(new_cwe);
}
found = true;
return false;
});
return found;
}
#define printf(format, ...) ;
bool ControlFlowGraph::find_cond_n_else() {
@@ -1889,6 +2077,12 @@ std::shared_ptr<ControlFlowGraph> build_cfg(const LinkedObjectFile& file, int se
if (!changed) {
changed = changed || cfg->find_goto_not_end();
}
if (!changed) {
changed = changed || cfg->find_cond_w_empty_else();
if (changed) {
}
}
}
if (!cfg->is_fully_resolved()) {
+7
View File
@@ -270,6 +270,12 @@ class Break : public CfgVtx {
CfgVtx* unreachable_block = nullptr;
};
class EmptyVtx : public CfgVtx {
public:
std::string to_string() const override;
goos::Object to_form() const override;
};
struct BasicBlock;
/*!
@@ -294,6 +300,7 @@ class ControlFlowGraph {
void link_fall_through_likely(BlockVtx* first, BlockVtx* second, std::vector<BasicBlock>& blocks);
void link_branch(BlockVtx* first, BlockVtx* second, std::vector<BasicBlock>& blocks);
bool find_cond_w_else();
bool find_cond_w_empty_else();
bool find_cond_n_else();
// bool find_if_else_top_level();
+1 -1
View File
@@ -197,7 +197,7 @@ FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const {
return pool.alloc_element<SetFormFormElement>(addr, val);
}
if (input_type.typespec() == TypeSpec("pointer")) {
if (input_type.typespec() == TypeSpec("pointer") && ro.offset == 0) {
std::string cast_type;
switch (m_size) {
case 1:
+7 -5
View File
@@ -540,11 +540,12 @@ TP_Type LoadVarOp::get_src_type(const TypeState& input,
// remember that we're an object new.
return TP_Type::make_object_new(method_type);
}
if (method_id == GOAL_NEW_METHOD ||
input_type.kind == TP_Type::Kind::TYPE_OF_TYPE_NO_VIRTUAL) {
if (method_id == GOAL_NEW_METHOD) {
return TP_Type::make_from_ts(method_type);
} else if (input_type.kind == TP_Type::Kind::TYPE_OF_TYPE_NO_VIRTUAL) {
return TP_Type::make_non_virtual_method(method_type);
} else {
return TP_Type::make_method(method_type);
return TP_Type::make_virtual_method(method_type);
}
}
@@ -555,7 +556,8 @@ TP_Type LoadVarOp::get_src_type(const TypeState& input,
auto method_info = dts.ts.lookup_method("object", method_id);
if (method_id != GOAL_NEW_METHOD && method_id != GOAL_RELOC_METHOD) {
// this can get us the wrong thing for `new` methods. And maybe relocate?
return TP_Type::make_from_ts(method_info.type.substitute_for_method_call("object"));
return TP_Type::make_non_virtual_method(
method_info.type.substitute_for_method_call("object"));
}
}
@@ -824,7 +826,7 @@ TypeState CallOp::propagate_types_internal(const TypeState& input,
for (uint32_t i = 0; i < in_type.arg_count() - 1; i++) {
m_read_regs.emplace_back(Reg::GPR, arg_regs[i]);
m_arg_vars.push_back(Variable(VariableMode::READ, m_read_regs.back(), m_my_idx));
if (i == 0 && in_tp.kind == TP_Type::Kind::METHOD) {
if (i == 0 && in_tp.kind == TP_Type::Kind::VIRTUAL_METHOD) {
m_read_regs.pop_back();
m_arg_vars.pop_back();
m_is_virtual_method = true;
+2 -1
View File
@@ -127,7 +127,8 @@ class SimpleExpressionElement : public FormElement {
FormPool& pool,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects);
bool allow_side_effects,
bool reverse);
void update_from_stack_force_ui_2(const Env& env,
FixedOperatorKind kind,
FormPool& pool,
+62 -16
View File
@@ -577,7 +577,8 @@ void SimpleExpressionElement::update_from_stack_force_si_2(const Env& env,
FormPool& pool,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) {
bool allow_side_effects,
bool reverse) {
auto arg0_i = is_int_type(env, m_my_idx, m_expr.get_arg(0).var());
bool arg1_i = true;
bool arg1_reg = m_expr.get_arg(1).is_var();
@@ -589,8 +590,17 @@ void SimpleExpressionElement::update_from_stack_force_si_2(const Env& env,
std::vector<Form*> args;
if (arg1_reg) {
args = pop_to_forms({m_expr.get_arg(0).var(), m_expr.get_arg(1).var()}, env, pool, stack,
allow_side_effects);
if (reverse) {
args = pop_to_forms({m_expr.get_arg(1).var(), m_expr.get_arg(0).var()}, env, pool, stack,
allow_side_effects);
auto temp = args.at(1);
args.at(1) = args.at(0);
args.at(0) = temp;
} else {
args = pop_to_forms({m_expr.get_arg(0).var(), m_expr.get_arg(1).var()}, env, pool, stack,
allow_side_effects);
}
} else {
args = pop_to_forms({m_expr.get_arg(0).var()}, env, pool, stack, allow_side_effects);
args.push_back(pool.alloc_single_element_form<SimpleAtomElement>(nullptr, m_expr.get_arg(1)));
@@ -807,19 +817,19 @@ void SimpleExpressionElement::update_from_stack(const Env& env,
break;
case SimpleExpression::Kind::DIV_SIGNED:
update_from_stack_force_si_2(env, FixedOperatorKind::DIVISION, pool, stack, result,
allow_side_effects);
allow_side_effects, false);
break;
case SimpleExpression::Kind::MOD_SIGNED:
update_from_stack_force_si_2(env, FixedOperatorKind::MOD, pool, stack, result,
allow_side_effects);
allow_side_effects, false);
break;
case SimpleExpression::Kind::MIN_SIGNED:
update_from_stack_force_si_2(env, FixedOperatorKind::MIN, pool, stack, result,
allow_side_effects);
allow_side_effects, false);
break;
case SimpleExpression::Kind::MAX_SIGNED:
update_from_stack_force_si_2(env, FixedOperatorKind::MAX, pool, stack, result,
allow_side_effects);
allow_side_effects, false);
break;
case SimpleExpression::Kind::AND:
update_from_stack_copy_first_int_2(env, FixedOperatorKind::LOGAND, pool, stack, result,
@@ -987,7 +997,7 @@ void FunctionCallElement::update_from_stack(const Env& env,
bool is_method = false;
auto& tp_type = env.get_types_before_op(all_pop_vars.at(0).idx()).get(all_pop_vars.at(0).reg());
if (env.has_type_analysis()) {
if (tp_type.kind == TP_Type::Kind::METHOD && all_pop_vars.size() >= 1) {
if (tp_type.kind == TP_Type::Kind::VIRTUAL_METHOD && all_pop_vars.size() >= 1) {
is_method = true;
}
function_type = tp_type.typespec();
@@ -1002,7 +1012,15 @@ void FunctionCallElement::update_from_stack(const Env& env,
// all_pop_vars.erase(all_pop_vars.begin() + 1);
// }
if (tp_type.kind == TP_Type::Kind::NON_VIRTUAL_METHOD) {
std::swap(all_pop_vars.at(0), all_pop_vars.at(1));
}
auto unstacked = pop_to_forms(all_pop_vars, env, pool, stack, allow_side_effects);
if (tp_type.kind == TP_Type::Kind::NON_VIRTUAL_METHOD) {
std::swap(unstacked.at(0), unstacked.at(1));
std::swap(all_pop_vars.at(0), all_pop_vars.at(1));
}
std::vector<Form*> arg_forms;
for (size_t arg_id = 0; arg_id < nargs; arg_id++) {
@@ -1200,7 +1218,12 @@ void FunctionCallElement::update_from_stack(const Env& env,
// temp_form->to_string(env));
}
} else {
throw std::runtime_error("Method call detected, not yet implemented");
auto ti = env.dts->ts.lookup_type(type_1);
auto is_basic = dynamic_cast<BasicType*>(ti);
if (!is_basic) {
throw std::runtime_error(
fmt::format("Method call detected, not yet implemented {} {}\n", name, type_1));
}
}
}
}
@@ -1743,24 +1766,47 @@ void ConditionElement::update_from_stack(const Env& env,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) {
std::vector<Form*> source_forms;
std::vector<Form*> source_forms, popped_forms;
std::vector<TypeSpec> source_types;
std::vector<Variable> vars;
for (int i = 0; i < get_condition_num_args(m_kind); i++) {
auto& var = m_src[i]->var();
vars.push_back(var);
source_types.push_back(env.get_types_before_op(var.idx()).get(var.reg()).typespec());
if (m_src[i]->is_var()) {
auto& var = m_src[i]->var();
vars.push_back(var);
source_types.push_back(env.get_types_before_op(var.idx()).get(var.reg()).typespec());
} else if (m_src[i]->is_int()) {
if (m_src[i]->get_int() == 0 && condition_uses_float(m_kind)) {
// if we're doing a floating point comparison, and one of our arguments is a constant
// which is an "integer zero", treat it as a floating point zero.
source_types.push_back(TypeSpec("float"));
} else {
source_types.push_back(TypeSpec("int"));
}
} else {
throw std::runtime_error("Unsupported atom in ConditionElement::push_to_stack");
}
}
if (m_flipped) {
std::reverse(vars.begin(), vars.end());
}
source_forms = pop_to_forms(vars, env, pool, stack, allow_side_effects, m_consumed);
popped_forms = pop_to_forms(vars, env, pool, stack, allow_side_effects, m_consumed);
if (m_flipped) {
std::reverse(source_forms.begin(), source_forms.end());
std::reverse(popped_forms.begin(), popped_forms.end());
}
int popped_counter = 0;
for (int i = 0; i < get_condition_num_args(m_kind); i++) {
if (m_src[i]->is_var()) {
source_forms.push_back(popped_forms.at(popped_counter++));
} else {
source_forms.push_back(pool.alloc_single_element_form<SimpleAtomElement>(nullptr, *m_src[i]));
}
}
assert(popped_counter == int(popped_forms.size()));
assert(source_forms.size() == source_types.size());
result->push_back(make_generic(env, pool, source_forms, source_types));
}
+2
View File
@@ -1463,6 +1463,8 @@ Form* cfg_to_ir(FormPool& pool, Function& f, const CfgVtx* vtx) {
nullptr, cfg_to_ir(pool, f, cvtx->body), cfg_to_ir(pool, f, cvtx->unreachable_block));
clean_up_break(pool, dynamic_cast<BreakElement*>(result->try_as_single_element()));
return result;
} else if (dynamic_cast<const EmptyVtx*>(vtx)) {
return pool.alloc_single_element_form<EmptyElement>(nullptr);
}
throw std::runtime_error("not yet implemented IR conversion.");
+17
View File
@@ -95,6 +95,23 @@ std::string final_defun_out(const Function& func,
append(top_form, pretty_print::build_list(inline_body));
return pretty_print::to_string(top_form);
}
if (func.guessed_name.kind == FunctionName::FunctionKind::UNIDENTIFIED) {
std::string def_name = "defun-anon";
assert(special_mode == FunctionDefSpecials::NONE);
std::vector<goos::Object> top;
top.push_back(pretty_print::to_symbol(def_name));
top.push_back(pretty_print::to_symbol(func.guessed_name.to_string()));
top.push_back(arguments);
auto top_form = pretty_print::build_list(top);
if (var_count > 0) {
append(top_form, pretty_print::build_list(var_dec));
}
append(top_form, pretty_print::build_list(inline_body));
return pretty_print::to_string(top_form);
}
return "nyi";
}
+12 -8
View File
@@ -197,6 +197,7 @@
(declare-type cpu-thread basic)
(declare-type state basic)
(declare-type dead-pool basic)
(declare-type event-message-block structure)
;; gkernel-h
(deftype thread (basic)
@@ -280,9 +281,9 @@
(state state :offset-assert #x38)
(trans-hook function :offset-assert #x3c)
(post-hook function :offset-assert #x40)
(event-hook (function stack-frame (function object) function state object) :offset-assert #x44)
(event-hook (function basic int basic event-message-block object) :offset-assert #x44)
(allocated-length int32 :offset-assert #x48)
(next-state basic :offset-assert #x4c)
(next-state state :offset-assert #x4c)
(heap-base pointer :offset-assert #x50)
(heap-top pointer :offset-assert #x54)
(heap-cur pointer :offset-assert #x58)
@@ -425,11 +426,14 @@
(trans (function object) :offset-assert 20)
(post function :offset-assert 24)
(enter (function object object object object object object object) :offset-assert 28)
(event basic :offset-assert 32)
(event (function basic int basic event-message-block object) :offset-assert 32)
)
(:methods
(new ((allocation symbol) (type-to-make type) (name basic) (code function)
(trans function) (enter function) (exit (function object)) (event function)) _type_ 0)
(trans (function object))
(enter (function object object object object object object object))
(exit (function object))
(event (function basic int basic event-message-block object))) _type_ 0)
)
:method-count-assert 9
:size-assert #x24
@@ -631,7 +635,7 @@
(define-extern copy-charp<-charp (function (pointer uint8) (pointer uint8) (pointer uint8)))
(define-extern cat-string<-string (function string string string))
(define-extern catn-string<-charp (function string (pointer uint8) int string))
(define-extern cat-string<-string_to_charp (function string string int (pointer uint8)))
(define-extern cat-string<-string_to_charp (function string string (pointer uint8) (pointer uint8)))
(define-extern append-character-to-string (function string uint8 int))
(define-extern charp-basename (function (pointer uint8) (pointer uint8)))
(define-extern clear (function string string))
@@ -639,9 +643,9 @@
(define-extern string>? (function string string symbol))
(define-extern string<=? (function string string symbol))
(define-extern string>=? (function string string symbol))
(define-extern string-skip-to-char (function (pointer uint8) uint8 (pointer uint8)))
(define-extern string-skip-to-char (function (pointer uint8) uint (pointer uint8)))
;; this one might be wrong
(define-extern string-cat-to-last-char (function uint8 string uint8 (pointer uint8)))
(define-extern string-cat-to-last-char (function string string uint (pointer uint8)))
(define-extern string-skip-whitespace (function (pointer uint8) (pointer uint8)))
(define-extern string-suck-up! (function string (pointer uint8) symbol))
(define-extern string-strip-leading-whitespace! (function string symbol))
@@ -689,7 +693,7 @@
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
(define-extern looping-code (function symbol))
(define-extern send-event-function (function process state object))
(define-extern send-event-function (function process event-message-block object))
(define-extern enter-state (function object object object object object object object))
(define-extern inherit-state (function state state state))
@@ -6,5 +6,9 @@
[28, "(function process symbol)"],
[30, "(function process symbol)"],
[32, "(function process symbol)"]
],
"hud":[
[15, "(function basic int basic event-message-block object)"]
]
}
@@ -105,6 +105,19 @@
"name=":[
[24, ["a1", "symbol"]],
[39, ["a0", "symbol"]]
]
],
"string-cat-to-last-char":[
[3, ["s5", "(pointer uint8)"]],
[4, ["s5", "string"]]
],
"string-strip-trailing-whitespace!":[
[15, ["v1", "(pointer uint8)"]]
],
"(anon-function 15 hud)":[
[0, ["s6", "hud"]]
]
}
@@ -236,6 +236,110 @@
"box-vector-inside?":{
"args":["box", "pt"]
},
"string=":{
"args":["str-a", "str-b"],
"vars":{"a2-0":"a-ptr", "v1-0":"b-ptr"}
},
"string-charp=":{
"args":["str", "charp"],
"vars":{"v1-0":"str-ptr"}
},
"copyn-string<-charp":{
"args":["str", "charp", "len"],
"vars":{"a3-0":"i", "v1-0":"str-ptr"}
},
"string<-charp":{
"args":["str", "charp"],
"vars":{"v1-0":"str-ptr"}
},
"charp<-string":{
"args":["charp", "str"],
"vars":{"v1-0":"str-ptr"}
},
"copy-charp<-charp":{
"args":["dst", "src"]
},
"cat-string<-string":{
"args":["a", "b"],
"vars":{"v1-0":"a-ptr", "a1-1":"b-ptr"}
},
"catn-string<-charp":{
"args":["a", "b", "len"],
"vars":{"v1-0":"a-ptr", "a3-2":"i"}
},
"cat-string<-string_to_charp":{
"args":["a", "b", "end-ptr"],
"vars":{"v1-0":"b-ptr", "v0-0":"a-ptr"}
},
"append-character-to-string":{
"args":["str", "char"],
"vars":{"v1-0":"str-ptr"}
},
"charp-basename":{
"args":["charp"],
"vars":{"v1-0":"ptr"}
},
"string<?":{
"args":["a", "b"],
"vars":{"s4-1":"len", "v1-4":"i"}
},
"string>?":{
"args":["a", "b"],
"vars":{"s4-1":"len", "v1-4":"i"}
},
"string<=?":{
"args":["a", "b"],
"vars":{"s4-1":"len", "v1-4":"i"}
},
"string>=?":{
"args":["a", "b"],
"vars":{"s4-1":"len", "v1-4":"i"}
},
"string-cat-to-last-char":{
"args":["base-str", "append-str", "char"],
"vars":{"s4-0":"end-of-append", "v1-0":"location-of-char"}
},
"string-suck-up!":{
"args":["str", "location"],
"vars":{"v1-2":"str-ptr"}
},
"string-strip-trailing-whitespace!":{
"args":["str"],
"vars":{"v1-6":"ptr"}
},
"string-get-arg!!":{
"args":["a-str", "arg"],
"vars":{"s4-0":"arg-word-start", "s4-1":"arg-end", "v1-3":"arg-start"}
},
"string->int":{
"args":["str"],
"vars":{"a0-1":"str-ptr", "v0-0":"result",
"a0-2":"next-char-1","a0-3":"next-char-2"}
},
"string-get-flag!!":{
"args":["result", "in", "first-flag", "second-flag"]
},
"(method 0 state)":{
"args":["allocation", "type-to-make", "name", "code", "trans", "enter", "exit", "event"],
"vars":{"v0-0":"obj"}
}
+7 -1
View File
@@ -277,7 +277,13 @@ TP_Type DecompilerTypeSystem::tp_lca(const TP_Type& existing,
*changed = true;
return TP_Type::make_from_ts("int");
case TP_Type::Kind::METHOD:
case TP_Type::Kind::VIRTUAL_METHOD:
// never allow this to remain method
*changed = true;
return TP_Type::make_from_ts(
ts.lowest_common_ancestor(existing.typespec(), add.typespec()));
case TP_Type::Kind::NON_VIRTUAL_METHOD:
// never allow this to remain method
*changed = true;
return TP_Type::make_from_ts(
+9 -3
View File
@@ -55,7 +55,9 @@ std::string TP_Type::print() const {
return fmt::format("<integer {} + ({} x {})>", m_int, m_extra_multiplier, m_ts.print());
case Kind::DYNAMIC_METHOD_ACCESS:
return fmt::format("<dynamic-method-access>");
case Kind::METHOD:
case Kind::VIRTUAL_METHOD:
return fmt::format("<vmethod {}>", m_ts.print());
case Kind::NON_VIRTUAL_METHOD:
return fmt::format("<method {}>", m_ts.print());
case Kind::INVALID:
default:
@@ -75,7 +77,9 @@ bool TP_Type::operator==(const TP_Type& other) const {
return m_ts == other.m_ts;
case Kind::TYPE_OF_TYPE_NO_VIRTUAL:
return m_ts == other.m_ts;
case Kind::METHOD:
case Kind::VIRTUAL_METHOD:
return m_ts == other.m_ts;
case Kind::NON_VIRTUAL_METHOD:
return m_ts == other.m_ts;
case Kind::FALSE_AS_NULL:
return true;
@@ -144,7 +148,9 @@ TypeSpec TP_Type::typespec() const {
return TypeSpec("object");
case Kind::FORMAT_STRING:
return TypeSpec("string");
case Kind::METHOD:
case Kind::VIRTUAL_METHOD:
return m_ts;
case Kind::NON_VIRTUAL_METHOD:
return m_ts;
case Kind::INVALID:
default:
+11 -3
View File
@@ -29,7 +29,8 @@ class TP_Type {
INTEGER_CONSTANT_PLUS_VAR, // constant + variable. for dynamic addr of
INTEGER_CONSTANT_PLUS_VAR_MULT, // like var + 100 + 12 * var2
DYNAMIC_METHOD_ACCESS, // partial access into a
METHOD,
VIRTUAL_METHOD,
NON_VIRTUAL_METHOD,
INVALID
} kind = Kind::UNINITIALIZED;
TP_Type() = default;
@@ -75,9 +76,16 @@ class TP_Type {
static TP_Type make_from_ts(const std::string& ts) { return make_from_ts(TypeSpec(ts)); }
static TP_Type make_method(const TypeSpec& method_type) {
static TP_Type make_virtual_method(const TypeSpec& method_type) {
TP_Type result;
result.kind = Kind::METHOD;
result.kind = Kind::VIRTUAL_METHOD;
result.m_ts = method_type;
return result;
}
static TP_Type make_non_virtual_method(const TypeSpec& method_type) {
TP_Type result;
result.kind = Kind::NON_VIRTUAL_METHOD;
result.m_ts = method_type;
return result;
}