mirror of
https://github.com/open-goal/jak-project.git
synced 2025-02-25 16:40:57 +00:00
Merge pull request #84 from xTVaser/goalc/auto-inspect
Add auto-generated `inspect` methods to `deftypes`
This commit is contained in:
commit
118a1b29e3
@ -116,6 +116,18 @@ class Compiler {
|
||||
|
||||
Val* compile_variable_shift(const RegVal* in, const RegVal* sa, Env* env, IntegerMathKind kind);
|
||||
|
||||
Val* compile_format_string(const goos::Object& form,
|
||||
Env* env,
|
||||
std::string& fmt_template,
|
||||
std::vector<RegVal*> args,
|
||||
const std::string& out_stream = "#t");
|
||||
void generate_field_description(StructureType* type,
|
||||
Env* env,
|
||||
RegVal* reg,
|
||||
Field f,
|
||||
std::vector<RegVal*> format_args,
|
||||
std::string& str_template);
|
||||
Val* generate_inspector_for_type(const goos::Object& form, Env* env, Type* type);
|
||||
RegVal* compile_get_method_of_type(const TypeSpec& type,
|
||||
const std::string& method_name,
|
||||
Env* env);
|
||||
|
@ -85,6 +85,124 @@ RegVal* Compiler::compile_get_method_of_object(RegVal* object,
|
||||
return deref->to_reg(env);
|
||||
}
|
||||
|
||||
Val* Compiler::compile_format_string(const goos::Object& form,
|
||||
Env* env,
|
||||
std::string& fmt_template,
|
||||
std::vector<RegVal*> args,
|
||||
const std::string& out_stream) {
|
||||
// Add first two format args
|
||||
args.insert(args.begin(),
|
||||
compile_string(fmt_template, env, get_parent_env_of_type<FunctionEnv>(env)->segment)
|
||||
->to_gpr(env));
|
||||
args.insert(args.begin(), compile_get_sym_obj(out_stream, env)->to_gpr(env));
|
||||
|
||||
// generate code in the method_env
|
||||
auto format_function = compile_get_symbol_value("_format", env)->to_gpr(env);
|
||||
return compile_real_function_call(form, format_function, args, env);
|
||||
}
|
||||
|
||||
void Compiler::generate_field_description(StructureType* type,
|
||||
Env* env,
|
||||
RegVal* reg,
|
||||
Field f,
|
||||
std::vector<RegVal*> format_args,
|
||||
std::string& str_template) {
|
||||
if (m_ts.typecheck(m_ts.make_typespec("type"), f.type(), "", false, false)) {
|
||||
// type
|
||||
return;
|
||||
} else if (m_ts.typecheck(m_ts.make_typespec("basic"), f.type(), "", false, false) ||
|
||||
m_ts.typecheck(m_ts.make_typespec("binteger"), f.type(), "", false, false) ||
|
||||
m_ts.typecheck(m_ts.make_typespec("pair"), f.type(), "", false, false)) {
|
||||
// basic, binteger, pair
|
||||
str_template += fmt::format("~T- {}: ~T~A~%", f.name());
|
||||
format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(env));
|
||||
} else if (m_ts.typecheck(m_ts.make_typespec("integer"), f.type(), "", false, false)) {
|
||||
// Integer
|
||||
str_template += fmt::format("~T- {}: ~T~D~%", f.name());
|
||||
format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(env));
|
||||
} else if (m_ts.typecheck(m_ts.make_typespec("float"), f.type(), "", false, false)) {
|
||||
// Float
|
||||
str_template += fmt::format("~T- {}: ~T~f~%", f.name());
|
||||
format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(env));
|
||||
} else if (m_ts.typecheck(m_ts.make_typespec("pointer"), f.type(), "", false, false)) {
|
||||
// Pointers
|
||||
str_template += fmt::format("~T- {}: ~T#x~X~%", f.name());
|
||||
format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(env));
|
||||
} else if (f.is_array()) {
|
||||
// Arrays
|
||||
str_template += fmt::format("~T- {}[{}]: ~T@ #x~X~%", f.name(), f.array_size());
|
||||
format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(env));
|
||||
} else if (f.is_dynamic()) {
|
||||
// Dynamic Field
|
||||
str_template += fmt::format("~T- {}[0]: ~T@ #x~X~%", f.name());
|
||||
format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(env));
|
||||
} else if (f.is_dynamic()) {
|
||||
// Structure
|
||||
str_template += fmt::format("~T- {}: ~T#<{} @ #x~X>~%", f.name(), f.type().print());
|
||||
format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(env));
|
||||
} else {
|
||||
// Otherwise, we havn't implemented it!
|
||||
str_template += fmt::format("~T- {}: ~TUndefined!~%", f.name());
|
||||
}
|
||||
}
|
||||
|
||||
Val* Compiler::generate_inspector_for_type(const goos::Object& form, Env* env, Type* type) {
|
||||
auto as_structure_type = dynamic_cast<StructureType*>(type);
|
||||
if (!as_structure_type) { // generate the inspect method
|
||||
return get_none();
|
||||
}
|
||||
|
||||
StructureType* structured_type = as_structure_type;
|
||||
|
||||
// Create a function environment to hold the code for the inspect method. The name is just for
|
||||
// debugging.
|
||||
auto method_env = std::make_unique<FunctionEnv>(env, "autogenerated-inspect-method");
|
||||
// put the method in the debug segment.
|
||||
method_env->set_segment(DEBUG_SEGMENT);
|
||||
|
||||
// Create a register which will hold the input to the inspect method
|
||||
auto input = method_env->make_ireg(structured_type->get_name(), emitter::RegKind::GPR);
|
||||
// "Constraint" this register to be the register that the function argument is passed in
|
||||
IRegConstraint constraint;
|
||||
constraint.instr_idx = 0; // constraint at the start of the function
|
||||
constraint.ireg = input->ireg(); // constrain this register
|
||||
constraint.desired_register = emitter::gRegInfo.get_arg_reg(0); // to the first argument
|
||||
method_env->constrain(constraint);
|
||||
// Inform the compiler that `input`'s value will be written to `rdi` (first arg register)
|
||||
method_env->emit(std::make_unique<IR_FunctionStart>(std::vector<RegVal*>{input}));
|
||||
|
||||
std::string str_template = fmt::format("~T- type: ~T{}~%", type->get_name());
|
||||
std::vector<RegVal*> format_args = {};
|
||||
|
||||
// Check if there are no fields
|
||||
if (structured_type->fields().empty()) {
|
||||
str_template += "~T- No fields!~%";
|
||||
} else {
|
||||
for (Field f : structured_type->fields()) {
|
||||
generate_field_description(structured_type, method_env.get(), input, f, format_args,
|
||||
str_template);
|
||||
}
|
||||
}
|
||||
|
||||
compile_format_string(form, method_env.get(), str_template, format_args);
|
||||
method_env->emit(std::make_unique<IR_Return>(method_env->make_gpr(input->type()), input));
|
||||
|
||||
// add this function to the object file
|
||||
auto fe = get_parent_env_of_type<FunctionEnv>(env);
|
||||
auto method = fe->alloc_val<LambdaVal>(m_ts.make_typespec("function"));
|
||||
method->func = method_env.get();
|
||||
auto obj_env_inspect = get_parent_env_of_type<FileEnv>(method_env.get());
|
||||
obj_env_inspect->add_function(std::move(method_env));
|
||||
|
||||
// call method-set!
|
||||
auto type_obj = compile_get_symbol_value(structured_type->get_name(), env)->to_gpr(env);
|
||||
auto id_val = compile_integer(m_ts.lookup_method(structured_type->get_name(), "inspect").id, env)
|
||||
->to_gpr(env);
|
||||
auto method_set_val = compile_get_symbol_value("method-set!", env)->to_gpr(env);
|
||||
return compile_real_function_call(form, method_set_val, {type_obj, id_val, method->to_gpr(env)},
|
||||
env);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Compile a (deftype ... form)
|
||||
*/
|
||||
@ -113,6 +231,9 @@ Val* Compiler::compile_deftype(const goos::Object& form, const goos::Object& res
|
||||
auto flags_int = compile_integer(result.flags.flag, env)->to_gpr(env);
|
||||
compile_real_function_call(form, new_type_method, {new_type_symbol, parent_type, flags_int}, env);
|
||||
|
||||
// Auto-generate (inspect) method
|
||||
generate_inspector_for_type(form, env, result.type_info);
|
||||
|
||||
// return none, making the value of (deftype..) unusable
|
||||
return get_none();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user