## raw-libfile.pkg
#
# The library representation used while actually parsing a file
#
# foo.lib
#
# This is only used in
#
#
src/app/makelib/parse/libfile-grammar-actions.pkg#
# This is an emphemeral form used while we are constructing the usual
# library dependency graph representation defined in:
#
#
src/app/makelib/depend/inter-library-dependency-graph.pkg#
src/app/makelib/depend/intra-library-dependency-graph.pkg# Compiled by:
#
src/app/makelib/makelib.sublib# Involves:
# - running tools
# - fully analyzing sub-libraries and sub-freezefiles
# - parsing source files and getting their export lists
stipulate
package ad = anchor_dictionary; # anchor_dictionary is from
src/app/makelib/paths/anchor-dictionary.pkg package err = error_message; # error_message is from
src/lib/compiler/front/basics/errormsg/error-message.pkg package lg = inter_library_dependency_graph; # inter_library_dependency_graph is from
src/app/makelib/depend/inter-library-dependency-graph.pkg package lnd = line_number_db; # line_number_db is from
src/lib/compiler/front/basics/source/line-number-db.pkg package lsi = library_source_index; # library_source_index is from
src/app/makelib/stuff/library-source-index.pkg package mdg = make_dependency_graph; # make_dependency_graph is from
src/app/makelib/depend/make-dependency-graph.pkg package ms = makelib_state; # makelib_state is from
src/app/makelib/main/makelib-state.pkg package mvi = makelib_version_intlist; # makelib_version_intlist is from
src/app/makelib/stuff/makelib-version-intlist.pkg package pmt = private_makelib_tools; # private_makelib_tools is from
src/app/makelib/tools/main/private-makelib-tools.pkg package sg = intra_library_dependency_graph; # intra_library_dependency_graph is from
src/app/makelib/depend/intra-library-dependency-graph.pkg package sm = symbol_map; # symbol_map is from
src/app/makelib/stuff/symbol-map.pkg package spm = source_path_map; # source_path_map is from
src/app/makelib/paths/source-path-map.pkg package sts = string_set; # string_set is from
src/lib/src/string-set.pkg package sy = symbol; # symbol is from
src/lib/compiler/front/basics/map/symbol.pkg package sys = symbol_set; # symbol_set is from
src/app/makelib/stuff/symbol-set.pkg package tlt = thawedlib_tome; # thawedlib_tome is from
src/app/makelib/compilable/thawedlib-tome.pkg package tst = tome_symbolmapstack; # tome_symbolmapstack is from
src/app/makelib/depend/tome-symbolmapstack.pkg package wsf = write_symbol_index_file; # write_symbol_index_file is from
src/app/makelib/depend/write-symbol-index-file.pkgherein
# We are referenced (only) in
#
#
src/app/makelib/parse/libfile-grammar-actions.pkg package raw_libfile
: Raw_Libfile # Raw_Libfile is from
src/app/makelib/stuff/raw-libfile.api {
Sublibraries
=
List( (
ad::File,
lg::Inter_Library_Dependency_Graph
, ad::Renamings # MUSTDIE
) );
Libfile
#
= LIBFILE
{
imports: sm::Map( lg::Fat_Tome ),
masked_tomes: List( (tlt::Thawedlib_Tome, sys::Set) ), # (tome, exported_symbols_set) pairs.
localdefs: sm::Map( tlt::Thawedlib_Tome ),
#
sublibraries: Sublibraries,
sources: spm::Map { ilk: String, derived: Bool }
}
#
| ERROR_LIBFILE
;
fun empty sources
=
LIBFILE
{
imports => sm::empty,
masked_tomes => [], # (tome, exported_symbols_set) pairs.
localdefs => sm::empty,
#
sublibraries => [],
sources
};
empty_libfile
=
empty spm::empty;
fun make_primordial_libfile (makelib_state: ms::Makelib_State) primordial_library
=
{ my { libfile => primordial_libfile, ... }
=
case primordial_library
#
lg::LIBRARY x => x;
lg::BAD_LIBRARY => err::impossible "raw-libfile.pkg: implicit: bad init.cmi primordial library";
esac;
sm = spm::singleton (primordial_libfile, { ilk => "cm", derived => FALSE } );
# This libfile is an implicit member
# of every library -- the "init" library
# which exports the pervasive dictionary:
LIBFILE
{
imports => sm::empty,
masked_tomes => [], # (tome, exported_symbols_set) pairs.
localdefs => sm::empty,
#
sources => sm,
#
sublibraries => [ ( primordial_libfile,
primordial_library
, [] # MUSTDIE
)
]
};
};
fun sequential ( LIBFILE c1,
LIBFILE c2,
error
)
=>
{ fun describe_symbol (s, r)
=
{ ns = sy::name_space s;
#
sy::name_space_to_string ns ! " " ! sy::name s ! r;
};
fun import_error
( s,
x as { masked_tome_thunk, tome_symbolmapstack, exports_mask }: lg::Fat_Tome,
y as { masked_tome_thunk => masked_tome_thunk', tome_symbolmapstack => tome_symbolmapstack', exports_mask => exports_mask' }: lg::Fat_Tome # 'y' is unused, present only for symmetry with x.
)
=
{ (masked_tome_thunk ()) -> { exports_mask => f, tome_tin => tome_tin };
(masked_tome_thunk' ()) -> { exports_mask => f', tome_tin => tome_tin' };
fun gripe ()
=
error (cat (describe_symbol
(s, [" imported from ",
sg::describe_tome tome_tin,
" and also from ",
sg::describe_tome tome_tin']
) ) );
fun union (NULL, _) => NULL;
union (_, NULL) => NULL;
#
union (THE f, THE f')
=>
THE (sys::union (f, f'));
end;
if (sg::same_tome_tin (tome_tin, tome_tin'))
#
masked_tome = { exports_mask => union (f, f'), tome_tin };
#
{ masked_tome_thunk => {. masked_tome; },
tome_symbolmapstack => tst::LAYER (tome_symbolmapstack, tome_symbolmapstack' ),
exports_mask => sys::union (exports_mask, exports_mask' )
}: lg::Fat_Tome;
else
gripe ();
x;
fi;
};
import_union
=
sm::keyed_union_with import_error;
fun local_def_error (s, f1, f2)
=
{ error (cat (describe_symbol
(s, [" defined in ", tlt::describe_thawedlib_tome f1,
" and also in ", tlt::describe_thawedlib_tome f2])));
f1;
};
local_def_union
=
sm::keyed_union_with local_def_error;
source_path_union
=
spm::union_with #1;
LIBFILE
{
imports => import_union (c1.imports, c2.imports),
masked_tomes => c1.masked_tomes @ c2.masked_tomes, # (tome, exported_symbols_set) pairs.
localdefs => local_def_union (c1.localdefs, c2.localdefs),
#
sublibraries => c1.sublibraries @ c2.sublibraries,
sources => source_path_union (c1.sources, c2.sources)
};
};
sequential (ERROR_LIBFILE, _, _) => ERROR_LIBFILE;
sequential (_, ERROR_LIBFILE, _) => ERROR_LIBFILE;
end; # fun sequential
# Generate a Libfile from something or another.
#
# We're called in just one place, member() in
#
# ./libfile-grammar-actions.pkg
#
fun expand_one
{ makelib_state,
recursive_parse,
load_plugin
}
#
{ name: String,
make_path: Void -> ad::Dir_Path,
library: (ad::File, lnd::Source_Code_Region),
ilk: Null_Or( String ),
tool_options: Null_Or( pmt::Tool_Options ),
local_index: pmt::Index,
path_root: ad::Path_Root
}
=
{ ilk = null_or::map (string::map char::to_lower) ilk;
error = lsi::error
makelib_state.library_source_index
library;
fun error0 s
=
error err::ERROR s err::null_error_body;
fun warn0 s
=
error err::WARNING s err::null_error_body;
my { source_files, makelib_files, sources }
=
pmt::expand
{
local_index,
error => error0,
spec => { name,
make_path,
ilk,
tool_options,
derived => FALSE
},
path_root,
load_plugin,
sysinfo => { get_makelib_preprocessor_symbol_value => \\ string = (makelib_state.makelib_session.find_makelib_preprocessor_symbol string).get (),
platform => makelib_state.makelib_session.platform
}
};
msources
=
fold_forward
spm::set'
spm::empty
sources;
fun makefile_libfiles (p, { version => v
, renamings => rb # MUSTDIE
}
)
=
case (recursive_parse
( p,
v
, rb # MUSTDIE
))
g as lg::LIBRARY { catalog => i, sources, libfile, sublibraries, more }
=>
{ makelib_version_intlist # Defined in
src/app/makelib/stuff/makelib-version-intlist.pkg =
case more
#
lg::SUBLIBRARY _ => NULL;
lg::MAIN_LIBRARY l => l.makelib_version_intlist;
esac;
case (v, makelib_version_intlist)
(NULL,NULL) => (); # printf "src/app/makelib/stuff/raw-libfile.pkg: (NULL,NULL) case\n";
(NULL,_ ) => printf "src/app/makelib/stuff/raw-libfile.pkg: (NULL,_ ) case\n";
(_ ,NULL) => printf "src/app/makelib/stuff/raw-libfile.pkg: (_ ,NULL) case\n";
(_ ,_ ) => printf "src/app/makelib/stuff/raw-libfile.pkg: (_ ,_ ) case\n";
esac;
case (v, makelib_version_intlist)
#
(NULL, _) => ();
#
(THE vrq, NULL)
=>
error0 "library does not carry a version stamp";
#
(THE vrq, THE ver)
=>
case (mvi::compare (vrq, ver))
#
GREATER => error0 "library is older than expected";
EQUAL => ();
LESS => case (mvi::compare (mvi::next_major vrq, ver))
#
GREATER => warn0 "library is slightly newer than expected";
_ => error0 "library is newer than expected";
esac;
esac;
esac;
LIBFILE
{
imports => i,
masked_tomes => [], # (tome, exported_symbols_set) pairs.
localdefs => sm::empty,
sources => spm::empty,
#
sublibraries => [ ( p,
g
, rb # MUSTDIE
)
]
};
};
lg::BAD_LIBRARY
=>
ERROR_LIBFILE;
esac;
fun smlfile_libfiles (p, sparams)
=
{ sparams -> { share, pre_compile_code, postcompile_code, split, noguid, is_local, controllers };
thawedlib_tome
=
tlt::make_thawedlib_tome
#
(split, noguid)
#
makelib_state
{
sourcepath => p,
library,
sharing_request => share,
pre_compile_code,
postcompile_code,
is_local,
controllers
};
exports
=
case (tlt::exports makelib_state thawedlib_tome)
#
NULL => sys::empty;
#
THE ex => ex
where
if (sys::is_empty ex)
#
error0 ("no module exports from " + ad::describe p);
fi;
end;
esac;
fun add_ld (s, m)
=
sm::set (m, s, thawedlib_tome);
localdefs = sys::fold_forward add_ld sm::empty exports;
if (sys::is_empty exports)
#
ERROR_LIBFILE;
else
LIBFILE
{
imports => sm::empty,
masked_tomes => [ (thawedlib_tome, exports) ], # (tome, exported_symbols_set) pairs.
localdefs,
#
sublibraries => [],
sources => spm::empty
};
fi;
};
libfiles
=
map makefile_libfiles makelib_files
@
map smlfile_libfiles source_files;
fun combine (c1, c2)
=
sequential (c2, c1, error0);
fold_forward combine (empty msources) libfiles;
};
# Invoked from:
# make_sublibrary
# make_main_library
# in
#
src/app/makelib/parse/libfile-grammar-actions.pkg #
fun make_libfile
(
g: ad::File,
LIBFILE c,
filter: sys::Set,
makelib_state: ms::Makelib_State,
pervasive_fsbnode: sg::Masked_Tome
)
=>
if (lsi::saw_errors makelib_state.library_source_index g)
#
{ exports => sm::empty,
imported_symbols => sys::empty
};
else
mdg::make_dependency_graph (c, filter, makelib_state, pervasive_fsbnode);
fi;
make_libfile (_, ERROR_LIBFILE, _, _, _)
=>
{ exports => sm::empty,
imported_symbols => sys::empty
};
end;
fun make_index (makelib_state, libfile, LIBFILE c)
=>
wsf::write_symbol_index_file (makelib_state, libfile, c);
make_index _ => ();
end;
fun sublibraries (LIBFILE { sublibraries => sg, ... } )
=>
sg;
sublibraries ERROR_LIBFILE => [];
end;
fun sources (LIBFILE { sources => s, ... } )
=>
s;
sources ERROR_LIBFILE => spm::empty;
end;
stipulate
fun get_hostprop (makelib_state: ms::Makelib_State) (lf: Libfile) (symbol_name: String)
=
(makelib_state.makelib_session.find_makelib_preprocessor_symbol symbol_name).get ();
herein
fun num_find makelib_state (libfile: Libfile) (string: String) = the_else (get_hostprop makelib_state libfile string, 0);
fun is_defined_hostproperty makelib_state (libfile: Libfile) (string: String) = not_null (get_hostprop makelib_state libfile string);
end;
fun ml_find (LIBFILE { imports, localdefs, ... } ) s
=>
not_null (sm::get (imports, s))
or
not_null (sm::get (localdefs, s));
ml_find ERROR_LIBFILE _ => TRUE;
end;
# Return symbol_set of all symbols exported
# by one or all .api and .pkg files in libfile:
#
fun api_or_pkg_exported_symbols (LIBFILE { masked_tomes, ... }, NULL, _)
=>
# Return set-union of exported symbols from all files
# in libfile which have is_local flag set FALSE:
#
fold_forward
(\\ ((tome: tlt::Thawedlib_Tome, symbols), symbols')
=
if (tlt::is_local tome) symbols';
else sys::union (symbols, symbols');
fi
)
sys::empty
masked_tomes; # (tome, exported_symbols_set) pairs.
api_or_pkg_exported_symbols (LIBFILE { masked_tomes, ... }, THE (sourcefile: ad::File), error)
=>
# Return set of exported symbols from 'sourcefile':
#
case (list::find same_tome masked_tomes)
#
THE (_, exported_symbols) => exported_symbols;
NULL => { error ("no such source file: " + ad::describe sourcefile); sys::empty; };
esac
where
fun same_tome (tome: tlt::Thawedlib_Tome, exported_symbols: sys::Set)
=
ad::compare (tlt::sourcepath_of tome, sourcefile) == EQUAL;
end;
api_or_pkg_exported_symbols (ERROR_LIBFILE, _, _)
=>
sys::empty;
end;
stipulate
fun same_path_as p (p', _ # Compare ad::File values for equality. (We need a curried version usable with list::find.)
, _ # MUSTDIE
)
=
ad::compare (p, p') == EQUAL;
fun add_domain (symbol_map, symbol_set) # Add keys from 'symbol_map' to 'symbol_set', return result.
=
sys::add_list (symbol_set, sm::keys_list symbol_map);
fun domain_of symbol_map # Return keys of 'symbol_map' as a sys::Set.
=
add_domain (symbol_map, sys::empty);
herein
# Return set of symbols exported by given_freezefile:
#
fun freezefile_exports (LIBFILE { sublibraries, ... }, given_freezefile: ad::File, error, hasoptions, elab)
=>
{ fun err m
=
{ error m;
sys::empty;
};
case (list::find (same_path_as given_freezefile) sublibraries)
#
THE ( _,
lg::LIBRARY { more => lg::MAIN_LIBRARY _, catalog, ... }
, _ # MUSTDIE
)
=>
if hasoptions
#
err (ad::describe given_freezefile +
" cannot have options because it is already\
\ listed as a member");
else
domain_of catalog;
fi;
THE _ =>
err (ad::describe given_freezefile +
" is a thawed library, not a .frozen library.");
NULL =>
case (elab ())
#
ERROR_LIBFILE => sys::empty;
#
LIBFILE
{
masked_tomes => [], # (tome, exported_symbols_set) pairs.
#
sublibraries => [ ( _,
lg::LIBRARY {
more => lg::MAIN_LIBRARY _,
catalog,
...
}
, _ # MUSTDIE
)
],
...
}
=>
domain_of catalog;
LIBFILE { masked_tomes, sublibraries, ... }
=>
{ apply
(\\ (given_freezefile, _
, _ # MUSTDIE
)
=
print (ad::describe given_freezefile + "\n")
)
sublibraries;
apply
(\\ (tome, exported_symbols_set) = print (tlt::describe_thawedlib_tome tome + "\n"))
masked_tomes; # (tome, exported_symbols_set) pairs.
err "precisely one library must be named here";
};
esac;
esac;
};
freezefile_exports (ERROR_LIBFILE, _, _, _, _)
=>
sys::empty;
end;
# Collect and return exported library symbols.
# If second arg is THE given_filepath then
# we process only the named sublibrary, otherwise
# we process all sublibraries:
#
fun sublibrary_exported_symbols (LIBFILE { sublibraries, ... }, NULL, _)
=>
fold_forward
note_symbols_exported_by_sublibrary # Processing fn.
sys::empty # Initial value.
sublibraries # List to process.
where
fun note_symbols_exported_by_sublibrary ((_, lg::LIBRARY { more => lg::SUBLIBRARY _, catalog, ... }
, _ # MUSTDIE
), result_symbolset)
=>
add_domain (catalog, result_symbolset); # Add all keys in 'catalog' (sublibrary contents -- apis, pkgs etc) to result_symbolset
note_symbols_exported_by_sublibrary (_, result_symbolset) # Ignore libraries which are not sublibraries.
=>
result_symbolset;
end;
end;
sublibrary_exported_symbols (LIBFILE { sublibraries, ... }, THE given_filepath, error)
=>
case (list::find (same_path_as given_filepath) sublibraries)
#
THE ( _,
lg::LIBRARY { more => lg::SUBLIBRARY _, catalog, ... }
, _ # MUSTDIE (?)
)
=>
domain_of catalog;
THE _ =>
{ error (ad::describe given_filepath + " is a main library not a sublibrary.");
sys::empty;
};
NULL =>
{ error ("no such sublibrary: " + ad::describe given_filepath);
sys::empty;
};
esac;
sublibrary_exported_symbols (ERROR_LIBFILE, _, _)
=>
sys::empty;
end;
end;
fun is_error_libfile ERROR_LIBFILE => TRUE;
is_error_libfile (LIBFILE _) => FALSE;
end;
};
end;
## (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.