File: normalize.ml

package info (click to toggle)
camlidl 1.12-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 1,592 kB
  • sloc: ml: 5,238; ansic: 945; cpp: 908; makefile: 358; xml: 213; sh: 74
file content (281 lines) | stat: -rw-r--r-- 9,202 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
(***********************************************************************)
(*                                                                     *)
(*                              CamlIDL                                *)
(*                                                                     *)
(*            Xavier Leroy, projet Cristal, INRIA Rocquencourt         *)
(*                                                                     *)
(*  Copyright 1999 Institut National de Recherche en Informatique et   *)
(*  en Automatique.  All rights reserved.  This file is distributed    *)
(*  under the terms of the GNU Lesser General Public License LGPL v2.1 *)
(*                                                                     *)
(***********************************************************************)

(* $Id: normalize.ml,v 1.22 2002-01-16 16:15:32 xleroy Exp $ *)

(* Normalization of IDL types after parsing *)

open Printf
open Utils
open Idltypes
open Typedef
open Funct
open Constdecl
open Intf
open File

let structs = (Hashtbl.create 13 : (string, struct_decl) Hashtbl.t)
let unions =  (Hashtbl.create 13 : (string, union_decl) Hashtbl.t)
let enums =   (Hashtbl.create 13 : (string, enum_decl) Hashtbl.t)
let intfs =   (Hashtbl.create 13 : (string, interface) Hashtbl.t)
let typedefs =(Hashtbl.create 13 : (string, type_decl) Hashtbl.t)

let find_typedef s =
  try
    Hashtbl.find typedefs s
  with Not_found ->
    error("unknown type name " ^ s)

let expand_typedef s = (find_typedef s).td_type

let _ =
  Typedef.find := find_typedef;
  Lexpr.expand_typedef := expand_typedef

let all_comps = ref ([] : component list)

let currstamp = ref 0

let newstamp () = incr currstamp; !currstamp

let in_fundecl = ref false

let error_if_fundecl kind =
  if !in_fundecl then
    error (sprintf "anonymous %s in function parameters or result type" kind)

let make_module_name filename =
  Filename.chop_extension (Filename.basename filename)

type char_class = Narrow | Wide

let rec classify_char = function
    Type_int((Char | UChar | Byte), _) -> Some Narrow
  | Type_int(UShort, _) -> Some Wide
  | Type_named(modname, tyname) -> classify_char (expand_typedef tyname)
  | Type_const ty -> classify_char ty
  | _ -> None

(* Generic function to handle declarations and definitions of struct,
   unions, enums and interfaces *)

