2000-01-18:

+ The amlazy file Data.sml containing a structure called Data: parse
  as AnonStruct, then resolve in the compiler

* Avoid shift/reduce and reduce/reduce conflicts in the parser.

+ Documentation: 

  - manual
  - syntax

+ Emitcode: switch larger than 256 ?  OK because the switch
  compilation in Back breaks switches into chunks of size < 256

+ Kit: It is functor Parse in k42.sml that causes trouble --- even
  when actions in k32.sml is commented out.  Functor Parse is declared
  in k35.sml.  More precisely, the application of functor GrammarUtils
  inside the Parse functor in k35.sml:

    structure GrammarUtils =
      GrammarUtils (structure TopdecGrammar = TopdecGrammar
		    structure LexBasics = LexBasics
		    structure ParseInfo = ParseInfo
		    structure Report = Report
		    structure PrettyPrint = PrettyPrint
		    structure Crash = Crash
		      )
  Functor GrammarUtils is declared in k32.sml.
 
  Problem: open of local decs.

+ Back.sml -- array size 65000 -> 4000 (used only for the locals of 
  the init code)

+ Size of mosmllex and mosmllnk: avoid linking in Types

+ exnName and exnMessage -> runtime

  prim_val exnname : exn -> string = 1 "sml_exnname";

  prim_val exnMessage : exn -> string = 1 "sml_exnmessage";

+ Add documentation to General.fke

+ Implement sharing of literals (strings, reals, etc) as globals cf
  the hol98 and cholera problems: Updated Patch and Reloc and Code_dec
  and Link.

+ Cleanup of the dynlibs; moved stable structures to src/mosmllib

+ Fix mgd dynlib to use new GD package and PNG format.

+ Fix mosmllib/test/Makefile to create sym- and hardlinks as needed

+ Fix errormessage in compiler/Emitcode

+ Fix printing of overloaded ops to distinguish num, numtxt etc

* Fix exn tag access under lambda in Match.sml

* In general, compile better code for accessing subvalues in matches.
  However, should never evaluate accesses that aren't needed (safe but
  unnecessarily slow). The matching function may return an `envelope'
  of let-bindings?

+ Include runtime system *.h files in distribution (for the sake of
  user-written C code and dynlibs)

* Perhaps fix mgdbm to use new GDBM?

+ Inexhaustive and redundant excon matches -- why not reported correctly?
  Because EExn carries IdInfo as argument, and that includes the location 
  of the identifier.  Of course no two identifier occurrences have the same 
  location.  How fix it?  Translate the exnname accesses early, and
  compare the access paths (the lambda code): equal access paths must
  produce equal string refs...

* Add an Odbc interface to unixODBC.
  Later; possibly Thomas Iversen, DIKU/KVL.

+ .h files in mosml/include

+ make dynlibs/* refer to mosml/include

+ move .so files from mosml/bin to mosml/lib

+ strange bug in dynlibs/interface/ for Solaris.  Crashes.  Fails
  test7, because it doesn't pass the fifth argument (a boolean)
  correctly.  test 7 works if the number of arguments is reduced to 4.
  test10 fails as well, why?  NON-BUG.  A symbolic link had been
  extended by recursive file copying.

+ Non-blocking IO in TextIO.  input calls fast_input, which is
  io.input in the runtime.  It calls getblock, which may call
  really_read if necessary to obtain data not in the buffer; and
  really_read calls Unix read.  This will raise sys_error in case Unix
  read fails (cannot obtain any data).

  Two solutions: (1) handle the SysError (and check that it is
  EAGAIN), or (2) add an extra parameter to really_read so that it
  avoids raising the SysError.

  (1) is inefficient, 

  (2) may be done as follows: Add a new boolean parameter `nonblocking' to
  really_read.  If it is true, then use fcntl to change to
  non-blocking (and back), and if read fails, return -1 instead of
  raising sys_error.

  void nonblocking_mode(int fd, int nonblocking) {
    int retcode = fcntl(fd, F_GETFL);
    if (retcode != -1) {
      if (blocking) 
        retcode = fcntl(fd, F_SETFL, retcode | O_NONBLOCK);
      else
        retcode = fcntl(fd, F_SETFL, retcode & (~O_NONBLOCK));
    }
    if (retcode == -1)
      failwith("set_blocking_io");
  }

  static int really_read(int fd, char * p, unsigned n, int nonblocking) {
    if (nonblocking)
      nonblocking_mode(fd, TRUE);		/* set non-blocking   */

    ...

    leave_blocking_section();
    if (nonblocking) {
      nonblocking_mode(fd, FALSE);		/* unset non-blocking */
      if (retcode == -1 && errno != EAGAIN)
        sys_error(NULL);
    } else if (retcode == -1)
        sys_error(NULL);
    return retcode;
  }

  Function input_scan_line must call really_read with nonblocking = false.

  Add a new parameter nonblocking to getblock.  It must be passed on
  to really_read.  Getblock must check whether really_read returns
  -1, which should be treated the same as 0, except that it does not mean 
  end of file:

int getblock(struct channel * channel, char * p, unsigned n, 
   int nonblocking)
{
  unsigned m, l;

  m = channel->max - channel->curr;
  if (n <= m) {
    bcopy(channel->curr, p, n);
    channel->curr += n;
    return n;
  } else if (m > 0) {
    bcopy(channel->curr, p, m);
    channel->curr += m;
    return m;
  } else if (n < IO_BUFFER_SIZE) {
    l = really_read(channel->fd, channel->buff, IO_BUFFER_SIZE, nonblocking);
    if (l == -1) /* Non-blocking read returned no data */ 
      return -1;
    else {
      channel->offset += l;
      channel->max = channel->buff + l;
      if (n > l) n = l;
      bcopy(channel->buff, p, n);
      channel->curr = channel->buff + n;
      return n;
    }
  } else {
    channel->curr = channel->buff;
    channel->max = channel->buff;
    l = really_read(channel->fd, p, n, nonblocking);
    if (l == -1)	/* Non-blocking read returned no data */ 
      return -1;
    else {
      channel->offset += l;
      return l;
    }
  }
}

Function input will just call getblock with non-blocking = FALSE:

value input(value channel, value buff, value start, value length) /* ML */
{
  return Val_long(getblock((struct channel *) channel,
                           &Byte(buff, Long_val(start)),
                           (unsigned) Long_val(length),
	                   /* nonblocking = */ FALSE));
}



Make really_getblock call getblock with nonblocking=FALSE:

int really_getblock(struct channel * chan, char * p, unsigned long n)
{
  unsigned r;
  while (n > 0) {
    r = (unsigned)getblock(chan, p, (unsigned) n, /* nonblocking = */ FALSE);
    if (r == 0) return 0;
    p += r;
    n -= r;
  }
  return 1;
}


  Add a new function input_nonblocking, which will call getblock with
  nonblocking=TRUE.  Returns NONE if getblock returns -1, otherwise 
  returns SOME 

value input_nonblocking(value channel, value buff, value start, value length) /* ML */
{ int n = getblock((struct channel *) channel,
                   &Byte(buff, Long_val(start)),
                   (unsigned) Long_val(length),
	           /* nonblocking = */ TRUE));
  if (n == -1)		/* Non-blocking read returned no data */ 
    return Val_NONE;
  else {
    value res = alloc(1, SOMEtag);
    Field(res, 0) = Val_long(n);
    return res;
  }
}

  
* 2000-03-15 Ken: Parametre til lexer-funktioner

  rule comment depth = parse ...

  for at kunne lave en rent funktionel lexing af indlejrede kommentarer.

+ 2000-03-28: Add a parser combinator module called Parse.
  Reimplement to use NONE/SOME instead of exceptions.  

  Add a formatting (unparsing) module called Format, using Olivier's
  ideas but avoiding repeated string concatenation (e.g. using a
  wseq-like structure) and having also a prsep style
  iterator-with-separator plus an prmap style iterator.

  May 2000: Decided to create mosml/example/parsercomb instead, as the
  parser combinator stuff seems too volatile.

+ Meta.fke;  remove Meta.system

+ Meta.fke; documentation

+ Lexing.sig

+ Parsing.sig

+ mosmllib/README

+ TextIO.scanStream -- get rid of cs? -- no: cannot

* Should gc time be subtracted from sys time?  (Timer, Mosml)

* Non-blocking IO should have a function canInput : int -> SOME int instead.

http://www.dina.kvl.dk/~sestoft/sml/imperative-io.html#IMPERATIVE_IO:SIG:SPEC

+ 2000-04-26: Michael Norrish: this crashes mosml 1.44 (and 1.99):

datatype 'a result =
    FIRST of 'a
  | SECOND of 'a;
val zz = case FIRST() of
    FIRST _ => ()
  | _ => ();     

while this works:

val z = case SECOND() of
    FIRST _ => ()
  | _ => ();

compiler/Rtvals.sml function prSeq; decode_obj thinks zz is a record
of length 1.  Why?  Has nothing to do with the polymorphism of result.

And really, the *representation* of the result is wrong; here zz
evaluates to false:

datatype result =
    FIRST of int
  | SECOND of int;
