PreviousUpNext

15.4.505  src/lib/compiler/back/top/lambdacode/translate-lambdacode-to-anormcode.pkg

## translate-lambdacode-to-anormcode.pkg
## monnier@cs.yale.edu 
#
# Converting lambdacode_form::Lambdacode_Expression
# to         anormcode_form::Function.
#
#
#
# CONTEXT:
#
#     The Mythryl compiler code representations used are, in order:
#
#     1)  Raw Syntax is the initial frontend code representation.
#     2)  Deep Syntax is the second and final frontend code representation.
#     3)  Lambdacode is the first backend code representation, used only transitionally.
#     4)  Anormcode (A-Normal format, which preserves expression tree structure) is the second backend code representation, and the first used for optimization.
#     5)  Nextcode ("continuation-passing style", a single-assignment basic-block-graph form where call and return are essentially the same) is the third and chief backend tophalf code representation.
#     6)  Treecode is the backend tophalf/lowhalf transitional code representation. It is typically slightly specialized for each target architecture, e.g. Intel32 (x86).
#     7)  Machcode abstracts the target architecture machine instructions. It gets specialized for each target architecture.
#     8)  Execode is absolute executable binary machine instructions for the target architecture.
#
#     Our task here is converting from the third to the fourth form.
#
#
#
# For lambdacode code format see:            src/lib/compiler/back/top/lambdacode/lambdacode-form.api
# For A-Normal code format see:              src/lib/compiler/back/top/anormcode/anormcode-form.api
# We get invoked (only) from:                src/lib/compiler/toplevel/main/translate-raw-syntax-to-execode-g.pkg

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





###                      "Reading a translation is like examining
###                       the back of a piece of tapesty."
###
###                                              -- Cervantes.



#DO set_control "compiler::trap_int_overflow" "TRUE";

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

    api Translate_Lambdacode_To_Anormcode {
        #
        translate_lambdacode_to_anormcode
            :
            lcf::Lambdacode_Expression
            ->
            acf::Function;
    };
end;


stipulate
    package acf =  anormcode_form;                              # anormcode_form                        is from   src/lib/compiler/back/top/anormcode/anormcode-form.pkg
    package acj =  anormcode_junk;                              # anormcode_junk                        is from   src/lib/compiler/back/top/anormcode/anormcode-junk.pkg
    package di  =  debruijn_index;                              # debruijn_index                        is from   src/lib/compiler/front/typer/basics/debruijn-index.pkg
    package m2m =  convert_monoarg_to_multiarg_anormcode;       # convert_monoarg_to_multiarg_anormcode is from   src/lib/compiler/back/top/lambdacode/convert-monoarg-to-multiarg-anormcode.pkg
    package hbo =  highcode_baseops;                            # highcode_baseops                      is from   src/lib/compiler/back/top/highcode/highcode-baseops.pkg
    package hcf =  highcode_form;                               # highcode_form                         is from   src/lib/compiler/back/top/highcode/highcode-form.pkg
    package hut =  highcode_uniq_types;                         # highcode_uniq_types                   is from   src/lib/compiler/back/top/highcode/highcode-uniq-types.pkg
    package lcf =  lambdacode_form;                             # lambdacode_form                       is from   src/lib/compiler/back/top/lambdacode/lambdacode-form.pkg
    package mtt =  more_type_types;                             # more_type_types                       is from   src/lib/compiler/front/typer/types/more-type-types.pkg
    package plx =  prettyprint_lambdacode_expression;           # prettyprint_lambdacode_expression     is from   src/lib/compiler/back/top/lambdacode/prettyprint-lambdacode-expression.pkg
    package pp  =  standard_prettyprinter;                      # standard_prettyprinter                is from   src/lib/prettyprint/big/src/standard-prettyprinter.pkg
    package tdt =  type_declaration_types;                      # type_declaration_types                is from   src/lib/compiler/front/typer-stuff/types/type-declaration-types.pkg
