Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support dir tpages #671

Merged
merged 5 commits into from
Jul 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions common/type_system/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ std::string reg_kind_to_string(RegClass kind) {
*/
bool MethodInfo::operator==(const MethodInfo& other) const {
return id == other.id && name == other.name && type == other.type &&
defined_in_type == other.defined_in_type && other.no_virtual == no_virtual;
defined_in_type == other.defined_in_type && other.no_virtual == no_virtual &&
other.overrides_method_type_of_parent == overrides_method_type_of_parent;
}

std::string MethodInfo::diff(const MethodInfo& other) const {
Expand All @@ -56,6 +57,11 @@ std::string MethodInfo::diff(const MethodInfo& other) const {
if (no_virtual != other.no_virtual) {
result += fmt::format("no_virtual: {} vs. {}\n", no_virtual, other.no_virtual);
}

if (overrides_method_type_of_parent != other.overrides_method_type_of_parent) {
result += fmt::format("overrides_method_type_of_parent: {} vs. {}\n",
overrides_method_type_of_parent, other.overrides_method_type_of_parent);
}
return result;
}

Expand Down Expand Up @@ -311,9 +317,11 @@ bool Type::get_my_method(int id, MethodInfo* out) const {
* defined specifically for this type or not.
*/
bool Type::get_my_last_method(MethodInfo* out) const {
if (!m_methods.empty()) {
*out = m_methods.back();
return true;
for (auto it = m_methods.rbegin(); it != m_methods.rend(); it++) {
if (!it->overrides_method_type_of_parent) {
*out = *it;
return true;
}
}
return false;
}
Expand All @@ -334,9 +342,13 @@ bool Type::get_my_new_method(MethodInfo* out) const {
* Add a method defined specifically for this type.
*/
const MethodInfo& Type::add_method(const MethodInfo& info) {
if (!m_methods.empty()) {
assert(m_methods.back().id + 1 == info.id);
for (auto it = m_methods.rbegin(); it != m_methods.rend(); it++) {
if (!it->overrides_method_type_of_parent) {
assert(it->id + 1 == info.id);
break;
}
}

m_methods.push_back(info);
return m_methods.back();
}
Expand Down
1 change: 1 addition & 0 deletions common/type_system/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ struct MethodInfo {
TypeSpec type;
std::string defined_in_type;
bool no_virtual = false;
bool overrides_method_type_of_parent = false;

bool operator==(const MethodInfo& other) const;
bool operator!=(const MethodInfo& other) const { return !((*this) == other); }
Expand Down
15 changes: 11 additions & 4 deletions common/type_system/TypeFieldLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ void try_reverse_lookup_other(const FieldReverseLookupInput& input,
FieldReverseMultiLookupOutput* output,
int max_count);

std::vector<FieldReverseLookupOutput::Token> parent_to_vector(const ReverseLookupNode* parent) {
if (!parent) {
return {};
}
return parent->to_vector();
}

/*!
* Handle a dereference of a pointer/boxed array. This can be:
* - just dereferencing a pointer
Expand Down Expand Up @@ -188,15 +195,15 @@ void try_reverse_lookup_array_like(const FieldReverseLookupInput& input,
// also just return the array
if (elt_idx == 0) {
if (boxed_array) {
auto vec = parent->to_vector();
auto vec = parent_to_vector(parent);
FieldReverseLookupOutput::Token tok;
tok.kind = FieldReverseLookupOutput::Token::Kind::FIELD;
tok.field_score = 0.0; // don't bother
tok.name = "data";
vec.push_back(tok);
output->results.emplace_back(false, array_data_type, vec);
} else {
auto parent_vector = parent->to_vector();
auto parent_vector = parent_to_vector(parent);
if (!parent_vector.empty()) {
output->results.emplace_back(false, input.base_type, parent_vector);
}
Expand Down Expand Up @@ -280,9 +287,9 @@ void try_reverse_lookup_inline_array(const FieldReverseLookupInput& input,

// can we just return the array?
if (expected_offset_into_elt == offset_into_elt && !input.deref.has_value() && elt_idx == 0) {
auto parent_vec = parent->to_vector();
auto parent_vec = parent_to_vector(parent);
if (!parent_vec.empty()) {
output->results.emplace_back(false, input.base_type, parent->to_vector());
output->results.emplace_back(false, input.base_type, parent_to_vector(parent));
}

if ((int)output->results.size() >= max_count) {
Expand Down
117 changes: 72 additions & 45 deletions common/type_system/TypeSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -477,8 +477,10 @@ int TypeSystem::get_load_size_allow_partial_def(const TypeSpec& ts) const {
MethodInfo TypeSystem::declare_method(const std::string& type_name,
const std::string& method_name,
bool no_virtual,
const TypeSpec& ts) {
return declare_method(lookup_type(make_typespec(type_name)), method_name, no_virtual, ts);
const TypeSpec& ts,
bool override_type) {
return declare_method(lookup_type(make_typespec(type_name)), method_name, no_virtual, ts,
override_type);
}

/*!
Expand All @@ -493,43 +495,61 @@ MethodInfo TypeSystem::declare_method(const std::string& type_name,
MethodInfo TypeSystem::declare_method(Type* type,
const std::string& method_name,
bool no_virtual,
const TypeSpec& ts) {
const TypeSpec& ts,
bool override_type) {
if (method_name == "new") {
if (override_type) {
throw_typesystem_error("Cannot use :replace option with a new method.");
}
return add_new_method(type, ts);
}

// look up the method
MethodInfo existing_info;
bool got_existing = try_lookup_method(type, method_name, &existing_info);

if (got_existing) {
// make sure we aren't changing anything.
if (!existing_info.type.is_compatible_child_method(ts, type->get_name())) {
if (override_type) {
if (!got_existing) {
throw_typesystem_error(
"The method {} of type {} was originally declared as {}, but has been "
"redeclared as {}\n",
method_name, type->get_name(), existing_info.type.print(), ts.print());
"Cannot use :replace on method {} of {} because this method was not previously declared "
"in a parent.",
method_name, type->get_name());
}

if ((existing_info.no_virtual || no_virtual) &&
existing_info.defined_in_type != type->get_name()) {
throw_typesystem_error(
"Cannot define method {} in type {} when it was defined as no_virtual in parent type {}",
method_name, type->get_name(), existing_info.defined_in_type);
}
// use the existing ID.
return type->add_method(
{existing_info.id, method_name, ts, type->get_name(), no_virtual, true});
} else {
if (got_existing) {
// make sure we aren't changing anything.
if (!existing_info.type.is_compatible_child_method(ts, type->get_name())) {
throw_typesystem_error(
"The method {} of type {} was originally declared as {}, but has been "
"redeclared as {}\n",
method_name, type->get_name(), existing_info.type.print(), ts.print());
}

if (no_virtual != existing_info.no_virtual) {
throw_typesystem_error(
"The method {} of type {} was originally declared with no_virtual = {}, but has been "
"redeclared as {}",
method_name, type->get_name(), existing_info.no_virtual, no_virtual);
}
if ((existing_info.no_virtual || no_virtual) &&
existing_info.defined_in_type != type->get_name()) {
throw_typesystem_error(
"Cannot define method {} in type {} when it was defined as no_virtual in parent type "
"{}",
method_name, type->get_name(), existing_info.defined_in_type);
}

return existing_info;
} else {
// add a new method!
return type->add_method(
{get_next_method_id(type), method_name, ts, type->get_name(), no_virtual});
if (no_virtual != existing_info.no_virtual) {
throw_typesystem_error(
"The method {} of type {} was originally declared with no_virtual = {}, but has been "
"redeclared as {}",
method_name, type->get_name(), existing_info.no_virtual, no_virtual);
}

return existing_info;
} else {
// add a new method!
return type->add_method(
{get_next_method_id(type), method_name, ts, type->get_name(), no_virtual, false});
}
}
}

Expand Down Expand Up @@ -955,23 +975,25 @@ void TypeSystem::add_builtin_types() {

// OBJECT
declare_method(obj_type, "new", false,
make_function_typespec({"symbol", "type", "int"}, "_type_"));
declare_method(obj_type, "delete", false, make_function_typespec({"_type_"}, "none"));
declare_method(obj_type, "print", false, make_function_typespec({"_type_"}, "_type_"));
declare_method(obj_type, "inspect", false, make_function_typespec({"_type_"}, "_type_"));
declare_method(obj_type, "length", false,
make_function_typespec({"_type_"}, "int")); // todo - this integer type?
declare_method(obj_type, "asize-of", false, make_function_typespec({"_type_"}, "int"));
declare_method(obj_type, "copy", false, make_function_typespec({"_type_", "symbol"}, "_type_"));
declare_method(obj_type, "relocate", false, make_function_typespec({"_type_", "int"}, "_type_"));
make_function_typespec({"symbol", "type", "int"}, "_type_"), false);
declare_method(obj_type, "delete", false, make_function_typespec({"_type_"}, "none"), false);
declare_method(obj_type, "print", false, make_function_typespec({"_type_"}, "_type_"), false);
declare_method(obj_type, "inspect", false, make_function_typespec({"_type_"}, "_type_"), false);
declare_method(obj_type, "length", false, make_function_typespec({"_type_"}, "int"),
false); // todo - this integer type?
declare_method(obj_type, "asize-of", false, make_function_typespec({"_type_"}, "int"), false);
declare_method(obj_type, "copy", false, make_function_typespec({"_type_", "symbol"}, "_type_"),
false);
declare_method(obj_type, "relocate", false, make_function_typespec({"_type_", "int"}, "_type_"),
false);
declare_method(obj_type, "mem-usage", false,
make_function_typespec({"_type_", "memory-usage-block", "int"}, "_type_"));
make_function_typespec({"_type_", "memory-usage-block", "int"}, "_type_"), false);

// STRUCTURE
// structure new doesn't support dynamic sizing, which is kinda weird - it grabs the size from
// the type. Dynamic structures use new-dynamic-structure, which is used exactly once ever.
declare_method(structure_type, "new", false,
make_function_typespec({"symbol", "type"}, "_type_"));
declare_method(structure_type, "new", false, make_function_typespec({"symbol", "type"}, "_type_"),
false);
// structure_type is a field-less StructureType, so we have to do this to match the runtime.
// structure_type->override_size_in_memory(4);

Expand All @@ -980,18 +1002,19 @@ void TypeSystem::add_builtin_types() {
add_field_to_type(basic_type, "type", make_typespec("type"));
// the default new basic doesn't support dynamic sizing. anything dynamic will override this
// and then call (method object new) to do the dynamically-sized allocation.
declare_method(basic_type, "new", false, make_function_typespec({"symbol", "type"}, "_type_"));
declare_method(basic_type, "new", false, make_function_typespec({"symbol", "type"}, "_type_"),
false);

// SYMBOL
builtin_structure_inherit(symbol_type);
add_field_to_type(symbol_type, "value", make_typespec("object"));
// a new method which returns type none means new is illegal.
declare_method(symbol_type, "new", false, make_function_typespec({}, "none"));
declare_method(symbol_type, "new", false, make_function_typespec({}, "none"), false);

// TYPE
builtin_structure_inherit(type_type);
declare_method(type_type, "new", false,
make_function_typespec({"symbol", "type", "int"}, "_type_"));
make_function_typespec({"symbol", "type", "int"}, "_type_"), false);
add_field_to_type(type_type, "symbol", make_typespec("symbol"));
add_field_to_type(type_type, "parent", make_typespec("type"));
add_field_to_type(type_type, "size", make_typespec("uint16")); // actually u16
Expand All @@ -1008,7 +1031,7 @@ void TypeSystem::add_builtin_types() {
// string is never deftype'd for the decompiler, so we need to manually give the constructor
// type here.
declare_method(string_type, "new", false,
make_function_typespec({"symbol", "type", "int", "string"}, "_type_"));
make_function_typespec({"symbol", "type", "int", "string"}, "_type_"), false);

// FUNCTION
builtin_structure_inherit(function_type);
Expand Down Expand Up @@ -1037,7 +1060,7 @@ void TypeSystem::add_builtin_types() {
// todo
builtin_structure_inherit(array_type);
declare_method(array_type, "new", false,
make_function_typespec({"symbol", "type", "type", "int"}, "_type_"));
make_function_typespec({"symbol", "type", "type", "int"}, "_type_"), false);
// array has: number, number, type
add_field_to_type(array_type, "length", make_typespec("int32"));
add_field_to_type(array_type, "allocated-length", make_typespec("int32"));
Expand All @@ -1047,7 +1070,7 @@ void TypeSystem::add_builtin_types() {
// pair
pair_type->override_offset(2);
declare_method(pair_type, "new", false,
make_function_typespec({"symbol", "type", "object", "object"}, "_type_"));
make_function_typespec({"symbol", "type", "object", "object"}, "_type_"), false);
add_field_to_type(pair_type, "car", make_typespec("object"));
add_field_to_type(pair_type, "cdr", make_typespec("object"));

Expand All @@ -1065,7 +1088,7 @@ void TypeSystem::add_builtin_types() {
add_field_to_type(file_stream_type, "name", make_typespec("string"));
add_field_to_type(file_stream_type, "file", make_typespec("uint32"));
declare_method(file_stream_type, "new", false,
make_function_typespec({"symbol", "type", "string", "basic"}, "_type_"));
make_function_typespec({"symbol", "type", "string", "basic"}, "_type_"), false);
}

/*!
Expand Down Expand Up @@ -1590,6 +1613,10 @@ std::string TypeSystem::generate_deftype_footer(const Type* type) const {
methods_string.append(":no-virtual ");
}

if (info.overrides_method_type_of_parent) {
methods_string.append(":replace ");
}

methods_string.append(fmt::format("{})\n ", info.id));
}

Expand Down
7 changes: 4 additions & 3 deletions common/type_system/TypeSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,13 @@ class TypeSystem {
MethodInfo declare_method(const std::string& type_name,
const std::string& method_name,
bool no_virtual,
const TypeSpec& ts);
const TypeSpec& ts,
bool override_type);
MethodInfo declare_method(Type* type,
const std::string& method_name,
bool no_virtual,
const TypeSpec& ts);

const TypeSpec& ts,
bool override_type);
MethodInfo define_method(const std::string& type_name,
const std::string& method_name,
const TypeSpec& ts);
Expand Down
9 changes: 8 additions & 1 deletion common/type_system/deftype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,12 +188,18 @@ void declare_method(Type* type, TypeSystem* type_system, const goos::Object& def
obj = cdr(obj);

bool no_virtual = false;
bool replace_method = false;

if (!obj->is_empty_list() && car(obj).is_symbol(":no-virtual")) {
obj = cdr(obj);
no_virtual = true;
}

if (!obj->is_empty_list() && car(obj).is_symbol(":replace")) {
obj = cdr(obj);
replace_method = true;
}

int id = -1;
if (!obj->is_empty_list() && car(obj).is_int()) {
auto& id_obj = car(obj);
Expand All @@ -212,7 +218,8 @@ void declare_method(Type* type, TypeSystem* type_system, const goos::Object& def
});
function_typespec.add_arg(parse_typespec(type_system, return_type));

auto info = type_system->declare_method(type, method_name, no_virtual, function_typespec);
auto info = type_system->declare_method(type, method_name, no_virtual, function_typespec,
replace_method);

// check the method assert
if (id != -1) {
Expand Down
1 change: 1 addition & 0 deletions decompiler/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ add_library(
analysis/type_analysis.cpp
analysis/variable_naming.cpp

data/dir_tpages.cpp
data/game_count.cpp
data/game_text.cpp
data/StrFileReader.cpp
Expand Down
Loading