issues writing SML/NJ scripts

View: New views
1 Messages — Rating Filter:   Alert me  

issues writing SML/NJ scripts

by Joe Wells-6 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Dear SML/NJ gurus,

Naturally, I'd like to use SML/NJ for writing scripts.

I've managed to get something working somewhat okay (appended below),
but I have discovered that I can't silence certain messages from the
compiler.  (I'm using version 110.54 that comes from the Ubuntu Dapper
Drake repositories.)

Here are the main issues I'd like to get some help with:

1. How do I completely silence the “[autoloading]” messages and the
   “[opening FILE.sml]” messages?  Supposedly CM.Control.verbose
   controls this, but it has no effect on this at all for me.  It
   doesn't matter whether I do “#set CM.Control.verbose false” from
   the REPL or “-Ccm.verbose=false” from the command line.  Right now
   I am modifying Control.Print.out, and this works, but I can't
   figure out how to do this early enough to silence every message.
   And of course there is no way to modify Control.Print.out from the
   command line.  And also this silences everything, unless I do a
   fancy implementation of the say function that decides which strings
   to print.

2. How do I silence the “Standard ML of New Jersey” banner message?

The above issues are the important ones for me, because they make
SML/NJ scripts useless in situations where what gets sent to stdout
matters.  Any help will be appreciated.

Here are some other issues:

3. How do I find out which command-line arguments have been handled by
   CM so that I can handle the others?  There seems to be no way to do
   this short of duplicating all the logic that CM uses.

4. How do I get CM to ignore arguments after a certain point in the
   argument list, so they will not cause warnings or errors?  Yes, I
   know I can just avoid having my file return control to the
   command-line processor, but I'd like to be able to allow doing this
   when debugging so that execution will continue into the REPL.
   There seems to be no way to accomplish what I want.

Here are some things that would make my life easier, but are less
important than the things above:

5. It would be helpful if I could pass SML code on the command line
   instead of via stdin or by files named on the command line.

