(* --------------------------- Ident syntax tests -------------------------- *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)

module M = struct type t = <| f : nat |> end
let _ = <| M .f = 1 |>

===============================================================================
module M = struct module N = struct type t = <| f : nat |> end end
let _ = <| M .N.f = 1 |>

===============================================================================
module M = struct module N = struct type t = <| f : nat |> end end
let _ = <| M. N.f = 1 |>

===============================================================================
module M = struct module N = struct type t = <| f : nat |> end end
let _ = <| M.N .f = 1 |>

===============================================================================
module M = struct module N = struct type t = <| f : nat |> end end
let _ = <| M.N. f = 1 |>

===============================================================================
module M = struct let x = (1 : nat) end
let _ = M .x

===============================================================================
module M = struct module N = struct let x = (1 : nat) end end
let _ = M .N.x

===============================================================================
module M = struct module N = struct let x = (1 : nat) end end
let _ = M. N.x

===============================================================================
module M = struct module N = struct let x = (1 : nat) end end
let _ = M.N .x

===============================================================================
module M = struct module N = struct let x = (1 : nat) end end
let _ = M.N. x


===============================================================================
(* --------------------------- Type tests ---------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)

type t = u

===============================================================================
type t = nat nat

===============================================================================
type t 'a = c of 'a
type u = t