val zz = () = (case FIRST 1 of
    FIRST _ => ()
  | _ => ());     

The generated lambda code looks OK:

(prim (set_global Top.zz/3) 
	(prim (ccall2 sml_equal) (BLOCK 0:1 ) 
	      let (BLOCK 0:2 1) in 
	          ((switch:2 var:0 of 
	              0:2 : (BLOCK 0:1 )) 
	            statichandle (BLOCK 0:1 )) 
              end))

But the Kcode is wrong:

(BLOCK 0:1 ); 
push; 
(BLOCK 0:2 1); 
push; 
access 0; 
strictbranchifnot 1; 
branch 2; 
label 2; (BLOCK 0:1 ); 
label 1; pop 1; 
ccall2 sml_equal;
set_global Top.zz/1

Problem: the returned value is the argument of FIRST (which is a block
of length 1 in this case): nothing is pushed between strictbranchifnot
1 and branch 2.  Probably we forget to generate code to put unit in
the accumulator???  Back.sml line 721, optimization for the case where
the else-branch is a constunit ().  In that case, then other branches
are () too (but may have side effects).

The problem is caused by an optimization in the compiler backend, file
compiler/Back.sml line 721.  If you want to get rid of it, uncomment
this code:

         (* if ifnot = Lconst constUnit
            then let val (lbl, C1) = labelCode C
                 in Kstrictbranchifnot lbl :: compexp sz dp ifso C1 end
            else *)

I'm afraid I introduced this optimization in 1997.  The reasoning was
that if some branch of a switch evaluates to () : unit, then all
branches do, and they are evaluated only for their side effects.  Not
so.  

+ 2000-04-26: Constructor ordering.  Constructors should be sorted
alphabetically so that the ordering in datatype declarations doesn't
matter.  That is, this should elaborate:

     signature SIG = 
     sig
	 datatype 'a t = Bt | Ct of int
	 datatype 'a u = Cu of int | Bu 
     end

     structure S: SIG = 
     struct
	 datatype 'a t = Ct of int | Bt
	 datatype 'a u = Bu | Cu of int
     end

     structure G : sig datatype order = EQUAL | GREATER | LESS end = General;
     structure G : sig datatype order = GREATER | EQUAL | LESS end = General;

   - should reorder the pervasive datatypes (order and frag) in Types.sml:

and infoEQUAL = mkSML "EQUAL"
  { conArity=0,   conIsGreedy=false,   conTag=0,   conSpan=3,
    conType=sc_order }
and infoGREATER = mkSML "GREATER"
  { conArity=0,   conIsGreedy=false,   conTag=1,   conSpan=3,
    conType=sc_order }
and infoLESS = mkSML "LESS"
  { conArity=0,   conIsGreedy=false,   conTag=2,   conSpan=3,
    conType=sc_order }
and infoANTIQUOTE = mkSML "ANTIQUOTE"
  { conArity=1,   conIsGreedy=false,   conTag=0,   conSpan=2,
    conType= scheme_1u (fn a =>
      type_arrow a (type_frag a)) }
and infoQUOTE = mkSML "QUOTE"
  { conArity=1,   conIsGreedy=false,   conTag=1,   conSpan=2,
    conType= scheme_1u (fn a =>
      type_arrow type_string (type_frag a)) }

val initial_order_CE = ConEnv [infoEQUAL, infoGREATER, infoLESS];
val initial_frag_CE = ConEnv [infoANTIQUOTE, infoQUOTE];

   - fix the corresponding extraction code in Smlperv.sml:

val [infoFalse, infoTrue] = deConEnv initial_bool_CE
and [infoNil, infoCons]   = deConEnv initial_list_CE   (* NOTE: NOT sorted *)
and [infoNONE, infoSOME]  = deConEnv initial_option_CE
and [infoEQUAL, infoGREATER, infoLESS] = deConEnv initial_order_CE
and [infoANTIQUOTE, infoQUOTE] = deConEnv initial_frag_CE

   - do we need to change only the conTag fields, or also the
     initial_frag_CE etc (as above)?  Better order both.

   - the bool and option datatypes are sorted already

   - we do *not* fix the list datatype, since the constructors
     nil and :: may not be respecified or redeclared.

   - there is no corresponding runtime system code

   - should reorder the constructors in mosmllib:

	open_flag: BasicIO, BinIO, Nonstdio, TextIO
        and runtime/sys.c variable sys_open_flags

	dbresultstatus: Mysql, Postgres
        and dynlibs/mmysql/mmysql.c function db_resultstatus
        and dynlibs/mpq/mpq.c  

	parserInput and parserOutput: Parsing
        and the macroes START, TOKEN_READ, ... in parsing.c

   - mosmlyac must sort the tokens (the token datatype), because the 
     token tags are used as indexes into the parsetable, in parsing.c 
     line 97. 

   - dynlibs/interface/smlside.sml and cside.c: datatype t

   - sort constructors in declarations as well as specifications:
     uncomment line 1865 in Elab.sml, function elabDatBind (this takes 
     care of declarations as well as specifications).  

   - loading of libraries crashes because hashtables
     (Hasht) are used to represent signatures, and the mosmllib stuff 
     was compiled with one constructor ordering in Hasht, and are loaded 
     with another ordering.

   - Sort tokens in the parsers generated by mosmlyac.  Strangely, hand-
     sorting the tokens in compiler/Parser.grm makes mosmlcmp shorter
     by 1 K.  Should do the same to lex/Grammar.grm of course.  How
     make mosmlyac sort tokens?  Tokens are stored in the same
     (hashed, linked) symbol table as other grammar symbols.  The tag
     of a token is used only as an index into the table yytransl, it
     seems (parsing.c line 97).  Hence it suffices to (1) sort the  
     tokens (by symbol_value) and their adapt the indexes (symbol_value). 

   - constructor sorting affects user programs that use 
     Nonstdio.{input_value, output_value}, string_mlval, mlval_string, 
     and hence Polygdbm

Bootstrapping:

(1) Modify the core mosmllib .sml files and recompile.  The new
compiler must be run with a new runtime system.  
(2) Recompile with new compiler and runtime system.  Binaries should be 
identical.
(3) Fix Types and Smlperv.  Does not affect runtime.  Bootstrap.
(4) Enable constructor sorting, reorder Hasht.bucket constructors, 
sort tokens in grammar specifications.
(5) Fix Mysql, Postgres, and their C code.
(6) Fix dynlibs/interface

+ Check that it compiles with Solaris, HP-UX, Linux/Alpha, ...

+ Change version to 2.00 (June 2000)

+ Make -quietdec more quiet; drop the welcome greeting.

* Size of .ui files: sharing?

+ Problem compiling on LinuxPPC

2000-07-01:

+ (Don't do, this is a gcc macro extension)
 
  There is no snprintf on HPUX (it is a GNU-libc-extension),
  so I said in mosml.h

#define snprintf(dest, n, format, args...) sprintf(dest, format , ##
args)

   (all on a single line, the space before the last comma is
   necessary).
   This works with gcc (var-arg macros are another GNU extension,
   but in the compiler, which is what I have).
   I don't know whether mosml.h is a good place to put this line,
   but this file is just included by those *.c who use snprintf.
   Maybe the config stuff should check for it's existence
   (or even provide an implementation for people with crippled
   libcs).

+  src/doc/helpsigs/Makefile redefines MOSMLHOME, overriding
   a possibly different value from src/Makefile.inc.

+  install.txt says in (8) to look for dynlib stuff in (4),
   but this is in (5). I think the upper items were renumbered
   without incrementing the reference.
   [Not a mistake, but unclarity]

2000-08-07: 

