Blame compiler/compile.ml

Packit bd2e5d
(***********************************************************************)
Packit bd2e5d
(*                                                                     *)
Packit bd2e5d
(*                 MLTk, Tcl/Tk interface of OCaml                     *)
Packit bd2e5d
(*                                                                     *)
Packit bd2e5d
(*    Francois Rouaix, Francois Pessaux, Jun Furuse and Pierre Weis    *)
Packit bd2e5d
(*               projet Cristal, INRIA Rocquencourt                    *)
Packit bd2e5d
(*            Jacques Garrigue, Kyoto University RIMS                  *)
Packit bd2e5d
(*                                                                     *)
Packit bd2e5d
(*  Copyright 2002 Institut National de Recherche en Informatique et   *)
Packit bd2e5d
(*  en Automatique and Kyoto University.  All rights reserved.         *)
Packit bd2e5d
(*  This file is distributed under the terms of the GNU Library        *)
Packit bd2e5d
(*  General Public License, with the special exception on linking      *)
Packit bd2e5d
(*  described in file LICENSE found in the OCaml source tree.          *)
Packit bd2e5d
(*                                                                     *)
Packit bd2e5d
(***********************************************************************)
Packit bd2e5d
Packit bd2e5d
(* $Id$ *)
Packit bd2e5d
Packit bd2e5d
open StdLabels
Packit bd2e5d
open Tables
Packit bd2e5d
Packit bd2e5d
(* CONFIGURE *)
Packit bd2e5d
(* if you set it true, ImagePhoto and ImageBitmap will annoy you... *)
Packit bd2e5d
let safetype = true
Packit bd2e5d
Packit bd2e5d
let labeloff ~at l = match l with
Packit bd2e5d
  "", t -> t
Packit bd2e5d
| l, t -> raise (Failure ("labeloff: " ^ l ^ " at " ^ at))
Packit bd2e5d
Packit bd2e5d
let labltk_labelstring l =
Packit bd2e5d
  if l = "" then l else
Packit bd2e5d
  if l.[0] = '?' then l ^ ":" else
Packit bd2e5d
  "~" ^ l ^ ":"
Packit bd2e5d
Packit bd2e5d
let camltk_labelstring l =
Packit bd2e5d
  if l = "" then l else
Packit bd2e5d
  if l.[0] = '?' then l ^ ":" else ""
Packit bd2e5d
Packit bd2e5d
let labelstring l =
Packit bd2e5d
  if !Flags.camltk then camltk_labelstring l
Packit bd2e5d
  else labltk_labelstring l
Packit bd2e5d
Packit bd2e5d
let labltk_typelabel l =
Packit bd2e5d
  if l = "" then l else l ^ ":"
Packit bd2e5d
Packit bd2e5d
let camltk_typelabel l =
Packit bd2e5d
  if l = "" then l
Packit bd2e5d
  else if l.[0] = '?' then l ^ ":" else ""
Packit bd2e5d
Packit bd2e5d
let typelabel l =
Packit bd2e5d
  if !Flags.camltk then camltk_typelabel l
Packit bd2e5d
  else labltk_typelabel l
Packit bd2e5d
Packit bd2e5d
let forbidden = [ "class"; "type"; "in"; "from"; "to" ]
Packit bd2e5d
let nicknames =
Packit bd2e5d
  [ "class", "clas";
Packit bd2e5d
    "type", "typ" ]
Packit bd2e5d
Packit bd2e5d
let small = String.lowercase_ascii
Packit bd2e5d
Packit bd2e5d
let gettklabel fc =
Packit bd2e5d
  match fc.template with
Packit bd2e5d
    ListArg( StringArg s :: _ ) ->
Packit bd2e5d
      let s = small s in
Packit bd2e5d
      if s = "" then s else
Packit bd2e5d
      let s =
Packit bd2e5d
        if s.[0] = '-'
Packit bd2e5d
        then String.sub s ~pos:1 ~len:(String.length s - 1)
Packit bd2e5d
        else s
Packit bd2e5d
      in begin
Packit bd2e5d
        if List.mem s forbidden then
Packit bd2e5d
          try List.assoc s nicknames
Packit bd2e5d
          with Not_found -> small fc.var_name
Packit bd2e5d
        else s
Packit bd2e5d
      end
Packit bd2e5d
  | _ -> raise (Failure "gettklabel")
Packit bd2e5d
Packit bd2e5d
let count ~item:x l =
Packit bd2e5d
  let count = ref 0 in
Packit bd2e5d
  List.iter ~f:(fun y -> if x = y then incr count) l;
Packit bd2e5d
  !count
Packit bd2e5d
Packit bd2e5d
let caml_name s =
Packit bd2e5d
  let b = Buffer.create (String.length s) in
Packit bd2e5d
  for i = 0 to String.length s - 1 do
Packit bd2e5d
    let c = s.[i] in
Packit bd2e5d
    if c <> ':' then Buffer.add_char b c
Packit bd2e5d
    else if i > 0 && s.[i-1] = ':' then Buffer.add_char b '_'
Packit bd2e5d
  done;
Packit bd2e5d
  Buffer.contents b
Packit bd2e5d
Packit bd2e5d
(* Extract all types from a template *)
Packit bd2e5d
let rec types_of_template = function
Packit bd2e5d
    StringArg _ -> []
Packit bd2e5d
  | TypeArg (l, t) -> [l, t]
Packit bd2e5d
  | ListArg l -> List.flatten (List.map ~f:types_of_template l)
Packit bd2e5d
  | OptionalArgs (l, tl, _) ->
Packit bd2e5d
      begin
Packit bd2e5d
        match List.flatten (List.map ~f:types_of_template tl) with
Packit bd2e5d
          ["", t] -> ["?" ^ l, t]
Packit bd2e5d
        | [_, _] -> raise (Failure "0 label required")
Packit bd2e5d
        | _ -> raise (Failure "0 or more than 1 args in for optionals")
Packit bd2e5d
      end
Packit bd2e5d
Packit bd2e5d
(*
Packit bd2e5d
 * Pretty print a type
Packit bd2e5d
 *  used to write ML type definitions
Packit bd2e5d
 *)
Packit bd2e5d
let ppMLtype ?(any=false) ?(return=false) ?(def=false) ?(counter=ref 0) =
Packit bd2e5d
  let rec ppMLtype =
Packit bd2e5d
  function
Packit bd2e5d
    Unit -> "unit"
Packit bd2e5d
  | Int -> "int"
Packit bd2e5d
  | Float -> "float"
Packit bd2e5d
  | Bool -> "bool"
Packit bd2e5d
  | Char -> "char"
Packit bd2e5d
  | String -> "string"
Packit bd2e5d
(* new *)
Packit bd2e5d
  | List (Subtype (sup, sub)) ->
Packit bd2e5d
    if !Flags.camltk then "(* " ^ sub ^ " *) " ^ caml_name sup ^ " list"
Packit bd2e5d
    else begin
Packit bd2e5d
      if return then
Packit bd2e5d
        caml_name sub ^ "_" ^ caml_name sup ^ " list"
Packit bd2e5d
      else begin
Packit bd2e5d
         try
Packit bd2e5d
          let typdef = Hashtbl.find types_table sup in
Packit bd2e5d
          let fcl = List.assoc sub typdef.subtypes in
Packit bd2e5d
          let tklabels = List.map ~f:gettklabel fcl in
Packit bd2e5d
          let l = List.map fcl ~f:
Packit bd2e5d
            begin fun fc ->
Packit bd2e5d
              "?" ^ begin let p = gettklabel fc in
Packit bd2e5d
                    if count ~item:p tklabels > 1 then small fc.var_name else p
Packit bd2e5d
                    end
Packit bd2e5d
              ^ ":" ^
Packit bd2e5d
              let l = types_of_template fc.template in
Packit bd2e5d
              match l with
Packit bd2e5d
                [] -> "unit"
Packit bd2e5d
              | [lt] -> ppMLtype (labeloff lt ~at:"ppMLtype")
Packit bd2e5d
              | l ->
Packit bd2e5d
                  "(" ^ String.concat ~sep:"*"
Packit bd2e5d
                    (List.map l
Packit bd2e5d
                       ~f:(fun lt -> ppMLtype (labeloff lt ~at:"ppMLtype")))
Packit bd2e5d
                  ^ ")"
Packit bd2e5d
            end in
Packit bd2e5d
          String.concat ~sep:"   ->\n" l
Packit bd2e5d
        with
Packit bd2e5d
          Not_found -> Printf.eprintf "ppMLtype %s/%s\n" sup sub; exit (-1)
Packit bd2e5d
       end
Packit bd2e5d
    end
Packit bd2e5d
  | List ty -> (ppMLtype ty) ^ " list"
Packit bd2e5d
  | Product tyl ->
Packit bd2e5d
      "(" ^ String.concat ~sep:" * " (List.map ~f:ppMLtype tyl) ^ ")"
Packit bd2e5d
  | Record tyl ->
Packit bd2e5d
      String.concat ~sep:" * "
Packit bd2e5d
        (List.map tyl ~f:(fun (l, t) -> typelabel l ^ ppMLtype t))
Packit bd2e5d
  | Subtype ("widget", sub) ->
Packit bd2e5d
      if !Flags.camltk then "(* " ^ sub ^" *) widget" else
Packit bd2e5d
      caml_name sub ^ " widget"
Packit bd2e5d
  | UserDefined "widget" ->
Packit bd2e5d
      if !Flags.camltk then "widget"
Packit bd2e5d
      else begin
Packit bd2e5d
        if any then "any widget" else
Packit bd2e5d
        let c = String.make 1 (Char.chr(Char.code 'a' + !counter)) in
Packit bd2e5d
        incr counter;
Packit bd2e5d
        "'" ^ c ^ " widget"
Packit bd2e5d
      end
Packit bd2e5d
  | UserDefined s ->
Packit bd2e5d
      if !Flags.camltk then s
Packit bd2e5d
      else begin
Packit bd2e5d
        (* a bit dirty hack for ImageBitmap and ImagePhoto *)
Packit bd2e5d
        try
Packit bd2e5d
          let typdef = Hashtbl.find types_table s in
Packit bd2e5d
          if typdef.variant then
Packit bd2e5d
            if return then try
Packit bd2e5d
              "[>" ^
Packit bd2e5d
              String.concat ~sep:"|"
Packit bd2e5d
                (List.map typdef.constructors ~f:
Packit bd2e5d
                   begin
Packit bd2e5d
                     fun c ->
Packit bd2e5d
                       "`" ^ c.var_name ^
Packit bd2e5d
                       (match types_of_template c.template with
Packit bd2e5d
                         [] -> ""
Packit bd2e5d
                       | l ->  " of " ^ ppMLtype (Product (List.map l
Packit bd2e5d
                             ~f:(labeloff ~at:"ppMLtype UserDefined"))))
Packit bd2e5d
                   end) ^ "]"
Packit bd2e5d
            with
Packit bd2e5d
              Not_found -> prerr_endline ("ppMLtype " ^ s ^ " ?"); s
Packit bd2e5d
            else if not def && List.length typdef.constructors > 1 then
Packit bd2e5d
              "[< " ^ s ^ "]"
Packit bd2e5d
            else s
Packit bd2e5d
          else s
Packit bd2e5d
        with Not_found -> s
Packit bd2e5d
      end
