summaryrefslogtreecommitdiff
path: root/tiger-compiler/src/object/desugar-visitor.cc
blob: db61a808e1aba0c63ee47ccc0d3ada3cb043fcb0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
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