use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BuiltinHeader {
Stddef,
Stdint,
Stdbool,
Stdarg,
Limits,
Float,
Iso646,
Stdatomic,
Stdalign,
Stdnoreturn,
Tgmath,
Unwind,
Cfloat,
}
impl BuiltinHeader {
pub fn filename(&self) -> &'static str {
match self {
Self::Stddef => "stddef.h",
Self::Stdint => "stdint.h",
Self::Stdbool => "stdbool.h",
Self::Stdarg => "stdarg.h",
Self::Limits => "limits.h",
Self::Float => "float.h",
Self::Iso646 => "iso646.h",
Self::Stdatomic => "stdatomic.h",
Self::Stdalign => "stdalign.h",
Self::Stdnoreturn => "stdnoreturn.h",
Self::Tgmath => "tgmath.h",
Self::Unwind => "unwind.h",
Self::Cfloat => "cfloat",
}
}
pub fn is_c89(&self) -> bool {
matches!(
self,
Self::Stddef | Self::Stdarg | Self::Limits | Self::Float
)
}
pub fn is_c99(&self) -> bool {
matches!(
self,
Self::Stddef
| Self::Stdint
| Self::Stdbool
| Self::Stdarg
| Self::Limits
| Self::Float
| Self::Iso646
| Self::Tgmath
)
}
pub fn is_c11(&self) -> bool {
matches!(
self,
Self::Stddef
| Self::Stdint
| Self::Stdbool
| Self::Stdarg
| Self::Limits
| Self::Float
| Self::Iso646
| Self::Stdatomic
| Self::Stdalign
| Self::Stdnoreturn
| Self::Tgmath
)
}
}
#[derive(Debug, Clone)]
pub struct BuiltinHeaderGenerator {
pub pointer_width: u32,
pub long_width: u32,
pub long_long_width: u32,
pub wchar_width: u32,
pub little_endian: bool,
pub int_width: u32,
pub short_width: u32,
pub char_width: u32,
pub char_is_signed: bool,
pub max_alignment: u32,
pub has_int128: bool,
}
impl BuiltinHeaderGenerator {
pub fn new_x86_64_linux() -> Self {
Self {
pointer_width: 64,
long_width: 64,
long_long_width: 64,
wchar_width: 32,
little_endian: true,
int_width: 32,
short_width: 16,
char_width: 8,
char_is_signed: true,
max_alignment: 16,
has_int128: true,
}
}
pub fn new_arm_linux() -> Self {
Self {
pointer_width: 32,
long_width: 32,
long_long_width: 64,
wchar_width: 32,
little_endian: true,
int_width: 32,
short_width: 16,
char_width: 8,
char_is_signed: false, max_alignment: 8,
has_int128: false,
}
}
pub fn new_aarch64_linux() -> Self {
Self {
pointer_width: 64,
long_width: 64,
long_long_width: 64,
wchar_width: 32,
little_endian: true,
int_width: 32,
short_width: 16,
char_width: 8,
char_is_signed: false,
max_alignment: 16,
has_int128: true,
}
}
pub fn new_x86_linux() -> Self {
Self {
pointer_width: 32,
long_width: 32,
long_long_width: 64,
wchar_width: 32,
little_endian: true,
int_width: 32,
short_width: 16,
char_width: 8,
char_is_signed: true,
max_alignment: 16,
has_int128: false,
}
}
pub fn generate(&self, header: BuiltinHeader) -> String {
match header {
BuiltinHeader::Stddef => self.generate_stddef(),
BuiltinHeader::Stdint => self.generate_stdint(),
BuiltinHeader::Stdbool => self.generate_stdbool(),
BuiltinHeader::Stdarg => self.generate_stdarg(),
BuiltinHeader::Limits => self.generate_limits(),
BuiltinHeader::Float => self.generate_float(),
BuiltinHeader::Iso646 => self.generate_iso646(),
BuiltinHeader::Stdatomic => self.generate_stdatomic(),
BuiltinHeader::Stdalign => self.generate_stdalign(),
BuiltinHeader::Stdnoreturn => self.generate_stdnoreturn(),
BuiltinHeader::Tgmath => self.generate_tgmath(),
BuiltinHeader::Unwind => self.generate_unwind(),
BuiltinHeader::Cfloat => self.generate_float(), }
}
pub fn generate_all(&self) -> HashMap<String, String> {
let mut map = HashMap::new();
let all = [
BuiltinHeader::Stddef,
BuiltinHeader::Stdint,
BuiltinHeader::Stdbool,
BuiltinHeader::Stdarg,
BuiltinHeader::Limits,
BuiltinHeader::Float,
BuiltinHeader::Iso646,
BuiltinHeader::Stdatomic,
BuiltinHeader::Stdalign,
BuiltinHeader::Stdnoreturn,
BuiltinHeader::Tgmath,
];
for h in &all {
map.insert(h.filename().to_string(), self.generate(*h));
}
map
}
fn generate_stddef(&self) -> String {
let mut s = String::new();
s.push_str("#ifndef __STDDEF_H\n");
s.push_str("#define __STDDEF_H\n\n");
s.push_str("#if defined(__need_size_t) || defined(__need_ptrdiff_t) \\\n");
s.push_str(" || defined(__need_wchar_t) || defined(__need_NULL) \\\n");
s.push_str(" || defined(__need_max_align_t) || !defined(__STDDEF_H)\n");
s.push_str("#define __STDDEF_H\n\n");
s.push_str("#if !defined(__size_t_defined)\n");
s.push_str("#define __size_t_defined\n");
if self.pointer_width == 64 {
s.push_str("typedef unsigned long size_t;\n");
} else {
s.push_str("typedef unsigned int size_t;\n");
}
s.push_str("#endif\n\n");
s.push_str("#if !defined(__ptrdiff_t_defined)\n");
s.push_str("#define __ptrdiff_t_defined\n");
if self.pointer_width == 64 {
s.push_str("typedef long ptrdiff_t;\n");
} else {
s.push_str("typedef int ptrdiff_t;\n");
}
s.push_str("#endif\n\n");
s.push_str("#if !defined(NULL)\n");
s.push_str("#if defined(__cplusplus)\n");
s.push_str("#if __cplusplus >= 201103L\n");
s.push_str("#define NULL nullptr\n");
s.push_str("#else\n");
s.push_str("#define NULL 0\n");
s.push_str("#endif\n");
s.push_str("#else\n");
s.push_str("#define NULL ((void*)0)\n");
s.push_str("#endif\n");
s.push_str("#endif\n\n");
s.push_str("#if !defined(offsetof)\n");
s.push_str("#define offsetof(type, member) ");
s.push_str("__builtin_offsetof(type, member)\n");
s.push_str("#endif\n\n");
s.push_str("#if !defined(__max_align_t_defined)\n");
s.push_str("#define __max_align_t_defined\n");
s.push_str("typedef struct {\n");
if self.max_alignment >= 16 {
s.push_str(" long long __max_align_ll __attribute__((__aligned__(__alignof__(long long))));\n");
s.push_str(" long double __max_align_ld __attribute__((__aligned__(__alignof__(long double))));\n");
} else if self.max_alignment >= 8 {
s.push_str(" long long __max_align_ll __attribute__((__aligned__(__alignof__(long long))));\n");
s.push_str(
" double __max_align_d __attribute__((__aligned__(__alignof__(double))));\n",
);
} else {
s.push_str(" long __max_align_l __attribute__((__aligned__(__alignof__(long))));\n");
s.push_str(
" double __max_align_d __attribute__((__aligned__(__alignof__(double))));\n",
);
}
s.push_str("} max_align_t;\n");
s.push_str("#endif\n\n");
s.push_str("#if !defined(__wchar_t_defined)\n");
s.push_str("#define __wchar_t_defined\n");
if self.wchar_width == 16 {
s.push_str("#ifndef __cplusplus\n");
s.push_str("typedef unsigned short wchar_t;\n");
s.push_str("#endif\n");
} else {
s.push_str("#ifndef __cplusplus\n");
s.push_str("typedef int wchar_t;\n");
s.push_str("#endif\n");
}
s.push_str("#endif\n\n");
s.push_str("#if !defined(__nullptr_t_defined)\n");
s.push_str("#define __nullptr_t_defined\n");
s.push_str("#if defined(__cplusplus) && __cplusplus >= 201103L\n");
s.push_str("typedef decltype(nullptr) nullptr_t;\n");
s.push_str("#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L\n");
s.push_str("typedef typeof(nullptr) nullptr_t;\n");
s.push_str("#endif\n");
s.push_str("#endif\n\n");
s.push_str("#if !defined(unreachable)\n");
s.push_str("#define unreachable() __builtin_unreachable()\n");
s.push_str("#endif\n\n");
s.push_str("#endif /* __STDDEF_H */\n");
s
}
fn generate_stdint(&self) -> String {
let mut s = String::new();
s.push_str("#ifndef __STDINT_H\n");
s.push_str("#define __STDINT_H\n\n");
s.push_str("#ifndef __INT_WIDTH_STANDARD\n");
s.push_str("#define __INT_WIDTH_STANDARD\n");
s.push_str("#define __INT8_WIDTH__ 8\n");
s.push_str("#define __INT16_WIDTH__ 16\n");
s.push_str("#define __INT32_WIDTH__ 32\n");
s.push_str("#define __INT64_WIDTH__ 64\n");
s.push_str("#endif\n\n");
s.push_str("/* Exact-width integer types */\n");
s.push_str("typedef signed char int8_t;\n");
s.push_str("typedef short int16_t;\n");
s.push_str("typedef int int32_t;\n");
if self.has_int128 {
s.push_str("typedef long int64_t;\n");
s.push_str("#ifdef __SIZEOF_INT128__\n");
s.push_str("typedef __int128 int128_t;\n");
s.push_str("#endif\n");
} else {
s.push_str("typedef long long int64_t;\n");
}
s.push_str("\n");
s.push_str("typedef unsigned char uint8_t;\n");
s.push_str("typedef unsigned short uint16_t;\n");
s.push_str("typedef unsigned int uint32_t;\n");
if self.has_int128 {
s.push_str("typedef unsigned long uint64_t;\n");
s.push_str("#ifdef __SIZEOF_INT128__\n");
s.push_str("typedef unsigned __int128 uint128_t;\n");
s.push_str("#endif\n");
} else {
s.push_str("typedef unsigned long long uint64_t;\n");
}
s.push_str("\n");
s.push_str("/* Minimum-width integer types */\n");
s.push_str("typedef signed char int_least8_t;\n");
s.push_str("typedef short int_least16_t;\n");
s.push_str("typedef int int_least32_t;\n");
if self.long_width >= 64 {
s.push_str("typedef long int_least64_t;\n");
} else {
s.push_str("typedef long long int_least64_t;\n");
}
s.push_str("\n");
s.push_str("typedef unsigned char uint_least8_t;\n");
s.push_str("typedef unsigned short uint_least16_t;\n");
s.push_str("typedef unsigned int uint_least32_t;\n");
if self.long_width >= 64 {
s.push_str("typedef unsigned long uint_least64_t;\n");
} else {
s.push_str("typedef unsigned long long uint_least64_t;\n");
}
s.push_str("\n");
s.push_str("/* Fastest minimum-width integer types */\n");
s.push_str("typedef signed char int_fast8_t;\n");
s.push_str("typedef int int_fast16_t;\n");
s.push_str("typedef int int_fast32_t;\n");
if self.pointer_width == 64 {
s.push_str("typedef long int_fast64_t;\n");
} else {
s.push_str("typedef long long int_fast64_t;\n");
}
s.push_str("\n");
s.push_str("typedef unsigned char uint_fast8_t;\n");
s.push_str("typedef unsigned int uint_fast16_t;\n");
s.push_str("typedef unsigned int uint_fast32_t;\n");
if self.pointer_width == 64 {
s.push_str("typedef unsigned long uint_fast64_t;\n");
} else {
s.push_str("typedef unsigned long long uint_fast64_t;\n");
}
s.push_str("\n");
s.push_str("/* Integer types capable of holding object pointers */\n");
if self.pointer_width == 64 {
s.push_str("typedef long intptr_t;\n");
s.push_str("typedef unsigned long uintptr_t;\n");
} else {
s.push_str("typedef int intptr_t;\n");
s.push_str("typedef unsigned int uintptr_t;\n");
}
s.push_str("\n");
s.push_str("/* Greatest-width integer types */\n");
if self.has_int128 {
s.push_str("#ifdef __SIZEOF_INT128__\n");
s.push_str("typedef __int128 intmax_t;\n");
s.push_str("typedef unsigned __int128 uintmax_t;\n");
s.push_str("#else\n");
s.push_str("typedef long long intmax_t;\n");
s.push_str("typedef unsigned long long uintmax_t;\n");
s.push_str("#endif\n");
} else {
s.push_str("typedef long long intmax_t;\n");
s.push_str("typedef unsigned long long uintmax_t;\n");
}
s.push_str("\n");
s.push_str("/* Limits of exact-width integer types */\n");
s.push_str("#define INT8_MIN (-128)\n");
s.push_str("#define INT8_MAX (127)\n");
s.push_str("#define UINT8_MAX (255)\n\n");
s.push_str("#define INT16_MIN (-32768)\n");
s.push_str("#define INT16_MAX (32767)\n");
s.push_str("#define UINT16_MAX (65535)\n\n");
s.push_str("#define INT32_MIN (-2147483647 - 1)\n");
s.push_str("#define INT32_MAX (2147483647)\n");
s.push_str("#define UINT32_MAX (4294967295U)\n\n");
if self.long_width >= 64 {
s.push_str("#define INT64_MIN (-9223372036854775807L - 1L)\n");
s.push_str("#define INT64_MAX (9223372036854775807L)\n");
s.push_str("#define UINT64_MAX (18446744073709551615UL)\n\n");
} else {
s.push_str("#define INT64_MIN (-9223372036854775807LL - 1LL)\n");
s.push_str("#define INT64_MAX (9223372036854775807LL)\n");
s.push_str("#define UINT64_MAX (18446744073709551615ULL)\n\n");
}
s.push_str("/* Limits of minimum-width integer types */\n");
s.push_str("#define INT_LEAST8_MIN INT8_MIN\n");
s.push_str("#define INT_LEAST8_MAX INT8_MAX\n");
s.push_str("#define UINT_LEAST8_MAX UINT8_MAX\n\n");
s.push_str("#define INT_LEAST16_MIN INT16_MIN\n");
s.push_str("#define INT_LEAST16_MAX INT16_MAX\n");
s.push_str("#define UINT_LEAST16_MAX UINT16_MAX\n\n");
s.push_str("#define INT_LEAST32_MIN INT32_MIN\n");
s.push_str("#define INT_LEAST32_MAX INT32_MAX\n");
s.push_str("#define UINT_LEAST32_MAX UINT32_MAX\n\n");
s.push_str("#define INT_LEAST64_MIN INT64_MIN\n");
s.push_str("#define INT_LEAST64_MAX INT64_MAX\n");
s.push_str("#define UINT_LEAST64_MAX UINT64_MAX\n\n");
s.push_str("/* Limits of fastest minimum-width integer types */\n");
s.push_str("#define INT_FAST8_MIN INT8_MIN\n");
s.push_str("#define INT_FAST8_MAX INT8_MAX\n");
s.push_str("#define UINT_FAST8_MAX UINT8_MAX\n\n");
s.push_str("#define INT_FAST16_MIN INT32_MIN\n");
s.push_str("#define INT_FAST16_MAX INT32_MAX\n");
s.push_str("#define UINT_FAST16_MAX UINT32_MAX\n\n");
s.push_str("#define INT_FAST32_MIN INT32_MIN\n");
s.push_str("#define INT_FAST32_MAX INT32_MAX\n");
s.push_str("#define UINT_FAST32_MAX UINT32_MAX\n\n");
s.push_str("#define INT_FAST64_MIN INT64_MIN\n");
s.push_str("#define INT_FAST64_MAX INT64_MAX\n");
s.push_str("#define UINT_FAST64_MAX UINT64_MAX\n\n");
s.push_str("/* Limits of pointer-sized integer types */\n");
if self.pointer_width == 64 {
s.push_str("#define INTPTR_MIN INT64_MIN\n");
s.push_str("#define INTPTR_MAX INT64_MAX\n");
s.push_str("#define UINTPTR_MAX UINT64_MAX\n\n");
} else {
s.push_str("#define INTPTR_MIN INT32_MIN\n");
s.push_str("#define INTPTR_MAX INT32_MAX\n");
s.push_str("#define UINTPTR_MAX UINT32_MAX\n\n");
}
s.push_str("/* Limits of greatest-width integer types */\n");
s.push_str("#define INTMAX_MIN INT64_MIN\n");
s.push_str("#define INTMAX_MAX INT64_MAX\n");
s.push_str("#define UINTMAX_MAX UINT64_MAX\n\n");
s.push_str("/* Limits of other integer types */\n");
if self.pointer_width == 64 {
s.push_str("#define PTRDIFF_MIN INT64_MIN\n");
s.push_str("#define PTRDIFF_MAX INT64_MAX\n\n");
s.push_str("#define SIZE_MAX UINT64_MAX\n\n");
} else {
s.push_str("#define PTRDIFF_MIN INT32_MIN\n");
s.push_str("#define PTRDIFF_MAX INT32_MAX\n\n");
s.push_str("#define SIZE_MAX UINT32_MAX\n\n");
}
if self.wchar_width == 16 {
if self.char_is_signed {
s.push_str("#define WCHAR_MIN (-32767 - 1)\n");
s.push_str("#define WCHAR_MAX (32767)\n\n");
} else {
s.push_str("#define WCHAR_MIN (0)\n");
s.push_str("#define WCHAR_MAX (65535)\n\n");
}
} else {
if self.char_is_signed {
s.push_str("#define WCHAR_MIN (-2147483647 - 1)\n");
s.push_str("#define WCHAR_MAX (2147483647)\n\n");
} else {
s.push_str("#define WCHAR_MIN (0)\n");
s.push_str("#define WCHAR_MAX (4294967295U)\n\n");
}
}
s.push_str("#define WINT_MIN INT32_MIN\n");
s.push_str("#define WINT_MAX INT32_MAX\n\n");
s.push_str("#define SIG_ATOMIC_MIN INT32_MIN\n");
s.push_str("#define SIG_ATOMIC_MAX INT32_MAX\n\n");
s.push_str("/* Macros for integer constant expressions */\n");
s.push_str("#define INT8_C(c) c\n");
s.push_str("#define INT16_C(c) c\n");
s.push_str("#define INT32_C(c) c\n");
if self.long_width >= 64 {
s.push_str("#define INT64_C(c) c ## L\n");
} else {
s.push_str("#define INT64_C(c) c ## LL\n");
}
s.push_str("#define INTMAX_C(c) c ## LL\n\n");
s.push_str("#define UINT8_C(c) c\n");
s.push_str("#define UINT16_C(c) c\n");
s.push_str("#define UINT32_C(c) c ## U\n");
if self.long_width >= 64 {
s.push_str("#define UINT64_C(c) c ## UL\n");
} else {
s.push_str("#define UINT64_C(c) c ## ULL\n");
}
s.push_str("#define UINTMAX_C(c) c ## ULL\n\n");
s.push_str("#endif /* __STDINT_H */\n");
s
}
fn generate_stdbool(&self) -> String {
let mut s = String::new();
s.push_str("#ifndef __STDBOOL_H\n");
s.push_str("#define __STDBOOL_H\n\n");
s.push_str("#ifndef __cplusplus\n\n");
s.push_str("#define bool _Bool\n");
s.push_str("#define true 1\n");
s.push_str("#define false 0\n\n");
s.push_str("#else /* __cplusplus */\n\n");
s.push_str("/* In C++, bool/true/false are keywords */\n");
s.push_str("#define __bool_true_false_are_defined 1\n\n");
s.push_str("#endif /* __cplusplus */\n\n");
s.push_str("#define __bool_true_false_are_defined 1\n\n");
s.push_str("#endif /* __STDBOOL_H */\n");
s
}
fn generate_stdarg(&self) -> String {
let mut s = String::new();
s.push_str("#ifndef __STDARG_H\n");
s.push_str("#define __STDARG_H\n\n");
s.push_str("/* va_list is provided by the compiler */\n");
s.push_str("typedef __builtin_va_list va_list;\n\n");
s.push_str("#define va_start(ap, param) ");
s.push_str("__builtin_va_start(ap, param)\n\n");
s.push_str("#define va_arg(ap, type) ");
s.push_str("__builtin_va_arg(ap, type)\n\n");
s.push_str("#define va_end(ap) ");
s.push_str("__builtin_va_end(ap)\n\n");
s.push_str("#define va_copy(dest, src) ");
s.push_str("__builtin_va_copy(dest, src)\n\n");
s.push_str("/* Legacy synonym */\n");
s.push_str("#ifndef __va_copy\n");
s.push_str("#define __va_copy(dest, src) ");
s.push_str("__builtin_va_copy(dest, src)\n");
s.push_str("#endif\n\n");
s.push_str("#endif /* __STDARG_H */\n");
s
}
fn generate_limits(&self) -> String {
let mut s = String::new();
s.push_str("#ifndef __LIMITS_H\n");
s.push_str("#define __LIMITS_H\n\n");
s.push_str("/* Number of bits in a character */\n");
s.push_str("#define CHAR_BIT 8\n\n");
s.push_str("/* Minimum and maximum values a 'signed char' can hold */\n");
s.push_str("#define SCHAR_MIN (-128)\n");
s.push_str("#define SCHAR_MAX 127\n\n");
s.push_str("/* Maximum value an 'unsigned char' can hold */\n");
s.push_str("#define UCHAR_MAX 255\n\n");
s.push_str("/* Minimum and maximum values a 'char' can hold */\n");
if self.char_is_signed {
s.push_str("#define CHAR_MIN SCHAR_MIN\n");
s.push_str("#define CHAR_MAX SCHAR_MAX\n\n");
} else {
s.push_str("#define CHAR_MIN 0\n");
s.push_str("#define CHAR_MAX UCHAR_MAX\n\n");
}
s.push_str("/* Minimum and maximum values a 'short int' can hold */\n");
if self.short_width == 16 {
s.push_str("#define SHRT_MIN (-32768)\n");
s.push_str("#define SHRT_MAX 32767\n\n");
} else {
s.push_str("#define SHRT_MIN (-32767 - 1)\n");
s.push_str("#define SHRT_MAX 32767\n\n");
}
s.push_str("/* Maximum value an 'unsigned short int' can hold */\n");
if self.short_width == 16 {
s.push_str("#define USHRT_MAX 65535\n\n");
} else {
s.push_str("#define USHRT_MAX 4294967295\n\n");
}
s.push_str("/* Minimum and maximum values an 'int' can hold */\n");
if self.int_width == 32 {
s.push_str("#define INT_MIN (-2147483647 - 1)\n");
s.push_str("#define INT_MAX 2147483647\n\n");
} else if self.int_width == 16 {
s.push_str("#define INT_MIN (-32768)\n");
s.push_str("#define INT_MAX 32767\n\n");
} else {
s.push_str("#define INT_MIN (-32767 - 1)\n");
s.push_str("#define INT_MAX 32767\n\n");
}
s.push_str("/* Maximum value an 'unsigned int' can hold */\n");
if self.int_width == 32 {
s.push_str("#define UINT_MAX 4294967295U\n\n");
} else {
s.push_str("#define UINT_MAX 65535U\n\n");
}
s.push_str("/* Minimum and maximum values a 'long int' can hold */\n");
if self.long_width == 64 {
s.push_str("#define LONG_MIN (-9223372036854775807L - 1L)\n");
s.push_str("#define LONG_MAX 9223372036854775807L\n\n");
} else {
s.push_str("#define LONG_MIN (-2147483647L - 1L)\n");
s.push_str("#define LONG_MAX 2147483647L\n\n");
}
s.push_str("/* Maximum value an 'unsigned long int' can hold */\n");
if self.long_width == 64 {
s.push_str("#define ULONG_MAX 18446744073709551615UL\n\n");
} else {
s.push_str("#define ULONG_MAX 4294967295UL\n\n");
}
s.push_str("/* Minimum and maximum values a 'long long int' can hold */\n");
s.push_str("#define LLONG_MIN (-9223372036854775807LL - 1LL)\n");
s.push_str("#define LLONG_MAX 9223372036854775807LL\n\n");
s.push_str("/* Maximum value an 'unsigned long long int' can hold */\n");
s.push_str("#define ULLONG_MAX 18446744073709551615ULL\n\n");
s.push_str("#ifndef MB_LEN_MAX\n");
s.push_str("#define MB_LEN_MAX 16\n");
s.push_str("#endif\n\n");
s.push_str("/* POSIX extensions */\n");
if self.pointer_width == 64 {
s.push_str("#define SSIZE_MAX LONG_MAX\n\n");
} else {
s.push_str("#define SSIZE_MAX INT_MAX\n\n");
}
s.push_str("#endif /* __LIMITS_H */\n");
s
}
fn generate_float(&self) -> String {
let mut s = String::new();
s.push_str("#ifndef __FLOAT_H\n");
s.push_str("#define __FLOAT_H\n\n");
s.push_str("/* Characteristics of floating-point types */\n\n");
s.push_str("/* float */\n");
s.push_str("#define FLT_RADIX 2\n");
s.push_str("#define FLT_MANT_DIG 24\n");
s.push_str("#define FLT_DIG 6\n");
s.push_str("#define FLT_MIN_EXP (-125)\n");
s.push_str("#define FLT_MIN_10_EXP (-37)\n");
s.push_str("#define FLT_MAX_EXP 128\n");
s.push_str("#define FLT_MAX_10_EXP 38\n");
s.push_str("#define FLT_MIN 1.17549435082228750796873653722224568e-38F\n");
s.push_str("#define FLT_MAX 3.40282346638528859811704183484516925e+38F\n");
s.push_str("#define FLT_EPSILON 1.1920928955078125e-07F\n");
s.push_str("#define FLT_TRUE_MIN 1.40129846432481707092372958328991613e-45F\n");
s.push_str("#define FLT_HAS_SUBNORM 1\n");
s.push_str("#define FLT_EVAL_METHOD 0\n");
s.push_str("#define FLT_DECIMAL_DIG 9\n\n");
s.push_str("/* double */\n");
s.push_str("#define DBL_MANT_DIG 53\n");
s.push_str("#define DBL_DIG 15\n");
s.push_str("#define DBL_MIN_EXP (-1021)\n");
s.push_str("#define DBL_MIN_10_EXP (-307)\n");
s.push_str("#define DBL_MAX_EXP 1024\n");
s.push_str("#define DBL_MAX_10_EXP 308\n");
s.push_str("#define DBL_MIN 2.22507385850720138309023271733240406e-308\n");
s.push_str("#define DBL_MAX 1.79769313486231570814527423731704357e+308\n");
s.push_str("#define DBL_EPSILON 2.22044604925031308084726333618164062e-16\n");
s.push_str("#define DBL_TRUE_MIN 4.94065645841246544176568792868221372e-324\n");
s.push_str("#define DBL_HAS_SUBNORM 1\n");
s.push_str("#define DBL_DECIMAL_DIG 17\n\n");
s.push_str("/* long double */\n");
if self.pointer_width == 64 && self.little_endian {
s.push_str("#define LDBL_MANT_DIG 64\n");
s.push_str("#define LDBL_DIG 18\n");
s.push_str("#define LDBL_MIN_EXP (-16381)\n");
s.push_str("#define LDBL_MIN_10_EXP (-4931)\n");
s.push_str("#define LDBL_MAX_EXP 16384\n");
s.push_str("#define LDBL_MAX_10_EXP 4932\n");
s.push_str("#define LDBL_MIN 3.36210314311209350626267781732175260e-4932L\n");
s.push_str("#define LDBL_MAX 1.18973149535723176502126385303097021e+4932L\n");
s.push_str("#define LDBL_EPSILON 1.08420217248550443400745280086994171e-19L\n");
s.push_str("#define LDBL_TRUE_MIN 3.64519953188247460252840593361941982e-4951L\n");
s.push_str("#define LDBL_HAS_SUBNORM 1\n");
s.push_str("#define LDBL_DECIMAL_DIG 21\n\n");
} else {
s.push_str("#define LDBL_MANT_DIG 113\n");
s.push_str("#define LDBL_DIG 33\n");
s.push_str("#define LDBL_MIN_EXP (-16381)\n");
s.push_str("#define LDBL_MIN_10_EXP (-4931)\n");
s.push_str("#define LDBL_MAX_EXP 16384\n");
s.push_str("#define LDBL_MAX_10_EXP 4932\n");
s.push_str("#define LDBL_MIN 3.36210314311209350626267781732175260e-4932L\n");
s.push_str("#define LDBL_MAX 1.18973149535723176502126385303097021e+4932L\n");
s.push_str("#define LDBL_EPSILON 1.92592994438723585305597794258492732e-34L\n");
s.push_str("#define LDBL_TRUE_MIN 6.47517511943802511092443895822764655e-4966L\n");
s.push_str("#define LDBL_HAS_SUBNORM 1\n");
s.push_str("#define LDBL_DECIMAL_DIG 36\n\n");
}
s.push_str("#endif /* __FLOAT_H */\n");
s
}
fn generate_iso646(&self) -> String {
let mut s = String::new();
s.push_str("#ifndef __ISO646_H\n");
s.push_str("#define __ISO646_H\n\n");
s.push_str("#ifndef __cplusplus\n\n");
s.push_str("/* Alternative spellings for operators (ISO 646) */\n");
s.push_str("#define and &&\n");
s.push_str("#define and_eq &=\n");
s.push_str("#define bitand &\n");
s.push_str("#define bitor |\n");
s.push_str("#define compl ~\n");
s.push_str("#define not !\n");
s.push_str("#define not_eq !=\n");
s.push_str("#define or ||\n");
s.push_str("#define or_eq |=\n");
s.push_str("#define xor ^\n");
s.push_str("#define xor_eq ^=\n\n");
s.push_str("#endif /* __cplusplus */\n\n");
s.push_str("#endif /* __ISO646_H */\n");
s
}
fn generate_stdatomic(&self) -> String {
let mut s = String::new();
s.push_str("#ifndef __STDATOMIC_H\n");
s.push_str("#define __STDATOMIC_H\n\n");
s.push_str("/* Atomic types and operations are compiler builtins */\n\n");
s.push_str("typedef enum {\n");
s.push_str(" memory_order_relaxed = __ATOMIC_RELAXED,\n");
s.push_str(" memory_order_consume = __ATOMIC_CONSUME,\n");
s.push_str(" memory_order_acquire = __ATOMIC_ACQUIRE,\n");
s.push_str(" memory_order_release = __ATOMIC_RELEASE,\n");
s.push_str(" memory_order_acq_rel = __ATOMIC_ACQ_REL,\n");
s.push_str(" memory_order_seq_cst = __ATOMIC_SEQ_CST\n");
s.push_str("} memory_order;\n\n");
s.push_str("#define ATOMIC_BOOL_LOCK_FREE 2\n");
s.push_str("#define ATOMIC_CHAR_LOCK_FREE 2\n");
s.push_str("#define ATOMIC_CHAR16_T_LOCK_FREE 2\n");
s.push_str("#define ATOMIC_CHAR32_T_LOCK_FREE 2\n");
s.push_str("#define ATOMIC_WCHAR_T_LOCK_FREE 2\n");
s.push_str("#define ATOMIC_SHORT_LOCK_FREE 2\n");
s.push_str("#define ATOMIC_INT_LOCK_FREE 2\n");
s.push_str("#define ATOMIC_LONG_LOCK_FREE 2\n");
s.push_str("#define ATOMIC_LLONG_LOCK_FREE 2\n");
s.push_str("#define ATOMIC_POINTER_LOCK_FREE 2\n\n");
s.push_str("#define atomic_init(obj, value) __c11_atomic_init(obj, value)\n");
s.push_str("#define atomic_load(obj) __c11_atomic_load(obj, memory_order_seq_cst)\n");
s.push_str(
"#define atomic_store(obj, val) __c11_atomic_store(obj, val, memory_order_seq_cst)\n",
);
s.push_str("#define atomic_exchange(obj, val) __c11_atomic_exchange(obj, val, memory_order_seq_cst)\n");
s.push_str("#define atomic_compare_exchange_strong(obj, exp, val) __c11_atomic_compare_exchange_strong(obj, exp, val, memory_order_seq_cst, memory_order_seq_cst)\n");
s.push_str("#define atomic_compare_exchange_weak(obj, exp, val) __c11_atomic_compare_exchange_weak(obj, exp, val, memory_order_seq_cst, memory_order_seq_cst)\n");
s.push_str("#define atomic_fetch_add(obj, val) __c11_atomic_fetch_add(obj, val, memory_order_seq_cst)\n");
s.push_str("#define atomic_fetch_sub(obj, val) __c11_atomic_fetch_sub(obj, val, memory_order_seq_cst)\n");
s.push_str("#define atomic_fetch_and(obj, val) __c11_atomic_fetch_and(obj, val, memory_order_seq_cst)\n");
s.push_str("#define atomic_fetch_or(obj, val) __c11_atomic_fetch_or(obj, val, memory_order_seq_cst)\n");
s.push_str("#define atomic_fetch_xor(obj, val) __c11_atomic_fetch_xor(obj, val, memory_order_seq_cst)\n");
s.push_str("#define atomic_thread_fence(order) __c11_atomic_thread_fence(order)\n");
s.push_str("#define atomic_signal_fence(order) __c11_atomic_signal_fence(order)\n\n");
s.push_str("#endif /* __STDATOMIC_H */\n");
s
}
fn generate_stdalign(&self) -> String {
let mut s = String::new();
s.push_str("#ifndef __STDALIGN_H\n");
s.push_str("#define __STDALIGN_H\n\n");
s.push_str("#ifndef __cplusplus\n\n");
s.push_str("/* alignas and alignof for C */\n");
s.push_str("#define alignas _Alignas\n");
s.push_str("#define alignof _Alignof\n\n");
s.push_str("#define __alignas_is_defined 1\n");
s.push_str("#define __alignof_is_defined 1\n\n");
s.push_str("#endif /* __cplusplus */\n\n");
s.push_str("#endif /* __STDALIGN_H */\n");
s
}
fn generate_stdnoreturn(&self) -> String {
let mut s = String::new();
s.push_str("#ifndef __STDNORETURN_H\n");
s.push_str("#define __STDNORETURN_H\n\n");
s.push_str("#ifndef __cplusplus\n\n");
s.push_str("/* noreturn for C */\n");
s.push_str("#define noreturn _Noreturn\n\n");
s.push_str("#endif /* __cplusplus */\n\n");
s.push_str("#endif /* __STDNORETURN_H */\n");
s
}
fn generate_tgmath(&self) -> String {
let mut s = String::new();
s.push_str("#ifndef __TGMATH_H\n");
s.push_str("#define __TGMATH_H\n\n");
s.push_str("/* Type-generic math is handled by compiler builtins */\n");
s.push_str("#if __has_builtin(__builtin_tgmath)\n\n");
s.push_str("#define sin(x) __builtin_tgmath(sinf, sin, sinl, x)\n");
s.push_str("#define cos(x) __builtin_tgmath(cosf, cos, cosl, x)\n");
s.push_str("#define tan(x) __builtin_tgmath(tanf, tan, tanl, x)\n");
s.push_str("#define asin(x) __builtin_tgmath(asinf, asin, asinl, x)\n");
s.push_str("#define acos(x) __builtin_tgmath(acosf, acos, acosl, x)\n");
s.push_str("#define atan(x) __builtin_tgmath(atanf, atan, atanl, x)\n");
s.push_str("#define atan2(y,x) __builtin_tgmath(atan2f, atan2, atan2l, y, x)\n");
s.push_str("#define sinh(x) __builtin_tgmath(sinhf, sinh, sinhl, x)\n");
s.push_str("#define cosh(x) __builtin_tgmath(coshf, cosh, coshl, x)\n");
s.push_str("#define tanh(x) __builtin_tgmath(tanhf, tanh, tanhl, x)\n");
s.push_str("#define exp(x) __builtin_tgmath(expf, exp, expl, x)\n");
s.push_str("#define log(x) __builtin_tgmath(logf, log, logl, x)\n");
s.push_str("#define log10(x) __builtin_tgmath(log10f, log10, log10l, x)\n");
s.push_str("#define sqrt(x) __builtin_tgmath(sqrtf, sqrt, sqrtl, x)\n");
s.push_str("#define fabs(x) __builtin_tgmath(fabsf, fabs, fabsl, x)\n");
s.push_str("#define pow(x,y) __builtin_tgmath(powf, pow, powl, x, y)\n");
s.push_str("#define ceil(x) __builtin_tgmath(ceilf, ceil, ceill, x)\n");
s.push_str("#define floor(x) __builtin_tgmath(floorf, floor, floorl, x)\n");
s.push_str("#define fmod(x,y) __builtin_tgmath(fmodf, fmod, fmodl, x, y)\n\n");
s.push_str("#endif /* __has_builtin(__builtin_tgmath) */\n\n");
s.push_str("#endif /* __TGMATH_H */\n");
s
}
fn generate_unwind(&self) -> String {
let mut s = String::new();
s.push_str("#ifndef __UNWIND_H\n");
s.push_str("#define __UNWIND_H\n\n");
s.push_str("#ifdef __clang__\n\n");
s.push_str("/* Unwinding types and functions */\n");
s.push_str("typedef unsigned _Unwind_Word __attribute__((__mode__(__word__)));\n");
if self.pointer_width == 64 {
s.push_str("typedef unsigned _Unwind_Ptr __attribute__((__mode__(__DI__)));\n");
} else {
s.push_str("typedef unsigned _Unwind_Ptr __attribute__((__mode__(__SI__)));\n");
}
s.push_str(
"typedef unsigned _Unwind_Exception_Class __attribute__((__mode__(__DI__)));\n\n",
);
s.push_str("struct _Unwind_Exception;\n");
s.push_str("struct _Unwind_Context;\n\n");
s.push_str("typedef void (*_Unwind_Exception_Cleanup_Fn)");
s.push_str("(_Unwind_Reason_Code reason, struct _Unwind_Exception *exc);\n\n");
s.push_str("struct _Unwind_Exception {\n");
s.push_str(" _Unwind_Exception_Class exception_class;\n");
s.push_str(" _Unwind_Exception_Cleanup_Fn exception_cleanup;\n");
if self.pointer_width == 64 {
s.push_str(" _Unwind_Word private_1;\n");
s.push_str(" _Unwind_Word private_2;\n");
} else {
s.push_str(" _Unwind_Word private_1;\n");
}
s.push_str("} __attribute__((__aligned__));\n\n");
s.push_str("typedef enum {\n");
s.push_str(" _URC_NO_REASON = 0,\n");
s.push_str(" _URC_FOREIGN_EXCEPTION_CAUGHT = 1,\n");
s.push_str(" _URC_FATAL_PHASE2_ERROR = 2,\n");
s.push_str(" _URC_FATAL_PHASE1_ERROR = 3,\n");
s.push_str(" _URC_NORMAL_STOP = 4,\n");
s.push_str(" _URC_END_OF_STACK = 5,\n");
s.push_str(" _URC_HANDLER_FOUND = 6,\n");
s.push_str(" _URC_INSTALL_CONTEXT = 7,\n");
s.push_str(" _URC_CONTINUE_UNWIND = 8\n");
s.push_str("} _Unwind_Reason_Code;\n\n");
s.push_str("typedef enum {\n");
s.push_str(" _UA_SEARCH_PHASE = 1,\n");
s.push_str(" _UA_CLEANUP_PHASE = 2,\n");
s.push_str(" _UA_HANDLER_FRAME = 4,\n");
s.push_str(" _UA_FORCE_UNWIND = 8,\n");
s.push_str(" _UA_END_OF_STACK = 16\n");
s.push_str("} _Unwind_Action;\n\n");
s.push_str("#endif /* __clang__ */\n\n");
s.push_str("#endif /* __UNWIND_H */\n");
s
}
}
impl Default for BuiltinHeaderGenerator {
fn default() -> Self {
Self::new_x86_64_linux()
}
}
#[derive(Debug, Clone)]
pub struct BuiltinFunction {
pub name: String,
pub num_operands: usize,
pub has_return: bool,
pub is_pure: bool,
pub is_noreturn: bool,
pub is_const: bool,
pub returns_twice: bool,
pub category: BuiltinCategory,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BuiltinCategory {
Memory,
Math,
String,
Io,
Atomic,
Vector,
TypeTrait,
Overflow,
Expect,
ObjectSize,
Prefetch,
Trap,
Other,
}
#[derive(Debug, Clone)]
pub struct BuiltinRegistry {
builtins: HashMap<String, BuiltinFunction>,
}
impl BuiltinRegistry {
pub fn new() -> Self {
let mut reg = Self {
builtins: HashMap::new(),
};
reg.register_defaults();
reg
}
fn register(&mut self, name: &str, func: BuiltinFunction) {
self.builtins.insert(name.to_string(), func);
}
fn register_defaults(&mut self) {
self.register(
"__builtin_alloca",
BuiltinFunction {
name: "__builtin_alloca".into(),
num_operands: 1,
has_return: true,
is_pure: false,
is_noreturn: false,
is_const: false,
returns_twice: false,
category: BuiltinCategory::Memory,
},
);
self.register(
"__builtin_alloca_with_align",
BuiltinFunction {
name: "__builtin_alloca_with_align".into(),
num_operands: 2,
has_return: true,
is_pure: false,
is_noreturn: false,
is_const: false,
returns_twice: false,
category: BuiltinCategory::Memory,
},
);
self.register(
"__builtin_assume_aligned",
BuiltinFunction {
name: "__builtin_assume_aligned".into(),
num_operands: 2,
has_return: true,
is_pure: true,
is_noreturn: false,
is_const: false,
returns_twice: false,
category: BuiltinCategory::Memory,
},
);
self.register(
"__builtin_memcpy",
BuiltinFunction {
name: "__builtin_memcpy".into(),
num_operands: 3,
has_return: true,
is_pure: false,
is_noreturn: false,
is_const: false,
returns_twice: false,
category: BuiltinCategory::Memory,
},
);
self.register(
"__builtin_memmove",
BuiltinFunction {
name: "__builtin_memmove".into(),
num_operands: 3,
has_return: true,
is_pure: false,
is_noreturn: false,
is_const: false,
returns_twice: false,
category: BuiltinCategory::Memory,
},
);
self.register(
"__builtin_memset",
BuiltinFunction {
name: "__builtin_memset".into(),
num_operands: 3,
has_return: true,
is_pure: false,
is_noreturn: false,
is_const: false,
returns_twice: false,
category: BuiltinCategory::Memory,
},
);
self.register(
"__builtin_types_compatible_p",
BuiltinFunction {
name: "__builtin_types_compatible_p".into(),
num_operands: 2,
has_return: true,
is_pure: true,
is_noreturn: false,
is_const: true,
returns_twice: false,
category: BuiltinCategory::TypeTrait,
},
);
self.register(
"__builtin_choose_expr",
BuiltinFunction {
name: "__builtin_choose_expr".into(),
num_operands: 3,
has_return: true,
is_pure: true,
is_noreturn: false,
is_const: true,
returns_twice: false,
category: BuiltinCategory::TypeTrait,
},
);
self.register(
"__builtin_is_constant_evaluated",
BuiltinFunction {
name: "__builtin_is_constant_evaluated".into(),
num_operands: 0,
has_return: true,
is_pure: true,
is_noreturn: false,
is_const: true,
returns_twice: false,
category: BuiltinCategory::TypeTrait,
},
);
self.register(
"__builtin_add_overflow",
BuiltinFunction {
name: "__builtin_add_overflow".into(),
num_operands: 3,
has_return: true,
is_pure: false,
is_noreturn: false,
is_const: false,
returns_twice: false,
category: BuiltinCategory::Overflow,
},
);
self.register(
"__builtin_sub_overflow",
BuiltinFunction {
name: "__builtin_sub_overflow".into(),
num_operands: 3,
has_return: true,
is_pure: false,
is_noreturn: false,
is_const: false,
returns_twice: false,
category: BuiltinCategory::Overflow,
},
);
self.register(
"__builtin_mul_overflow",
BuiltinFunction {
name: "__builtin_mul_overflow".into(),
num_operands: 3,
has_return: true,
is_pure: false,
is_noreturn: false,
is_const: false,
returns_twice: false,
category: BuiltinCategory::Overflow,
},
);
self.register(
"__builtin_add_overflow_p",
BuiltinFunction {
name: "__builtin_add_overflow_p".into(),
num_operands: 3,
has_return: true,
is_pure: true,
is_noreturn: false,
is_const: true,
returns_twice: false,
category: BuiltinCategory::Overflow,
},
);
self.register(
"__builtin_sub_overflow_p",
BuiltinFunction {
name: "__builtin_sub_overflow_p".into(),
num_operands: 3,
has_return: true,
is_pure: true,
is_noreturn: false,
is_const: true,
returns_twice: false,
category: BuiltinCategory::Overflow,
},
);
self.register(
"__builtin_mul_overflow_p",
BuiltinFunction {
name: "__builtin_mul_overflow_p".into(),
num_operands: 3,
has_return: true,
is_pure: true,
is_noreturn: false,
is_const: true,
returns_twice: false,
category: BuiltinCategory::Overflow,
},
);
self.register(
"__builtin_expect",
BuiltinFunction {
name: "__builtin_expect".into(),
num_operands: 2,
has_return: true,
is_pure: true,
is_noreturn: false,
is_const: false,
returns_twice: false,
category: BuiltinCategory::Expect,
},
);
self.register(
"__builtin_expect_with_probability",
BuiltinFunction {
name: "__builtin_expect_with_probability".into(),
num_operands: 3,
has_return: true,
is_pure: true,
is_noreturn: false,
is_const: false,
returns_twice: false,
category: BuiltinCategory::Expect,
},
);
self.register(
"__builtin_unpredictable",
BuiltinFunction {
name: "__builtin_unpredictable".into(),
num_operands: 1,
has_return: true,
is_pure: true,
is_noreturn: false,
is_const: false,
returns_twice: false,
category: BuiltinCategory::Expect,
},
);
self.register(
"__builtin_object_size",
BuiltinFunction {
name: "__builtin_object_size".into(),
num_operands: 2,
has_return: true,
is_pure: true,
is_noreturn: false,
is_const: true,
returns_twice: false,
category: BuiltinCategory::ObjectSize,
},
);
self.register(
"__builtin_dynamic_object_size",
BuiltinFunction {
name: "__builtin_dynamic_object_size".into(),
num_operands: 2,
has_return: true,
is_pure: true,
is_noreturn: false,
is_const: false,
returns_twice: false,
category: BuiltinCategory::ObjectSize,
},
);
self.register(
"__builtin_prefetch",
BuiltinFunction {
name: "__builtin_prefetch".into(),
num_operands: 3,
has_return: false,
is_pure: false,
is_noreturn: false,
is_const: false,
returns_twice: false,
category: BuiltinCategory::Prefetch,
},
);
self.register(
"__builtin_trap",
BuiltinFunction {
name: "__builtin_trap".into(),
num_operands: 0,
has_return: false,
is_pure: false,
is_noreturn: true,
is_const: false,
returns_twice: false,
category: BuiltinCategory::Trap,
},
);
self.register(
"__builtin_unreachable",
BuiltinFunction {
name: "__builtin_unreachable".into(),
num_operands: 0,
has_return: false,
is_pure: false,
is_noreturn: true,
is_const: false,
returns_twice: false,
category: BuiltinCategory::Trap,
},
);
self.register(
"__builtin_debugtrap",
BuiltinFunction {
name: "__builtin_debugtrap".into(),
num_operands: 0,
has_return: false,
is_pure: false,
is_noreturn: false,
is_const: false,
returns_twice: false,
category: BuiltinCategory::Trap,
},
);
self.register(
"__builtin_return_address",
BuiltinFunction {
name: "__builtin_return_address".into(),
num_operands: 1,
has_return: true,
is_pure: true,
is_noreturn: false,
is_const: false,
returns_twice: false,
category: BuiltinCategory::Other,
},
);
self.register(
"__builtin_frame_address",
BuiltinFunction {
name: "__builtin_frame_address".into(),
num_operands: 1,
has_return: true,
is_pure: true,
is_noreturn: false,
is_const: false,
returns_twice: false,
category: BuiltinCategory::Other,
},
);
self.register(
"__builtin___clear_cache",
BuiltinFunction {
name: "__builtin___clear_cache".into(),
num_operands: 2,
has_return: false,
is_pure: false,
is_noreturn: false,
is_const: false,
returns_twice: false,
category: BuiltinCategory::Memory,
},
);
}
pub fn lookup(&self, name: &str) -> Option<&BuiltinFunction> {
self.builtins.get(name)
}
pub fn is_builtin(&self, name: &str) -> bool {
self.builtins.contains_key(name)
}
pub fn builtin_names(&self) -> Vec<&String> {
self.builtins.keys().collect()
}
pub fn builtin_count(&self) -> usize {
self.builtins.len()
}
}
impl Default for BuiltinRegistry {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct BuiltinIncludeResolver {
generator: BuiltinHeaderGenerator,
cache: HashMap<String, String>,
}
impl BuiltinIncludeResolver {
pub fn new(generator: BuiltinHeaderGenerator) -> Self {
Self {
generator,
cache: HashMap::new(),
}
}
pub fn resolve(&mut self, header_name: &str) -> Option<&str> {
let normalized = header_name
.trim_matches('"')
.trim_matches('<')
.trim_matches('>');
let all = [
BuiltinHeader::Stddef,
BuiltinHeader::Stdint,
BuiltinHeader::Stdbool,
BuiltinHeader::Stdarg,
BuiltinHeader::Limits,
BuiltinHeader::Float,
BuiltinHeader::Iso646,
BuiltinHeader::Stdatomic,
BuiltinHeader::Stdalign,
BuiltinHeader::Stdnoreturn,
BuiltinHeader::Tgmath,
BuiltinHeader::Unwind,
BuiltinHeader::Cfloat,
];
for h in &all {
if h.filename() == normalized {
let entry = self.cache.entry(h.filename().to_string());
let content = entry.or_insert_with(|| self.generator.generate(*h));
return Some(content.as_str());
}
}
None
}
pub fn is_builtin_header(&self, header_name: &str) -> bool {
let normalized = header_name
.trim_matches('"')
.trim_matches('<')
.trim_matches('>');
let all = [
BuiltinHeader::Stddef,
BuiltinHeader::Stdint,
BuiltinHeader::Stdbool,
BuiltinHeader::Stdarg,
BuiltinHeader::Limits,
BuiltinHeader::Float,
BuiltinHeader::Iso646,
BuiltinHeader::Stdatomic,
BuiltinHeader::Stdalign,
BuiltinHeader::Stdnoreturn,
BuiltinHeader::Tgmath,
BuiltinHeader::Unwind,
];
all.iter().any(|h| h.filename() == normalized)
}
pub fn prewarm_cache(&mut self) {
self.generator
.generate_all()
.into_iter()
.for_each(|(k, v)| {
self.cache.insert(k, v);
});
}
pub fn clear_cache(&mut self) {
self.cache.clear();
}
}
impl Default for BuiltinIncludeResolver {
fn default() -> Self {
Self::new(BuiltinHeaderGenerator::default())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_builtin_header_filename() {
assert_eq!(BuiltinHeader::Stddef.filename(), "stddef.h");
assert_eq!(BuiltinHeader::Stdint.filename(), "stdint.h");
assert_eq!(BuiltinHeader::Stdbool.filename(), "stdbool.h");
assert_eq!(BuiltinHeader::Stdarg.filename(), "stdarg.h");
assert_eq!(BuiltinHeader::Limits.filename(), "limits.h");
assert_eq!(BuiltinHeader::Float.filename(), "float.h");
assert_eq!(BuiltinHeader::Iso646.filename(), "iso646.h");
}
#[test]
fn test_builtin_header_categories() {
assert!(BuiltinHeader::Stddef.is_c89());
assert!(BuiltinHeader::Limits.is_c89());
assert!(!BuiltinHeader::Stdbool.is_c89());
assert!(BuiltinHeader::Stdbool.is_c99());
assert!(BuiltinHeader::Stdatomic.is_c11());
assert!(!BuiltinHeader::Stdatomic.is_c89());
}
#[test]
fn test_generate_stddef_x86_64() {
let gen = BuiltinHeaderGenerator::new_x86_64_linux();
let content = gen.generate(BuiltinHeader::Stddef);
assert!(content.contains("typedef unsigned long size_t;"));
assert!(content.contains("typedef long ptrdiff_t;"));
assert!(content.contains("__builtin_offsetof"));
assert!(content.contains("max_align_t"));
assert!(content.contains("NULL"));
}
#[test]
fn test_generate_stdint_x86_64() {
let gen = BuiltinHeaderGenerator::new_x86_64_linux();
let content = gen.generate(BuiltinHeader::Stdint);
assert!(content.contains("int8_t"));
assert!(content.contains("uint64_t"));
assert!(content.contains("INT32_MAX"));
assert!(content.contains("SIZE_MAX"));
}
#[test]
fn test_generate_stdbool() {
let gen = BuiltinHeaderGenerator::new_x86_64_linux();
let content = gen.generate(BuiltinHeader::Stdbool);
assert!(content.contains("#define bool _Bool"));
assert!(content.contains("#define true 1"));
assert!(content.contains("#define false 0"));
assert!(content.contains("__bool_true_false_are_defined"));
}
#[test]
fn test_generate_stdarg() {
let gen = BuiltinHeaderGenerator::new_x86_64_linux();
let content = gen.generate(BuiltinHeader::Stdarg);
assert!(content.contains("__builtin_va_list"));
assert!(content.contains("__builtin_va_start"));
assert!(content.contains("__builtin_va_arg"));
assert!(content.contains("__builtin_va_end"));
assert!(content.contains("__builtin_va_copy"));
}
#[test]
fn test_generate_limits_x86_64() {
let gen = BuiltinHeaderGenerator::new_x86_64_linux();
let content = gen.generate(BuiltinHeader::Limits);
assert!(content.contains("CHAR_BIT"));
assert!(content.contains("SCHAR_MIN"));
assert!(content.contains("LONG_MAX"));
assert!(content.contains("ULLONG_MAX"));
}
#[test]
fn test_generate_limits_arm() {
let gen = BuiltinHeaderGenerator::new_arm_linux();
let content = gen.generate(BuiltinHeader::Limits);
assert!(content.contains("CHAR_MIN 0")); assert!(content.contains("LONG_MAX 2147483647L"));
}
#[test]
fn test_generate_float() {
let gen = BuiltinHeaderGenerator::new_x86_64_linux();
let content = gen.generate(BuiltinHeader::Float);
assert!(content.contains("FLT_RADIX 2"));
assert!(content.contains("FLT_MANT_DIG"));
assert!(content.contains("DBL_EPSILON"));
assert!(content.contains("LDBL_MANT_DIG"));
}
#[test]
fn test_generate_iso646() {
let gen = BuiltinHeaderGenerator::new_x86_64_linux();
let content = gen.generate(BuiltinHeader::Iso646);
assert!(content.contains("#define and &&"));
assert!(content.contains("#define or ||"));
assert!(content.contains("#define not !"));
assert!(content.contains("#define xor ^"));
}
#[test]
fn test_generate_stdatomic() {
let gen = BuiltinHeaderGenerator::new_x86_64_linux();
let content = gen.generate(BuiltinHeader::Stdatomic);
assert!(content.contains("memory_order_seq_cst"));
assert!(content.contains("ATOMIC_BOOL_LOCK_FREE"));
assert!(content.contains("__c11_atomic_init"));
}
#[test]
fn test_generate_stdalign() {
let gen = BuiltinHeaderGenerator::new_x86_64_linux();
let content = gen.generate(BuiltinHeader::Stdalign);
assert!(content.contains("#define alignas _Alignas"));
assert!(content.contains("#define alignof _Alignof"));
}
#[test]
fn test_generate_stdnoreturn() {
let gen = BuiltinHeaderGenerator::new_x86_64_linux();
let content = gen.generate(BuiltinHeader::Stdnoreturn);
assert!(content.contains("#define noreturn _Noreturn"));
}
#[test]
fn test_generate_tgmath() {
let gen = BuiltinHeaderGenerator::new_x86_64_linux();
let content = gen.generate(BuiltinHeader::Tgmath);
assert!(content.contains("__builtin_tgmath"));
assert!(content.contains("sin"));
assert!(content.contains("sqrt"));
}
#[test]
fn test_generate_unwind() {
let gen = BuiltinHeaderGenerator::new_x86_64_linux();
let content = gen.generate(BuiltinHeader::Unwind);
assert!(content.contains("_Unwind_Exception"));
assert!(content.contains("_Unwind_Reason_Code"));
assert!(content.contains("_URC_END_OF_STACK"));
}
#[test]
fn test_generate_all() {
let gen = BuiltinHeaderGenerator::new_x86_64_linux();
let map = gen.generate_all();
assert!(map.contains_key("stddef.h"));
assert!(map.contains_key("stdint.h"));
assert!(map.contains_key("stdbool.h"));
assert!(map.contains_key("stdarg.h"));
assert!(map.contains_key("limits.h"));
assert!(map.contains_key("float.h"));
}
#[test]
fn test_builtin_registry_memory() {
let reg = BuiltinRegistry::new();
let ba = reg.lookup("__builtin_alloca").unwrap();
assert_eq!(ba.num_operands, 1);
assert!(ba.has_return);
let bm = reg.lookup("__builtin_memcpy").unwrap();
assert_eq!(bm.num_operands, 3);
assert_eq!(bm.category, BuiltinCategory::Memory);
}
#[test]
fn test_builtin_registry_type_trait() {
let reg = BuiltinRegistry::new();
let bt = reg.lookup("__builtin_types_compatible_p").unwrap();
assert!(bt.is_const);
assert_eq!(bt.category, BuiltinCategory::TypeTrait);
let bc = reg.lookup("__builtin_choose_expr").unwrap();
assert_eq!(bc.num_operands, 3);
}
#[test]
fn test_builtin_registry_overflow() {
let reg = BuiltinRegistry::new();
let ba = reg.lookup("__builtin_add_overflow").unwrap();
assert_eq!(ba.category, BuiltinCategory::Overflow);
assert_eq!(ba.num_operands, 3);
let bm = reg.lookup("__builtin_mul_overflow").unwrap();
assert_eq!(bm.category, BuiltinCategory::Overflow);
assert!(reg.lookup("__builtin_sub_overflow").is_some());
}
#[test]
fn test_builtin_registry_expect() {
let reg = BuiltinRegistry::new();
let be = reg.lookup("__builtin_expect").unwrap();
assert_eq!(be.category, BuiltinCategory::Expect);
assert!(be.is_pure);
let bp = reg.lookup("__builtin_expect_with_probability").unwrap();
assert_eq!(bp.num_operands, 3);
}
#[test]
fn test_builtin_registry_trap() {
let reg = BuiltinRegistry::new();
let bt = reg.lookup("__builtin_trap").unwrap();
assert!(bt.is_noreturn);
let bu = reg.lookup("__builtin_unreachable").unwrap();
assert!(bu.is_noreturn);
}
#[test]
fn test_builtin_registry_count() {
let reg = BuiltinRegistry::new();
assert!(reg.builtin_count() >= 20);
}
#[test]
fn test_builtin_registry_is_builtin() {
let reg = BuiltinRegistry::new();
assert!(reg.is_builtin("__builtin_memset"));
assert!(!reg.is_builtin("nonexistent_func"));
}
#[test]
fn test_builtin_include_resolver_resolve() {
let gen = BuiltinHeaderGenerator::new_x86_64_linux();
let mut resolver = BuiltinIncludeResolver::new(gen);
let content = resolver.resolve("stddef.h").unwrap();
assert!(content.contains("size_t"));
}
#[test]
fn test_builtin_include_resolver_is_builtin_header() {
let gen = BuiltinHeaderGenerator::new_x86_64_linux();
let resolver = BuiltinIncludeResolver::new(gen);
assert!(resolver.is_builtin_header("stddef.h"));
assert!(resolver.is_builtin_header("stdint.h"));
assert!(!resolver.is_builtin_header("stdio.h")); }
#[test]
fn test_builtin_include_resolver_cache() {
let gen = BuiltinHeaderGenerator::new_x86_64_linux();
let mut resolver = BuiltinIncludeResolver::new(gen);
let _c1 = resolver.resolve("stddef.h").unwrap();
let _c2 = resolver.resolve("stddef.h").unwrap();
}
#[test]
fn test_generator_new_aarch64() {
let gen = BuiltinHeaderGenerator::new_aarch64_linux();
assert_eq!(gen.pointer_width, 64);
assert!(!gen.char_is_signed); }
#[test]
fn test_generator_new_x86() {
let gen = BuiltinHeaderGenerator::new_x86_linux();
assert_eq!(gen.pointer_width, 32);
assert_eq!(gen.long_width, 32);
let content = gen.generate(BuiltinHeader::Stdint);
assert!(content.contains("long long"));
}
#[test]
fn test_builtin_header_attributes() {
let gen = BuiltinHeaderGenerator::new_x86_64_linux();
let content = gen.generate(BuiltinHeader::Stddef);
assert!(content.contains("__attribute__((__aligned__"));
}
#[test]
fn test_generate_float_double_epsilon() {
let gen = BuiltinHeaderGenerator::new_x86_64_linux();
let content = gen.generate(BuiltinHeader::Float);
assert!(content.contains("DBL_EPSILON"));
assert!(content.contains("FLT_EPSILON"));
}
#[test]
fn test_generate_stdint_constant_macros_x86_64() {
let gen = BuiltinHeaderGenerator::new_x86_64_linux();
let content = gen.generate(BuiltinHeader::Stdint);
assert!(content.contains("INT64_C(c) c ## L"));
}
#[test]
fn test_generate_stdint_ptr_x86_32() {
let gen = BuiltinHeaderGenerator::new_x86_linux();
let content = gen.generate(BuiltinHeader::Stdint);
assert!(content.contains("typedef int intptr_t;"));
}
}