summaryrefslogtreecommitdiffstats
path: root/otherlibs/labltk/compiler/compile.ml
diff options
context:
space:
mode:
Diffstat (limited to 'otherlibs/labltk/compiler/compile.ml')
-rw-r--r--otherlibs/labltk/compiler/compile.ml803
1 files changed, 803 insertions, 0 deletions
diff --git a/otherlibs/labltk/compiler/compile.ml b/otherlibs/labltk/compiler/compile.ml
new file mode 100644
index 000000000..dbc777da1
--- /dev/null
+++ b/otherlibs/labltk/compiler/compile.ml
@@ -0,0 +1,803 @@
+(* $Id$ *)
+
+open Tables
+
+(* CONFIGURE *)
+(* if you set it true, ImagePhoto and ImageBitmap will annoy you... *)
+let safetype = false
+
+let lowercase s =
+ let r = String.create len:(String.length s) in
+ String.blit s pos:0 to:r to_pos:0 len:(String.length s);
+ for i = 0 to String.length s - 1
+ do
+ let c = s.[i] in
+ if c >= 'A' & c <= 'Z' then r.[i] <- Char.chr(Char.code c + 32)
+ done;
+ r
+
+let labeloff :at l = match l with
+ "",t -> t
+| l ,t -> raise (Failure ("labeloff : " ^ l ^ " at " ^ at))
+
+let labelstring l = match l with
+ "" -> ""
+| _ -> l ^ ":"
+
+let labelprint :w l = w (labelstring l)
+
+let small s =
+ let sout = ref "" in
+ for i=0 to String.length s - 1 do
+ let c =
+ if s.[i] >= 'A' && s.[i] <= 'Z' then
+ Char.chr(Char.code(s.[i]) - (Char.code 'A' - Char.code 'a'))
+ else s.[i]
+ in
+ sout := !sout ^ (String.make len:1 c)
+ done;
+ !sout
+
+let small_ident s =
+ let idents = ["to"; "raise"; "in"; "class"; "new"]
+ in
+ let s = small s in
+ if List.mem elt:s idents then (String.make len:1 s.[0])^s
+ else s
+
+let gettklabel fc =
+ match fc.template with
+ ListArg( StringArg s :: _ ) ->
+ if (try s.[0] = '-' with _ -> false) then
+ String.sub s pos:1 len:(String.length s - 1)
+ else
+ if s = "" then small fc.ml_name else small s
+ | _ -> raise (Failure "gettklabel")
+
+let count elt:x l =
+ let count = ref 0 in
+ List.iter fun:(fun y -> if x = y then incr count) l;
+ !count
+
+let catenate_sep :sep =
+ function
+ [] -> ""
+ | x::l -> List.fold_left fun:(fun :acc s' -> acc ^ sep ^ s') acc:x l
+
+(* Extract all types from a template *)
+let rec types_of_template = function
+ StringArg _ -> []
+ | TypeArg (l,t) -> [l,t]
+ | ListArg l -> List.flatten (List.map fun:types_of_template l)
+ | OptionalArgs (l,tl,_) ->
+ begin
+ match List.flatten (List.map fun:types_of_template tl) with
+ ["",t] -> ["?"^l,t]
+ | [_,_] -> raise (Failure "0 label required")
+ | _ -> raise (Failure "0 or more than 1 args in for optionals")
+ end
+
+(*
+ * Pretty print a type
+ * used to write ML type definitions
+ *)
+let ppMLtype ?:any{=false} ?:return{=false} ?:def{=false} ?:counter{=ref 0} =
+ let rec ppMLtype =
+ function
+ Unit -> "unit"
+ | Int -> "int"
+ | Float -> "float"
+ | Bool -> "bool"
+ | Char -> "char"
+ | String -> "string"
+(* new *)
+ | List (Subtype (sup,sub)) ->
+ if return then
+ sub^"_"^sup^" list"
+ else
+ begin
+ try
+ let typdef = Hashtbl.find types_table key:sup in
+ let fcl = List.assoc key:sub typdef.subtypes in
+ let tklabels = List.map fun:gettklabel fcl in
+ let l = List.map fcl fun:
+ begin fun fc ->
+ "?" ^ begin let p = gettklabel fc in
+ if count elt:p tklabels > 1 then small fc.ml_name else p
+ end
+ ^ ":" ^
+ let l = types_of_template fc.template in
+ match l with
+ [] -> "unit"
+ | [lt] -> ppMLtype (labeloff lt at:"ppMLtype")
+ | l ->
+ "(" ^ catenate_sep sep:"*"
+ (List.map l
+ fun:(fun lt -> ppMLtype (labeloff lt at:"ppMLtype")))
+ ^ ")"
+ end in
+ catenate_sep sep:" ->\n" l
+ with
+ Not_found -> Printf.eprintf "ppMLtype %s/%s\n" sup sub; exit (-1)
+ end
+ | List ty -> (ppMLtype ty) ^ " list"
+ | Product tyl -> catenate_sep sep:" * " (List.map fun:ppMLtype tyl)
+ | Record tyl ->
+ catenate_sep sep:" * "
+ (List.map tyl fun:(fun (l,t) -> labelstring l ^ ppMLtype t))
+ | Subtype ("widget", sub) -> sub ^ " widget"
+ | UserDefined "widget" ->
+ if any then "any widget" else
+ let c = String.make len:1 (Char.chr(Char.code 'a' + !counter))
+ in
+ incr counter;
+ "'" ^ c ^ " widget"
+ | UserDefined s ->
+ (* a bit dirty hack for ImageBitmap and ImagePhoto *)
+ begin
+ try
+ let typdef = Hashtbl.find types_table key:s in
+ if typdef.variant then
+ if return then try
+ "[>" ^
+ catenate_sep sep:"|"
+ (List.map typdef.constructors fun:
+ begin
+ fun c ->
+ "`" ^ c.var_name ^
+ (match types_of_template c.template with
+ [] -> ""
+ | l -> " " ^ ppMLtype (Product (List.map l
+ fun:(labeloff at:"ppMLtype UserDefined"))))
+ end) ^ "]"
+ with
+ Not_found ->
+ (prerr_endline ("ppMLtype "^s^ " ?"); s)
+ else if not def & List.length typdef.constructors > 1 then
+ "#" ^ s
+ else s
+ else s
+ with Not_found -> s
+ end
+ | Subtype (s,s') -> s'^"_"^s
+ | Function (Product tyl) ->
+ raise (Failure "Function (Product tyl) ? ppMLtype")
+ | Function (Record tyl) ->
+ "(" ^ catenate_sep sep:" -> "
+ (List.map tyl fun:(fun (l,t) -> labelstring l ^ ppMLtype t))
+ ^ " -> unit)"
+ | Function ty ->
+ "(" ^ (ppMLtype ty) ^ " -> unit)"
+ | As (_, s) -> s
+ in
+ ppMLtype
+
+(* Produce a documentation version of a template *)
+let rec ppTemplate = function
+ StringArg s -> s
+ | TypeArg (l,t) -> "<" ^ ppMLtype t ^ ">"
+ | ListArg l -> "{" ^ catenate_sep sep:" " (List.map fun:ppTemplate l) ^ "}"
+ | OptionalArgs (l,tl,d) ->
+ "?" ^ l ^ "{" ^ catenate_sep sep:" " (List.map fun:ppTemplate tl)
+ ^ "}[<" ^ catenate_sep sep:" " (List.map fun:ppTemplate d) ^ ">]"
+
+let doc_of_template = function
+ ListArg l -> catenate_sep sep:" " (List.map fun:ppTemplate l)
+ | t -> ppTemplate t
+
+(*
+ * Type definitions
+ *)
+
+(* Write an ML constructor *)
+let write_constructor :w {ml_name = mlconstr; template = t} =
+ w mlconstr;
+ begin match types_of_template t with
+ [] -> ()
+ | l -> w " of ";
+ w (ppMLtype any:true (Product (List.map l
+ fun:(labeloff at:"write_constructor"))))
+ end;
+ w "\t\t(* tk option: "; w (doc_of_template t); w " *)"
+
+(* Write a rhs type decl *)
+let write_constructors :w = function
+ [] -> fatal_error "empty type"
+ | x::l ->
+ write_constructor :w x;
+ List.iter l fun:
+ begin fun x ->
+ w "\n\t| ";
+ write_constructor :w x
+ end
+
+(* Write an ML variant *)
+let write_variant :w {ml_name = mlconstr; var_name = varname; template = t} =
+ w "`";
+ w varname;
+ begin match types_of_template t with
+ [] -> ()
+ | l ->
+ w " ";
+ w (ppMLtype any:true def:true
+ (Product (List.map l fun:(labeloff at:"write_variant"))))
+ end;
+ w "\t\t(* tk option: "; w (doc_of_template t); w " *)"
+
+let write_variants :w = function
+ [] -> fatal_error "empty variants"
+ | x::l ->
+ write_variant :w x;
+ List.iter l fun:
+ begin fun x ->
+ w "\n | ";
+ write_variant :w x
+ end
+
+(* Definition of a type *)
+let write_type intf:w impl:w' name def:typdef =
+(* if typdef.subtypes = [] then (* If there is no subtypes *)
+ begin
+ (* The type itself *)
+ (* Put markers for extraction *)
+ w "(* type *)\n";
+ w ("type "^name^" =\n\t");
+ write_constructors :w (sort_components typdef.constructors);
+ w "\n(* /type *)\n\n"
+ end
+ else
+*)
+ begin
+ if typdef.subtypes = [] then
+ begin
+ w "(* Variant type *)\n";
+ w ("type "^name^" = [\n ");
+ write_variants :w (sort_components typdef.constructors);
+ w "\n]\n\n"
+ end
+ else
+ begin
+ (* Dynamic Subtyping *)
+ (* All the subtypes *)
+ List.iter typdef.subtypes fun:
+ begin fun (s,l) ->
+ w ("type "^s^"_"^name^" = [\n\t");
+ write_variants w:w (sort_components l);
+ w ("]\n\n")
+ end
+ end
+ end
+
+(************************************************************)
+(* Converters *)
+(************************************************************)
+
+let rec converterTKtoCAML argname as:ty =
+ match ty with
+ Int -> "int_of_string " ^ argname
+ | Float -> "float_of_string " ^ argname
+ | Bool -> "(match " ^ argname ^" with
+ \"1\" -> true
+ | \"0\" -> false
+ | s -> Pervasives.raise (Invalid_argument (\"cTKtoCAMLbool\" ^ s)))"
+ | Char -> "String.get "^argname ^" 0"
+ | String -> argname
+ | UserDefined s -> "cTKtoCAML"^s^" "^argname
+ | Subtype ("widget",s') ->
+ "(Obj.magic (cTKtoCAMLwidget "^argname^") : "^s'^" widget)"
+ | Subtype (s,s') -> "cTKtoCAML"^s'^"_"^s^" "^argname
+ | List ty ->
+ begin match type_parser_arity ty with
+ OneToken ->
+ "(List.map (function x -> " ^ (converterTKtoCAML "x) " as:ty)
+ ^ argname ^ ")"
+ | MultipleToken ->
+ "iterate_converter (function x -> " ^
+ (converterTKtoCAML "x) " as:ty) ^ argname ^ ")"
+ end
+ | As (ty, _) -> converterTKtoCAML argname as:ty
+ | t -> (prerr_endline ("ERROR with "^argname^" "^ppMLtype t);fatal_error "converterTKtoCAML")
+
+
+(*******************************)
+(* Wrappers *)
+(*******************************)
+let varnames :prefix n =
+ let rec var i =
+ if i > n then []
+ else (prefix^(string_of_int i)) :: (var (succ i))
+ in var 1
+
+(*
+ * generate wrapper source for callbacks
+ * transform a function ... -> unit in a function : unit -> unit
+ * using primitives arg_ ... from the protocol
+ * Warning: sequentiality is important in generated code
+ * TODO: remove arg_ stuff and process lists directly ?
+ *)
+
+let rec wrapper_code fname of:ty =
+ match ty with
+ Unit -> "(function _ -> "^fname^" ())"
+ | As (ty, _) -> wrapper_code fname of:ty
+ | ty ->
+ "(function args ->\n\t\t" ^
+ begin match ty with
+ Product tyl -> raise (Failure "Product -> record was done. ???")
+ | Record tyl ->
+ (* variables for each component of the product *)
+ let vnames = varnames prefix:"a" (List.length tyl) in
+ (* getting the arguments *)
+ let readarg =
+ List.map2 vnames tyl fun:
+ begin fun v (l,ty) ->
+ match type_parser_arity ty with
+ OneToken ->
+ "let ("^v^",args) = " ^
+ converterTKtoCAML "(List.hd args)" as:ty ^
+ ", List.tl args in\n\t\t"
+ | MultipleToken ->
+ "let ("^v^",args) = " ^
+ converterTKtoCAML "args" as:ty ^
+ " in\n\t\t"
+ end in
+ catenate_sep sep:"" readarg ^ fname ^ " " ^
+ catenate_sep sep:" "
+ (List.map2 fun:(fun v (l,_) -> labelstring l^v) vnames tyl)
+
+ (* all other types are read in one operation *)
+ | List ty ->
+ fname ^ "(" ^ converterTKtoCAML "args" as:ty ^ ")"
+ | String ->
+ fname ^ "(" ^ converterTKtoCAML "(List.hd args)" as:ty ^ ")"
+ | ty ->
+ begin match type_parser_arity ty with
+ OneToken ->
+ fname ^ "(" ^ converterTKtoCAML "(List.hd args)" as:ty ^ ")"
+ | MultipleToken ->
+ "let (v,_) = " ^ converterTKtoCAML "args" as:ty ^
+ " in\n\t\t" ^ fname ^ " v"
+ end
+ end ^ ")"
+
+(*************************************************************)
+(* Parsers *)
+(* are required only for values returned by commands and *)
+(* functions (table is computed by the parser) *)
+
+(* Tuples/Lists are Ok if they don't contain strings *)
+(* they will be returned as list of strings *)
+
+(* Can we generate a "parser" ?
+ -> all constructors are unit and at most one int and one string, with null constr
+*)
+type parser_pieces =
+ { mutable zeroary : (string * string) list ; (* kw string, ml name *)
+ mutable intpar : string list; (* one at most, mlname *)
+ mutable stringpar : string list (* idem *)
+ }
+
+type mini_parser =
+ NoParser
+ | ParserPieces of parser_pieces
+
+let can_generate_parser constructors =
+ let pp = {zeroary = []; intpar = []; stringpar = []} in
+ if List.for_all constructors pred:
+ begin fun c ->
+ match c.template with
+ ListArg [StringArg s] ->
+ pp.zeroary <- (s,"`" ^ c.var_name)::
+ pp.zeroary; true
+ | ListArg [TypeArg(_,Int)] | ListArg[TypeArg(_,Float)] ->
+ if pp.intpar <> [] then false
+ else (pp.intpar <- ["`" ^ c.var_name]; true)
+ | ListArg [TypeArg(_,String)] ->
+ if pp.stringpar <> [] then false
+ else (pp.stringpar <- ["`" ^ c.var_name]; true)
+ | _ -> false
+ end
+ then ParserPieces pp
+ else NoParser
+
+
+(* We can generate parsers only for simple types *)
+(* we should avoid multiple walks *)
+let write_TKtoCAML :w name def:typdef =
+ if typdef.parser_arity = MultipleToken then
+ prerr_string ("You must write cTKtoCAML" ^ name ^
+ " : string list ->" ^ name ^ " * string list\n")
+ else
+ let write :consts :name =
+ match can_generate_parser consts with
+ NoParser ->
+ prerr_string
+ ("You must write cTKtoCAML" ^ name ^" : string ->"^name^"\n")
+ | ParserPieces pp ->
+ w ("let cTKtoCAML"^name^" n =\n");
+ (* First check integer *)
+ if pp.intpar <> [] then
+ begin
+ w (" try " ^ List.hd pp.intpar ^ " (int_of_string n)\n");
+ w (" with _ ->\n")
+ end;
+ w ("\tmatch n with\n");
+ let first = ref true in
+ List.iter pp.zeroary fun:
+ begin fun (tk,ml) ->
+ if not !first then w "\t| " else w "\t";
+ first := false;
+ w "\""; w tk; w "\" -> "; w ml; w "\n"
+ end;
+ let final = if pp.stringpar <> [] then
+ "n -> " ^ List.hd pp.stringpar ^ " n"
+ else " s -> Pervasives.raise (Invalid_argument (\"cTKtoCAML"
+ ^ name ^ ": \" ^s))"
+ in
+ if not !first then w "\t| " else w "\t";
+ w final;
+ w "\n\n"
+ in
+ begin
+ write :name consts:typdef.constructors;
+ List.iter typdef.subtypes fun: begin
+ fun (subname,consts) -> write name:(subname^"_"^name) :consts
+ end
+ end
+
+(******************************)
+(* Converters *)
+(******************************)
+
+(* Produce an in-lined converter Caml -> Tk for simple types *)
+(* the converter is a function of type: <type> -> string *)
+let rec converterCAMLtoTK :context_widget argname as:ty =
+ match ty with
+ Int -> "TkToken (string_of_int " ^ argname ^ ")"
+ | Float -> "TkToken (string_of_float " ^ argname ^ ")"
+ | Bool -> "if "^argname^" then TkToken \"1\" else TkToken \"0\""
+ | Char -> "TkToken (Char.escaped " ^ argname ^ ")"
+ | String -> "TkToken " ^ argname
+ | As (ty, _) -> converterCAMLtoTK :context_widget argname as:ty
+ | UserDefined s ->
+ let name = "cCAMLtoTK"^s^" " in
+ let args = argname in
+(*
+ let args =
+ if is_subtyped s then (* unconstraint subtype *)
+ s^"_any_table "^args
+ else args in
+*)
+ let args =
+ if requires_widget_context s then
+ context_widget^" "^args
+ else args in
+ name^args
+ | Subtype ("widget",s') ->
+ let name = "cCAMLtoTKwidget" in
+ let args = "("^argname^" : "^s'^" widget)" in
+(*
+ let args =
+ if requires_widget_context s then
+ context_widget^" "^args
+ else args in
+*)
+ name^args
+ | Subtype (s,s') ->
+ let name = "cCAMLtoTK"^s'^"_"^s^" " in
+ let args = if safetype then "("^argname^" : "^s'^"_"^s^")" else argname
+ in
+(*
+ let args = s^"_"^s'^"_table "^argname in
+*)
+ let args =
+ if requires_widget_context s then
+ context_widget^" "^args
+ else args in
+ name^args
+ | Function _ -> fatal_error "unexpected function type in converterCAMLtoTK"
+ | Unit -> fatal_error "unexpected unit type in converterCAMLtoTK"
+ | Product _ -> fatal_error "unexpected product type in converterCAMLtoTK"
+ | Record _ -> fatal_error "unexpected product type in converterCAMLtoTK"
+ | List ty -> fatal_error "unexpected list type in converterCAMLtoTK"
+
+(*
+ * Produce a list of arguments from a template
+ * The idea here is to avoid allocation as much as possible
+ *
+ *)
+
+let code_of_template :context_widget ?func:funtemplate{=false} template =
+ let catch_opts = ref ("","") in (* class name and first option *)
+ let variables = ref [] in
+ let variables2 = ref [] in
+ let varcnter = ref 0 in
+ let optionvar = ref None in
+ let newvar1 l =
+ match !optionvar with
+ Some v -> optionvar := None; v
+ | None ->
+ incr varcnter;
+ let v = "v" ^ (string_of_int !varcnter) in
+ variables := (l,v) :: !variables; v in
+ let newvar2 l =
+ match !optionvar with
+ Some v -> optionvar := None; v
+ | None ->
+ incr varcnter;
+ let v = "v" ^ (string_of_int !varcnter) in
+ variables2 := (l,v) :: !variables2; v in
+ let newvar = ref newvar1 in
+ let rec coderec = function
+ StringArg s -> "TkToken\"" ^ s ^ "\""
+ | TypeArg (_,List (Subtype (sup,sub) as ty)) ->
+ let typdef = Hashtbl.find key:sup types_table in
+ let classdef = List.assoc key:sub typdef.subtypes in
+ let lbl = gettklabel (List.hd classdef) in
+ catch_opts := (sub^"_"^sup, lbl);
+ newvar := newvar2;
+ "TkTokenList (List.map fun:(function x -> "
+ ^ converterCAMLtoTK :context_widget "x" as:ty ^ ") opts)"
+ | TypeArg (l,List ty) ->
+ "TkTokenList (List.map fun:(function x -> "
+ ^ converterCAMLtoTK :context_widget "x" as:ty
+ ^ ") " ^ !newvar l ^ ")"
+ | TypeArg (l,Function tyarg) ->
+ "let id = register_callback " ^context_widget
+ ^ " callback: "^ wrapper_code (!newvar l) of:tyarg
+ ^ " in TkToken (\"camlcb \"^id)"
+ | TypeArg (l,ty) -> converterCAMLtoTK :context_widget (!newvar l) as:ty
+ | ListArg l ->
+ "TkQuote (TkTokenList ["
+ ^ catenate_sep sep:";\n\t" (List.map fun:coderec l) ^ "])"
+ | OptionalArgs (l,tl,d) ->
+ let nv = !newvar ("?"^l) in
+ optionvar := Some nv; (* Store *)
+ let argstr = catenate_sep sep:"; " (List.map fun:coderec tl) in
+ let defstr = catenate_sep sep:"; " (List.map fun:coderec d) in
+ "TkTokenList (match "^ nv ^" with\n"
+ ^ " Some " ^ nv ^ " -> [" ^ argstr ^ "]\n"
+ ^ " | None -> [" ^ defstr ^ "])"
+ in
+ let code =
+ if funtemplate then
+ match template with
+ ListArg l ->
+ "[|" ^ catenate_sep sep:";\n\t" (List.map fun:coderec l) ^ "|]"
+ | _ -> "[|" ^ coderec template ^ "|]"
+ else
+ match template with
+ ListArg [x] -> coderec x
+ | ListArg l ->
+ "TkTokenList ["
+ ^ catenate_sep sep:";\n\t" (List.map fun:coderec l) ^ "]"
+ | _ -> coderec template
+ in
+ code , List.rev !variables, List.rev !variables2, !catch_opts
+
+(*
+ * Converters for user defined types
+ *)
+
+(* For each case of a concrete type *)
+let write_clause :w :context_widget comp =
+ let warrow () =
+ w " -> "
+ in
+
+ w "`";
+ w comp.var_name;
+
+ let code, variables, variables2, (co, _) =
+ code_of_template :context_widget comp.template in
+
+ (* no subtype I think ... *)
+ if co <> "" then raise (Failure "write_clause subtype ?");
+ begin match variables with
+ [] -> warrow()
+ | [x] -> w " "; w (labeloff x at:"write_clause"); warrow()
+ | l ->
+ w " ( ";
+ w (catenate_sep sep:", " (List.map fun:(labeloff at:"write_clause") l));
+ w ")";
+ warrow()
+ end;
+ w code
+
+
+(* The full converter *)
+let write_CAMLtoTK :w def:typdef ?safetype:st{=true} name =
+ let write_one name constrs =
+ w ("let cCAMLtoTK"^name);
+ let context_widget =
+ if typdef.requires_widget_context then begin
+ w " w"; "w"
+ end
+ else
+ "dummy" in
+ if safetype && st then
+ w (" : " ^ name ^ " -> tkArgs ");
+ w(" = function\n\t");
+ write_clause :w :context_widget (List.hd constrs);
+ List.iter (List.tl constrs)
+ fun:(fun c -> w "\n\t| "; write_clause :w :context_widget c);
+ w "\n\n\n"
+ in
+ if typdef.subtypes == [] then
+ write_one name typdef.constructors
+ else
+ List.iter typdef.subtypes fun:begin
+ fun (subname,constrs) ->
+ write_one (subname^"_"^name) constrs
+ end
+
+(* Tcl does not really return "lists". It returns sp separated tokens *)
+let rec write_result_parsing :w = function
+ List String ->
+ w "(splitlist res)"
+ | List ty ->
+ w ("\tList.map fun: "^ converterTKtoCAML "(splitlist res)" as:ty)
+ | Product tyl -> raise (Failure "Product -> record was done. ???")
+ | Record tyl -> (* of course all the labels are "" *)
+ let rnames = varnames prefix:"r" (List.length tyl) in
+ w "\tlet l = splitlist res in\n";
+ w ("\t if List.length l <> " ^ string_of_int (List.length tyl) ^ "\n");
+ w ("\t then Pervasives.raise (TkError (\"unexpected result: \" ^ res))");
+ w ("\t else ");
+ List.iter2 rnames tyl fun:
+ begin fun r (l,ty) ->
+ if l <> "" then raise (Failure "lables in return type!!!");
+ w ("\tlet " ^ r ^ ", l = ");
+ begin match type_parser_arity ty with
+ OneToken ->
+ w (converterTKtoCAML "(List.hd l)" as:ty); w (", List.tl l")
+ | MultipleToken ->
+ w (converterTKtoCAML "l" as:ty)
+ end;
+ w (" in\n")
+ end;
+ w (catenate_sep sep:"," rnames)
+ | String ->
+ w (converterTKtoCAML "res" as:String)
+ | As (ty, _) -> write_result_parsing :w ty
+ | ty ->
+ match type_parser_arity ty with
+ OneToken -> w (converterTKtoCAML "res" as:ty)
+ | MultipleToken -> w (converterTKtoCAML "(splitlist res)" as:ty)
+
+let write_function :w def =
+ w ("let "^def.ml_name);
+ (* a bit approximative *)
+ let context_widget = match def.template with
+ ListArg (TypeArg(_,UserDefined("widget"))::_) -> "v1"
+ | ListArg (TypeArg(_,Subtype("widget",_))::_) -> "v1"
+ | _ -> "dummy" in
+
+ let code, variables, variables2, (co, lbl) =
+ code_of_template func:true :context_widget def.template in
+ (* Arguments *)
+ let uv, lv, ov =
+ let rec replace_args :u :l :o = function
+ [] -> u, l, o
+ | ("",x)::ls ->
+ replace_args u:(x::u) :l :o ls
+ | (p,_ as x)::ls when p.[0] = '?' ->
+ replace_args :u :l o:(x::o) ls
+ | x::ls ->
+ replace_args :u l:(x::l) :o ls
+ in
+ replace_args u:[] l:[] o:[] (List.rev (variables @ variables2))
+ in
+ List.iter (lv@ov) fun:(fun (l,v) -> w " "; w (labelstring l); w v);
+ if co <> "" then begin
+ if lv = [] && ov = [] then w (" ?" ^ lbl ^ ":eta");
+ w " =\n";
+ w (co ^ "_optionals");
+ if lv = [] && ov = [] then w (" ?" ^ lbl ^ ":eta");
+ w " (fun opts";
+ if uv = [] then w " ()"
+ else List.iter uv fun:(fun x -> w " "; w x);
+ w " ->\n"
+ end else begin
+ List.iter uv fun:(fun x -> w " "; w x);
+ if (ov <> [] || lv = []) && uv = [] then w " ()";
+ w " =\n"
+ end;
+ begin match def.result with
+ Unit | As (Unit, _) ->
+ w "tkEval "; w code; w ";()";
+ | ty ->
+ w "let res = tkEval "; w code ; w " in \n";
+ write_result_parsing :w ty;
+ end;
+ if co <> "" then w ")";
+ w "\n\n"
+
+let write_create :w clas =
+ (w "let create :parent ?:name =\n" : unit);
+ w (" "^ clas ^ "_options_optionals (fun options () ->\n");
+ w (" let w = new_atom \"" ^ clas ^ "\" :parent ?:name in\n");
+ w " tkEval [|";
+ w ("TkToken \"" ^ clas ^ "\";\n");
+ w (" TkToken (Widget.name w);\n");
+ w (" TkTokenList (List.map fun:(cCAMLtoTK" ^ clas ^ "_options dummy) options) |];\n");
+ w (" w)\n\n\n")
+
+(* builtin-code: the file (without suffix) is in .template... *)
+(* not efficient, but hell *)
+let write_external :w def =
+ match def.template with
+ StringArg fname ->
+ let ic = open_in_bin (fname ^ ".ml") in
+ begin try
+ while true do
+ w (input_line ic);
+ w "\n"
+ done
+ with
+ End_of_file -> close_in ic
+ end
+ | _ -> raise (Compiler_Error "invalid external definition")
+
+let write_catch_optionals :w clas def:typdef =
+ if typdef.subtypes = [] then
+ (* begin Printf.eprintf "No subtypes\n";() end *) ()
+ else
+ (* Printf.eprintf "Type constructors of %s\n" clas; *)
+ List.iter typdef.subtypes fun:
+ begin fun (subclass, classdefs) ->
+(*
+ Printf.eprintf "Subclass %s" subclass;
+ List.iter (fun fc ->
+ Printf.eprintf " %s\n" fc.ml_name) classdefs;
+*)
+ w ("let " ^ subclass ^"_"^ clas ^ "_optionals f = fun\n");
+ let tklabels = List.map fun:gettklabel classdefs in
+ let l =
+ List.map classdefs fun:
+ begin fun fc ->
+ List.length (types_of_template fc.template),
+ types_of_template fc.template,
+ (* used as names of variants *)
+ fc.var_name,
+ begin let p = gettklabel fc in
+ if count elt:p tklabels > 1 then small fc.ml_name else p
+ end,
+ small_ident fc.ml_name (* used as labels *)
+ end in
+ let p =
+ List.map l fun:
+ begin fun (_,_,_,s,si) ->
+ if s = si then " ?:" ^ s
+ else " ?" ^ s ^ ":" ^ si
+ end in
+ let v =
+ List.map l fun:
+ begin fun (i,t,c,s,si) ->
+ let vars =
+ if i = 0 then "()" else
+ if i = 1 then "x"
+ else
+ let s = ref [] in
+ for i=1 to i do
+ s := !s @ ["x" ^ string_of_int i]
+ done;
+ "(" ^ catenate_sep sep:"," !s ^ ")"
+ in
+ let apvars =
+ if i = 0 then ""
+ (* VERY VERY QUICK HACK FOR 'a widget -> any widget *)
+ else if i = 1 && vars = "x" && t = ["",UserDefined "widget"] then
+ "(forget_type x)"
+ else vars
+ in
+ "(maycons (fun " ^ vars ^ " -> " ^ "`" ^ c ^ " " ^ apvars ^ ") " ^ si
+ end in
+ w (catenate_sep sep:"\n" p);
+ w " ->\n";
+ w " f ";
+ w (catenate_sep sep:"\n " v);
+ w "\n []";
+ w (String.make len:(List.length v) ')');
+ w "\n\n"
+ end