open StdLabels

(** Make a module lazy *)
module Make (S : Sym.SYM_EXPR) = struct
  type 'a repr = 'a S.repr Lazy.t
  type 'a obs = 'a S.obs Lazy.t
  type 'a path_repr = 'a S.path_repr

  let empty : unit -> 'a repr = fun () -> lazy (S.empty ())

  let expr : 'a repr -> 'a repr =
   fun expr -> Lazy.map (fun expr -> S.expr expr) expr

  let literal : string -> 'a repr = fun l -> lazy (S.literal l)
  let integer : string -> 'a repr = fun i -> lazy (S.integer i)

  let path : 'b path_repr -> 'b -> 'a repr =
   fun repr path -> lazy (S.path repr path)

  let concat : 'a repr list -> 'a repr =
   fun exprs ->
    lazy
      (let exprs' = List.map ~f:Lazy.force exprs in
       S.concat exprs')

  let window : 'a repr T.window -> 'a repr list -> 'a repr list -> 'a repr =
   fun w group sort ->
    lazy
      (let w' = T.map_window ~f:Lazy.force w
       and group' = List.map ~f:Lazy.force group
       and sort' = List.map ~f:Lazy.force sort in
       S.window w' group' sort')

  let nvl : 'a repr list -> 'a repr =
   fun exprs ->
    lazy
      (let exprs' = List.map ~f:Lazy.force exprs in
       S.nvl exprs')

  let join : string -> 'a repr list -> 'a repr =
   fun sep exprs ->
    lazy
      (let exprs' = List.map ~f:Lazy.force exprs in
       S.join sep exprs')

  let boperator : T.binary_operator -> 'a repr -> 'a repr -> 'a repr =
   fun op e1 e2 ->
    lazy
      (let e1' = Lazy.force e1 and e2' = Lazy.force e2 in
       S.boperator op e1' e2')

  let gequality : T.binary_operator -> 'a repr -> 'a repr list -> 'a repr =
   fun op e exprs ->
    lazy
      (let e' = Lazy.force e and exprs' = List.map ~f:Lazy.force exprs in
       S.gequality op e' exprs')

  let funct : string -> 'a repr list -> 'a repr =
   fun name exprs ->
    lazy
      (let exprs' = List.map ~f:Lazy.force exprs in
       S.funct name exprs')

  let function' : T.funct -> 'a repr list -> 'a repr =
   fun f exprs ->
    lazy
      (let exprs' = List.map ~f:Lazy.force exprs in
       S.function' f exprs')

  let observe : 'a repr -> 'a obs = fun v -> Lazy.map S.observe v
end