===============================================================================
class (c 'a) val f : 'a end
type t = c

===============================================================================
(* ------------------------ Pattern tests ---------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)

type x = | X
let f (X a) = (1 : nat)

===============================================================================
type x = | X of bool
let f (X a b) = (1 : nat)

===============================================================================
module M = struct type t = | Y end
let f (M.X y) = 1

===============================================================================
let f (M.X y) = (1 : nat)

===============================================================================
type t = <| X : nat |>
let f (X y) = (1 : nat)

===============================================================================
let f (X y) = 1

===============================================================================
type t = | X of nat
let f (_ as X) = match 1 with | (X 1) -> 1 end

===============================================================================
let f <| fld = (1:nat) |> = (1:nat)

===============================================================================
type t = | fld
let f <| fld = (1:nat) |> = (1:nat)

===============================================================================
let fld = (1:nat)
let f <| fld = (1:nat) |> = (1:nat)

===============================================================================
class (c 'a) val fld : nat end
let f <| fld = (1:nat) |> = (1:nat)

===============================================================================
type t = <| fld : bool |>
let f <| fld = true; fld2 = false |> = 0

===============================================================================
type t = <| fld : bool |>
let f <| fld = true; fld = true |> = 0

===============================================================================
let f (x,x) = 1

===============================================================================
(* ------------------------ Expression tests ------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)

let _ = x

===============================================================================
let f x = x +++ x

===============================================================================
let _ = M.x

===============================================================================
module M = struct let y = (10:nat) end
let _ = M.x

===============================================================================
module M = struct let y = (10:nat) end
let _ = M.N.x

===============================================================================
type t = <| x : bool |>
let _ = x

===============================================================================
let _ = fun x x -> x

===============================================================================
let _ = <| fld = (1:nat) |>

===============================================================================
type t = | fld
let _ = <| fld = (1:nat) |>

===============================================================================
let fld = (1 : nat)
let _ = <| fld = (1:nat) |>

===============================================================================
type t = <| fld : bool |>
let _ = <| fld = true; fld2 = false |>

===============================================================================
type t = <| fld : bool |>
let _ = <| fld = true; fld = true |>

===============================================================================
type t = <| fld1 : bool; fld2 : bool |>
let _ = <| fld1 = true |>

===============================================================================
let _ = 
  let x = x in
    x

===============================================================================
let _ = 
  let f x = f x in
    f

===============================================================================
let _ = 
  let f x = 1 in
    x

===============================================================================
let _ = { x | forall y | x }

===============================================================================
let _ = { x | forall (x IN x) | x }

===============================================================================
let _ = { x | forall (x IN {}) (x IN {}) | x }

===============================================================================
let _ = [ x | forall (x IN {}) | x ]

===============================================================================
let _ = [ x | forall x | x ]

===============================================================================
let _ = forall (x IN x). true

===============================================================================
let _ = forall (x IN {}) (x IN {}). true

===============================================================================

(* ---------------------------- Do notation tests -------------------------- *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)

let _ = 
  do M
  in
    [(4 : nat)]
  end

===============================================================================
module M = struct
  type x = nat
end
let _ =
  do M
  in
    Nothing 
end

===============================================================================
module M = struct
  type t 'a = maybe 'a
end
let _ =
  do M
  in
    Nothing 
end

===============================================================================
module M = struct
  type t 'a = maybe 'a
  let return x = Just x
end
let _ =
  do M
  in
    Nothing 
end

===============================================================================
module M = struct
  type t 'a = maybe 'a
  let bind x y = match x with Nothing -> Nothing | Just x -> y x end
end
let _ =
  do M
  in
    Nothing 
end

===============================================================================
module M = struct
  let return x = Just x
  let bind x y = match x with Nothing -> Nothing | Just x -> y x end
end
let _ =
  do M
  in
    Nothing 
end

===============================================================================
module M = struct
  type t 'a = return of 'a
  val bind : forall 'a 'b. t 'a -> ('a -> t 'b) -> t 'b
  let bind x f = match x with return y -> f y end
end
let _ =
  do M
  in
    M.return (1 : nat) 
end

===============================================================================
module M = struct
  type t 'a = maybe 'a
  let return x = Just x
  let bind x y = match x with Nothing -> Nothing | Just x -> y x end
end
let _ =
  do M
    x <- (1 : nat);
  in
    Nothing 
end

===============================================================================
module M = struct
  type t 'a = maybe 'a
  let return x = x
  let bind x y = match x with Nothing -> Nothing | Just x -> y x end
end
let _ =
  do M
  in
    Nothing 
end

===============================================================================
module M = struct
  type t 'a = maybe 'a
  let return x = Just x
  let bind x y = match x with Nothing -> Nothing | Just x -> x end
end
let _ =
  do M
  in
    Nothing 
end

===============================================================================
module M = struct
  type t 'a = maybe 'a
  let return x = Just x
  let bind x y = match x with Nothing -> Nothing | Just x -> y x end
end
let _ =
  do M
  in
    (1 : nat) 
end

===============================================================================
module M = struct
  type t = maybe nat 
  let return x = Just x
  let bind x y = match x with Nothing -> Nothing | Just x -> y x end
end
let _ =
  do M
  in
    Nothing 
end

===============================================================================
module M = struct
  type t 'a 'b = maybe 'a 
  let return x = Just x
  let bind x y = match x with Nothing -> Nothing | Just x -> y x end
end
let _ =
  do M
  in
    Nothing
end

===============================================================================
module M = struct
  type t 'a = maybe 'a 
  let return (x,y) = Just x
  let bind x y = match x with Nothing -> Nothing | Just x -> y x end
end
let _ =
  do M
  in
    Nothing
end

===============================================================================
module M = struct
  type t 'a = maybe 'a 
  let return x = Just x
  val bind : forall 'a. t 'a -> ('a -> t 'a) -> t 'a
  let bind x y = match x with Nothing -> Nothing | Just x -> y x end
end
let _ =
  do M
  in
    Nothing 
end

===============================================================================

(* ------------------------ Type definition tests -------------------------- *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)

type t = nat and t = bool

===============================================================================
type t = nat
type t = nat

===============================================================================
class (c 'a) val f : 'a end
type c = nat

===============================================================================
type t 'a 'a = nat

===============================================================================
type t = <| f : bool; f : bool |>

===============================================================================
type t = <| f : bool |>
type u = <| f : bool |>

===============================================================================
type t = <| f : bool |> and u = <| f : bool |>

===============================================================================
type t = u and u = bool

===============================================================================
type t = | C | C

===============================================================================
type t = | C and u = | C

===============================================================================
type t = | C
type u = | C

===============================================================================
let C = (1:nat)
type u = | C

===============================================================================
class (c 'a) val C : nat end
type u = | C

===============================================================================
type u 'a = 'a and t = list 'a

===============================================================================
type u 'a = 'a and t = C of 'a

===============================================================================
type u 'a = 'a and t = <| f : 'a |>

===============================================================================
type t 'a
type u 'b = t

===============================================================================
type t
type u 'b = t 'b

===============================================================================
type t 'a 'b 
type u 'b = t 'b

===============================================================================
type t = _

===============================================================================
type t = C of _

===============================================================================

(* ------------------------ Value definition tests ------------------------- *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)

(* Has a type error, unless not using any backends (except for tex) *)
val x : nat
let _ = x

===============================================================================
val x : 'a

===============================================================================
val x : forall 'a 'b 'a. nat

===============================================================================
val x : _

===============================================================================
val x : forall 'a. c 'a => nat

===============================================================================
class (c 'a) val f : nat end
val x : forall 'a. c 'b => nat

===============================================================================
val x : nat
val x : nat

===============================================================================
type t = |x
val x : nat

===============================================================================
class (c 'a) val x : nat end
val x : nat

===============================================================================
let x = (10 : nat)
val x : nat

===============================================================================
let {hol} x = (10 : nat)
val x : nat

===============================================================================
let x = (1 : nat)
let x = (2 : nat)

===============================================================================
class (c 'a) val x : nat end
let x = (1 : nat)

===============================================================================
type t = |x
let x y = (1 : nat)

===============================================================================
val x : nat
let {hol} x = 1
let {isabelle;hol} x = 2

===============================================================================
let {hol} x = 1
let x = 2

===============================================================================
let x = (1 : nat)
let rec y (1 : nat) = (1 : nat) and x (1:nat) = (1:nat)

===============================================================================
let x = (1:nat)
indreln [ x : forall 'a. 'a -> bool ] arm : forall y. true ==> x y

===============================================================================
val x : nat
let inline {hol} x = 1
let inline {hol} x = 1

===============================================================================
val x : nat
let {ocaml} x = 1
let _ = x

===============================================================================
val x : nat
let {ocaml} x = 1
let {hol} _ = x

===============================================================================
val x : nat
let x = 1
let _ = x
let {hol} x = 1

===============================================================================
(* ------------------------ Modules ---------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)

module X = struct let y = (1 : nat) end
module X = struct let z = (1 : nat) end

===============================================================================
module X = struct let Y = (1 : nat) end
module Y = X
module Y = X

===============================================================================
module X = struct let Y = (1:nat) end
module Y = struct let Z = (1:nat) end
module X = Y

===============================================================================
module X = Y

===============================================================================
open x

===============================================================================
module X = struct let X = (1 : nat) let X = (1 : nat) end

===============================================================================
module X = struct let C = (1 : nat) end
type t = | C of nat
open X
let f (C 1) = (1 : nat)

===============================================================================

(* --------------------------- Type classes -------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)

class (c 'a) val x : 'b end

===============================================================================
class (c 'a) val x : 'a end
class (c 'a) val y : 'a end

===============================================================================
type c = nat
class (c 'a) val x : 'a end

===============================================================================
class (c 'a) val x : 'a end
class (d 'a) val x : 'a end

===============================================================================
class (c 'a) val x : 'a val x : 'a end

===============================================================================
let x = (1:nat)
class (c 'a) val x : 'a end

===============================================================================
val x : nat
class (c 'a) val x : 'a end

===============================================================================
type t = | x
class (c 'a) val x : 'a end

===============================================================================
class (c 'a) val x : _ end

===============================================================================

(* --------------------------- Class instances ----------------------------- *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)

class (c 'a) val y : 'a end
instance (c nat) let x = 1 end

===============================================================================
class (c 'a) val x : 'a end
module M = struct let x = (10 : nat) end
open M
instance (c nat) let x = (10 : nat) end

===============================================================================
class (d 'a) val x : nat end
instance (c nat) let x = 1 end

===============================================================================
class (c 'a) val x : 'a val y : 'a end
instance (c nat) let x = 1 end

===============================================================================
class (c 'a) val x : 'a end
class (d 'a) val y : 'a end
instance (c nat) let x = 1 let y = 2 end

===============================================================================
class (c 'a) val x : 'a end
type t 'a = list 'a
instance (c t nat) let x = [] end

===============================================================================
class (c 'a) val x : 'a end
instance (c list nat) let x = [] end

===============================================================================
class (c 'a) val x : 'a end
instance (c (nat*nat)) let x = (1,1) end

===============================================================================
class (c 'a) val x : 'a end
instance forall 'a. c 'a => (c ('a*'a)) let x = (x,x) end

===============================================================================
class (c 'a) val x : nat end
instance (c 'a) let x = 1 end

===============================================================================
class (c 'a) val x : nat end
instance forall 'a. c 'b => (c 'a) let x = 1 end

===============================================================================
class (c 'a) val x : nat end
instance forall 'a. d 'd => (c 'a) let x = 1 end

===============================================================================
class (c 'a) val x : nat end
instance forall 'a 'b. (c 'a) let x = 1 end

===============================================================================
class (c 'a) val x : 'a end
instance (c nat) let x = 1 let x = 1 end

===============================================================================
class (d 'a) val x : nat end
type c = nat
instance (c nat) let x = 10 end

===============================================================================
class (c 'a) val x : nat end
instance (c nat) let {hol} x = 10 end

===============================================================================
class (c 'a) val x : nat end
instance forall 'a 'a. (c 'a) let x = 10 end

===============================================================================
class (c 'a) val x : 'a end
instance forall 'a. c 'a => (c 'a list) let x = x end
instance forall 'b. c 'b => (c 'b list) let x = x end

===============================================================================

(* ------------------------ Class constraints ------------------------------ *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)

class (c 'a) val x : 'a end
let _ = x::[(4:nat)]

===============================================================================
(* TODO: error message should include (test.c 'a list) *)
class (c 'a) val x : 'a end
class (d 'a) val y : 'a val z : list 'a end
default_instance forall 'a. (d 'a) let y = x let z = x end

===============================================================================
class (c 'a) val x : 'a end
class (d 'a) val y : 'a end
instance forall 'a 'b. c 'a , d 'b => (c ('a*'b)) let x = (x, y) end
val a : nat
let a = match x with (a,b) -> (1 : nat) end

===============================================================================
class (c 'a) val x : 'a end
class (d 'a) val y : 'a end
instance forall 'a 'b. c 'a, d 'b => (c ('a*'b)) let x = (x, y) end
val a : forall 'a. 'a -> nat
let inline {hol} a y = match x with (a,b) -> 1 end

===============================================================================

(* ------------------------ Type Mismatches -------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)

let f (1 : bool) = (1 : nat)

===============================================================================
type x = | X of bool
let f (X 1) = (1 : nat)

===============================================================================
type t = <| fld : bool |>
let f <| fld = 1 |> = (1 : nat)

===============================================================================
let f [1;true] = (1 : nat)

===============================================================================
let f (1::[true]) = (1 : nat)

===============================================================================
let x = true
let _ = x + (1 : nat)

===============================================================================
let f (x : bool) = x + 1

===============================================================================
type t = | X
let _ = X (1 : nat) 

===============================================================================
type t = | X of bool
let _ = X (1 : nat) 

===============================================================================
type t = | X of bool
let _ = X true (1 : nat) 

===============================================================================
let _ = fun (x : bool) -> x + (1 : nat)

===============================================================================
type x = | X of bool
let _ = fun (X x) -> x + (1 : nat)

===============================================================================
type x = <| fld : bool |>
let _ = fun <| fld = x |> -> x + (1 : nat)

===============================================================================
let _ = function | true -> 1 | (1 : nat) -> (1 : nat) end

===============================================================================
let _ = function | _ -> 1 | _ -> true end

===============================================================================
let _ = (1 : nat) (2 : nat)

===============================================================================
let _ = (fun (1:nat) -> (1:nat)) true

===============================================================================
let _ = (function | 1 -> (1 : nat) end) true

===============================================================================
let _ = (fun x -> x) (1 : nat) (2 : nat)

===============================================================================
let _ = true + (1 : nat)


===============================================================================
type t5 [name = "nv*"] = NV of bool | NVC of nat
let test17 = fun (x : t5) -> x

===============================================================================
type t5 [nme = "nv*"] = NV of bool | NVC of nat

===============================================================================
type t5 = NV of bool | NVC of nat
type t6 [name = "nv*"] = t5

===============================================================================
type ctype [name = ".+_ty$\\|ty[0-9 ']*$"] = | Void
let f (foo_ty : ctype) (ty2 : ctype) = true
let g (x : ctype) = false
