File Coverage

blib/lib/XS/JIT/Header/TypeMap.pm
Criterion Covered Total %
statement 47 52 90.3
branch 12 20 60.0
condition 3 6 50.0
subroutine 7 8 87.5
pod 6 6 100.0
total 75 92 81.5


line stmt bran cond sub pod time code
1             package XS::JIT::Header::TypeMap;
2              
3 4     4   76093 use strict;
  4         6  
  4         148  
4 4     4   14 use warnings;
  4         5  
  4         7001  
5              
6             our $VERSION = '0.17';
7              
8             # C type to Perl type mapping
9             # Each entry contains:
10             # perl - Perl type category (IV, UV, NV, PV, void)
11             # c - Canonical C type
12             # convert - Macro to convert SV to C value
13             # create - Macro to create SV from C value
14             # is_ptr - True if this is a pointer type
15              
16             our %C_TO_PERL = (
17             # Signed integer types
18             'char' => { perl => 'IV', c => 'char', convert => 'SvIV', create => 'newSViv' },
19             'signed char' => { perl => 'IV', c => 'signed char', convert => 'SvIV', create => 'newSViv' },
20             'short' => { perl => 'IV', c => 'short', convert => 'SvIV', create => 'newSViv' },
21             'short int' => { perl => 'IV', c => 'short', convert => 'SvIV', create => 'newSViv' },
22             'signed short' => { perl => 'IV', c => 'short', convert => 'SvIV', create => 'newSViv' },
23             'signed short int' => { perl => 'IV', c => 'short', convert => 'SvIV', create => 'newSViv' },
24             'int' => { perl => 'IV', c => 'int', convert => 'SvIV', create => 'newSViv' },
25             'signed' => { perl => 'IV', c => 'int', convert => 'SvIV', create => 'newSViv' },
26             'signed int' => { perl => 'IV', c => 'int', convert => 'SvIV', create => 'newSViv' },
27             'long' => { perl => 'IV', c => 'long', convert => 'SvIV', create => 'newSViv' },
28             'long int' => { perl => 'IV', c => 'long', convert => 'SvIV', create => 'newSViv' },
29             'signed long' => { perl => 'IV', c => 'long', convert => 'SvIV', create => 'newSViv' },
30             'signed long int' => { perl => 'IV', c => 'long', convert => 'SvIV', create => 'newSViv' },
31             'long long' => { perl => 'IV', c => 'long long', convert => 'SvIV', create => 'newSViv' },
32             'long long int' => { perl => 'IV', c => 'long long', convert => 'SvIV', create => 'newSViv' },
33             'signed long long' => { perl => 'IV', c => 'long long', convert => 'SvIV', create => 'newSViv' },
34              
35             # Unsigned integer types
36             'unsigned char' => { perl => 'UV', c => 'unsigned char', convert => 'SvUV', create => 'newSVuv' },
37             'unsigned short' => { perl => 'UV', c => 'unsigned short', convert => 'SvUV', create => 'newSVuv' },
38             'unsigned short int' => { perl => 'UV', c => 'unsigned short', convert => 'SvUV', create => 'newSVuv' },
39             'unsigned' => { perl => 'UV', c => 'unsigned int', convert => 'SvUV', create => 'newSVuv' },
40             'unsigned int' => { perl => 'UV', c => 'unsigned int', convert => 'SvUV', create => 'newSVuv' },
41             'unsigned long' => { perl => 'UV', c => 'unsigned long', convert => 'SvUV', create => 'newSVuv' },
42             'unsigned long int' => { perl => 'UV', c => 'unsigned long', convert => 'SvUV', create => 'newSVuv' },
43             'unsigned long long' => { perl => 'UV', c => 'unsigned long long', convert => 'SvUV', create => 'newSVuv' },
44              
45             # Fixed-width integers (C99 stdint.h)
46             'int8_t' => { perl => 'IV', c => 'int8_t', convert => 'SvIV', create => 'newSViv' },
47             'int16_t' => { perl => 'IV', c => 'int16_t', convert => 'SvIV', create => 'newSViv' },
48             'int32_t' => { perl => 'IV', c => 'int32_t', convert => 'SvIV', create => 'newSViv' },
49             'int64_t' => { perl => 'IV', c => 'int64_t', convert => 'SvIV', create => 'newSViv' },
50             'uint8_t' => { perl => 'UV', c => 'uint8_t', convert => 'SvUV', create => 'newSVuv' },
51             'uint16_t' => { perl => 'UV', c => 'uint16_t', convert => 'SvUV', create => 'newSVuv' },
52             'uint32_t' => { perl => 'UV', c => 'uint32_t', convert => 'SvUV', create => 'newSVuv' },
53             'uint64_t' => { perl => 'UV', c => 'uint64_t', convert => 'SvUV', create => 'newSVuv' },
54              
55             # Minimum-width integers (C99 stdint.h)
56             'int_least8_t' => { perl => 'IV', c => 'int_least8_t', convert => 'SvIV', create => 'newSViv' },
57             'int_least16_t' => { perl => 'IV', c => 'int_least16_t', convert => 'SvIV', create => 'newSViv' },
58             'int_least32_t' => { perl => 'IV', c => 'int_least32_t', convert => 'SvIV', create => 'newSViv' },
59             'int_least64_t' => { perl => 'IV', c => 'int_least64_t', convert => 'SvIV', create => 'newSViv' },
60             'uint_least8_t' => { perl => 'UV', c => 'uint_least8_t', convert => 'SvUV', create => 'newSVuv' },
61             'uint_least16_t' => { perl => 'UV', c => 'uint_least16_t', convert => 'SvUV', create => 'newSVuv' },
62             'uint_least32_t' => { perl => 'UV', c => 'uint_least32_t', convert => 'SvUV', create => 'newSVuv' },
63             'uint_least64_t' => { perl => 'UV', c => 'uint_least64_t', convert => 'SvUV', create => 'newSVuv' },
64              
65             # Fast minimum-width integers (C99 stdint.h)
66             'int_fast8_t' => { perl => 'IV', c => 'int_fast8_t', convert => 'SvIV', create => 'newSViv' },
67             'int_fast16_t' => { perl => 'IV', c => 'int_fast16_t', convert => 'SvIV', create => 'newSViv' },
68             'int_fast32_t' => { perl => 'IV', c => 'int_fast32_t', convert => 'SvIV', create => 'newSViv' },
69             'int_fast64_t' => { perl => 'IV', c => 'int_fast64_t', convert => 'SvIV', create => 'newSViv' },
70             'uint_fast8_t' => { perl => 'UV', c => 'uint_fast8_t', convert => 'SvUV', create => 'newSVuv' },
71             'uint_fast16_t' => { perl => 'UV', c => 'uint_fast16_t', convert => 'SvUV', create => 'newSVuv' },
72             'uint_fast32_t' => { perl => 'UV', c => 'uint_fast32_t', convert => 'SvUV', create => 'newSVuv' },
73             'uint_fast64_t' => { perl => 'UV', c => 'uint_fast64_t', convert => 'SvUV', create => 'newSVuv' },
74              
75             # Maximum-width integers (C99 stdint.h)
76             'intmax_t' => { perl => 'IV', c => 'intmax_t', convert => 'SvIV', create => 'newSViv' },
77             'uintmax_t' => { perl => 'UV', c => 'uintmax_t', convert => 'SvUV', create => 'newSVuv' },
78              
79             # Size types
80             'size_t' => { perl => 'UV', c => 'size_t', convert => 'SvUV', create => 'newSVuv' },
81             'ssize_t' => { perl => 'IV', c => 'ssize_t', convert => 'SvIV', create => 'newSViv' },
82             'ptrdiff_t' => { perl => 'IV', c => 'ptrdiff_t', convert => 'SvIV', create => 'newSViv' },
83             'intptr_t' => { perl => 'IV', c => 'intptr_t', convert => 'SvIV', create => 'newSViv' },
84             'uintptr_t' => { perl => 'UV', c => 'uintptr_t', convert => 'SvUV', create => 'newSVuv' },
85             'max_align_t' => { perl => 'UV', c => 'max_align_t', convert => 'SvUV', create => 'newSVuv' },
86              
87             # Wide character types (wchar.h)
88             'wchar_t' => { perl => 'IV', c => 'wchar_t', convert => 'SvIV', create => 'newSViv' },
89             'wint_t' => { perl => 'IV', c => 'wint_t', convert => 'SvIV', create => 'newSViv' },
90              
91             # Unicode character types (C11 uchar.h)
92             'char16_t' => { perl => 'UV', c => 'char16_t', convert => 'SvUV', create => 'newSVuv' },
93             'char32_t' => { perl => 'UV', c => 'char32_t', convert => 'SvUV', create => 'newSVuv' },
94              
95             # POSIX types
96             'off_t' => { perl => 'IV', c => 'off_t', convert => 'SvIV', create => 'newSViv' },
97             'pid_t' => { perl => 'IV', c => 'pid_t', convert => 'SvIV', create => 'newSViv' },
98             'uid_t' => { perl => 'UV', c => 'uid_t', convert => 'SvUV', create => 'newSVuv' },
99             'gid_t' => { perl => 'UV', c => 'gid_t', convert => 'SvUV', create => 'newSVuv' },
100             'mode_t' => { perl => 'UV', c => 'mode_t', convert => 'SvUV', create => 'newSVuv' },
101             'dev_t' => { perl => 'UV', c => 'dev_t', convert => 'SvUV', create => 'newSVuv' },
102             'ino_t' => { perl => 'UV', c => 'ino_t', convert => 'SvUV', create => 'newSVuv' },
103             'nlink_t' => { perl => 'UV', c => 'nlink_t', convert => 'SvUV', create => 'newSVuv' },
104             'blksize_t' => { perl => 'IV', c => 'blksize_t', convert => 'SvIV', create => 'newSViv' },
105             'blkcnt_t' => { perl => 'IV', c => 'blkcnt_t', convert => 'SvIV', create => 'newSViv' },
106              
107             # Time types
108             'time_t' => { perl => 'IV', c => 'time_t', convert => 'SvIV', create => 'newSViv' },
109             'clock_t' => { perl => 'IV', c => 'clock_t', convert => 'SvIV', create => 'newSViv' },
110             'suseconds_t' => { perl => 'IV', c => 'suseconds_t', convert => 'SvIV', create => 'newSViv' },
111              
112             # Floating point types
113             'float' => { perl => 'NV', c => 'float', convert => 'SvNV', create => 'newSVnv' },
114             'double' => { perl => 'NV', c => 'double', convert => 'SvNV', create => 'newSVnv' },
115             'long double' => { perl => 'NV', c => 'long double', convert => 'SvNV', create => 'newSVnv' },
116              
117             # String types
118             'char*' => { perl => 'PV', c => 'char*', convert => 'SvPV_nolen', create => 'newSVpv', is_string => 1 },
119             'char *' => { perl => 'PV', c => 'char*', convert => 'SvPV_nolen', create => 'newSVpv', is_string => 1 },
120             'const char*' => { perl => 'PV', c => 'const char*', convert => 'SvPV_nolen', create => 'newSVpv', is_string => 1 },
121             'const char *' => { perl => 'PV', c => 'const char*', convert => 'SvPV_nolen', create => 'newSVpv', is_string => 1 },
122              
123             # Void
124             'void' => { perl => 'void', c => 'void', convert => undef, create => undef },
125              
126             # Pointer types (opaque)
127             'void*' => { perl => 'UV', c => 'void*', convert => 'PTR2UV', create => 'newSVuv', is_ptr => 1 },
128             'void *' => { perl => 'UV', c => 'void*', convert => 'PTR2UV', create => 'newSVuv', is_ptr => 1 },
129              
130             # Boolean (C99)
131             '_Bool' => { perl => 'IV', c => '_Bool', convert => 'SvIV', create => 'newSViv' },
132             'bool' => { perl => 'IV', c => 'bool', convert => 'SvIV', create => 'newSViv' },
133              
134             # Perl internal types - pass-through (no conversion needed)
135             # These allow C code to work directly with Perl data structures
136             'SV*' => { perl => 'SV', c => 'SV*', convert => '', create => '', is_perl => 1 },
137             'SV *' => { perl => 'SV', c => 'SV*', convert => '', create => '', is_perl => 1 },
138             'HV*' => { perl => 'HV', c => 'HV*', convert => '(HV*)SvRV', create => 'newRV_noinc((SV*)', is_perl => 1, is_hash => 1 },
139             'HV *' => { perl => 'HV', c => 'HV*', convert => '(HV*)SvRV', create => 'newRV_noinc((SV*)', is_perl => 1, is_hash => 1 },
140             'AV*' => { perl => 'AV', c => 'AV*', convert => '(AV*)SvRV', create => 'newRV_noinc((SV*)', is_perl => 1, is_array => 1 },
141             'AV *' => { perl => 'AV', c => 'AV*', convert => '(AV*)SvRV', create => 'newRV_noinc((SV*)', is_perl => 1, is_array => 1 },
142             'CV*' => { perl => 'CV', c => 'CV*', convert => '(CV*)SvRV', create => 'newRV_noinc((SV*)', is_perl => 1, is_code => 1 },
143             'CV *' => { perl => 'CV', c => 'CV*', convert => '(CV*)SvRV', create => 'newRV_noinc((SV*)', is_perl => 1, is_code => 1 },
144              
145             # Complex types (C99) - stored as array refs of [real, imag]
146             'float _Complex' => { perl => 'NV', c => 'float _Complex', convert => 'SvNV', create => 'newSVnv', is_complex => 1 },
147             'double _Complex' => { perl => 'NV', c => 'double _Complex', convert => 'SvNV', create => 'newSVnv', is_complex => 1 },
148             'long double _Complex' => { perl => 'NV', c => 'long double _Complex', convert => 'SvNV', create => 'newSVnv', is_complex => 1 },
149             'float complex' => { perl => 'NV', c => 'float _Complex', convert => 'SvNV', create => 'newSVnv', is_complex => 1 },
150             'double complex' => { perl => 'NV', c => 'double _Complex', convert => 'SvNV', create => 'newSVnv', is_complex => 1 },
151             'long double complex' => { perl => 'NV', c => 'long double _Complex', convert => 'SvNV', create => 'newSVnv', is_complex => 1 },
152              
153             # Atomic types (C11) - treated as their base types
154             'atomic_bool' => { perl => 'IV', c => 'atomic_bool', convert => 'SvIV', create => 'newSViv' },
155             'atomic_char' => { perl => 'IV', c => 'atomic_char', convert => 'SvIV', create => 'newSViv' },
156             'atomic_schar' => { perl => 'IV', c => 'atomic_schar', convert => 'SvIV', create => 'newSViv' },
157             'atomic_uchar' => { perl => 'UV', c => 'atomic_uchar', convert => 'SvUV', create => 'newSVuv' },
158             'atomic_short' => { perl => 'IV', c => 'atomic_short', convert => 'SvIV', create => 'newSViv' },
159             'atomic_ushort' => { perl => 'UV', c => 'atomic_ushort', convert => 'SvUV', create => 'newSVuv' },
160             'atomic_int' => { perl => 'IV', c => 'atomic_int', convert => 'SvIV', create => 'newSViv' },
161             'atomic_uint' => { perl => 'UV', c => 'atomic_uint', convert => 'SvUV', create => 'newSVuv' },
162             'atomic_long' => { perl => 'IV', c => 'atomic_long', convert => 'SvIV', create => 'newSViv' },
163             'atomic_ulong' => { perl => 'UV', c => 'atomic_ulong', convert => 'SvUV', create => 'newSVuv' },
164             'atomic_llong' => { perl => 'IV', c => 'atomic_llong', convert => 'SvIV', create => 'newSViv' },
165             'atomic_ullong' => { perl => 'UV', c => 'atomic_ullong', convert => 'SvUV', create => 'newSVuv' },
166             'atomic_size_t' => { perl => 'UV', c => 'atomic_size_t', convert => 'SvUV', create => 'newSVuv' },
167             'atomic_ptrdiff_t' => { perl => 'IV', c => 'atomic_ptrdiff_t', convert => 'SvIV', create => 'newSViv' },
168             'atomic_intptr_t' => { perl => 'IV', c => 'atomic_intptr_t', convert => 'SvIV', create => 'newSViv' },
169             'atomic_uintptr_t' => { perl => 'UV', c => 'atomic_uintptr_t', convert => 'SvUV', create => 'newSVuv' },
170             'atomic_intmax_t' => { perl => 'IV', c => 'atomic_intmax_t', convert => 'SvIV', create => 'newSViv' },
171             'atomic_uintmax_t' => { perl => 'UV', c => 'atomic_uintmax_t', convert => 'SvUV', create => 'newSVuv' },
172              
173             # Windows types (commonly encountered)
174             'BOOL' => { perl => 'IV', c => 'BOOL', convert => 'SvIV', create => 'newSViv' },
175             'BYTE' => { perl => 'UV', c => 'BYTE', convert => 'SvUV', create => 'newSVuv' },
176             'WORD' => { perl => 'UV', c => 'WORD', convert => 'SvUV', create => 'newSVuv' },
177             'DWORD' => { perl => 'UV', c => 'DWORD', convert => 'SvUV', create => 'newSVuv' },
178             'QWORD' => { perl => 'UV', c => 'QWORD', convert => 'SvUV', create => 'newSVuv' },
179             'INT' => { perl => 'IV', c => 'INT', convert => 'SvIV', create => 'newSViv' },
180             'UINT' => { perl => 'UV', c => 'UINT', convert => 'SvUV', create => 'newSVuv' },
181             'LONG' => { perl => 'IV', c => 'LONG', convert => 'SvIV', create => 'newSViv' },
182             'ULONG' => { perl => 'UV', c => 'ULONG', convert => 'SvUV', create => 'newSVuv' },
183             'LONGLONG' => { perl => 'IV', c => 'LONGLONG', convert => 'SvIV', create => 'newSViv' },
184             'ULONGLONG' => { perl => 'UV', c => 'ULONGLONG', convert => 'SvUV', create => 'newSVuv' },
185             'HANDLE' => { perl => 'UV', c => 'HANDLE', convert => 'PTR2UV', create => 'newSVuv', is_ptr => 1 },
186             'LPVOID' => { perl => 'UV', c => 'LPVOID', convert => 'PTR2UV', create => 'newSVuv', is_ptr => 1 },
187             'LPCVOID' => { perl => 'UV', c => 'LPCVOID', convert => 'PTR2UV', create => 'newSVuv', is_ptr => 1 },
188             'LPSTR' => { perl => 'PV', c => 'LPSTR', convert => 'SvPV_nolen', create => 'newSVpv', is_string => 1 },
189             'LPCSTR' => { perl => 'PV', c => 'LPCSTR', convert => 'SvPV_nolen', create => 'newSVpv', is_string => 1 },
190             'LPWSTR' => { perl => 'PV', c => 'LPWSTR', convert => 'SvPV_nolen', create => 'newSVpv', is_string => 1 },
191             'LPCWSTR' => { perl => 'PV', c => 'LPCWSTR', convert => 'SvPV_nolen', create => 'newSVpv', is_string => 1 },
192             'SIZE_T' => { perl => 'UV', c => 'SIZE_T', convert => 'SvUV', create => 'newSVuv' },
193             'SSIZE_T' => { perl => 'IV', c => 'SSIZE_T', convert => 'SvIV', create => 'newSViv' },
194             );
195              
196             # Normalize type string: remove extra whitespace, normalize pointer syntax
197             sub normalize_type {
198 112     112 1 3119 my ($type) = @_;
199 112 50       238 return undef unless defined $type;
200              
201             # Remove leading/trailing whitespace
202 112         293 $type =~ s/^\s+//;
203 112         234 $type =~ s/\s+$//;
204              
205             # Normalize multiple spaces to single space
206 112         192 $type =~ s/\s+/ /g;
207              
208             # Normalize pointer spacing: "char *" -> "char*", "char * *" -> "char**"
209 112         195 $type =~ s/\s*\*\s*/*/g;
210              
211             # But keep space before first * if preceded by word: "char*" not "char *"
212             # Actually, normalize to "type*" format
213 112         287 $type =~ s/(\w)\s*\*/$1*/g;
214              
215 112         238 return $type;
216             }
217              
218             # Resolve a C type to its Perl mapping
219             # Returns hashref with: perl, c, convert, create, is_ptr, is_string
220             sub resolve {
221 91     91 1 353443 my ($type) = @_;
222              
223 91         152 $type = normalize_type($type);
224 91 50       141 return undef unless defined $type;
225              
226             # Direct match
227 91 100       203 if (exists $C_TO_PERL{$type}) {
228 85         127 return { %{$C_TO_PERL{$type}} };
  85         545  
229             }
230              
231             # Check with/without const
232 6         11 my $without_const = $type;
233 6         9 $without_const =~ s/\bconst\s*//g;
234 6         8 $without_const = normalize_type($without_const);
235              
236 6 50       17 if (exists $C_TO_PERL{$without_const}) {
237 0         0 my $info = { %{$C_TO_PERL{$without_const}} };
  0         0  
238 0         0 $info->{c} = $type; # Keep original type with const
239 0         0 return $info;
240             }
241              
242             # Handle pointers to known types
243 6 100       23 if ($type =~ /^(.+?)\*+$/) {
244 4         10 my $base = normalize_type($1);
245 4         11 my $ptr_count = ($type =~ tr/*/*/);
246              
247             # Single pointer to known type
248 4 50 66     19 if ($ptr_count == 1 && exists $C_TO_PERL{$base}) {
249             return {
250 3         18 perl => 'UV',
251             c => $type,
252             convert => 'PTR2UV',
253             create => 'newSVuv',
254             is_ptr => 1,
255             base => $base,
256             };
257             }
258              
259             # Multi-level pointer or pointer to unknown type
260             return {
261 1         13 perl => 'UV',
262             c => $type,
263             convert => 'PTR2UV',
264             create => 'newSVuv',
265             is_ptr => 1,
266             opaque => 1,
267             };
268             }
269              
270             # Unknown type - treat as opaque (likely a typedef or struct)
271             return {
272 2         14 perl => 'UV',
273             c => $type,
274             convert => 'PTR2UV',
275             create => 'newSVuv',
276             is_ptr => 1,
277             opaque => 1,
278             unknown => 1,
279             };
280             }
281              
282             # Check if a type is known
283             sub is_known {
284 4     4 1 3394 my ($type) = @_;
285 4         10 $type = normalize_type($type);
286 4         15 return exists $C_TO_PERL{$type};
287             }
288              
289             # Get all known types
290             sub known_types {
291 0     0 1 0 return keys %C_TO_PERL;
292             }
293              
294             # Register a custom type mapping
295             sub register {
296 1     1 1 2538 my ($type, %info) = @_;
297              
298 1 50       3 die "Type name required" unless defined $type;
299 1 50       2 die "Perl type required" unless defined $info{perl};
300 1 50       2 die "C type required" unless defined $info{c};
301              
302 1         3 $type = normalize_type($type);
303 1         2 $C_TO_PERL{$type} = \%info;
304              
305 1         3 return 1;
306             }
307              
308             # Register a type alias (maps to existing type)
309             sub alias {
310 1     1 1 3062 my ($new_type, $existing_type) = @_;
311              
312 1         3 my $info = resolve($existing_type);
313 1 50 33     7 die "Unknown type: $existing_type" unless $info && !$info->{unknown};
314              
315 1         6 $new_type = normalize_type($new_type);
316 1         6 $C_TO_PERL{$new_type} = { %$info, c => $new_type };
317              
318 1         4 return 1;
319             }
320              
321             1;
322              
323             __END__