6. It would be useful if SML/NJ could do something nice with UNIX #!
   lines.  Something like Perl's -x command-line option which tells
   Perl to skip everything until a line beginning with a particular
   fixed string.  This would allow starting SML/NJ scripts with
   #!/usr/bin/sml or #!/bin/sh without needing to do lots of tedious
   work to avoid SML/NJ parsing the stuff at the front of the file.
   Right now I have to copy the SML code into a temporary file (using
   bash's “here document” mechanism) instead of just using the script
   file.

7. It would be nice if I could tell SML/NJ how to treat a file
   mentioned on the command line even though the file's name doesn't
   end in one of the extensions “.sml”, “.sig”, “.fun”, or “.cm”.
   Right now I have to make a symbolic link to /dev/fd/X that ends in
   “.sml”.  And I have to make a temporary directory to have a secure
   place to put the symbolic link.  And then I have to make sure the
   temporary directory gets cleaned up, so I can't just exec SML/NJ
   but need to leave a bash process hanging around.  (I suppose I
   could do the cleanup in SML, but I have to set up cleanup code in
   bash anyway in case invoking SML/NJ fails.)

8. It would be nice if there was a way to add definitions to the
   environment seen by a nested invocation of “use” _before_ the
   current invocation ends.  Right now I have to break the input to
   SML/NJ into 2 files, and then invocations of “use” from the 2nd
   file can use declarations made by the 1st file.  This is awkward.

9. It would be nice to be able to silence messages listing new
   declarations added to the top-level environment without also
   silencing everything else from the compiler.

I will appreciate hearing any comments on how to accomplish what I am
trying to do.

--
Thanks,

Joe

----------------------------------------------------------------------
#!/bin/bash
#**********************************************************************
# SML/NJ script template by Joe Wells *********************************
#**********************************************************************
# Tested with SML/NJ version 110.54 on Ubuntu Dapper Drake. ***********
#**********************************************************************
#** SML/NJ script startup boilerplate, ignore *************************
#**********************************************************************
TmpDir="`mktemp -d -t smlnj-script.XXXXXX`"
CleanUp () { rm -r "$TmpDir"; }
trap 'CleanUp; exit 1' INT TERM HUP
trap CleanUp EXIT
ln -s /dev/fd/4 "$TmpDir/a.sml"
ln -s /dev/fd/5 "$TmpDir/b.sml"
sml -Ccm.verbose=false "$TmpDir/a.sml" "$TmpDir/b.sml" XyzzyPlugh "$0" "$@" 3<&0 <<'AAAA' 4<&0- <<'BBBB' 5<&0- 0<&3-
(**********************************************************************)
(** boilerplate definitions, available to evalled code ****************)
(**********************************************************************)

local
  val original_Control_Print_out = ! Control.Print.out;
in
  fun unsilence_compiler () =
    Control.Print.out := original_Control_Print_out;
  fun silence_compiler () =
    Control.Print.out := { flush = fn () => (), say = fn _ => () };
  (* Don't show declarations added to the top-level environment or
     further autoloading messages.  Disable next line if you want type
     error messages. *)
  val _ = silence_compiler ();
end

(* Arrgh!

   The code in system/smlnj/internal/int-sys.sml seems to
   unconditionally print the "Standard ML of New Jersey" banner and
   has already done so.  This is done with print rather than
   Control.Print.say, so even if we had already run silence_compiler
   it would still be printed.

   Also, messages about the loading of this file and the autoloading
   of something (which is not identified) have already been printed.
   These use Control.Print.say, but have already been printed.

   Of course, this wouldn't be necessary at all if the command-line
   option -Ccm.verbose=false worked as advertised.  It seems to have
   no effect.  It certainly has no effect on autoloading messages.
*)

(* Here is an example of providing definitions that can be used by
   configuration files which will be evalled. *)
datatype option_data = STR of string | INT of int;
val options_state : (string * option_data) list ref = ref nil;
fun set_option name value =
  options_state := (name, value)::(! options_state);

AAAA
(**********************************************************************)
(** more boilerplate definitions, but not available to evalled code ***)
(**********************************************************************)

fun get_option name =
  case (List.find (fn (n,_) => n = name) (! options_state)) of
    NONE => NONE
  | SOME (_,value) => SOME value;

(* Maybe I should pass the command-line arguments another way, because
   there is no good way to automatically determine which are handled by
   CM, plus any options for the script will still be handled by CM after
   this code is done, so it interferes with trying to continue on into
   the REPL (read-eval-print loop) when debugging. *)
fun find_real_args ("XyzzyPlugh"::rest) = rest
  | find_real_args (_::rest) = find_real_args rest
  | find_real_args nil = raise (Fail "magic word sentinel argument missing")
val argv = find_real_args (CommandLine.arguments ());

(**********************************************************************)
(** start of your SML/NJ script ***************************************)
(**********************************************************************)

(* Here is an example of loading a config file and relying on the
   compiler to parse and type-check it.  As you can see, we can ignore
   syntax and type errors in the config file if we want to. *)
(use "smlnj-script-config") handle _ => ();

case (get_option "input-data") of
  NONE => raise (Fail "no input data")
| SOME (STR stuff) => print ("input data string: ["^stuff^"]\n")
| SOME (INT stuff) => print ("input data int: ["^(Int.toString stuff)^"]\n");

List.app (fn x => print ("command-line argument: ["^x^ "]\n")) argv;

(**********************************************************************)
(** end of your SML/NJ script *****************************************)
(**********************************************************************)

(**********************************************************************)
(** more boilerplate code follows *************************************)
(**********************************************************************)

(* For debugging, you might want to comment out the next line, and
   then SML/NJ will enter the top-level REPL when your code is
   done. *)
ignore (OS.Process.exit OS.Process.success);

(* WARNING: If we continue on to the REPL, then the remaining
   command-line arguments will be processed by the code in
   cm/main/cm-boot.sml!  Hopefully they will not be recognized and
   will just cause harmless error messages.  There appears to be
   nothing we can do to stop this without also preventing the REPL
   from being entered. *)

(* We need to (re)enable the compiler to speak to us when we
   enter the REPL. *)
unsilence_compiler ();

BBBB


--
Heriot-Watt University is a Scottish charity
registered under charity number SC000278.


------------------------------------------------------------------------------
Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are
powering Web 2.0 with engaging, cross-platform capabilities. Quickly and
easily build your RIAs with Flex Builder, the Eclipse(TM)based development
software that enables intelligent coding and step-through debugging.
Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com
_______________________________________________
Smlnj-list mailing list
Smlnj-list@...
https://lists.sourceforge.net/lists/listinfo/smlnj-list