|
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 |
|
|
Packit |
bd2e5d |
(* Internal compiler errors *)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
exception Compiler_Error of string
|
|
Packit |
bd2e5d |
let fatal_error s = raise (Compiler_Error s)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Types of the description language *)
|
|
Packit |
bd2e5d |
type mltype =
|
|
Packit |
bd2e5d |
Unit
|
|
Packit |
bd2e5d |
| Int
|
|
Packit |
bd2e5d |
| Float
|
|
Packit |
bd2e5d |
| Bool
|
|
Packit |
bd2e5d |
| Char
|
|
Packit |
bd2e5d |
| String
|
|
Packit |
bd2e5d |
| List of mltype
|
|
Packit |
bd2e5d |
| Product of mltype list
|
|
Packit |
bd2e5d |
| Record of (string * mltype) list
|
|
Packit |
bd2e5d |
| UserDefined of string
|
|
Packit |
bd2e5d |
| Subtype of string * string
|
|
Packit |
bd2e5d |
| Function of mltype (* arg type only *)
|
|
Packit |
bd2e5d |
| As of mltype * string
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
type template =
|
|
Packit |
bd2e5d |
StringArg of string
|
|
Packit |
bd2e5d |
| TypeArg of string * mltype
|
|
Packit |
bd2e5d |
| ListArg of template list
|
|
Packit |
bd2e5d |
| OptionalArgs of string * template list * template list
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Sorts of components *)
|
|
Packit |
bd2e5d |
type component_type =
|
|
Packit |
bd2e5d |
Constructor
|
|
Packit |
bd2e5d |
| Command
|
|
Packit |
bd2e5d |
| External
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Full definition of a component *)
|
|
Packit |
bd2e5d |
type fullcomponent = {
|
|
Packit |
bd2e5d |
component : component_type;
|
|
Packit |
bd2e5d |
ml_name : string; (* used for camltk *)
|
|
Packit |
bd2e5d |
var_name : string; (* used just for labltk *)
|
|
Packit |
bd2e5d |
template : template;
|
|
Packit |
bd2e5d |
result : mltype;
|
|
Packit |
bd2e5d |
safe : bool
|
|
Packit |
bd2e5d |
}
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let sort_components =
|
|
Packit |
bd2e5d |
List.sort ~cmp:(fun c1 c2 -> compare c1.ml_name c2.ml_name)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* components are given either in full or abbreviated *)
|
|
Packit |
bd2e5d |
type component =
|
|
Packit |
bd2e5d |
Full of fullcomponent
|
|
Packit |
bd2e5d |
| Abbrev of string
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* A type definition *)
|
|
Packit |
bd2e5d |
(*
|
|
Packit |
bd2e5d |
requires_widget_context: the converter of the type MUST be passed
|
|
Packit |
bd2e5d |
an additional argument of type Widget.
|
|
Packit |
bd2e5d |
*)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
type parser_arity =
|
|
Packit |
bd2e5d |
OneToken
|
|
Packit |
bd2e5d |
| MultipleToken
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
type type_def = {
|
|
Packit |
bd2e5d |
parser_arity : parser_arity;
|
|
Packit |
bd2e5d |
mutable constructors : fullcomponent list;
|
|
Packit |
bd2e5d |
mutable subtypes : (string * fullcomponent list) list;
|
|
Packit |
bd2e5d |
mutable requires_widget_context : bool;
|
|
Packit |
bd2e5d |
mutable variant : bool
|
|
Packit |
bd2e5d |
}
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
type module_type =
|
|
Packit |
bd2e5d |
Widget
|
|
Packit |
bd2e5d |
| Family
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
type module_def = {
|
|
Packit |
bd2e5d |
module_type : module_type;
|
|
Packit |
bd2e5d |
commands : fullcomponent list;
|
|
Packit |
bd2e5d |
externals : fullcomponent list
|
|
Packit |
bd2e5d |
}
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(******************** The tables ********************)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* the table of all explicitly defined types *)
|
|
Packit |
bd2e5d |
let types_table = (Hashtbl.create 37 : (string, type_def) Hashtbl.t)
|
|
Packit |
bd2e5d |
(* "builtin" types *)
|
|
Packit |
bd2e5d |
let types_external = ref ([] : (string * parser_arity) list)
|
|
Packit |
bd2e5d |
(* dependancy order *)
|
|
Packit |
bd2e5d |
let types_order = (Tsort.create () : string Tsort.porder)
|
|
Packit |
bd2e5d |
(* Types of atomic values returned by Tk functions *)
|
|
Packit |
bd2e5d |
let types_returned = ref ([] : string list)
|
|
Packit |
bd2e5d |
(* Function table *)
|
|
Packit |
bd2e5d |
let function_table = ref ([] : fullcomponent list)
|
|
Packit |
bd2e5d |
(* Widget/Module table *)
|
|
Packit |
bd2e5d |
let module_table = (Hashtbl.create 37 : (string, module_def) Hashtbl.t)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* variant name *)
|
|
Packit |
bd2e5d |
let rec getvarname ml_name temp =
|
|
Packit |
bd2e5d |
let offhypben s =
|
|
Packit |
bd2e5d |
if (try String.sub s ~pos:0 ~len:1 with _ -> "") = "-" then
|
|
Packit |
bd2e5d |
String.sub s ~pos:1 ~len:(String.length s - 1)
|
|
Packit |
bd2e5d |
else s
|
|
Packit |
bd2e5d |
in
|
|
Packit |
bd2e5d |
let head = String.capitalize_ascii (offhypben begin
|
|
Packit |
bd2e5d |
match temp with
|
|
Packit |
bd2e5d |
StringArg s -> s
|
|
Packit |
bd2e5d |
| TypeArg (s,t) -> s
|
|
Packit |
bd2e5d |
| ListArg (h::_) -> getvarname ml_name h
|
|
Packit |
bd2e5d |
| OptionalArgs (s,_,_) -> s
|
|
Packit |
bd2e5d |
| ListArg [] -> ""
|
|
Packit |
bd2e5d |
end)
|
|
Packit |
bd2e5d |
in
|
|
Packit |
bd2e5d |
let varname = if head = "" then ml_name
|
|
Packit |
bd2e5d |
else if head.[0] >= 'A' && head.[0] <= 'Z' then head
|
|
Packit |
bd2e5d |
else ml_name
|
|
Packit |
bd2e5d |
in varname
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(***** Some utilities on the various tables *****)
|
|
Packit |
bd2e5d |
(* Enter a new empty type *)
|
|
Packit |
bd2e5d |
let new_type typname arity =
|
|
Packit |
bd2e5d |
Tsort.add_element types_order typname;
|
|
Packit |
bd2e5d |
let typdef = {parser_arity = arity;
|
|
Packit |
bd2e5d |
constructors = [];
|
|
Packit |
bd2e5d |
subtypes = [];
|
|
Packit |
bd2e5d |
requires_widget_context = false;
|
|
Packit |
bd2e5d |
variant = false} in
|
|
Packit |
bd2e5d |
Hashtbl.add types_table typname typdef;
|
|
Packit |
bd2e5d |
typdef
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Assume that types not yet defined are not subtyped *)
|
|
Packit |
bd2e5d |
(* Widget is builtin and implicitly subtyped *)
|
|
Packit |
bd2e5d |
let is_subtyped s =
|
|
Packit |
bd2e5d |
s = "widget" ||
|
|
Packit |
bd2e5d |
try
|
|
Packit |
bd2e5d |
let typdef = Hashtbl.find types_table s in
|
|
Packit |
bd2e5d |
typdef.subtypes <> []
|
|
Packit |
bd2e5d |
with
|
|
Packit |
bd2e5d |
Not_found -> false
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let requires_widget_context s =
|
|
Packit |
bd2e5d |
try
|
|
Packit |
bd2e5d |
(Hashtbl.find types_table s).requires_widget_context
|
|
Packit |
bd2e5d |
with
|
|
Packit |
bd2e5d |
Not_found -> false
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let declared_type_parser_arity s =
|
|
Packit |
bd2e5d |
try
|
|
Packit |
bd2e5d |
(Hashtbl.find types_table s).parser_arity
|
|
Packit |
bd2e5d |
with
|
|
Packit |
bd2e5d |
Not_found ->
|
|
Packit |
bd2e5d |
try List.assoc s !types_external
|
|
Packit |
bd2e5d |
with
|
|
Packit |
bd2e5d |
Not_found ->
|
|
Packit |
bd2e5d |
prerr_string "Type "; prerr_string s;
|
|
Packit |
bd2e5d |
prerr_string " is undeclared external or undefined\n";
|
|
Packit |
bd2e5d |
prerr_string ("Assuming cTKtoCAML"^s^" : string -> "^s^"\n");
|
|
Packit |
bd2e5d |
OneToken
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let rec type_parser_arity = function
|
|
Packit |
bd2e5d |
Unit -> OneToken
|
|
Packit |
bd2e5d |
| Int -> OneToken
|
|
Packit |
bd2e5d |
| Float -> OneToken
|
|
Packit |
bd2e5d |
| Bool -> OneToken
|
|
Packit |
bd2e5d |
| Char -> OneToken
|
|
Packit |
bd2e5d |
| String -> OneToken
|
|
Packit |
bd2e5d |
| List _ -> MultipleToken
|
|
Packit |
bd2e5d |
| Product _ -> MultipleToken
|
|
Packit |
bd2e5d |
| Record _ -> MultipleToken
|
|
Packit |
bd2e5d |
| UserDefined s -> declared_type_parser_arity s
|
|
Packit |
bd2e5d |
| Subtype (s,_) -> declared_type_parser_arity s
|
|
Packit |
bd2e5d |
| Function _ -> OneToken
|
|
Packit |
bd2e5d |
| As (ty, _) -> type_parser_arity ty
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let enter_external_type s v =
|
|
Packit |
bd2e5d |
types_external := (s,v)::!types_external
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(*** Stuff for topological Sort.list of types ***)
|
|
Packit |
bd2e5d |
(* Make sure all types used in commands and functions are in *)
|
|
Packit |
bd2e5d |
(* the table *)
|
|
Packit |
bd2e5d |
let rec enter_argtype = function
|
|
Packit |
bd2e5d |
Unit | Int | Float | Bool | Char | String -> ()
|
|
Packit |
bd2e5d |
| List ty -> enter_argtype ty
|
|
Packit |
bd2e5d |
| Product tyl -> List.iter ~f:enter_argtype tyl
|
|
Packit |
bd2e5d |
| Record tyl -> List.iter tyl ~f:(fun (l,t) -> enter_argtype t)
|
|
Packit |
bd2e5d |
| UserDefined s -> Tsort.add_element types_order s
|
|
Packit |
bd2e5d |
| Subtype (s,_) -> Tsort.add_element types_order s
|
|
Packit |
bd2e5d |
| Function ty -> enter_argtype ty
|
|
Packit |
bd2e5d |
| As (ty, _) -> enter_argtype ty
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let rec enter_template_types = function
|
|
Packit |
bd2e5d |
StringArg _ -> ()
|
|
Packit |
bd2e5d |
| TypeArg (l,t) -> enter_argtype t
|
|
Packit |
bd2e5d |
| ListArg l -> List.iter ~f:enter_template_types l
|
|
Packit |
bd2e5d |
| OptionalArgs (_,tl,_) -> List.iter ~f:enter_template_types tl
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Find type dependancies on s *)
|
|
Packit |
bd2e5d |
let rec add_dependancies s =
|
|
Packit |
bd2e5d |
function
|
|
Packit |
bd2e5d |
List ty -> add_dependancies s ty
|
|
Packit |
bd2e5d |
| Product tyl -> List.iter ~f:(add_dependancies s) tyl
|
|
Packit |
bd2e5d |
| Subtype(s',_) -> if s <> s' then Tsort.add_relation types_order (s', s)
|
|
Packit |
bd2e5d |
| UserDefined s' -> if s <> s' then Tsort.add_relation types_order (s', s)
|
|
Packit |
bd2e5d |
| Function ty -> add_dependancies s ty
|
|
Packit |
bd2e5d |
| As (ty, _) -> add_dependancies s ty
|
|
Packit |
bd2e5d |
| _ -> ()
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let rec add_template_dependancies s = function
|
|
Packit |
bd2e5d |
StringArg _ -> ()
|
|
Packit |
bd2e5d |
| TypeArg (l,t) -> add_dependancies s t
|
|
Packit |
bd2e5d |
| ListArg l -> List.iter ~f:(add_template_dependancies s) l
|
|
Packit |
bd2e5d |
| OptionalArgs (_,tl,_) -> List.iter ~f:(add_template_dependancies s) tl
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Assumes functions are not nested in products, which is reasonable due to syntax*)
|
|
Packit |
bd2e5d |
let rec has_callback = function
|
|
Packit |
bd2e5d |
StringArg _ -> false
|
|
Packit |
bd2e5d |
| TypeArg (l,Function _ ) -> true
|
|
Packit |
bd2e5d |
| TypeArg _ -> false
|
|
Packit |
bd2e5d |
| ListArg l -> List.exists ~f:has_callback l
|
|
Packit |
bd2e5d |
| OptionalArgs (_,tl,_) -> List.exists ~f:has_callback tl
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(*** Returned types ***)
|
|
Packit |
bd2e5d |
let really_add ty =
|
|
Packit |
bd2e5d |
if List.mem ty !types_returned then ()
|
|
Packit |
bd2e5d |
else types_returned := ty :: !types_returned
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let rec add_return_type = function
|
|
Packit |
bd2e5d |
Unit -> ()
|
|
Packit |
bd2e5d |
| Int -> ()
|
|
Packit |
bd2e5d |
| Float -> ()
|
|
Packit |
bd2e5d |
| Bool -> ()
|
|
Packit |
bd2e5d |
| Char -> ()
|
|
Packit |
bd2e5d |
| String -> ()
|
|
Packit |
bd2e5d |
| List ty -> add_return_type ty
|
|
Packit |
bd2e5d |
| Product tyl -> List.iter ~f:add_return_type tyl
|
|
Packit |
bd2e5d |
| Record tyl -> List.iter tyl ~f:(fun (l,t) -> add_return_type t)
|
|
Packit |
bd2e5d |
| UserDefined s -> really_add s
|
|
Packit |
bd2e5d |
| Subtype (s,_) -> really_add s
|
|
Packit |
bd2e5d |
| Function _ -> fatal_error "unexpected return type (function)" (* whoah *)
|
|
Packit |
bd2e5d |
| As (ty, _) -> add_return_type ty
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(*** Update tables for a component ***)
|
|
Packit |
bd2e5d |
let enter_component_types {template = t; result = r} =
|
|
Packit |
bd2e5d |
add_return_type r;
|
|
Packit |
bd2e5d |
enter_argtype r;
|
|
Packit |
bd2e5d |
enter_template_types t
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(******************** Types and subtypes ********************)
|
|
Packit |
bd2e5d |
exception Duplicate_Definition of string * string
|
|
Packit |
bd2e5d |
exception Invalid_implicit_constructor of string
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Checking duplicate definition of constructor in subtypes *)
|
|
Packit |
bd2e5d |
let rec check_duplicate_constr allowed c =
|
|
Packit |
bd2e5d |
function
|
|
Packit |
bd2e5d |
[] -> false (* not defined *)
|
|
Packit |
bd2e5d |
| c'::rest ->
|
|
Packit |
bd2e5d |
if c.ml_name = c'.ml_name then (* defined *)
|
|
Packit |
bd2e5d |
if allowed then
|
|
Packit |
bd2e5d |
if c.template = c'.template then true (* same arg *)
|
|
Packit |
bd2e5d |
else raise (Duplicate_Definition ("constructor",c.ml_name))
|
|
Packit |
bd2e5d |
else raise (Duplicate_Definition ("constructor", c.ml_name))
|
|
Packit |
bd2e5d |
else check_duplicate_constr allowed c rest
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Retrieve constructor *)
|
|
Packit |
bd2e5d |
let rec find_constructor cname = function
|
|
Packit |
bd2e5d |
[] -> raise (Invalid_implicit_constructor cname)
|
|
Packit |
bd2e5d |
| c::l -> if c.ml_name = cname then c
|
|
Packit |
bd2e5d |
else find_constructor cname l
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Enter a type, must not be previously defined *)
|
|
Packit |
bd2e5d |
let enter_type typname ?(variant = false) arity constructors =
|
|
Packit |
bd2e5d |
if Hashtbl.mem types_table typname then
|
|
Packit |
bd2e5d |
raise (Duplicate_Definition ("type", typname)) else
|
|
Packit |
bd2e5d |
let typdef = new_type typname arity in
|
|
Packit |
bd2e5d |
if variant then typdef.variant <- true;
|
|
Packit |
bd2e5d |
List.iter constructors ~f:
|
|
Packit |
bd2e5d |
begin fun c ->
|
|
Packit |
bd2e5d |
if not (check_duplicate_constr false c typdef.constructors)
|
|
Packit |
bd2e5d |
then begin
|
|
Packit |
bd2e5d |
typdef.constructors <- c :: typdef.constructors;
|
|
Packit |
bd2e5d |
add_template_dependancies typname c.template
|
|
Packit |
bd2e5d |
end;
|
|
Packit |
bd2e5d |
(* Callbacks require widget context *)
|
|
Packit |
bd2e5d |
typdef.requires_widget_context <-
|
|
Packit |
bd2e5d |
typdef.requires_widget_context ||
|
|
Packit |
bd2e5d |
has_callback c.template
|
|
Packit |
bd2e5d |
end
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Enter a subtype *)
|
|
Packit |
bd2e5d |
let enter_subtype typ arity subtyp constructors =
|
|
Packit |
bd2e5d |
(* Retrieve the type if already defined, else add a new one *)
|
|
Packit |
bd2e5d |
let typdef =
|
|
Packit |
bd2e5d |
try Hashtbl.find types_table typ
|
|
Packit |
bd2e5d |
with Not_found -> new_type typ arity
|
|
Packit |
bd2e5d |
in
|
|
Packit |
bd2e5d |
if List.mem_assoc subtyp typdef.subtypes
|
|
Packit |
bd2e5d |
then raise (Duplicate_Definition ("subtype", typ ^" "^subtyp))
|
|
Packit |
bd2e5d |
else begin
|
|
Packit |
bd2e5d |
let real_constructors =
|
|
Packit |
bd2e5d |
List.map constructors ~f:
|
|
Packit |
bd2e5d |
begin function
|
|
Packit |
bd2e5d |
Full c ->
|
|
Packit |
bd2e5d |
if not (check_duplicate_constr true c typdef.constructors)
|
|
Packit |
bd2e5d |
then begin
|
|
Packit |
bd2e5d |
add_template_dependancies typ c.template;
|
|
Packit |
bd2e5d |
typdef.constructors <- c :: typdef.constructors
|
|
Packit |
bd2e5d |
end;
|
|
Packit |
bd2e5d |
typdef.requires_widget_context <-
|
|
Packit |
bd2e5d |
typdef.requires_widget_context ||
|
|
Packit |
bd2e5d |
has_callback c.template;
|
|
Packit |
bd2e5d |
c
|
|
Packit |
bd2e5d |
| Abbrev name -> find_constructor name typdef.constructors
|
|
Packit |
bd2e5d |
end
|
|
Packit |
bd2e5d |
in
|
|
Packit |
bd2e5d |
(* TODO: duplicate def in subtype are not checked *)
|
|
Packit |
bd2e5d |
typdef.subtypes <-
|
|
Packit |
bd2e5d |
(subtyp , List.sort real_constructors
|
|
Packit |
bd2e5d |
~cmp:(fun c1 c2 -> compare c1.var_name c2.var_name)) ::
|
|
Packit |
bd2e5d |
typdef.subtypes
|
|
Packit |
bd2e5d |
end
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(******************** Widgets ********************)
|
|
Packit |
bd2e5d |
(* used by the parser; when enter_widget is called,
|
|
Packit |
bd2e5d |
all components are assumed to be in Full form *)
|
|
Packit |
bd2e5d |
let retrieve_option optname =
|
|
Packit |
bd2e5d |
let optiontyp =
|
|
Packit |
bd2e5d |
try Hashtbl.find types_table "options"
|
|
Packit |
bd2e5d |
with
|
|
Packit |
bd2e5d |
Not_found -> raise (Invalid_implicit_constructor optname)
|
|
Packit |
bd2e5d |
in find_constructor optname optiontyp.constructors
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Sort components by type *)
|
|
Packit |
bd2e5d |
let rec add_sort l obj =
|
|
Packit |
bd2e5d |
match l with
|
|
Packit |
bd2e5d |
[] -> [obj.component ,[obj]]
|
|
Packit |
bd2e5d |
| (s',l)::rest ->
|
|
Packit |
bd2e5d |
if obj.component = s' then
|
|
Packit |
bd2e5d |
(s',obj::l)::rest
|
|
Packit |
bd2e5d |
else
|
|
Packit |
bd2e5d |
(s',l)::(add_sort rest obj)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let separate_components = List.fold_left ~f:add_sort ~init:[]
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let enter_widget name components =
|
|
Packit |
bd2e5d |
if Hashtbl.mem module_table name then
|
|
Packit |
bd2e5d |
raise (Duplicate_Definition ("widget/module", name)) else
|
|
Packit |
bd2e5d |
let sorted_components = separate_components components in
|
|
Packit |
bd2e5d |
List.iter sorted_components ~f:
|
|
Packit |
bd2e5d |
begin function
|
|
Packit |
bd2e5d |
Constructor, l ->
|
|
Packit |
bd2e5d |
enter_subtype "options" MultipleToken
|
|
Packit |
bd2e5d |
name (List.map ~f:(fun c -> Full c) l)
|
|
Packit |
bd2e5d |
| Command, l ->
|
|
Packit |
bd2e5d |
List.iter ~f:enter_component_types l
|
|
Packit |
bd2e5d |
| External, _ -> ()
|
|
Packit |
bd2e5d |
end;
|
|
Packit |
bd2e5d |
let commands =
|
|
Packit |
bd2e5d |
try List.assoc Command sorted_components
|
|
Packit |
bd2e5d |
with Not_found -> []
|
|
Packit |
bd2e5d |
and externals =
|
|
Packit |
bd2e5d |
try List.assoc External sorted_components
|
|
Packit |
bd2e5d |
with Not_found -> []
|
|
Packit |
bd2e5d |
in
|
|
Packit |
bd2e5d |
Hashtbl.add module_table name
|
|
Packit |
bd2e5d |
{module_type = Widget; commands = commands; externals = externals}
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(******************** Functions ********************)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let enter_function comp =
|
|
Packit |
bd2e5d |
enter_component_types comp;
|
|
Packit |
bd2e5d |
function_table := comp :: !function_table
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(******************** Modules ********************)
|
|
Packit |
bd2e5d |
let enter_module name components =
|
|
Packit |
bd2e5d |
if Hashtbl.mem module_table name then
|
|
Packit |
bd2e5d |
raise (Duplicate_Definition ("widget/module", name)) else
|
|
Packit |
bd2e5d |
let sorted_components = separate_components components in
|
|
Packit |
bd2e5d |
List.iter sorted_components ~f:
|
|
Packit |
bd2e5d |
begin function
|
|
Packit |
bd2e5d |
Constructor, l -> fatal_error "unexpected Constructor"
|
|
Packit |
bd2e5d |
| Command, l -> List.iter ~f:enter_component_types l
|
|
Packit |
bd2e5d |
| External, _ -> ()
|
|
Packit |
bd2e5d |
end;
|
|
Packit |
bd2e5d |
let commands =
|
|
Packit |
bd2e5d |
try List.assoc Command sorted_components
|
|
Packit |
bd2e5d |
with Not_found -> []
|
|
Packit |
bd2e5d |
and externals =
|
|
Packit |
bd2e5d |
try List.assoc External sorted_components
|
|
Packit |
bd2e5d |
with Not_found -> []
|
|
Packit |
bd2e5d |
in
|
|
Packit |
bd2e5d |
Hashtbl.add module_table name
|
|
Packit |
bd2e5d |
{module_type = Family; commands = commands; externals = externals}
|