## makelib-g.pkg
# Compiled by:
#
src/app/makelib/makelib.sublib# This module constitutes our standard
#
# makelib application + compiler + interactive system
#
# which is to say, what winds up as the
#
# bin/mythryld
#
# "executable" (heap image).
#
# We use this application to make+compile everything
# -except- itself. (Compiling the Mythryl compiler itself
# involves special cases which are handled by the special
#
#
src/app/makelib/mythryl-compiler-compiler/mythryl-compiler-compiler-g.pkg#
# facility.)
#
# This is the module that actually puts together
# the contents of the
# pkg makelib
# people find in
#
src/lib/core/makelib/makelib.lib# which is to say, the set of makelib::* types, functions and values
# visible from the mythryld prompt at runtime.
#
# For example, if you run
# bin/mythryld
# and then enter
# makelib::makelib_state::show_all ();
# at the interactive prompt, you'll invoke the
# show_all fun defined in this file, which
# lists all toplevel symbols.
#
# The code in this file is almost all lightweight
# stuff -- commandline switch parsing and top-level
# glue logic hooking together functionality implemented
# elsewhere.
#
# The major functionality imvoked here is doing the dagwalks
# of the sourcefile dependency graph so as to compile no sourcefile
# until all files it depends upon have been compiled, making the
# type information etc in those files available. This process is
# somewhat obscured by the "server" facility to allow compiling
# multiple sourcefiles in parallel using multiple Unix subprocesses
# (optionally on separate machines). This facility appears broken.
#
# The actual dagwalk functionality is largely implemented in
#
#
src/app/makelib/compile/compile-in-dependency-order-g.pkg#
src/app/makelib/compile/link-in-dependency-order-g.pkg#
#
# generic invocation context:
#
# The generic we define is invoked (only) in
#
#
src/lib/core/internal/makelib-internal.pkg#
# which consists of the single statement
#
# package makelib_internal = makelib_g (package mythryl_compiler = mythryl_compiler)
#
# makelib_internal is used in four places (lumping all the platform files together):
#
# src/lib/core/mythryl-compiler-compiler/mythryl-compiler-compiler-for-intel32-posix.pkg: load_plugin = makelib_internal::load_plugin
# src/lib/core/internal/make-mythryl-compiler-etc.pkg: package make_mythryl_compiler_etc = make_mythryl_compiler_etc_g
# src/lib/core/makelib/makelib.pkg: package makelib: Makelib = makelib_internal::makelib
# src/lib/core/makelib/tools.pkg: package tools: Tools = makelib_internal::tools
#
# generic argument:
#
# "mythryl_compiler" is defined by
#
# package mythryl_compiler = mythryl_compiler_for_intel32_posix;
# in
#
src/lib/core/compiler/set-mythryl_compiler-to-mythryl_compiler_for_intel32_posix.pkg#
# which gets conditionally included by
#
#
src/lib/core/compiler/mythryl-compiler-for-this-platform.lib#
# (The above is for "intel32-linux";
# other platforms are similar.)
#
#
#
# Runtime invocation context:
#
# The two most important runtime
# entrypoints in this file are our
# make
# compile
# functions, which are respectively invoked by typing
# make "foobar.lib"
# compile "foobar.lib"
# at the interactive prompt.
#
#
#
# We also export a
#
# read_''library_contents''_and_compile_''init_cmi''_and_preload_libraries
#
# function which is indirectly invoked by
#
#
src/lib/core/internal/make-mythryld-executable.pkg#
# shortly before dumping the heap image which
# generates the compiler "executable" heap image.
### "The most important difference is not that
### the good programmers are better at getting
### out of trouble, but that the poor ones are
### better at getting into it."
### "Mithril is the fantasy version of unobtainium."
stipulate
package acf = anormcode_form; # anormcode_form is from
src/lib/compiler/back/top/anormcode/anormcode-form.pkg package ad = anchor_dictionary; # anchor_dictionary is from
src/app/makelib/paths/anchor-dictionary.pkg package cmd = commandline; # commandline is from
src/lib/std/commandline.pkg package cms = compiler_mapstack_set; # compiler_mapstack_set is from
src/lib/compiler/toplevel/compiler-state/compiler-mapstack-set.pkg package cs = compiler_state; # compiler_state is from
src/lib/compiler/toplevel/interact/compiler-state.pkg package ds = deep_syntax; # deep_syntax is from
src/lib/compiler/front/typer-stuff/deep-syntax/deep-syntax.pkg package err = error_message; # error_message is from
src/lib/compiler/front/basics/errormsg/error-message.pkg package f8b = eight_byte_float; # eight_byte_float is from
src/lib/std/eight-byte-float.pkg package fcx = find_set_of_compiled_files_for_executable; # find_set_of_compiled_files_for_executable is from
src/app/makelib/mythryl-compiler-compiler/find-set-of-compiledfiles-for-executable.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 fzp = freeze_policy; # freeze_policy is from
src/app/makelib/parse/freeze-policy.pkg package im = int_map; # int_map is from
src/app/makelib/stuff/int-map.pkg package it = import_tree; # import_tree is from
src/lib/compiler/execution/main/import-tree.pkg package lg = inter_library_dependency_graph; # inter_library_dependency_graph is from
src/app/makelib/depend/inter-library-dependency-graph.pkg package lgr = logger; # logger is from
src/lib/src/lib/thread-kit/src/lib/logger.pkg package llp = lib_load_path; # lib_load_path is from
src/app/makelib/main/lib-load-path.pkg package lms = list_mergesort; # list_mergesort is from
src/lib/src/list-mergesort.pkg package lsi = library_source_index; # library_source_index is from
src/app/makelib/stuff/library-source-index.pkg package lt = linking_mapstack; # linking_mapstack is from
src/lib/compiler/execution/linking-mapstack/linking-mapstack.pkg package mcc = mythryl_compiler_compiler_configuration; # mythryl_compiler_compiler_configuration is from
src/app/makelib/mythryl-compiler-compiler/mythryl-compiler-compiler-configuration.pkg package mcv = mythryl_compiler_version; # mythryl_compiler_version is from
src/lib/core/internal/mythryl-compiler-version.pkg package mld = makelib_defaults; # makelib_defaults is from
src/app/makelib/stuff/makelib-defaults.pkg package ms = makelib_state; # makelib_state is from
src/app/makelib/main/makelib-state.pkg package mtq = makelib_thread_boss; # makelib_thread_boss is from
src/app/makelib/concurrency/makelib-thread-boss.pkg package myp = mythryl_parser; # mythryl_parser is from
src/lib/compiler/front/parser/main/mythryl-parser.pkg package pcs = per_compile_stuff; # per_compile_stuff is from
src/lib/compiler/front/typer-stuff/main/per-compile-stuff.pkg package ph = picklehash; # picklehash is from
src/lib/compiler/front/basics/map/picklehash.pkg package plp = platform_properties; # platform_properties is from
src/lib/std/src/nj/platform-properties.pkg package pp = standard_prettyprinter; # standard_prettyprinter is from
src/lib/prettyprint/big/src/standard-prettyprinter.pkg package ps = pervasive_symbol; # pervasive_symbol is from
src/app/makelib/main/pervasive-symbol.pkg package psx = posixlib; # posixlib is from
src/lib/std/src/psx/posixlib.pkg package pth = winix__premicrothread::path; # winix__premicrothread is from
src/lib/std/winix--premicrothread.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 seg = code_segment; # code_segment is from
src/lib/compiler/execution/code-segments/code-segment.pkg package sg = intra_library_dependency_graph; # intra_library_dependency_graph is from
src/app/makelib/depend/intra-library-dependency-graph.pkg package sj = string_junk; # string_junk is from
src/lib/std/src/string-junk.pkg package sm = string_map; # string_map is from
src/lib/src/string-map.pkg package sma = supported_architectures; # supported_architectures is from
src/lib/compiler/front/basics/main/supported-architectures.pkg package spm = source_path_map; # source_path_map is from
src/app/makelib/paths/source-path-map.pkg package sps = source_path_set; # source_path_set is from
src/app/makelib/paths/source-path-set.pkg package sy = symbol; # symbol is from
src/lib/compiler/front/basics/map/symbol.pkg package sym = symbol_map; # symbol_map is from
src/app/makelib/stuff/symbol-map.pkg package syx = symbolmapstack; # symbolmapstack is from
src/lib/compiler/front/typer-stuff/symbolmapstack/symbolmapstack.pkg package tc = thawedlib_tome; # thawedlib_tome is from
src/app/makelib/compilable/thawedlib-tome.pkg package tmp = highcode_codetemp; # highcode_codetemp is from
src/lib/compiler/back/top/highcode/highcode-codetemp.pkg package wnx = winix__premicrothread; # winix__premicrothread is from
src/lib/std/winix--premicrothread.pkg # Logging support. To log messages from this file scatter
#
# to_log {. sprintf "Whatever"; }; # Do not add trailing newline to message string.
#
# calls through the code as appropriate and then either
# uncomment the below
#
# my _ = lgr::enable makelib_logging;
#
# line or do
#
# logger::enable (the (logger::find_logtree_node_by_name "makelib::logging"));
#
# from the Mythryl interactive prompt.
#
makelib_logging
=
lgr::make_logtree_leaf
{
parent => fil::all_logging,
name => "makelib::logging",
default => FALSE # Change to true or call (lgr::enable makelib_logging) to enable logging in this file.
};
#
to_log = lgr::log_if makelib_logging 0;
herein
generic package makelib_g (
# # "myc" == "mythryl_compiler".
package myc: Mythryl_Compiler; # Mythryl_Compiler is from
src/lib/compiler/toplevel/compiler/mythryl-compiler.api # mythryl_compiler_for_intel32_posix is from
src/lib/compiler/toplevel/compiler/mythryl-compiler-for-intel32-posix.pkg )
{
stipulate
#
os_kind = plp::get_os_kind (); # UNIX
| WIN32 | OS2;
# Set platform to "intel32-posix" or such:
#
platform
=
cat [
architecture_name, # "pwrpc32"/"sparc32"/"intel32".
"-",
fp::os_kind_to_string os_kind
]
where
architecture_name = sma::architecture_name myc::target_architecture;
end;
# Set up a little dictionary defining
# half a dozen platform properties
# like architecture ("intel32" or such):
#
package mps # "mps" == "makelib preprocessor state"
=
makelib_preprocessor_state_g ( # makelib_preprocessor_state_g is from
src/app/makelib/main/makelib-preprocessor-state-g.pkg #
architecture = myc::target_architecture; # PWRPC32/SPARC32/INTEL32.
os_kind = os_kind;
abi_variant = myc::abi_variant;
);
#############################################################################
#
# 'seed_libraries_index__local' gets loaded by read_picklehash_map() from
#
# $ROOT/LIBRARY_CONTENTS
#
# and constitutes our master index to the complete
# contents of the set of seed libraries used to bootstrap
# the Mythryl system.
#
# The seed_libraries_index__local index is structured as a map
#
# ad::File -> int_map::Map(cms::Linking_Mapstack)
#
# which, given the ad::File equivalent of (say)
#
# $ROOT/
src/lib/core/internal/makelib-internal.lib #
# gives us back a summary of the pickle-by-pickle (== compiledfile-by-compiledfile)
# contents of the corresponding freezefile
#
# $ROOT/src/lib/core/internal/makelib-internal.lib.frozen
#
# essentially in the form of a list of triples
#
# (byte_offset_in_freezefile:Int, Picklehash, pickle:Chunk)
#
# (The actual structure is an intmap from byte offsets to
# singleton Linking_Mapstacks associating picklehash to pickle chunk.)
#
seed_libraries_index__local
=
REF (spm::empty: spm::Map( int_map::Map(cms::Linking_Mapstack) )); # XXX BUGGO FIXME more icky thread-hostile mutable global state :-/
# int_map is from
src/app/makelib/stuff/int-map.pkg # "A central index of freezefile symbol tables,
# stored in packed stampmapstack form:"
#
package ffr # XXX BUGGO FIXME more thread-hostile mutable global storage. :-(
= # stampmapstack is from
src/lib/compiler/front/typer-stuff/modules/stampmapstack.pkg freezefile_roster_g (); # freezefile_roster_g is from
src/app/makelib/freezefile/freezefile-roster-g.pkg read_eval_print_from_stream__hook # This gets set just once during initialization, below in read_''library_contents''_and_compile_''init_cmi''_and_preload_libraries,
= # so it isn't a problem for concurrent operation.
REF (\\ _ = { msg = "read_eval_print_from_stream__hook not set!" # This hook winds up pointing to read_eval_print_from_stream from
src/lib/compiler/toplevel/interact/read-eval-print-loop-g.pkg
+ " --makelib-g.pkg";
log::fatal msg;
raise exception DIE msg;
}
)
:
Ref( fil::Input_Stream -> Void );
parse_string_to_raw_declarations__hook # This gets set just once during initialization, below in read_''library_contents''_and_compile_''init_cmi''_and_preload_libraries,
= # so it isn't a problem for concurrent operation.
REF (\\ _ = { msg = "parse_string_to_raw_declarations__hook" # This hook winds up pointing to parse_string_to_raw_declarations from
src/lib/compiler/toplevel/interact/read-eval-print-loop-g.pkg
+ "not set! --makelib-g.pkg";
log::fatal msg;
raise exception DIE msg;
}
)
:
Ref( { sourcecode_info: sci::Sourcecode_Info,
pp: pp::Prettyprinter # Where to prettyprint results.
}
->
List( raw::Declaration )
);
compile_raw_declaration_to_package_closure__hook #
=
REF (\\ _ = { msg = "compile_raw_declaration_to_package_closure__hook" # This hook winds up pointing to compile_raw_declaration_to_package_closure from
src/lib/compiler/toplevel/interact/read-eval-print-loop-g.pkg
+ "not set! --makelib-g.pkg";
log::fatal msg;
raise exception DIE msg;
}
)
:
Ref (
{ #
declaration: raw::Declaration, #
sourcecode_info: sci::Sourcecode_Info, # Source code to compile, also error sink.
pp: pp::Prettyprinter, # Where to prettyprint results.
compiler_state_stack: (cs::Compiler_State, List(cs::Compiler_State)), # Compiler symbol tables to use for this compile.
options: List( cs::Compile_And_Eval_String_Option ) # Future-proofing, lets us add more parameters in future without breaking backward compatibility at the client-call level.
} #
->
Null_Or(
{ package_closure: seg::Package_Closure,
import_trees: List( it::Import_Tree ),
export_picklehash: Null_Or( ph::Picklehash ),
linking_mapstack: lt::Picklehash_To_Heapchunk_Mapstack,
code_and_data_segments: seg::Code_And_Data_Segments,
new_symbolmapstack: syx::Symbolmapstack, # A symbol table delta containing (only) stuff from raw_declaration.
deep_syntax_declaration: ds::Declaration, # Typechecked form of raw_declaration.
exported_highcode_variables: List( tmp::Codetemp ),
inline_expression: Null_Or( acf::Function ),
top_level_pkg_etc_defs_jar: cs::Compiler_Mapstack_Set_Jar,
get_current_compiler_mapstack_set: Void -> cs::Compiler_Mapstack_Set,
compiler_verbosity: pcs::Compiler_Verbosity,
compiler_state_stack: (cs::Compiler_State, List(cs::Compiler_State))
}
)
);
link_and_run_package_closure__hook #
=
REF (\\ _ = { msg = "link_and_run_package_closure__hook" # This hook winds up pointing to link_and_run_package_closure from
src/lib/compiler/toplevel/interact/read-eval-print-loop-g.pkg
+ "not set! --makelib-g.pkg";
log::fatal msg;
raise exception DIE msg;
}
)
:
Ref ( { sourcecode_info: sci::Sourcecode_Info, # Source code to compile, also error sink.
pp: pp::Prettyprinter # Where to prettyprint results.
}
->
{ package_closure: seg::Package_Closure,
import_trees: List( it::Import_Tree ),
export_picklehash: Null_Or( ph::Picklehash ),
linking_mapstack: lt::Picklehash_To_Heapchunk_Mapstack,
code_and_data_segments: seg::Code_And_Data_Segments,
new_symbolmapstack: syx::Symbolmapstack, # A symbol table delta containing (only) stuff from raw_declaration.
deep_syntax_declaration: ds::Declaration, # Typechecked form of raw_declaration.
exported_highcode_variables: List( tmp::Codetemp ),
inline_expression: Null_Or( acf::Function ),
top_level_pkg_etc_defs_jar: cs::Compiler_Mapstack_Set_Jar,
get_current_compiler_mapstack_set: Void -> cs::Compiler_Mapstack_Set,
compiler_verbosity: pcs::Compiler_Verbosity,
compiler_state_stack: (cs::Compiler_State, List(cs::Compiler_State)) # Compiler symbol tables to use for this compile.
} #
-> #
(cs::Compiler_State, List(cs::Compiler_State)) # Updated compiler symbol tables. Caller may keep or discard.
);
# 2008-02-24 CrT: This is a quick hack to get the eval definition
# from where I can get it to where I want it. A
# cleaner mechanism would be cool. XXX BUGGO FIXME.
#
# (I don't intend ever changing this pointer
# once set, so this is not really an example
# of problematic global state.)
#
my eval_hook : Ref(String -> Void)
= REF (\\ _ = ());
package cdo # "cdo" == 'compile_(in_)dependency_order".
=
compile_in_dependency_order_g ( # compile_in_dependency_order_g is from
src/app/makelib/compile/compile-in-dependency-order-g.pkg # # mythryl_compiler_for_intel32_posix is from
src/lib/compiler/toplevel/compiler/mythryl-compiler-for-intel32-posix.pkg package myc = myc; # "myc" == "mythryl_compiler".
package ffr = ffr; # "ffr" == "freezefile_roster".
#
fun read_eval_print_from_stream stream
=
*read_eval_print_from_stream__hook stream; # This hook winds up pointing to read_eval_print_from_stream from
src/lib/compiler/toplevel/interact/read-eval-print-loop-g.pkg
);
package t2c # "t2c" == "thawedlib_tome to compiledfile".
=
thawedlib_tome__to__compiledfile__map_g ( # thawedlib_tome__to__compiledfile__map_g is from
src/app/makelib/compile/thawedlib-tome--to--compiledfile-contents--map-g.pkg #
architecture = myc::target_architecture; # PWRPC32/SPARC32/INTEL32. (Used in compiledfile::read_compiledfile to check that we're loading compiled code for the right architecture.)
);
package ltw # "ltw" == "linking dagwalk".
=
link_in_dependency_order_g ( # link_in_dependency_order_g is from
src/app/makelib/compile/link-in-dependency-order-g.pkg #
package thawedlib_tome__to__compiledfile__map = t2c;
#
seed_libraries_index__local = seed_libraries_index__local;
);
#
drop_thawedlib_tome_from_linker_map
=
ltw::drop_thawedlib_tome_from_linker_map;
stipulate
find_files
=
fcx::find_set_of_compiled_files_for_executable
#
(\\ filepath = filepath); # Null filename transform.
herein
make_bootlist
=
.l o find_files;
end;
# This is the 'dagwalker' function
# for the 'compile' function implementing
#
# makelib::compile "foo.lib"
#
fun dagwalker_for_compile_command
#
(makelib_state: ms::Makelib_State)
#
(root_library: lg::Inter_Library_Dependency_Graph) # Freshly read in by parse_libfile_tree_and_return_interlibrary_dependency_graph from
src/app/makelib/parse/libfile-parser-g.pkg =
{
my { compile_library_catalog_in_dependency_order, ... }
=
cdo::make_dependency_order_compile_fns
{
root_library,
#
maybe_drop_thawedlib_tome_from_linker_map
=> drop_thawedlib_tome_from_linker_map, # Sometimes we pass in a dummy, but not here.
#
set__compiledfile__for__thawedlib_tome
=>
\\ _ = () # Dummy.
};
{
not_null (compile_library_catalog_in_dependency_order makelib_state);
}
then
{
ltw::cleanup makelib_state;
};
};
# make_dependency_order_compile_fns is from
src/app/makelib/compile/compile-in-dependency-order-g.pkg # evict is from
src/app/makelib/compile/link-in-dependency-order-g.pkg # This is the 'dagwalker' function for the 'make' function implementing
# makelib::make "foo.lib"
# It combines the actions of "compile" and "exec".
# When successful, it combines the results
# (thus forming a full dictionary) and adds
# it to the toplevel dictionary.
#
fun dagwalker_for_make_command
# MUSTDIE add_namings is probably part of the problem:
(add_namings: Bool) # Bool: 'TRUE' for regular commandline make, 'FALSE' when called from load_plugin'
(makelib_state: ms::Makelib_State)
(root_library as lg::LIBRARY _) # The result of (parse_libfile_tree_and_return_interlibrary_dependency_graph foo.lib)
=>
{
(t2c::make__thawedlib_tome__to__compiledfile__map ()) # cc is defined at top of file.
->
{ set__compiledfile__for__thawedlib_tome,
get__compiledfile__for__thawedlib_tome
};
# Both of the next two calls return
# fates, which must be called
# with a makelib_state argument in order
# to actually obtain a useful result:
#
my { compile_library_catalog_in_dependency_order => compile_my_library, ... }
=
cdo::make_dependency_order_compile_fns
{
root_library,
#
maybe_drop_thawedlib_tome_from_linker_map
=> drop_thawedlib_tome_from_linker_map, # Sometimes we pass in a dummy, but not here.
#
set__compiledfile__for__thawedlib_tome
};
my { linking_mapstack => linking_fate, ... }
=
ltw::make_linking_dagwalk (
root_library,
.compiledfile o get__compiledfile__for__thawedlib_tome
);
case (compile_my_library makelib_state)
#
# NULL => FALSE;
NULL =>
{
FALSE;
};
#
THE { symbolmapstack, inlining_mapstack }
=>
{
ltw::cleanup makelib_state;
# string_set is from
src/lib/src/string-set.pkg case (linking_fate makelib_state)
#
THE linking_mapstack
=>
{
if add_namings
#
compiler_mapstack_set_differences
=
cms::make_compiler_mapstack_set {
symbolmapstack,
linking_mapstack,
inlining_mapstack
};
top_level_pkg_etc_defs_jar = cs::get_top_level_pkg_etc_defs_jar ();
base_compiler_mapstack_set = top_level_pkg_etc_defs_jar.get_mapstack_set ();
new_compiler_mapstack_set
=
cms::concatenate_compiler_mapstack_sets
(
compiler_mapstack_set_differences,
base_compiler_mapstack_set
);
top_level_pkg_etc_defs_jar.set_mapstack_set new_compiler_mapstack_set;
fil::say {. " makelib-g.pkg: New names added."; };
fi;
TRUE;
};
NULL => FALSE;
esac;
};
esac;
};
dagwalker_for_make_command _ _ lg::BAD_LIBRARY
=>
FALSE;
end;
package fzf # "fzf" == "freezefile".
=
freezefile_g ( # freezefile_g is from
src/app/makelib/freezefile/freezefile-g.pkg #
architecture = myc::target_architecture; # PWRPC32/SPARC32/INTEL32.
#
package ffr = ffr; # "ffr" == "freezefile_roster".
# thawedlib_tome__to__compiledfile__map_g is from
src/app/makelib/compile/thawedlib-tome--to--compiledfile-contents--map-g.pkg # A function which allows
#
# freezefile::save_freezefile
#
# to compile any thawed library
# handed to it, one tome at a time:
#
fun compile_library
#
(makelib_state: ms::Makelib_State)
#
(root_library: lg::Inter_Library_Dependency_Graph)
=
{ (t2c::make__thawedlib_tome__to__compiledfile__map ())
->
{ set__compiledfile__for__thawedlib_tome,
get__compiledfile__for__thawedlib_tome
};
my { compile_library_catalog_in_dependency_order => compile_my_library, ... }
=
cdo::make_dependency_order_compile_fns
{
root_library,
#
maybe_drop_thawedlib_tome_from_linker_map
=> drop_thawedlib_tome_from_linker_map,
#
set__compiledfile__for__thawedlib_tome
};
case (compile_my_library makelib_state)
#
THE _ => THE get__compiledfile__for__thawedlib_tome;
NULL => NULL;
esac;
};
get_symbol_and_inlining_mapstacks
=
cdo::get_symbol_and_inlining_mapstacks;
);
# "Access to the library-building mechanism
# is integrated into the .lib file parser.
#
# "I'm not sure if this is the cleanest way,
# but it works well enough." -- Matthias Blume
#
package lfp # "lfp" == "libfile parser"
=
libfile_parser_g ( # libfile_parser_g is from
src/app/makelib/parse/libfile-parser-g.pkg #
package freezefile = fzf;
package freezefile_roster = ffr;
#
fun drop_stale_entries_from_compiler_and_linker_maps ()
=
{ cdo::drop_stale_entries_from_compiler_map ();
ltw::drop_stale_entries_from_linker_map ();
};
);
stipulate
Primordial_Library_Dependency_Graph
=
{ primordial_library: lg::Inter_Library_Dependency_Graph };
filename_policy = fp::policy;
# filename_policy is from
src/app/makelib/main/filename-policy.pkg primordial_library_hook
=
REF (NULL: Null_Or( Primordial_Library_Dependency_Graph ));
herein
anchor_dictionary = ad::dictionary;
#
fun make_standard_source_path file_path # E.g. "$ROOT/src/lib/core/init/init.cmi" or "$ROOT/src/lib/std/standard.lib"
= # or "$ROOT/src/lib/core/mythryl-compiler-compiler/mythryl-compiler-compiler-for-this-platform.lib"
case (llp::search_lib_load_path_for_file file_path)
#
THE file_path => ad::from_standard anchor_dictionary file_path; # Found file on MYTHRYL_LIB_LOAD_PATH (or default value for it) so use expansion for it.
NULL => ad::from_standard anchor_dictionary file_path; # Did not find file via new lib-load-path facility, so fall back to Matthias Blume's old anchor-dictionary mechanism.
esac;
#
fun show_api (api_name: String)
=
{
symbolmapstack
=
compiler_mapstack_set::symbolmapstack_part
(cs::combined ());
symbol = sy::make_api_symbol api_name;
case (symbolmapstack::get (symbolmapstack, symbol))
#
symbolmapstack_entry::NAMED_API a
=>
{
output_stream
=
{ consumer => (\\ string = fil::write (fil::stdout, string)),
flush => {. fil::flush fil::stdout; },
close => \\ () = ()
};
pp = pp::make_prettyprinter output_stream [];
# unparse_package_language is from
src/lib/compiler/front/typer/print/unparse-package-language.pkg unparse_package_language::unparse_api
pp
(a, symbolmapstack, /* max prettyprint recursion depth: */ 200);
pp::flush_prettyprinter pp;
};
_ =>
print " makelib-g.pkg:show_api: Improbable failure.\n";
esac
except
unbound
=
print ("No api " + api_name + " defined at top level.\n");
};
#
fun show_pkg (pkg_name: String)
=
{
symbolmapstack
=
compiler_mapstack_set::symbolmapstack_part
(cs::combined ());
symbol
=
sy::make_package_symbol pkg_name;
case (symbolmapstack::get (symbolmapstack, symbol))
#
symbolmapstack_entry::NAMED_PACKAGE a
=>
{
output_stream
=
{ consumer => (\\ string = fil::write (fil::stdout, string)),
flush => {. fil::flush fil::stdout; },
close => \\ () = ()
};
pp = pp::make_prettyprinter output_stream [];
unparse_package_language::unparse_package
pp
(a, symbolmapstack, /* max prettyprint recursion depth: */ 200);
pp::flush_prettyprinter pp;
};
#
_ => print " makelib-g.pkg:show_pkg: Improbable failure.\n";
esac
except
unbound
=
print ("No package " + pkg_name + " defined at top level.\n");
};
# symbolmapstack_entry is from
src/lib/compiler/front/typer-stuff/symbolmapstack/symbolmapstack-entry.pkg # symbolmapstack is from
src/lib/compiler/front/typer-stuff/symbolmapstack/symbolmapstack.pkg #
# compiler_mapstack_set is from
src/lib/compiler/toplevel/compiler-state/compiler-mapstack-set.pkg # symbol is from
src/lib/compiler/front/basics/map/symbol.pkg # symbol_map is from
src/app/makelib/stuff/symbol-map.pkg #
fun show_all ()
=
{ symbols = cs::list_bound_symbols ();
descriptions
=
map
sy::describe
symbols;
#
fun pr s
=
fil::say {. s; };
fil::say {. "\nTop-level definitions:"; };
apply pr descriptions;
};
#
fun show title_string filter_fn
=
{ symbols = cs::list_bound_symbols ();
symbols = list::filter filter_fn symbols;
names = map
sy::name
symbols;
sorted_names = lms::sort_list string::(>) names;
#
fun pr s
=
fil::say {. cat [s, " "]; };
fil::say {. cat ["\nTop-level ", title_string, " definitions:"]; };
apply pr sorted_names;
fil::say {. ""; };
};
#
fun show_vals () = show "val" (\\ symbol = (sy::name_space symbol == sy::VALUE_NAMESPACE ));
fun show_apis () = show "api" (\\ symbol = (sy::name_space symbol == sy::API_NAMESPACE ));
fun show_pkgs () = show "pkg" (\\ symbol = (sy::name_space symbol == sy::PACKAGE_NAMESPACE));
fun show_types () = show "type" (\\ symbol = (sy::name_space symbol == sy::TYPE_NAMESPACE ));
fun show_generics () = show "generic" (\\ symbol = (sy::name_space symbol == sy::GENERIC_NAMESPACE));
# unparse_compiler_state is from
src/lib/compiler/front/typer-stuff/symbolmapstack/unparse-compiler-state.pkg # latex_print_compiler_state is from
src/lib/compiler/front/typer-stuff/symbolmapstack/latex-print-compiler-state.pkg #
fun dump_api_reference filename
=
unparse_compiler_state::unparse_compiler_state_to_file
filename;
#
fun latex_dump_api_reference
{ directory,
filename_prefix,
filename_suffix
}
=
latex_print_compiler_state::latex_print_compiler_state_to_file
{ directory,
filename_prefix,
filename_suffix
};
#
fun get_primordial_library_hook_value ()
=
the *primordial_library_hook
except
NULL_OR
=
raise exception DIE " makelib-g.pkg: primordial_library_hook not initialized";
#
fun make_makelib_session { we_are_a_subprocess, keep_going_after_compile_errors }
=
{ makelib_thread_boss = mtq::make_makelib_thread_boss ();
#
{ filename_policy,
anchor_dictionary,
platform,
we_are_a_subprocess => REF we_are_a_subprocess,
#
find_makelib_preprocessor_symbol => mps::find_makelib_preprocessor_symbol,
keep_going_after_compile_errors,
makelib_thread_boss
};
};
primordial_library
=
.primordial_library o get_primordial_library_hook_value;
# makelib_defaults is from
src/app/makelib/stuff/makelib-defaults.pkg # libfile_parser_g is from
src/app/makelib/parse/libfile-parser-g.pkg # Maybe delete picklestrings
# from memory to save ram:
#
fun maybe_clear_pickle_cache ()
=
if (mld::conserve_memory.get ()) # 'FALSE' by default, but user-settable.
#
lfp::clear_pickle_cache ();
fi;
# Construct an arg record for parse_libfile_tree_and_return_interlibrary_dependency_graph argument from
src/app/makelib/parse/libfile-parser-g.pkg #
fun parse_arg_0 we_are_a_subprocess (library_source_index, freeze_policy, makelib_file_to_read)
=
{ makelib_file_to_read, # Primary input to parse_libfile_tree_and_return_interlibrary_dependency_graph fn.
load_plugin,
library_source_index,
makelib_session
=>
make_makelib_session
{
we_are_a_subprocess,
keep_going_after_compile_errors => mld::keep_going_after_compile_errors.get ()
},
freeze_policy, # See explanation in
src/app/makelib/parse/freeze-policy.api primordial_library => primordial_library (),
paranoid => FALSE
}
also
fun parse_arg x = parse_arg_0 FALSE x
also
fun server_parse_arg x = parse_arg_0 TRUE x
also
fun run
make_src_path # Always make_standard_source_path.
freeze_policy # One of: fzp::FREEZE_NONE fzp::FREEZE_ONE fzp::FREEZE_ALL
dagwalker # dagwalker_for_freeze_command / dagwalker_for_make_command TRUE / dagwalker_for_compile_command
libfile_path_string # E.g. "$ROOT/src/lib/std/standard.lib"
=
# Read in a .lib library definition file and
# apply given 'dagwalker' to the result:
#
{
libfile_path = make_src_path libfile_path_string;
#
library_source_index
=
lsi::make_library_source_index ();
{ fil::say {.
cat [
" makelib-g.pkg: Making library ",
libfile_path_string
];
};
# show_all ();
case (lfp::parse_libfile_tree_and_return_interlibrary_dependency_graph
(parse_arg
( library_source_index,
freeze_policy,
libfile_path
)
))
#
THE (library, makelib_state)
=>
{
dagwalker makelib_state library;
};
#
NULL
=>
{
FALSE;
};
esac;
}
then
maybe_clear_pickle_cache ();
}
also
fun load_plugin' plugin_path
=
{ plugin_description
=
ad::describe plugin_path;
fil::say {.
cat
[
" makelib-g.pkg: Attempting to load plugin ",
plugin_description
];
};
library_source_index
=
lsi::make_library_source_index ();
succeeded
=
{ case (lfp::parse_libfile_tree_and_return_interlibrary_dependency_graph (
parse_arg (
library_source_index,
fzp::FREEZE_NONE,
plugin_path
)
))
THE (group, makelib_state)
=>
dagwalker_for_make_command FALSE makelib_state group;
NULL
=>
FALSE;
esac
then
maybe_clear_pickle_cache ();
}
except
_ = FALSE;
if succeeded fil::say {. cat [" makelib-g.pkg: plugin ", plugin_description, " loaded successfully]"]; };
else fil::say {. cat [" makelib-g.pkg: Unable to load plugin ", plugin_description]; };
fi;
succeeded;
}
also
fun load_plugin path_root file_path
=
{ fun badname string
=
fil::say {.
cat
[
" makelib-g.pkg: Bad plugin name: '",
string,
"'\n"
];
};
# say is from
src/lib/std/src/io/say.pkg prefile
=
ad::from_standard'
{ anchor_dictionary,
plaint_sink => badname
}
{ path_root,
file_path
};
load_plugin' (ad::file prefile);
};
#
fun cwd_load_plugin x
=
load_plugin (ad::current_working_directory ()) x;
# This function may be interactively invoked
# from the commandline as makelib::freeze'.
# (Or as makelib::freeze
# in which case the 'recursively' boolean arg is implicit.)
#
fun freeze'
#
{ recursively }
#
root
=
{
# Since we are a toplevel interactive entrypoint,
# allot a fresh makelib state:
#
makelib_state
=
{ library_source_index => lsi::make_library_source_index (),
plaint_sink => err::default_plaint_sink (),
#
timestamp_of_youngest_sourcefile_in_library
=>
REF timestamp::ancient, # Set up to track most recent (known) edit of any sourcefile in the library.
makelib_session
=>
make_makelib_session
{
we_are_a_subprocess => FALSE,
keep_going_after_compile_errors => mld::keep_going_after_compile_errors.get ()
}
};
fun dagwalker_for_freeze_command makelib_state g
=
{
my { compile_all_fat_tomes_in_library_in_dependency_order, ... }
=
cdo::make_dependency_order_compile_fns
{
root_library => g,
#
maybe_drop_thawedlib_tome_from_linker_map
=> drop_thawedlib_tome_from_linker_map,
#
set__compiledfile__for__thawedlib_tome
=>
\\ _ = ()
};
# compile_dagwalk def is above.
# linking_dagwalk def is above.
compile_all_fat_tomes_in_library_in_dependency_order makelib_state;
};
#
fun freeze_library_dummy_dagwalker makelib_state group
=
TRUE;
cdo::clear_state (); # A bit too draconian?
run
make_standard_source_path
(recursively ?? fzp::FREEZE_ALL :: fzp::FREEZE_ONE)
freeze_library_dummy_dagwalker
root;
}; # fun freeze'
##########################################################
# These are the entry points that will execute when we
# respectively do 'makelib::make "foobar.lib"; or
# 'makelib::compile "foobar.lib";'
# at the interactive prompt:
##########################################################
my make = run make_standard_source_path fzp::FREEZE_NONE (dagwalker_for_make_command TRUE);
my compile = run make_standard_source_path fzp::FREEZE_NONE dagwalker_for_compile_command;
#
fun to_portable s
=
{ gp = make_standard_source_path s; # "gp" might be "group", one old name for a library.
#
fun nativesrc file_path
=
{ p = ad::from_standard'
{ plaint_sink => \\ s = raise exception DIE s,
anchor_dictionary
}
{ path_root => ad::dir gp,
file_path
};
ad::os_string' (ad::file p);
};
#
fun mkres (g, pl)
=
{ graph => g,
imports => pl,
nativesrc
};
null_or::map
(mkres o to_portable::export)
(lfp::parse_libfile_tree_and_return_interlibrary_dependency_graph
(parse_arg
( lsi::make_library_source_index (),
fzp::FREEZE_NONE,
make_standard_source_path s
)
)
);
};
# null_or is from
src/lib/std/src/null-or.pkg # to_portable is from
src/app/makelib/depend/to-portable.pkg # library_source_index is from
src/app/makelib/stuff/library-source-index.pkg # This function is exported to the user interface as
# makelib::sources. It provides dependency generation
# support used by 'makedepend7'.
#
# According to the manual:
#
# The 'makelib::sources' function can be used to find the
# names of all source files that a given library depends on.
#
# It returns the names of all files involved with
# the exception of module_dependencies_summary files and .compiled files.
#
# Frozen libraries are represented by their freezefile;
# their description file or constituent members are
# NOT listed.
#
# Normally, the function reports actual file
# names as used for accessing the file system.
#
# For freezefiles this behavior can be
# inconvenient because these names depend on
# architecture and operating system.
#
# For this reason, makelib::sources accepts an
# optional pair of strings that then will be used
# in place of the architecture- and OS-specific
# part of these names.
#
# If there was some error analyzing the specified
# library or sublibrary, makelib::sources returns NULL.
# Otherwise the result is a list of records, each
# carrying a file name, the corresponding ilk, and
# information about whether or not the source was
# created by some tool:
#
# my sources: { arch: String, os: String } Null_Or
# -> String
# -> Null_Or( List { file: String, ilk: String, derived: Bool } )
#
fun sources platform group
=
{ policy
=
case platform
#
NULL => filename_policy;
THE architecture_and_os => fp::policy;
esac;
# filename_policy is from
src/app/makelib/main/filename-policy.pkg # source_path_set is from
src/app/makelib/paths/source-path-set.pkg #
fun sources_of ((lt: lg::Library_Thunk), (v, a))
=
{ v' = sps::add (v, lt.libfile);
case (lt.library_thunk ())
#
lg::LIBRARY { more, sources, ... }
=>
{ fun add (p, x, a)
=
sm::set (a, ad::os_string p, x);
#
fun sg l
=
if (sps::member (v, lt.libfile))
#
(v, a);
else
fold_forward
sources_of
( v',
spm::keyed_fold_forward add a sources
)
l;
fi;
case more
#
lg::SUBLIBRARY n
=>
sg n.sublibraries;
#
lg::MAIN_LIBRARY { frozen_vs_thawed_stuff, makelib_version_intlist }
=>
case frozen_vs_thawed_stuff
#
lg::THAWEDLIB_STUFF d => sg d.sublibraries;
#
lg::FROZENLIB_STUFF _
=>
{ f = ad::os_string lt.libfile;
#
(sm::get_and_drop (a, f)) -> (a, x);
freezefile_name
=
fp::make_freezefile_name
policy
lt.libfile;
( v',
sm::set (a, freezefile_name, the x) # We're trust that 'f' is always in 'a' above.
);
};
esac;
esac;
};
lg::BAD_LIBRARY
=>
(v', a);
esac;
};
p = make_standard_source_path group;
library_source_index
=
lsi::make_library_source_index ();
case (lfp::parse_libfile_tree_and_return_interlibrary_dependency_graph
(parse_arg
( library_source_index,
fzp::FREEZE_NONE,
p
) ) )
#
THE (g, _)
=>
{ my (_, sm)
=
sources_of ( { libfile => p,
library_thunk => \\ () = g
,renamings => [] # MUSTDIE
},
( sps::empty,
sm::singleton ( ad::os_string p,
{ ilk => "cm",
derived => FALSE
}
)
)
);
#
fun add (s, { ilk, derived }, l)
=
{ file => s, ilk, derived } ! l;
THE (sm::keyed_fold_forward add [] sm);
};
#
_ => NULL;
esac
then
maybe_clear_pickle_cache ();
};
#
fun build_executable_heap_image
freeze_policy # fzp::FREEZE_NONE/fzp::FREEZE_ONE/fzp::FREEZE_ALL
{ setup, # Always NULL in practice.
libfile_to_run, # E.g. "nowhere.lib"
wrapper_libfile, # One-line scratch .lib file created by bin/build-an-executable-mythryl-heap-image script.
heap_filename # Heapfile to create (i.e., executable), say "nowhere"
}
=
{ spopt = null_or::map make_standard_source_path setup;
libfile_to_run = make_standard_source_path libfile_to_run;
wrapper_libfile = make_standard_source_path wrapper_libfile;
timestamp = timestamp::last_file_modification_time heap_filename;
# timestamp is from
src/app/makelib/paths/timestamp.pkg library_source_index
=
lsi::make_library_source_index ();
#
fun do_libfile p
=
case (lfp::parse_libfile_tree_and_return_interlibrary_dependency_graph
(parse_arg
( library_source_index,
fzp::FREEZE_NONE,
p
)
) )
#
THE (g, gp)
=>
if (dagwalker_for_compile_command gp g) THE (make_bootlist g);
else NULL;
fi;
#
NULL => NULL;
esac;
set_up_list
=
case spopt
#
THE sp => the_else (do_libfile sp, []);
NULL => [];
esac;
#
fun in_setup (i, _)
=
list::exists
(fcx::same_info i o #1)
set_up_list;
# list is from
src/lib/std/src/list.pkg #
fun do_wrapper ()
=
case (do_libfile wrapper_libfile)
#
NULL => NULL;
THE l => THE ( map #2 ( set_up_list @ list::filter (not o in_setup) l) );
esac;
case (lfp::parse_libfile_tree_and_return_interlibrary_dependency_graph
(parse_arg
( library_source_index,
freeze_policy,
libfile_to_run
)
) )
#
THE (group, makelib_state)
=>
if (freeze_policy != fzp::FREEZE_NONE
or dagwalker_for_compile_command makelib_state group
)
# If none of the sourcefiles have been
# modified since the target was created,
# we don't need to rebuild:
#
case (timestamp, *makelib_state.timestamp_of_youngest_sourcefile_in_library) # This is the only place in the codebase where we actually *use* timestamp_of_youngest_sourcefile_in_library.
# # This field is actually computed in
src/app/makelib/compile/compile-in-dependency-order-g.pkg ( timestamp::TIMESTAMP target_timestamp,
timestamp::TIMESTAMP source_timestamp
)
=>
if (time::(<) (target_timestamp, source_timestamp)) do_wrapper ();
else THE [];
fi;
_ =>
do_wrapper ();
esac;
else
NULL;
fi;
#
NULL => NULL;
esac
then
maybe_clear_pickle_cache ();
};
#
fun redump_heap filename_for_heap_image: Void
=
fate::switch_to_fate *myc::rpl::redump_heap_fate filename_for_heap_image; # redump_heap_fate is from
src/lib/compiler/toplevel/interact/read-eval-print-loops-g.pkg # The following function is essentially the second half
# of the 'bin/build-an-executable-mythryl-heap-image'
# (aka sh/_build-an-executable-mythryl-heap-image) script
# to build an executable heap image file from a .lib file.
#
# The script invokes this function using a
# ' --build-an-executable-mythryl-heap-image' commandline switch
# kludged into bin/mythryld. It probably should be executed
# via a "'bin/mythryld -e 'your code here()', sort of mechanism,
# but we haven't implemented that yet. XXX BUGGO FIXME
#
fun build_an_executable_mythryl_heap_image buildargs
=
wnx::process::exit
#
case buildargs
#
[ libfile_to_run, libfile, heap, compiled_files_file, linkargs_file] => do_it (NULL, libfile_to_run, libfile, heap, compiled_files_file, linkargs_file);
[setup, libfile_to_run, libfile, heap, compiled_files_file, linkargs_file] => do_it (THE setup, libfile_to_run, libfile, heap, compiled_files_file, linkargs_file);
#
_ => { fil::say {. "bad arguments to --build-an-executable-mythryl-heap-image"; };
wnx::process::failure;
};
esac
where
#
fun do_it (setup, libfile_to_run, wrapper_libfile, heap_filename, compiled_files_file, linkargs_file)
=
case (build_executable_heap_image
fzp::FREEZE_NONE
{ setup,
libfile_to_run, # Master .lib to build the app, e.g. "nowhere.lib"
heap_filename, # "Executable" file to create, e.g. "nowhere"
wrapper_libfile # Scratch one-line .lib file created by bin/build-an-executable-mythryl-heap-image script.
}
)
#
NULL => { fil::say {. "Compilation failed."; }; wnx::process::failure; };
THE [] => { fil::say {. "Heap was already up-to-date."; }; wnx::process::success; };
#
THE l
=>
{ fun wrf (f, l)
=
{ s = fil::open_for_write f;
#
fun wr string
=
fil::write (s, string + "\n");
fil::say {.
cat ["\n",
" makelib-g.pkg: Creating file '", f, "'\n"
];
};
apply wr l;
fil::close_output s;
fil::say {. ""; };
};
s = fil::open_for_write compiled_files_file;
#
fun wr str
=
fil::write (s, str + "\n");
n = length l;
#
fun maxsz (s, n)
=
int::max (size s, n);
m = fold_forward maxsz 0 l;
wrf (compiled_files_file,
"# This file built by src/app/makelib/main/makelib-g.pkg: build_an_executable_mythryl_heap_image"
! "# for consumption by src/c/main/load-compiledfiles.c: BuildCompiled_FileList."
! "#"
! "# It gives a list of .compiled files to be linked together to form a Mythryl \"executable\" (heap image)."
! "#"
! "# Each line after the header specifies one .compiled file to load."
! "#"
! "# The lines are topogically sorted so that no .compiled file depends upon a later one."
! "#"
! "# A .compiled file is specified as either a simple filename, or else as a"
! "# FREEZEFILENAME@OFFSET: LIBRARY_DESCRIPTION triple giving the offset of the"
! "# compiledfile image within some library file, where LIBRARY_DESCRIPTION in turn"
! "# is a LIBFILE@OFFSET (SOURCEFILE) triple giving the .lib file which created"
! "# the library and the name of the source file which was compiled to produce"
! "# the .compiled file. (The second OFFSET is redundant with the first.)"
! cat ["FILES=", int::to_string n ]
! cat ["MAX_LINE_LENGTH=", int::to_string m ]
! ""
! l);
wrf (linkargs_file,
[cat [" --runtime-compiledfiles-to-load=", compiled_files_file]]);
wnx::process::success;
}
except
_ = wnx::process::failure;
esac;
end;
#
fun clear_state ()
=
{ cdo::clear_state ();
ltw::clear_state ();
#
lfp::clear_state (); # libfile_parser_g is from
src/app/makelib/parse/libfile-parser-g.pkg tc::clear_state (); # thawedlib_tome is from
src/app/makelib/compilable/thawedlib-tome.pkg ffr::clear_state (); # freezefile_roster_g is from
src/app/makelib/freezefile/freezefile-roster-g.pkg };
# Our tasks here are:
#
# 1) Load $ROOT/LIBRARY_CONTENTS into memory.
# 2) Compile and load primordial libfile "src/lib/core/init/init.cmi"
# 3) Set up primordial_library_hook for use elsewhere in file.
# 4) Preload the libraries listed in mcc::libraries_to_preload;
#
# Calling this function is the last
# thing done by 'read_''library_contents''_and_compile_''init_cmi''_and_preload_libraries'.
#
# This means that we, like it, are
# essentially executed at compiletime
# rather than runtime --
#
#
src/lib/core/internal/make-mythryld-executable.pkg #
# calls us -before- dumping to disk
# the heap image which becomes the
# mythryld "executable":
#
fun read_''library_contents''_and_compile_''init_cmi''_and_preload_libraries'
{
root_directory, # Contains src/ bin/ sh/ etc.
linking_mapstack,
run_commandline,
makelib_state
}
=
{
# print ("src/app/makelib/main/makelib-g.pkg/read_''library_contents''_and_compile_''init_cmi''_and_preload_libraries'/AAA: root_directory = " + root_directory + " cwd= " + (psx::current_directory()) + "\n");
##########################################################
# Saving an in-memory datastructure to disk is
# called "pickling", and the result is called
# a "pickle".
#
# In particular, the .compiled object-code files
# produced by the compiler consist of pickles
# plus a little relish.
#
# We identify pickles by 16-byte hashes of their
# contents, which we call "picklehashes".
#
# A library freezefile is essentially a collection
# of pickles, and to use it we mainly need to know
# which pickles are where, which we express by an
# index mapping picklehashes (abstract pickle names) to
# byte offsets (pickle locations within the freezefile).
#
# The file
#
# LIBRARY_CONTENTS
#
# contains one such an index for every freezefile
# in the src/* directory tree which is slated for
# inclusion in the mythryld executable, in a simple
# one-index-per-line text format. For more details,
# see its top-of-file comments or the code that creates
# it: write_picklehash_map() in
#
# src/app/makelib/mythryl-compiler-compiler/mythryl-compiler-compiler-g.pkg:
#
# Our next task is to load LIBRARY_CONTENTS into memory.
##########################################################
# picklehash is from
src/lib/compiler/front/basics/map/picklehash.pkg # string is from
src/lib/std/string.pkg # source_path_map is from
src/app/makelib/paths/source-path-map.pkg # Construct full pathname for
# the LIBRARY_CONTENTS file:
#
picklehash_map_file # Something like: "/home/cynbe/src/mythryl7.110.58/LIBRARY_CONTENTS"
=
pth::cat (
root_directory, # Root of Mythryl distribution sourcecode tree -- contains sh/ bin/ src/ ...
mcc::picklehash_map_filename # "LIBRARY_CONTENTS"
);
#
fun read_picklehash_map s
=
{ seed_libraries_index__local
:=
loop spm::empty;
}
where
#
fun loop seed_libraries_index
=
{ fun add_seed_library's_pickles_to_index
( lib, # Some string like: "$ROOT/src/lib/core/internal/makelib-internal.lib"
pickles # Some list like: [ "38830:0868B4FAE15B953295FA742D8CAC2A73", "265848:B47207DB3FD2774954EA9DC70B9EAA8D" ]
)
=
# Map the ad::File for the foo.lib library name
# to the contents of the library, in the form of
# a map from file byte-offsets to pickles, where
# the pickles in turn are in turn (Picklehash,Chunk)
# pairs (in essence):
#
spm::set (
#
seed_libraries_index,
#
ad::decode anchor_dictionary lib, # Resolve text library name into internal ad::File representation.
#
fold_forward parse_pickles im::empty pickles
)
where
#
fun parse_pickles
(
pickle_info, # Some string like: "38830:0868B4FAE15B953295FA742D8CAC2A73" -- byte_offset_in_freezefile followed by hash_of_pickle.
byteoffset_to_pickle_map # Given the byte offst of a pickle in a freezefile, returns pickle as a singleton linktable mapping (Picklehash -> Chunk)
)
=
case (string::tokens (\\ c = c == ':') pickle_info) # E.g., split "38830:0868B4FAE15B953295FA742D8CAC2A73" into [ "38830", "0868B4FAE15B953295FA742D8CAC2A73" ].
#
[ decimal_byte_offset_in_freezefile, hex_picklehash ]
=>
case ( ph::from_hex hex_picklehash, # Convert picklehash from ascii string to binary in-ram form.
int::from_string decimal_byte_offset_in_freezefile # Convert byte-offset from ascii string to Int form.
)
#
(THE picklehash, THE byte_offset_in_freezefile)
=>
case (lt::get linking_mapstack picklehash)
#
THE chunk
=>
im::set
( byteoffset_to_pickle_map,
byte_offset_in_freezefile,
lt::singleton (picklehash, chunk)
);
#
NULL => byteoffset_to_pickle_map; # Is this another "impossible" case being silently ignored? Or...? XXX BUGGO FIXME
esac;
#
_ => byteoffset_to_pickle_map; # Ascii-to-binary conversion failed(?!) -- silently ignore this pickle. XXX BUGGO FIXME.
esac;
#
_ => byteoffset_to_pickle_map; # Breaking pickle on ':' failed to produce two strings?! Silently ignore it. XXX BUGGO FIXME.
esac;
end;
# A sample line from LIBRARY_CONTENTS looks like:
#
# $ROOT/
src/lib/core/internal/makelib-internal.lib 38830:0868B4FAE15B953295FA742D8CAC2A73 265848:B47207DB3FD2774954EA9DC70B9EAA8D
#
# The logical structure here is:
#
# library: $ROOT/
src/lib/core/internal/makelib-internal.lib # list-of-compiledfiles-in-library: 38830:0868B4FAE15B953295FA742D8CAC2A73 265848:B47207DB3FD2774954EA9DC70B9EAA8D
#
# Here $ROOT is the root directory of the Mythryl source distribution, say /home/cynbe/src/mythryl-110.58
#
# In practice we are interested not in
#
# makelib-internal.lib
#
# itself but rather in
#
# makelib-internal.lib.frozen
#
# which contains all the compiled code for the library. This file
# is structured essentially as a sequence of "pickles" -- compiled
# sourcefiles is on-disk form.
#
# The compiledfile references are structured as
#
# byte_offset_in_freezefile:picklehash_for_compiledfile
#
# pairs, which tell us the two things we initially want to
# know about a pickle:
#
# o What byte offset to seek to in makelib-internal.lib.frozen
# in order to read it.
#
# o The 16-byte 'picklehash' (message digest hash of the pickle)
# which we use internally to identify that pickle.
#
case (fil::read_line s)
#
NULL => seed_libraries_index; # No more lines in LIBRARY_CONTENTS file, so return result.
#
THE line # Got next line from LIBRARY_CONTENTS file.
=>
if (string::get_byte_as_char (line, 0) == '#') # Is it a comment line?
#
loop seed_libraries_index; # Yes, ignore it.
else
case (string::tokens char::is_space line) # Break line up into tokens delimited by whitespace.
#
lib ! pickles => loop (add_seed_library's_pickles_to_index( lib, pickles ));
_ => loop seed_libraries_index; # Some sort of garbage line, silently ignore it. XXX BUGGO FIXME.
esac;
fi;
esac;
}; # fun loop
end; # fun read_picklehash_map
# The following will print something like:
#
#
src/app/makelib/main/makelib-g.pkg about to open picklehash_map_file /mythryl7/mythryl7.110.58/mythryl7.110.58/LIBRARY_CONTENTS: cwd = /mythryl7/mythryl7.110.58/mythryl7.110.58
#
# print ("src/app/makelib/main/makelib-g.pkg about to open picklehash_map_file " + picklehash_map_file + ": cwd = " + (psx::current_directory()) + "\n");
safely::do
{
open_it => {. fil::open_for_read picklehash_map_file; },
close_it => fil::close_input,
cleanup => \\ _ = ()
}
read_picklehash_map;
mythryl_primordial_library # "$ROOT/src/lib/core/init/init.cmi"
=
make_standard_source_path mcc::mythryl_primordial_library;
# library_source_index is from
src/app/makelib/stuff/library-source-index.pkg # timestamp is from
src/app/makelib/paths/timestamp.pkg # freezefile is defined above, via freezefile_g().
fun load_primordial_library ()
=
fzf::load_freezefile
#
{ get_library => \\ _ = raise exception DIE "makelib-g.pkg: load_primordial_library",
saw_errors => REF FALSE
}
#
( makelib_state,
mythryl_primordial_library,
NULL # 'makelib_version_intlist' info XXX BUGGO DELETME
, [] # MUSTDIE
);
case (load_primordial_library ())
#
THE primordial_library
=>
{ cdo::clear_state ();
ltw::clear_state ();
my { per_fat_tome_fns_to_compile_after_dependencies, ... }
=
cdo::make_dependency_order_compile_fns
{
root_library => primordial_library,
maybe_drop_thawedlib_tome_from_linker_map => \\ _ = \\ _ = (),
set__compiledfile__for__thawedlib_tome => \\ _ = ()
};
my { exports => linking_dagwalk_map, ... }
=
ltw::make_linking_dagwalk
(
primordial_library,
\\ _ = raise exception DIE "init: get bfc?"
);
#
fun get_symbol_dagwalk (dagwalk_map, symbol)
=
case (sym::get (dagwalk_map, symbol))
#
THE dagwalk => dagwalk;
NULL => raise exception DIE "init: bogus init library (1)";
esac;
stipulate
pervasive_symbol = ps::pervasive_package_symbol; # Get symbol for "<Pervasive>".
herein
pervasive_compile_dagwalk = get_symbol_dagwalk ( per_fat_tome_fns_to_compile_after_dependencies, pervasive_symbol );
pervasive_linking_dagwalk = get_symbol_dagwalk ( linking_dagwalk_map, pervasive_symbol );
end;
#
fun do_dagwalk dagwalk
=
case (dagwalk makelib_state)
#
THE r => r;
NULL => raise exception DIE "init: bogus init library (2)";
esac;
(do_dagwalk pervasive_compile_dagwalk)
->
{ symbolmapstack => pervasive_symbolmapstack,
inlining_mapstack => pervasive_inlining_mapstack
};
pervasive_linking_mapstack
=
do_dagwalk pervasive_linking_dagwalk;
pervasive_fun_etc_defs
=
cms::make_compiler_mapstack_set
{
symbolmapstack => pervasive_symbolmapstack,
linking_mapstack => pervasive_linking_mapstack,
inlining_mapstack => pervasive_inlining_mapstack
};
#
fun bare_autoload x
=
{ fil::say {. cat ["!* ", x, ": \"autoload\" not available, using \"make\""]; };
make x;
};
cs::pervasive_fun_etc_defs_jar.set_mapstack_set
#
pervasive_fun_etc_defs;
(cs::get_top_level_pkg_etc_defs_jar ()).set_mapstack_set
#
cms::null_compiler_mapstack_set; # redundant? XXX BUGGO FIXME
primordial_library_hook
:=
THE { primordial_library };
# preload is from
src/app/makelib/main/preload.pkg # 'load' all the libraries which are
# to be preloaded into the final
# mythryld executable image:
#
preload::load make mcc::libraries_to_preload;
THE run_commandline;
};
#
NULL => raise exception DIE "makelib-g.pkg: Unable to load primordial libfile init.cmi";
#
esac;
}; # fun read_''library_contents''_and_compile_''init_cmi''_and_preload_libraries'
end; # stipulate ... in ...
#
fun show_controls (getarg, getval, padval) level
=
{ fun walk indent (global_control_index::INDEX_TREE rt)
=
{ include package printf_combinator; # printf_combinator is from
src/lib/src/printf-combinator.pkg fun say strings = fil::say {. cat strings; };
rt -> { help, control_set, subregs, path };
#
fun one ci
=
{ arg = cat
(fold_backward
(\\ (s, r) = s ! "::" ! r)
[getarg ci]
path
);
value = getval ci;
size' = size value;
lw = *control_print::linewidth;
padsz = lw - 6 - size arg - indent;
if (padsz < size')
#
padsz' = int::max (lw, size' + 8 + indent);
format' say (sp (indent + 6) o
text arg o nl o
padval padsz' (text value)
);
else
format' say ( sp (indent + 6)
o text arg
o padval padsz (text value)
);
fi;
};
case (control_set, subregs)
#
([], []) => ();
#
_ => { format' say (sp indent o text help o text ":" o nl);
apply one control_set;
apply (walk (indent + 1)) subregs;
};
esac;
};
#
fun inc n
=
n + 1;
# global_control_index is from
src/lib/global-controls/global-control-index.pkg # basic_control is from
src/lib/compiler/front/basics/main/basic-control.pkg walk 2 (global_control_index::controls
(basic_control::top_index, null_or::map inc level));
};
#
fun show_control_setting level
=
show_controls
(
\\ ci = (global_control::name ci.control + " = "),
\\ ci = global_control::get ci.control,
\\ _ = \\ ff = ff
)
level;
#
fun show_controls' ()
=
{ show_control_setting NULL;
#
fil::say {. cat [ "\nTo get a control value interactively: show_control \"mythryl_parser::show_interactive_result_types\";" ]; };
fil::say {. cat [ "To set a control value interactively: set_control \"mythryl_parser::show_interactive_result_types\" \"TRUE\";" ]; };
fil::say {. cat [ "To do same thing at commandline: my -Cmythryl_parser::show_interactive_result_types=TRUE" ]; };
};
stipulate
# global_control_index is from
src/lib/global-controls/global-control-index.pkg # basic_control is from
src/lib/compiler/front/basics/main/basic-control.pkg # global_control is from
src/lib/global-controls/global-control.pkg find_control
=
global_control_index::find_control
basic_control::top_index;
#
fun split_control_path path
=
string::tokens (\\ c = c == ':') path;
herein
#
fun show_control name
=
if (name == "")
#
print "Control name must be non-empty\n";
else
case (find_control (split_control_path name))
#
NULL => fil::say {. cat ["!* no such control: ", name, "\n"]; };
THE control => print (global_control::get control + "\n");
esac;
fi;
#
fun set_control''' name value
=
case (find_control (split_control_path name))
#
NULL => fil::say {. cat ["!* no such control: ", name, "\n"]; };
#
THE control =>
#
global_control::set (control, value)
except
global_control::BAD_VALUE_SYNTAX vse
=
fil::say {.
cat [ "!* unable to parse value `",
vse.value, "' for ",
vse.control_name, " : ",
vse.name_of_type, "\n"
];
};
esac;
#
fun set_control'' name value
=
if (name == "") print "Control name must be non-null\n";
else set_control''' name value;
fi;
#
fun set_control'
bad #
is_config # FALSE
spec # "name=value"
=
{
my (name, value)
=
substring::split_off_prefix {. #c != '='; } spec;
name = substring::to_string name;
value = substring::to_string
if (substring::size value > 0)
substring::make_slice (value, 1, NULL);
else value;
fi;
if (name == "")
#
bad ();
#
elif is_config
#
set_control''' name value;
#
elif (value == "")
#
# #define $name 1
#
(mps::find_makelib_preprocessor_symbol name).set (THE 1);
else
case (int::from_string value)
#
THE i => (mps::find_makelib_preprocessor_symbol name).set (THE i); # #define $name i
NULL => bad ();
esac;
fi;
};
end; # stipulate
#
fun set_control spec
=
set_control'
{. print "Bad option\n"; }
TRUE # is_config
(substring::from_string spec); # "name=value"
herein # outermost 'stipulate'
# We get called ultimately by
#
src/lib/core/internal/make-mythryld-executable.pkg # via
#
src/lib/core/internal/make-mythryl-compiler-etc.pkg # shortly before it dumps the heap image
# which becomes our standard mythryld
# make/compiler executable (see top of file
# comments for details).
#
# Thus, we essentially do this initialization
# at the compiler's compiletime rather than
# at its runtime.
#
# Runtime arguments:
#
# read_eval_print_from_stream,
# #
# # Ultimately defined in
# #
src/lib/compiler/toplevel/interact/read-eval-print-loop-g.pkg # # We pass this to
# #
src/app/makelib/compile/compile-in-dependency-order-g.pkg # # which uses it to execute pre/post 'setup' sourcecode fragments
# # extracted originally from .lib files.
#
# read_eval_print_from_file
# #
# # Defined in
# #
src/lib/compiler/toplevel/interact/read-eval-print-loops-g.pkg # # as a wrapper of above.
#
# read_eval_print_from_user
# #
# # Likewise defined in
# #
src/lib/compiler/toplevel/interact/read-eval-print-loops-g.pkg # # but as a wrapper for read_eval_print_from_user in
# #
src/lib/compiler/toplevel/interact/read-eval-print-loop-g.pkg #
fun read_''library_contents''_and_compile_''init_cmi''_and_preload_libraries
( root_directory, # Contains sh/ bin/ src/ ...
linking_mapstack,
parse_string_to_raw_declarations,
compile_raw_declaration_to_package_closure,
link_and_run_package_closure,
read_eval_print_from_user,
read_eval_print_from_stream, # We pass this to compile-dependency-graph-walk, to evaluate sourcecode fragments.
read_eval_print_from_file, # We use this to compile vanilla commandline source files like foo.pkg
errorwrap
)
=
{
makelib_state
=
{ library_source_index => lsi::make_library_source_index (),
plaint_sink => err::default_plaint_sink (),
#
timestamp_of_youngest_sourcefile_in_library
=>
REF timestamp::ancient, # Set up to track most recent (known) edit of any sourcefile in the library.
makelib_session
=>
make_makelib_session
{
we_are_a_subprocess => FALSE,
keep_going_after_compile_errors => FALSE
}
};
#
fun eval_string code_string # This should be a supported, exported 'eval' function. XXX BUGGO FIXME
=
safely::do
{
open_it => {. fil::open_string (code_string + " ;;"); },
close_it => fil::close_input,
cleanup => \\ _ = ()
}
read_eval_print_from_stream;
eval_hook := eval_string;
fun run_commandline ()
#
# Function to process Unix command-line switches
# and filename arguments given to mythryld.
#
# We get called (only...?) from main() in
#
#
src/lib/core/internal/mythryld-app.pkg #
# NB: Any options starting with --runtime
# will already have been eaten by
#
# src/c/main/runtime-options.c
=
{ make = errorwrap (ignore o make );
#
fun process_filename (filename, mk, ("api"
| "pkg") ) => read_eval_print_from_file filename;
process_filename (filename, mk, "lib" ) => mk filename;
process_filename (filename, mk, extension ) => fil::say {. cat ["!* unable to process `", filename, "' (unknown extension `", extension, "')\n"]; };
end;
#
fun help level
=
{ fil::say {. cat
["mythryld [rtsargs] [options] [files]\n\
\\n\
\ run time system args:\n\
\ --runtime-heap-image-to-run=<h> (start specified heap image)\n\
\ --runtime-gc-gen0-bufsize=<s> (gc generation-zero buffer size)\n\
\ --runtime-cmdname=<n> (set command name)\n\
\ --runtime-verbosity=<n> (set level of runtime verbosity)\n\
\ --runtime-show-code-chunk-comments (list code heapchunks)\n\
\ --runtime-debug=<f> (write debugging info to file)\n\
\\n\
\ files:\n\
\ <file>.lib (makelib::make)\n\
\ <file>.api (run)\n\
\ <file>.pkg (run)\n\
\\n\
\ options:\n\
\ -e 'expression' (Evaluate and print 'expression', then quit.)\n\
\ -x 'expression' (Like -e, but also prints a newline.)\n\
\ -E 'expression' (Like -E, but does not quit.)\n\
\ -D<name>=<v> (set makelib variable to given value)\n\
\ -D<name> (set makelib variable to 1)\n\
\ -Uname (unset makelib variable)\n\
\ -C<control>=<v> (set named control)\n\
\ -H (produce complete help listing)\n\
\ -h (produce minimal help listing)\n\
\ -h<level> (help with obscurity limit)\n\
\ -S (list all current settings)\n\
\ -s<level> (limited list of settings)\n\
\ -P (list all preprocessor variables)\n\
\ -p<level> (limited list of preprocessor variables)\n\
\ --no-prompt (Disable interactive mode prompts)\n\
\n\
\Do bin/mythryld to start an interactive session.\n\
\n"]; };
show_controls (global_control::name o .control,
\\ ci =
cat ["(", .help (global_control::info ci.control),
")"],
printf_combinator::pad printf_combinator::left)
level;
# global_control is from
src/lib/global-controls/global-control.pkg # printf_combinator is from
src/lib/src/printf-combinator.pkg };
#
fun show_env_vars level
=
show_controls
( \\ ci = (global_control::name ci.control + ":"),
\\ ci = null_or::the_else (ci.info.dictionary_name, "(none)"),
printf_combinator::pad printf_combinator::left
)
level;
#
fun badopt opt f ()
=
fil::say {.
cat ["!* bad ", opt, " option: `", f, "'\n",
"!* try `-h' or `-h<level>' for help\n"];
};
#
fun quit ()
=
wnx::process::exit
wnx::process::success;
#
fun quit_if TRUE => quit ();
quit_if FALSE => ();
end;
# This function mainly handles Unix commandline arguments of the form -Xyyy
# where X is a switch char and yyy is some argument string for it. (Ick. XXX BUGGO FIXME. Change to usual GNU conventions.)
#
# We also arrive here for anything else
# not previously recognized as a switch,
# in particular for filename arguments.
#
# First argument is the two-char "-X" argument prefix.
# Second argument is the full argument.
# Third argument is either 'automake' or 'make' function, per last -a or -m switch.
# Fourth argument is TRUE iff there is more stuff remaining on commandline.
#
# What 'carg' is supposed to mean, I haven't a clue. continued_arg maybe. ("commandline_arg"? "control_arg"? "config_arg"? "compound arg"?) XXX BUGGO FIXME pick a decent name.
#
fun carg ( opt as ("-C"
| "-D"), f, _, _)
=>
{ bad = badopt opt f;
spec = substring::extract (f, 2, NULL); # substring is from
src/lib/std/substring.pkg is_config = opt == "-C";
set_control' bad is_config spec;
};
carg ("-U", f, _, _) => case (string::extract (f, 2, NULL))
#
"" => badopt "-U" f ();
var => (mps::find_makelib_preprocessor_symbol var).set NULL; # #undef $var
esac;
carg ("-h", f, _, last) => { case (string::extract (f, 2, NULL))
#
"" => help (THE 0);
level => help (int::from_string level);
esac;
quit_if last;
};
carg ("-s", f, _, last) => { case (string::extract (f, 2, NULL))
#
"" => show_control_setting (THE 0);
level => show_control_setting (int::from_string level);
esac;
quit_if last;
};
carg ("-p", f, _, last) => { case (string::extract (f, 2, NULL))
#
"" => show_env_vars (THE 0);
level => show_env_vars (int::from_string level);
esac;
quit_if last;
};
carg (_, filename, mk, _) => process_filename (
filename,
mk,
string::map char::to_lower (the_else (wnx::path::ext filename, "<none>"))
);
# string is from
src/lib/std/string.pkg # char is from
src/lib/std/char.pkg # winix__premicrothread is from
src/lib/std/winix--premicrothread.pkg end;
interactive
=
myp::print_interactive_prompts;
unparse_result
=
myp::unparse_result;
just_return = REF FALSE;
force_interactive = REF FALSE; # temporary kludge
# Process all commandline arguments,
# both switches and filenames:
#
fun args ("-H" ! rest, mk) => { help NULL; args_q (rest, mk); };
args ("-S" ! rest, mk) => { show_control_setting NULL; args_q (rest, mk); };
args ("-P" ! rest, mk) => { show_env_vars NULL; args_q (rest, mk); };
args ("-z" ! rest, mk) => { just_return := TRUE; args (rest, mk); };
args ("-q" ! _, _) => quit ();
args ("-i" ! _, _) => { force_interactive := TRUE; myp::print_interactive_prompts := TRUE; };
args ("--build" ! rest, _) => build_an_executable_mythryl_heap_image rest;
args ("--build-an-executable-mythryl-heap-image" ! rest, _) => build_an_executable_mythryl_heap_image rest;
args (["--redump", heapfile], _)
=>
redump_heap heapfile;
args ("-e" ! code_string ! rest, mk)
=>
{ interactive := FALSE;
eval_string code_string;
quit ();
};
args ("-x" ! code_string ! rest, mk)
=>
{ interactive := FALSE;
eval_string code_string;
print "\n";
quit ();
};
args ("-E" ! code_string ! rest, mk)
=>
{ interactive := FALSE;
eval_string code_string;
interactive := TRUE;
args( rest, mk );
};
args (filename ! rest, mk)
=>
{ carg
( string::substring (filename, 0, 2) except exceptions::INDEX_OUT_OF_BOUNDS = "",
filename,
mk, # make
list::null rest
);
args (rest, mk);
};
args ([], _) => ();
end
also
fun args_q ([], _) => quit ();
args_q (rest, f) => args (rest, f);
end;
# winix_base_text_file_io_driver_for_posix__premicrothread is from
src/lib/std/src/io/winix-base-text-file-io-driver-for-posix--premicrothread.pkg # winix__premicrothread is from
src/lib/std/winix--premicrothread.pkg # winix_text_file_for_os_g__premicrothread is from
src/lib/std/src/io/winix-text-file-for-os-g--premicrothread.pkg # This fn is duplicated between here and
src/lib/compiler/toplevel/interact/read-eval-print-loop-g.pkg XXX BUGGO FIXME
#
fun input_is_tty f
=
{ (fil::pur::get_reader (fil::get_instream f)) # "pur" == "pure" (I/O).
->
(rd, buf);
is_tty
=
case rd
#
winix_base_text_file_io_driver_for_posix__premicrothread::FILEREADER { io_descriptor => THE iod, ... }
=>
(wnx::io::iod_to_iodkind iod == wnx::io::CHAR_DEVICE);
_ => FALSE;
esac;
# Since getting the reader will have terminated
# the stream, we now need to build a new stream:
#
fil::set_instream (f, fil::pur::make_instream (rd, buf) );
is_tty;
};
case (cmd::get_commandline_arguments ())
#
l =>
{
# The next line was part of a failed attempt
# to get multi-core 'make-compiler' compiles
# working: XXX BUGGO FIXME
#
# fil::set_process_name_in_logfile "MYTHRYLD";
fil::set_logger_to (fil::LOG_TO_FILE "mythryl.compile.log");
args (l, make); # Process all commandline switches and arguments.
if (not *just_return)
if (input_is_tty fil::stdin
or *force_interactive)
#
read_eval_print_from_user ();
quit ();
fi;
interactive := FALSE;
unparse_result := FALSE;
fi;
# Issue the interactive blurb. # I think the below code paragraph may now be dead code ripe to delete.
# We delay doing this until commandline # In particular, if one does 'mythryld' at the Linux commandline,
# switches have been processed, so as # the banner gets printed by the logic in read_eval_print_from_user() in
src/lib/compiler/toplevel/interact/read-eval-print-loop-g.pkg # to be able to disable it with --no-prompt: # not by the below logic. -- 2015-09-01 CrT
#
if *myp::print_interactive_prompts
#
print "\n";
print mcv::mythryl_interactive_banner; # Something like: "Mythryl 110.58.3.0.2 built Thu Dec 23 14:11:49 2010"
print "\nDo help(); for help (interact)";
fi;
};
esac;
};
read_eval_print_from_stream__hook := read_eval_print_from_stream; # Set hook to read_eval_print_from_stream from
src/lib/compiler/toplevel/interact/read-eval-print-loop-g.pkg parse_string_to_raw_declarations__hook := parse_string_to_raw_declarations; # Set hook to parse_string_to_raw_declarations from
src/lib/compiler/toplevel/interact/read-eval-print-loop-g.pkg compile_raw_declaration_to_package_closure__hook := compile_raw_declaration_to_package_closure; # Set hook to compile_raw_declaration_to_package_closure from
src/lib/compiler/toplevel/interact/read-eval-print-loop-g.pkg link_and_run_package_closure__hook := link_and_run_package_closure; # Set hook to link_and_run_package_closure from
src/lib/compiler/toplevel/interact/read-eval-print-loop-g.pkg read_''library_contents''_and_compile_''init_cmi''_and_preload_libraries'
{
root_directory,
linking_mapstack,
run_commandline,
makelib_state
};
}; # fun read_''library_contents''_and_compile_''init_cmi''_and_preload_libraries
#
fun help ()
=
apply
print
[ "\n\n",
" Mythryl Interactive Help\n",
"\n",
"You are interacting with an incremental compiler for\n",
"Mythryl, an advanced posix-flavored mostly-functional\n",
"programming language.\n",
"\n",
"Enter one expression per line.\n",
"\n",
"Examples:\n",
" 2+2;\n",
" print \"Hello, world!\\n\";\n",
" print `ls -l`;\n",
" printf \"%d %g\\n\" (1 << 3) (sin 0.3);\n",
" for (i=0; i<10; ++i) { printf \"%d\\n\" i; };\n",
" fun hello () = print \"Hello, world!\\n\";\n",
" hello ();\n",
"\n",
"Some useful commands:\n",
"\n",
" # List values, functions, packages and APIs defined at top level:\n",
" show_all ();\n",
" show_apis(); # As above, showing only API defs\n",
" show_pkgs(); # As above, showing only package defs\n",
" show_vals(); # value defs\n",
" show_types(); # type defs\n",
" show_generics(); # generic defs\n",
"\n",
" show_api \"Integer\"; # Show definition of Integer API\n",
" show_pkg \"control\"; # Mainly useful for packages with anonymous APIs.\n",
"\n",
" # Display all compiler configuration variables:\n",
" show_controls();\n",
"\n",
" # Load hello lib into ram, first re/compiling as needed:\n",
" make \"src/app/tut/hello/hello.lib\";\n",
"\n",
" # Make hello.lib library freezefile 'hello.lib.frozen':\n",
" freeze \"src/app/tut/hello/hello.lib\";\n",
"\n",
"Type <Ctrl>-D to exit. (<Ctrl>-Q <Ctrl>-D in emacs.)\n"
];
# This package defines the externally visible 'makelib', exported by
#
#
src/lib/core/makelib/makelib.pkg #
# sealed with the Makelib api from
#
#
src/lib/core/internal/makelib.api #
package makelib_external {
Controller(X) = { get: Void -> X,
set: X -> Void
};
# makelib_defaults is from
src/app/makelib/stuff/makelib-defaults.pkg # libfile_parser_g is from
src/app/makelib/parse/libfile-parser-g.pkg package control {
#
verbose = mld::verbose;
parse_caching = mld::parse_caching;
#
warn_on_obsolete_syntax = mld::warn_on_obsolete_syntax;
debug = mld::debug;
conserve_memory = mld::conserve_memory;
#
generate_index = mld::generate_index;
#
keep_going_after_compile_errors
=
mld::keep_going_after_compile_errors;
};
package freezefile_db {
#
Freezefile = ad::File;
#
known = lfp::list_freezefiles;
describe = ad::describe;
#
os_string = ad::os_string;
dismiss = lfp::dismiss_freezefile;
#
fun unshare library
=
{ ltw::unshare library;
#
dismiss library;
};
};
package makelib_state {
#
clear_state = clear_state;
dump = dump_api_reference;
dump_latex = latex_dump_api_reference;
};
compile = compile; # Defined above by my compile = ... [ LATER ] This probably doesn't belong in the scripting globals -- not of broad/frequent enough interest.
search_lib_load_path_for_file = llp::search_lib_load_path_for_file; # [ LATER ] This probably doesn't belong in the scripting globals -- not of broad/frequent enough interest.
help = help;
make = make; /* DEPRECATED */ # Defined above by my make = ...
load = make; /* DEPRECATED */ # For now (at least) this is just a synonym for 'make', intended to read better at the top of scripts.
use = make; # Another synonym for 'make'. Perl has this right: Scripters care about making the library available;
# they don't care about compiling vs loading etc. DEPRECATING 'make' and 'load' here.
freeze = freeze' { recursively => TRUE };
freeze' = freeze';
show_all = show_all;
show_apis = show_apis;
show_pkgs = show_pkgs;
show_vals = show_vals;
show_types = show_types;
show_generics = show_generics;
show_controls = show_controls';
show_control = show_control;
set_control = set_control'';
show_api = show_api;
show_pkg = show_pkg;
sources = sources;
get_makelib_preprocessor_symbol_value
=
mps::find_makelib_preprocessor_symbol;
load_plugin = cwd_load_plugin;
build_executable_heap_image
=
build_executable_heap_image;
fun parse_string_to_raw_declarations arg = *parse_string_to_raw_declarations__hook arg;
fun compile_raw_declaration_to_package_closure arg = *compile_raw_declaration_to_package_closure__hook arg;
fun link_and_run_package_closure arg1 arg2 = *link_and_run_package_closure__hook arg1 arg2;
package graph = package {
graph = to_portable;
};
redump_heap = redump_heap;
# Random stuff we want to be defined globally at the
# interactive prompt. This gets 'included' by
#
src/lib/core/internal/make-mythryld-executable.pkg # There's probably a cleaner way to do this.
# These are available as unqualified names in scripts;
# they may be accessed as makelib::scripting_globals::foo
# in non-script code:
#
package scripting_globals { # NB: If you change types or values in scripting_globals you'll want make matching changes in
src/lib/core/internal/makelib.api (_!) = multiword_int::(_!); # Factorial.
# Note: The (_[]) enables 'vec[index]' notation;
# The (_[]:=) enables 'vec[index] := value' notation;
#
# (_[]) = string::get_byte_as_char;
# (_[]) = rw_vector::get;
(_[]:=) = rw_vector::set;
in = list::in;
exit = wnx::process::exit;
exit_x = wnx::process::exit_x;
bin_sh = spawn__premicrothread::bin_sh;
bin_sh' = wnx::process::bin_sh';
#
fun round f = f8b::to_int ieee_float::TO_NEAREST f;
atoi = sj::atoi;
atod = sj::atod;
basename = sj::basename;
dirname = sj::dirname;
trim = sj::trim;
#
fun die message = { print message; exit 1; };
fun die_x message = { print message; exit_x 1; };
=~ = regex::(=~);
chomp = string::chomp;
chdir = wnx::file::change_directory;
environ = psx::environment;
explode = string::explode;
factors = int::factors;
fields = string::fields;
filter = list::filter;
fscanf = scanf::fscanf;
getcwd = wnx::file::current_directory;
getenv = wnx::process::get_env;
getpid = wnx::process::get_process_id;
getppid = psx::get_parent_process_id;
getuid = psx::get_user_id;
geteuid = psx::get_effective_user_id;
getgid = psx::get_group_id;
getegid = psx::get_effective_group_id;
getgroups = psx::get_group_ids;
getlogin = psx::get_login;
getpgrp = psx::get_process_group;
setgid = psx::set_group_id;
setpgid = psx::set_process_group_id;
setsid = psx::set_session_id;
setuid = psx::set_user_id;
implode = string::implode;
iseven = \\ i = i & 1 == 0;
isodd = \\ i = i & 1 == 1;
isprime = int::is_prime;
join = string::join;
join' = string::join';
lstat = psx::lstat;
mkdir = (\\ path = psx::mkdir (path, psx::s::flags [ psx::s::irwxu, psx::s::irgrp, psx::s::iwgrp, psx::s::iroth, psx::s::iwoth ])); # XXX BUGGO FIXME somehow this is producing 744 instead of 755.
now = time::to_float_seconds o time::get_current_time_utc;
product = int::product;
rename = psx::rename;
rmdir = psx::rmdir;
shuffle = list_shuffle::shuffle;
shuffle' = list_shuffle::shuffle';
sleep = wnx::process::sleep;
sort = lms::sort_list;
sorted = lms::list_is_sorted;
scanf = scanf::scanf;
sscanf = scanf::sscanf;
stat = psx::stat;
strcat = string::cat;
strlen = string::length_in_bytes;
strsort = (lms::sort_list string::(>));
struniqsort = (lms::sort_list_and_drop_duplicates string::compare);
sum = int::sum;
symlink = psx::symlink;
time = psx::get_elapsed_seconds_since_1970; # NB: 'now' has much more precision.
tolower = string::to_lower;
toupper = string::to_upper;
tokens = string::tokens;
uniquesort = lms::sort_list_and_drop_duplicates;
unlink = psx::unlink;
words = string::tokens char::is_space;
dotqquotes__op = words; # So that ."a b c d e f" == ["a", "b", "c", "d", "e", "f"]
backticks__op = words; # So that ."a b c d e f" == ["a", "b", "c", "d", "e", "f"]
#
# The following String -> X symbols are initialized in
#
src/lib/core/init/pervasive.pkg # and we leave them at those values. We mostly use
# them to quote regular expressions:
#
# dotquotes__op = identity; # .'foo'
# dotbrokets__op = identity; # .<foo>
# dotbarets__op = identity; # .
|foo|
# dotslashets__op = identity; # ./foo/
# dothashets__op = identity; # .#foo#
# dotbackticks__op = identity; # .`foo`
#
# NB: We also have the X -> Y symbols
|i| <i> /i/ {i} <i| |i>.
# They may be set via
# (
|_|) = foo;
# (<_>) = foo;
# (/_/) = foo;
# ({_}) = foo;
# (<_
|) = foo;
# (
|_>) = foo;
#
# I wonder if we shouldn't also have a .[_]: List(X) -> Y syntax.
arg0 = cmd::get_program_name; # XXX BUGGO FIXME For scripts this comes out "bin/my" or "/usr/bin/my" or such, which is not helpful.
argv = cmd::get_commandline_arguments;
# NB: The following have the perl-inspired
# lexer-implemented synonyms
# -F -D -P -L -S -C -B
#
fun isfile filename = psx::stat::is_file (psx::stat filename) except _ = FALSE;
fun isdir filename = psx::stat::is_directory (psx::stat filename) except _ = FALSE;
fun ispipe filename = psx::stat::is_pipe (psx::stat filename) except _ = FALSE;
fun issymlink filename = psx::stat::is_symlink (psx::lstat filename) except _ = FALSE;
fun issocket filename = psx::stat::is_socket (psx::stat filename) except _ = FALSE;
fun ischardev filename = psx::stat::is_char_dev (psx::stat filename) except _ = FALSE;
fun isblockdev filename = psx::stat::is_block_dev (psx::stat filename) except _ = FALSE;
# I would like these to return TRUE if
# the effective uid may do the indicated
# operation. I don't know if this code
# implements exactly that, but it is a
# quick first cut, at least. XXX BUGGO FIXME
#
# NB: The following have the perl-inspired
# lexer-implemented synonyms
# -R -W -X
#
fun mayread filename = wnx::file::access (filename, [wnx::file::MAY_READ]) except _ = FALSE;
fun maywrite filename = wnx::file::access (filename, [wnx::file::MAY_WRITE]) except _ = FALSE;
fun mayexecute filename = wnx::file::access (filename, [wnx::file::MAY_EXECUTE]) except _ = FALSE;
# These are used in
#
src/lib/src/eval-unit-test.pkg # There must be a cleaner way! *ruefulgrin* XXX BUGGO FIXME
#
eval_kludge_ref_int = REF 0;
eval_kludge_ref_float = REF 0.0;
eval_kludge_ref_string = REF "";
#
eval_kludge_ref_list_int = REF []: Ref( List( Int ) );
eval_kludge_ref_list_float = REF []: Ref( List( Float ) );
eval_kludge_ref_list_string = REF []: Ref( List( String ) );
#
fun eval code_string
= *eval_hook code_string;
#
fun evali user_code = { eval("makelib::scripting_globals::eval_kludge_ref_int := (" + user_code + ")"); *eval_kludge_ref_int; };
fun evalf user_code = { eval("makelib::scripting_globals::eval_kludge_ref_float := (" + user_code + ")"); *eval_kludge_ref_float; };
fun evals user_code = { eval("makelib::scripting_globals::eval_kludge_ref_string := (" + user_code + ")"); *eval_kludge_ref_string; };
#
fun evalli user_code = { eval("makelib::scripting_globals::eval_kludge_ref_list_int := (" + user_code + ")"); *eval_kludge_ref_list_int; };
fun evallf user_code = { eval("makelib::scripting_globals::eval_kludge_ref_list_float := (" + user_code + ")"); *eval_kludge_ref_list_float; };
fun evalls user_code = { eval("makelib::scripting_globals::eval_kludge_ref_list_string := (" + user_code + ")"); *eval_kludge_ref_list_string; };
include package threadkit; # threadkit is from
src/lib/src/lib/thread-kit/src/core-thread-kit/threadkit.pkg };
}; # package makelib
package mythryl_compiler_compiler_configuration
= mythryl_compiler_compiler_configuration; # mythryl_compiler_compiler_configuration is from
src/app/makelib/mythryl-compiler-compiler/mythryl-compiler-compiler-configuration.pkg # tools_g is from
src/app/makelib/tools/main/tools-g.pkg package tools
=
tools_g (
load_plugin' = load_plugin';
anchor_dictionary = anchor_dictionary;
);
load_plugin = load_plugin;
(_!) = multiword_int::(_!);
end; # stipulate ... herein ...
}; # generic makelib_g
end;