PreviousUpNext

15.4.65  src/app/makelib/depend/to-portable.pkg

## to-portable.pkg

# Compiled by:
#     src/app/makelib/makelib.sublib



# Generate list-of-edges dependency graph representation from
# internal makelib data structures.

stipulate
    package ad  =  anchor_dictionary;                   # anchor_dictionary                     is from   src/app/makelib/paths/anchor-dictionary.pkg
    package flt =  frozenlib_tome;                      # frozenlib_tome                        is from   src/app/makelib/freezefile/frozenlib-tome.pkg
    package ftm =  frozenlib_tome_map;                  # frozenlib_tome_map                    is from   src/app/makelib/freezefile/frozenlib-tome-map.pkg
    package lg  =  inter_library_dependency_graph;      # inter_library_dependency_graph        is from   src/app/makelib/depend/inter-library-dependency-graph.pkg
    package mls =  makelib_state;                       # makelib_state                         is from   src/app/makelib/main/makelib-state.pkg
    package pg  =  portable_graph;                      # portable_graph                        is from   src/app/makelib/portable-graph/portable-graph.pkg
    package sg  =  intra_library_dependency_graph;      # intra_library_dependency_graph        is from   src/app/makelib/depend/intra-library-dependency-graph.pkg
    package spm =  source_path_map;                     # source_path_map                       is from   src/app/makelib/paths/source-path-map.pkg
    package ss  =  symbol_set;                          # symbol_set                            is from   src/app/makelib/stuff/symbol-set.pkg
    package str =  string;                              # string                                is from   src/lib/std/string.pkg
    package sym =  symbol_map;                          # symbol_map                            is from   src/app/makelib/stuff/symbol-map.pkg
    package tlt =  thawedlib_tome;                      # thawedlib_tome                        is from   src/app/makelib/compilable/thawedlib-tome.pkg
    package ttm =  thawedlib_tome_map;                  # thawedlib_tome_map                    is from   src/app/makelib/compilable/thawedlib-tome-map.pkg
