Remove EJS tests.
[amitay/samba.git] / pidl / lib / Parse / Pidl / Typelist.pm
1 ###################################################
2 # Samba4 parser generator for IDL structures
3 # Copyright jelmer@samba.org 2005
4 # released under the GNU GPL
5
6 package Parse::Pidl::Typelist;
7
8 require Exporter;
9 @ISA = qw(Exporter);
10 @EXPORT_OK = qw(hasType getType resolveType mapTypeName scalar_is_reference expandAlias
11                             mapScalarType addType typeIs is_scalar enum_type_fn
12                                 bitmap_type_fn mapType typeHasBody
13 );
14 use vars qw($VERSION);
15 $VERSION = '0.01';
16
17 use Parse::Pidl::Util qw(has_property);
18 use strict;
19
20 my %types = ();
21
22 my @reference_scalars = (
23         "string", "string_array", "nbt_string", 
24         "wrepl_nbt_name", "ipv4address"
25 );
26
27 # a list of known scalar types
28 my %scalars = (
29         "void"          => "void",
30         "char"          => "char",
31         "int8"          => "int8_t",
32         "uint8"         => "uint8_t",
33         "int16"         => "int16_t",
34         "uint16"        => "uint16_t",
35         "int32"         => "int32_t",
36         "uint32"        => "uint32_t",
37         "hyper"         => "uint64_t",
38         "dlong"         => "int64_t",
39         "udlong"        => "uint64_t",
40         "udlongr"       => "uint64_t",
41         "pointer"       => "void*",
42         "DATA_BLOB"     => "DATA_BLOB",
43         "string"        => "const char *",
44         "string_array"  => "const char **",
45         "time_t"        => "time_t",
46         "NTTIME"        => "NTTIME",
47         "NTTIME_1sec"   => "NTTIME",
48         "NTTIME_hyper"  => "NTTIME",
49         "WERROR"        => "WERROR",
50         "NTSTATUS"      => "NTSTATUS",
51         "COMRESULT" => "COMRESULT",
52         "nbt_string"    => "const char *",
53         "wrepl_nbt_name"=> "struct nbt_name *",
54         "ipv4address"   => "const char *",
55 );
56
57 my %aliases = (
58         "error_status_t" => "uint32",
59         "boolean8" => "uint8",
60         "boolean32" => "uint32",
61         "DWORD" => "uint32",
62         "uint" => "uint32",
63         "int" => "int32",
64         "WORD" => "uint16",
65         "char" => "uint8",
66         "long" => "int32",
67         "short" => "int16",
68         "HYPER_T" => "hyper",
69         "HRESULT" => "COMRESULT",
70 );
71
72 sub expandAlias($)
73 {
74         my $name = shift;
75
76         return $aliases{$name} if defined($aliases{$name});
77
78         return $name;
79 }
80
81 # map from a IDL type to a C header type
82 sub mapScalarType($)
83 {
84         my $name = shift;
85
86         # it's a bug when a type is not in the list
87         # of known scalars or has no mapping
88         return $scalars{$name} if defined($scalars{$name});
89
90         die("Unknown scalar type $name");
91 }
92
93 sub addType($)
94 {
95         my $t = shift;
96         $types{$t->{NAME}} = $t;
97 }
98
99 sub resolveType($)
100 {
101         my ($ctype) = @_;
102
103         if (not hasType($ctype)) {
104                 # assume struct typedef
105                 return { TYPE => "TYPEDEF", NAME => $ctype, DATA => { TYPE => "STRUCT" } };
106         } else {
107                 return getType($ctype);
108         }
109
110         return $ctype;
111 }
112
113 sub getType($)
114 {
115         my $t = shift;
116         return ($t) if (ref($t) eq "HASH" and not defined($t->{NAME}));
117         return undef if not hasType($t);
118         return $types{$t->{NAME}} if (ref($t) eq "HASH");
119         return $types{$t};
120 }
121
122 sub typeIs($$)
123 {
124         my ($t,$tt) = @_;
125         
126         if (ref($t) eq "HASH") {
127                 return 1 if ($t->{TYPE} eq $tt);
128                 return 0;
129         }
130         return 1 if (hasType($t) and getType($t)->{TYPE} eq "TYPEDEF" and 
131                          getType($t)->{DATA}->{TYPE} eq $tt);
132         return 0;
133 }
134
135 sub hasType($)
136 {
137         my $t = shift;
138         if (ref($t) eq "HASH") {
139                 return 1 if (not defined($t->{NAME}));
140                 return 1 if (defined($types{$t->{NAME}}) and 
141                         $types{$t->{NAME}}->{TYPE} eq $t->{TYPE});
142                 return 0;
143         }
144         return 1 if defined($types{$t});
145         return 0;
146 }
147
148 sub is_scalar($)
149 {
150         sub is_scalar($);
151         my $type = shift;
152
153         return 1 if (ref($type) eq "HASH" and 
154                 ($type->{TYPE} eq "SCALAR" or $type->{TYPE} eq "ENUM" or 
155                  $type->{TYPE} eq "BITMAP"));
156
157         if (my $dt = getType($type)) {
158                 return is_scalar($dt->{DATA}) if ($dt->{TYPE} eq "TYPEDEF");
159                 return 1 if ($dt->{TYPE} eq "SCALAR" or $dt->{TYPE} eq "ENUM" or 
160                                  $dt->{TYPE} eq "BITMAP");
161         }
162
163         return 0;
164 }
165
166 sub scalar_is_reference($)
167 {
168         my $name = shift;
169
170         return 1 if (grep(/^$name$/, @reference_scalars));
171         return 0;
172 }
173
174 sub RegisterScalars()
175 {
176         foreach (keys %scalars) {
177                 addType({
178                         NAME => $_,
179                         TYPE => "TYPEDEF",
180                         DATA => {
181                                 TYPE => "SCALAR",
182                                 NAME => $_
183                         }
184                 }
185                 );
186         }
187 }
188
189 sub enum_type_fn($)
190 {
191         my $enum = shift;
192         $enum->{TYPE} eq "ENUM" or die("not an enum");
193
194         # for typedef enum { } we need to check $enum->{PARENT}
195         if (has_property($enum, "enum8bit")) {
196                 return "uint8";
197         } elsif (has_property($enum, "enum16bit")) {
198                 return "uint16";
199         } elsif (has_property($enum, "v1_enum")) {
200                 return "uint32";
201         } elsif (has_property($enum->{PARENT}, "enum8bit")) {
202                 return "uint8";
203         } elsif (has_property($enum->{PARENT}, "enum16bit")) {
204                 return "uint16";
205         } elsif (has_property($enum->{PARENT}, "v1_enum")) {
206                 return "uint32";
207         }
208         return "uint16";
209 }
210
211 sub bitmap_type_fn($)
212 {
213         my $bitmap = shift;
214
215         $bitmap->{TYPE} eq "BITMAP" or die("not a bitmap");
216
217         if (has_property($bitmap, "bitmap8bit")) {
218                 return "uint8";
219         } elsif (has_property($bitmap, "bitmap16bit")) {
220                 return "uint16";
221         } elsif (has_property($bitmap, "bitmap64bit")) {
222                 return "hyper";
223         }
224         return "uint32";
225 }
226
227 sub typeHasBody($)
228 {
229         sub typeHasBody($);
230         my ($e) = @_;
231
232         if ($e->{TYPE} eq "TYPEDEF") {
233                 return 0 unless(defined($e->{DATA}));
234                 return typeHasBody($e->{DATA});
235         }
236
237         return defined($e->{ELEMENTS});
238 }
239
240 sub mapType($$)
241 {
242         sub mapType($$);
243         my ($t, $n) = @_;
244
245         return mapType($t->{DATA}, $n) if ($t->{TYPE} eq "TYPEDEF");
246         return mapScalarType($n) if ($t->{TYPE} eq "SCALAR");
247         return "enum $n" if ($t->{TYPE} eq "ENUM");
248         return "struct $n" if ($t->{TYPE} eq "STRUCT" or $t->{TYPE} eq "INTERFACE");
249         return "union $n" if ($t->{TYPE} eq "UNION");
250         return mapScalarType(bitmap_type_fn($t)) if ($t->{TYPE} eq "BITMAP");
251         die("Unknown type $t->{TYPE}");
252 }
253
254 sub mapTypeName($)
255 {
256         my $t = shift;
257         return "void" unless defined($t);
258         my $dt;
259         $t = expandAlias($t);
260
261         unless ($dt or ($dt = getType($t))) {
262                 # Best guess
263                 return "struct $t";
264         }
265
266         return mapType($dt, $dt->{NAME});
267 }
268
269 sub LoadIdl($)
270 {
271         my ($idl) = @_;
272
273         foreach my $x (@{$idl}) {
274                 next if $x->{TYPE} ne "INTERFACE";
275
276                 # DCOM interfaces can be types as well
277                 addType({
278                         NAME => $x->{NAME},
279                         TYPE => "TYPEDEF",
280                         DATA => $x
281                         }) if (has_property($x, "object"));
282
283                 foreach my $y (@{$x->{DATA}}) {
284                         addType($y) if (
285                                 $y->{TYPE} eq "TYPEDEF" 
286                                  or $y->{TYPE} eq "UNION"
287                                  or $y->{TYPE} eq "STRUCT"
288                          or $y->{TYPE} eq "ENUM"
289                          or $y->{TYPE} eq "BITMAP");
290                 }
291         }
292 }
293
294 sub GenerateTypeLib()
295 {
296         return Parse::Pidl::Util::MyDumper(\%types);
297 }
298
299 RegisterScalars();
300
301 1;