(* TEST *)

(* Exotic OCaml syntax constructs found in the manual that are not *)
(* used in the source of the OCaml distribution (even in the tests). *)

(* Spaces between the parts of the ?label: token in a typexpr.
   (used in bin-prot) *)
type t1 = ? label : int -> int -> int;;

(* Lazy in a pattern. (used in advi) *)
function lazy y -> y;;

(* Spaces between the parts of the ?label: token in a class-type. *)
class c1 =
  (fun ?label:x y -> object end : ? label : int -> int -> object end)
;;

(* type-class annotation in class-expr *)
class c2 = (object end : object end);;

(* virtual object field *)
class virtual c3 = object val virtual x : int end;;
class virtual c4 = object val mutable virtual x : int end;;

(* abstract module type in a signature *)
module type T = sig
  module type U
end;;

(* associativity rules for patterns *)
function Some Some x -> x | _ -> 0;;
function Some `Tag x -> x | _ -> 0;;
function `Tag Some x -> x | _ -> 0;;
function `Tag `Tag x -> x | _ -> 0;;

(* negative int32, int64, nativeint constants in patterns *)
function -1l -> () | _ -> ();;
function -1L -> () | _ -> ();;
function -1n -> () | _ -> ();;

(* surprising places where you can use an operator as a variable name *)
function (+) -> (+);;
function _ as (+) -> (+);;
for (+) = 0 to 1 do () done;;

(* access a class-type through an extended-module-path *)
module F (X : sig end) = struct
  class type t = object end
end;;
module M1 = struct end;;
class type u = F(M1).t;;

(* conjunctive constraints on tags (used by the compiler to print some
   inferred types) *)
type 'a t2 = [< `A of int & int & int ] as 'a;;

(* same for a parameterless tag (triggers a very strange error message) *)
(*type ('a, 'b) t3 = [< `A of & 'b ] as 'a;;*)

(* negative float constant in a pattern *)
function -1.0 -> 1 | _ -> 2;;

(* combining language extensions (sec. 7.13 and 7.17) *)
class c5 = object method f = 1 end;;
object
  inherit c5
  method! f : type t . int = 2
end;;

(* private polymorphic method with local type *)
object method private f : type t . int = 1 end;;

(* type annotations on record fields, both in patterns and expressions, and both
   with and without punning *)
let get_int { contents : int } = contents
let get_int2 { contents : int = c } = c
let set_int contents = { contents : int }
let set_int2 c = { contents : int = c }
;;

(* applying a functor to the unpacking of a first-class module *)
module M() = struct
  module type String = module type of String
  let string = (module String : String)
  module M = Set.Make(val string)
end ;;

(* More exotic: not even found in the manual (up to version 4.00),
   but used in some programs found in the wild.
*)

(* local functor *)
let module M (M1 : sig end) = struct end in ();;

(* let-binding with a type coercion *)
let x :> <m:int> = object method m = 0 method n=1 end;;
let x : [`A ] :> [> `A | `B ] = (`A: [`A]);;

(* "begin end" as an alias for "()" *)
begin end;;

(* putting "virtual" before "mutable" or "private" *)
class type virtual ct = object
  val mutable virtual x : int
  val virtual mutable y : int
  method private virtual f : int
  method virtual private g : int
end;;
class virtual c = object
  val mutable virtual x : int
  val virtual mutable y : int
  method private virtual f : int
  method virtual private g : int
end;;

(* Double-semicolon at the beginning of a module body [ocp-indent] *)
module M2 = struct ;; end;;


(**********************

(* Most exotic: not found in the manual (up to 4.00) and not used
   deliberately by anyone, but still implemented by the compiler. *)

(* whitespace inside val!, method!, inherit! [found in ocamlspot] *)
object
  val x = 1
  val ! x = 2
  method m = 1
  method ! m = 2
  inherit ! object val x = 3 end
end;;

(* Using () as a constructor name [found in gettext] *)
type t = ();;
let x : t = ();;

(* Using :: as a constructor name *)
type t = :: of int * int;;

(* Prefix syntax for :: in expressions *)
(::) (1, 1);;

(* Prefix syntax for :: in patterns *)
function (::) (_, _) -> 1;;

(* Unary plus in expressions (ints and float) *)
+1;;
+1l;;
+1L;;
+1n;;
+1.0;;

(* Unary plus in patterns (ints and floats) *)
function +1 -> ();;
function +1l -> ();;
function +1L -> ();;
function +1n -> ();;
function +1.0 -> ();;

**********************)