herein

    package to_portable: (weak)  api {
                                export:  ( lg::Inter_Library_Dependency_Graph,
                                           mls::Makelib_State
                                         )
                                         ->
                                         ( pg::Graph,
                                           List( ad::File )
                                         );
                           }
    {

        package slm
            =
            red_black_map_g(                            # red_black_map_g                       is from   src/lib/src/red-black-map-g.pkg

                Key = List( String );

                fun compare ([], []) =>  EQUAL;
                    compare ([], _)  =>  LESS;
                    compare (_, [])  =>  GREATER;

                    compare (h ! t, h' ! t')
                        =>
                        case (str::compare (h, h'))
                            #
                            EQUAL   =>  compare (t, t');
                            unequal =>  unequal;
                        esac;
                end;
            );

        package fm
            =
            red_black_map_g(

              Key = (String, String);

              fun compare ((v, f), (v', f'))
                  =
                  case (str::compare (v, v'))
                      #
                      EQUAL   =>  str::compare (f, f');
                      unequal =>  unequal;
                  esac;
        );

        package ssm
            =
            red_black_map_g(

                Key = ss::Set;
                compare = ss::compare;
            );

        package im
            =
            red_black_map_g(

                Key = (ad::File, String);

                fun compare ((p, s), (p', s'))
                    =
                    case (ad::compare (p, p'))
                        #
                        EQUAL   =>  str::compare (s, s');
                        unequal =>  unequal;
                    esac;
        );

        ignored_symbols
            =
            ss::add_list  ( ss::empty,
                            [ pervasive_symbol::pervasive_package_symbol, core_symbol::core_symbol ]
                          );

        fun export (lg::BAD_LIBRARY, _)
                =>
               raise exception DIE "to_portable::export BAD_LIBRARY";

            export (lg::LIBRARY { catalog, sublibraries, libfile, ... }, makelib_state)
                =>
                {   cwd = winix__premicrothread::file::current_directory ();

                    fun to_absolute p
                        =
                        if   (winix__premicrothread::path::is_absolute p)
                             p;
                        else winix__premicrothread::path::make_absolute { path => p, relative_to => cwd };fi;

                    library_dir
                        =
                        winix__premicrothread::path::dir  (to_absolute  (ad::os_string  libfile));

                    stipulate

                        fun make_tome_to_libfile_maps []
                                =>
                                ( ttm::empty,                   # This will map thawedlib_tome -> (libfile, exports_mask)
                                  ftm::empty                    # This will map frozenlib_tome -> (libfile, exports_mask)
                                );

                            make_tome_to_libfile_maps ((lt: lg::Library_Thunk) ! ls)
                                =>
                                {   (make_tome_to_libfile_maps  ls)
                                        ->
                                        (thawedlib_tome_map, frozenlib_tome_map);

                                    fun update (get, set) (map, i, (p, ex))
                                        =
                                        case (get (map, i))
                                            #
                                            THE (p', ex') =>   set (map, i, (p', ss::union (ex, ex')));
                                            NULL          =>   set (map, i, (p, ex));
                                        esac;

                                    update_thawedlib_tome_map = update (ttm::get, ttm::set);
                                    update_frozenlib_tome_map = update (ftm::get, ftm::set);

                                    fun one_e  (symbol,  (tome: lg::Fat_Tome),  (thawedlib_tome_map, frozenlib_tome_map))
                                        =
                                        case (tome.masked_tome_thunk ())
                                            #
                                            { exports_mask, tome_tin => sg::TOME_IN_FROZENLIB { frozenlib_tome_tin => sg::FROZENLIB_TOME_TIN tin, ... } }
                                                =>
                                                (thawedlib_tome_map, update_frozenlib_tome_map (frozenlib_tome_map, tin.frozenlib_tome, (lt.libfile, tome.exports_mask)));

                                            { exports_mask, tome_tin => sg::TOME_IN_THAWEDLIB (sg::THAWEDLIB_TOME_TIN tin) }
                                                =>
                                                (update_thawedlib_tome_map (thawedlib_tome_map, tin.thawedlib_tome, (lt.libfile, tome.exports_mask)), frozenlib_tome_map);
                                        esac;

                                    case (lt.library_thunk ())
                                        #
                                        lg::LIBRARY { catalog, ... }
                                            =>
                                            sym::keyed_fold_forward  one_e  (thawedlib_tome_map, frozenlib_tome_map)  catalog;

                                        _ => (thawedlib_tome_map, frozenlib_tome_map);
                                    esac;
                                };
                        end;

                        (make_tome_to_libfile_maps  sublibraries)
                            ->
                            (thawedlib_tome_map, frozenlib_tome_map);

                        fun drop_ignored_symbols (p, ex)
                          =
                          ( p,
                            ss::difference (ex, ignored_symbols)
                          );

                        thawedlib_tome_map = ttm::map  drop_ignored_symbols  thawedlib_tome_map;
                        frozenlib_tome_map = ftm::map  drop_ignored_symbols  frozenlib_tome_map;
                    herein


                        fun get_libfile_and_exports_for_frozenlib_tome
                                #
                                (frozenlib_tome:  flt::Frozenlib_Tome)
                            =
                            case (ftm::get  (frozenlib_tome_map,  frozenlib_tome))
                                #
                                THE libfile_and_exports =>  libfile_and_exports;
                                NULL                    =>  raise exception DIE "get_libfile_and_exports_for_frozenlib_tome";
                            esac;


                        fun get_libfile_and_exports_for_thawedlib_tome
                                #
                                (thawedlib_tome:  tlt::Thawedlib_Tome)
                            =
                            ttm::get  (thawedlib_tome_map,  thawedlib_tome);
                    end;

                    stipulate
                        namings   =   REF [];
                    herein
                        fun gen_bind (lhs, rhs)
                            =
                            namings := pg::DEF { lhs, rhs } ! *namings;

                        fun all_namings ()
                            =
                            reverse *namings;
                    end;

                    fun relname i
                        =
                        {   p = to_absolute (ad::os_string (tlt::sourcepath_of i));

                            s = winix__premicrothread::path::make_relative { path => p, relative_to => library_dir };

                            my { arcs, is_absolute, disk_volume }
                                =
                                winix__premicrothread::path::from_string s;

                            fun badarc a
                                =
                                a != winix__premicrothread::path::current_arc and
                                a != winix__premicrothread::path::parent_arc and
                                (a == "." or a == ".." or char::contains a '/');

                            fun to_unix []
                                    =>
                                    ".";

                                to_unix (h ! t)
                                    =>
                                    {   fun trans a
                                            =
                                            if   (a == winix__premicrothread::path::current_arc   )   ".";
                                            elif (a == winix__premicrothread::path::parent_arc    )   "..";
                                            else                                       a;
                                            fi;

                                        cat (reverse (fold_forward (\\ (a, l) = trans a ! "/" ! l)
                                                           [trans h] t));
                                    };
                            end;

                            if (is_absolute or disk_volume != ""    or
                                list::exists badarc arcs
                            )
                                (s, TRUE);
                            else
                                (to_unix arcs, FALSE);
                            fi;
                        };

                    gensym
                        =
                        { next = REF 0;

                            \\ prefix
                               =
                               {   i = *next;

                                   prefix + int::to_string i
                                   then
                                       next := i + 1;
                               };
                        };

                    smlmap    =   REF ttm::empty;
                    imports   =   REF spm::empty;

                    fun gen_lib p
                        =
                        case (spm::get (*imports, p))
                            #
                            THE v => v;

                            NULL => {   v = gensym "l";

                                        imports := spm::set (*imports, p, v);
                                        v;
                                    };
                        esac;

                    stipulate
                        symbols = REF sym::empty;
                    herein
                        fun gen_sym s
                            =
                            case (sym::get (*symbols, s))
                                #
                                THE v => v;

                                NULL
                                    =>
                                    {   my (p, ns)
                                            =
                                            case (symbol::name_space s)
                                                #
                                                symbol::API_NAMESPACE         =>  ("sgn", pg::SGN);
                                                symbol::PACKAGE_NAMESPACE     =>  ("str", pg::PACKAGE);
                                                symbol::GENERIC_NAMESPACE     =>  ("fct", pg::GENERIC);
                                                symbol::GENERIC_API_NAMESPACE => raise exception DIE "funsig not permitted in portable graphs";
                                                #
                                                _ => raise exception DIE "unexpected namespace";
                                            esac;

                                        v = gensym p;

                                        gen_bind (v, pg::SYM (ns, symbol::name s));
                                        symbols := sym::set (*symbols, s, v);
                                        v;
                                    };
                            esac;
                    end;

                    stipulate
                        sets = REF ssm::empty;
                    herein
                        fun gen_syms ss
                            =
                            case (ssm::get (*sets, ss))
                                #
                                THE v => v;

                                NULL => { v  = gensym "ss";
                                             sl = ss::vals_list ss;

                                            gen_bind (v, pg::SYMS (map gen_sym sl));
                                            sets := ssm::set (*sets, ss, v);
                                            v;
                                         }; esac;
                    end;

                    stipulate
                        filters = REF fm::empty;
                        imps    = REF im::empty;
                    herein
                        fun prevent_filter (e, f)
                            =
                            filters := fm::set (*filters, (e, f), e);

                        fun gen_filter (v, f)
                            =
                            {   s = gen_syms f;

                                case (fm::get (*filters, (v, s)))
                                    #
                                    THE e => e;

                                    NULL => {   e = gensym "e";

                                                gen_bind (e, pg::FILTER { env => v, syms => s } );
                                                filters := fm::set (*filters, (v, s), e);
                                                prevent_filter (e, s);
                                                e;
                                            };
                                esac;
                            };

                        fun gen_filter' (vex as (v, ex), f)
                            =
                            {   f' = ss::intersection (ex, f);
                                #
                                if (ss::equal (ex, f'))   vex;
                                else                      (gen_filter (v, f'), f');
                                fi;
                            };

                        fun unlayer l
                            =
                            loop (l, ss::empty, [])
                            where
                                fun loop ([], _, a)
                                        =>
                                        reverse a;

                                    loop ((h, hss) ! t, ss, a)
                                        =>
                                        {   i = ss::intersection (ss, hss);
                                            u = ss::union (ss, hss);
                                            f = ss::difference (hss, ss);

                                            if     (ss::is_empty f)   loop (t, u, a);
                                            elif   (ss::is_empty i)   loop (t, u, h ! a);
                                            else                      loop (t, u, gen_filter (h, f) ! a);
                                            fi;
                                        };
                                end;
                            end;

                        stipulate

                            merges = REF slm::empty;

                        herein
                            fun gen_merge [e]
                                    =>
                                    e;

                                gen_merge l
                                    =>
                                    case (slm::get (*merges, l))
                                        #
                                        THE e => e;

                                        NULL => { e = gensym "e";

                                                    gen_bind (e, pg::MERGE l);
                                                    merges := slm::set (*merges, l, e);
                                                    e;
                                                };
                                     esac;
                            end;
                        end;

                        fun gen_compile (v, s, e, ex)
                            =
                            {   ss = gen_syms ex;

                                prevent_filter (v, ss);
                                gen_bind (v, pg::COMPILE { src => s, env => e, syms => ss } );
                            };

                        fun gen_import (lib, ex)
                            =
                            if (ss::is_empty ex)
                                #
                                ("dummy", ex);
                            else
                                s = gen_syms ex;

                                case (im::get (*imps, (lib, s)))
                                    #
                                    THE v => (v, ex);

                                    NULL
                                        =>
                                        {   v = gensym "e";
                                            l = gen_lib lib;

                                            imps := im::set (*imps, (lib, s), v);
                                            gen_bind (v, pg::IMPORT { lib => l, syms => s } );
                                            prevent_filter (v, s);
                                            (v, ex);
                                        };
                                esac;
                           fi;
                    end;

                    fun do_thawedlib_tome_import (thawedlib_tome:  tlt::Thawedlib_Tome)
                        =
                        case (get_libfile_and_exports_for_thawedlib_tome  thawedlib_tome)
                            #   
                            THE libfile_and_exports =>   THE (gen_import libfile_and_exports);
                            NULL                    =>   NULL;
                        esac;


                    fun do_frozenlib_tome  (frozenlib_tome:  flt::Frozenlib_Tome)
                        =
                        gen_import (get_libfile_and_exports_for_frozenlib_tome  frozenlib_tome);


                    fun do_thawedlib_tome_tin (sg::THAWEDLIB_TOME_TIN { thawedlib_tome, near_imports, far_imports } )
                        =
                        case (ttm::get (*smlmap, thawedlib_tome))
                            #
                            THE vex => vex;
                            #
                            NULL =>
                                {   v =  gensym  "e";

                                    ex =    case (tlt::exports  makelib_state  thawedlib_tome)
                                                #
                                                THE ex =>  ex;
                                                NULL   =>  raise exception DIE "cannot parse SML file";
                                            esac;

                                    vex = (v, ex);
                                                                                          my _ =
                                    smlmap :=  ttm::set (*smlmap, thawedlib_tome, vex);

                                    gi =  map do_masked_tome far_imports;
                                    li =  map  do_thawedlib_tome_tin near_imports;

                                    e = gen_merge (unlayer (li @ gi));

                                    gen_compile (v, relname thawedlib_tome, e, ex);
                                    vex;
                                };
                        esac

                    also
                    fun do_masked_tome { exports_mask => NULL,   tome_tin } =>                 do_tome_tin  tome_tin;
                        do_masked_tome { exports_mask => THE f,  tome_tin } =>   gen_filter'  (do_tome_tin  tome_tin,  f);
                    end 

                    also
                    fun do_tome_tin (sg::TOME_IN_THAWEDLIB (tome_tin as sg::THAWEDLIB_TOME_TIN { thawedlib_tome, ... } ))
                            =>
                            case (do_thawedlib_tome_import  thawedlib_tome)
                                #
                                NULL    =>  do_thawedlib_tome_tin  tome_tin;
                                THE vex =>  vex;
                            esac;

                        do_tome_tin (sg::TOME_IN_FROZENLIB { frozenlib_tome_tin => sg::FROZENLIB_TOME_TIN tome_tin, ... })
                            =>
                            do_frozenlib_tome  tome_tin.frozenlib_tome;
                    end;


                    fun import_export  (fat_tome:  lg::Fat_Tome)
                        =
                        #1 (gen_filter' (do_masked_tome (fat_tome.masked_tome_thunk ()), fat_tome.exports_mask));


                    iel =                               # "iel" == "import export list"... ?
                        sym::fold_backward
                            (\\ (ie, l)
                                =
                                import_export ie ! l
                            )
                            []
                            catalog;


                    export  = gen_merge iel;


                    ( pg::GRAPH   { imports =>   spm::vals_list  *imports,
                                    defs    =>   all_namings (),
                                    export
                                  },

                      spm::keys_list  *imports
                    );
                };
        end;
    };
end;

## (C) 2001 Lucent Technologies, Bell Labs
## author: Matthias Blume (blume@research.bell-labs.com)
## Subsequent changes by Jeff Prothero Copyright (c) 2010-2015,
## released per terms of SMLNJ-COPYRIGHT.


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext