diff options
Diffstat (limited to 'tiger-compiler/src/object/desugar-visitor.cc')
| -rw-r--r-- | tiger-compiler/src/object/desugar-visitor.cc | 1127 |
1 files changed, 1127 insertions, 0 deletions
diff --git a/tiger-compiler/src/object/desugar-visitor.cc b/tiger-compiler/src/object/desugar-visitor.cc new file mode 100644 index 0000000..db61a80 --- /dev/null +++ b/tiger-compiler/src/object/desugar-visitor.cc @@ -0,0 +1,1127 @@ +/** + ** \file object/desugar-visitor.cc + ** \brief Implementation of object::DesugarVisitor. + */ + +#include <sstream> + +#include <algorithm> +#include <ast/all.hh> +#include <misc/contract.hh> +#include <misc/set.hh> +#include <misc/symbol.hh> +#include <object/desugar-visitor.hh> +#include <parse/libparse.hh> +#include <parse/tweast.hh> +#include <type/class.hh> +#include <type/function.hh> +#include <type/record.hh> + +namespace object +{ + DesugarVisitor::DesugarVisitor(const class_names_type& names) + : class_names_(names) + {} + + /*---------------------------. + | Handling names and types. | + `---------------------------*/ + + namespace + { + // Desugar prefixes. + + // Prefix of every class id (label). + const char* class_id_prefix = "_id_"; + // Prefix of every record holding the contents of a desugared class. + const char* class_contents_prefix = "_contents_"; + // Prefix of every variant storing the possible dynamic type for + // a given static type. + const char* class_variant_prefix = "_variant_"; + // Prefix of the fields in the variant. + const char* variant_field_prefix = "field_"; + // Prefix of constructors. + const char* class_ctor_prefix = "_new_"; + // Prefix of methods. + const char* method_prefix = "_method_"; + + // Useful routines. + + // Try to get the class type of \a t. If \a t is not a class + // type, return a null pointer. + const type::Class* class_type_query(const ast::Typable& t) + { + // FIXME DONE: Some code was deleted here. + return dynamic_cast<const type::Class*>(&t.type_get()->actual()); + } + + // Like class_type_query, but ensure the type is actually a class. + const type::Class* class_type_get(const ast::Typable& t) + { + const type::Class* class_type = class_type_query(t); + postcondition(class_type); + return class_type; + } + + } // namespace + + /*------------------. + | Code generation. | + `------------------*/ + + std::string DesugarVisitor::type_symbol(const type::Type* type) + { + // FIXME DONE: Some code was deleted here (Check int, then string, then class name). + if (dynamic_cast<const type::Int*>(type)) + { + return "int"; + } + else if (dynamic_cast<const type::String*>(type)) + { + return "string"; + } + else if (const auto named = dynamic_cast<const type::Named*>(type)) + { + return named->name_get().get(); + } + else + { + throw std::invalid_argument("type was neither a builtin or named"); + } + } + + std::string DesugarVisitor::upcast_fun_name(const type::Class* from, + const type::Class* to) + { + std::stringstream s; + s << "_upcast_" << class_names_(from) << "_to_" << class_names_(to); + return s.str(); + } + + std::string DesugarVisitor::downcast_fun_name(const type::Class* from, + const type::Class* to) + { + std::stringstream s; + s << "_downcast_" << class_names_(from) << "_to_" << class_names_(to); + return s.str(); + } + + std::string DesugarVisitor::dispatch_fun_name(const type::Class* owner, + const type::Method* method) + { + std::stringstream s; + // If an extension is found, add it to the dispatch suffix. + if (dispatch_map_.find(method) != dispatch_map_.end()) + s << "_dispatch_" << dispatch_map_[method] << "_" << class_names_(owner) + << "_" << method->name_get(); + else + s << "_dispatch_" << class_names_(owner) << "_" << method->name_get(); + + return s.str(); + } + + void DesugarVisitor::adapt_type(ast::Exp*& source_exp, + const type::Class* source_type, + const type::Class* target_type) + { + // If the source type is different from the target type, (up)cast + // the source expression to the latter. + if (source_type && target_type && source_type != target_type) + source_exp = parse::parse(parse::Tweast() + << upcast_fun_name(source_type, target_type) + << " (" << source_exp << ")"); + } + + ast::Exp* DesugarVisitor::variant_exp(const type::Class* static_type, + const std::string& exact_type, + const field_inits_type& inits) + { + parse::Tweast input; + misc::symbol static_type_name = class_names_(static_type); + input << " " << class_variant_prefix << static_type_name + << " {" + " exact_type = " + << exact_type; + /* For each field of the variant, store the corresponding + initialization value if one was given, otherwise set the field + to `nil'. */ + // Fields of the static type. + for (const type::Class* c = static_type; c; c = c->super_get()) + // Don't generate slots for classes with no data. + if (c->has_data()) + { + input << ",\n" << variant_field_prefix << class_names_(c) << " = "; + // These fields must have a value (we don't need to put an + // assertion here, misc::map::operator() already handles this. + std::string init = inits.operator()(c); + input << init; + } + // Potential fields of the dynamic type (from subclasses of the + // static type). + for (const type::Class* subclass : static_type->subclasses_get()) + // Don't generate slots for classes with no data. + if (subclass->has_data()) + { + input << ",\n" + << variant_field_prefix << class_names_(subclass) << " = "; + // These fields might be nil. + const auto i = inits.find(subclass); + if (i != inits.end()) + input << i->second; + else + input << "nil"; + } + input << " }\n"; + return parse::parse(input); + } + + // Syntactic sugar. + ast::Exp* DesugarVisitor::variant_exp(const type::Class* static_type, + const type::Class* dynamic_type, + const field_inits_type& inits) + { + std::string exact_type = class_id_prefix + class_names_(dynamic_type).get(); + return variant_exp(static_type, exact_type, inits); + } + + void DesugarVisitor::fill_variant_fields(const type::Class* class_type, + parse::Tweast* input) + { + // Don't generate slots for classes with no data. + if (class_type->has_data()) + { + misc::symbol class_name = class_names_(class_type); + *input << ",\n" + << " " << variant_field_prefix << class_name << " : " + << " " << class_contents_prefix << class_name; + } + } + + // Desugar a class type as a variant (record) type. + parse::Tweast* DesugarVisitor::variant_ty(const type::Class* class_type) + { + auto input = new parse::Tweast; + *input << " {" + << " exact_type : int"; + // Actual data slots. + /* First, populate the variant with mandatory fields (always non + nil) starting with the type of the visited class, then super + classes. */ + for (const type::Class* c = class_type; c; c = c->super_get()) + fill_variant_fields(c, input); + /* Then add all subclasses types. These might be nil, according to + the exact type of the object. */ + for (const type::Class* subclass : class_type->subclasses_get()) + fill_variant_fields(subclass, input); + *input << " }\n"; + return input; + } + + void DesugarVisitor::fill_init_list(const type::Class* class_type, + field_inits_type& inits) + { + // Populate the initialization list with classes + // owning actual data only. + if (class_type->has_data()) + { + std::string field_name = class_names_(class_type); + misc::put(inits, class_type, + std::string("source.") + variant_field_prefix + field_name); + } + } + + parse::Tweast* DesugarVisitor::cast_function(const std::string& name, + const type::Class* source, + const type::Class* target, + const type::Class* exact_type) + { + auto input = new parse::Tweast; + *input << " function " << name << " (source : " << class_variant_prefix + << class_names_(source) + << ") :" + " " + << class_variant_prefix << class_names_(target) << " = "; + + // Copy all fields from the source. + field_inits_type inits; + // First, fields from the class and its super classes... + for (const type::Class* c = source; c; c = c->super_get()) + fill_init_list(c, inits); + // ...then, fields from the subclasses. + for (const type::Class* c : source->subclasses_get()) + fill_init_list(c, inits); + *input << variant_exp(target, exact_type, inits) << "\n"; + return input; + } + + parse::Tweast* DesugarVisitor::upcast_function(const type::Class* source, + const type::Class* target) + { + return cast_function(upcast_fun_name(source, target), source, target, + source); + } + + parse::Tweast* DesugarVisitor::downcast_function(const type::Class* source, + const type::Class* target) + { + return cast_function(downcast_fun_name(source, target), source, target, + target); + } + + ast::Exp* DesugarVisitor::dispatch_switch(const type::Class* class_type, + const type::Method* method, + const ast::TypeChunk* typechunk, + const type::Method* dispatch_method) + { + parse::Tweast input; + misc::symbol method_name = method->name_get(); + // If a recursive call is needed, dispatch_method will not be + // nullptr. It means that during the dispatch function + // declaration, formals of the mother method have been used + // (because of the use of dispatch_map_, we cannot use child's + // formals. + const ast::MethodDec* def; + // FIXME DONE: Some code was deleted here (Initialize def). + def = dispatch_method ? dispatch_method->def_get() : method->def_get(); + const ast::VarChunk& formals = def->formals_get(); + + // Create a case for each method redefinition. + classes_type overridings; + for (const type::Class* c : class_type->subclasses_get()) + if (std::ranges::any_of(*typechunk, [c](const ast::TypeDec* tmp) { + return class_type_query(*tmp) == c; + })) + overridings.emplace_back(c); + + if (overridings.empty()) + // No dispatch is needed; simply call the method. + input << method_call(class_names_(class_type), method_name, "self", + formals); + else + { + // Emit code for self. + bool first = true; + // Emit code for other types. + for (auto c : overridings) + { + if (!first) + input << " else "; + input << " if self.exact_type = " << class_id_prefix + << class_names_(c) << " then "; + // We search for the nearest implementation of our method. + const type::Class* nearest_c = c; + while (nearest_c && !(nearest_c->owned_meth_find(method_name))) + nearest_c = nearest_c->super_get(); + input << method_call( + class_names_(nearest_c), method_name, + ((*class_type != *nearest_c) + ? downcast_fun_name(class_type, nearest_c) + " (self)" + : "self"), + formals); + first = false; + } + input << " else "; + // If this is a sub dispatch function, call the last dispatch + // method built so we don't need to write every single test + // for exact_type. + if (dispatch_method) + { + input << "_dispatch_"; + if ((dispatch_map_[method] - 1) != 1) + input << (dispatch_map_[method] - 1) << "_"; + input << class_names_(class_type) << "_" << method->name_get() + << " (self"; + // Get the other arguments. + for (const ast::VarDec* arg : formals) + input << ", " << arg->name_get(); + input << ")"; + } + else + input << method_call(class_names_(class_type), method_name, "self", + formals); + } + input << '\n'; + return parse::parse(input); + } + + parse::Tweast* DesugarVisitor::method_call(misc::symbol class_name, + misc::symbol method_name, + const std::string& target, + const ast::VarChunk& formals) + { + auto input = new parse::Tweast; + *input << method_prefix << class_name << "_" << method_name << " ("; + + // Pass the target. + // FIXME DONE: Some code was deleted here. + *input << target; + + // Pass other arguments. + // FIXME DONE: Some code was deleted here. + for (const auto var : formals) + { + // FIXME: Is potentially wrong + *input << ", " << *recurse(*var); + } + + *input << ")"; + return input; + } + + /*------------------------. + | Visiting declarations. | + `------------------------*/ + + void DesugarVisitor::operator()(const ast::ChunkList& e) + { + const ast::Location& location = e.location_get(); + // This is an inlined and specialized version of + // astclone::Cloner::recurse_collection. Maybe we could factor + // it, but it's not easy to see whether we could benefit from + // this. (Maybe a variant would be appropriate.) + ast::ChunkList::list_type contents; + for (const ast::ChunkInterface* d : e) + { + d->accept(*this); + // The result can be either an ast::ChunkInterface* or an ast::ChunkList*. + auto chunk = dynamic_cast<ast::ChunkInterface*>(result_); + if (chunk) + contents.emplace_back(chunk); + else + { + auto chunklist = dynamic_cast<ast::ChunkList*>(result_); + if (chunklist) + { + contents.splice(contents.end(), chunklist->chunks_get()); + delete chunklist; + } + else + abort(); + } + } + result_ = new ast::ChunkList(location, contents); + } + + /*-----------------------------. + | Desugar class declarations. | + `-----------------------------*/ + + void DesugarVisitor::desugar_constructor(parse::Tweast& functions, + const type::Class* cls, + misc::symbol class_name) + { + functions << " function " << class_ctor_prefix << class_name + << "() : " + " " + << class_variant_prefix << class_name + << " = " + " let"; + // Initialize each mandatory field of the variant (i.e., + // the fields holding the attributes of the classes and + // its super classes). + for (const type::Class* c = cls; c; c = c->super_get()) + if (c->has_data()) + { + functions << " var contents_" << class_names_(c) << " := " + << " " << class_contents_prefix << class_names_(c) << " { "; + + for (auto a = c->attrs_get().begin(); a != c->attrs_get().end(); a++) + { + if (a != c->attrs_get().begin()) + functions << ", "; + const ast::VarDec* attr; + // FIXME DONE: Some code was deleted here (Initialize attr). + attr = a->def_get(); + misc::symbol attr_name = attr->name_get(); + // Partially clone the contents of the VarDec + // (cloning the whole VarDec would leak memory). + + ast::Exp* attr_init = recurse(attr->init_get()); + // Cast the initialization value if needed. + if (attr->init_get() && attr->type_name_get()) + adapt_type(attr_init, class_type_query(*attr->init_get()), + class_type_query(*attr->type_name_get())); + functions << attr_name << " = " << attr_init; + } + functions << " } "; + } + functions << " in "; + // Create a list of initializations for each field of the + // variant being constructed. + field_inits_type inits; + for (const type::Class* c = cls; c; c = c->super_get()) + if (c->has_data()) + { + // FIXME DONE: Some code was deleted here. + std::string base = "contents_"; + std::string name = class_names_(c); + misc::put(inits, c, base + name); + } + // Create the contents of the variant. + functions << variant_exp(cls, cls, inits) << " end\n"; + } + + void DesugarVisitor::desugar_method(parse::Tweast& functions, + const type::Method* method, + misc::symbol class_name) + { + functions << " function " << method_prefix << class_name << "_" + << method->name_get() << " (self : " << class_variant_prefix + << class_name; + // Get the other arguments. + const ast::MethodDec* def; + // FIXME DONE: Some code was deleted here (Initiliaze def). + def = method->def_get(); + for (const ast::VarDec* arg : def->formals_get()) + functions << ", " << arg->name_get() << " : " + << recurse(*arg->type_name_get()); + functions << ")"; + if (def->result_get()) + functions << " : " << recurse(def->result_get()); + ast::Exp* body = recurse(def->body_get()); + // Cast the return value of the function if needed. + if (def->result_get()) + adapt_type(body, class_type_query(*def->body_get()), + class_type_query(*def->result_get())); + functions << " = " << body << "\n"; + } + + void DesugarVisitor::dispatch_function(parse::Tweast& functions, + const ast::TypeChunk& e, + const type::Class* cls, + const type::Method* method, + misc::symbol class_name, + dispatch_list_type& sub_dispatches) + { + for (const type::Class* c = cls->super_get(); c; c = c->super_get()) + { + // If this class is not defined in the current chunk, then + // the subdispatch method is not needed yet (since it can + // only be called after the declaration of the said class. + if (std::ranges::any_of(e, [c](const ast::TypeDec* t) { + return class_type_query(*t) == c; + })) + continue; + + // Determine if the class c implements our method. If not, + // we do not need to write a sub dispatch method for it. + auto meth_it = std::ranges::find_if( + c->meths_get(), [method](const type::Method* meth) { + return meth->name_get() == method->name_get(); + }); + + if (meth_it == c->meths_get().end()) + continue; + + const type::Method* parent_method = *meth_it; + + // Since we're looping inside a chunk, we do not rebuild an + // already built sub dispatch method. + auto disp_it = sub_dispatches.emplace(c, parent_method); + + if (!disp_it.second) + continue; + + // Increments the dispatch counter. + if (dispatch_map_.find(parent_method) == dispatch_map_.end()) + dispatch_map_[parent_method] = 2; + else + dispatch_map_[parent_method] = dispatch_map_[parent_method] + 1; + + // Keep track of the added dispatch. + dispatch_added_ += parent_method; + + // We build the subdispatch method. + functions << " function " << dispatch_fun_name(c, parent_method) + << " (self : " << class_variant_prefix << class_names_(c); + // Get the other arguments. + const ast::MethodDec* def; + // FIXME DONE: Some code was deleted here (Initialize def). + def = parent_method->def_get(); + for (const ast::VarDec* arg : def->formals_get()) + functions << ", " << arg->name_get() << " : " + << recurse(*arg->type_name_get()); + functions << ")"; + if (def->result_get()) + functions << " : " << recurse(def->result_get()); + functions << " = " << dispatch_switch(c, parent_method, &e, method); + } + + functions << " function " << dispatch_fun_name(cls, method) + << " (self : " << class_variant_prefix << class_name; + // Get the other arguments. + const ast::MethodDec* def; + // FIXME DONE: Some code was deleted here (Initialize def). + def = method->def_get(); + for (const ast::VarDec* arg : def->formals_get()) + functions << ", " << arg->name_get() << " : " + << recurse(*arg->type_name_get()); + functions << ")"; + if (def->result_get() != nullptr) + functions << " : " << recurse(def->result_get()); + functions << " = " << dispatch_switch(cls, method, &e); + } + + void DesugarVisitor::handle_class(const ast::TypeChunk& e, + const type::Class* cls, + parse::Tweast& functions, + dispatch_list_type& sub_dispatches) + { + misc::symbol class_name = class_names_(cls); + + /*---------------------------. + | Introduce a new class id. | + `---------------------------*/ + + class_ids_ << " var " << class_id_prefix << class_name + << " := " << cls->id_get() << "\n"; + + /*----------------------------------------------------. + | Create a record holding the actual class contents. | + `----------------------------------------------------*/ + + if (cls->has_data()) + { + types_ << " type " << class_contents_prefix << class_name << " =" + << " { "; + // FIXME DONE: Some code was deleted here (Populate the record with attributes (names and types)). + const auto& attributes = cls->attrs_get(); + const auto& first = attributes.begin(); + + for (auto attribute = first; attribute != attributes.end(); ++attribute) + { + if (attribute != first) + types_ << ", "; + + types_ << attribute->name_get() << " : " + << type_symbol(&attribute->type_get()); + } + + types_ << " }\n"; + } + + /*--------------------------------------------------------------. + | Create a variant able to store any dynamic type corresponding | + | to this (static) class type. | + `--------------------------------------------------------------*/ + + types_ << " type " << class_variant_prefix << class_name << " =" + << variant_ty(cls); + + /*-----------------------. + | Create a constructor. | + `-----------------------*/ + + desugar_constructor(functions, cls, class_name); + + /*-------------------------------------------------------------. + | Create conversion routines from the class type to any of its | + | super types. | + `-------------------------------------------------------------*/ + + for (const type::Class* super_type = cls->super_get(); super_type; + super_type = super_type->super_get()) + funs_tweast << upcast_function(cls, super_type); + + /*-------------------------------------------------------------. + | Create conversion routines from the class type to any of its | + | subtypes. | + `-------------------------------------------------------------*/ + + for (const type::Class* subclass : cls->subclasses_get()) + functions << downcast_function(cls, subclass); + + for (const type::Method* m : cls->meths_get()) + { + desugar_method(functions, m, class_name); + dispatch_function(functions, e, cls, m, class_name, sub_dispatches); + } + } + + /* All type-related code is emitted into the top-level chunklist, so + that all classes are stored in the same typechunk, allowing them + to see their subclasses and be able to build a variant for each + of them. */ + void DesugarVisitor::operator()(const ast::TypeChunk& e) + { + parse::Tweast functions; + // Is used to know what class/method pair we already have seen for the + // sub dispatch functions. + dispatch_list_type sub_dispatches; + for (const ast::TypeDec* t : e) + { + const type::Class* cls = nullptr; + // FIXME DONE: Some code was deleted here (Get the ty's class type). + cls = class_type_get(t->ty_get()); + + if (cls) + handle_class(e, cls, functions, sub_dispatches); + else + { + /* FIXME: In the rest of the visitor, the + simply-clone-this-node case is handled before the + desugar-this-node case. */ + // Otherwise, clone the type declaration. + ast::TypeDec* typedec = recurse(*t); + assertion(typedec); + types_ << *typedec << '\n'; + } + } + + ast::ChunkList* funs_list = parse::parse(functions); + result_ = funs_list; + } + + /*------------------------------------------------. + | Desugar class instantiations and object usage. | + `------------------------------------------------*/ + + void DesugarVisitor::operator()(const ast::VarDec& e) + { + /* We don't desugar everything using concrete syntax here, because + it would require a lot of additional manipulations, as we + cannot easily produce a single VarDec from a parsing. Also + working from VarChunk (with an `s') doesn't help much either, as + VarDec (with no `s') are also found in FunctionDec. */ + + // If this is not an object instantiation, delegate to the cloner. + + const type::Class* class_type = class_type_query(e); + if (!class_type) + return super_type::operator()(e); + + // Otherwise, handle the different cases. + const ast::Location& location = e.location_get(); + ast::NameTy* type_name = nullptr; + ast::Exp* init = nullptr; + if (e.init_get()) + { + // Object (variable) declaration. + if (e.type_name_get()) + { + type_name = recurse(e.type_name_get()); + init = recurse(e.init_get()); + // If the dynamic type is non-nil and different from the + // static type, cast INIT to the latter. + // FIXME DONE: Some code was deleted here. + if (!init) + { + unreachable(); + } + + const type::Class* name_type = class_type_get(*type_name); + const type::Class* init_type = class_type_get(*init); + if (name_type != init_type) + { + adapt_type(init, name_type, init_type); + } + // Up to here + } + else + // No manifest type: simply clone the declaration as-is. + return super_type::operator()(e); + } + else + // Formal declaration. + type_name = recurse(e.type_name_get()); + + misc::symbol name = e.name_get(); + + result_ = new ast::VarDec(location, name, type_name, init); + postcondition(type_name || init); + } + + // Desugar a class instantiation as a call to the desugared ctor routine. + void DesugarVisitor::operator()(const ast::ObjectExp& e) + { + // FIXME DONE: Some code was deleted here. + const ast::Location location = e.location_get(); + + const std::string class_name = e.type_name_get().name_get(); + + const std::string call_name = class_ctor_prefix + class_name; + const auto args = new ast::exps_type; + result_ = new ast::CallExp(location, call_name, args); + } + + void DesugarVisitor::operator()(const ast::IfExp& e) + { + // FIXME DONE: Some code was deleted here. + ast::Exp* cond = recurse(e.test_get()); + ast::Exp* then_clause = recurse(e.thenclause_get()); + ast::Exp* else_clause = recurse(e.elseclause_get()); + result_ = new ast::IfExp(e.location_get(), cond, then_clause, else_clause); + } + + void DesugarVisitor::operator()(const ast::AssignExp& e) + { + // If this is not an object assignment, delegate to the cloner. + const type::Class* lhs_class_type; + // FIXME DONE: Some code was deleted here. + lhs_class_type = class_type_query(e.var_get()); + + if (!lhs_class_type) + return super_type::operator()(e); + + // Duplicate the subtrees of E. + ast::Var* var = nullptr; + // FIXME DONE: Some code was deleted here (Recurse). + var = recurse(e.var_get()); + + ast::Exp* exp = nullptr; + // FIXME DONE: Some code was deleted here (Recurse). + exp = recurse(e.exp_get()); + + // If the RHS type is non-nil and different from the LHS type, + // cast EXP to the latter. + // FIXME DONE: Some code was deleted here. + const type::Class* rhs_class_type = class_type_get(*exp); + if (lhs_class_type != rhs_class_type) + { + adapt_type(exp, rhs_class_type, lhs_class_type); + } + // Up to here + + ast::Exp* assignment = + parse::parse(parse::Tweast() << var << " := " << exp); + result_ = assignment; + } + + ast::exps_type* DesugarVisitor::recurse_args(const ast::exps_type& actuals, + const type::Record& formals) + { + // For each argument, check the type of the actual argument + // against the formal one. If they are two different class types, + // convert the actual argument to the expected type. + auto args = new ast::exps_type; + ast::exps_type::const_iterator i; + type::Record::const_iterator j; + for (i = actuals.begin(), j = formals.begin(); + i != actuals.end() && j != formals.end(); ++i, ++j) + { + // Clone the argument. + ast::Exp* arg = recurse(**i); + + // In the case of a class, handle the case of a (non-nil) actual + // argument having a different type than the corresponding + // formal. + const type::Type* formal_type = &j->type_get().actual(); + auto formal_class_type = dynamic_cast<const type::Class*>(formal_type); + // FIXME DONE: Some code was deleted here. + // How to check if this arg is non nil ? + // Checking if arg is not a nullptr ? + if (formal_class_type && arg) + { + const type::Type* arg_type = &((*i)->type_get()->actual()); + auto arg_class_type = dynamic_cast<const type::Class*>(arg_type); + adapt_type(arg, arg_class_type, formal_class_type); + } + // Up to here + args->emplace_back(arg); + } + return args; + } + + void DesugarVisitor::operator()(const ast::ArrayExp& e) + { + // We want to allow this: + // let + // class A {} + // class B extends A {} + // type arrtype = array of A + // var arr := arrtype[10] of new B + // in + // arr[0] := new B; + // arr[1] := new A + // end + // FIXME DONE: Some code was deleted here. + + parse::Tweast input; + const type::Type* contener_type = &(e.type_name_get().type_get()->actual()); + const type::Type* init_type = &(e.init_get().type_get()->actual()); + + auto contener_class_type = dynamic_cast<const type::Class*>(contener_type); + auto init_class_type = dynamic_cast<const type::Class*>(init_type); + + ast::Exp* reced = recurse(e.init_get()); + if (contener_class_type && init_class_type && reced) + { + adapt_type(reced, init_class_type, contener_class_type); + } + + result_ = recurse(e); + } + + void DesugarVisitor::operator()(const ast::RecordExp& e) + { + // We want to allow this: + // let + // class A {} + // class B extends A {} + // type rectype = { a : A } + // var rec := rectype { a = new B } + // in + // end + // FIXME DONE: Some code was deleted here. + + const type::Type* rec_type = &(e.type_get()->actual()); + auto actual_rec_type = dynamic_cast<const type::Record*>(rec_type); + + if (actual_rec_type) + { + ast::fieldinits_type::const_iterator i; + type::Record::const_iterator j; + for (i = e.fields_get().begin(), j = actual_rec_type->fields_get().begin(); + i != e.fields_get().end() && j != actual_rec_type->fields_get().end(); + ++i, ++j) + { + const type::Type* given_type = &((*i)->init_get().type_get()->actual()); + const type::Type* asked_type = &j->type_get().actual(); + auto class_given = dynamic_cast<const type::Class*>(given_type); + auto class_asked = dynamic_cast<const type::Class*>(asked_type); + + ast::Exp* reced = recurse((*i)->init_get()); + + if (class_given && class_asked && reced) + { + adapt_type(reced, class_given, class_asked); + } + } + } + + // Maybe need to change this because we may need to create another + result_ = recurse(e); + } + + void DesugarVisitor::operator()(const ast::CallExp& e) + { + const type::Function* function_type; + // FIXME DONE: Some code was deleted here. + const ast::FunctionDec* interm = e.def_get(); + function_type = dynamic_cast<const type::Function*>(interm); + + if (!interm) + { + unreachable(); + } + + const ast::Location& location = e.location_get(); + // FIXME DONE: Some code was deleted here (Grab name). + misc::symbol name = e.name_get(); + + // FIXME DONE: Some code was deleted here (Actual arguments). + const ast::exps_type& arguments = e.args_get(); + + // (Types of) formal arguments. + const type::Record& formals = function_type->formals_get(); + // Desugar the arguments and handle possible polymorphic assignments. + // FIXME DONE: Some code was deleted here. + ast::exps_type* final_args = recurse_args(arguments, formals); + + // FIXME DONE: Some code was deleted here (Instantiate into result). + result_ = new ast::CallExp(location, name, final_args); + } + + /*------------------------------------. + | Desugar accesses to class members. | + `------------------------------------*/ + + void DesugarVisitor::operator()(const ast::FieldVar& e) + { + // Check the type of the variable to see whether it is a class or + // a record. + const type::Class* class_type; + // FIXME DONE: Some code was deleted here. + class_type = class_type_query(e.var_get()); + + // If this is not a class, delegate to the cloner. + if (!class_type) + return super_type::operator()(e); + + // FIXME DONE: Some code was deleted here (Grab name). + misc::symbol name = e.name_get(); + + // Otherwise, desugar this FieldVar as an access to an attribute. + + // Look for the attribute within the class and its base classes. + const type::Class* owner = nullptr; + for (const type::Class* c = class_type; c; c = c->super_get()) + { + // FIXME DONE: Some code was deleted here. + if (c->attr_find(name)) + { + owner = c; + break; + } + } + assertion(owner); + + ast::Var* var; + // FIXME DONE: Some code was deleted here (Recurse). + var = recurse(e.var_get()); + + ast::Exp* attr_var = + parse::parse(parse::Tweast() << var << "." << variant_field_prefix + << class_names_(owner) << "." + // FIXME DONE ??: Some code was deleted here. + << name + ); + result_ = attr_var; + } + + void DesugarVisitor::operator()(const ast::LetExp& e) + { + // Save the current scope situation for dispatched methods + auto saved_dispatch_added_ = dispatch_added_; + dispatch_added_.clear(); + + super_type::operator()(e); + + // After exiting the scope, remove unreachable dispatch methods + for (const auto* meth : dispatch_added_) + { + if (dispatch_map_[meth] == 2) + dispatch_map_.take(meth); + else + dispatch_map_[meth] -= 1; + } + + // Resume the current scope + dispatch_added_ = saved_dispatch_added_; + } + + void DesugarVisitor::operator()(const ast::MethodCallExp& e) + { + const type::Method* method_type; + // FIXME DONE: Some code was deleted here (Initialize method_type). + method_type = dynamic_cast<const type::Method*>(&e.def_get()->type_get()->actual()); + // Maybe we need this ? + if (!method_type) + { + unreachable(); + } + + const type::Class* owner_type = method_type->owner_get(); + + const ast::Location& location = e.location_get(); + std::string name = dispatch_fun_name(owner_type, method_type); + + // FIXME DONE: Some code was deleted here (Fetch actual arguments). + // ??????????????????????????????????????????????????????????? + const ast::exps_type actual_args = e.args_get(); + + // (Types of) formal arguments. + const type::Record& formals = method_type->formals_get(); + // Desugar the arguments and handle possible polymorphic assignements. + ast::exps_type* args; + // FIXME DONE: Some code was deleted here (Initialize args). + args = recurse_args(actual_args, formals); + + // Process the target of the method call, and convert it to the + // expected type if needed. + ast::Exp* object; + // FIXME DONE: Some code was deleted here (Recurse). + object = recurse(e.object_get()); + + // FIXME DONE: Some code was deleted here (Adapt type). + const type::Class* item_type = class_type_query(*object); + adapt_type(object, item_type, owner_type); + // Prepend the target to the actual arguments, as the desugared + // method expects to find it as its first arguments. + args->insert(args->begin(), object); + + // Turn the method call into a function call to the desugared method. + // FIXME DONE: Some code was deleted here (Instanciate into result). + ast::Var* finial = dynamic_cast<ast::Var*>(object); + if (!finial) + { + unreachable(); + } + result_ = new ast::MethodCallExp(location, name, args, finial); + } + + /*--------------------------. + | New types and functions. | + `--------------------------*/ + + // Introduce a desugared builtin Object in the top-level function. + void DesugarVisitor::operator()(const ast::FunctionDec& e) + { + bool is_main; + // FIXME DONE: Some code was deleted here (Setup is_main). + is_main = e.name_get() == "_main"; + if (is_main) + { + // Desugared data structures of the builtin Object. + types_ << " type " << class_variant_prefix + << "Object =" << variant_ty(&type::Class::object_instance()); + // Object's class id. + class_ids_ << " var " << class_id_prefix + << "Object := " + " " + << type::Class::object_instance().id_get(); + } + + // Process E. + super_type::operator()(e); + if (is_main) + { + // Object's ctor. + funs_tweast << " function " << class_ctor_prefix + << "Object() :" + " " + << class_variant_prefix << "Object ="; + // Initialize the variant (a single field is filled, the one + // corresponding to Object). + field_inits_type object_init; + misc::put(object_init, &type::Class::object_instance(), + std::string(class_contents_prefix) + "Object {}"); + // Create the variant. + funs_tweast << variant_exp(&type::Class::object_instance(), + &type::Class::object_instance(), + object_init); + + // Parse the built TWEASTs. + ast::ChunkList* types = parse::parse(types_); + ast::ChunkList* class_ids = parse::parse(class_ids_); + ast::ChunkList* funs = parse::parse(funs_tweast); + // Gather these declarations. + types->splice_back(*class_ids); + types->splice_back(*funs); + // Add them to the top of the program. + auto res = dynamic_cast<ast::FunctionDec*>(result_); + parse::Tweast input; + input << "let " << types << " in " << res->body_get() << " end"; + res->body_set(parse::parse(input)); + } + + // Cast the return value of the function if needed. + if (e.body_get() && e.result_get()) + { + const type::Class* body_type = class_type_query(*e.body_get()); + const type::Class* result_type = class_type_query(*e.result_get()); + if (body_type && result_type && body_type != result_type) + { + auto res = dynamic_cast<ast::FunctionDec*>(result_); + parse::Tweast input; + input << upcast_fun_name(body_type, result_type) << " (" + << res->body_get() << ")"; + res->body_set(parse::parse(input)); + } + } + } + + void DesugarVisitor::operator()(const ast::NameTy& e) + { + // Check if E is the name of a class; if not, just clone it. + const type::Class* class_type = class_type_query(e); + if (!class_type) + return super_type::operator()(e); + + // Otherwise, desugar the name of E. + const ast::Location& location = e.location_get(); + result_ = new ast::NameTy( + location, class_variant_prefix + class_names_(class_type).get()); + } + +} // namespace object |
