README: interactive interpreter for Fun language

1. The program consists of the following files:

  fun.cm            -- CM description file for building the interpreter

 -- input character streams of various forms --
  charstream.sig       -- INSTREAM signature
  liststream.sml       -- ListInstream: INSTREAM  structure   (source = lists of characters)
  stringstream.sml     -- StringStream: INSTREAM  structure   (source = string)
  lazystreamstream.sml -- LazyStreamStream: INSTREAM structure (source = lazy list of chars)
  generatorstream.sml  -- GeneratorStream: INSTREAM structure  (source = character generator fn)
  instreamstream.sml   -- InstreamSteam: INSTEAM structure     (source = TextIO.instream)
  filestream.sml       -- FileStream: INSTREAM structure       (source = text file)
  interactstream.sml   -- InteractStream: INSTREAM structure   (source = stdin)

 -- the reader abstraction --
  reader.sig        -- READER signature, interface for a generic reader monad
  reader.sml        -- Reader: READER, implements READER

 -- lexical analysis --
  token.sml         -- Token structure, defining set of lexical tokens
  lexerfn.sml       -- LexerFn(S: INSTREAM), the lexer (scanner, tokenizer)

 -- parsing --
  syntax.sml        -- Syntax - abstract syntax of types, expressions, declaratons, statements
  parserFn.sml      -- Parser(S: INSTREAM) - parses instream to abstract syntax

 -- type checking --
  type.sml          -- Type - the type checker

 -- evaluation --
  env.sml           -- Env - polymorphic environments with string keys implemented by ordered alists
  eval.sml          -- Eval - defines values and evaluators for expressions and declarations

 -- top-level interpreter --
  print.sml         -- Print - simple print functions for types and values and statements
  interp.sml        -- InterpFn(S: INSTREAM) - interactive top-level loop of interpeter (function run).

  test.sml          -- define run functions for string, file, interact instreams


2. To build, run sml in the fun source directory and execute

   - CM.make "fun.cm";


3. To run the interactive interpreter, instantitate the interpreter for a particular
kind of instream.  E.g.

   - structure I = InterpFn (StringStream);

Then invoke I.run with an appropriate instream of that kind:

   - I.run(StringStream.mkInstream "3+2; quit;");

Another example gives an interactive top-level for the interpreter:

   - structure Interact = InterpFn(InteractStream);

   - Interact.run(InteractStream.mkInstream ());

Now you can type in expressions and declarations in the Fun language, terminating
each expression or declaration with a semicolon to form a top-level statement.
The input prompt is the "#" character. Exit the interpreter by inputing the
statement "quit;".

Several interpreters are set up in the file test.sml.  Load this file by 
executing

   - use "test.sml";


----------------------------------------------------------------------------------
Discussion  [Requires updating.]

The language accepted by the Fun interpreter is very similar to the
language PTFun defined in Appendix A of Lecture 10 in CMSC 22100 (Fall, 2010).
It is a typed call-by-value functional language, including polymorphic and recursive
types.

It handles arithmetic operators including unary negation (~) and binary operators:

     +, -        (addition and subtraction)
     *, /, %     (multiplication, integer division, modulo)

It also handles boolean expressions:

     e relop e'    (relop in  ==, /=, <, >, <=, >=)
     e || e'
     e && e'
     not(e)

It has variables (alphanumeric) bound by let declarations:

     val x = e

and anonymous function expressions:

     fn x : ty => e

with function applications of the form

     f e
     f e1 e2
     f e1 e2 e3
     etc.

where f and the argument expressions ei are atomic (variables or parenthesized
expressions).

The operator precedences are follow the usual conventions, from weakest to
strongest:

     ||; &&; (==, /=, <, >, <=, >=); (+, -); (*, /, %)

with function application forms ("not(e)", "~e", "f(e)") binding most strongly.

There is also a general conditional expression

    if e1 then e2 else e3

where e1 must have a boolean value and e2 and e3 can have any values.

Recursive functions can be declared at top-level.  For instance, the factorial function can be
defined by:

    fun fact(x:Int):Int = if x == 0 then 1 else x * fact(x-1)

Recursive functions can also be declared locally using letrec.

Fun Grammar
-----------
[Not up to date. -- See Appendix A of CMSC 221 Lecture 10, or refer to the parser
 defintion in parserfn.sml.]

Here is the full grammar of the Fun language handled by the interpeter.

empty  ::=

-- atomic expressions
nat     ::=  Nat n    -- literal Nat token
bool    ::=  "True" | "False"
id      ::=  Id s     -- literal Id token
atom    ::=  nat | bool | id | "(" expr ")"

-- application expression
appexpr ::= atom atom+     -- curried application 

-- arithmetic expressions
aexpr   ::=  aterm ("+" aexpr | "-" aexpr | empty)
aterm   ::=  afactor ("*" aterm | "/" aterm | "%" aterm | empty)
afactor ::=  appexpr | atom

-- relational expression
rexpr  ::=  aexpr "==" aexpr | aexpr "/=" aexpr | aexpr "<" aexpr
        |   aexpr ">" aexpr | aexpr "<=" aexpr | aexpr ">=" aexpr 

-- boolean expressions
bexpr   ::=  bterm ("||" bexpr | empty)
bterm   ::=  bfactor ("&&" | empty)
bfactor ::=  rexpr | aexpr

-- conditional expression
cexpr  ::=  "if" expr "then" expr "else" expr

-- let expression
lexpr  ::=  "let" id "=" expr in expr

-- function expression
fexpr  ::=  "fn" id "=>" expr

-- toplevel expression
expr ::= lexpr
      |  fnexpr
      |  cexpr
      |  bexpr

decl   ::=  "def" id "=" expr | "fun" id id = expr
stmt   ::=  decl | expr
prog   ::=  stmt (";" prog | empty)


----------------------------------------------------------------------
To Do.

* Type checker is not being invoked in the interactive loop.
