PreviousUpNext

15.4.125  src/app/makelib/tools/main/private-makelib-tools.pkg

## private-makelib-tools.pkg
#
# Private interface to makelib's tools mechanism.
# It lacks certain public features implemented by tools_g
# but provides other, non-public routines such as "expand".

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



###             "Klingon software is not "released".
###              It escapes, leaving behind a bloody
###              trail of QA people."



stipulate
    package ad  =  anchor_dictionary;                                                   # anchor_dictionary             is from   src/app/makelib/paths/anchor-dictionary.pkg
    package bc  =  basic_control;                                                       # basic_control                 is from   src/lib/compiler/front/basics/main/basic-control.pkg
    package ci  =  global_control_index;                                                # global_control_index                  is from   src/lib/global-controls/global-control-index.pkg
    package ctl =  global_control;                                                      # global_control                is from   src/lib/global-controls/global-control.pkg
    package lst =  list;                                                                # list                          is from   src/lib/std/src/list.pkg
    package mvi =  makelib_version_intlist;                                             # makelib_version_intlist       is from   src/app/makelib/stuff/makelib-version-intlist.pkg
    package shm =  sharing_mode;                                                        # sharing_mode                  is from   src/app/makelib/stuff/sharing-mode.pkg
    package spm =  source_path_map;                                                     # source_path_map               is from   src/app/makelib/paths/source-path-map.pkg
    package stm =  string_map;                                                          # string_map                    is from   src/lib/src/string-map.pkg
herein

    # This package is referenced (only) in:
    #
    #    src/app/makelib/stuff/raw-libfile.pkg
    #    src/app/makelib/parse/libfile.grammar
    #    src/app/makelib/parse/libfile-grammar-actions.pkg
    #    src/app/makelib/tools/main/tools-g.pkg
    #
    package   private_makelib_tools
    : (weak)  Private_Makelib_Tools                                                     # Private_Makelib_Tools         is from   src/app/makelib/tools/main/private-makelib-tools.api
    {
        Ilk = String;

        File_Path =  ad::File;
        Dir_Path  =  ad::Dir_Path;
        Renamings =  ad::Renamings;     # MUSTDIE

        native_spec     =  ad::os_string_relative;
        native_pre_spec =  ad::os_string_basename_relative;

        srcpath = ad::file;
        augment = ad::extend;

        exception TOOL_ERROR  { tool: String,
                                msg:  String
                              };

        Pathmaker =  Void -> Dir_Path;

        Fnspec
          =
          { name:       String,
            make_path:  Pathmaker
          };

        Tool_Option
          = STRING  Fnspec
          | SUBOPTS   { name:           String,
                        tool_options:   Tool_Options
                      }
        withtype
            Tool_Options =  List( Tool_Option );

        Tooloptcvt
            =
            Null_Or( Tool_Options ) ->
            Null_Or( Tool_Options );

        Spec
          =
          { name:               String,
            make_path:          Pathmaker,
            #
            ilk:                Null_Or( Ilk ),
            tool_options:       Null_Or( Tool_Options ),
            #
            derived:            Bool
          };


        Inlining
            =
            Null_Or( Null_Or( Int ) );

        Controller
            =
            { save_controller_state:    Void -> Void -> Void,
              set:              Void -> Void
            };

        Ml_Parameters
             =
             { share:               shm::Request,
               pre_compile_code:    Null_Or(String),
               postcompile_code:    Null_Or(String),
               split:               Inlining,
               noguid:              Bool,
               is_local:            Bool,
               controllers:         List( Controller )
             };

        Makelib_Parameters
             =
             { version:   Null_Or( mvi::Makelib_Version_Intlist )
            ,   renamings: Renamings                    # MUSTDIE
             };

        Expansion
             =
             { source_files:    List( (File_Path, Ml_Parameters) ),
               makelib_files:   List( (File_Path, Makelib_Parameters)  ),
               sources:         List( (File_Path, { ilk: String, derived: Bool }) )
             };

        Partial_Expansion
             =
             (Expansion, List( Spec ));

        Rulefn
            =
            Void -> Partial_Expansion;

        Rulecontext
             =
             Rulefn -> Partial_Expansion;

        Rule
          =
          { spec:              Spec,
            context:           Rulecontext,
            native2pathmaker:  String -> Pathmaker,
            default_ilk_of:    Fnspec -> Null_Or( Ilk ),

            sysinfo: { get_makelib_preprocessor_symbol_value:   String -> Null_Or( Int ),
                       platform:                                String
                     }
          }
          ->
          Partial_Expansion;

        Gcarg =   { name:               String,
                    make_filename:      Void -> String
                  };

        Index =   { ilks:                           Ref( stm::Map(  Rule ) ),
                    filename_suffix_classifiers:    Ref( String -> Null_Or( Ilk ) ) ,
                    general_filename_classifiers:   Ref( Gcarg  -> Null_Or( Ilk ) )
                  };

        fun layer (get1, get2) s
            =
            case (get1 s)
                #
                NULL =>  get2 s;
                x    =>  x;
            esac;

        fun make_index ()
            =
            { ilks                         =>  REF stm::empty,
              filename_suffix_classifiers  =>  REF (\\ _ = NULL),
              general_filename_classifiers =>  REF (\\ _ = NULL)
            }
            :
            Index;



        # Three indices:
        #
        #  1. global: Where globally available tools are noted and found.
        #
        #  2. local:  Where locally available tools are found;
        #             the local index is set anew every time "expand"
        #             is being called; each instance of a local registry belongs
        #             to one description file that is being processed.
        #
        #  3. plugin indices:
        #             Mapping from tool implementations (indexed
        #             by their respective description files) to that tool's
        #             index. This is where local tools register themselves;
        #             the rule for the "tool" ilk causes the tool to register
        #             itself if it has not already done so and then merges
        #             the contents of the tool's index into the current
        #             local index.
        #
        # These complications exist because tools
        # register themselves via side-effects.
        #
        global_index
            =
            make_index ();


        my local_index:   Ref( Index )                                                                  # XXX SUCKO FIXME More icky thread-hostile mutable global state.
            =
            REF (make_index ());


        my plugin_indices:  Ref( spm::Map( Index ) )                                                    # XXX SUCKO FIXME More icky thread-hostile mutable global state.
            =
            REF spm::empty;


        current_plugin =   ((REF NULL):   Ref( Null_Or( ad::File ) ));                                  # XXX SUCKO FIXME More icky thread-hostile mutable global state.


        stipulate
            fun index select convert s
                =
                {   get =  convert o (*_) o select;
                    #
                    layer (get *local_index, get global_index) s;
                };

            fun curry f x y
                =
                f (x, y);
        herein

            ilks                         =  index .ilks (curry stm::get);
            filename_suffix_classifiers  =  index .filename_suffix_classifiers   (\\ x = x);
            general_filename_classifiers =  index .general_filename_classifiers  (\\ x = x);

        end;

        Filename_Classifier
          #
          = FILENAME_SUFFIX_CLASSIFIER   String -> Null_Or( Ilk )
          | GENERAL_FILENAME_CLASSIFIER  Gcarg  -> Null_Or( Ilk )
          ;


        fun standard_filename_suffix_classifier { suffix, ilk }
            =
            FILENAME_SUFFIX_CLASSIFIER
                (\\ e
                    =
                    if (suffix == e)    THE ilk;
                    else                NULL;
                    fi
                );


        stipulate

            fun upd select augment
                =
                {   rf = select case *current_plugin                                                    # "rf" might be "ref".
                                    #                      
                                    NULL  =>    global_index;
                                    #
                                    THE p =>    case (spm::get (*plugin_indices, p))
                                                    #
                                                    THE r =>  r;
                                                    #
                                                    NULL  =>
                                                        {   r = make_index ();

                                                            plugin_indices
                                                                :=
                                                                spm::set (*plugin_indices, p, r);
                                                            r;
                                                        };
                                                esac;
                                esac;

                    rf :=  augment *rf;
                };

        herein

            fun note_ilk (ilk, rule)
                =
                upd .ilks (\\ index =  stm::set (index, ilk, rule));


            fun note_filename_classifier (FILENAME_SUFFIX_CLASSIFIER c)
                    =>
                    upd .filename_suffix_classifiers (\\ c' =  layer (c, c'));

               note_filename_classifier (GENERAL_FILENAME_CLASSIFIER c)
                    =>
                    upd .general_filename_classifiers (\\ c' =  layer (c, c'));
            end;


            fun transfer_local p
                =
                {   lr =  *local_index;

                    case (spm::get (*plugin_indices, p))
                        #
                        NULL   =>  ();
                        #
                        THE pr =>   {   fun upd select join
                                            =
                                            select lr := join (*(select pr), *(select lr));

                                        upd .ilks (stm::union_with #1);
                                        upd .filename_suffix_classifiers  layer;
                                        upd .general_filename_classifiers layer;
                                    };
                    esac;
                };

            fun with_plugin p thunk
                =
                safely::do
                    {
                      open_it    =>   {.   *current_plugin
                                           then
                                               current_plugin :=  THE p;
                                       },

                      close_it   =>   \\ prev = {   transfer_local p;
                                                    current_plugin := prev;
                                                },

                      cleanup    =>   \\ _ = ()
                    }
                    (\\ _ = thunk ());
        end;


        Extension_Style
          = EXTEND   List( (String, Null_Or(Ilk), Tooloptcvt))
          | REPLACE (List(String),  List ((String, Null_Or(Ilk), Tooloptcvt)))
          ;


        fun extend_filename (EXTEND l) (f, too)
                =>
                map
                    (\\ (s, co, toc) =  (cat [f, ".", s], co, toc too))
                    l;

            extend_filename (REPLACE (ol, nl)) (f, too)
                =>
                {   (winix__premicrothread::path::split_base_ext  f)
                        ->
                        { base, ext };


                    fun join b (e, co, toc)
                        =
                        (winix__premicrothread::path::join_base_ext { base => b, ext => THE e }, co, toc too);


                    fun gen b
                        =
                        map (join b) nl;


                    fun same_ext (e1: String) (e2: String)
                        =
                        e1 == e2;


                    case ext
                        #                         
                        NULL  =>   gen base;
                        #
                        THE e =>    if (lst::exists (same_ext e) ol)   gen base;
                                    else                                gen f;
                                    fi;
                    esac;
                };
        end;

        stipulate

            fun timex f
                =
                (winix__premicrothread::file::last_file_modification_time f, TRUE)
                except
                    _ =  (time::zero_time, FALSE);

            my (<) =  time::(<);


            fun older_than t f
                =
                winix__premicrothread::file::last_file_modification_time  f  <  t;


            fun cannot_access tool f
                =
                raise exception TOOL_ERROR { tool, msg => "cannot access " + f };

        herein

            fun outdated tool (l, f)
                =
                {   (timex f) ->   (ftime, fexists);
                    #
                    (lst::exists (older_than ftime) l)
                    except
                        _ =  if   fexists      TRUE;
                                            else   cannot_access tool f;  fi;
                };

            fun outdated' tool { source_file_name, timestamp_file_name, target_file_name }
                =
                {   (timex  source_file_name) ->   (source_t, source_e);
                    (timex  target_file_name) ->   (target_t, target_e);
                    #
                    if (not source_e)
                        #                    
                        if target_e     FALSE;
                        else            cannot_access tool source_file_name;
                        fi;
                    else 
                        if target_e
                            #
                            (timex  timestamp_file_name)
                                ->
                                (timestamp_t, timestamp_e);

                            if  timestamp_e    timestamp_t < source_t;
                            else               target_t    < source_t;
                            fi;
                        else
                            TRUE;
                        fi;
                    fi;
                };
        end;


        open_text_output
            =
            autodir::open_text_output;


        make_all_directories_on_path
            =
            autodir::make_all_directories_on_path;


        fun globally load_plugin arg
            =
            safely::do
                {
                  open_it  =>  {.   *current_plugin
                                     then
                                        current_plugin := NULL;
                                },
                  close_it =>   \\ prev =  current_plugin := prev,
                  cleanup  =>   \\ _ =  ()
                }
                (\\ _ =  load_plugin arg);


        # Query default ilk 
        #
        fun default_ilk_of  load_plugin  (s: Fnspec)
            =
            {   p =  s.name;

                make_filename =   ad::os_string_basename  o  .make_path  s;

                gcarg =   { name => p,   make_filename };


                fun filename_suffix_gen_check  e
                    =
                    case (filename_suffix_classifiers  e)
                        #                 
                        THE c =>  THE c;
                        NULL  =>  general_filename_classifiers  gcarg;
                    esac;


                case (winix__premicrothread::path::ext p)
                    #         
                    THE e
                        =>
                        case (filename_suffix_gen_check e)
                            #
                            THE c =>  THE c;
                            #
                            NULL
                                =>
                                {   plugin = cat ["$/", e, "-ext.lib"];

                                    if (globally load_plugin plugin)   filename_suffix_gen_check  e;
                                    else                               NULL;
                                    fi;
                                };
                        esac;

                    NULL =>   general_filename_classifiers  gcarg;
                esac;
            };


        fun parse_options { tool, keywords, tool_options }
            =
            loop (tool_options, stm::empty, [])
            where
                fun err m
                    =
                    raise exception TOOL_ERROR { tool, msg => m };


                fun is_kw kw
                    =
                    lst::exists
                        (\\ kw' =  kw == kw')
                        keywords;


                fun loop ([], m, ro)
                        =>
                        { matches           =>  \\ kw =  stm::get (m, kw),
                          remaining_options =>  reverse ro
                        };

                    loop (STRING { name, ... } ! t, m, ro)
                        =>
                        loop (t, m, name ! ro);

                    loop (SUBOPTS { name, tool_options } ! t, m, ro)
                        =>
                        if (not (is_kw name))
                            #                        
                            raise exception err (cat ["keyword option `", name, "' not recognized"]);
                        else
                            case (stm::get (m, name))
                                #
                                THE _ =>  err (cat ["keyword option `", name,
                                                  "' specified more than once"]);

                                NULL  =>  loop (t, stm::set (m, name, tool_options), ro);
                            esac;
                        fi;
                end;
            end;


        fun ml_rule  enforce_lazy
              {
                spec,
                context,
                native2pathmaker,
                default_ilk_of,
                sysinfo
              }
            =
            {   spec -> { name, make_path, tool_options => oto, derived, ... } : Spec;

                tool = "pkg";

                fun err  s =  raise exception TOOL_ERROR { tool, msg => s };
                fun fail s =  raise exception DIE ("(SML Tool) " + s);


                kw_pre_compile_code = "pre_compile_code";
                kw_postcompile_code = "postcompile_code";
                kw_with             = "with";

                kw_lambdasplit      = "lambdasplit";
                kw_noguid           = "noguid";

                kw_local            = "local";
                kw_lazy             = "lazy";

                use_default         = NULL;
                suggest             = THE;


                lazy_controller
                  =
                  { save_controller_state
                        =>
                       {.   orig =  *global_controls::lazy_is_a_keyword;
                            #
                           {. global_controls::lazy_is_a_keyword := orig; };
                        },

                    set =>
                        {.   global_controls::lazy_is_a_keyword := TRUE;   }
                 };


                my (srq, pre_compile_code, postcompile_code, inlining, noguid, is_local, controllers)
                    =
                    case oto
                        #                 
                        NULL => ( shm::DONT_CARE,
                                  NULL,
                                  NULL,
                                  use_default,
                                  FALSE,
                                  FALSE,
                                  if enforce_lazy       [lazy_controller];
                                  else                  [];
                                  fi
                                );
                        THE to
                            =>
                            {   my { matches, remaining_options }
                                    =
                                    parse_options
                                        {
                                          tool,
                                          keywords => [ kw_pre_compile_code,
                                                        kw_postcompile_code,
                                                        kw_with,
                                                        kw_lambdasplit
                                                      ],
                                          tool_options => to
                                        };

                                fun is_sharing_specification "shared"  =>  TRUE;
                                    is_sharing_specification "private" =>  TRUE;
                                    is_sharing_specification _         =>  FALSE;
                                end;

                                my (sh_options, remaining_options)
                                    =
                                    lst::partition
                                        is_sharing_specification
                                        remaining_options;

                                srq =   case sh_options                                         # "srq" might be "sharing_request".
                                            #
                                            []          =>  shm::DONT_CARE;
                                            ["shared"]  =>  shm::SHARED;
                                            ["private"] =>  shm::PRIVATE;
                                            _           =>  err "invalid option (s)";
                                        esac;


                                fun is_kw  kw  s
                                    = 
                                    string::compare (kw, s)   ==   EQUAL;


                                my (locals, remaining_options)
                                    =
                                    lst::partition (is_kw kw_local) remaining_options;


                                my (noguids, remaining_options)
                                    =
                                    lst::partition (is_kw kw_noguid) remaining_options;


                                my (lazies, remaining_options)
                                    =
                                    lst::partition (is_kw kw_lazy) remaining_options;


                                is_local =  not (lst::null locals);
                                noguid   =  not (lst::null noguids);

                                lazy_is_a_keyword
                                    =
                                    enforce_lazy or not (lst::null lazies);


                                if (not (lst::null remaining_options))
                                    #
                                    err (cat
                                             ( "invalid option (s): "
                                               !
                                               fold_backward
                                                   (\\ (x, l) =  " " ! x ! l)
                                                   []
                                                   remaining_options
                                             )
                                        );
                                fi;

                                pre_compile_code
                                    =
                                    case (matches  kw_pre_compile_code)
                                        #
                                        NULL           =>  NULL;
                                        THE []         =>  NULL;
                                        THE [STRING s] =>  THE s.name;
                                        #
                                        _   =>   err "invalid pre_compile_code spec";
                                    esac;

                                postcompile_code
                                    =
                                    case (matches kw_postcompile_code)
                                        #
                                        NULL           =>  NULL;
                                        THE []         =>  NULL;
                                        THE [STRING s] =>  THE s.name;

                                        _   => err "invalid postcompile_code spec";
                                    esac;

                                controllers
                                    =
                                    case (matches kw_with)
                                        #
                                        NULL =>   [];

                                        THE subopts
                                            =>
                                            loop (subopts, [])
                                            where

                                                fun fields c s
                                                    =
                                                    string::fields
                                                        (\\ c' =  c == c')
                                                        s;


                                                fun set (c, v)
                                                    =
                                                    ctl::set' (c, v)
                                                    except
                                                        ctl::BAD_VALUE_SYNTAX vse
                                                            =
                                                            fail (cat ["error setting \
                                                                         \ controller: \
                                                                         \unable to parse \
                                                                         \value `",
                                                                         vse.value,        "' for ",
                                                                         vse.control_name, " : ",
                                                                         vse.name_of_type
                                                                      ] );

                                                fun mk (n, v)
                                                    =
                                                    case (ci::find_control  bc::top_index  (fields '.' n))
                                                        #
                                                        THE c =>    { save_controller_state =>   {. ctl::save_controller_state c; },
                                                                      #
                                                                      set =>   set (c, v)
                                                                    };

                                                        NULL =>   err ("no such control: " + n);
                                                    esac;


                                                fun loop ([], a)
                                                        =>
                                                        a;

                                                    loop (STRING nv ! r, a)
                                                        =>
                                                        case (fields '=' nv.name)

                                                             [n, v] =>  loop (r, mk (n, v) ! a);
                                                             [n]    =>  loop (r, mk (n, "true") ! a);
                                                             _      =>  err "invalid controller spec";
                                                        esac;

                                                    loop (SUBOPTS { name         =>  "name",
                                                                    tool_options =>  [STRING n] } !
                                                          SUBOPTS { name         =>  "value",
                                                                    tool_options =>  [STRING v] } ! r,
                                                          a)
                                                        =>
                                                        loop (r, mk (n.name, v.name) ! a);

                                                    loop (SUBOPTS { name         =>  "name",
                                                                    tool_options =>  [STRING n] } ! r,
                                                          a)
                                                        =>
                                                        loop (r, mk (n.name, "true") ! a);

                                                    loop _
                                                        =>
                                                        err "invalid controller spec";
                                                end;

                                            end;
                                    esac;

                                inlining
                                    =
                                    {   fun invalid ()
                                            =
                                            err "invalid lambdasplit spec";

                                        fun spec (s: Fnspec)
                                            =
                                            case (lsplit_arg::arg s.name)
                                                #
                                                THE ls =>  ls;
                                                NULL   =>  invalid ();
                                            esac;

                                        case (matches kw_lambdasplit)
                                            #
                                            NULL           =>  use_default;
                                            THE []         =>  suggest (THE 0);        #  == "on" 
                                            THE [STRING x] =>  spec x;
                                            _              =>  invalid ();
                                        esac;
                                    };

                                controllers
                                    =
                                    if lazy_is_a_keyword   lazy_controller ! controllers;
                                    else                                     controllers;
                                    fi;

                                (srq, pre_compile_code, postcompile_code, inlining, noguid, is_local, controllers);
                            };
                    esac;

                p =  srcpath (make_path ());

                sparam                          # "sparam" may be "(per-)sourcefile parameters".
                    =
                    { share  => srq,
                      split  => inlining,
                      # 
                      pre_compile_code,
                      postcompile_code,
                      # 
                      noguid,
                      is_local,
                      controllers
                    };

                ( { source_files    =>  [(p, sparam)],
                    sources         =>  [(p, { ilk => "sml", derived } )],
                    makelib_files   =>  []
                  },
                  []
                );
            };


        fun makelib_rule { spec: Spec, context, native2pathmaker, default_ilk_of, sysinfo }
            =
            {   spec ->   { name, make_path, tool_options => oto, derived, ... };

                fun err m
                    =
                    raise exception TOOL_ERROR { tool => "cm", msg => m };


                fun process_options (rb, vrq, [])
                        =>
                        (rb, vrq);

                    process_options (_, _, STRING _ ! _)
                        =>
                        err "ill-formed option";

                    process_options (rb, vrq, SUBOPTS { name => "version", tool_options } ! r)
                        =>
                        {   fun ill ()
                                =
                                err "ill-formed version specification";

                            case (vrq, tool_options)
                                #                         
                                (THE _, _)
                                    =>
                                    err "version cannot be specified more than once";
                                #
                                (NULL, [STRING { name, ... } ])
                                    =>
                                    case (mvi::from_string name)
                                        #
                                        NULL  =>  ill ();
                                        THE v =>  process_options (rb, THE v, r);
                                    esac;

                                _ => ill ();
                            esac;
                        };

                    process_options (rb, vrq, SUBOPTS { name => "bind", tool_options } ! r)
                        =>
                        case tool_options
                            #                 
                            [ SUBOPTS { name => "anchor", tool_options => [STRING { name, ... } ] },
                              SUBOPTS { name => "value",  tool_options => [STRING v] }
                            ]
                                =>
                                process_options ( { anchor => name, value => v.make_path () }
                                        ! rb,
                                       vrq, r);

                            _   =>
                                err "ill-formed bind specification";
                        esac;


                    process_options (_, _, SUBOPTS { name, ... } ! _)
                        =>
                        err ("unknown option: " + name);
                end;

                my (rb, vrq)    # XXX BUGGO KILLME 'rb' is old anchor rebindings which can die.
                    =
                    case oto
                        #                 
                        NULL  =>  ([], NULL);
                        THE l =>   process_options ([], NULL, l);
                    esac;

                p = srcpath (make_path ());

                cparams
                    =
                    { version => vrq
                      , renamings => reverse rb # MUSTDIE
                    };

                ( { source_files => [],
                    sources => [(p, { ilk => "cm", derived } )],
                    makelib_files => [(p, cparams)]
                  },

                  []
                );
            };


        fun expand
              {
                error:           String -> Void,
                local_index => lr,
                spec:            Spec,
                path_root:       ad::Path_Root,
                load_plugin:     ad::Path_Root -> String -> Bool,
                sysinfo
              }
            =
            {   dummy
                    =
                    ( { source_files =>  [],
                        makelib_files  =>  [],
                        sources      =>  []
                      },
                      []
                    );


                fun norule _
                    =
                    dummy;


                fun native2pathmaker file_path ()
                    =
                    ad::from_native
                        { plaint_sink => error }
                        { path_root,   file_path };


                fun ilk2rule ilk
                    =
                    case (ilks ilk)
                        #                 
                        THE rule
                            =>
                            rule;

                        NULL
                            =>
                            {   base   =  cat ["$/", ilk, "-tool"];

                                plugin
                                    =
                                    winix__premicrothread::path::join_base_ext
                                        {
                                          base,
                                          ext  =>  THE "lib"
                                        };

                                fun complain ()
                                    =
                                    {   error (cat ["unknown ilk: ", ilk]);
                                        norule;
                                    };

                                if (globally  (load_plugin  path_root)  plugin)
                                    #
                                    case (ilks ilk)
                                        #
                                        THE rule =>  rule;
                                        NULL     =>  complain ();
                                    esac;
                                else
                                    complain ();
                                fi;
                            };
                    esac;

                fun expand1 (spec as { name, make_path, ilk => co, ... } )
                    =
                    {   fns = { name, make_path };

                        rule
                            =
                            case co
                                #                         
                                THE c0
                                    =>
                                    ilk2rule (string::map char::to_lower c0);

                                NULL
                                    =>
                                    case (default_ilk_of  (load_plugin  path_root)  fns)
                                        #
                                        THE c =>    ilk2rule c;
                                        #
                                        NULL  =>    {   error (cat ["unable to classify: ", name]);
                                                        norule;
                                                    };
                                    esac;
                            esac;

                        fun rcontext rf         # "rf" might be "rule function"
                            =
                            {   dir =  ad::os_string_dir  path_root;
                                cwd =  winix__premicrothread::file::current_directory ();

                                safely::do
                                    {
                                      open_it  =>  {. winix__premicrothread::file::change_directory  dir; },
                                      close_it =>  {. winix__premicrothread::file::change_directory  cwd; },
                                      cleanup  =>  \\ _ = ()
                                    }
                                    rf;
                            };

                        rule {
                          spec,
                          sysinfo,
                          native2pathmaker,
                          context        =>  rcontext,
                          default_ilk_of =>  default_ilk_of  (load_plugin  path_root)
                        }
                        except
                            TOOL_ERROR { tool, msg }
                                =
                                {   error (cat ["tool \"", tool, "\" failed: ", msg]);
                                    dummy;
                                };
                    };


                fun loop ([],   expansion)
                        =>
                        expansion;

                    loop (item ! items,   { source_files, makelib_files, sources })
                        =>
                        {   (expand1 item)
                                ->
                                ( { source_files =>  source_files',
                                    makelib_files  =>  makelib_files',
                                    sources      =>  sources'
                                  },
                                  il
                                );


                            loop ( il @ items,

                                   { source_files =>  source_files @ source_files',
                                     makelib_files  =>  makelib_files  @ makelib_files',
                                     sources      =>  sources      @ sources'
                                   }
                                 );
                        };
                end;

                safely::do
                    {
                      open_it  =>  {.    *local_index
                                         then
                                             local_index := lr;
                                    },

                      close_it =>  {. local_index := #prev; },

                      cleanup  =>  \\ _ = ()
                    }
                    (\\ _
                        =
                        loop (

                            [spec],

                            { source_files  =>  [],
                              makelib_files =>  [],
                              sources       =>  []
                            }
                        )
                    );
            };                  # fun expand

        stipulate

            fun suffix (suffix, ilk)
                =
                note_filename_classifier
                    #
                    (standard_filename_suffix_classifier { suffix, ilk } );
        herein
                                                                        my _ = 
            note_ilk ("sml",            ml_rule FALSE);                 my _ =
            note_ilk ("lazy-mythryl",   ml_rule TRUE);                  my _ =
            note_ilk ("cm",             makelib_rule);                  my _ =
            note_ilk ("makelib",        makelib_rule);                  my _ =

            suffix ("lib",              "makelib");                     my _ =                  # foo.lib       files contain Mythryl library definitions.
            suffix ("sublib",           "makelib");                     my _ =                  # foo.sublib    files contain Mythryl sublibrary definitions.
            suffix ("api",              "sml");                         my _ =                  # foo.api       files contain Mythryl sourcecode.
            suffix ("pkg",              "sml");                         my _ =                  # foo.pkg       files contain Mythryl sourcecode.
            suffix ("class",            "sml");                         my _ =                  # foo.class     files contain Mythryl sourcecode.
            suffix ("lazy-api",         "lazy-mythryl");                my _ =                  # foo.lazy-api  files contain Mythryl sourcecode with laziness support.  (Unsupported, undocumented functionality.)
            suffix ("lazy-pkg",         "lazy-mythryl");                                        # foo.lazy-pkg  files contain Mythryl sourcecode with laziness support.  (Unsupported, undocumented functionality.)
        end;
    };
end;


# Author: Matthias Blume (blume@kurims.kyoto-u.ac.jp)
# (C) 2000 Lucent Technologies, Bell Laboratories
## Subsequent changes by Jeff Prothero Copyright (c) 2010-2015,
## released per terms of SMLNJ-COPYRIGHT.




Comments and suggestions to: bugs@mythryl.org

PreviousUpNext