PreviousUpNext

15.4.489  src/lib/compiler/back/top/improve/convert-free-variables-to-parameters-in-anormcode.pkg

## convert-free-variables-to-parameters-in-anormcode.pkg                        "typelift.pkg" in SML/NJ
#
#   ``"Lambda lifting" is a well-known transformation which rewrites
#      a program into an equivalent one in which no function has
#      free variables.''
#           -- page 93 of Zhong Shao's PhD thesis,
#              Compiling Standard ML for Efficient Execution on Modern Machines
#              http://flint.cs.yale.edu/flint/publications/zsh-thesis.html
#
#  Which is to say, all values accessed by all functions
#  are then passed as parameters:
#
#      fun print_sum x =  printf "sum %d\n x y;
#
#  gets transformed to (say)
#
#      fun print_sum (x, y) =  printf "sum %d\n x y;
#
#
#   For additional background beyond Shao's thesis, read:
#
#       Lambda Lifting: Transforming Programs to Recursive Equations
#       Thomas Johnsson
#       1985, 15p
#       http://citeseer.ist.psu.edu/johnsson85lambda.html
#
#       Optimal Type Lifting
#       Bratin Saha, Zhong Shao (Yale)
#       1998, 36p
#       http://flint.cs.yale.edu/flint/publications/lift-tr.ps.gz

# Compiled by:
#     src/lib/compiler/core.sublib



# This is one of the A-Normal Form compiler passes --
# for context see the comments in
#
#     src/lib/compiler/back/top/anormcode/anormcode-form.api
#




###             "Never eat more than you can lift."
###
###                            --  Miss Piggy



stipulate
    package acf =  anormcode_form;                              # anormcode_form                is from   src/lib/compiler/back/top/anormcode/anormcode-form.pkg
herein

    api Convert_Free_Variables_To_Parameters_In_Anormcode {
        #
        convert_free_variables_to_parameters_in_anormcode:    acf::Function -> acf::Function;           # was called type_lift
        anormcode_is_well_formed:                             acf::Function -> Bool;
    };
end;
  

stipulate
    package acf =  anormcode_form;                              # anormcode_form                is from   src/lib/compiler/back/top/anormcode/anormcode-form.pkg
    package asc =  anormcode_sequencer_controls;                # anormcode_sequencer_controls  is from   src/lib/compiler/back/top/main/anormcode-sequencer-controls.pkg
    package di  =  debruijn_index;                              # debruijn_index                is from   src/lib/compiler/front/typer/basics/debruijn-index.pkg
    package hut =  highcode_uniq_types;                         # highcode_uniq_types           is from   src/lib/compiler/back/top/highcode/highcode-uniq-types.pkg
    package hcf =  highcode_form;                               # highcode_form                 is from   src/lib/compiler/back/top/highcode/highcode-form.pkg
    package tmp =  highcode_codetemp;                           # highcode_codetemp             is from   src/lib/compiler/back/top/highcode/highcode-codetemp.pkg
    package iht =  int_hashtable;                               # int_hashtable                 is from   src/lib/src/int-hashtable.pkg
    package vh  =  varhome;                                     # varhome                       is from   src/lib/compiler/front/typer-stuff/basics/varhome.pkg
herein

    package   convert_free_variables_to_parameters_in_anormcode
    : (weak)  Convert_Free_Variables_To_Parameters_In_Anormcode                 # Convert_Free_Variables_To_Parameters_In_Anormcode     is from   src/lib/compiler/back/top/improve/convert-free-variables-to-parameters-in-anormcode.pkg
    {


        # ****  Utility functions ****


        exception PARTIAL_TYPE_APP; 
        exception VAR_NOT_FOUND;
        exception LIFT_TYPE_UNKNOWN;
        exception DO_NOT_LIFT;
        exception FTABLE;
        exception LIFT_COMPILE_ERROR;
        exception VENV;
        exception FENV;
        exception ABSTRACT;

        fun bug s
            =
            error_message::impossible ("Lift: " + s);


        make_var = highcode_codetemp::issue_highcode_codetemp;

        wellfixed  = REF TRUE;
        welltapped = REF TRUE;
        tapp_lifted = REF 0;

        Depth    = Int;
        Tdepth   = Int;
        Num      = Int;
        Abstract = Bool;

        Var  =  (hut::Uniqtypoid, List(tmp::Codetemp), Depth, Tdepth, Abstract, Num);
        Venv =  iht::Hashtable( Var );

        Freevar =  (tmp::Codetemp, hut::Uniqtypoid);
        Fenv    =  List (iht::Hashtable( Freevar ) );



        Ltype = TYPE_FUN | TYPEFN_APP;
        Header = List( (Ltype, tmp::Codetemp, acf::Expression) );

        Dictionary = IENV  (Venv, Fenv);

        #  Utility functions 

        abs = TRUE;
        noabs = FALSE;

        fkfct = { loop_info         =>  NULL,
                  private =>  FALSE,
                  inlining_hint     =>  acf::INLINE_IF_SIZE_SAFE,
                  call_as           =>  acf::CALL_AS_GENERIC_PACKAGE
                };

        fun adjust (t, ntd, otd)
            =
            hcf::change_depth_of_uniqtypoid (t, otd, ntd);

        fun find_dictionary (v, IENV (venv, fenvs))
            = 
            (iht::get  venv  v)
            except
                _ = {   print (int::to_string v);
                        bug "findDict: var not found" ;
                    };

        fun get_variable (v, IENV (venv, fenv ! fenvs), t, td, td')
                => 
                {   my (v', nt') = (iht::get  fenv  v);
                    (v', nt', NIL);
                }
                except
                    _ = {   v' = make_var();
                            nt' = adjust (t, td, td');
                            iht::set fenv (v, (v', nt'));

                            (v', nt', [v]);
                        };

            get_variable _
                =>
                bug "unexpected freevariableDict in getVariable";
        end;

        fun new_variable (v, dictionary, td)
            = 
            expression
            where
                my (t, vs, td', d', abs, _)
                    =
                    find_dictionary (v, dictionary);

                expression = if (abs and (d' > 0) and (td' < td)) 

                                  my (v', t', fv) = get_variable (v, dictionary, t, td, td');

                                  (v', t', fv);
                             else
                                  (v, adjust (t, td, td'), NIL);
                             fi;
            end;


        fun push_fenv (IENV (venv, fenvs))
            = 
            {   nt = iht::make_hashtable  { size_hint => 32,  not_found_exception => FTABLE };
                IENV (venv, nt ! fenvs);
            };

        fun pop_fenv (IENV (venv, fenv ! fenvs)) => IENV (venv, fenvs);
            pop_fenv _ => raise exception LIFT_COMPILE_ERROR;
        end;

        fun add_dictionary (IENV (venv, fenvs), vs, ts, fvs, td, d, abs)
            =
            {
                fun f (v, t)
                    =
                    iht::set venv (v, (t, fvs, td, d, abs, 0));

                fun zip ([], [], acc)         =>  acc;
                    zip (a ! r, a' ! r', acc) =>  zip (r, r', (a, a') ! acc);
                    zip _                     =>  raise exception LIFT_COMPILE_ERROR;
                end;

                map f (zip (vs, ts, NIL));
            };

        fun rm_dictionary (IENV (venv, fenvs), v)
            =
            iht::drop  venv  v;

        fun get_free_variable (fvs, IENV (venv, fenv ! fenvs))
                => 
                map f fvs
                where
                    fun f (v)
                        =
                        (iht::get  fenv  v)
                        except
                            _ = bug "freevar not found";
                end;

            get_free_variable _
                =>
                bug "unexpected freevariableDict in getFreeVariable";
        end;


        fun write_lambda ([], expression)
                =>
                expression;

            write_lambda (fvs, expression)
                =>
                {   fun g (fvs', expression')
                        = 
                        {   new_var = make_var();

                            fund = { loop_info         =>  NULL,
                                     call_as           =>  acf::CALL_AS_FUNCTION (hut::VARIABLE_CALLING_CONVENTION { arg_is_raw => TRUE, body_is_raw => TRUE }),
                                     private =>  FALSE,
                                     inlining_hint     =>  acf::INLINE_IF_SIZE_SAFE
                                   };

                            acf::MUTUALLY_RECURSIVE_FNS
                              ( [ (fund, new_var, fvs', expression') ],
                                acf::RET [acf::VAR new_var]
                              );
                        };

                    if (list::length(fvs) <= 9)  
                        #
                        g (fvs, expression);
                    else
                        fun f (x, e) =  ([x], e);

                        fold_backward (g o f) expression fvs;
                    fi;
                };
        end;


        fun write_app (v, vs)
            = 
            if (list::length(vs) <= 9)
                #
                acf::APPLY (v, vs);
            else
                fun f ([], e)
                        =>
                        {   new_var = make_var();
                            (acf::RET [acf::VAR new_var], new_var);
                        };

                    f (v ! vs, e)
                        =>
                        {   my (e', v') = f (vs, e);
                            new_var = make_var();
                            (acf::LET([v'], acf::APPLY (acf::VAR new_var,[v]), e'), new_var);
                        };
                end;

                my (e', v') = f (list::tail vs, acf::RET []);

                acf::LET ([v'], acf::APPLY (v, [list::head vs]), e');
            fi;


        fun write_header (hd, expression)
            = 
            fold_backward  f  expression  hd
            where
                fun f ((TYPEFN_APP, v, e), e')                   =>  acf::LET ([v], e, e');
                    f ((TYPE_FUN, v, acf::TYPEFUN (e, e')), e'') =>  acf::TYPEFUN (e, e'');
                    f _ => bug "unexpected header in writeHeader";
                end;
            end;


        # The way renaming is done is that if rename is TRUE and d > 0
        # and td < td' then change var
        #
        fun init_info_dictionary ()
            =
            {   my venv:  Venv = iht::make_hashtable  { size_hint => 32,  not_found_exception => VENV };
                my fenv        = iht::make_hashtable  { size_hint => 32,  not_found_exception => FENV };

                IENV (venv, [fenv]);
            };


        fun anormcode_is_well_formed (fdec:  acf::Function)
            = 
            case fdec
                #
                (fk as { call_as => acf::CALL_AS_GENERIC_PACKAGE, ... }, v, vts, e)
                    =>
                    formed (e, 0)
                    where
                        fun formed (acf::RET _, d) => TRUE;
                            formed (acf::LET (vs, e1, e2), d) => formed (e1, d) and formed (e2, d);
                            formed (acf::APPLY (v, vs), d) => TRUE;

                            formed (acf::APPLY_TYPEFUN (v, ts), d)
                                =>
                                case d    0 => TRUE;
                                          _ => FALSE;
                                esac;

                            formed (acf::RECORD (rk, vs, v, e), d) => formed (e, d);
                            formed (acf::GET_FIELD (v, i, l, e), d) => formed (e, d);
                            formed (acf::RAISE _, d) => TRUE;
                            formed (acf::EXCEPT (e, v), d) => formed (e, d);
                            formed (acf::BRANCH (pr, vs, e1, e2), d) => formed (e1, d) and formed (e2, d);
                            formed (acf::BASEOP (pr, vs, l, e), d) => formed (e, d);

                            formed (acf::SWITCH (v, a, ces, eopt), d)
                                => 
                                {   b1 = case eopt    NULL => TRUE;
                                                      THE e => formed (e, d);
                                         esac;

                                    fun f (c, e) = (e, d);

                                    es = map f ces;
                                    b2 = map formed es;

                                    b = fold_backward   (\\ (x, y) = x and y)   b1   b2;

                                    b;
                                };
                            formed (acf::CONSTRUCTOR (dc, ts, v, l, e), d) => formed (e, d);

                            formed (acf::TYPEFUN((tfk, l, ts, e1), e2), d)
                                =>
                                formed (e1, d) and formed (e2, d);

                            formed (acf::MUTUALLY_RECURSIVE_FNS (fds, e), d)
                                => 
                                {
                                    b1 = formed (e, d);
                                    b2 = case fds   
                                        ( { call_as => acf::CALL_AS_GENERIC_PACKAGE, ... }, l, vs, e') ! r => map formed [(e', d)];
                                       _ => { fun f (v1, v2, v3, v4) = (v4, d + 1);
                                                 es = map f fds;
                                                 b' = map formed es;

                                                 b';
                                             }; esac;

                                    b = fold_backward   (\\ (x, y) = x and y)   b1   b2;

                                    b;
                                };
                        end;
                    end;

                _ => bug "non GENERIC program in Lift";
            esac;


        fun lift (e, dictionary, td, d, ad, rename)
            = 
            loope (e, dictionary, d, ad)
            where 

                fun comb ((v, t, fv, hd), (l1, l2, l3, l4))
                    =
                    (v ! l1, t ! l2, fv@l3, hd@l4);

                fun lt_inst (lt, ts)
                    = 
                    case (hcf::apply_typeagnostic_type_to_arglist (lt, ts))
                        #
                        [x] => x;
                       _ => bug "unexpected case in ltInst";
                    esac;

                fun arglty (lt, ts)
                    = 
                    { 
                        my (_, atys, _) =  hcf::unpack_arrow_uniqtypoid (lt_inst (lt, ts));

                        case atys   
                            [x] => x;
                           _ => bug "unexpected case in arglty";
                        esac;
                    };

                fun reslty (lt, ts)
                    =
                    {   my (_, _, rtys)
                            =
                            hcf::unpack_arrow_uniqtypoid (lt_inst (lt, ts));

                        case rtys
                            #
                            [x] =>   x;
                            _   =>   bug "unexpected case in reslty";
                        esac;
                    };

                fun loopcv dictionary var v
                    =
                    {   my (v', t, fv)
                            =
                            new_variable (v, dictionary, td); #  Not checking for poly 

                        (var v', t, fv, NIL);   #  Check whether this is t or t' 
                    };

                fun loopc dictionary v
                    =
                    {   fun c t =   (v, t, [], []);

                        case v
                            #
                            acf::VAR v'              => loopcv dictionary acf::VAR v';
                            #
                            (acf::INT _   | acf::UNT _ )  => c hcf::int_uniqtypoid;
                            (acf::INT1 _ | acf::UNT1 _) => c hcf::int1_uniqtypoid;
                            #
                            acf::FLOAT64 _           => c hcf::float64_uniqtypoid;
                            acf::STRING  _           => c hcf::string_uniqtypoid;
                        esac;
                    };

                fun lpacc dictionary (vh::HIGHCODE_VARIABLE v)
                        => 
                        {   (loopcv  dictionary  (\\ v = v)  v)
                                ->
                                (v', _, fv, _);

                            ( vh::HIGHCODE_VARIABLE v',
                              fv
                            );
                        };

                    lpacc dictionary (vh::PATH (a, i))
                        => 
                        {   (lpacc dictionary a) ->   (a', fvs);
                            #
                            (vh::PATH (a', i), fvs);
                        };

                    lpacc dictionary a => (a, NIL);
                end;

                fun lpcon dictionary (vh::EXCEPTION a)
                        =>  
                        {   (lpacc dictionary a) ->   (a', fv);
                            #
                            (vh::EXCEPTION (a'), fv);
                        };

                    lpcon dictionary (vh::SUSPENSION NULL)
                        =>
                        (vh::SUSPENSION(NULL), NIL);

                    lpcon dictionary (vh::SUSPENSION (THE (a', a'')))
                        => 
                        {   (lpacc dictionary a' ) ->   (a1, fv1);
                            (lpacc dictionary a'') ->   (a2, fv2);
                            #
                            (vh::SUSPENSION (THE (a', a'')), fv1 @ fv2);
                        };

                    lpcon dictionary a
                        =>
                        (a, NIL);
               end;

               fun loope (acf::RET vs, dictionary, d, ad)
                       => 
                       {   vls =  map (loopc dictionary) vs;

                           my (vs, ts, fvs, hd)
                               =
                               fold_backward comb (NIL, NIL, NIL, NIL) vls;

                           (acf::RET vs, ts, fvs, hd);
                       };

                  loope (acf::LET (vs, e1, e2), dictionary, d, ad)
                      => 
                      {
                          my (e', ts, fvs, hd) = loope (e1, dictionary, d, ad);
                          add_dictionary (dictionary, vs, ts, fvs, td, d, abs);
                          my (e'', ts', fvs', hd') = loope (e2, dictionary, d, ad);

                          (acf::LET (vs, e', e''), ts', fvs@fvs', hd@hd');
                      };

                  loope (acf::APPLY (v1, vs), dictionary, d, ad)
                      =>
                      {   my (v1', t, fvs, hd)
                              =
                              loopc dictionary v1;

                          vls = map (loopc dictionary) vs;

                          my (vs', ts', fvs', hd')
                             =
                             fold_backward comb (NIL, NIL, NIL, NIL) vls;

                          nt = #2 (hcf::ltd_fkfun t);

                          (acf::APPLY (v1', vs'), nt, fvs@fvs', hd@hd');
                      };

                  loope (e as acf::APPLY_TYPEFUN (v, types), dictionary as IENV (venv, fenvs), d, ad)
                      =>
                      {
                          (loopc dictionary v) ->   (v', nt', fv', hd);                 #  fv' and hd are NIL 

                          nt = hcf::apply_typeagnostic_type_to_arglist (nt', types);

                          len1 = list::length types;

                          case d   
                              0 => (e, nt, fv', hd);

                             _ => case v   
                                      #
                                      acf::VAR v'' => 
                                          { 
                                              my (t', fvs', len2, vd, _, _)
                                                  = 
                                                  (iht::get  venv  v'')
                                                  except
                                                      _ = bug "TYPEFN_APP var not found";

                                              if ((len1 == len2) or (vd == 0)) 
                                                  #
                                                  new_var = make_var();
                                                  hd' = (TYPEFN_APP, new_var, acf::APPLY_TYPEFUN (v, types));
                                                  fun f (x) = loopc dictionary (acf::VAR x);

                                                  my (expression, fvs)
                                                      =
                                                      case fvs'    
                                                          #
                                                          [] => (acf::RET([acf::VAR new_var]), NIL);

                                                          _ => { fvs'' = map f fvs';
                                                                    my (r1, r2, r3, r4) = fold_backward comb (NIL, NIL, NIL, NIL) fvs'';

                                                                    (write_app (acf::VAR new_var, r1), r3);
                                                                };
                                                      esac;

                                                 tapp_lifted := *tapp_lifted + 1;

                                                 (expression, nt, fv'@fvs, [hd']);
                                             else
                                                 welltapped := FALSE;
                                                 tapp_lifted := 0;
                                                 raise exception PARTIAL_TYPE_APP ;
                                             fi;
                                          };    

                                     _ => (e, nt, fv', hd);
                                 esac;
                          esac;
                      };

                  loope (e as acf::TYPEFUN((tfk, v, tvs, e1), e2), dictionary as IENV (venv, fenvs), d, ad)
                      =>
                      case  d
                          #
                          0 => 
                              {
                                  (lift (e1, dictionary, di::next td, d, ad, TRUE))
                                      ->
                                      (e1', nt', fv', hd');

                                  ks =   map   (\\ (t, k) = k)   tvs;

                                  nt = hcf::make_typeagnostic_uniqtypoid (ks, nt');

                                  # Hack for TYPEFN_APP. Stores the number of tvs instead of td  

                                  add_dictionary (dictionary, [v], [nt], fv', (list::length tvs), d, noabs);

                                  (loope (e2, dictionary, d, ad))
                                      ->
                                      (e2', nt'', fv'', hd'');

                                  (acf::TYPEFUN((tfk, v, tvs, e1'), e2'), nt'', fv'@fv'', hd'@hd'');
                              };
                         _ => 
                              {
                                  dictionary' =  push_fenv (dictionary);

                                  (lift (e1, dictionary', di::next td, d, di::next ad, TRUE))
                                      ->
                                      (e1', nt', fvs, hd);

                                  freevars =  get_free_variable (fvs, dictionary');

                                  ks =   map   (\\ (t, k) = k)   tvs;

                                  nt =  hcf::make_typeagnostic_uniqtypoid (ks, nt');

                                  # Hack for TYPEFN_APP. Stores the number of tvs 

                                  add_dictionary (dictionary, [v], [nt], fvs, (list::length tvs), d, noabs);

                                  (loope (e2, dictionary, d, ad))
                                      ->
                                      (e2', nt'', fvs', hd');

                                  expression  =  write_lambda (freevars, e1');
                                  expression' =  write_header (hd, expression);

                                  hd =  (TYPE_FUN, v, acf::TYPEFUN((tfk, v, tvs, expression'), acf::RET [])) ! hd';

                                  (e2', nt'', fvs', hd);
                              };
                      esac;

                  loope (acf::SWITCH (v, a, cels, eopt), dictionary, d, ad)
                      =>
                      {   my (v', nt, fv, hd) = loopc dictionary v;

                          fun f (c, e)
                              = 
                              {   case  c
                                      #
                                      acf::VAL_CASETAG((_, _, lt), ts, v)
                                          =>
                                          add_dictionary (dictionary, [v], [arglty (lt, ts)], NIL, td, d, abs);

                                      _ => [()];
                                  esac;

                                  (loope (e, dictionary, d, ad))
                                      ->
                                      (e', nt', fvs, hds);

                                  ((c, e'), nt', fvs, hds);
                              };

                          ls =  map f cels;


                          (fold_backward comb (NIL, NIL, NIL, NIL) ls)
                              ->
                              (cels', nt', fvs', hds');
                              

                          my (expression, t, f, h)
                              =
                              case eopt
                                  #
                                  NULL => (acf::SWITCH (v', a, cels', eopt), list::head nt', fv@fvs', hd@hds');

                                  THE (eopt') => 
                                      {
                                          (loope (eopt', dictionary, d, ad))
                                              ->
                                              (eopt'', nt'', fvs'', hd'');

                                          (acf::SWITCH (v', a, cels', THE (eopt'')), list::head nt', fv@fvs'@fvs'', hd@hds'@hd'');
                                      };
                              esac;

                          (expression, t, f, h);
                      };

                  loope (acf::CONSTRUCTOR (dcons, tcs, vl, v, e), dictionary, d, ad)
                      =>
                      {   dcons -> (s, cr, lt);
                          (lpcon dictionary cr) ->  (cr', fv);

                          nt =  reslty (lt, tcs);

                          (loopc dictionary vl) ->   (vl', nt', fvs', hd');

                          add_dictionary (dictionary, [v], [nt], NIL, td, d, TRUE);

                          (loope (e, dictionary, d, ad))
                              ->
                              (e'', nt'', fvs'', hd'');

                          (acf::CONSTRUCTOR((s, cr', lt), tcs, vl', v, e''), nt'', fv@fvs'@fvs'', hd'@hd'');
                       };

                  loope (acf::RECORD (rk, vls, v, e), dictionary, d, ad)
                      =>
                      {   ls =  map  (loopc dictionary)  vls;

                          (fold_backward comb (NIL, NIL, NIL, NIL) ls)
                              ->
                              (vls', nt', fvs', hd');

                          nt =  hcf::ltc_rkind (rk, nt');

                          add_dictionary (dictionary, [v], [nt], fvs', td, d, TRUE);

                          (loope (e, dictionary, d, ad))
                              ->
                              (e', nt'', fvs'', hd'');

                          (acf::RECORD (rk, vls', v, e'), nt'', fvs'@fvs'', hd'@hd'');
                      };

                  loope (acf::GET_FIELD (v, i, l, e), dictionary, d, ad)
                      =>
                      {   (loopc dictionary v)
                              ->
                              (v', nt', fvs', hd');

                          nt =  hcf::ltd_rkind (nt', i);

                          add_dictionary (dictionary, [l], [nt], fvs', td, d, TRUE);

                          (loope (e, dictionary, d, ad))
                              ->
                              (e', nt'', fvs'', hd'');

                          (acf::GET_FIELD (v', i, l, e'), nt'', fvs'@fvs'', hd'@hd'');
                      };

                  loope (acf::RAISE (v, ls), dictionary, d, ad)
                      =>
                      {   (loopc dictionary v) ->   (v', nt', fvs', hd');

                          (acf::RAISE (v', ls), ls, fvs', hd');
                      };

                  loope (acf::EXCEPT (e, v), dictionary, d, ad)
                      => 
                      {   (loopc dictionary v)           ->   (v', nt',  fvs',  hd' );
                          (loope (e, dictionary, d, ad)) ->   (e', nt'', fvs'', hd'');

                          (acf::EXCEPT (e', v'), nt'', fvs'@fvs'', hd'@hd'');
                      };

                  loope (acf::BRANCH (pr, vl, e1, e2), dictionary, d, ad)
                      => 
                      {   ls =   map   (loopc dictionary)   vl;

                          (fold_backward comb (NIL, NIL, NIL, NIL) ls) ->   (vls', nt',   fvs',   hd'  );
                          (loope (e1, dictionary, d, ad))           ->   (e1',  nt'',  fvs'',  hd'' );
                          (loope (e2, dictionary, d, ad))           ->   (e2',  nt''', fvs''', hd''');

                          (acf::BRANCH (pr, vls', e1', e2'), nt''', fvs'@fvs''@fvs''', hd'@hd''@hd''');
                      };

                  loope (acf::BASEOP (pr, vl, l, e), dictionary, d, ad)
                      => 
                      {   ls = map (loopc dictionary) vl;

                          (fold_backward comb (NIL, NIL, NIL, NIL) ls)
                              ->
                              (vls', nt', fvs', hd');

                          pr ->   (_, _, lt, ts);

                          nt =  reslty (lt, ts);

                          add_dictionary (dictionary, [l], [nt], fvs', td, d, abs);

                          (loope (e, dictionary, d, ad))
                              ->
                              (e', nt'', fvs'', hd'');

                          (acf::BASEOP (pr, vls', l, e'), nt'', fvs'@fvs'', hd'@hd'');
                      };

                  loope (e as acf::MUTUALLY_RECURSIVE_FNS ( [ ( { call_as => acf::CALL_AS_GENERIC_PACKAGE, ... }, v, lvs, e1)], e2), dictionary, d, ad)
                      => 
                      {
                          vs =  map  #1  lvs;
                          ts =  map  #2  lvs;

                          if (d > 0)      wellfixed := FALSE;   fi;

                          add_dictionary (dictionary, vs, ts, NIL, td, 0, noabs);

                          (loope (e1, dictionary, 0, di::next ad))
                              ->
                              (e', nt', fvs', hd');
                              

                          nt = hcf::ltc_fkfun (fkfct, ts, nt');

                          add_dictionary (dictionary, [v], [nt], fvs', td, 0, noabs);

                          (loope (e2, dictionary, d, ad))
                              ->
                              (e'', nt'', fvs'', hd'');

                          (acf::MUTUALLY_RECURSIVE_FNS([(fkfct, v, lvs, e')], e''), nt'', fvs'@fvs'', hd'@hd'');
                      };

                  loope (e as acf::MUTUALLY_RECURSIVE_FNS([(fk, v, lvs, e1)], e2), dictionary, d, ad)
                      => 
                      case fk
                          #
                          { loop_info =>  NULL,
                            call_as   =>  acf::CALL_AS_FUNCTION _,
                            ...
                          }
                              => 
                              { 
                                  vs =  map  #1  lvs;
                                  ts =  map  #2  lvs;

                                  add_dictionary (dictionary, vs, ts, NIL, td, di::next d, abs);

                                  (loope (e1, dictionary, di::next d, di::next ad))
                                      ->
                                      (e', nt', fvs', hd');

                                  nt =   hcf::ltc_fkfun (fk, ts, nt');

                                  abs =   if (d > 0)   TRUE;
                                          else         FALSE;
                                          fi;

                                  add_dictionary (dictionary, [v], [nt], fvs', td, d, abs);

                                  (loope (e2, dictionary, d, ad))
                                      ->
                                      (e'', nt'', fvs'', hd'');

                                  ne' =   acf::MUTUALLY_RECURSIVE_FNS([(fk, v, lvs, e')], e'');

                                  my (ne, hd)
                                      =
                                      case d   
                                          0 => (write_header (hd'@hd'', ne'), NIL);
                                          _ => (ne', hd'@hd'');
                                      esac;

                                 (ne, nt'', fvs'@fvs'', hd);
                              };

                          { loop_info => THE (rts, _), call_as => acf::CALL_AS_FUNCTION _, ... }
                              => 
                              {
                                  vs = map (#1) lvs;
                                  ts = map (#2) lvs;

                                  add_dictionary (dictionary, [v], [hcf::ltc_fkfun (fk, ts, rts)], NIL, td, di::next d, abs);

                                  add_dictionary (dictionary, vs, ts, NIL, td, di::next d, abs);

                                  (loope (e1, dictionary, di::next d, di::next ad))
                                      ->
                                      (e', nt', fvs', hd');

                                  #  Check to see that the new value is inserted 

                                  add_dictionary (dictionary, [v], [hcf::ltc_fkfun (fk, ts, rts)], NIL, td, d, abs);

                                  #  The depth is changed for correct behaviour 

                                  (loope (e2, dictionary, d, ad))
                                      ->
                                      (e'', nt'', fvs'', hd'');

                                  ne' =  acf::MUTUALLY_RECURSIVE_FNS([(fk, v, lvs, e')], e'');

                                  my (ne, hd)
                                      =
                                      case d   
                                          0 => (write_header (hd'@hd'', ne'), NIL);
                                          _ => (ne', hd'@hd'');
                                      esac;

                                  (ne, nt'', fvs'@fvs'', hd);
                              }; 

                          _ => bug "unexpected Function in main loop";
                      esac;

                  loope (e as acf::MUTUALLY_RECURSIVE_FNS (fds, e2), dictionary, d, ad)
                      =>
                      {
                          fun h d' ((fk as { loop_info => THE (rts, _), ... }, f, lvs, e1):  acf::Function)
                                  => 
                                  add_dictionary (dictionary, [f], [hcf::ltc_fkfun (fk, map #2 lvs, rts)], NIL, td, d', abs);

                              h d fk
                                  =>
                                  bug "unexpected non-recursive fkind in loop";
                          end;

                          fun g ((fk, f, lvs, e):  acf::Function)
                              = 
                              {   add_dictionary (dictionary, map #1 lvs, map #2 lvs, NIL, td, di::next d, abs);

                                  (loope (e, dictionary, di::next d, di::next ad))
                                      ->
                                      (e', nt', fvs', hd');

                                  ( (fk, f, lvs, e'), [hcf::ltc_fkfun (fk, map #2 lvs, nt')], fvs', hd');
                              };

                          map  (h (di::next d))  fds;

                          rets = map g fds;

                          (fold_backward comb (NIL, NIL, NIL, NIL) rets)
                              ->
                              (fds, nts, fvs, hds);

                          #  Check to see that the correct value is inserted 

                          map  (h d)  fds;      # Shouldn't this be 'apply'? XXX BUGGO FIXME

                          (loope (e2, dictionary, d, ad))
                              ->
                              (e'', nt'', fvs'', hd'');

                          ne' =   acf::MUTUALLY_RECURSIVE_FNS (fds, e'');

                          case d    
                              0 =>  (write_header(hds@hd'', ne'),  nt'',  fvs@fvs'',  NIL);
                              _ =>  (ne', nt'', fvs@fvs'', hds@hd'');
                          esac;
                      };
              end;
        end;


        fun convert_free_variables_to_parameters_in_anormcode  fdec:  acf::Function
            =
            #  if *controls::compiler::lifttype then 
            case fdec
                #
                (fk as { call_as => acf::CALL_AS_GENERIC_PACKAGE, ... }, v, vts, e)
                    =>
                    {
                        dictionary = init_info_dictionary();
                        d    = 0; #  di::top ?? 
                        td   = 0; #  di::top ?? 
                        ad   = 0; #  di::top ?? 

                        rename = FALSE;

                        vs = map #1 vts;
                        ts = map #2 vts;

                        add_dictionary (dictionary, vs, ts, NIL, td, d, noabs);

                        my (ne, _, _, _)
                            =
                            ( lift (e, dictionary, td, d, ad, rename) )
                            except
                                PARTIAL_TYPE_APP
                                    =
                                    { print "\n*** No Typelifting ";
                                      print " Partial Type Apply ***\n";
                                      (e, NIL, NIL, NIL);
                                    };

                        if *wellfixed 
                                   ();
                                else
                                    (); #  print "\n *** generic package at d > 0 *** \n" 
                        fi;

                        if *asc::saytappinfo 
                            #
                            print "\n *** No. of TYPEFN_APPs lifted ";
                            print (" " + (int::to_string *tapp_lifted) + " \n");
                        fi;

                        tapp_lifted := 0; 
                        wellfixed   := TRUE;
                        welltapped  := TRUE;

                        (fk, v, vts, ne);
                    };

                _ => bug "non GENERIC program in Lift";
            esac;
    };
end;




Comments and suggestions to: bugs@mythryl.org

PreviousUpNext