Packit bd2e5d
  | Subtype (s, s') ->
Packit bd2e5d
      if !Flags.camltk then "(* " ^ s' ^ " *) " ^ caml_name s else
Packit bd2e5d
      caml_name s' ^ "_" ^ caml_name s
Packit bd2e5d
  | Function (Product tyl) ->
Packit bd2e5d
        raise (Failure "Function (Product tyl) ? ppMLtype")
Packit bd2e5d
  | Function (Record tyl) ->
Packit bd2e5d
        "(" ^ String.concat ~sep:" -> "
Packit bd2e5d
          (List.map tyl ~f:(fun (l, t) -> typelabel l ^ ppMLtype t))
Packit bd2e5d
        ^ " -> unit)"
Packit bd2e5d
  | Function ty ->
Packit bd2e5d
        "(" ^ (ppMLtype ty) ^ " -> unit)"
Packit bd2e5d
  | As (t, s) ->
Packit bd2e5d
      if !Flags.camltk then ppMLtype t
Packit bd2e5d
      else s
Packit bd2e5d
  in
Packit bd2e5d
    ppMLtype
Packit bd2e5d
Packit bd2e5d
(* Produce a documentation version of a template *)
Packit bd2e5d
let rec ppTemplate = function
Packit bd2e5d
    StringArg s -> s
Packit bd2e5d
  | TypeArg (l, t) -> "<" ^ ppMLtype t ^ ">"
Packit bd2e5d
  | ListArg l -> "{" ^ String.concat ~sep:" " (List.map ~f:ppTemplate l) ^ "}"
Packit bd2e5d
  | OptionalArgs (l, tl, d) ->
Packit bd2e5d
      "?" ^ l ^ "{" ^ String.concat ~sep:" " (List.map ~f:ppTemplate tl)
Packit bd2e5d
      ^ "}[<" ^ String.concat ~sep:" " (List.map ~f:ppTemplate d) ^ ">]"
Packit bd2e5d
Packit bd2e5d
let doc_of_template = function
Packit bd2e5d
    ListArg l -> String.concat ~sep:" " (List.map ~f:ppTemplate l)
Packit bd2e5d
  | t -> ppTemplate t
Packit bd2e5d
Packit bd2e5d
(*
Packit bd2e5d
 * Type definitions
Packit bd2e5d
 *)
Packit bd2e5d
Packit bd2e5d
(* Write an ML constructor *)
Packit bd2e5d
let write_constructor ~w {ml_name = mlconstr; template = t} =
Packit bd2e5d
   w mlconstr;
Packit bd2e5d
   begin match types_of_template t with
Packit bd2e5d
       [] -> ()
Packit bd2e5d
     | l -> w " of ";
Packit bd2e5d
         w (ppMLtype ~any:true (Product (List.map l
Packit bd2e5d
                ~f:(labeloff ~at:"write_constructor"))))
Packit bd2e5d
   end;
Packit bd2e5d
   w "        (* tk option: "; w (doc_of_template t); w " *)"
Packit bd2e5d
Packit bd2e5d
(* Write a rhs type decl *)
Packit bd2e5d
let write_constructors ~w = function
Packit bd2e5d
    [] -> fatal_error "empty type"
Packit bd2e5d
  | x :: l ->
Packit bd2e5d
      write_constructor ~w x;
Packit bd2e5d
      List.iter l ~f:
Packit bd2e5d
        begin fun x ->
Packit bd2e5d
          w "\n  | ";
Packit bd2e5d
          write_constructor ~w x
Packit bd2e5d
        end
Packit bd2e5d
Packit bd2e5d
(* Write an ML variant *)
Packit bd2e5d
let write_variant ~w {var_name = varname; template = t} =
Packit bd2e5d
  w "`";
Packit bd2e5d
  w varname;
Packit bd2e5d
  begin match types_of_template t with
Packit bd2e5d
    [] -> ()
Packit bd2e5d
  | l ->
Packit bd2e5d
      w " of ";
Packit bd2e5d
      w (ppMLtype ~any:true ~def:true
Packit bd2e5d
           (Product (List.map l ~f:(labeloff ~at:"write_variant"))))
Packit bd2e5d
   end;
Packit bd2e5d
   w "        (* tk option: "; w (doc_of_template t); w " *)"
Packit bd2e5d
Packit bd2e5d
let write_variants ~w = function
Packit bd2e5d
    [] -> fatal_error "empty variants"
Packit bd2e5d
  | l ->
Packit bd2e5d
      List.iter l ~f:
Packit bd2e5d
        begin fun x ->
Packit bd2e5d
          w "\n  | ";
Packit bd2e5d
          write_variant ~w x
Packit bd2e5d
        end
Packit bd2e5d
Packit bd2e5d
(* Definition of a type *)
Packit bd2e5d
let labltk_write_type ~intf:w ~impl:w' name ~def:typdef =
Packit bd2e5d
  (* Only needed if no subtypes, otherwise use optionals *)
Packit bd2e5d
  if typdef.subtypes = [] then begin
Packit bd2e5d
    w "(* Variant type *)\n";
Packit bd2e5d
    w ("type " ^ name ^ " = [");
Packit bd2e5d
    write_variants ~w (sort_components typdef.constructors);
Packit bd2e5d
    w "\n]\n\n"
Packit bd2e5d
  end
Packit bd2e5d
Packit bd2e5d
(* CamlTk: List of constructors, for runtime subtyping *)
Packit bd2e5d
let write_constructor_set ~w ~sep = function
Packit bd2e5d
  | [] -> fatal_error "empty type"
Packit bd2e5d
  | x::l ->
Packit bd2e5d
      w ("C" ^ x.ml_name);
Packit bd2e5d
      List.iter l ~f: (function x ->
Packit bd2e5d
        w sep;
Packit bd2e5d
        w ("C" ^ x.ml_name))
Packit bd2e5d
Packit bd2e5d
(* CamlTk: Definition of a type *)
Packit bd2e5d
let camltk_write_type ~intf:w ~impl:w' name ~def:typdef =
Packit bd2e5d
  (* Put markers for extraction *)
Packit bd2e5d
  w "(* type *)\n";
Packit bd2e5d
  w ("type " ^ name ^ " =\n");
Packit bd2e5d
  w "  | ";
Packit bd2e5d
  write_constructors ~w (sort_components typdef.constructors);
Packit bd2e5d
  w "\n(* /type *)\n\n";
Packit bd2e5d
  (* Dynamic Subtyping *)
Packit bd2e5d
  if typdef.subtypes <> [] then begin
Packit bd2e5d
    (* The set of its constructors *)
Packit bd2e5d
    if name = "options" then begin
Packit bd2e5d
      w "(* type *)\n";
Packit bd2e5d
      w ("type "^name^"_constrs =\n\t")
Packit bd2e5d
    end else begin
Packit bd2e5d
      (* added some prefix to avoid being picked up in documentation *)
Packit bd2e5d
      w ("(* no doc *) type "^name^"_constrs =\n")
Packit bd2e5d
    end;
Packit bd2e5d
    w "  | ";
Packit bd2e5d
    write_constructor_set ~w:w ~sep: "\n  | "
Packit bd2e5d
      (sort_components typdef.constructors);
Packit bd2e5d
    w "\n\n";
Packit bd2e5d
    (* The set of all constructors *)
Packit bd2e5d
    w' ("let "^caml_name name^"_any_table = [");
Packit bd2e5d
    write_constructor_set ~w:w' ~sep:"; "
Packit bd2e5d
      (sort_components typdef.constructors);
Packit bd2e5d
    w' ("]\n\n");
Packit bd2e5d
    (* The subset of constructors for each subtype *)
Packit bd2e5d
    List.iter ~f:(function (s,l) ->
Packit bd2e5d
      w' ("let "^caml_name name^"_"^caml_name s^"_table = [");
Packit bd2e5d
      write_constructor_set ~w:w' ~sep:"; " (sort_components l);
Packit bd2e5d
      w' ("]\n\n"))
Packit bd2e5d
      typdef.subtypes
Packit bd2e5d
  end
Packit bd2e5d
Packit bd2e5d
let write_type ~intf:w ~impl:w' name ~def:typdef =
Packit bd2e5d
  (if !Flags.camltk then camltk_write_type else labltk_write_type)
Packit bd2e5d
    ~intf:w ~impl:w' name ~def:typdef
Packit bd2e5d
Packit bd2e5d
(************************************************************)
Packit bd2e5d
(* Converters                                               *)
Packit bd2e5d
(************************************************************)
Packit bd2e5d
Packit bd2e5d
let rec converterTKtoCAML ~arg = function
Packit bd2e5d
  | Int -> "int_of_string " ^ arg
Packit bd2e5d
  | Float -> "float_of_string " ^ arg
Packit bd2e5d
  | Bool -> "(match " ^ arg ^ " with\n\
Packit bd2e5d
            | \"1\" -> true\n\
Packit bd2e5d
            | \"0\" -> false\n\
Packit bd2e5d
            | s -> Pervasives.raise (Invalid_argument (\"cTKtoCAMLbool\" ^ s)))"
Packit bd2e5d
  | Char -> "String.get " ^ arg ^ " 0"
Packit bd2e5d
  | String -> arg
Packit bd2e5d
  | UserDefined s -> "cTKtoCAML" ^ s ^ " " ^ arg
Packit bd2e5d
  | Subtype ("widget", s') when not !Flags.camltk ->
Packit bd2e5d
      String.concat ~sep:" "
Packit bd2e5d
        ["(Obj.magic (cTKtoCAMLwidget "; arg; ") :"; s'; "widget)"]
Packit bd2e5d
  | Subtype (s, s') ->
Packit bd2e5d
      if !Flags.camltk then
Packit bd2e5d
        "cTKtoCAML" ^ s ^ " " ^ arg
Packit bd2e5d
      else
Packit bd2e5d
        "cTKtoCAML" ^ s' ^ "_" ^ s ^ " " ^ arg
Packit bd2e5d
  | List ty ->
Packit bd2e5d
     begin match type_parser_arity ty with
Packit bd2e5d
       OneToken ->
Packit bd2e5d
         String.concat ~sep:" "
Packit bd2e5d
           ["(List.map (function x ->";
Packit bd2e5d
            converterTKtoCAML ~arg:"x" ty; ")"; arg; ")"]
Packit bd2e5d
     | MultipleToken ->
Packit bd2e5d
         String.concat ~sep:" "
Packit bd2e5d
           ["iterate_converter (function x ->";
Packit bd2e5d
            converterTKtoCAML ~arg:"x" ty; ")"; arg; ")"]
Packit bd2e5d
     end
Packit bd2e5d
  | As (ty, _) -> converterTKtoCAML ~arg ty
Packit bd2e5d
  | t ->
Packit bd2e5d
     prerr_endline ("ERROR with " ^ arg ^ " " ^ ppMLtype t);
Packit bd2e5d
     fatal_error "converterTKtoCAML"
Packit bd2e5d
Packit bd2e5d
Packit bd2e5d
(*******************************)
Packit bd2e5d
(* Wrappers                    *)
Packit bd2e5d
(*******************************)
Packit bd2e5d
let varnames ~prefix n =
Packit bd2e5d
  let rec var i =
Packit bd2e5d
    if i > n then []
Packit bd2e5d
    else (prefix ^ string_of_int i) :: var (succ i)
Packit bd2e5d
  in var 1
Packit bd2e5d
Packit bd2e5d
(*
Packit bd2e5d
 * generate wrapper source for callbacks
Packit bd2e5d
 *  transform a function ... -> unit in a function : unit -> unit
Packit bd2e5d
 *  using primitives arg_ ... from the protocol
Packit bd2e5d
 *  Warning: sequentiality is important in generated code
Packit bd2e5d
 *  TODO: remove arg_ stuff and process lists directly ?
Packit bd2e5d
 *)
Packit bd2e5d
Packit bd2e5d
let rec wrapper_code ~name ty =
Packit bd2e5d
  match ty with
Packit bd2e5d
    Unit -> "(fun _ -> " ^ name ^ " ())"
Packit bd2e5d
  | As (ty, _) -> wrapper_code ~name ty
Packit bd2e5d
  | ty ->
Packit bd2e5d
      "(fun args ->\n        " ^
Packit bd2e5d
      begin match ty with
Packit bd2e5d
          Product tyl -> raise (Failure "Product -> record was done. ???")
Packit bd2e5d
        | Record tyl ->
Packit bd2e5d
          (* variables for each component of the product *)
Packit bd2e5d
          let vnames = varnames ~prefix:"a" (List.length tyl) in
Packit bd2e5d
          (* getting the arguments *)
Packit bd2e5d
          let readarg =
Packit bd2e5d
            List.map2 vnames tyl ~f:
Packit bd2e5d
            begin fun v (l, ty) ->
Packit bd2e5d
              match type_parser_arity ty with
Packit bd2e5d
                OneToken ->
Packit bd2e5d
                  "let (" ^ v ^ ", args) = " ^
Packit bd2e5d
                  converterTKtoCAML ~arg:"(List.hd args)" ty ^
Packit bd2e5d
                  ", List.tl args in\n        "
Packit bd2e5d
              | MultipleToken ->
Packit bd2e5d
                  "let (" ^ v ^ ", args) = " ^
Packit bd2e5d
                  converterTKtoCAML ~arg:"args" ty ^
Packit bd2e5d
                  " in\n        "
Packit bd2e5d
            end in
Packit bd2e5d
          String.concat ~sep:"" readarg ^ name ^ " " ^
Packit bd2e5d
          String.concat ~sep:" "
Packit bd2e5d
            (List.map2 ~f:(fun v (l, _) ->
Packit bd2e5d
              if !Flags.camltk then v
Packit bd2e5d
              else labelstring l ^ v) vnames tyl)
Packit bd2e5d
Packit bd2e5d
        (* all other types are read in one operation *)
Packit bd2e5d
        | List ty ->
Packit bd2e5d
            name ^ "(" ^ converterTKtoCAML ~arg:"args" ty ^ ")"
Packit bd2e5d
        | String ->
Packit bd2e5d
            name ^ "(" ^ converterTKtoCAML ~arg:"(List.hd args)" ty ^ ")"
Packit bd2e5d
        | ty ->
Packit bd2e5d
          begin match type_parser_arity ty with
Packit bd2e5d
            OneToken ->
Packit bd2e5d
              name ^ "(" ^ converterTKtoCAML ~arg:"(List.hd args)" ty ^ ")"
Packit bd2e5d
          | MultipleToken ->
Packit bd2e5d
              "let (v, _) = " ^ converterTKtoCAML ~arg:"args" ty ^
Packit bd2e5d
              " in\n        " ^ name ^ " v"
Packit bd2e5d
          end
Packit bd2e5d
      end ^ ")"
Packit bd2e5d
Packit bd2e5d
(*************************************************************)
Packit bd2e5d
(* Parsers                                                   *)
Packit bd2e5d
(*  are required only for values returned by commands and    *)
Packit bd2e5d
(*  functions (table is computed by the parser)              *)
Packit bd2e5d
Packit bd2e5d
(* Tuples/Lists are Ok if they don't contain strings         *)
Packit bd2e5d
(* they will be returned as list of strings                  *)
Packit bd2e5d
Packit bd2e5d
(* Can we generate a "parser" ?
Packit bd2e5d
   -> all constructors are unit and at most one int and one string, with null constr
Packit bd2e5d
*)
Packit bd2e5d
type parser_pieces =
Packit bd2e5d
    { mutable zeroary : (string * string) list ; (* kw string, ml name *)
Packit bd2e5d
      mutable intpar : string list; (* one at most, mlname *)
Packit bd2e5d
      mutable stringpar : string list (* idem *)
Packit bd2e5d
    }
Packit bd2e5d
Packit bd2e5d
type mini_parser =
Packit bd2e5d
   NoParser
Packit bd2e5d
 | ParserPieces of parser_pieces
Packit bd2e5d
Packit bd2e5d
let can_generate_parser constructors =
Packit bd2e5d
  let pp = {zeroary = []; intpar = []; stringpar = []} in
Packit bd2e5d
  if List.for_all constructors ~f:
Packit bd2e5d
    begin fun c ->
Packit bd2e5d
      let vname = if !Flags.camltk then c.ml_name else c.var_name in
Packit bd2e5d
      match c.template with
Packit bd2e5d
        ListArg [StringArg s] ->
Packit bd2e5d
          pp.zeroary <- (s, vname) ::
Packit bd2e5d
            pp.zeroary; true
Packit bd2e5d
      | ListArg [TypeArg(_, Int)] | ListArg[TypeArg(_, Float)] ->
Packit bd2e5d
          if pp.intpar <> [] then false
Packit bd2e5d
          else (pp.intpar <- [vname]; true)
Packit bd2e5d
      | ListArg [TypeArg(_, String)] ->
Packit bd2e5d
          if pp.stringpar <> [] then false
Packit bd2e5d
          else (pp.stringpar <- [vname]; true)
Packit bd2e5d
      | _ -> false
Packit bd2e5d
    end
Packit bd2e5d
  then ParserPieces pp
Packit bd2e5d
  else NoParser
Packit bd2e5d
Packit bd2e5d
Packit bd2e5d
(* We can generate parsers only for simple types *)
Packit bd2e5d
(* we should avoid multiple walks *)
Packit bd2e5d
let labltk_write_TKtoCAML ~w name ~def:typdef =
Packit bd2e5d
  if typdef.parser_arity = MultipleToken then
Packit bd2e5d
    prerr_string ("You must write cTKtoCAML" ^ name ^
Packit bd2e5d
                            " : string list ->" ^ name ^ " * string list\n")
Packit bd2e5d
  else
Packit bd2e5d
  let write ~consts ~name =
Packit bd2e5d
    match can_generate_parser consts with
Packit bd2e5d
      NoParser ->
Packit bd2e5d
        prerr_string
Packit bd2e5d
          ("You must write cTKtoCAML" ^ name ^ " : string ->" ^ name ^ "\n")
Packit bd2e5d
    | ParserPieces pp ->
Packit bd2e5d
        w ("let cTKtoCAML" ^ name ^ " n =\n");
Packit bd2e5d
        (* First check integer *)
Packit bd2e5d
        if pp.intpar <> [] then
Packit bd2e5d
        begin
Packit bd2e5d
          w ("   try `" ^ List.hd pp.intpar ^ " (int_of_string n)\n");
Packit bd2e5d
          w ("   with _ ->\n")
Packit bd2e5d
        end;
Packit bd2e5d
        w ("    match n with\n");
Packit bd2e5d
        List.iter pp.zeroary ~f:
Packit bd2e5d
          begin fun (tk, ml) ->
Packit bd2e5d
            w "    | \""; w tk; w "\" -> `"; w ml; w "\n"
Packit bd2e5d
          end;
Packit bd2e5d
        let final = if pp.stringpar <> [] then
Packit bd2e5d
              "n -> `" ^ List.hd pp.stringpar ^ " n"
Packit bd2e5d
           else "s -> Pervasives.raise (Invalid_argument (\"cTKtoCAML"
Packit bd2e5d
                ^ name ^ ": \" ^ s))"
Packit bd2e5d
        in
Packit bd2e5d
        w "    | ";
Packit bd2e5d
        w final;
Packit bd2e5d
        w "\n\n"
Packit bd2e5d
  in
Packit bd2e5d
    begin
Packit bd2e5d
      write ~name ~consts:typdef.constructors;
Packit bd2e5d
      List.iter typdef.subtypes ~f: begin
Packit bd2e5d
        fun (subname, consts) -> write ~name:(subname ^ "_" ^ name) ~consts
Packit bd2e5d
      end
Packit bd2e5d
    end
Packit bd2e5d
Packit bd2e5d
let camltk_write_TKtoCAML ~w name ~def:typdef =
Packit bd2e5d
  if typdef.parser_arity = MultipleToken then
Packit bd2e5d
    prerr_string ("You must write cTKtoCAML" ^ name ^
Packit bd2e5d
                            " : string list ->" ^ name ^ " * string list\n")
Packit bd2e5d
  else
Packit bd2e5d
  let write ~consts ~name =
Packit bd2e5d
    match can_generate_parser consts with
Packit bd2e5d
      NoParser ->
Packit bd2e5d
        prerr_string
Packit bd2e5d
          ("You must write cTKtoCAML" ^ name ^ " : string ->" ^ name ^ "\n")
Packit bd2e5d
    | ParserPieces pp ->
Packit bd2e5d
        w ("let cTKtoCAML" ^ name ^ " n =\n");
Packit bd2e5d
        (* First check integer *)
Packit bd2e5d
        if pp.intpar <> [] then
Packit bd2e5d
        begin
Packit bd2e5d
          w ("   try " ^ List.hd pp.intpar ^ " (int_of_string n)\n");
Packit bd2e5d
          w ("   with _ ->\n")
Packit bd2e5d
        end;
Packit bd2e5d
        w ("    match n with\n");
Packit bd2e5d
        List.iter pp.zeroary ~f:
Packit bd2e5d
          begin fun (tk, ml) ->
Packit bd2e5d
            w "    | \""; w tk; w "\" -> "; w ml; w "\n"
Packit bd2e5d
          end;
Packit bd2e5d
        let final = if pp.stringpar <> [] then
Packit bd2e5d
              "n -> " ^ List.hd pp.stringpar ^ " n"
Packit bd2e5d
           else "s -> Pervasives.raise (Invalid_argument (\"cTKtoCAML"
Packit bd2e5d
                ^ name ^ ": \" ^ s))"
Packit bd2e5d
        in
Packit bd2e5d
        w "    | ";
Packit bd2e5d
        w final;
Packit bd2e5d
        w "\n\n"
Packit bd2e5d
  in
Packit bd2e5d
    begin
Packit bd2e5d
      write ~name ~consts:typdef.constructors;
Packit bd2e5d
      List.iter typdef.subtypes ~f: begin
Packit bd2e5d
        fun (subname, consts) -> write ~name:(subname ^ "_" ^ name) ~consts
Packit bd2e5d
      end
Packit bd2e5d
    end
Packit bd2e5d
Packit bd2e5d
let write_TKtoCAML ~w name ~def:typdef =
Packit bd2e5d
  (if !Flags.camltk then camltk_write_TKtoCAML else labltk_write_TKtoCAML)
Packit bd2e5d
    ~w name ~def: typdef
Packit bd2e5d
Packit bd2e5d
(******************************)
Packit bd2e5d
(* Converters                 *)
Packit bd2e5d
(******************************)
Packit bd2e5d
Packit bd2e5d
(* Produce an in-lined converter OCaml -> Tk for simple types *)
Packit bd2e5d
(* the converter is a function of type:  <type> -> string  *)
Packit bd2e5d
let rec converterCAMLtoTK ~context_widget argname ty =
Packit bd2e5d
 match ty with
Packit bd2e5d
    Int -> "TkToken (string_of_int " ^ argname ^ ")"
Packit bd2e5d
 |  Float -> "TkToken (Printf.sprintf \"%g\" " ^ argname ^ ")"
Packit bd2e5d
 |  Bool -> "if " ^ argname ^ " then TkToken \"1\" else TkToken \"0\""
Packit bd2e5d
 |  Char -> "TkToken (Char.escaped " ^ argname ^ ")"
Packit bd2e5d
 |  String -> "TkToken " ^ argname
Packit bd2e5d
 |  As (ty, _) -> converterCAMLtoTK ~context_widget argname ty
Packit bd2e5d
 |  UserDefined s ->
Packit bd2e5d
       let name = "cCAMLtoTK" ^ s ^ " " in
Packit bd2e5d
       let args = argname in
Packit bd2e5d
       let args =
Packit bd2e5d
         if !Flags.camltk then begin
Packit bd2e5d
           if is_subtyped s then (* unconstraint subtype *)
Packit bd2e5d
             s ^ "_any_table " ^ args
Packit bd2e5d
           else args
Packit bd2e5d
         end else args
Packit bd2e5d
       in
Packit bd2e5d
       let args =
Packit bd2e5d
           if requires_widget_context s then
Packit bd2e5d
             context_widget ^ " " ^ args
Packit bd2e5d
           else args in
Packit bd2e5d
       name ^ args
Packit bd2e5d
 |  Subtype ("widget", s') ->
Packit bd2e5d
       if !Flags.camltk then
Packit bd2e5d
         let name = "cCAMLtoTKwidget " in
Packit bd2e5d
         let args = "widget_"^caml_name s'^"_table "^argname in
Packit bd2e5d
         let args =
Packit bd2e5d
           if requires_widget_context "widget" then
Packit bd2e5d
             context_widget^" "^args
Packit bd2e5d
           else args in
Packit bd2e5d
         name^args
Packit bd2e5d
       else begin
Packit bd2e5d
         let name = "cCAMLtoTKwidget " in
Packit bd2e5d
         let args = "(" ^ argname ^ " : " ^ caml_name s' ^ " widget)" in
Packit bd2e5d
         name ^ args
Packit bd2e5d
       end
Packit bd2e5d
 |  Subtype (s, s') ->
Packit bd2e5d
       let name =
Packit bd2e5d
         if !Flags.camltk then "cCAMLtoTK" ^ s ^ " "
Packit bd2e5d
         else "cCAMLtoTK" ^ s' ^ "_" ^ s ^ " "
Packit bd2e5d
       in
Packit bd2e5d
       let args =
Packit bd2e5d
         if !Flags.camltk then begin
Packit bd2e5d
           caml_name s^"_"^caml_name s'^"_table "^argname
Packit bd2e5d
         end else begin
Packit bd2e5d
           if safetype then
Packit bd2e5d
             "(" ^ argname ^ " : [< " ^ caml_name s' ^ "_" ^ caml_name s ^ "])"
Packit bd2e5d
           else argname
Packit bd2e5d
         end
Packit bd2e5d
       in
Packit bd2e5d
       let args =
Packit bd2e5d
           if requires_widget_context s then context_widget ^ " " ^ args
Packit bd2e5d
           else args in
Packit bd2e5d
       name ^ args
Packit bd2e5d
 | Product tyl ->
Packit bd2e5d
     let vars = varnames ~prefix:"z" (List.length tyl) in
Packit bd2e5d
     String.concat ~sep:" "
Packit bd2e5d
       ("let" :: String.concat ~sep:"," vars :: "=" :: argname ::
Packit bd2e5d
        "in TkTokenList [" ::
Packit bd2e5d
        String.concat ~sep:"; "
Packit bd2e5d
          (List.map2 vars tyl ~f:(converterCAMLtoTK ~context_widget)) ::
Packit bd2e5d
        ["]"])
Packit bd2e5d
 | List ty -> (* Just added for Imagephoto.put *)
Packit bd2e5d
     String.concat ~sep:" "
Packit bd2e5d
       [(if !Flags.camltk then
Packit bd2e5d
           "TkQuote (TkTokenList (List.map (fun y -> "
Packit bd2e5d
         else
Packit bd2e5d
           "TkQuote (TkTokenList (List.map ~f:(fun y -> ");
Packit bd2e5d
        converterCAMLtoTK ~context_widget "y" ty;
Packit bd2e5d
        ")";
Packit bd2e5d
        argname;
Packit bd2e5d
        "))"]
Packit bd2e5d
 | Function _ -> fatal_error "unexpected function type in converterCAMLtoTK"
Packit bd2e5d
 | Unit -> fatal_error "unexpected unit type in converterCAMLtoTK"
Packit bd2e5d
 | Record _ -> fatal_error "unexpected product type in converterCAMLtoTK"
Packit bd2e5d
Packit bd2e5d
(*
Packit bd2e5d
 * Produce a list of arguments from a template
Packit bd2e5d
 *  The idea here is to avoid allocation as much as possible
Packit bd2e5d
 *
Packit bd2e5d
 *)
Packit bd2e5d
Packit bd2e5d
let code_of_template ~context_widget ?func:(funtemplate=false) template =
Packit bd2e5d
  let catch_opts = ref ("", "") in (* class name and first option *)
Packit bd2e5d
  let variables = ref [] in
Packit bd2e5d
  let variables2 = ref [] in
Packit bd2e5d
  let varcnter = ref 0 in
Packit bd2e5d
  let optionvar = ref None in
Packit bd2e5d
  let newvar1 l =
Packit bd2e5d
      match !optionvar with
Packit bd2e5d
        Some v -> optionvar := None; v
Packit bd2e5d
      | None ->
Packit bd2e5d
          incr varcnter;
Packit bd2e5d
          let v = "v" ^ (string_of_int !varcnter) in
Packit bd2e5d
          variables := (l, v) :: !variables; v in
Packit bd2e5d
  let newvar2 l =
Packit bd2e5d
      match !optionvar with
Packit bd2e5d
        Some v -> optionvar := None; v
Packit bd2e5d
      | None ->
Packit bd2e5d
          incr varcnter;
Packit bd2e5d
          let v = "v" ^ (string_of_int !varcnter) in
Packit bd2e5d
          variables2 := (l, v) :: !variables2; v in
Packit bd2e5d
  let newvar = ref newvar1 in
Packit bd2e5d
  let rec coderec = function
Packit bd2e5d
    StringArg s -> "TkToken \"" ^ s ^ "\""
Packit bd2e5d
  | TypeArg (_, List (Subtype (sup, sub))) when not !Flags.camltk ->
Packit bd2e5d
      begin try
Packit bd2e5d
        let typdef = Hashtbl.find types_table sup in
Packit bd2e5d
        let classdef = List.assoc sub typdef.subtypes in
Packit bd2e5d
        let lbl = gettklabel (List.hd classdef) in
Packit bd2e5d
        catch_opts := (sub ^ "_" ^ sup, lbl);
Packit bd2e5d
        newvar := newvar2;
Packit bd2e5d
        "TkTokenList opts"
Packit bd2e5d
      with Not_found ->
Packit bd2e5d
        raise (Failure (Printf.sprintf "type %s(%s) not found" sup sub));
Packit bd2e5d
      end
Packit bd2e5d
  | TypeArg (l, List ty) ->
Packit bd2e5d
      (if !Flags.camltk then
Packit bd2e5d
         "TkTokenList (List.map (function x -> "
Packit bd2e5d
       else
Packit bd2e5d
         "TkTokenList (List.map ~f:(function x -> ")
Packit bd2e5d
      ^ converterCAMLtoTK ~context_widget "x" ty
Packit bd2e5d
      ^ ") " ^ !newvar l ^ ")"
Packit bd2e5d
  | TypeArg (l, Function tyarg) ->
Packit bd2e5d
     "let id = register_callback " ^ context_widget
Packit bd2e5d
     ^ " ~callback: " ^ wrapper_code ~name:(!newvar l) tyarg
Packit bd2e5d
     ^ " in TkToken (\"camlcb \" ^ id)"
Packit bd2e5d
  | TypeArg (l, ty) -> converterCAMLtoTK ~context_widget (!newvar l) ty
Packit bd2e5d
  | ListArg l ->
Packit bd2e5d
      "TkQuote (TkTokenList ["
Packit bd2e5d
      ^ String.concat ~sep:";\n    " (List.map ~f:coderec l) ^ "])"
Packit bd2e5d
  | OptionalArgs (l, tl, d) ->
Packit bd2e5d
      let nv = !newvar ("?" ^ l) in
Packit bd2e5d
      optionvar := Some nv; (* Store *)
Packit bd2e5d
      let argstr = String.concat ~sep:"; " (List.map ~f:coderec tl) in
Packit bd2e5d
      let defstr = String.concat ~sep:"; " (List.map ~f:coderec d) in
Packit bd2e5d
      "TkTokenList (match " ^ nv ^ " with\n"
Packit bd2e5d
      ^ " | Some " ^ nv ^ " -> [" ^ argstr ^ "]\n"
Packit bd2e5d
      ^ " | None -> [" ^ defstr ^ "])"
Packit bd2e5d
  in
Packit bd2e5d
  let code =
Packit bd2e5d
    if funtemplate then
Packit bd2e5d
    match template with
Packit bd2e5d
      ListArg l ->
Packit bd2e5d
        "[|" ^ String.concat ~sep:";\n    " (List.map ~f:coderec l) ^ "|]"
Packit bd2e5d
    | _ -> "[|" ^ coderec template ^ "|]"
Packit bd2e5d
    else
Packit bd2e5d
    match template with
Packit bd2e5d
      ListArg [x] -> coderec x
Packit bd2e5d
    | ListArg l ->
Packit bd2e5d
        "TkTokenList [" ^
Packit bd2e5d
        String.concat ~sep:";\n    " (List.map ~f:coderec l) ^
Packit bd2e5d
        "]"
Packit bd2e5d
    | _ -> coderec template
Packit bd2e5d
    in
Packit bd2e5d
    code, List.rev !variables, List.rev !variables2, !catch_opts
Packit bd2e5d
Packit bd2e5d
(*
Packit bd2e5d
 * Converters for user defined types
Packit bd2e5d
 *)
Packit bd2e5d
Packit bd2e5d
(* For each case of a concrete type *)
Packit bd2e5d
let labltk_write_clause ~w ~context_widget comp =
Packit bd2e5d
  let warrow () = w " -> " in
Packit bd2e5d
  w "`";
Packit bd2e5d
  w comp.var_name;
Packit bd2e5d
Packit bd2e5d
  let code, variables, variables2, (co, _) =
Packit bd2e5d
    code_of_template ~context_widget comp.template in
Packit bd2e5d
Packit bd2e5d
  (* no subtype I think ... *)
Packit bd2e5d
  if co <> "" then raise (Failure "write_clause subtype ?");
Packit bd2e5d
  begin match variables with
Packit bd2e5d
  | [] -> warrow()
Packit bd2e5d
  | [x] -> w " "; w (labeloff x ~at:"write_clause"); warrow()
Packit bd2e5d
  | l ->
Packit bd2e5d
      w " ( ";
Packit bd2e5d
      w (String.concat ~sep:", " (List.map ~f:(labeloff ~at:"write_clause") l));
Packit bd2e5d
      w ")";
Packit bd2e5d
      warrow()
Packit bd2e5d
  end;
Packit bd2e5d
  w code
Packit bd2e5d
Packit bd2e5d
let camltk_write_clause ~w ~context_widget ~subtype comp =
Packit bd2e5d
  let warrow () =
Packit bd2e5d
    w " -> ";
Packit bd2e5d
    if subtype then
Packit bd2e5d
      w ("chk_sub \""^comp.ml_name^"\" table C" ^ comp.ml_name ^ "; ")
Packit bd2e5d
  in
Packit bd2e5d
Packit bd2e5d
  w comp.ml_name; (* we use ml_name, not var_name, specialized for labltk *)
Packit bd2e5d
Packit bd2e5d
  let code, variables, variables2, (co, _) =
Packit bd2e5d
    code_of_template ~context_widget comp.template in
Packit bd2e5d
Packit bd2e5d
  (* no subtype I think ... *)
Packit bd2e5d
  if co <> "" then raise (Failure "write_clause subtype ?");
Packit bd2e5d
  begin match variables with
Packit bd2e5d
  | [] -> warrow()
Packit bd2e5d
  | [x] -> w " "; w (labeloff x ~at:"write_clause"); warrow()
Packit bd2e5d
  | l ->
Packit bd2e5d
      w " ( ";
Packit bd2e5d
      w (String.concat ~sep:", " (List.map ~f:(labeloff ~at:"write_clause") l));
Packit bd2e5d
      w ")";
Packit bd2e5d
      warrow()
Packit bd2e5d
  end;
Packit bd2e5d
  w code
Packit bd2e5d
Packit bd2e5d
let write_clause ~w ~context_widget ~subtype comp =
Packit bd2e5d
  if !Flags.camltk then camltk_write_clause ~w ~context_widget ~subtype comp
Packit bd2e5d
  else labltk_write_clause ~w ~context_widget comp
Packit bd2e5d
Packit bd2e5d
(* The full converter *)
Packit bd2e5d
let write_CAMLtoTK ~w ~def:typdef ?safetype:(st = true) name =
Packit bd2e5d
  let write_one name constrs =
Packit bd2e5d
    let subtype = typdef.subtypes <> [] in
Packit bd2e5d
    w ("let cCAMLtoTK" ^ name);
Packit bd2e5d
    let context_widget =
Packit bd2e5d
      if typdef.requires_widget_context then begin
Packit bd2e5d
        w " w"; "w"
Packit bd2e5d
        end
Packit bd2e5d
      else
Packit bd2e5d
        "dummy" in
Packit bd2e5d
    if !Flags.camltk && subtype then w " table";
Packit bd2e5d
    if st then begin
Packit bd2e5d
      w " : ";
Packit bd2e5d
      if typdef.variant then w ("[< " ^ name ^ "]") else w name;
Packit bd2e5d
      w " -> tkArgs "
Packit bd2e5d
    end;
Packit bd2e5d
    w (" = function");
Packit bd2e5d
    List.iter constrs
Packit bd2e5d
      ~f:(fun c -> w "\n  | "; write_clause ~w ~context_widget ~subtype c);
Packit bd2e5d
    w "\n\n\n"
Packit bd2e5d
  in
Packit bd2e5d
Packit bd2e5d
  let constrs = typdef.constructors in
Packit bd2e5d
  if !Flags.camltk then write_one name constrs
Packit bd2e5d
  else begin
Packit bd2e5d
    (* Only needed if no subtypes, otherwise use optionals *)
Packit bd2e5d
    if typdef.subtypes == [] then
Packit bd2e5d
      write_one name constrs
Packit bd2e5d
    else
Packit bd2e5d
      List.iter constrs ~f:
Packit bd2e5d
        begin fun fc ->
Packit bd2e5d
          let code, vars, _, (co, _) =
Packit bd2e5d
            code_of_template ~context_widget:"dummy" fc.template in
Packit bd2e5d
          if co <> "" then fatal_error "optionals in optionals";
Packit bd2e5d
          let vars = List.map ~f:snd vars in
Packit bd2e5d
          w "let ccCAMLtoTK"; w name; w "_"; w (small fc.ml_name);
Packit bd2e5d
          w " ("; w (String.concat ~sep:", " vars); w ") =\n    ";
Packit bd2e5d
          w code; w "\n\n"
Packit bd2e5d
        end
Packit bd2e5d
  end
Packit bd2e5d
Packit bd2e5d
(* Tcl does not really return "lists". It returns sp separated tokens *)
Packit bd2e5d
let rec write_result_parsing ~w = function
Packit bd2e5d
    List String ->
Packit bd2e5d
      w "(splitlist res)"
Packit bd2e5d
  | List ty ->
Packit bd2e5d
      if !Flags.camltk then
Packit bd2e5d
        w ("    List.map " ^ converterTKtoCAML ~arg:"(splitlist res)" ty)
Packit bd2e5d
      else
Packit bd2e5d
        w ("    List.map ~f: " ^ converterTKtoCAML ~arg:"(splitlist res)" ty)
Packit bd2e5d
  | Product tyl -> raise (Failure "Product -> record was done. ???")
Packit bd2e5d
  | Record tyl -> (* of course all the labels are "" *)
Packit bd2e5d
      let rnames = varnames ~prefix:"r" (List.length tyl) in
Packit bd2e5d
      w "    let l = splitlist res in";
Packit bd2e5d
      w ("\n      if List.length l <> " ^ string_of_int (List.length tyl));
Packit bd2e5d
      w ("\n      then Pervasives.raise (TkError (\"unexpected result: \" ^ res))");
Packit bd2e5d
      w ("\n      else ");
Packit bd2e5d
      List.iter2 rnames tyl ~f:
Packit bd2e5d
        begin fun r (l, ty) ->
Packit bd2e5d
          if l <> "" then raise (Failure "lables in return type!!!");
Packit bd2e5d
          w ("    let " ^ r ^ ", l = ");
Packit bd2e5d
          begin match type_parser_arity ty with
Packit bd2e5d
            OneToken ->
Packit bd2e5d
              w (converterTKtoCAML ~arg:"(List.hd l)" ty); w (", List.tl l")
Packit bd2e5d
          | MultipleToken ->
Packit bd2e5d
              w (converterTKtoCAML ~arg:"l" ty)
Packit bd2e5d
          end;
Packit bd2e5d
          w (" in\n")
Packit bd2e5d
        end;
Packit bd2e5d
      w (String.concat ~sep:", " rnames)
Packit bd2e5d
  | String ->
Packit bd2e5d
      w (converterTKtoCAML ~arg:"res" String)
Packit bd2e5d
  | As (ty, _) -> write_result_parsing ~w ty
Packit bd2e5d
  | ty ->
Packit bd2e5d
      match type_parser_arity ty with
Packit bd2e5d
        OneToken -> w (converterTKtoCAML ~arg:"res" ty)
Packit bd2e5d
      | MultipleToken -> w (converterTKtoCAML ~arg:"(splitlist res)" ty)
Packit bd2e5d
Packit bd2e5d
let labltk_write_function ~w def =
Packit bd2e5d
  w ("let " ^ caml_name def.ml_name);
Packit bd2e5d
  (* a bit approximative *)
Packit bd2e5d
  let context_widget = match def.template with
Packit bd2e5d
    ListArg (TypeArg(_, UserDefined("widget")) :: _) -> "v1"
Packit bd2e5d
  | ListArg (TypeArg(_, Subtype("widget", _)) :: _) -> "v1"
Packit bd2e5d
  | _ -> "dummy" in
Packit bd2e5d
Packit bd2e5d
  let code, variables, variables2, (co, lbl) =
Packit bd2e5d
    code_of_template ~func:true ~context_widget def.template in
Packit bd2e5d
  (* Arguments *)
Packit bd2e5d
  let uv, lv, ov =
Packit bd2e5d
    let rec replace_args ~u ~l ~o = function
Packit bd2e5d
        [] -> u, l, o
Packit bd2e5d
      | ("", x) :: ls ->
Packit bd2e5d
          replace_args ~u:(x :: u) ~l ~o  ls
Packit bd2e5d
      | (p, _ as x) :: ls when p.[0] = '?' ->
Packit bd2e5d
          replace_args ~u ~l ~o:(x :: o) ls
Packit bd2e5d
      | x :: ls ->
Packit bd2e5d
          replace_args ~u ~l:(x :: l) ~o ls
Packit bd2e5d
    in
Packit bd2e5d
      replace_args ~u:[] ~l:[] ~o:[] (List.rev (variables @ variables2))
Packit bd2e5d
  in
Packit bd2e5d
  let has_opts = (ov <> [] || co <> "") in
Packit bd2e5d
  if not has_opts then List.iter uv ~f:(fun x -> w " "; w x);
Packit bd2e5d
  List.iter (lv@ov) ~f:(fun (l, v) -> w " "; w (labelstring l); w v);
Packit bd2e5d
  if co <> "" then begin
Packit bd2e5d
    if lv = [] && ov = [] then w (" ?" ^ lbl ^ ":eta");
Packit bd2e5d
    w " =\n";
Packit bd2e5d
    w (co ^ "_optionals");
Packit bd2e5d
    if lv = [] && ov = [] then w (" ?" ^ lbl ^ ":eta");
Packit bd2e5d
    w " (fun opts";
Packit bd2e5d
    if uv = [] then w " ()" else
Packit bd2e5d
    if has_opts then List.iter uv ~f:(fun x -> w " "; w x);
Packit bd2e5d
    w " ->\n"
Packit bd2e5d
  end else begin
Packit bd2e5d
    if (ov <> [] || lv = []) && uv = [] then w " ()" else
Packit bd2e5d
    if has_opts then List.iter uv ~f:(fun x -> w " "; w x);
Packit bd2e5d
    w " =\n"
Packit bd2e5d
  end;
Packit bd2e5d
  begin match def.result with
Packit bd2e5d
  | Unit | As (Unit, _) -> w "tkCommand "; w code
Packit bd2e5d
  | ty ->
Packit bd2e5d
      w "let res = tkEval "; w code ; w " in \n";
Packit bd2e5d
      write_result_parsing ~w ty
Packit bd2e5d
  end;
Packit bd2e5d
  if co <> "" then w ")";
Packit bd2e5d
  w "\n\n"
Packit bd2e5d
Packit bd2e5d
let camltk_write_function ~w def =
Packit bd2e5d
  w ("let " ^ caml_name def.ml_name);
Packit bd2e5d
  (* a bit approximative *)
Packit bd2e5d
  let context_widget = match def.template with
Packit bd2e5d
    ListArg (TypeArg(_, UserDefined("widget")) :: _) -> "v1"
Packit bd2e5d
  | ListArg (TypeArg(_, Subtype("widget", _)) :: _) -> "v1"
Packit bd2e5d
  | _ -> "dummy" in
Packit bd2e5d
Packit bd2e5d
  let code, variables, variables2, (co, lbl) =
Packit bd2e5d
    code_of_template ~func:true ~context_widget def.template in
Packit bd2e5d
  (* Arguments *)
Packit bd2e5d
  let uv, ov =
Packit bd2e5d
    let rec replace_args ~u ~o = function
Packit bd2e5d
        [] -> u, o
Packit bd2e5d
      | ("", x) :: ls ->
Packit bd2e5d
          replace_args ~u:(x :: u) ~o  ls
Packit bd2e5d
      | (p, _ as x) :: ls when p.[0] = '?' ->
Packit bd2e5d
          replace_args ~u ~o:(x :: o) ls
Packit bd2e5d
      | (_,x) :: ls ->
Packit bd2e5d
          replace_args ~u:(x::u) ~o ls
Packit bd2e5d
    in
Packit bd2e5d
      replace_args ~u:[] ~o:[] (List.rev (variables @ variables2))
Packit bd2e5d
  in
Packit bd2e5d
  let has_opts = ov <> [] (* (ov <> [] || co <> "") *) in
Packit bd2e5d
  if not has_opts then List.iter uv ~f:(fun x -> w " "; w x);
Packit bd2e5d
  List.iter ov ~f:(fun (l, v) -> w " "; w (labelstring l); w v);
Packit bd2e5d
  begin
Packit bd2e5d
    if uv = [] then w " ()" else
Packit bd2e5d
    if has_opts then List.iter uv ~f:(fun x -> w " "; w x);
Packit bd2e5d
    w " =\n"
Packit bd2e5d
  end;
Packit bd2e5d
  begin match def.result with
Packit bd2e5d
  | Unit | As (Unit, _) -> w "tkCommand "; w code
Packit bd2e5d
  | ty ->
Packit bd2e5d
      w "let res = tkEval "; w code ; w " in \n";
Packit bd2e5d
      write_result_parsing ~w ty
Packit bd2e5d
  end;
Packit bd2e5d
  w "\n\n"
Packit bd2e5d
Packit bd2e5d
(*
Packit bd2e5d
  w ("let " ^ def.ml_name);
Packit bd2e5d
  (* a bit approximative *)
Packit bd2e5d
  let context_widget = match def.template with
Packit bd2e5d
    ListArg (TypeArg(_, UserDefined("widget")) :: _) -> "v1"
Packit bd2e5d
  | ListArg (TypeArg(_, Subtype("widget", _)) :: _) -> "v1"
Packit bd2e5d
  | _ -> "dummy" in
Packit bd2e5d
Packit bd2e5d
  let code, variables, variables2, (co, lbl) =
Packit bd2e5d
    code_of_template ~func:true ~context_widget def.template in
Packit bd2e5d
  let variables = variables @ variables2 in
Packit bd2e5d
  (* Arguments *)
Packit bd2e5d
  begin match variables with
Packit bd2e5d
    [] -> w " () =\n"
Packit bd2e5d
  | l ->
Packit bd2e5d
      let has_normal_argument = ref false in
Packit bd2e5d
      List.iter (fun (l,x) ->
Packit bd2e5d
        w " ";
Packit bd2e5d
        if l <> "" then
Packit bd2e5d
          if l.[0] = '?' then w (l ^ ":") else has_normal_argument := true
Packit bd2e5d
        else has_normal_argument := true;
Packit bd2e5d
        w x) l;
Packit bd2e5d
      if not !has_normal_argument then w " ()";
Packit bd2e5d
      w " =\n"
Packit bd2e5d
  end;
Packit bd2e5d
  begin match def.result with
Packit bd2e5d
  | Unit | As (Unit, _) ->  w "tkCommand ";  w code
Packit bd2e5d
  | ty ->
Packit bd2e5d
      w "let res = tkEval "; w code ; w " in \n";
Packit bd2e5d
      write_result_parsing ~w ty
Packit bd2e5d
  end;
Packit bd2e5d
  w "\n\n"
Packit bd2e5d
*)
Packit bd2e5d
Packit bd2e5d
let write_function ~w def =
Packit bd2e5d
  if !Flags.camltk then camltk_write_function ~w def
Packit bd2e5d
  else labltk_write_function ~w def
Packit bd2e5d
;;
Packit bd2e5d
Packit bd2e5d
let labltk_write_create ~w clas =
Packit bd2e5d
  let oclas = caml_name clas in
Packit bd2e5d
  w ("let create ?name =\n");
Packit bd2e5d
  w ("  " ^ oclas ^ "_options_optionals (fun opts parent ->\n");
Packit bd2e5d
  w ("     let w = new_atom \"" ^ clas ^ "\" ~parent ?name in\n");
Packit bd2e5d
  w  "     tkCommand [|";
Packit bd2e5d
  w ("TkToken \"" ^ clas ^ "\";\n");
Packit bd2e5d
  w ("              TkToken (Widget.name w);\n");
Packit bd2e5d
  w ("              TkTokenList opts |];\n");
Packit bd2e5d
  w ("      w)\n\n\n")
Packit bd2e5d
Packit bd2e5d
let camltk_write_create ~w clas =
Packit bd2e5d
  w ("let create ?name parent options =\n");
Packit bd2e5d
  w ("  let w = new_atom \"" ^ clas ^ "\" ~parent ?name in\n");
Packit bd2e5d
  w  "  tkCommand [|";
Packit bd2e5d
  w ("TkToken \"" ^ clas ^ "\";\n");
Packit bd2e5d
  w ("              TkToken (Widget.name w);\n");
Packit bd2e5d
  w ("              TkTokenList (List.map (function x -> "^
Packit bd2e5d
                                        converterCAMLtoTK "w" "x" (Subtype("options",clas)) ^ ") options)\n");
Packit bd2e5d
  w ("             |];\n");
Packit bd2e5d
  w ("      w\n\n")
Packit bd2e5d
Packit bd2e5d
let camltk_write_named_create ~w clas =
Packit bd2e5d
  w ("let create_named parent name options =\n");
Packit bd2e5d
  w ("  let w = new_atom \"" ^ clas ^ "\" ~parent ~name in\n");
Packit bd2e5d
  w  "  tkCommand [|";
Packit bd2e5d
  w ("TkToken \"" ^ clas ^ "\";\n");
Packit bd2e5d
  w ("              TkToken (Widget.name w);\n");
Packit bd2e5d
  w ("              TkTokenList (List.map (function x -> "^
Packit bd2e5d
                                        converterCAMLtoTK "w" "x" (Subtype("options",clas)) ^ ") options)\n");
Packit bd2e5d
  w ("             |];\n");
Packit bd2e5d
  w ("      w\n\n")
Packit bd2e5d
Packit bd2e5d
(* Search Path. *)
Packit bd2e5d
let search_path = ref ["."]
Packit bd2e5d
Packit bd2e5d
(* taken from utils/misc.ml *)
Packit bd2e5d
let find_in_path path name =
Packit bd2e5d
  if not (Filename.is_implicit name) then
Packit bd2e5d
    if Sys.file_exists name then name else raise Not_found
Packit bd2e5d
  else begin
Packit bd2e5d
    let rec try_dir = function
Packit bd2e5d
      [] -> raise Not_found
Packit bd2e5d
    | dir :: rem ->
Packit bd2e5d
        let fullname = Filename.concat dir name in
Packit bd2e5d
        if Sys.file_exists fullname then fullname else try_dir rem
Packit bd2e5d
    in try_dir path
Packit bd2e5d
  end
Packit bd2e5d
Packit bd2e5d
(* builtin-code: the file (without suffix) is in .template... *)
Packit bd2e5d
(* not efficient, but hell *)
Packit bd2e5d
let write_external ~w def =
Packit bd2e5d
  match def.template with
Packit bd2e5d
  | StringArg fname ->
Packit bd2e5d
      begin try
Packit bd2e5d
        let realname = find_in_path !search_path (fname ^ ".ml") in
Packit bd2e5d
        let ic = open_in_bin realname in
Packit bd2e5d
        try
Packit bd2e5d
          let code_list = Ppparse.parse_channel ic in
Packit bd2e5d
          close_in ic;
Packit bd2e5d
          List.iter (Ppexec.exec (fun _ -> ()) w)
Packit bd2e5d
            (if !Flags.camltk then
Packit bd2e5d
              Code.Define "CAMLTK" :: code_list else code_list );
Packit bd2e5d
        with
Packit bd2e5d
        | Ppparse.Error s ->
Packit bd2e5d
            close_in ic;
Packit bd2e5d
            raise (Compiler_Error (Printf.sprintf "Preprocess error: %s" s))
Packit bd2e5d
      with
Packit bd2e5d
      | Not_found ->
Packit bd2e5d
          raise (Compiler_Error ("can't find external file: " ^ fname))
Packit bd2e5d
      end
Packit bd2e5d
  | _ -> raise (Compiler_Error "invalid external definition")
Packit bd2e5d
Packit bd2e5d
let write_catch_optionals ~w clas ~def:typdef =
Packit bd2e5d
  if typdef.subtypes = [] then () else
Packit bd2e5d
  List.iter typdef.subtypes ~f:
Packit bd2e5d
  begin fun (subclass, classdefs) ->
Packit bd2e5d
    w  ("let " ^ caml_name subclass ^ "_" ^ caml_name clas ^
Packit bd2e5d
        "_optionals f = fun\n");
Packit bd2e5d
    let tklabels = List.map ~f:gettklabel classdefs in
Packit bd2e5d
    let l =
Packit bd2e5d
      List.map classdefs ~f:
Packit bd2e5d
      begin fun fc ->
Packit bd2e5d
        (*
Packit bd2e5d
        let code, vars, _, (co, _) =
Packit bd2e5d
          code_of_template ~context_widget:"dummy" fc.template in
Packit bd2e5d
        if co <> "" then fatal_error "optionals in optionals";
Packit bd2e5d
        *)
Packit bd2e5d
        let p = gettklabel fc in
Packit bd2e5d
        (if count ~item:p tklabels > 1 then small fc.var_name else p),
Packit bd2e5d
        small fc.ml_name
Packit bd2e5d
      end in
Packit bd2e5d
    let p =  List.map l ~f:(fun (si, _) -> "  ?" ^ si) in
Packit bd2e5d
    let v =
Packit bd2e5d
      List.map l ~f:
Packit bd2e5d
        begin fun (si, s) ->
Packit bd2e5d
          "(maycons ccCAMLtoTK" ^ caml_name clas ^ "_" ^ caml_name s ^ " " ^ si
Packit bd2e5d
        end in
Packit bd2e5d
    w (String.concat ~sep:"\n" p);
Packit bd2e5d
    w " ->\n";
Packit bd2e5d
    w "    f ";
Packit bd2e5d
    w (String.concat ~sep:"\n      " v);
Packit bd2e5d
    w "\n       []";
Packit bd2e5d
    w (String.make (List.length v) ')');
Packit bd2e5d
    w "\n\n"
Packit bd2e5d
  end