herein


    package   translate_lambdacode_to_anormcode
    : (weak)  Translate_Lambdacode_To_Anormcode                 # Translate_Lambdacode_To_Anormcode     is from   src/lib/compiler/back/top/lambdacode/translate-lambdacode-to-anormcode.pkg
    {
        say   = control_print::say;

        make_codetemp =  highcode_codetemp::issue_highcode_codetemp;

        ident = \\ le:  lcf::Lambdacode_Expression
                    =
                    le;

        my (iadd_prim, uadd_prim)
            = 
            {   lt_int =  hcf::int_uniqtypoid;
                #
                int_op_type = hcf::make_lambdacode_arrow_uniqtypoid (hcf::make_tuple_uniqtypoid [lt_int, lt_int], lt_int);

                addu = hbo::ARITH { op=>hbo::ADD, overflow=>FALSE, kind_and_size=>hbo::UNT 31 };
            
                ( lcf::BASEOP (hbo::iadd, int_op_type, []),
                  lcf::BASEOP (addu,      int_op_type, [])
                );
            };

        fun bug msg
            =
            error_message::impossible("translate_lambdacode_to_anormcode: " + msg);

        stipulate
            my (true_valcon', false_valcon')
                = 
                ( h mtt::true_valcon,
                  h mtt::false_valcon
                )
                where
                    type =  hcf::make_arrow_uniqtypoid                          # Highcode type "Void -> Bool".
                              (
                                hcf::rawraw_variable_calling_convention,
                                [ hcf::void_uniqtypoid ],
                                [ hcf::bool_uniqtypoid ]
                              );

                    fun h (tdt::VALCON { name, form, ... } )
                        =
                        (name, form, type);
                end;

            fun bool_lexp b
                = 
                {   v = make_codetemp();
                    w = make_codetemp();

                    dc = if b  true_valcon';
                         else  false_valcon';
                         fi;
                
                    acf::RECORD (acj::rk_tuple, [], v, 
                    acf::CONSTRUCTOR (dc, [], acf::VAR v, w, acf::RET [acf::VAR w]));
                };
        herein 

            fun highcode_baseop
                  ( baseop                                                      # : acf::Baseop
                        as
                        ( dictionary:   Null_Or( acf::Dictionary ),             # Map from types to matching make_foo fns.
                          op:           hbo::Baseop,                            # Op to perform -- add, shift, fetch-from-vector, whatever.
                          op_type:      hut::Uniqtypoid,                        # Result of op.
                          arg_types:    List( hut::Uniqtype )
                        ),
                    vs,                                                         # Arg vals
                    v,                                                          # Highcode var
                    e                                                           # c_lexp
                  )
                = 
                case op

                    # Branch baseops get translated into acf::BRANCH:
                    #
                    ( hbo::IS_BOXED  | hbo::IS_UNBOXED | hbo::COMPARE _ | hbo::POINTER_EQL
                    | hbo::POINTER_NEQ | hbo::POLY_EQL | hbo::POLY_NEQ
                    )
                        =>
                        acf::LET( [v],
                                  acf::BRANCH (baseop, vs, bool_lexp TRUE, bool_lexp FALSE),
                                  e
                                );

                    # baseops that take zero arguments;
                    # argument types must be void
                    #
                    ( hbo::GET_RUNTIME_ASM_PACKAGE_RECORD               # This appears to be dead code.
                    | hbo::GET_EXCEPTION_HANDLER_REGISTER
                    | hbo::GET_CURRENT_MICROTHREAD_REGISTER
                    | hbo::DEFLVAR                                      # This appears to be dead code.
                    )
                        =>
                        {   fun fix t
                                = 
                                hcf::if_uniqtypoid_is_arrow_type
                                  ( t, 
                                    \\ (ff,[t1], ts2)
                                            =>
                                            if (hcf::same_uniqtype (t1, hcf::void_uniqtype)) 
                                                #
                                                hcf::make_type_uniqtypoid (hcf::make_arrow_uniqtype (ff, [], ts2));
                                            else
                                                bug "unexpected zero-args prims 1 in highcode_baseop";
                                            fi;

                                        _ => bug "highcodePrim: t1";
                                    end,

                                    \\ _ =  bug "unexpected zero-args prims 2 in highcode_baseop"
                                  );

                            new_op_type
                                =
                                hcf::if_uniqtypoid_is_lambdacode_typeagnostic
                                  ( op_type, 
                                    \\ (ks, t) =  hcf::make_lambdacode_typeagnostic_uniqtypoid (ks, fix t),
                                    \\ _       =  fix op_type
                                  );

                            acf::BASEOP ((dictionary, op, new_op_type, arg_types), [], v, e);
                       };

                    _ =>   acf::BASEOP (baseop, vs, v, e);
                esac;

        end;                                    #  stipulate highcode_baseop 

        # force_raw freezes the calling conventions of a data constructor;
        # strictly used by the CON and VALCON only 
        #
        fun force_raw  pty
            = 
            if (hcf::uniqtypoid_is_lambdacode_typeagnostic  pty)
                #
                my (ks, body) =  hcf::unpack_lambdacode_typeagnostic_uniqtypoid   pty;
                my (aty, rty) =  hcf::unpack_lambdacode_arrow_uniqtypoid          body;

                hcf::make_lambdacode_typeagnostic_uniqtypoid
                  ( ks,
                    hcf::make_arrow_uniqtypoid
                      (
                        hcf::rawraw_variable_calling_convention,
                        [ m2m::ltc_raw  aty ],
                        [ m2m::ltc_raw  rty ]
                      )
                  );
            else 
                (hcf::unpack_lambdacode_arrow_uniqtypoid  pty)
                    ->
                    (aty, rty);

                hcf::make_arrow_uniqtypoid
                  (
                    hcf::rawraw_variable_calling_convention,
                    [ m2m::ltc_raw  aty ],
                    [ m2m::ltc_raw  rty ]
                  );

            fi;                                 #  function force_raw 

        fun to_con  con
            =
            case con
                #
                lcf::INT_CASETAG     x =>  acf::INT_CASETAG     x;
                lcf::INT1_CASETAG    x =>  acf::INT1_CASETAG    x;
                lcf::UNT_CASETAG     x =>  acf::UNT_CASETAG     x;
                lcf::UNT1_CASETAG    x =>  acf::UNT1_CASETAG    x;
                lcf::FLOAT64_CASETAG x =>  acf::FLOAT64_CASETAG x;
                lcf::STRING_CASETAG  x =>  acf::STRING_CASETAG  x;
                lcf::VLEN_CASETAG    x =>  acf::VLEN_CASETAG    x;
                #
                lcf::INTEGER_CASETAG _ =>  bug "INTEGER_CASETAG" ;
                lcf::VAL_CASETAG     x =>  bug "unexpected case in to_con";
            esac;

        fun to_function_declaration
              ( venv,                           # Maps highcode variables to types;  initially empty.   "venv" == "variable environment".
                d,                              # Debruijn depth;  initially di::top.
                f_lv,                           # Codetemp to serve as fn name.
                arg_lv,                         # Arg for function.
                arg_lty,                        # Type of arg for function.
                body,                           # Body of function.
                loop_info                       # Initially FALSE.
              )
            =
            {   
                                                                                                                                if *log::debugging      printf "to_function_declaration/AAA   -- translate-lambdacode-to-anormcode.pkg\n";      fi;

                (to_lambda_expression  (hcf::set_uniqtypoid_for_var (venv, arg_lv, arg_lty, d), d)   body)                      # Translate the body (in the extended dictionary):
                    ->
                    (body', body_lty);

                                                                                                                                if *log::debugging      printf "to_function_declaration/BBB   -- translate-lambdacode-to-anormcode.pkg\n";      fi;

                (m2m::v_punflatten  arg_lty)                                                                                    # Detuple the arg type.
                    ->
                    ((arg_is_raw, arg_ltys, _), unflatten);
                    

                                                                                                                                if *log::debugging      printf "to_function_declaration/CCC   -- translate-lambdacode-to-anormcode.pkg\n";      fi;

                (unflatten (arg_lv, body'))                                                                                     # Add tupling code at the beginning of the body.
                    ->
                    (arg_lvs, body'');

                                                                                                                                if *log::debugging      printf "to_function_declaration/DDD   -- translate-lambdacode-to-anormcode.pkg\n";      fi;

                (m2m::t_pflatten  body_lty)                                                                                     # Construct the return type if necessary.
                    ->
                    (body_is_raw, body_ltys, _);

                                                                                                                                if *log::debugging      printf "to_function_declaration/EEE   -- translate-lambdacode-to-anormcode.pkg\n";      fi;
                rettype = if (not loop_info)  NULL;
                          else                THE (map m2m::ltc_raw body_ltys, acf::OTHER_LOOP);
                          fi;

                                                                                                                                if *log::debugging      printf "to_function_declaration/FFF   -- translate-lambdacode-to-anormcode.pkg\n";      fi;
                my (f_lty, fkind)
                    =
                    if (hcf::uniqtypoid_is_type arg_lty and hcf::uniqtypoid_is_type body_lty) 

                        # A function:
                        #
                        ( hcf::make_lambdacode_arrow_uniqtypoid (arg_lty, body_lty),

                          { loop_info         =>  rettype,
                            private =>  FALSE,
                            inlining_hint     =>  acf::INLINE_IF_SIZE_SAFE,
                            call_as           =>  acf::CALL_AS_FUNCTION (hcf::make_variable_calling_convention { arg_is_raw, body_is_raw })
                          }
                        );
                    else 
                        # A generic package:
                        # 
                        ( hcf::make_lambdacode_generic_package_uniqtypoid (arg_lty, body_lty),

                          { loop_info         =>  rettype,
                            private =>  FALSE,
                            inlining_hint     =>  acf::INLINE_IF_SIZE_SAFE,
                            call_as           =>  acf::CALL_AS_GENERIC_PACKAGE
                          }
                        );
                    fi;

                                                                                                                                if *log::debugging      printf "to_function_declaration/ZZZ   -- translate-lambdacode-to-anormcode.pkg\n";      fi;
                ( (fkind, f_lv, paired_lists::zip (arg_lvs, map m2m::ltc_raw arg_ltys), body''),
                  f_lty
                );
            }


        # Translate expressions whose structure is the same
        # in Anormcode as in lambdacode (either both naming or both non-naming)
        # a fate is unnecessary:
        #
        also
        fun to_lambda_expression  (venv, d)  lambda_expression
            =
            {   fun default_to_values ()
                    =
                    to_values
                      ( venv,
                        d,
                        lambda_expression,
                        \\ (vals, lambda_type)
                            =
                            (acf::RET vals, lambda_type)
                      );

                                                                                                                                if *log::debugging      printf "to_lambda_expression/AAA   -- translate-lambdacode-to-anormcode.pkg\n";
#                                                                                                                                       print   (pp::prettyprint_to_string [] {.
#                                                                                                                                                   pp = #pp;
#                                                                                                                                                   plx::prettyprint_lambdacode_expression  pp lambda_expression;
#                                                                                                                                               });
#                                                                                                                                                                                       printf "end of lambda-exprettion/AAA printout  -- translate-lambdacode-to-anormcode.pkg\n";
                                                                                                                                fi;
                case lambda_expression
                    #
#                   lcf::APPLY (lcf::BASEOP _, arg) => default_to_values();
#                   lcf::APPLY (lcf::GENOP  _, arg) => default_to_values();
                    lcf::APPLY (lcf::BASEOP _, arg) =>  {
                                                                                                                                if *log::debugging      printf "to_lambda_expression/BASEOP -- translate-lambdacode-to-anormcode.pkg\n";        fi;
                                                        default_to_values();
                                                        };
                    lcf::APPLY (lcf::GENOP  _, arg) =>  {
                                                                                                                                if *log::debugging      printf "to_lambda_expression/GENOP -- translate-lambdacode-to-anormcode.pkg\n";         fi;
                                                        default_to_values();
                                                        };

                    lcf::APPLY (lcf::FN (arg_lv, arg_lty, body), arg_le)
                        =>
                        {
                                                                                                                                if *log::debugging      printf "to_lambda_expression/APPLY -- translate-lambdacode-to-anormcode.pkg\n";         fi;
                            to_lambda_expression  (venv, d)  (lcf::LET (arg_lv, arg_le, body));
                        };

                    lcf::APPLY (f, arg)
                        =>
                        # First, evaluate f to a mere value:
                        # 
                        {
                                                                                                                                if *log::debugging      printf "to_lambda_expression/APPLY(2) -- translate-lambdacode-to-anormcode.pkg\n";              fi;
                            to_value
                              ( venv,
                                d,
                                f,
                                \\ (f_val, f_lty)
                                    =
                                    # Then evaluate the argument:
                                    #
{
                                                                                                                                if *log::debugging      printf "to_lambda_expression/APPLY(2)/\\ -- translate-lambdacode-to-anormcode.pkg\n";           fi;
                                    to_values
                                      ( venv,
                                        d,
                                        arg,
                                        \\ (arg_vals, arg_lty)
                                            =
                                            # Now find the return type:
                                            #
                                            {
                                                                                                                                if *log::debugging      printf "to_lambda_expression/APPLY(2)/fn2/AAA -- translate-lambdacode-to-anormcode.pkg\n";              fi;
                                                my (_, r_lty)
                                                    = 
                                                    hcf::uniqtypoid_is_lambdacode_generic_package  f_lty
                                                        ??  hcf::unpack_lambdacode_generic_package_uniqtypoid    f_lty
                                                        ::  hcf::unpack_lambdacode_arrow_uniqtypoid  f_lty;

                                                                                                                                if *log::debugging      printf "to_lambda_expression/APPLY(2)/fn2/ZZZ -- translate-lambdacode-to-anormcode.pkg\n";              fi;
                                                # And finally do the call:
                                                # 
                                                (acf::APPLY (f_val, arg_vals), r_lty);
                                            }
                                      )
; }
                              );
                        };

                    lcf::MUTUALLY_RECURSIVE_FNS (lvs, ltys, lexps, lambda_expression)
                        =>
                        {
                                                                                                                                if *log::debugging      printf "to_lambda_expression/MUTUALLY_RECURSIVE_FNS -- translate-lambdacode-to-anormcode.pkg\n";                fi;

                            venv' = paired_lists::fold_forward                                                                  # First, set up the enriched dictionary with those funs.
                                        (\\ (lv, lambda_type, ve) = hcf::set_uniqtypoid_for_var (ve, lv, lambda_type, d))
                                        venv
                                        (lvs, ltys);

                             fun map3 _ ([], _, _) => [];
                                 map3 _ (_, [], _) => [];
                                 map3 _ (_, _, []) => [];

                                 map3 f (x ! xs, y ! ys, z ! zs)
                                     =>
                                     f (x, y, z) ! map3 f (xs, ys, zs);
                             end;

                             funs = map3  \\ (f_lv, f_lty, lcf::FN (arg_lv, arg_lty, body))                                     # Then translate each function in turn.
                                                 =>
                                                 #1 (to_function_declaration (venv', d, f_lv, arg_lv, arg_lty, body, TRUE));

                                               _ =>
                                                 bug "non-function in lcf::MUTUALLY_RECURSIVE_FNS";
                                          end

                                          (lvs, ltys, lexps);

                             (to_lambda_expression  (venv', d)  lambda_expression)                                              # Finally, translate the Lambdacode_Expression.
                                 ->
                                 (lambda_expression', lambda_type);

                             ( acf::MUTUALLY_RECURSIVE_FNS (funs, lambda_expression'),
                               lambda_type
                             );
                         };

                    lcf::LET (highcode_variable, lambda_expression1, lambda_expression2)
                        =>
                        {
                                                                                                                                if *log::debugging      printf "to_lambda_expression/LET -- translate-lambdacode-to-anormcode.pkg\n";           fi;
                            to_lvar
                              ( venv,
                                d,
                                highcode_variable,
                                lambda_expression1,
                                \\ lambda_type1
                                    =
                                    to_lambda_expression
                                      ( hcf::set_uniqtypoid_for_var (venv, highcode_variable, lambda_type1, d),
                                        d
                                      )
                                      lambda_expression2
                              );
                        };

                    lcf::RAISE (le, r_lty)
                        => 
                        {
                                                                                                                                if *log::debugging      printf "to_lambda_expression/RAISE -- translate-lambdacode-to-anormcode.pkg\n";         fi;
                            to_value
                              ( venv,
                                d,
                                le,
                                \\ (le_val, le_lty)
                                    =
                                    {   my (_, r_ltys, _)
                                            =
                                            m2m::t_pflatten r_lty;

                                        ( acf::RAISE (le_val, map m2m::ltc_raw r_ltys),
                                          r_lty
                                        );
                                    }
                              );
                        };

                    lcf::EXCEPT (body, handler)
                        =>
                        {
                                                                                                                                if *log::debugging      printf "to_lambda_expression/EXCEPT -- translate-lambdacode-to-anormcode.pkg\n";                fi;
                            to_value
                              ( venv,
                                d,
                                handler,
                                \\ (h_val, h_lty)
                                    =
                                    {   (to_lambda_expression  (venv, d)  body)
                                            ->
                                            (body', body_lty);

                                        (acf::EXCEPT (body', h_val), body_lty);
                                    }
                              );
                        };

                    lcf::SWITCH (le, acs,[], NULL)
                        => bug "unexpected case in lcf::SWITCH";
                         #  to_value (venv, d, le, \\ _ = (acf::RET[], [])) 

                    lcf::SWITCH (le, acs,[], THE lambda_expression)
                        =>
                        {
                                                                                                                                if *log::debugging      printf "to_lambda_expression/SWITCH -- translate-lambdacode-to-anormcode.pkg\n";                fi;
                            to_value
                              ( venv,
                                d,
                                le,
                                \\ (v, lambda_type)
                                    =
                                    to_lambda_expression
                                      (venv, d)
                                      lambda_expression
                              );
                        };

                    lcf::SWITCH (le, acs, conlexps, default)
                        =>
                        {
                                                                                                                                if *log::debugging      printf "to_lambda_expression/SWITCH(2) -- translate-lambdacode-to-anormcode.pkg\n";             fi;
                            fun f (lcf::VAL_CASETAG((s, cr, lambda_type), types, highcode_variable), le)
                                    =>
                                    {   my (lv_lty, _)
                                            =
                                            hcf::unpack_lambdacode_arrow_uniqtypoid
                                              (hcf::apply_typeagnostic_type_to_arglist_with_single_result
                                                  (lambda_type, types)
                                              );

                                        newvenv = hcf::set_uniqtypoid_for_var (venv, highcode_variable, lv_lty, d);

                                        (to_lambda_expression  (newvenv, d)  le)
                                            ->
                                            (le, le_lty);

                                        ( ( acf::VAL_CASETAG
                                              ( (s, cr, force_raw  lambda_type),
                                                map m2m::tcc_raw  types,
                                                highcode_variable
                                              ),
                                            le
                                          ),
                                          le_lty
                                        );
                                    };

                                f (con, le)
                                    =>
                                    {   (to_lambda_expression (venv, d) le) ->   (lambda_expression, lambda_type);
                                        #
                                        ((to_con con, lambda_expression), lambda_type);
                                    };
                            end;

                            to_value
                              ( venv,
                                d,
                                le,
                                \\ (v, lambda_type)
                                    =
                                    {   default  = null_or::map  (#1 o to_lambda_expression (venv, d))  default;
                                        conlexps = map f conlexps;
                                        lambda_type = #2 (list::head conlexps);
                                        (acf::SWITCH (v, acs, map #1 conlexps, default), lambda_type);
                                    }
                              );
                       };

                    # For mere values, use to_values:
                    # 
                    _ => {
                                                                                                                                if *log::debugging      printf "to_lambda_expression/_ -- translate-lambdacode-to-anormcode.pkg\n";             fi;
                                default_to_values ();
                         };
                esac;
            }


        # tovalue: turns a lambdacode Lambdacode_Expression into a value+type and then calls
        # the fate that will turn it into an Anormcode Lambdacode_Expression+type
        # (ltyenv * debruijn_index * lcf::Lambdacode_Expression * ((value * Uniqtypoid) -> (acf::Lambdacode_Expression * Uniqtypoid list))) -> (acf::Lambdacode_Expression * Uniqtypoid)
        # 
        # - venv is the type dictionary for values
        # - conts is the fate
        #
        also
        fun to_value (venv, d, lambda_expression, fate)
            =
            case lambda_expression
                #                  
                # For simple values, it's trivial:
                #        
                lcf::VAR v
                    =>
                    fate (acf::VAR v, hcf::get_uniqtypoid_for_var (venv, v, d));

                lcf::INT i
                    => 
                    {   i+i+2;                                  # Maybe trigger OVERFLOW exception.
                        fate (acf::INT i, hcf::int_uniqtypoid);
                    }
                    except
                        OVERFLOW
                            =
                            {   z  = i / 2;
                                ne = lcf::APPLY (iadd_prim, lcf::RECORD [lcf::INT z, lcf::INT (i-z)]);
                                to_value (venv, d, ne, fate);
                            };


                lcf::UNT i
                    => 
                    {   max_unt = 0ux20000000;

                        if (unt::(<) (i, max_unt))
                            #
                            fate (acf::UNT i, hcf::int_uniqtypoid);
                        else
                            x1 = unt::(/) (i, 0u2);
                            x2 = unt::(-) (i, x1);

                            ne = lcf::APPLY (uadd_prim, lcf::RECORD [lcf::UNT x1, lcf::UNT x2]);

                            to_value (venv, d, ne, fate);
                        fi;
                    };

                lcf::INT1   n =>  fate (acf::INT1   n, hcf::int1_uniqtypoid);
                lcf::UNT1   n =>  fate (acf::UNT1   n, hcf::int1_uniqtypoid);
                lcf::FLOAT64 x =>  fate (acf::FLOAT64 x, hcf::float64_uniqtypoid);
                lcf::STRING  s =>  fate (acf::STRING  s, hcf::string_uniqtypoid);

                # For cases where to_lvar is more convenient:
                #        
                _   => 
                    {   lv = make_codetemp();
                        to_lvar
                          ( venv,
                            d,
                            lv,
                            lambda_expression,
                            \\ lambda_type
                                =
                                fate (acf::VAR lv, lambda_type)
                          );
                    };
            esac



        # to_values: turns a lambdacode Lambdacode_Expression into a list of values and a list of types
        # and then calls the fate that will turn it into an Anormcode Lambdacode_Expression+type
        #
        # ( ltyenv,
        #   debruijn_index,
        #   lcf::Lambdacode_Expression,
        #   ((List(value), List(Uniqtypoid)) -> (acf::Lambdacode_Expression,  List(Uniqtypoid)))
        # ) 
        # -> (acf::Lambdacode_Expression, Uniqtypoid)
        # 
        # - venv is the type dictionary for values
        # - fate is the fate
        #
        also
        fun to_values (venv, d, lambda_expression, fate)
            =
            case lambda_expression   
                #
                lcf::RECORD  lexps
                    =>
                    lexps2values
                      ( venv,
                        d,
                        lexps,
                        \\ (vals, ltys)
                            =
                            {   lambda_type =  hcf::make_tuple_uniqtypoid  ltys;
                                #
                                (m2m::t_pflatten lambda_type)
                                    ->
                                    (_, ltys, _);

                                # Detect the case where
                                # flattening is trivial:
                                # 
                                if (hcf::same_uniqtypoid (lambda_type, hcf::make_tuple_uniqtypoid ltys) )
                                    #
                                    fate (vals, lambda_type);
                                else
                                    lv = make_codetemp();

                                    (m2m::v_pflatten lambda_type) ->   (_, pflatten)  ;
                                    (pflatten (acf::VAR lv))      ->   (vs, wrap)     ;
                                    (fate (vs, lambda_type))      ->   (c_lexp, c_lty);

                                    ( acf::RECORD (acj::rk_tuple, vals, lv, wrap c_lexp),
                                      c_lty
                                    );
                                fi;
                            }
                      );

                _   =>
                    to_value
                      ( venv,
                        d,
                        lambda_expression,
                        \\ (v, lambda_type)
                            =
                            {   ((#2 (m2m::v_pflatten lambda_type))  v)
                                    ->
                                    (vs, wrap);

                                (fate (vs, lambda_type))
                                    ->
                                    (c_lexp, c_lty);

                                (wrap c_lexp, c_lty);
                            }
                      );
            esac

        # Evaluate each lambda_expression
        # to a value:
        # 
        also
        fun lexps2values (venv, d, lexps, fate)
            =
            f lexps ([], [])
            where
                fun f [] (vals, ltys)
                        =>
                        fate (reverse vals, reverse ltys);

                    f (lambda_expression ! lexps) (vals, ltys)
                        =>
                        to_value
                          ( venv,
                            d,
                            lambda_expression,
                            \\ (v, lambda_type)
                                =
                                f lexps (v ! vals, lambda_type ! ltys)
                          );
                end;
            end


        # to_lvar: Same as to_value except that
        # it binds the value of the lambdacode
        # to the indicated Variable
        # and passes just the type to the continuation:
        #
        also
        fun to_lvar
               ( venv,
                 d,
                 highcode_variable,
                 lambda_expression,
                 fate
               )
            =
            {   fun eta_expand (f, f_lty)                                       # "eta-expansion" is the conversion   f   ->   \\ x = f(x)
                    =                                                           # E.g., we do this to baseops because they are not legal function values in anormcode (unlike lambdacode).
                    {   lv = make_codetemp();
                        #
                        (hcf::unpack_lambdacode_arrow_uniqtypoid  f_lty)
                            ->
                            (arg_lty, ret_lty);                                 # Arg type and return type of 'f'.

                        to_lvar
                          ( venv,
                            d,
                            highcode_variable,
                            lcf::FN (lv, arg_lty, lcf::APPLY (f, lcf::VAR lv)),
                            fate
                          );
                    };

                # inbetween to_lvar and to_value:
                # it binds the lambda_expression
                # to a variable but is free to choose
                # the Variable and passes
                # it to the continutation:
                #
                fun to_lvarvalue (venv, d, lambda_expression, fate)
                    =
                    to_value
                      ( venv,
                        d,
                        lambda_expression,
                        \\ (v, lambda_type)
                            =
                            case v
                                #
                                acf::VAR lv
                                    =>
                                    fate (lv, lambda_type);

                                _   =>
                                    {   lv =  make_codetemp ();
                                        #
                                        (fate (lv, lambda_type))
                                            ->
                                            (lambda_expression', lambda_type);

                                        (acf::LET ([lv], acf::RET [v], lambda_expression'), lambda_type);
                                    };
                            esac
                      );

                fun baseop_helper (arg, f_lty, types, filler)
                    =
                    # Invariant:  baseop's types are always fully closed.
                    # 
                    {   # pty is the resulting highcode type of the underlying baseop,
                        # r_lty is the result lambdacode type of this baseop expression,
                        # and flatten_args indicates whether we should flatten the arguments or not.
                        # The results of baseops are never flattened.
                        #
                        my (pty, r_lty, flatten_args)
                            = 
                            case (hcf::uniqtypoid_is_lambdacode_typeagnostic f_lty, types) 
                                #
                                (TRUE, _)               # Typeagnostic case.
                                    => 
                                    {   my (ks,  lt ) =  hcf::unpack_lambdacode_typeagnostic_uniqtypoid   f_lty;
                                        my (aty, rty) =  hcf::unpack_lambdacode_arrow_uniqtypoid  lt;

                                        r_lty
                                            = 
                                            hcf::apply_typeagnostic_type_to_arglist_with_single_result
                                              ( hcf::make_lambdacode_typeagnostic_uniqtypoid (ks, rty),
                                                types
                                              );

                                        (m2m::t_pflatten aty) ->   (_, atys, flatten_args);

                                        # You really want to have a simpler                             # XXX SUCKO FIXME
                                        # flattening heuristic here; in fact,
                                        # baseop can have its own flattening
                                        # strategy. The key is that baseop's 
                                        # type never escape outside.

                                        atys =  map  m2m::ltc_raw  atys;

                                        nrty =  m2m::ltc_raw rty;

                                        pty  =  hcf::make_arrow_uniqtypoid
                                                  (
                                                    hcf::rawraw_variable_calling_convention,
                                                    atys,
                                                    [ nrty ]
                                                  );

                                        ( hcf::make_lambdacode_typeagnostic_uniqtypoid (ks, pty),
                                          r_lty,
                                          flatten_args
                                        );
                                    };

                                (FALSE, [])             # Typelocked case.
                                    =>
                                    {   (hcf::unpack_lambdacode_arrow_uniqtypoid  f_lty)
                                            ->
                                            (aty, rty );

                                        (m2m::t_pflatten  aty)
                                            ->
                                            (_, atys, flatten_args);

                                        atys =  map  m2m::ltc_raw  atys;

                                        nrty =  m2m::ltc_raw  rty;

                                        pty  =  hcf::make_arrow_uniqtypoid
                                                  (
                                                    hcf::rawraw_variable_calling_convention,
                                                    atys,
                                                    [nrty]
                                                  );

                                        (pty, rty, flatten_args);
                                    };

                                _ => bug "unexpected case in baseop_helper";
                            esac;

                        if flatten_args 
                            #
                            # ZHONG asks: is the following definitely safe ?                    XXX QUERO FIXME
                            # what would happen if ltc_raw is not an identity function ?
                            #
                            to_values
                              ( venv,
                                d,
                                arg,
                                \\ (arg_vals, arg_lty)
                                    =
                                    {   (fate (r_lty)) ->   (c_lexp, c_lty);
                                        #       
                                        (filler (arg_vals, pty, c_lexp), c_lty);                                                        # Put the filling inbetween.
                                    }
                              );  
                        else 
                            to_value
                              ( venv,
                                d,
                                arg,
                                \\ (arg_val, arg_lty)
                                    =
                                    {   (fate (r_lty)) ->   (c_lexp, c_lty);
                                        #       
                                        (filler([arg_val], pty, c_lexp), c_lty);                                                        # Put the filling inbetween.
                                    }
                              );
                        fi;   
                    };                  # fun baseop_helper 

                fun default_tolexp ()
                    =
                    {   (to_lambda_expression (venv, d) lambda_expression)
                            ->
                            (lambda_expression', lambda_type);

                        (fate (lambda_type))            ->   (c_lexp, c_lty);

                        (m2m::v_punflatten lambda_type) ->   (_, punflatten);

                        (punflatten (highcode_variable, c_lexp)) ->   (lvs, c_lexp' );

                        (acf::LET (lvs, lambda_expression', c_lexp'),   c_lty);
                    };

#              fun default_to_value ()
#                   = 
#                  to_value
#                     ( venv,
#                       d,
#                       lambda_expression, 
#                       \\ (v, lambdaType)
#                          = 
#                          {  my (lambda_expression', ltys) = fate (lambdaType); 
#                             (acf::LET([highcode_variable], acf::RET[v], lambda_expression'), ltys) ;
#                          }
#                     ) 

            
                case lambda_expression
                    #
                    # baseops have to be eta-expanded (wrapped in functions) here because
                    # bare baseops are not valid function values in anormcode (unlike lambdacode):

                    lcf::BASEOP   (_, lambda_type, types) =>  eta_expand (lambda_expression, hcf::apply_typeagnostic_type_to_arglist_with_single_result (lambda_type, types));
                    lcf::GENOP (_, _, lambda_type, types) =>  eta_expand (lambda_expression, hcf::apply_typeagnostic_type_to_arglist_with_single_result (lambda_type, types));

                    lcf::FN (arg_lv, arg_lty, body)
                        =>
                        # Translate the body with the extended 
                        # dictionary into a Function_Declaration:
                        #
                        {   (to_function_declaration (venv, d, highcode_variable, arg_lv, arg_lty, body, FALSE))
                                ->
                                (function_declaration as (fk, f_lv, args, body'), f_lty);

                            (fate  f_lty)
                                ->
                                (lambda_expression, lambda_type);

                            ( acf::MUTUALLY_RECURSIVE_FNS ( [function_declaration], lambda_expression),
                              lambda_type
                            );
                        };

                    # This is were we really deal with baseops:
                    # 
                    lcf::APPLY  (lcf::BASEOP (baseop, f_lty, types),  arg)
                        =>
                        baseop_helper
                          ( arg,
                            f_lty,
                            types,
                            \\ (arg_vals, pty, c_lexp)
                                =
                                highcode_baseop
                                  ( (NULL, baseop, pty, map m2m::tcc_raw types),
                                    arg_vals,
                                    highcode_variable,
                                    c_lexp
                                  )
                          );

                    lcf::APPLY (lcf::GENOP( { default, table }, baseop, f_lty, types), arg)
                        =>
                        {   fun evaluate_table ([], result, fate)
                                    =>
                                    fate result;

                                evaluate_table ((types, le) ! t1, t2, fate)
                                    =>
                                    to_lvarvalue
                                      ( venv,
                                        d,
                                        le,
                                        \\ (le_lv, le_lty)
                                            =
                                            evaluate_table (t1, (map m2m::tcc_raw types, le_lv) ! t2, fate)
                                      );
                            end;

                            # First, evaluate default:
                            # 
                            to_lvarvalue
                              ( venv,
                                d,
                                default,
                                \\ (default_lv, default_lty)
                                    =
                                    # Then evaluate the table:
                                    # 
                                    evaluate_table ( table,
                                        [],
                                        \\ table'
                                            =
                                            baseop_helper
                                              ( arg,
                                                f_lty,
                                                types,
                                                \\ (arg_vals, pty, c_lexp)
                                                    =
                                                    highcode_baseop
                                                      ( ( THE { default => default_lv, 
                                                                table   => table'
                                                              },
                                                          baseop,
                                                          pty, 
                                                          map m2m::tcc_raw types
                                                        ),
                                                        arg_vals,
                                                        highcode_variable,
                                                        c_lexp
                                                      )
                                              )
                                      )
                              );
                        };


                    lcf::TYPEFUN (tks, body)
                        =>
                        {   my (body', body_lty)
                                =
                                to_value
                                  ( venv,
                                    di::next d,
                                    body, 
                                    \\ (le_val, le_lty)
                                        =
                                        (acf::RET [le_val], le_lty)
                                  );

                            lambda_type = hcf::make_lambdacode_typeagnostic_uniqtypoid (tks, body_lty);

                            (fate (lambda_type))
                                ->
                                (lambda_expression', lambda_type);

                            args =   map  (\\ tk = (make_codetemp(), tk))  tks;

                            ( acf::TYPEFUN
                                ( ( { inlining_hint => acf::INLINE_IF_SIZE_SAFE },
                                    highcode_variable,
                                    args,
                                    body'
                                  ),
                                  lambda_expression'
                                ),
                              lambda_type
                            );
                        };

                    lcf::APPLY_TYPEFUN (f, types)
                        =>
                        # Similar to APPLY:
                        # 
                        to_value
                          ( venv,
                            d,
                            f,
                            \\ (f_val, f_lty)
                                =
                                {   f_lty = hcf::apply_typeagnostic_type_to_arglist_with_single_result
                                                (f_lty, types);

                                    my (c_lexp, c_lty)
                                        =
                                        fate (f_lty);

                                    ( acf::LET( [highcode_variable],
                                              acf::APPLY_TYPEFUN (f_val,  map  m2m::tcc_raw  types),
                                              c_lexp
                                            ),
                                      c_lty
                                    );
                                }
                          );

                    lcf::EXCEPTION_TAG (le, lambda_type)
                        =>
                        to_value
                          ( venv,
                            d,
                            le,
                            \\ (le_lv, le_lty)
                                =
                                {   (fate (hcf::make_exception_tag_uniqtypoid lambda_type))
                                        ->
                                        (c_lexp, c_lty);

                                    make_exception_tag
                                        =
                                        acj::make__make_exception_tag
                                            #
                                            (m2m::tcc_raw  (hcf::unpack_type_uniqtypoid lambda_type));

                                    ( highcode_baseop (make_exception_tag, [le_lv], highcode_variable, c_lexp),
                                      c_lty
                                    );
                                }
                          );

                    lcf::CONSTRUCTOR ((s, cr, lambda_type), types, le)
                        =>
                        to_value
                          ( venv,
                            d,
                            le,
                            \\ (v, _)
                                =
                                {   r_lty = hcf::apply_typeagnostic_type_to_arglist_with_single_result
                                                #
                                                (lambda_type, types);

                                    (hcf::unpack_lambdacode_arrow_uniqtypoid  r_lty) ->   (_,      v_lty);
                                    (fate                                     v_lty) ->   (c_lexp, c_lty);

                                    ( acf::CONSTRUCTOR
                                        ( (s, cr, force_raw lambda_type),
                                          map m2m::tcc_raw types,
                                          v,
                                          highcode_variable,
                                          c_lexp
                                        ),

                                      c_lty
                                    );
                                }
                           );

                    lcf::VECTOR (lexps, type)
                        =>
                        lexps2values
                          ( venv,
                            d,
                            lexps,
                            \\ (vals, ltys)
                                =
                                {   lambda_type
                                        =
                                        hcf::make_type_uniqtypoid
                                            #
                                            (hcf::make_ro_vector_uniqtype  type);

                                    (fate (lambda_type)) ->   (c_lexp, c_lty);

                                    ( acf::RECORD
                                        ( acf::RK_VECTOR (m2m::tcc_raw type),
                                          vals,
                                          highcode_variable,
                                          c_lexp
                                        ),
                                        c_lty
                                    );
                                }
                          );

                    lcf::RECORD lexps
                        =>
                        lexps2values
                          ( venv,
                            d,
                            lexps,
                            \\ (vals, ltys)
                                =
                                {   lambda_type = hcf::make_tuple_uniqtypoid  ltys;
                                    #
                                    (fate lambda_type) ->   (c_lexp, c_lty);

                                    (acf::RECORD (acj::rk_tuple, vals, highcode_variable, c_lexp), c_lty);
                                }
                          );

                    lcf::PACKAGE_RECORD lexps
                        =>
                        lexps2values
                          ( venv,
                            d,
                            lexps,
                            \\ (vals, ltys)
                                =
                                {   lambda_type =  hcf::make_package_uniqtypoid  ltys;
                                    #
                                    (fate  lambda_type) ->   (c_lexp, c_lty);

                                    ( acf::RECORD
                                        ( acf::RK_PACKAGE,
                                          vals,
                                          highcode_variable,
                                          c_lexp
                                        ),

                                      c_lty
                                    );
                                }
                          );

                    lcf::GET_FIELD (n, lambda_expression)
                        =>
                        to_value
                          ( venv,
                            d,
                            lambda_expression,
                            \\ (v, lambda_type)
                                =
                                {   lambda_type =  (hcf::lt_get_field (lambda_type, n));
                                    #
                                    (fate  lambda_type) ->   (c_lexp, c_lty);

                                    ( acf::GET_FIELD (v, n, highcode_variable, c_lexp),
                                      c_lty
                                    );
                                }
                          );

                    lcf::PACK (lambda_type, otypes, ntypes, lambda_expression)
                        =>
                        bug "PACK is not currently supported";

            /*
                        to_value (venv, d, lambda_expression,
                                \\ (v, v_lty) =>
                                let nlty = hcf::pmacroExpandPolymorephicLambdaTypeOrHOC (lambdaType, ntypes)
                                    my (c_lexp, c_lty) = fate (nlty)
                                in (acf::PACK (lambdaType,
                                           map m2m::tcc_raw otypes,
                                           map m2m::tcc_raw ntypes,
                                           v, highcode_variable, c_lexp),
                                    c_lty)
                                end)
            */

                  #  these ones shouldn't matter because they shouldn't appear 
            #        | lcf::WRAP _ => bug "unexpected WRAP in plambda" 
            #        | lcf::UNWRAP _ => bug "unexpected UNWRAP in plambda" 

                    _ => default_tolexp ();
                esac;
            };

        # We get invoked (only) from:
        #
        #     src/lib/compiler/toplevel/main/translate-raw-syntax-to-execode-g.pkg
        #
        fun translate_lambdacode_to_anormcode (lambda_expression as lcf::FN (arg_lv, arg_lty, body))                                    # PUBLIC.
                =>
                #1 (to_function_declaration (hcf::empty_highcode_variable_to_uniqtypoid_map, di::top, make_codetemp(), arg_lv, arg_lty, body, FALSE))
                except
                    x = raise exception x;

            translate_lambdacode_to_anormcode _
                =>
                bug "unexpected toplevel Lambdacode_Expression";
        end;
    };                                  # package translate_lambdacode_to_anormcode 
end;                                    # toplevel stipulate 


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext