PreviousUpNext

15.4.50  src/app/makelib/compilable/thawedlib-tome.pkg

## thawedlib-tome.pkg
#
# This is where we track information about a sourcecode file
# which we have compiled, are compiling, or might compile.
#
# We track in particular the name of the file and the name
# of the foo.lib library claiming that file.
#
# We track in addition basically all relevant information
# about that file which doesn't require compiling it.
#
# Compiler-produced info about the file is stored separately in
#
#     src/app/makelib/compile/thawedlib-tome--to--compiledfile-contents--map-g.pkg
#
# using our Thawedlib_Tome record as the lookup key.

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

# See overview comments in
#      src/app/makelib/compilable/thawedlib-tome.api

stipulate
    package ad  =  anchor_dictionary;                                                   # anchor_dictionary             is from   src/app/makelib/paths/anchor-dictionary.pkg
    package bio =  data_file__premicrothread;                                           # data_file__premicrothread     is from   src/lib/std/src/posix/data-file--premicrothread.pkg
    package cf  =  compiledfile;                                                        # compiledfile                  is from   src/lib/compiler/execution/compiledfile/compiledfile.pkg
    package ctl =  global_controls;                                                     # global_controls               is from   src/lib/compiler/toplevel/main/global-controls.pkg
    package err =  error_message;                                                       # error_message                 is from   src/lib/compiler/front/basics/errormsg/error-message.pkg
    package fil =  file__premicrothread;                                                # file__premicrothread          is from   src/lib/std/src/posix/file--premicrothread.pkg
    package fp  =  filename_policy;                                                     # filename_policy               is from   src/app/makelib/main/filename-policy.pkg
    package iox =  io_exceptions;                                                       # io_exceptions                 is from   src/lib/std/src/io/io-exceptions.pkg
    package lsi =  library_source_index;                                                # library_source_index          is from   src/app/makelib/stuff/library-source-index.pkg
    package mds =  module_dependencies_summary;                                         # module_dependencies_summary   is from   src/app/makelib/compilable/module-dependencies-summary.pkg
    package mld =  makelib_defaults;                                                    # makelib_defaults              is from   src/app/makelib/stuff/makelib-defaults.pkg
    package mls =  makelib_state;                                                       # makelib_state                 is from   src/app/makelib/main/makelib-state.pkg
    package mp  =  mythryl_parser;                                                      # mythryl_parser                is from   src/lib/compiler/front/parser/main/mythryl-parser.pkg
    package pm  =  parse_mythryl;                                                       # parse_mythryl                 is from   src/lib/compiler/front/parser/main/parse-mythryl.pkg
    package pn  =  parse_nada;                                                          # parse_nada                    is from   src/lib/compiler/front/parser/main/parse-nada.pkg
    package pp  =  standard_prettyprinter;                                              # standard_prettyprinter        is from   src/lib/prettyprint/big/src/standard-prettyprinter.pkg
    package raw =  raw_syntax;                                                          # raw_syntax                    is from   src/lib/compiler/front/parser/raw-syntax/raw-syntax.pkg
    package sci =  sourcecode_info;                                                     # sourcecode_info               is from   src/lib/compiler/front/basics/source/sourcecode-info.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 sm  =  line_number_db;                                                      # line_number_db                is from   src/lib/compiler/front/basics/source/line-number-db.pkg
    package syx =  symbolmapstack;                                                      # symbolmapstack                is from   src/lib/compiler/front/typer-stuff/symbolmapstack/symbolmapstack.pkg
    package sy  =  symbol;                                                              # symbol                        is from   src/lib/compiler/front/basics/map/symbol.pkg
    package ts  =  timestamp;                                                           # timestamp                     is from   src/app/makelib/paths/timestamp.pkg
    package wnx =  winix__premicrothread;                                               # winix__premicrothread         is from   src/lib/std/winix--premicrothread.pkg
