(*
 Code from the 2nd lecture.
*)

val ex1 =
    case [1,2,3] of
      [] => 0
    | (1::xs) => if null xs
                    then 1
                    else 2
    | (x::xs) => 3;


val ex2 =
  let val x = 34
      fun f x = x - 3
  in f x - 4 end;


exception Error of string;

fun error s = raise (Error s);

fun ex3 b = (if b then error "true branch" else "false branch")
            handle   Error message => message
                   | other => raise other;


datatype Tree = Tip | Node of Tree * int * Tree;

val tree1 = Node (Node(Tip,4,Tip),7,Node(Tip,10,Tip));

fun sum Tip = 0
  | sum (Node(x,n,y)) = n + sum x + sum y;

(* using the binary search tree invariant *)

fun search n Tip = false
  | search n (Node(x,m,y)) =
      if n=m
         then true
         else if (n < m) then search n x
                         else search n y;

val ex4 = search 3 tree1;
val ex5 = search 10 tree1;

datatype Exp
  = Const of int
  | Add of Exp * Exp
  | Mult of Exp * Exp
  | Sub of Exp * Exp;

val exp1 = Add(Const 4,Const 3);
val exp2 = Mult(exp1,exp1);

fun ExpValue (Const n) = n
  | ExpValue (Add(x,y))  = ExpValue x + ExpValue y
  | ExpValue (Mult(x,y)) = ExpValue x * ExpValue y
  | ExpValue (Sub(x,y))  = ExpValue x - ExpValue y;


datatype Token
  = Id of string
  | Plus
  | Times
  | Eql
  | Int of int
  | Illegal;




fun extend x (xs, cs) = ((x::xs), cs);

(* ident: char -> char list -> (Token * char list) *)
fun ident c cs =
  let fun help x [] = ([x],cs)
        | help x (c::cs) =
              if Char.isAlpha c
                 then extend x (help c cs)
                 else ([x],c :: cs)
      val (lexeme,rest) = help c cs
  in (Id (String.implode lexeme),rest) end;


(* literal: char -> char list -> (Token * char list)  *)
fun literal c cs =
  let fun help x [] = ([x],cs)
        | help x (c::cs) =
              if Char.isDigit c
                 then extend x (help c cs)
                 else ([x],c :: cs)
      val (lexeme,rest) = help c cs
  in case Int.fromString (String.implode lexeme) of
       NONE => (Illegal,rest)
     | SOME n => (Int n,rest)
  end;


(* lex : char list -> (Token * char list) *)
fun lex [] = (Illegal,[])
  | lex (#" " :: cs) = lex cs
  | lex (#"+" :: cs) = (Plus,cs)
  | lex (#"*" :: cs) = (Times,cs)
  | lex (#"=" :: cs) = (Eql,cs)
  | lex (c :: cs) =
      if      Char.isAlpha c then ident c cs
      else if Char.isDigit c then literal c cs
      else (Illegal,c::cs);

fun test s =
   let val (token,cs) = lex(String.explode s)
   in (token,String.implode cs) end;


(* 
*)