* Binarymap (and Binaryset etc) based on Doug's Bin234map.
  Should admit interval queries a la sml/besked/Datemap:

   datatype 'key interval =
       All
     | From of 'key
     | To of 'key
     | FromTo of 'key * 'key

   val getAll : ('key, 'a) dict * 'key interval -> ('key * 'a) list

  such that  getAll dict All  is  equivalent to  listItems dict.

  The complexity of getAll dict intv should be O(log(N) + M) where N
  is the number of items in the dict, and M is the number of items in
  the answer.

  Also useful:

  val getMin : ('key, 'a) dict * 'key interval -> ('key * 'a) option
  val getMax : ('key, 'a) dict * 'key interval -> ('key * 'a) option

  which return the element with the least (resp. the largest) key in
  the interval, if any.  Thus

  getMin dict intv = (SOME (List.hd (getAll dict intv)) handle Empty => NONE
  getMax dict intv = (SOME (List.last (getAll dict intv)) handle Empty => NONE

  But the complexity of getMin dict intv and getMax dict intv should
  be O(log(N)) where N is the number of items in the dict.

  Also useful: a general lookup/insert/update/delete function 
   val peekMap : ('key, 'a) dict * 'key * ('a option -> 'a option) -> unit
  such that 

	peekMap(d, k, f) computes res = f(SOME v) if k is in dict with
        value v, and computes res = f(NONE) otherwise.  Subsequently, if 
	res = SOME r, it inserts/updates k in dict to r, and if res = NONE, 
	removes k from dict.

* Httpclient module

* Inet name queries etc

* 2000-08-10 #line comments for machine-generated mosml code:

--------------------------------------------------
From: Norman Ramsey <nr@eecs.harvard.edu>

I wonder if there's any chance of supporting some form of #line numbering.
Objective Caml supports the C style, i.e., 

# 27 "bits.nw"

 
Here is the style we have used in STandard ML of New Jersey:

(*#line 182 "mlscheme.nw"*)type name = string
type 'value simplemap = (name * 'value ref) list
val emptyMap : 'a simplemap = []


I'd be delighted if there were some way to get one of these
conventions, or a similar convention, into Moscow ML.
Do let me know what you think.
--------------------------------------------------

One way to implement this (2000-08-11): Maintain a table of the source
positions (byte offsets) at which #line directives occur (could be a
dynamic array; the positions would automatically be sorted increasing
and thus be suitable for binary search).  Whenever a message with
start and end locations xL and xR is to be emitted, look up the most
recent #line directive at or preceding xL.  Scan the source file until
xL, then reset the line counter to the line number indicated by that
#line directive and set the filename, then continue as usual.  This
ignores any #line directives between xL and xR.

The lexer should recognize the special comments of form 
(*#line n... "x..."*) 
where n... is a non-negative decimal number, x... is a string of
characters (in which an occurrence of *) is taken to be part of the
file name, presumably?).  In SML/NJ nothing can separate the terminal
quote (") and the asterisk (*) in the closing comment bracket.

?1 Must a #line directive appear at the very beginning of a line?  In
   SML/NJ: yes (but this makes lexing 

?2 Should a #line directive inside a comment be ignored?  In SML/NJ: yes.

* IntInt.int should be an equality type

* mosmlyac generates non-sml compliant signatures (local in end)

* 2000-09-22 Jeremy Dawson:

- datatype thing = / of int * int ;
datatype thing = / of int * int
- infix / ; 
infix /
- 1 / 2;
val it = 1 / 2 : thing

I find the SML/NJ output easier.
Would it be worth considering for MosML?


* 2000-09-22 Jeremy Dawson:

The command 
mosmlc -c a.sml b.sml c.sml d.sml e.sml f.sml g.sml h.sml i.sml j.sml
compiles all these files, in such a way that
load "j" ; 
loads all the others even though it doesn't depend on them.
Is there a reason for this?
If so, could the fact be mentioned in the documentation?
(At present, when load "x" can cause behaviour that bears no relation
to anything in x.sml or any other unit that x depends on,
which is very difficult to diagnose).

* 2000-10-04 Jakob Lichtenberg:

Output fra mosmlc -standalone kan ikke meningsfuldt strippes, idet
strip fjerner al bytekoden, saa kun camlrunm bliver tilbage!

Find ud af hvordan ELF-formatet er opbygget, og saet stoerrelsen
korrekt, saa strip ikke mutilerer den linkede fil.  See GNU binutils in info.

Maaske 
	objcopy --add-section BYTECODE=<bytecodefile> camlrunm mosmlout

Nej, duer ikke, for der ligger noget indeksinformation i enden af en
ELF fil...

Maaske der findes en C-funktion til at laese et navngivet segment fra
en linket fil, f.eks. et segment kaldet BYTECODE.

size -A mlsexe kan fortaelle hvor store de enkelte sektioner er.

* 2000-10-20:  SML Basis Library 

+ zillions of changes already made
+ Word8Array, CharArray   -- remove and simplify
+ Word8Vector, CharVector -- remove and simplify
+ test/vector.sml -- many missing cases
+ Word8ArraySlice, CharArraySlice -- add
+ Word8VectorSlice, CharVectorSlice -- add
+ Negative Time values -- how?  Use reals, represent time as 
  whole number of microseconds since the epoch (possibly negative).  
  This gives exact times in a range of 2^52 = 4.503.599.627.370.496, 
  that is, microsecond resolution from 1828 till 2112.
* Extended date offset range?
+ ~ (ones-complement) in Word, Word8
+ Timer -- do not include GC time, add new function
+ Process.status not equality type
* Unix structure -- various changes


+ 2000-10-20: Mosml library

Further unify Mysql and Postgres signatures; must match a common Db
signature.

* 2000-10-31: Stephen T Weeks (comp.lang.ml)
Date: 30 Oct 2000 15:17:52 GMT

There's definitely some differences amongst SML implementations
regarding type specifications in signatures.  Consider the following
two programs.

(* program 1 *)
signature S =
   sig
      type t
      and u = int
   end

(* program 2 *)
signature S =
   sig
      type t = int
      and u = t
   end

According to the Definition (pages 14, 35 (rule 80), and 59 (figure
19)), program 1 should be rejected as a syntax error and program 2
should be accepted (because of the expansion explained in the previous
post.  Here's a comparison of five different SML implementations on
the two programs.

The Definition		reject	accept

ML Kit Version 3	reject	accept
MLton 20000906		accept	reject
Moscow ML 2.00		reject	reject
Poly/ML 4.0		accept	reject
SML/NJ 110.0.6		accept	accept
SML/NJ 110.29		accept	accept

As you can see, all four possibilities are achieved.

Of the five compilers, only the ML Kit gets both programs right,
Moscow ML and SML/NJ get one right (and disagree with each other), and
MLton and PolyML get both wrong.

+ Exception Option should be available in the top-level by default.
  Should go in src/compiler/Smlperv.sml and in runtime/globals.h
  Fixed Jan 2001.

* 2001-02-16: Dynamic linking under MacOS X.  See man ld, man dyld.

  cc -dynamiclib?

  #include <mach-o/dyld.h>
  
  Documentation/DeveloperTools/Compiler

  man 3 dyld

+ 2001-02-27: Ken: Jeg mener at foelgende funktion er hale rekursiv,
men Mosml er ikke enig med mig (den oversaetter iht det rekursive kald
til fitting til et apply):

--------
fun fitting [] left          = true
  | fitting (s :: rest) left = 
    left >= 0 andalso
    (case s of
         "\n" => true
       | _    => fitting rest (left - size s))
--------
(og ligeledes med orelse)

Årsag: I kodegenereringen for Landalso og Lorelse i Back.sml mangler
der det tilfælde hvor oversættelsestids-continuation starter med
Klabel :: Kreturn _ :: ... 

Fixed by updating addPop to handle the case where C is Klabel :: Kreturn.

* 2001-04-02: Streamline the (Basis Library) test cases so that they
  can be effectively used also by the ML Kit.

  Avoid inclusion by `use'.  Instead open Testaux and open other
  needed structures.  Batch compile the test files, and load them to
  produce the test output.  Rename check' to check, and give it
  one more argument: a string indicating the name of the test.

* 2001-05-11: Ken 

  I've made a new mosml windows installer it is available from:
        http://www.it.edu/~kfl/tmp/mosml-setup-2_00.exe
 
 I've tested it on my laptop with windows 2000 where it seems to work
 fine, and I would like if you could help me testing it like last time.  

+ 2001-05-22: Date: 21 May 2001 14:28:31 +0200
              From: Martin Elsman <mael@dina.kvl.dk>
Subject: Int overflow

Hej Peter,

Jeg har modificeret koden til scanning og formattering af små
heltalskonstanter således at Overflow ikke forekommer, som i følgende
session:

  mael@daffy> mosml -P full
  Moscow ML version 2.00 (June 2000)
  Enter `quit();' to quit.
  - Int.fmt StringCvt.DEC (valOf Int.minInt);
  ! Uncaught exception: 
  ! Overflow
  - Int.fmt StringCvt.BIN (valOf Int.minInt);
  ! Uncaught exception: 
  ! Overflow
  - Int.fromString "~1073741824";
  ! Uncaught exception: 
  ! Overflow
  - 

Funktionen conv i strukturen Int ændres til:

  fun conv radix i =
    if SOME i = minInt then          (* Be careful not to Overflow *)
      let fun tag s1 s2 = if precision = SOME 31 then s1 else s2
      in case radix
	   of 2 => tag "~1000000000000000000000000000000" "~10000000000000000000000000000000"
	    | 8 => tag "~10000000000" "~20000000000"
	    | 10 => tag "~1073741824" "~2147483648"
	    | 16 => tag "~40000000" "~80000000"
	    | _ => raise Fail "conv"
      end
    else
      let fun h 0 res = res
	    | h n res = h (n div radix) (prhex (n mod radix) :: res)
	  fun tostr n = h (n div radix) [prhex (n mod radix)]
      in implode (if i < 0 then #"~" :: tostr (~i) else tostr i) 
      end

Funktionen dig1 i strukturen Int ændres til:

    fun dig1 sgn NONE = NONE
      | dig1 sgn (SOME (c, rest)) =
      let fun digr (res:int) next_val src =
	case getc src
	  of NONE => SOME (res, src)
	   | SOME (c, rest) => if isDigit c then digr (next_val(factor, res, hexval c)) next_val rest
			       else SOME (res, src)
	  val next_val =
	    if sgn = 1 then fn (factor, res, hv) => factor * res + hv
	    else fn (factor, res, hv) => factor * res - hv
      in if isDigit c then digr (sgn * hexval c) next_val rest else NONE 
      end


 * 2001-05-15: the binaries for MacOS X [Version 2.00 for Macintosh
PPC with MacOS X (without dynamic libraries)] and they fail with the
following error:
 
matt@mec30:~/Downloads/mosml/bin $ ./mosml
./mosml: no such file or directory: /Users/lcp/mosml/bin/camlrunm [11]
                                                
 * 2001-05-25: From: Konrad Slind <Konrad.Slind@cl.cam.ac.uk>

Surprised I was, when a student sent me this, in contradiction of
something I said in a supervision:
 
    Moscow ML version 2.00 (June 2000)
    Enter `quit();' to quit.
    - fun f g g = g;
    > val ('a, 'b) f = fn : 'a -> 'b -> 'b
 
[Presumably wrong according to the Definition's appendix on derived
forms]

 * 2001-05-17: jeremy@discus.anu.edu.au

ON page 8, (sec 3.4), under description of loadPath,
it says (2nd sentence)
This variable affects the load, loadOne and use functions.
 
It seems from my experiments that it also affects the
compile, compileStructure and compileToplevel functions.      


 * 2001-05-25: Ken Friis Larsen <kfl@it.edu>
 
I've found a small bug in mosml's handling of signatures.  This should
be correct SML:
 
signature COL = sig type elem type col end
signature INTCOL1 = COL where type col = int list
                       where type elem = int
signature INTCOL2 = COL where type elem = int
                        where type col = int list
signature INTERM = COL where type elem = int
signature INTCOL3 = INTERM where type col = int list    

 * 2000-06-05: Henning Makholm:

Could future versions of mosmlyac please take a consistent stance
about whether they support rules without actions? The current one
glefully processes the grammar file without error, but produces a
parser that raises Fail when it tries to reduce the actionless rule.
 
If the nonterminal has a type definition, mosmlyac warns that the
default action produces an undefined value - in reality the default
action (used in the definition of yyact in the generated gode) throws
an exception. If the nonterminal does not have a type defintion
(as in the typescript below), no warning at all is produced - but
the default action still throws an exception...   

$ cat foo.grm
%{
%}
  %token FOO
  %type <int> S
  %start S
%%
  S : T { 42 } ; T : FOO ;
%%
$ cat bar.sml
val _ = foo.S (fn _ => foo.FOO) (Lexing.createLexerString "")
$ mosmlyac -v foo.grm
$ mosmlc foo.sig foo.sml bar.sml

* 2001-06-08:jeremy@discus.anu.edu.au   

Last year I emailed you about what turns out to be a related
problem - I'd assumed that
mosmlc -c A.sml B.sml C.sml
would do the same as
mosmlc -c A.sml
mosmlc -c B.sml
mosmlc -c C.sml
but in fact fake dependencies were introduced there also.    
I wonder if this issue warrants a mention in the documentation.

* 2001-06-11: Michael Norrish <Michael.Norrish@cl.cam.ac.uk>   

The system-administrators here dislike the fact that the mosml2.0 RPM
 
  "installs files into /usr/bin and /usr/mosml and is not
  relocatable."
 
Rather than use this, they then installed the binary version, without
then setting things up as per the instructions, and what they've
installed doesn't work well.
 
Also, the instructions at
 
  ftp://ftp.dina.kvl.dk/pub/mosml/install-linux.txt
 
don't say anything about the symbolic link at <mosmldir>/lib/camlrunm,
which seems to be used when linking.                 

[The latter is an RPM-problem / Peter]

* 2001-06-21: Martin Elsman <mael@dina.kvl.dk>

Det ser ud som om Moscow ML ikke binder Option og Span som exception
konstruktører på top-niveau, som foreskrevet i
 
  http://www.dina.kvl.dk/%7Esestoft/sml/top-level-chapter.html

* 2001-07-17:  Stephen Weeks <sweeks@intertrust.com>
 
Mosml accepts the following program.  It should report an error because x is
bound twice in the same valbind.
 
val x = 13
and rec x = fn () => ()     

* 2001-08-02: PS to check up on Buffer.{sig, sml} from Ken.

* 2001-08-02: PS to check up on Ken's red-black tree implementation.
              Compare with Doug's 2-3-4 maps.
  2001-10-15:
 
   Add interval operations (done, but not tested).
   Add hash codes.
   Ensure reasonable naming schemes, short names:

    Rbset, Rbmap		functional (persistent)
    Hashset, Hashmap		imperative

   Create an SML version of the nfa-to-dfa conversion procedure, using
   a hashmap of treesets etc.

  Bugs found:
   isSubset was wrong for empty first arg and non-empty second arg

* 2001-08-14: Michael Norrish, email

  There doesn't seem to be any nice way of finding the key of a
  Binary map that maps to the least value (say the range is int).
  
* 2001-10-18: Michael Norrish: 

  * enable call to system prettyprinter from installed prettyprinters,

    This is best done by introducing a pseudopolymorphic function 

	Meta.fmtVal : 'a -> (ppstream -> unit) -> unit
 
    that takes as argument a value and a ppstream and prints on that, 
    exactly as Rtvals.prVal (which implements printVal) already does.

    The most sensible thing would be to pass the PP.ppstream to prVal
    and all its helpers, and replace msgString etc from Mixture with
    appropriate function calls.  This is a bit tedious but perfectly
    doable.

  * prettyprint infix constructors as infix

    This should be done in the very last branch of prVal, checking for
    arity = 2 and using Units.pervasiveInfixBasis to look up the
    fixity of the constructor.  I wonder whether the prior logic in
    prVal would handle right-associative operators correctly?  If it
    doesn't, that just means there will be excess parentheses in some
    cases.  The prior precedece logic of prVal would need to be fixed
    to fit the precendece actually use in SML.

* 2001-10-29 Don Sanella:

> According to the Moscow ML library documentation, various functions
> in TextIO may raise the exception Io.Io.  According to the SML Basic
> Library that is supposed to be IO.Io.  There appears to be a library
> module called IO, since    load "IO"    doesn't complain, and it
> contains an exception IO.Io, but there is no section about the IO
> module in the Moscow ML library documentation.
   
* 2001-10-29 Michael Norrish:

It would be very nice to have a time-out function available.
Something like
 
  timeout : time -> ('a -> 'b) -> 'a -> 'b
 
which raises an exception if the time allotted expires.
 
This would make proof strategies that combined black-box components a
positive pleasure to write.  It would need to work both interactively
and in compiled code.
 
Also, it would be nice to have the magic (involving prim_val) that
makes the Interrupt exception "work" in executables (i.e., catches       
Ctl-C) properly documented.
 
Currently I just copy
 
  prim_val catch_interrupt : bool -> unit = 1 "sys_catch_break";
  val _ = catch_interrupt true;
 
from file to file without understanding what I'm doing.       

* 2001-11-05 Nils Andersen: integer Overflow when computing ~32768*32768.

* 2001-11-05 Konrad Slind: Is Splaymap.transform tail-recursive?  No.
  Is the problem that the trees get very unbalanced?  Probably.

* 2001-11-13: Delete Closure_wosize from mlvalues.h and from signals.h
  (where an empty `env' is allocated; strictly speaking an
  always-ignored () : unit, which is a mistake).

* 2001 December: List of bugs compiled by Claudio and Peter at MSR:

  * local_dec bug (level error)

  * structure mode dec bug (level error)

  * win32 mosmlc bugs

  * local type projections grammar bug (int   )

  * non-linear patterns  fun f a a = ...  should be forbidden

  * Stephen Weeks type spec 

  * incompleteness for recursive structures

  * sig elaboration performance

  * type explosion, datatypes copied

  * MacOS X dynlib

  * maps and sets in libraries

  * parsing of numbers in scan (?)

  * SML Basis Library (check updates)

  * test cases, share with ML Kit and SML.NET as far as possible

  * dynlib `examples' to be integrated with rest of mosml

  * PM?

  * Doug's mosmle?

  * parser combinators to lib, plus an actual example use

  * Windows installer (Jakob Lichtenberg or .msi? or ?)

  * document or fix Dawson bug (*.ui)

* 2001-12-17: Mosmlcgi and Mosmlcookie suggestions from Hans Molin.

* 2001-12-26: Stanislaw Skowron, see skowron-bug.sml: excess
  polymorphism leads to segmentation fault.

* 2002-01-15: Binarymap desiderata.  

  * Benchmark Ken's red-black vs Doug's 234-trees.
 
  * Konrad wants a way to map a map to something else by a function f,
    while preserving the key order.  A function such as 
      remap : ('a -> 'c) * ('b -> 'd) -> ('a,'b)dict -> ('c,'d)dict 
    which must be applied only to functions f that satisfy
      compare1 k1 k2 = compare2 (f k1) (f k2)
    where compare1 : 'a * 'a -> order and compare2 : 'b * 'b -> order
    This should be done in linear time, not using inserts all over the 
    place again.

  * Ken suggests: The new key ('c) might depend on the data ('b).
    Actually the type should be:
 
        val genmap : ('c * 'c -> order) -> ('a * 'b -> 'c * 'd)
                                        -> ('a,'b)dict -> ('c,'d)dict
 
    because we need the new compare function to construct the result
    dist.  If I should implement genmap for RB trees then I'd first
    genrate a list of the mapped elements, check that the list is
    sorted and then use fromSortedList.  But then I can be over
    defensive in my (SML) programming.


* 2002-02-22: Ordered map desiderata: From: Michael Norrish
<Michael.Norrish@cl.cam.ac.uk>
 
The various map datatype implementations in the mosml library should
include a function to update a value at a particular key.  This would
then save a traversal of the tree  (well, not in the case of Splay
maps I guess).
 
  val fupdate : ('a,'b) dict -> ('b -> 'b) -> 'a -> ('a,'b)dict
 
This sort of thing is useful when maintaining a map of counts, where
you want to be incrementing values all over the place.
 
The most efficient alternative at the moment would seem to be a
hashtable of references.

* 2002-02-26: David.Richerby@cl.cam.ac.uk       

I found the following in Moscow ML version 2.00 on a RedHat 7.1
machine while trying to fix a broken program.  Consider the following,
where [^D] on the sixth line indicates that I pressed ctrl-D at that
point rather than return.
 
$ mosml
Moscow ML version 2.00 (June 2000)
Enter `quit();' to quit.
- fun app (f: int->int) x = f x;
> val app = fn : (int -> int) -> int -> int
- fun bug f x y = (app (app f x)) y;[^D]! Toplevel input:
! fun bug f x y = (app (app f x)) y;<EOF>
!                       ^^^^^^^^^^^^
! Type clash: expression of type
!   int
! cannot have type
!   int -> int
- quit();

sestoft: The abstract syntax tree is annotated with source code
positions which are used when reporting errors.  Somehow the end of
the subtree (app f x) is wrong.  Probably this is due to some mistake
in mosml/src/mosmllib/Parsing.sml or (more likely) in
mosml/src/runtime/parsing.c.  I'll investigate.
 
I've never encountered the problem myself, possibly because emacs
always appends a newline at the end of source code files when saved.

* 2002-04-08: MacOS X on swallow.al.cl.cam.ac.uk

Compiler is cc, not gcc.

Added option -traditional-cpp to CC.

Added option -S to strip.

~/bin is on PATH, but the shell needs a rehash to be able to find
newly installed programs there.

The mosmllib/test/filesys.sml tests test6e test6f test8d test8h fail
because realpath and fullpath are too intelligent on MacOS X.  Changed
the tests to accept the results.

Dynamic linking is done using the dlcompat package from
http://sourceforge.net/projects/fink/ which appears to be preinstalled
in /sw/include and /sw/lib (but undocumented); it gives an interface
similar to dlopen from Solaris/Linux.  

Notes:

 + If camlrunm is stripped, the symbols defined in it are not linkable.

 + Files that are to be linked dynamically must be linked
   using cc, not ld, otherwise symbol dyld_stub_binding_helper is
   missing.

 + The compiler (or linker?) inserts an underscore in front of
   symbols it attempts to look up.  Wonderful.  This has been fixed by
   a MacOS X specific version of dlsym() in runtime/dynlib.c.  We
   recognize MacOS X as #if defined(__APPLE__) && defined(__MACH__)
   and hope this is adequate.

Now the crypt, interface, munix, mregex, msocket, mgdbm examples work.
The remaining examples mgd mpq intinf mmysql require extra software.
Callbacks work as well.

* 2002-05-11: From slind@cs.utah.edu Sat May 11 03:59:14 2002

  This is a rushed note about some things I have on my MoscowML wish
list. Just thought I'd scribble them down before I forgot:

  1. A type of SML abstract syntax trees, with a parser that produces
     them.

  2. An evaluator for such ASTs (something like NJSML's eval_string, or
     whatever it's called). Something like

      evalAST : AST -> unit

     that wouldn't return values, but would evaluate the argument (in
     the current environment) and update the current environment.

  3. The left margin on the prettyprinter sometimes gets way too far
     over on the page. I remember fixing the NJSML prettyprinter to
     automatically reset the left margin once it got past 2/3 of the
     width of the page.

For 1,2 the motivation is that HOL is a collection of libraries sitting
on top of ML. One of those libraries lets me define (total) logical
functions that look like ML programs (with pattern matching, etc). I'd
like to be able to generate ML code for these within a session. I have a
hack using references and writing to files and calling "use", but that
of course only works interatively. Hmm, I've got to go now, but will try
to write more coherently tomorrow.

2002-07-25: The Postgres interface now works with PostgreSQL 7.2
provided databases are created with LATIN1 or another 8-bit encoding,
and recognizes the int8 type (returned by COUNT).

* 2002-08-19: Kenneth MacKenzie <kwxm@dcs.ed.ac.uk>
 
Hi Kenneth (Peter),
 
Oh dear, that's an embarrassing grammatical bug. I do remember wondering if
the absence of parentheses for signatures would bite me sometime, but I didn't
look hard enough for counter-examples.
 
Yes, I do have some pull with the implementors (technically, I'm still one of
them, but I never seem to find the time and I haven't pulled my weight for a
long while.)
 
About the error message, I think its supposed to read that the type of the
expression is found to be bool, but expected to be int from the context. I      can't remember if the compiler order them consistently or not.
I'm forwarding the message to Peter too, for the record.
 
-c
 
-----Original Message-----
From: Kenneth MacKenzie [mailto:kwxm@dcs.ed.ac.uk]
Sent: 19 August 2002 14:58
To: Claudio Russo
Subject: Moscow ML
 
Hi Claudio,
   I just remembered that when you were up here I was complaining
  about some problem I'd had with the Moscow ML syntax.  Here's the
problem.
 
Suppose you have
 
   signature S = sig type t val x:t end;
 
Then you can have the opaque functor signature
 
   signature FSIG = functor (A: S where type t = int) -> S;
 
and Moscow ML accepts it without complaining.  However,  if you
attempt to make this into a transparent signature
 
   signature FSIG' = functor A: S where type t = int -> S;
 
then you get a syntax error,  presumably because the parser thinks
that you're trying to refer to a type t = (int->S).  I wasn't able to           find any way of getting round this (and by now I've forgotten whether
it makes any sense to have type constraints in a transparent
signature).  It's not a huge problem,  but it does seem that using
presence/absence of parentheses to denote different types of
signatures means that you can't use parentheses to make sure that
things have the correct precedence.
 
By the way,  do you have any influence with writers of Moscow ML?
I've found Moscow ML to be really useful,  but the messages that you
get for type errors are really frustrating.  If you type
 
   fun f x = x+1; f true;
 
then you get
 
! Toplevel input:
! f true;
!   ^^^^                                                                       ! Type clash: expression of type
!   bool
! cannot have type
!   int
 
The message is fairly easy to understand in this case, but for more
complicated type errors I always find that I can't remember which type
is the one that was expected.  It would be a lot easier if it said
"expected expression of type int, but found expression of type bool",
or something similar.
 
* 2002-08-29: From Joe Hurd <joe.hurd@cl.cam.ac.uk>

   I've just been to TPHOLs, where I discussed with Carl Witty the issue
   of minimizing space usage during execution of ML. He came up with
   (what seemed to me) a rather good idea, so thought I'd pass it on.

   The idea is that if you compare the following two terms for equality

   CON subterm1 = CON subterm2

   and the test succeeds, then it's fine to swing the pointer from
   subterm1 to subterm2 (correcting the reference counts as you do it).
   subterm1 might then be left with no references, allowing it to be
   garbage collected. Refinements that suggest themselves are swinging
   the pointer from the least-referenced object to the most-referenced,
   or favouring objects living in more permanent generations with respect
   to the garbage collector.

   Over time, this may well shrink the heap size to its optimal size,
   with only a small overhead on each nontrivial successful equality
   test.

   Has this been tried before? Can you see any flaws with the scheme?

This could be implemented in sml_equal_aux, in the default (block of
references) case.  When two referred-to values *p1 and *p2 are found
to be equal but not identical (*p1 != *p2), and both point into the
young or old heap, we can assign one to the other:
	*p2 = *p1
or 
   	*p1 = *p2

If both p1 and p2 point into the old heap, make both point to the
object with the lowest address (case p1 < p2 resp. p2 < p1 above).  
This never creates a new reference from the old heap to the young one.

If one (say p1) points into the young heap and one (say p2) points
into the old heap, replace the young reference with the old one:
	*p1 = *p2 
This never creates a new reference from the old heap to the young one.

If both p1 and p2 point into the young heap, then:
  - if one block (say v1) is in the young heap and one (say v2) is in the 
	old heap, update the young heap block 
	*p1 = *p2
    (this avoids creating a reference from old heap to the young one)
  - otherwise (both v1 and v2 are in the young heap, or both are in
	the old heap)
	then make both point to least addr.
    (if both are in the young heap, then obviously this does not
    create a reference from the old heap; if both are in the old heap 
    then both references p1 and p2 must be in the ref table already).

The scenario we want to avoid: p1 and p2 point into the young heap and
p2 < p1 so we want to assign *p1 = *p2.  But v1 is in the old heap and
v2 in the young heap.  Then the assignment *p1 = *p2 would create a
new reference from the old heap to the young one.

The garbage collector's invariants must be maintained.  If the garbage
collector is in the mark phase, and the pointed-to block (*p2
resp. *p1 above) is in the old heap, then it must be darkened.  In
principle, this is necessary only if the containing block (v2
resp. v1) is grey or black.

comp w old share 19.920s  ui+uo 4275878 total  

comp w young+old share    ui+uo 4275750 total  
lib  w young+old share    ui+uo 1622111 total 

comp w/o share 20.530s    ui+uo 4280650 total 
lib  w/o share            ui+uo 1622471 total 


test10 w young+old share 
                 User: 1028.260  System: 6.040  GC: 882.780 59388 KB

test10 w/o share User: 1048.470  System: 1.090  GC: 904.220 59736 KB
	         User: 1029.400  System: 0.900  GC: 884.230  

2003-02-20: Doubleword double alignment constraint on Solaris/gcc3.2
were not correctly detected by config/auto-aux/dblalign.c, leading to
crashes (Andreas Jonasson, Gothenburg).  

The dblalign.c script must be compiled with option -O2 to behave like
the production system, and has been made more complicated to provoke
gcc-3.2 to fail.

* 2003-02-26

Random.newgenseed 0.0
 
creates a generator which causes Random.random to always return 0.0

----------------------------------------------------------------------

* 2004-01-12: Time trouble.  

In Moscow ML 2.00 time is represented as a pair of ints.  This
representation was carefully offset by -(2^30) so that it would work
until year 2038 despite the fact that ints are 31 bit only.  (The
unreleased CVS version of Moscow ML uses reals to represent time,
giving microsecond resolution until 2112 and millisecond resolution or
better until year 143970).

But the Moscow ML 2.00 implementation was not careful enough, it turns
out.  After January 10, 2004, the number of seconds since January 1,
1970 exceeds 2^30:

- Date.toString(Date.fromTimeUniv(Time.fromReal(Math.pow(2.0, 30.0)-1.0)));
> val it = "Sat Jan 10 13:37:03 2004" : string

This causes two problems:

(1) On all 32-bit platforms (except Moscow ML.Net) Time.toSeconds will
raise Overflow.  This is unavoidable.  Use Time.toReal instead (this
gives fractional seconds).

(2) Under Moscow ML 2.00 for Windows, loading the Timer structure (or
invoking Moscow ML with mosml -P full, which loads the Timer
structure), will fail.  The reason is that function getrutime in
mosml/src/runtime/mosml.c takes both usr time and real time from the
system time, but neglects to apply the -(2^30) offset:

  Field (res, 2) = Val_long (t.time);
  Field (res, 3) = Val_long (((long) t.millitm) * 1000);
  Field (res, 4) = Val_long (t.time);
  Field (res, 5) = Val_long (((long) t.millitm) * 1000);

This code ought to be fixed as follows:

  Field (res, 2) = Val_long (t.time + TIMEBASE);
  Field (res, 3) = Val_long (((long) t.millitm) * 1000);
  Field (res, 4) = Val_long (t.time + TIMEBASE);
  Field (res, 5) = Val_long (((long) t.millitm) * 1000);

(3) Under CVS mosml, Time.fromReal(Math.pow(2.0, 30.0)) raises
Overflow in fromReal because trunc is applied to the number of seconds
>= 2^30.  Under 2.00 it does not.  

Easily fixed by not doing any truncation in Time.fromReal.

(4) Under CVS mosml Random.newgen() fails because of computations on
time.  Moscow ML 2.00 works (actually, the surprise is that it worked
before 10 Jan 2004).  

Fixed by dividing the number of microseconds by 10^7 rather than 10^6
before applying trunc; this works until year 2310.

(5) Under Moscow ML 2.00, Time.toString(Time.now()) raises Overflow
after 10 Jan 2004 (under CVS mosml it does not).  

Fixed by using basically the same code as in CVS mosml:
    fun fmt p t =
	Real.fmt (StringCvt.FIX (SOME (if p > 0 then p else 0))) (toReal t)

This changes the behaviour of fmt for negative p, but that's mandated
by the new Basis spec anyway.

(6) Under Moscow ML 2.00, Time.now() + Time.fromReal 0.0 raises Overflow.

This has been fixed by performing the computation in reals and convert
to integers afterwards.  Not very pretty:

    val op + = fn ({sec=sec1, usec=usec1} : time, {sec=sec2, usec=usec2}) =>
	let val usecs = usec1 + usec2 in
	    {sec  = trunc(real sec1 - real timebase 
			  + real sec2 + real(usecs div 1000000)),
	     usec = usecs mod 1000000}
	end 


The good news is that under Moscow ML 2.00 as well as CVS mosml,
Date.toString(Date.fromTimeUniv(Time.now())) works correctly.

----------------------------------------------------------------------

* 2004-03-08: Norman Ramsey

Subject: parsing bug in Moscow ML 2.00?
Date: Thu, 26 Feb 2004 14:36:13 -0500 (EST)
From: nr@eecs.harvard.edu (Norman Ramsey)

Peter,

I'm not sure if this is a known bug.  Moscow ML rejects a signature
that is modified with a second `where type' clause.  I believe multiple
`where type' clauses are permitted for the nonterminal `sigexp' in the
Definition, and the file is accepted by SML of New Jersey and by MLton.
I'd welcome a patch.


Norman

: nr@labrador 654 ; mosml                 
Moscow ML version 2.00 (June 2000)
Enter `quit();' to quit.
- 
: nr@labrador 655 ; mosmlc -toplevel -c /tmp/bad.sml
File "/tmp/bad.sml", line 6, characters 41-45:
! functor F(S : S where type t = int where type u = bool) = struct
!                                          ^^^^
! Syntax error.
: nr@labrador 656 ; cat /tmp/bad.sml
signature S = sig
  type t
  type u
end

functor F(S : S where type t = int where type u = bool) = struct
  fun f (x:S.u) = if x then 3 else (4:S.t)
end
: nr@labrador 657 ;

--- 

Indeed your example should compile according to the definition.  It
does not in Moscow ML 2.00 and 2.01 because of a Moscow ML language
extension that permits longtycons to have a where clause.  This causes
a shift/reduce conflict in the parser that is resolved in the wrong
way.  I thought I could fix it with associativity and precedence
declarations, but it's a little harder than expected.

But here's a (non-pretty) fix: put parentheses around your longtycons,
as in

  functor F(S : S where type t = (int) where type u = (bool)) = struct end

This is legal SML syntax and so should be acceptable to SML/NJ and
MLton, and it prevents mosml 2.00 from thinking that the `where type
u' belongs to `int'.

---

517: shift/reduce conflict (shift 478, reduce 324) on WHERE
state 517
	ModExp : ModExp COLONGT SigExp .  (324)
	SigExp : SigExp . WHERE WhereType  (342)

	WHERE  shift 478
	ABSTYPE  reduce 324
	AND  reduce 324

Here we would like it to reduce rather than shift on WHERE.  Thus it
might be possible to fix this by making WHERE left-associative and
give it a sufficiently high precedence.  However, that might
jeopardize WHERE in connection with functor signatures.

Tried this but failed:

/* %left COLON COLONGT */
/* %left     WHERE */

+ 2004-05-24: Thu, 20 May 2004 22:34:41 +0200 Andrzej Wasowski
   <wasowski@data.pl>

structure C = struct
        datatype 'a t1 = T1 of 'a * 'a t2 list
             and 'a t2 = T2 of 'a t1 list

        fun f (T1 (a,ls)) = T1 (a, map g ls)
        and g (T2 ls    ) = T2 (map f ls   )
end


structure B = struct
        structure D = C
end

Fails with complaint about non-generalized type variable.  Claudio: my
suspicion is that the problem is due to the inferred type schemes for
f and g having a shared bound type variable, (generalization doesn't
rename the bound variables) which subsequently could confuse the
renaming code that assumes all bound variables are distinct.  

Changed closeValBindVE in Elab.sml to copy the type scheme before
closing the valbind.


+ 2004-07-26: From David Greaves <David.Greaves@cl.cam.ac.uk>

There is a bug in mosml sockets implementation that means that only 16
byte of a received UDP datagram are passed up to the user.

The bug is in the foreign function msocket_recvfrom in 
src/dynlibs/msocket/msocket.c:

/* ML type: sock_ -> Word8Vector.vector -> int -> int -> int -> int * addr */
EXTERNML value msocket_recvfrom(value sock, value buff, value offset, ...
  ...

  ret = recvfrom(Sock_val(sock), &Byte(buff, Long_val(offset)), 
                 Int_val(size),
                 Int_val(flags), &addr.sockaddr_gen, &len);
  ...

    res = alloc_tuple(2);
    modify(&Field(res, 0), Val_int(len));     <------ ERROR!!!!
    modify(&Field(res, 1), roots[0]);

  ...
 
  return res;
}

The faulty line should read:

  modify(&Field(res, 0), Val_int(ret));    


2004-11-02: Andrzej W:

This looks like a bug in the parser of Moscow ML:

signature A = sig type a type b end
                      where type a = int
                      where type b = int

(*
wasowski@klimt scope--reachability--0-SOURCE $ mosml ,test.sml
Moscow ML version 2.01 (January 2004)
Enter `quit();' to quit.
[opening file ",test.sml"]
File ",test.sml", line 4, characters 14-18:
!                     where type b = int end
!                           ^^^^
! Syntax error.
[closing file ",test.sml"]
-
*)


The above code parses both in SML/NJ and MLTon. Also the definition
(p.13, sigexp) seems to allow multiple where clauses.

This error in the parser has been noted also by Norman Ramsey, see
2004-03-08.


* 2005-05-23: From: varming@itu.dk
To: Peter Sestoft <sestoft@itu.dk>
Subject: The Standard ML Basis Library Manual inconsistency

Someone permuted the argument to packString.

The type of Byte.packString in the manual:
Word8Array.array * int * substring -> unit

and in mosml and the kit:
val it = fn : substring * array * int -> unit


+ 2005-06-25:
Date: Sat, 25 Jun 2005 15:18:42 +0000
From: Rob Arthan <rda@lemma-one.com>
Subject: Problem with antiquotation in Moscow ML

It isn't any great problem to me, but I noticed playing around with quotations
and antiquotations that (illegal) input like `a b c ^42` makes Moscow ML
hang. Here's a transcript:

    - `a b c ^(42)`; (* OK *)
    - `a b c ^42`; (* illegal: "42" is not an identifier, hangs ... *)
[Control+C typed here]

PS fixed Lexer.lex by replacing:

  | _
      { 
        lexingMode := QUOTElm;   
        lexError "ill-formed antiquotation" lexbuf 

      }

with 

  | _
      { 
        skipString "ill-formed antiquotation" SkipQuotation lexbuf
      }


+ 2005-06-28: Extending the globals offset from 16 to 32 bits.

Currently, 

GETGLOBAL, SETGLOBAL, PUSH_GETGLOBAL, PUSH_GETGLOBAL_APPLY[1-4]: 
 16-bit --> 32-bit arg

PUSH_GETGLOBAL_APPTERM[1-4]:
 16-bit + 16-bit --> 16-bit + 32-bit

compiler/Emitcode.sml

 No changes.

compiler/Reloc.sml

 + slot_for_literal, slot_for_get_global and slot_for_set_global should
   out_long instead of out_short

compiler/Patch.sml

 + patch_object should patch_long (new function) for literals and globals

runtime/interp.c:

 + In byte_raise_break_exn, two more 0's, at the end (little-endian) or
   the beginning (big-endian).

 + Increase RAISE_CODE_LEN to 6

 + In GETGLOBAL, SETGLOBAL, PUSH_GETGLOBAL_APPLY[1-4], etc:
   u16pc -> u32pc and += SHORT -> += LONG

 + In PUSH_GETGLOBAL_APPTERM1 (only), second occurrence of u16pc -> u32pc. 

runtime/fixcode.c:

 + In fixup_endianness, more GETGLOBAL etc and SETGLOBAL to the
   MAKEBLOCK group of instructions.

 + Need a new category: one two-byte and one four-byte argument, for
   PUSH_GETGLOBAL_APPLY[1-4]
	
runtime/expand.c:

 + Move GETGLOBAL, SETGLOBAL, PUSH_GETGLOBAL_APPLY[1-4] to the MAKEBLOCK
   group of instructions.

 + Change the PUSH_GETGLOBAL_APPTERM[1-4] instructions to use u32pc for
   the second arg, and LONG instead of SHORT

* 2005-10-19: Fritz Henglein <henglein@gmail.com>

Under MosML 2.01 (Windows XP) sker der at

Date.date {year = 1970, month = Date.Jan, day = 1, hour = 0, minute = 0,
second = 0, offset = NONE};

får MosML til at gå ned.  Det sker øjensynligt for de (og kun de?!)
datoer, der ligger den 1. januar 1970 f'ør kl. 1:00, altså
1.1.1970 fra kl. 0:00:00 til 0:59:59.

> Det lyder som den rigtige diagnose. Men hvorfor fungerer det øjensynligt for
> datoer i 1969? (Er det, fordi de bliver håndteret særskilt i MosML?)

Ja, forklaringen er denne betingelse:

    if year < 1970 orelse year > 2037 then date1
            else
                case offset of
                    NONE   =>
                        tmozToDate (getlocaltime_ (mktime_ (dateToTmoz date1)))
                                   offset
                  | SOME t => date1

som forsøger at gøre alle tilpas ved at normalisere datoen (med ugedag
osv) hvis den falder inden for et interval hvor det et plausibelt at
det kan lade sig gøre.  På Win XP er der så 1 time hvor det ikke
virker; det må vi vist forsøge at håndtere i C-koden.

* 2005-11-09 Discussion with Ken 
  Moscow ML future:

   - Moscow ML.NET:
     Ken has resurrected mosml.net and integrated into CVS version.
     Some build problems remain.
     Should remain in sync in the future.
     Should check in somehow into mosml2.0 CVS.
     Make mosml.net the main branch?  
       Pro: 32 bit int, no sync needed, thread support, .Net libs, 
            simple FFI, potential MS funding, F# collaboration, 
            new research (sep comp on .Net w speed), easier MSR contrib, 
            ...
       Con: lockin (but: Mono), redo libraries (MuDDy, mGTK, msql, intinf), 
            performance, memory consumption, ...
     Milestone  0: Makefile from NJK so Ken can build
     Milestone  1: integration with current CVS mosml
     Milestone  2: simplify build process (stay w csc and gnu make)
     Milestone  3: build with mono 
     Milestone  4: integrate library source files (#ifdef)
     Milestone  5: design joint libraries (files, io)
     More ...
     Milestone 10: only one compiler with options: mosmlc -net *.sml
     How to integrate the two libraries and the two backends etc?
       --> #ifdef?
       
   - Support for MLB files:
     Similar to PM files
     - Need mosmlc option to specify target: 
         mosmlc A.sml -toplevel -targetprefix _1A
       when compiling "local A.sml in C.sml end".
       Ken to implement this option.
       (Or, more ambitiously, create packages of .ui and .uo files)
     - Need mosmlb tool to read .mlb files and call mosmlc.

   - Next release, what is needed

     Release 2.02 (mini-release): Date 
     - Library up to date
       Ken to organize lib BL status investigation 
       (w Michael N, Henning, Claudio)
     - Various bug fixes and small embellishments
     - Option -targetprefix
     - mosmlb (Ken)

     Release 2.10:
     - Many more bug fixes
       - 
     - Requests for new functionality (this file)
       - 
     
     
   - Collaboration ML Kit and mlton
     Especially Basis Library io and .mlb files.


2006-06-25 Michael Norrish intern.c exception "too big" 

sestoft@jones:~/tmp$ ll trace0910Theory.uo
40024 -rw-r--r--  1 sestoft sestoft 40938033 Jun 22 07:55 trace0910Theory.uo
sestoft@jones:~/tmp$ md5sum trace0910Theory.uo
2bed6ce5b00498b93da8f5c6d0c819c2  trace0910Theory.uo

load "trace0910Theory.uo";

Stop = 6247533 (from Smltop.sml) = 00 5f 54 6d
code_len = 6247529 (from Smltop.sml)
wosize = 8672622 (from intern.c)
! Uncaught exception:
! Fail  "intern: structure too big #2"

The claimed size of the data structure is 8672622 * 4 B = 34690488

Added to the code size, that gives 40938021 B, which doesn't leave
enough space for the header and the metadata at the end of the file.
Not to mention that there are several (short) strings in the file.


hd trace0910Theory.uo:

00000000  00 5f 54 6d 6a 00 00 00  00 5d 05 13 00 00 00 6a  |._Tmj....].....j|

005f5460  00 00 6c 00 00 00 00 03  05 00 00 00 48 84 95 a6  |..l.........H...|
005f5470  ba 00 84 55 6f 00 17 00  00 02 00 00 00 1c 00 00  |...Uo...........|
005f5480  00 24 00 00 00 30 00 00  00 4c 00 00 00 fa 07 00  |.$...0...L......|
005f5490  00 58 00 00 00 01 0b 00  00 64 00 00 00 78 00 00  |.X.......d...x..|
005f54a0  00 fd 1b 00 00 4e 31 6c  5a 49 44 58 7a 2b 54 75  |.....N1lZIDXz+Tu|

@005f546d = 8495a6ba = 1000 0100 1001 0101 1010 0110 1011 1010 
@005f5471 = 0084556f = 8672623 (dec) which whsize.

The object we're looking for has type compiled_unit_tables and is a
record of size 5.

A wosize of 5 should give a header of this form (in bin):

00000000 00000000 000101xx 00000000 where xx = 11 is a Black header

and in hex

00 00 17 00 



 * Date: Tue, 14 Mar 2006 17:09:58 -0700
   From: Konrad Slind <slind@cs.utah.edu>
   Subject: FYI Moscow ML on Tiger

I just spent a little time getting Moscow ML to build on Tiger. Not
sure that I've got it completely sussed wrt dynamic libraries, but
the following over-rides in src/Makefile.inc of the Moscow ML
distribution helped in getting the basic executable to compile:

     CC=gcc-3.3
     LD=gcc-3.3 -flat_namespace
     STRIP=echo

In src/runtime/Makefile, you also need to add -lSystemStubs to BASELIBS:

    BASELIBS=-lm -lSystemStubs

If you get better info than the above results of my blundering about,
let me know!

 * Date: Sun, 20 Aug 2006 15:09:54 +0100
   From: Ian Grant <ian.grant@cl.cam.ac.uk>

Here is a tiny patch to allow the mosml 2.01 msocket library to compile under 
GCC4 which no-longer allows a cast in an lvalue (see 
http://gcc.gnu.org/gcc-3.4/changes.html "The cast-as-lvalue extension has 
been removed for C++ and deprecated for C and Objective-C.") . I have tested 
this with the simple client/server test in that directory, so I know it has 
run at least once :-) The #ifdef macintosh branch of the Sock_val define 
could probably be merged with this change as it most likely came about for 
the same reason.

Yours sincerely
Ian Grant

--- src/dynlibs/msocket/msocket.c.orig  2000-01-21 10:07:13.000000000 +0000
+++ src/dynlibs/msocket/msocket.c       2006-08-20 14:35:06.000000000 +0100
@@ -70,6 +70,7 @@
 #else
 #define Sock_val(x) ((int) Field(x,0))
 #endif
+#define Sock_lval(x) (Field(x,0))
 
 /* Decomposition of addr values: */
 #define Size_addrval(a)   Field(a, 0)
@@ -111,7 +112,7 @@
 /* ML return type: sock_ */
 static value newsocket(int sock) {
   value result = alloc(1, Abstract_tag);
-  Sock_val(result) = sock;
+  Sock_lval(result) = sock;
   return result;
 }
 
+ Problem building on Fedora, Gentoo and SUSE 64 bit

2007-10-17: This is due to problems with certain versions of malloc(),
which alternatively allocate memory for the camlrunm heap in very high
addresses using mmap() or in very low addresses using brk().  

This span requires a huge page_table (14 GB or so), which it would be
silly to allocate.

The problem can be avoided by either forcing high memory allocation
using this environment variable:

   export MALLOC_MMAP_THRESHOLD_=0

or by using forcing low memory allocation using this environment
variable:

   export MALLOC_MMAP_MAX_=0

There may be performance implications of either of these choices.  The
latter one would limit usable mosml memory to at most 3 GB, I think,
whereas the former one has been experimentally tested to allow mosml
to use more than 4 GB.

Also note that these environment variables affect *all* programs that
use malloc() and hence may have mysterious side effects.

A better solution is to use 

   export MALLOC_MMAP_MAX_=0

in the shell only when building Moscow ML, and then use a shell script
that sets one of these variables, in the new shell only, when invoking
mosml, mosmlc and mosmllex.  This way it will not affect any other programs.  

The long term solution is to add yet another #ifdef to the runtime
source, and use mmap() and munmap() instead of malloc() and free() on
64-bit architectures.


+ 2008-03-05: Mail from Tom Ridge, Cambridge: glibc 2.7 is a problem.  Diagnosed on 
virtual machine (ssh -p 2222 -l itu localhost) thanks to Kenneth Ahn Jensen.

From
http://www.gnu.org/software/libtool/manual/libc/Malloc-Tunable-Parameters.html
and <malloc.h> we have

/* mallopt options that actually do something */
#define M_TRIM_THRESHOLD    -1
#define M_TOP_PAD           -2
#define M_MMAP_THRESHOLD    -3
#define M_MMAP_MAX          -4
#define M_CHECK_ACTION      -5

/* General SVID/XPG interface to tunable parameters. */
extern int mallopt __MALLOC_P ((int __param, int __val));

That is, one could initially call 

	mallopt(M_MMAP_MAX, 0);

to make sure that there is no allocation using mmap().

The right place to do this is in mosml/src/runtime/gc_ctrl.c function
init_gc; a version gc_ctrl.c.new with the required edits has been made
and has been tested with glibc 2.7 on a 32 bit machine and on a 64 bit
machine.


2008-11-19 Unsafe type inference

Date: Wed, 19 Nov 2008 10:10:53 +0000
From: Claudio Russo <crusso@microsoft.com>

Carsten (Varming) has discovered a type inference bug in Mosml which
allows violations of the value restriction.

Here’s his original code. Warning: the presence/absence of semicolons
between declarations is significant!


(* GOOD ML PROGRAM *)

fun new () = let val r = ref NONE
in ((fn t => fn () => r := SOME t), fn f => (r := NONE ; f() : unit ; valOf (!r)))

end (* no semicolon here is significant! *)

(* BAD NON-ML PROGRAM *)

val bad = let val r = ref NONE
in ((fn t => fn () => r := SOME t), fn f => (r := NONE ; f() : unit ; valOf (!r)))
end;

val (a,b) = bad; (*a, b are polymorphic not monomorphic as they should be...*)

val z = a 1;

val y = #1 bad "1";

val yy = #2 bad y;

(* val crash = #2 bad z; *)

And here’s a smaller repro:

(* smaller repro *)

(* compare *)

val y = ref []; val z_ok = y;

(* z_ok correctly not polymorphic *)

(* with *)

val x = () val y = ref []; val z_wrong = y;

(* z_wrong incorrectly polymorphic *)

Notice that in the smaller repro, the only difference is that y is
declared in a compound declaration. I

It's just a hunch but what I think this boils down to is a levels bug.
Perhaps the current type var level is being incremented in the nested
declaration, but then reverted at the semicolon, leading to incorrect
generalization at z_wrong.

I always regret not having gone for a purely functional implementation of
type inference....

For now, it might be good to add this email to the bugs list (wherever
that lives) or just check it in somewhere in the repository.

Claudio adds: I've had a quick look at the mosmlnet source (all I
have) and it does indeed look like the binding level is reset to zero
at each topdec, so variables generated with a higher level, but not
generalized in the previous dec, will get generalized in a subsequent
one. I think a fix might be to reset the binding levels of all new
type variables in the object of the current dec to zero before
proceeding.

There may be even be handle to those variables somewhere handy but I
can't recall just now.


2008-12-25:  From: Claudio Russo <crusso@microsoft.com>

I?ve been told of yet another bug, this one thankfully a little more
obscure ? can you add it to the list? This one came up in the authors?
response to a referee report on recursive modules...


> Moscow ML's type checker aborts
> signaling "Internal error: elabRecSigExp", given the recursive
> signature below:

signature REC =
  rec (Z: sig functor F : functor X : sig type t end -> sig type t end
               structure M : sig type t end
          end)
  sig
    functor F : functor X :  sig type t end 
                             -> 
                             sig datatype t = A of Y.t where Y = Z.F(Z.M) end
    structure M : sig type t end
end

2009-03-15: From ian.grant@cl.cam.ac.uk Tue Dec 23 17:21:46 2008

Thanks for you help on the Moscow ML build issue. I have fixed the  
MacPorts mosml package and added a new one mosml-dynlibs with all the  
dynlibs except the big databases (mysql and postgres.)

I submitted the changes to the MacPorts people: http://trac.macports.org/ticket/17659 
  and we just have to wait for someone to apply them. I'll let you  
know when it happens.

As regards the existence of this directory. I think it is there  
because the file config.h is originally from the runtime subdirectory  
where it uses

#include "../config/m.h"
#include "../config/s.h"

to get at the auto-generated files. So when config.h is copied into  
$MOSMLHOME/include it needs the symbolic link to work. I got around it  
in the MacPorts build by adding an LSB switch which I turn on when  
building dynlibs after the initial mosml install.

--- ../mosml.orig/include/config.h      2004-01-19 15:02:21.000000000  
+0000
+++ ./include/config.h  2008-12-03 11:39:56.000000000 +0000
@@ -2,7 +2,7 @@
  #define _config_


-#if defined(__MWERKS__) || defined(THINK_C)
+#if defined(__MWERKS__) || defined(THINK_C) || defined(LSB)
  #include "m.h"
  #include "s.h"
  #else

>> I am trying to fix the Mac Ports Moscow ML package to use dynamic  
>> libraries. These all build and work well on Mac OS X now.

>> The problem is that the config -> include symlink is complicating  
>> matters. Standard use of namespace means that we can't install  
>> headers, binaries etc in $MOSMLHOME e.g. /usr/mosml/ 
>> {bin,include,config} etc, rather we must install under /usr/bin, / 
>> usr/lib, /usr/include/mosml etc. This makes the symbolic link that  
>> was $MOSMLHOME/config -> $MOSMLHOME/include awkward. I am trying to  
>> remove all references to the $MOSMLHOME/config subdirectory but  
>> they keep popping up again. Do you recall what is the reason for  
>> separating config and include directories in the first place?
