Partial move to new generator.
[panamaz] / src / code.pm
1 package code;
2
3 use strict;
4
5 use File::Path qw(make_path);
6 use File::Basename;
7 use Data::Dumper;
8 use List::Util qw(first);
9
10 require genapi;
11
12 my %typeSizes = (
13         i8 => 'byte', u8 => 'byte',
14         i16 => 'short', u16 => 'short',
15         i32 => 'int', u32 => 'int',
16         i64 => 'long', u64 => 'long',
17         f32 => 'float',
18         f64 => 'double',
19 );
20
21 my %typeSuffix = (
22         'long' => 'L',
23         'float' => 'f'
24 );
25
26 my %defineType = (
27         %typeSizes,
28         string => 'String'
29 );
30
31 my %typePrefix = (
32         i8 => '(byte)',
33         u8 => '(byte)',
34         i16 => '(short)',
35         u16 => '(short)',
36         string => '"'
37 );
38
39 my %typeSuffix = (
40         u64 => 'L',
41         i64 => 'L',
42         f32 => 'f',
43         string => '"'
44 );
45
46 my %typeSignature = (
47         'byte' => 'B',
48         'short' => 'S',
49         'int' => 'I',
50         'long' => 'J',
51         'float' => 'F',
52         'double' => 'D',
53         'void' => 'V',
54         'MemorySegment' => 'Ljdk/incubator/foreign/MemorySegment;',
55         'MemoryAddress' => 'Ljdk/incubator/foreign/MemoryAddress;',
56 );
57
58 # creates per-field type info, used by methods and structs
59 # the names are bit naff here
60 sub scanFields {
61         my $api = shift;
62         my $s = shift;
63         my $data = $api->{data};
64
65         my @members = ();
66         foreach my $m (defined($s->{result}) ? $s->{result} : (), @{$s->{items}}) {
67                 my $info = $api->findType($m);
68                 my $type = $info->{type};
69                 my $match = $info->{match};
70                 my $typeSizes = $code::typeSizes;
71
72                 foreach my $k (keys %{$type->{items}}) {
73                         my $f = $type->{items}->{$k};
74
75                         if (defined $f) {
76                                 my $e = eval $f;
77                                 if (!defined $e) {
78                                         print "$typeSizes{$match->{ctype}}\n";
79
80                                         print "$s->{name} field=$m->{name} deref=$m->{deref} regex=$type->{regex} $k=\n$f\n";
81                                         print "match=".Dumper($match);
82                                         print "error: $! $@\n";
83                                         die;
84                                 } else {
85                                         #print "$m->{name} $type->{regex} $k = $f = $e\n";
86                                 }
87                                 $match->{$k} = $e;
88                         }
89                 }
90
91                 # hmm this should probably be in loop above, but there's clashes with things like {type}
92                 foreach my $o (grep { defined $m->{$_} } 'tonative') {
93                         $match->{$o} = findCode($api, $m->{$o});
94                 }
95
96                 $match->{name} = $m->{name};
97                 $match->{rename} = $m->{rename};
98                 $match->{segment} = 'segment()';
99                 $match->{scope} = 'scope()';
100
101                 push @members, { field=>$m, type=>$type, match=>$match };
102         }
103         @members;
104 }
105
106 sub findCode {
107         my $api = shift;
108         my $v = shift;
109
110         if ($v =~ m/^(code:.+)=(.*)$/) {
111                 my $t = $api->{index}->{$1};
112                 my $l = genapi::findItem($t, $2);
113
114                 die "Uknown template '$1.$2'" if !defined($t) || !defined($l);
115                 $l->{literal};
116         } else {
117                 $v;
118         }
119 }
120
121 sub formatFunctionDescriptor {
122         my $api = shift;
123         my $members = shift;
124         my $d;
125
126         if ($members->[0]->{field}->{deref} eq 'void') {
127                 shift @$members;
128                 $d = "FunctionDescriptor.ofVoid(";
129         } else {
130                 $d = "FunctionDescriptor.of(";
131         }
132
133         $d .= join(', ', map { formatTemplate($_->{match}->{layout}, $_->{match}) } @$members);
134         $d .= ')';
135
136         return $d;
137 }
138
139 sub formatFunctionSignature {
140         my $api = shift;
141         my $members = shift;
142         my $result = shift @$members;
143
144         return '('.join('', map { $typeSignature{$_->{match}->{carrier}} } @$members).')'
145                 .$typeSignature{$result->{match}->{carrier}};
146 }
147
148 sub formatStructLayout {
149         my $api = shift;
150         my $s = shift;
151         my $members = shift;
152         my $count = 0;
153         my $lastOffset = 0;
154         my $maxSize = 8;
155         my $layout;
156
157         $layout = "\tpublic static final GroupLayout LAYOUT = MemoryLayout.$s->{type}Layout(\n\t\t";
158
159         foreach my $i (@$members) {
160                 my $m = $i->{field};
161                 my $type = $i->{type};
162                 my $match = $i->{match};
163
164                 $maxSize = bitfieldSize($m) if (bitfieldSize($m) > $maxSize);
165
166                 if ($match->{layout}) {
167                         if ($m->{offset} > $lastOffset) {
168                                 $layout .= ",\n\t\t" if $count++;
169                                 $layout .= 'MemoryLayout.paddingLayout('.($m->{offset} - $lastOffset).')';
170                         }
171                         $layout .= ",\n\t\t" if $count++;
172                         $layout .= formatTemplate($match->{layout}, $match).".withName(\"$m->{name}\")";
173                         $lastOffset = $m->{offset} + $m->{size};
174                 }
175         }
176         if ($s->{size} > $lastOffset) {
177                 $layout .= ",\n\t\t" if ($count++ > 0);
178                 $layout .= 'MemoryLayout.paddingLayout('.($s->{size} - $lastOffset).')';
179         }
180
181         $layout .= "\n\t).withBitAlignment($maxSize);\n";
182         $layout;
183 }
184
185 sub formatDefine {
186         my $api = shift;
187         my $s = shift;
188
189         my $d = join "\n\t", map {
190                 my $type = $_->{type};
191                 my $name = $_->{name};
192                 my $value = $_->{value};
193
194                 "public static final $defineType{$type} $name = $typePrefix{$type}$value$typeSuffix{$type};";
195         } @{$s->{items}};
196
197         return "\t$d\n";
198 }
199
200 sub formatEnum {
201         my $api = shift;
202         my $s = shift;
203         my $type = $defineType{$s->{value_type}};
204
205         my $d = join "\n\t", "// enum $s->{name}", map {
206                 my $name = $_->{name};
207                 my $value = $_->{value};
208
209                 "public static final $type $name = $typePrefix{$type}$value$typeSuffix{$type};";
210         } @{$s->{items}};
211
212         return "\t$d\n";
213 }
214
215 sub formatTemplate {
216         my $template = shift;
217         my $vars = shift;
218         my $prefix = shift;
219         my $result;
220
221         #print "apply-template vars=".Dumper($vars);
222
223         while ($template =~ m/^(.*?)\{([\w-]+)\}(.*)$/s) {
224                 $result .= $1;
225
226                 #print "  $2 -> $vars->{$2}\n";
227
228                 if (defined $vars->{$2}) {
229                         $template = $vars->{$2}.$3;
230                 } else {
231                         $result .= "{$2}";
232                         $template = $3;
233                 }
234         }
235         $result .= $template;
236         $result =~ s/^/$prefix/gm;
237         $result;
238 }
239
240 # takes a template entry applies options and then formats it
241 # applyTemplate(template-item, vars)
242 sub applyTemplate {
243         my $code = shift;
244         my $match = shift;
245         my $vars = \%{$match};
246
247         foreach my $set (genapi::optionValuesAll('set', $code)) {
248                 $vars->{$1} = $2 if ($set =~ m/^(\w+)=(.*)/);
249         }
250
251         formatTemplate($code->{literal}, $vars);
252 }
253
254 sub bitfieldSize {
255         my $m = shift;
256         my $size = $m->{size};
257
258         return 64 if ($size > 32);
259         return 32 if ($size > 16);
260         return 16 if ($size > 8);
261         return 8;
262 }
263
264 sub bitfieldType {
265         my $m = shift;
266         my $size = $m->{size};
267         return 'long' if ($size > 32);
268         return 'int' if ($size > 16);
269         return 'short' if ($size > 8);
270         return 'byte';
271 }
272
273 sub bitfieldIndex {
274         use integer;
275         my $m = shift;
276
277         $m->{offset} / bitfieldSize($m);
278 }
279
280 sub bitfieldOffset {
281         use integer;
282         my $m = shift;
283
284         $m->{offset} & (bitfieldSize($m) - 1);
285 }
286
287 sub bitfieldMask {
288         use integer;
289         my $m = shift;
290
291         sprintf("0x%x", ((1 << $m->{size}) - 1) << bitfieldOffset($m)).$typeSuffix{bitfieldType($m)};
292 }
293
294 1;