let process_declarator kind tbl name sourcedecl 
                       proj_contents make_decl update_decl record_decl =
  if name = "" then begin
    (* Unnamed definition *)
    if !in_fundecl then
     error (sprintf "anonymous %s in function parameters or result type" kind);
    let newdecl = make_decl() in
    update_decl newdecl sourcedecl;
    record_decl newdecl;
    newdecl
  end else if proj_contents sourcedecl = [] then begin
    (* Reference to previous definition, or forward declaration *)
    try
      Hashtbl.find tbl name
    with Not_found ->
      let newdecl = make_decl() in
      Hashtbl.add tbl name newdecl;
      record_decl (make_decl()); (* record with contents still empty *)
      newdecl
  end else begin
    (* Named definition *)
    let decl =
      try
        Hashtbl.find tbl name
      with Not_found ->
        let newdecl = make_decl() in
        Hashtbl.add tbl name newdecl;
        newdecl in
    (* Check we're not redefining *)
    if proj_contents decl <> [] then
      error (sprintf "redefinition of %s %s" kind name);
    (* Process the components *)
    update_decl decl sourcedecl;
    (* Record the full declaration *)
    record_decl decl;
    decl
  end

(* Normalize types and declarators *)

let rec normalize_type = function
    Type_pointer(kind, ty_elt) ->
      Type_pointer(kind, normalize_type ty_elt)
  | Type_array(attr, ty_elt) -> begin
      let norm_ty_elt = normalize_type ty_elt in
      if not attr.is_string then Type_array(attr, norm_ty_elt) else
      match classify_char norm_ty_elt with
      | None -> error "[string] argument applies only to \
                       char array or pointer to char"
      | Some Narrow -> Type_array(attr, norm_ty_elt)
      | Some Wide ->
        let attr' = {attr with is_string = false; null_terminated = true} in
        Type_array(attr', norm_ty_elt)
    end
  | Type_struct sd ->
      Type_struct(enter_struct sd)
  | Type_union(ud, discr) ->
      Type_union(enter_union ud, discr)
  | Type_enum (en, attr) ->
      Type_enum(enter_enum en, attr)
  | Type_named(_, s) ->
      begin try
        let itf = Hashtbl.find intfs s in
        Type_interface(itf.intf_mod, itf.intf_name)
      with Not_found ->
      try
        let td = Hashtbl.find typedefs s in
        Type_named(td.td_mod, td.td_name)
      with Not_found ->
        error("Unknown type name " ^ s)
      end
  | Type_const ty ->
      Type_const(normalize_type ty)
  | ty -> ty

and normalize_field f =
  {f with field_typ = normalize_type f.field_typ}

and normalize_case c =
  match c.case_field with
    None -> c
  | Some f -> {c with case_field = Some(normalize_field f)}

and enter_struct sd =
  process_declarator "struct" structs sd.sd_name sd
    (fun sd -> sd.sd_fields)
    (fun () ->
      { sd_name = sd.sd_name; sd_mod = !module_name;
        sd_stamp = 0; sd_fields = [] })
    (fun sd' sd ->
      sd'.sd_stamp <- newstamp();
      sd'.sd_fields <- List.map normalize_field sd.sd_fields)
    (fun sd ->
      all_comps := Comp_structdecl sd :: !all_comps)

and enter_union ud =
  process_declarator "union" unions ud.ud_name ud
    (fun ud -> ud.ud_cases)
    (fun () ->
      { ud_name = ud.ud_name; ud_mod = !module_name;
        ud_stamp = 0; ud_cases = [] })
    (fun ud' ud ->
      ud'.ud_stamp <- newstamp();
      ud'.ud_cases <- List.map normalize_case ud.ud_cases)
    (fun ud ->
      all_comps := Comp_uniondecl ud :: !all_comps)

and enter_enum en =
  process_declarator "enum" enums en.en_name en
    (fun en -> en.en_consts)
    (fun () ->
      { en_name = en.en_name; en_mod = !module_name;
        en_stamp = 0; en_consts = [] })
    (fun en' en ->
      en'.en_stamp <- newstamp();
      en'.en_consts <- en.en_consts)
    (fun en ->
      all_comps := Comp_enumdecl en :: !all_comps)

let normalize_fundecl fd =
  current_function := fd.fun_name;
  in_fundecl := true;
  let res =
    { fd with
      fun_mod = !module_name;
      fun_res = normalize_type fd.fun_res;
      fun_params =
        List.map (fun (n, io, ty) -> (n,io, normalize_type ty)) fd.fun_params }
  in
  in_fundecl := false;
  current_function := "";
  res

let normalize_constdecl cd =
  { cd with cd_type = normalize_type cd.cd_type }
  
let enter_typedecl td =
  let td' =
    { td with td_mod = !module_name;
              td_type = if td.td_abstract
                        then td.td_type
                        else normalize_type td.td_type } in
  all_comps := Comp_typedecl td' :: !all_comps;
  Hashtbl.add typedefs td'.td_name td'

let enter_interface i =
  process_declarator "interface" intfs i.intf_name i
    (fun i -> i.intf_methods)
    (fun () ->
      { intf_name = i.intf_name; intf_mod = !module_name;
        intf_super = i.intf_super; intf_methods = []; intf_uid = "" })
    (fun i' i ->
      let super =
        try
          Hashtbl.find intfs i.intf_super.intf_name
        with Not_found ->
          error (sprintf "unknown interface %s as super-interface of %s"
                         i.intf_super.intf_name i.intf_name) in
      i'.intf_uid <- i.intf_uid;
      i'.intf_super <- super;
      i'.intf_methods <- List.map normalize_fundecl i.intf_methods)
    (fun i ->
      all_comps := Comp_interface i :: !all_comps)

let rec normalize_component = function
    Comp_typedecl td -> enter_typedecl td
  | Comp_structdecl sd -> ignore(enter_struct sd)
  | Comp_uniondecl ud -> ignore(enter_union ud)
  | Comp_enumdecl en -> ignore(enter_enum en)
  | Comp_fundecl fd ->
      all_comps := Comp_fundecl(normalize_fundecl fd) :: !all_comps
  | Comp_constdecl cd ->
      all_comps := Comp_constdecl(normalize_constdecl cd) :: !all_comps
  | Comp_diversion(ty, s) ->
      all_comps := Comp_diversion(ty, s) :: !all_comps
  | Comp_interface intf -> ignore(enter_interface intf)
  | Comp_import(filename, comps) ->
      let name = make_module_name filename in
      let saved_name = !module_name in
      module_name := name;
      let comps' = normalize_components comps in
      module_name := saved_name;
      all_comps := Comp_import(name, comps') :: !all_comps

and normalize_components comps =
  let saved_all_comps = !all_comps in
  all_comps := [];
  List.iter normalize_component comps;
  let ac = List.rev !all_comps in
  all_comps := saved_all_comps;
  ac

(* Main entry point *)

let normalize_file filename =
  Hashtbl.clear structs;
  Hashtbl.clear unions;
  Hashtbl.clear enums;
  Hashtbl.clear intfs;
  Hashtbl.clear typedefs;
  List.iter (fun td -> Hashtbl.add typedefs td.td_name td) Predef.typedefs;
  List.iter (fun i -> Hashtbl.add intfs i.intf_name i) Predef.interfaces;
  module_name := make_module_name filename;
  let res =
    normalize_components (Fixlabels.prefix_file (Parse.read_file filename)) in
  Hashtbl.clear structs;
  Hashtbl.clear unions;
  Hashtbl.clear enums;
  Hashtbl.clear intfs;
  res