From c72ca18f00fea767d79005273dbe37b1b3af4057 Mon Sep 17 00:00:00 2001 From: Tyler Wilding Date: Thu, 15 Oct 2020 00:34:52 -0400 Subject: [PATCH 1/3] Add auto-generated `inspect` methods to `deftypes` --- goalc/compiler/Compiler.h | 6 +++ goalc/compiler/compilation/Type.cpp | 72 +++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/goalc/compiler/Compiler.h b/goalc/compiler/Compiler.h index 1720f4e45c..e8e741260b 100644 --- a/goalc/compiler/Compiler.h +++ b/goalc/compiler/Compiler.h @@ -116,6 +116,12 @@ 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 args, + const std::string& out_stream = "#t"); + 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); diff --git a/goalc/compiler/compilation/Type.cpp b/goalc/compiler/compilation/Type.cpp index 3ca6d014e4..a5d46c9c57 100644 --- a/goalc/compiler/compilation/Type.cpp +++ b/goalc/compiler/compilation/Type.cpp @@ -85,6 +85,75 @@ 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 args, + const std::string& out_stream) { + // Add first two format args + args.insert(args.begin(), compile_string(fmt_template, env, DEBUG_SEGMENT)->to_reg(env)); + args.insert(args.begin(), compile_get_sym_obj(out_stream, env)->to_reg(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); +} + +Val* Compiler::generate_inspector_for_type(const goos::Object& form, Env* env, Type* type) { + auto as_structure_type = dynamic_cast(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(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); + + std::string str_template = ""; + std::vector formatArgs = {}; + + // Check if there are no fields + if (structured_type->fields().empty()) { + str_template = "Type has no fields!~%"; + } else { + for (Field f : structured_type->fields()) { + str_template += "~A~%"; + formatArgs.push_back( + compile_string(f.print(), method_env.get(), DEBUG_SEGMENT)->to_reg(method_env.get())); + } + } + + compile_format_string(form, method_env.get(), str_template, formatArgs); + + // add this function to the object file + auto fe = get_parent_env_of_type(env); + auto method = fe->alloc_val(m_ts.make_typespec("function")); + method->func = method_env.get(); + auto obj_env_inspect = get_parent_env_of_type(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 +182,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(); } From 28d732737f9829b959041b65f609557e97fa708f Mon Sep 17 00:00:00 2001 From: Tyler Wilding Date: Thu, 15 Oct 2020 21:13:52 -0400 Subject: [PATCH 2/3] More customized format depending on the field type --- goalc/compiler/Compiler.h | 6 +++ goalc/compiler/compilation/Type.cpp | 65 +++++++++++++++++++++++++---- 2 files changed, 62 insertions(+), 9 deletions(-) diff --git a/goalc/compiler/Compiler.h b/goalc/compiler/Compiler.h index e8e741260b..0f6c4164f4 100644 --- a/goalc/compiler/Compiler.h +++ b/goalc/compiler/Compiler.h @@ -121,6 +121,12 @@ class Compiler { std::string& fmt_template, std::vector args, const std::string& out_stream = "#t"); + void generate_field_description(StructureType* type, + Env* env, + RegVal* reg, + Field f, + std::vector 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, diff --git a/goalc/compiler/compilation/Type.cpp b/goalc/compiler/compilation/Type.cpp index a5d46c9c57..7ea0f9110f 100644 --- a/goalc/compiler/compilation/Type.cpp +++ b/goalc/compiler/compilation/Type.cpp @@ -91,14 +91,61 @@ Val* Compiler::compile_format_string(const goos::Object& form, std::vector args, const std::string& out_stream) { // Add first two format args - args.insert(args.begin(), compile_string(fmt_template, env, DEBUG_SEGMENT)->to_reg(env)); - args.insert(args.begin(), compile_get_sym_obj(out_stream, env)->to_reg(env)); + args.insert(args.begin(), + compile_string(fmt_template, env, get_parent_env_of_type(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 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(type); if (!as_structure_type) { // generate the inspect method @@ -122,21 +169,21 @@ Val* Compiler::generate_inspector_for_type(const goos::Object& form, Env* env, T constraint.desired_register = emitter::gRegInfo.get_arg_reg(0); // to the first argument method_env->constrain(constraint); - std::string str_template = ""; - std::vector formatArgs = {}; + std::string str_template = fmt::format("~T- type: ~T{}~%", type->get_name()); + std::vector format_args = {}; // Check if there are no fields if (structured_type->fields().empty()) { - str_template = "Type has no fields!~%"; + str_template += "~T- No fields!~%"; } else { for (Field f : structured_type->fields()) { - str_template += "~A~%"; - formatArgs.push_back( - compile_string(f.print(), method_env.get(), DEBUG_SEGMENT)->to_reg(method_env.get())); + generate_field_description(structured_type, method_env.get(), input, f, format_args, + str_template); } } - compile_format_string(form, method_env.get(), str_template, formatArgs); + compile_format_string(form, method_env.get(), str_template, format_args); + method_env->emit(std::make_unique(method_env->make_gpr(input->type()), input)); // add this function to the object file auto fe = get_parent_env_of_type(env); From b8a4a4e7fb67c9068b4bdd1b94c53362e16b8255 Mon Sep 17 00:00:00 2001 From: Tyler Wilding Date: Thu, 15 Oct 2020 21:58:15 -0400 Subject: [PATCH 3/3] Correct compiler error --- goalc/compiler/compilation/Type.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/goalc/compiler/compilation/Type.cpp b/goalc/compiler/compilation/Type.cpp index 7ea0f9110f..6efb13c252 100644 --- a/goalc/compiler/compilation/Type.cpp +++ b/goalc/compiler/compilation/Type.cpp @@ -168,6 +168,8 @@ Val* Compiler::generate_inspector_for_type(const goos::Object& form, Env* env, T 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(std::vector{input})); std::string str_template = fmt::format("~T- type: ~T{}~%", type->get_name()); std::vector format_args = {}; @@ -183,7 +185,7 @@ Val* Compiler::generate_inspector_for_type(const goos::Object& form, Env* env, T } compile_format_string(form, method_env.get(), str_template, format_args); - method_env->emit(std::make_unique(method_env->make_gpr(input->type()), input)); + method_env->emit(std::make_unique(method_env->make_gpr(input->type()), input)); // add this function to the object file auto fe = get_parent_env_of_type(env);