/** ** \file object/desugar-visitor.cc ** \brief Implementation of object::DesugarVisitor. */ #include #include #include #include #include #include #include #include #include #include #include #include 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(&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(type)) { return "int"; } else if (dynamic_cast(type)) { return "string"; } else if (const auto named = dynamic_cast(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(result_); if (chunk) contents.emplace_back(chunk); else { auto chunklist = dynamic_cast(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(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(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(contener_type); auto init_class_type = dynamic_cast(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(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(given_type); auto class_asked = dynamic_cast(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(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(&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(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(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(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