herein

    package   thawedlib_tome
    :         Thawedlib_Tome                                                            # Thawedlib_Tome                is from   src/app/makelib/compilable/thawedlib-tome.api
    {
        Source_Code_Region =   sm::Source_Code_Region;
        Inlining_Request   =   ctl::inline::Localsetting;

        Plaint_Sink        =   err::Plaint_Sink;

        Attributes
          =
          { crossmodule_inlining_aggressiveness:        Inlining_Request,               # This gets used in   src/lib/compiler/back/top/improve/do-crossmodule-anormcode-inlining.pkg
            #
            is_runtime_package:              Bool,                                      # Special bootstrap kludge supporting access C-code level --   see src/lib/core/init/runtime.pkg
            noguid:                          Bool,
            #
            explicit_core_symbol:            Null_Or( sy::Symbol ),                     # Deep bootstrap magic for special "_Core"/"Core" package.
            extra_static_compile_dictionary: Null_Or( syx::Symbolmapstack )             # See bottom-of-file comments in   src/app/makelib/compilable/thawedlib-tome.api
          };

        Controller
          =
          { save_controller_state:  Void -> Void -> Void,                                       # Generate a thunk containing the current controller state, which when run will restore the controller to that state.
            set:           Void -> Void
          };

        Info_Args                                                                       # Argument to the make_thawedlib_tome and make_thawedlib_tome' calls which create Thawedlib_Tome instances.
          =
          { sourcepath:         ad::File,                                               # File containing source code which compiles to produce .compiled file in question.     
            library:           (ad::File, Source_Code_Region),
            sharing_request:    shm::Request,
            pre_compile_code:   Null_Or(String), 
            postcompile_code:   Null_Or(String), 
            is_local:           Bool,
            controllers:        List( Controller )
          };

         Sourcefile_Syntax
             =
             MYTHRYL | NADA;

         Generation
             =
             Ref( Void );


         # 2007-08-20 CrT:
         # You'd think from the name that we must
         # store Persistent_Tome_Info records on disk
         # somewhere, but I find no evidence of this.
         # I think its name comes from the fact that
         # it is what our 'known_info' in-memory index
         # stores on a per-file basis.
         #
         Persistent_Tome_Info
            =
            PERSISTENT_TOME_INFO
              {
                library:    (ad::File, Source_Code_Region),
                generation: Ref( Generation ),
                #
                sourcefile_timestamp
                    :
                    Ref( ts::Timestamp ),

                raw_declaration_and_sourcecode_info:    Ref( Null_Or( (raw::Declaration, sci::Sourcecode_Info)) ),

                module_dependencies_summary:            Ref( Null_Or(  mds::Declaration ) ),

                # The sharing_mode is an elaboration of sharing_request.
                # It must be persistent and gets properly recomputed
                # when there is a new sharing_request:

                sharing_mode:    Ref( shm::Mode ),

                get_compiledfile_version:    Void -> String,                            # Something like:  "version-$ROOT/src/app/makelib/(makelib-lib.lib):compilable/thawedlib-tome.pkg-1187780741.285"
                set_compiledfile_version:    String -> Void,                            # Reverse of previous.

                sourcefile_syntax: Sourcefile_Syntax                                    #  XXX BUGGO FIXME Do we need to be saving and restoring this in some pickling code somewhere? 
              };



        Thawedlib_Tome                                                                  # Named is for symmetry with   Frozenlib_Tome   from   src/app/makelib/freezefile/frozenlib-tome.pkg
          =
          #
          # This is our central record describing one .api or .pkg sourcefile.
          # This is also the main sumtype entrypoint into this file,
          # referenced in particular by THAWEDLIB_TOME in
          #
          #     src/app/makelib/depend/intra-library-dependency-graph.pkg
          #
          THAWEDLIB_TOME  {
            #
            sourcepath:                                 ad::File,                       # File containing source code which compiles to produce us.     
            make_module_dependencies_summaryfile_name:  Void -> String,                 # File in which we cache a brief summary of the source code.    
            make_compiledfile_name:                     Void -> String,                 # File to which we should write the generated .compiled binary -- normally "foo.pkg.compiled"  if input is "foo.pkg".
            #
            persistent_tome_info:   Persistent_Tome_Info,
            sharing_request:        shm::Request,
            attributes:             Attributes,
            #
            pre_compile_code:       Null_Or(String),                                    # 'tool' support: Mythryl source code to execute before compile.
            postcompile_code:       Null_Or(String),                                    # 'tool' support: Mythryl source code to execute after compile.
                                                                                        # See  compile_and_run_mythryl_codestring()  in  src/app/makelib/compile/compile-in-dependency-order-g.pkg
            is_local:               Bool,
            controllers:            List( Controller )
          };



        Key =  Thawedlib_Tome;

        stipulate
            generation = REF (REF ());                                                  # XXX BUGGO FIXME More icky buried global state preventing multithreading :(
        herein
            fun now ()
                =
                *generation;
            #
            fun new_generation ()
                =
                generation := REF ();
        end;


        fun make_compiledfile_name                      (THAWEDLIB_TOME t) =  t.make_compiledfile_name ();


        fun sourcepath_of                               (THAWEDLIB_TOME t) =  t.sourcepath;
        fun sharing_request_of                          (THAWEDLIB_TOME t) =  t.sharing_request;

        fun attributes_of                               (THAWEDLIB_TOME t) =  t.attributes;
        fun pre_compile_code_of                         (THAWEDLIB_TOME t) =  t.pre_compile_code;
        fun postcompile_code_of                         (THAWEDLIB_TOME t) =  t.postcompile_code;

        fun controllers_of                              (THAWEDLIB_TOME t) =  t.controllers;
        fun is_local                                    (THAWEDLIB_TOME t) =  t.is_local;
        fun module_dependencies_summaryfile_name_of     (THAWEDLIB_TOME t) =  t.make_module_dependencies_summaryfile_name ();

        #
        fun get_sharing_mode   (THAWEDLIB_TOME { persistent_tome_info => PERSISTENT_TOME_INFO { sharing_mode => REF m, ... }, ... } )
            =
            m;

        #
        fun set_sharing_mode   (THAWEDLIB_TOME { persistent_tome_info => PERSISTENT_TOME_INFO { sharing_mode,          ... }, ... },   m)
            =
            sharing_mode := m;

        #
        fun sourcefile_syntax_of (THAWEDLIB_TOME { persistent_tome_info => PERSISTENT_TOME_INFO { sourcefile_syntax,    ... }, ... } )
            =
            sourcefile_syntax;

        #
        fun gerror (makelib_state: mls::Makelib_State)
            =
            lsi::error makelib_state.library_source_index;

        #
        fun error makelib_state (THAWEDLIB_TOME { persistent_tome_info => PERSISTENT_TOME_INFO { library, ... }, ... } )
            =
            gerror makelib_state library;

        #
        fun group_of (THAWEDLIB_TOME { persistent_tome_info => PERSISTENT_TOME_INFO { library => (g, _), ... }, ... } )
            =
            g;

        #
        fun compare (THAWEDLIB_TOME { sourcepath => p, ... }, THAWEDLIB_TOME { sourcepath => p', ... } )
            =
            ad::compare (p, p');

        #
        fun same_thawedlib_tome (i, i')
            =
            compare (i, i') == EQUAL;

        #
        fun sourcefile_timestamp_of (THAWEDLIB_TOME { persistent_tome_info => PERSISTENT_TOME_INFO { sourcefile_timestamp, ... }, ... } )
            =
            *sourcefile_timestamp;


        # XXX BUGGO FIXME more thread-unsafe mutable global state:

        known_info                                              # XXX BUGGO FIXME There's got to be a more perspicuous name for than this. :(
            =
            REF (spm::empty:   spm::Map( Persistent_Tome_Info ));

        #
        fun is_known (THAWEDLIB_TOME { sourcepath, ... } )
            =
            not_null (spm::get (*known_info, sourcepath));

        #
        fun count_parse_trees ()
            =
            spm::fold_forward
                count_one
                0
                *known_info
            where
                fun count_one  (PERSISTENT_TOME_INFO { raw_declaration_and_sourcecode_info => REF (THE _), ... },  count)
                        =>
                        count + 1;

                    count_one (_, count) =>   count;
                end;
            end;
            #
            # Counting the trees explicitly may be a bit slow,
            # but maintaining an accurate count is difficult,
            # and this method is at least robust.  I don't think
            # that the overhead of counting will make a noticeable
            # difference.   -- Matthias Blume


        #
        fun forget_raw_declaration_and_sourcecode_info (THAWEDLIB_TOME { persistent_tome_info => PERSISTENT_TOME_INFO { raw_declaration_and_sourcecode_info, ... }, ... } )
            =
            raw_declaration_and_sourcecode_info
                :=
                NULL;

        #
        fun clean_library  now_built  g
            =
            {   n =   now ();
                #
                fun is_current (PERSISTENT_TOME_INFO { generation => REF gen, library => (g', _), ... } )
                    =
                    ((not now_built) and gen == n)
                    or
                    ad::compare (g, g') != EQUAL;

                known_info :=  spm::filter  is_current  *known_info;
            };

        #
        fun clear_state ()
            =
            known_info :=  spm::empty;



        # Check timestamp and throw away any invalid cache:
        #
        fun validate (sourcepath, PERSISTENT_TOME_INFO persistent_tome_info)
            =
            {   # We avoid using  the "..." pattern here
                # so as to have the compiler flag additions
                # to the type via a compile error message:
                #
                persistent_tome_info
                    ->
                   { library,
                     sourcefile_timestamp,
                     raw_declaration_and_sourcecode_info,
                     module_dependencies_summary,
                     sharing_mode,
                     generation,
                     get_compiledfile_version,
                     set_compiledfile_version,
                     sourcefile_syntax
                    };

                timestamp =   *sourcefile_timestamp;

                new_timestamp =   ad::timestamp sourcepath;

                if  (ts::needs_update {
                         source => new_timestamp,
                         target => timestamp
                     }
                )
                     sourcefile_timestamp
                         :=
                         new_timestamp;

                     generation :=   now ();

                     raw_declaration_and_sourcecode_info
                        :=
                        NULL;

                     module_dependencies_summary   := NULL;
                fi;
            };
                                                    # timestamp         is from   src/app/makelib/paths/timestamp.pkg


        # Construct and return a THAWEDLIB_TOME record
        # for a given .api or .pkg file.  (This record
        # is our primary internal representative for
        # a file which is being -- or has been -- compiled.)
        #
        # This function is called directly from "fun sml" in
        #     src/app/makelib/mythryl-compiler-compiler/process-mythryl-primordial-library.pkg
        # We also get called via our below "fun make_thawedlib_tome" wrapper from
        # fun smlfile_collections in
        #     src/app/makelib/stuff/raw-libfile.pkg
        #
        fun make_thawedlib_tome'
                attributes
                (makelib_state: mls::Makelib_State)
                arg
            =
            THAWEDLIB_TOME
              {
                sourcepath,                             # File containing source code which compiles to produce .compiled in question.  
                make_module_dependencies_summaryfile_name,
                make_compiledfile_name,
                #
                persistent_tome_info =>  get_or_make_persistent_tome_info (),
                sharing_request,
                #
                attributes,
                pre_compile_code,               # Arbitrary code to execute before compiling this file.
                postcompile_code,               # Arbitrary code to execute after  compiling this file.
                is_local,
                #
                controllers
              }
            where
                arg ->
                    { library => gr as (library, source_code_region),
                      sourcepath,                       # File containing source code which compiles to produce .compiled in question.  
                      sharing_request,
                      pre_compile_code,                 # Random code to execute before compiling this file.
                      postcompile_code,                 # Random code to execute after  compiling this file.
                      is_local,
                      controllers
                    };

                policy =   makelib_state.makelib_session.filename_policy;
                #
                fun make_module_dependencies_summaryfile_name () =   fp::make_module_dependencies_summaryfile_name  policy  sourcepath;
                fun make_compiledfile_name                    () =   fp::make_compiledfile_name                     policy  sourcepath;
                fun make_versionfile_name                     () =   fp::make_versionfile_name                      policy  sourcepath;

                library_source_index
                    =
                    makelib_state.library_source_index;



                # NB:  The 'noguid' attribute appears to default to FALSE
                #      and to be set to TRUE by c-glue-maker, and to be
                #      almost entirely undocumented.  The below 'if' appears
                #      to be the only place it is tested and used:
                #
                my (get_compiledfile_version, set_compiledfile_version)
                    =
                    if attributes.noguid                                        # So apparently 'noguid' means "Don't use compiledfile versions", implying "guid" == "globally unique identifier"(presumably) == compiledfile version. 
                        #
                        ( \\ () =  "",
                          \\ _  =  ()
                        );
                    else
                        (get_compiledfile_version, set_compiledfile_version)
                        where 

                            compiledfile_version_cache =   REF NULL;            # Or (say)  (THE "version-$ROOT/src/app/makelib/(makelib-lib.lib):compilable/thawedlib-tome.pkg-1187780741.285")

                            #
                            fun version_string_from_compiled_file ()
                                =
                                # Return NULL immediately if file is unreadable.
                                # This isn't strictly necessary, but avoids
                                # generating background failed-to-open-file
                                # errors that can be distracting when debugging:
                                #
                                {   filename =  make_compiledfile_name ();

                                    if (not (wnx::file::access (filename, [wnx::file::MAY_READ])))
                                        #
                                        NULL;
                                    else
                                        safely::do
                                            {
                                              open_it  =>  {. bio::open_for_read  filename; },
                                              close_it =>  bio::close_input,
                                              cleanup  =>  \\ _ = ()
                                            }
                                            (THE o cf::read_version)
                                        except
                                            iox::IO _ =  NULL;
                                    fi;
                                };

                                                                   # compiledfile       is from   src/lib/compiler/execution/compiledfile/compiledfile.pkg
                            #
                            fun version_string_from_version_file ()
                                =
                                {   filename =   make_versionfile_name ();

                                    # Return NULL immediately if file is unreadable.
                                    # This isn't strictly necessary, but avoids
                                    # generating background failed-to-open-file
                                    # errors that can be distracting when debugging:
                                    #
                                    if (not (wnx::file::access (filename, [wnx::file::MAY_READ])))
                                        #
                                        NULL;
                                    else
                                        safely::do
                                            {
                                              open_it  =>  {. fil::open_for_read filename; },
                                              close_it =>  fil::close_input,
                                              cleanup  =>  \\ _ = ()
                                            }
                                            (THE o fil::read_all)
                                        except                  # file__premicrothread  is from   src/lib/std/src/posix/file--premicrothread.pkg
                                            iox::IO _ =  NULL;
                                    fi;
                                };      

                            #
                            fun set_compiledfile_version  compiledfile_version_string
                                =
                                {   compiledfile_version_cache :=  THE compiledfile_version_string;
                                    #
                                    write_to_versionfile  compiledfile_version_string
                                    where
                                        fun write_to_versionfile  compiledfile_version_string           # Say, "version-$ROOT/src/app/makelib/(makelib-lib.lib):compilable/thawedlib-tome.pkg-1187780741.285"
                                            =
                                            {   version_filename                # For            src/app/makelib/compilable/thawedlib-tome.pkg
                                                    =                           # this will be   src/app/makelib/compilable/thawedlib-tome.pkg.version
                                                    make_versionfile_name ();

                                                safely::do
                                                    {
                                                      open_it  =>  {. autodir::open_text_output  version_filename; },
                                                      close_it =>  fil::close_output,
                                                      cleanup  =>  \\ _ =  wnx::file::remove_file  version_filename
                                                    }
                                                    {. fil::write (#s, compiledfile_version_string); };
                                            };
                                    end;
                                };

                            #
                            fun save_compiledfile_version  compiledfile_version_string
                                =
                                {   set_compiledfile_version  compiledfile_version_string;
                                    #
                                    compiledfile_version_string;
                                };


                            # Try successively up to four ways of obtaining
                            # the version string for our .compiled file:
                            #  o Cached in our version_cache variable;
                            #  o Stored in the .compiled file itself;
                            #  o Stored in the .version file;
                            #  o Create a new one from scratch.  
                            #
           # XXX BUGGO DELETEME This 'version' game is not worth the code complexity candle -- it should all be ripped out. 2007-11-03 CrT
                            fun get_compiledfile_version ()
                                =
                                {   # Create a version string.  This will look like
                                    #     "version-$ROOT/src/app/makelib/(makelib-lib.lib):compilable/thawedlib-tome.pkg-1187780741.285"

                                    # XXX BUGGO FIXME This should probably be in a separate version-string.pkg or such.
                                    # XXX BUGGO FIXME We apparently just assume no two compiles of the same source
                                    #                 can complete at the same millisecond.  With parallel compiles
                                    #                 in different processes on on multicore machines and such, this
                                    #                 may not be true -- some sort of explicit file locking or such is probably needed.
                                    #
                                    fun make_compiledfile_version_string ()     # XXX BUGGO DELETEME This 'version' game is not worth the code complexity candle -- it should all be ripped out. 2007-11-03 CrT
                                        =
                                        cat [     "version-",
   #                                           ad::describe sourcepath,         # sourcepath was in "fun make_thawedlib_tome'"'s 'arg' argument, above.
   #                                           "-",
   #                                           ts::to_string(   ad::timestamp sourcepath ),
   #                                           time::to_string (time::now ()),  # Matthias had this, which screws up 'make fixpoint', so I substituted the above. I don't understand what the point of all this is, however, so that might be bad. XXX BUGGO FIXME
                                                  "\n"
                                               ];

                                                                   # time       is from   src/lib/std/time.pkg
                                    case *compiledfile_version_cache
                                        #
                                        THE compiledfile_version_string =>   compiledfile_version_string;
                                        #
                                        NULL =>
                                            case (version_string_from_compiled_file ())
                                                #
                                                THE compiledfile_version_string
                                                    =>
                                                    save_compiledfile_version  compiledfile_version_string;
                                                #
                                                NULL =>
                                                    case (version_string_from_version_file ())
                                                        #
                                                        THE compiledfile_version_string =>   compiledfile_version_string;
                                                        NULL                            =>   save_compiledfile_version (make_compiledfile_version_string ());
                                                    esac;
                                            esac;
                                    esac;
                                };
                        end;
                    fi;



                # Our syntactic scope at this point is within the     fun make_thawedlib_tome'   definition code block.


                #
                fun make_persistent_tome_info ()
                    =
                    persistent_tome_info
                    where 

                        timestamp =   ad::timestamp  sourcepath;                # sourcepath was in "fun make'"'s 'arg' argument, above.
                        filename  =   ad::os_string'  sourcepath; 

                        sourcefile_syntax
                            = 
                            if   (string::is_suffix ".pkg7" filename)   NADA;
                            elif (string::is_suffix ".api7" filename)   NADA;
                            else                                        MYTHRYL;
                            fi;

                                                                            # string    is from   src/lib/std/string.pkg

                        persistent_tome_info
                            =
                            PERSISTENT_TOME_INFO
                              {
                                sourcefile_timestamp    =>   REF timestamp,
                                library                 =>  gr,
                                #
                                raw_declaration_and_sourcecode_info     =>  REF NULL,
                                module_dependencies_summary             =>  REF NULL,
                                
                                sharing_mode =>  REF (shm::SHARE FALSE),
                                generation   =>  REF (now ()),

                                set_compiledfile_version,
                                get_compiledfile_version,

                                sourcefile_syntax
                              };


                        known_info
                            :=
                            spm::set
                                (*known_info, sourcepath, persistent_tome_info);
                    end;

                #
                fun get_or_make_persistent_tome_info ()
                    =
                    case (spm::get  (*known_info,  sourcepath))
                        #
                        NULL =>   make_persistent_tome_info ();
                        #
                        THE (persistent_tome_info as PERSISTENT_TOME_INFO { library => gr' as (g, r), generation, ... } )
                            =>
                            if (ad::compare (library, g) == EQUAL)
                                #
                                validate (sourcepath, persistent_tome_info);
                                persistent_tome_info;
                            else
                                n =   ad::describe sourcepath;

                                if (*generation == now ())
                                    #   
                                    gerror makelib_state gr err::ERROR
                                       (cat ["Source file ", n,
                                                " appears in more than one library"])
                                       err::null_error_body;
                                    #   
                                    gerror makelib_state gr' err::ERROR
                                       (cat ["(previous occurence of ", n, ")"])
                                       err::null_error_body;

                                else
                                    gerror makelib_state gr err::WARNING
                                       (cat ["Source file ", n,
                                                " has switched libraries"])
                                       err::null_error_body;
                                fi;

                                make_persistent_tome_info ();
                            fi;
                    esac;
            end;                              #  fun make_thawedlib_tome' 


        # This function seems to mainly be called from
        # fun smlfile_collections in
        #   src/app/makelib/stuff/raw-libfile.pkg
        #
        fun make_thawedlib_tome (crossmodule_inlining_aggressiveness, noguid)
            =
            make_thawedlib_tome'
              {
                extra_static_compile_dictionary         =>  NULL,
                is_runtime_package                      =>  FALSE,
                explicit_core_symbol                    =>  NULL,
                crossmodule_inlining_aggressiveness,
                noguid
              };



        # The following functions are only
        # concerned with getting the data,
        # not with checking time stamps:
        #
        fun get_parsetree
                #
                makelib_state
                #
                { thawedlib_tome   as   THAWEDLIB_TOME tome_record,             # XXX BUGGO FIXME this should be a record not a tuple, for readability
                  quiet,
                  unparse_info
                }
            = 
            {   tome_record
                    ->
                    { persistent_tome_info =>   PERSISTENT_TOME_INFO { raw_declaration_and_sourcecode_info, sourcefile_syntax, ... },
                      sourcepath,
                      controllers,
                      ...
                    };
                #
                fun err m
                    =
                    error  makelib_state  thawedlib_tome  err::ERROR  m  err::null_error_body;
                #
                case *raw_declaration_and_sourcecode_info
                    #         
                    THE raw_declaration_and_sourcecode_info  =>
                    THE raw_declaration_and_sourcecode_info;
                    #
                    NULL =>
                        {   previous_controller_settings                                        # Save states of our controllers as a list of thunks; evaluating those thunks will restore the original controller states.
                                =
                                map (\\ controller =  controller.save_controller_state ())
                                    controllers;
                            #
                            fun parse_sourcefile  source_stream
                                =
                                {
if (mld::debug.get ())     printf "thawedlib-tome: parse_sourcefile(%s)/TOP     [makelib::debug]\n" (ad::os_string' sourcepath);        fi;
                                    if (not quiet)
                                        #
                                        fil::say {.
                                            cat [
                                                "                      thawedlib-tome.pkg:   Parsing   source file   ",
                                                ad::os_string' sourcepath
                                            ];
                                        };
                                    fi;


                                    # XXX BUGGO DELETEME this is temporary codebase conversion infrastructure
                                    #
                                    if *mp::log_edit_requests
                                        #
                                        filename =  cat [  ad::os_string'  sourcepath,
                                                            ".EDIT_REQUESTS"
                                                        ];

                                        stream =   fil::open_for_write  filename;

                                        mp::edit_request_stream
                                            :=
                                            THE stream;
                                    fi;

                                    sourcecode_info
                                        =       
                                        sci::make_sourcecode_info
                                          {
                                            file_name      =>  ad::os_string'  sourcepath,
                                            line_num       =>  1,
                                            source_stream,
                                            is_interactive =>  FALSE,
                                            error_consumer =>  makelib_state.plaint_sink
                                          };


                                    apply
                                        (\\ c =  c.set ())
                                        controllers;


                                    # If unparse_info is not NULL, we also
                                    # prettyprint the parsetree to a diskfile:
                                    #
                                    case unparse_info
                                        #
                                        NULL =>
                                          (
                                            case sourcefile_syntax
                                                #
                                                MYTHRYL =>  pm::parse_complete_mythryl_file  sourcecode_info;
                                                NADA    =>  pn::parse_complete_nada_file     sourcecode_info;
                                            esac,

                                            sourcecode_info
                                          )
                                          then
                                              apply
                                                  (\\ r =  r ())
                                                  previous_controller_settings;

                                        (THE (symbolmapstack, unparse_generic))
                                            =>
                                            result
                                            where 
                                                result
                                                  =
                                                  ( case sourcefile_syntax
                                                        #
                                                        MYTHRYL =>  pm::parse_complete_mythryl_file  sourcecode_info;
                                                        NADA    =>  pn::parse_complete_nada_file     sourcecode_info;
                                                    esac,

                                                    sourcecode_info
                                                  )
                                                  then
                                                      apply
                                                          (\\ r =  r ())
                                                          previous_controller_settings;


                                                raw_syntax_tree    =   #1 result;
                                                unparse_filename   =   cat [ ad::os_string'  sourcepath,   ".PRETTY_PRINT" ];
                                                unparse_textstream =   fil::open_for_write  unparse_filename; 

                                                output_stream
                                                  =
                                                  { consumer  =>  (\\ string =  fil::write  (unparse_textstream,  string)),
                                                    flush     =>  {. fil::flush         unparse_textstream; },
                                                    close         =>  {. fil::close_output  unparse_textstream; }
                                                  };


                                                prettyprinter =   pp::make_prettyprinter  output_stream  [];

                                                unparse_generic
                                                    (symbolmapstack, NULL)
                                                    prettyprinter
                                                    ( raw_syntax_tree,
                                                      1000                  # Arbitrary large output device width
                                                    );

                                                pp::flush_prettyprinter   prettyprinter;

                                                fil::flush         unparse_textstream;

                                                fil::close_output  unparse_textstream;
                                            end;
                                    esac

                                    # XXX BUGGO DELETEME this is temporary codebase conversion infrastructure
                                    then
                                        case *mp::edit_request_stream
                                            #
                                            NULL => ();
                                            #
                                            THE stream
                                                =>
                                                {   fil::flush         stream;
                                                    fil::close_output  stream;

                                                    mp::edit_request_stream
                                                        :=
                                                        NULL;
                                                };
                                        esac;


                                };                                              # fun parse_sourcefile
                            #
                            fun open_it ()
                                =
                                fil::open_for_read  (ad::os_string  sourcepath);
                            #
                            fun cleanup _
                                =
                                apply  (\\ r =  r ())  previous_controller_settings;

                            optional_parsetree
                                =
                                THE (
                                    safely::do {
                                      open_it,
                                      cleanup,
                                      close_it =>  fil::close_input
                                    }
                                    parse_sourcefile
                                );

                            ntrees =     count_parse_trees ();

                            treelimit =  mld::parse_caching.get ();

                            if (ntrees < treelimit)
                                #       
                                raw_declaration_and_sourcecode_info
                                    :=
                                    optional_parsetree;
                            fi;

                            optional_parsetree;

                        }
                        except
                            exn as iox::IO _
                                =>
                                {   err (exceptions::exception_message  exn);
                                    NULL;
                                };

                           compilation_exception::COMPILE msg
                               =>
                               {   err  msg;
                                   NULL;
                               };
                        end;
                   esac;
            };                                             #  fun get_parsetree 
        #
        fun module_dependencies_summary makelib_state (i as THAWEDLIB_TOME tome_record)
            =
            {   tome_record
                    ->
                    { sourcepath,
                      make_module_dependencies_summaryfile_name,
                      persistent_tome_info => PERSISTENT_TOME_INFO  persistent_tome_info_record,
                      ...
                    };


                persistent_tome_info_record
                    ->
                    { module_dependencies_summary,
                      sourcefile_timestamp,
                      ...
                    };

                #
                case *module_dependencies_summary
                    #         
                    THE module_dependencies_summary  =>
                    THE module_dependencies_summary;
                    #
                    NULL =>
                        {   module_dependencies_summaryfile_name
                                =
                                make_module_dependencies_summaryfile_name ();

                                                                                                          # module_dependencies_summary_io      is from   src/app/makelib/compilable/module-dependencies-summary-io.pkg
                            #
                            case (module_dependencies_summary_io::read  (module_dependencies_summaryfile_name,  *sourcefile_timestamp))
                                #
                                THE module_dependencies_summary'
                                    =>
                                    {   module_dependencies_summary := THE module_dependencies_summary';
                                        THE module_dependencies_summary';
                                    };
                                #
                                NULL =>
                                    case (get_parsetree
                                              #
                                              makelib_state
                                              #
                                              { thawedlib_tome =>  i,
                                                quiet          =>  FALSE,
                                                unparse_info   =>  NULL
                                              }
                                         )
                                        #
                                        NULL => NULL;
                                        #
                                        THE (tree, source)
                                            =>
                                            {   fun err  sv  source_code_region  s
                                                    =
                                                    err::error  source  source_code_region  sv  s  err::null_error_body;

                                                                                                        # raw_syntax_to_module_dependencies_summary     is from   src/app/makelib/compilable/raw-syntax-to-module-dependencies-summary.pkg
                                                                                                        # module_dependencies_summary_io                is from   src/app/makelib/compilable/module-dependencies-summary-io.pkg

                                                my  {   module_dependencies_summary => module_dependencies_summary',
                                                        complain
                                                    }
                                                    =
                                                    raw_syntax_to_module_dependencies_summary::convert
                                                      {
                                                        tree,
                                                        err
                                                      };


                                                complain ();

                                                if (err::saw_errors  (err::errors  source))
                                                    #
                                                    error makelib_state  i  err::ERROR
                                                         "error (s) in source file"
                                                         err::null_error_body;
                                                else
                                                    module_dependencies_summary_io::write
                                                        (module_dependencies_summaryfile_name,  module_dependencies_summary',  *sourcefile_timestamp);

                                                    module_dependencies_summary
                                                        :=
                                                        THE  module_dependencies_summary' ;
                                                fi;

                                                THE  module_dependencies_summary' ;
                                            };
                                    esac;
                            esac;
                        };
                 esac;
            };



        #  We only complain at the time of getting the exports: 
        #
        fun exports  makelib_state  i
            =
            null_or::map
                get_toplevel_module_dependencies_summary_exports::get_toplevel_module_dependencies_summary_exports
                (module_dependencies_summary makelib_state  i);

                                                                        # null_or                                               is from   src/lib/std/src/null-or.pkg
                                                                        # get_toplevel_module_dependencies_summary_exports      is from   src/app/makelib/compilable/get-toplevel-module-dependencies-summary-exports.pkg

        # Return the raw parsetree for this file.
        # We get it from in-memory cache if possible,
        # otherwise we read and parse the source file.
        #
        fun find_raw_declaration_and_sourcecode_info                            # Called (only) from                                            src/app/makelib/compile/compile-in-dependency-order-g.pkg
                #
                makelib_state
                unparse_info                                            # NULL or top-level compiler symbol table plus prettyprint fn.
                thawedlib_tome                                          # Has all info on the file, including sourcefile name.
            #
            :   Null_Or( (raw::Declaration, sci::Sourcecode_Info) )
            =
            get_parsetree
                #
                makelib_state
                #
                { thawedlib_tome,
                  quiet =>  TRUE,
                  unparse_info
                };

        #
        fun describe_thawedlib_tome (THAWEDLIB_TOME { sourcepath, ... } )               # Something like   "src/lib/reactive/(reactive.lib):reactive.pkg"   or   "src/lib/x-kit/(xkit.lib):xclient/(xclient.sublib):(xclient-internals.sublib):src/color/rgb.pkg"
                =
                ad::describe sourcepath;

        #
        fun error_location (makelib_state: mls::Makelib_State) (THAWEDLIB_TOME info)
            =
            {   info
                    ->
                    { persistent_tome_info => PERSISTENT_TOME_INFO { library => (library, reg), ... }, ... };

                err::match_error_string
                    (lsi::look_up  makelib_state.library_source_index  library)
                    reg;
            };

        #
        fun get_compiledfile_version (THAWEDLIB_TOME { persistent_tome_info => PERSISTENT_TOME_INFO { get_compiledfile_version, ... }, ... } )
            =
            get_compiledfile_version ();

        #
        fun set_compiledfile_version (THAWEDLIB_TOME { persistent_tome_info => PERSISTENT_TOME_INFO { set_compiledfile_version, ... }, ... }, compiledfile_version)
            =
            set_compiledfile_version  compiledfile_version;
    };
end;

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


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext