1use rucc_session::Std;
47use rucc_target::TargetInfo;
48use rucc_types::{IntKind, int_width};
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52pub struct IntConstant {
53 pub value: u128,
57 pub ty: IntConstantType,
59 pub remarks: Remarks,
61}
62
63#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub enum IntConstantType {
66 Standard(IntKind),
68 BitInt {
70 signed: bool,
72 width: u32,
74 },
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq)]
82pub enum IntError {
83 Floating,
85 InvalidSuffix,
87 InvalidOctalDigit,
89 NoDigits,
91 TooLarge,
94}
95
96impl IntError {
97 #[must_use]
102 pub const fn message(self) -> &'static str {
103 match self {
104 IntError::Floating => "not an integer constant",
105 IntError::InvalidSuffix => "invalid suffix on integer constant",
106 IntError::InvalidOctalDigit => "invalid digit in octal constant",
107 IntError::NoDigits => "no digits in integer constant",
108 IntError::TooLarge => "integer constant is too large to be represented in any type",
109 }
110 }
111}
112
113#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
120pub struct Remarks(u8);
121
122impl Remarks {
123 pub const NONE: Remarks = Remarks(0);
125 pub const BINARY: Remarks = Remarks(1);
127 pub const SEPARATORS: Remarks = Remarks(2);
129 pub const BIT_INT: Remarks = Remarks(4);
131 pub const LONG_LONG: Remarks = Remarks(8);
133 pub const UNSIGNED: Remarks = Remarks(16);
137
138 #[inline]
140 #[must_use]
141 pub const fn has(self, other: Remarks) -> bool {
142 self.0 & other.0 == other.0
143 }
144
145 #[inline]
147 #[must_use]
148 pub const fn with(self, other: Remarks) -> Remarks {
149 Remarks(self.0 | other.0)
150 }
151
152 #[inline]
154 #[must_use]
155 pub const fn is_none(self) -> bool {
156 self.0 == 0
157 }
158}
159
160pub fn integer(text: &str, std: Std, target: &TargetInfo) -> Result<IntConstant, IntError> {
167 let bytes = text.as_bytes();
168 let (base, start) = base_of(bytes);
169 if floating(bytes, base) {
170 return Err(IntError::Floating);
171 }
172 let mut remarks = Remarks::NONE;
173 if base == 2 && std < Std::C23 {
174 remarks = remarks.with(Remarks::BINARY);
175 }
176
177 let mut value: u128 = 0;
178 let mut digits = 0;
179 let mut index = start;
180 while index < bytes.len() {
181 let byte = bytes[index];
182 if byte == b'\'' {
183 if digits == 0 || index + 1 >= bytes.len() || digit(bytes[index + 1], base).is_none() {
187 return Err(IntError::InvalidSuffix);
188 }
189 if std < Std::C23 {
190 remarks = remarks.with(Remarks::SEPARATORS);
191 }
192 index += 1;
193 continue;
194 }
195 let Some(digit) = digit(byte, base) else {
196 break;
197 };
198 value = value
199 .checked_mul(u128::from(base))
200 .and_then(|shifted| shifted.checked_add(u128::from(digit)))
201 .ok_or(IntError::TooLarge)?;
202 digits += 1;
203 index += 1;
204 }
205 if digits == 0 {
206 return Err(IntError::NoDigits);
209 }
210 if base == 8 && bytes[start..index].iter().any(|&byte| byte == b'8' || byte == b'9') {
211 return Err(IntError::InvalidOctalDigit);
212 }
213
214 let suffix = suffix_of(&bytes[index..])?;
215 if suffix.length == Some(Length::LongLong) && std == Std::C89 {
216 remarks = remarks.with(Remarks::LONG_LONG);
217 }
218 if suffix.length == Some(Length::BitInt) {
219 if std < Std::C23 {
220 remarks = remarks.with(Remarks::BIT_INT);
221 }
222 return Ok(IntConstant { value, ty: bit_int(value, suffix.unsigned), remarks });
223 }
224
225 let candidates = candidates(base, suffix, std);
226 let kind = candidates
227 .iter()
228 .copied()
229 .find(|&kind| fits(value, kind, target))
230 .ok_or(IntError::TooLarge)?;
231 if base == 10 && !suffix.unsigned && !signed_standard(kind) {
232 remarks = remarks.with(Remarks::UNSIGNED);
233 }
234 Ok(IntConstant { value, ty: IntConstantType::Standard(kind), remarks })
235}
236
237fn base_of(bytes: &[u8]) -> (u32, usize) {
243 match bytes {
244 [b'0', b'x' | b'X', ..] => (16, 2),
245 [b'0', b'b' | b'B', ..] => (2, 2),
246 [b'0', next, ..] if next.is_ascii_digit() => (8, 1),
247 _ => (10, 0),
248 }
249}
250
251fn floating(bytes: &[u8], base: u32) -> bool {
261 let exponent = if base == 16 { *b"pP" } else { *b"eE" };
262 bytes.iter().any(|&byte| byte == b'.' || exponent.contains(&byte))
263}
264
265fn digit(byte: u8, base: u32) -> Option<u32> {
270 char::from(byte).to_digit(if base == 8 { 10 } else { base })
271}
272
273#[derive(Debug, Clone, Copy, PartialEq, Eq)]
275enum Length {
276 Long,
278 LongLong,
280 BitInt,
282}
283
284#[derive(Debug, Clone, Copy, PartialEq, Eq)]
286struct Suffix {
287 unsigned: bool,
289 length: Option<Length>,
291}
292
293fn suffix_of(mut rest: &[u8]) -> Result<Suffix, IntError> {
295 let mut suffix = Suffix { unsigned: false, length: None };
296 while let Some(&byte) = rest.first() {
297 let taken = match byte {
298 b'u' | b'U' if !suffix.unsigned => {
299 suffix.unsigned = true;
300 1
301 }
302 b'l' | b'L' if suffix.length.is_none() => {
305 if rest.get(1) == Some(&byte) {
306 suffix.length = Some(Length::LongLong);
307 2
308 } else {
309 suffix.length = Some(Length::Long);
310 1
311 }
312 }
313 b'w' | b'W' if suffix.length.is_none() => {
314 let second = if byte == b'w' { b'b' } else { b'B' };
315 if rest.get(1) != Some(&second) {
316 return Err(IntError::InvalidSuffix);
317 }
318 suffix.length = Some(Length::BitInt);
319 2
320 }
321 _ => return Err(IntError::InvalidSuffix),
322 };
323 rest = &rest[taken..];
324 }
325 Ok(suffix)
326}
327
328fn bit_int(value: u128, unsigned: bool) -> IntConstantType {
334 let used = 128 - value.leading_zeros();
335 let width = if unsigned { used.max(1) } else { used + 1 };
336 IntConstantType::BitInt { signed: !unsigned, width: width.max(if unsigned { 1 } else { 2 }) }
337}
338
339fn signed_standard(kind: IntKind) -> bool {
342 matches!(kind, IntKind::Int | IntKind::Long | IntKind::LongLong)
343}
344
345fn fits(value: u128, kind: IntKind, target: &TargetInfo) -> bool {
347 let width = int_width(kind, target);
348 let bits = if kind.is_signed(false) { width - 1 } else { width };
351 bits >= 128 || value >> bits == 0
354}
355
356fn candidates(base: u32, suffix: Suffix, std: Std) -> &'static [IntKind] {
363 use IntKind::{Int, Int128, Long, LongLong, UInt, UInt128, ULong, ULongLong};
364
365 let decimal = base == 10;
366 let c89 = std == Std::C89;
367 match (suffix.unsigned, suffix.length) {
368 (false, None) if decimal && c89 => &[Int, Long, ULong, Int128, UInt128],
369 (false, None) if decimal => &[Int, Long, LongLong, Int128],
370 (false, None) if c89 => &[Int, UInt, Long, ULong, Int128, UInt128],
371 (false, None) => &[Int, UInt, Long, ULong, LongLong, ULongLong, Int128, UInt128],
372
373 (true, None) if c89 => &[UInt, ULong, UInt128],
374 (true, None) => &[UInt, ULong, ULongLong, UInt128],
375
376 (false, Some(Length::Long)) if decimal && c89 => &[Long, ULong, Int128, UInt128],
377 (false, Some(Length::Long)) if decimal => &[Long, LongLong, Int128],
378 (false, Some(Length::Long)) if c89 => &[Long, ULong, Int128, UInt128],
379 (false, Some(Length::Long)) => &[Long, ULong, LongLong, ULongLong, Int128, UInt128],
380
381 (true, Some(Length::Long)) if c89 => &[ULong, UInt128],
382 (true, Some(Length::Long)) => &[ULong, ULongLong, UInt128],
383
384 (false, Some(Length::LongLong)) if decimal => &[LongLong, Int128],
385 (false, Some(Length::LongLong)) => &[LongLong, ULongLong, Int128, UInt128],
386 (true, Some(Length::LongLong)) => &[ULongLong, UInt128],
387
388 (_, Some(Length::BitInt)) => &[],
390 }
391}
392
393#[cfg(test)]
394mod tests {
395 use rucc_target::Triple;
396
397 use super::*;
398
399 fn linux() -> TargetInfo {
400 TargetInfo::new("x86_64-unknown-linux-gnu".parse::<Triple>().expect("a known triple"))
401 }
402
403 fn c23(text: &str) -> Result<IntConstant, IntError> {
405 integer(text, Std::C23, &linux())
406 }
407
408 fn kind(text: &str, std: Std) -> IntKind {
410 match integer(text, std, &linux()).expect("a valid constant").ty {
411 IntConstantType::Standard(kind) => kind,
412 IntConstantType::BitInt { .. } => panic!("{text} is a _BitInt constant"),
413 }
414 }
415
416 #[test]
417 fn a_constant_in_each_base_has_the_value_it_says() {
418 assert_eq!(c23("0").expect("zero").value, 0);
419 assert_eq!(c23("42").expect("decimal").value, 42);
420 assert_eq!(c23("0777").expect("octal").value, 0o777);
421 assert_eq!(c23("0xdeadBEEF").expect("hex").value, 0xdead_beef);
422 assert_eq!(c23("0b1010").expect("binary").value, 0b1010);
423 assert_eq!(c23("0X10").expect("upper case prefix").value, 16);
424 assert_eq!(c23("0u").expect("zero with a suffix").value, 0);
427 }
428
429 #[test]
430 fn digit_separators_are_stripped_and_reported_before_c23() {
431 let value = c23("1'000'000").expect("a C23 constant");
432 assert_eq!(value.value, 1_000_000);
433 assert!(value.remarks.is_none());
434 assert_eq!(c23("0x1'0").expect("hex with a separator").value, 16);
435
436 let older = integer("1'000", Std::C17, &linux()).expect("still converted");
437 assert!(older.remarks.has(Remarks::SEPARATORS));
438 assert_eq!(older.value, 1000);
439 }
440
441 #[test]
442 fn the_type_of_a_decimal_constant_walks_the_signed_types_only() {
443 assert_eq!(kind("2147483647", Std::C23), IntKind::Int);
445 assert_eq!(kind("2147483648", Std::C23), IntKind::Long);
446 assert_eq!(kind("4294967295", Std::C23), IntKind::Long);
447 assert_eq!(kind("9223372036854775807", Std::C23), IntKind::Long);
448 assert_eq!(kind("9223372036854775808", Std::C23), IntKind::Int128);
451 assert_eq!(kind("18446744073709551615", Std::C23), IntKind::Int128);
452 let large = c23("18446744073709551615").expect("fits __int128");
453 assert!(large.remarks.has(Remarks::UNSIGNED));
454 }
455
456 #[test]
457 fn a_constant_in_another_base_may_be_unsigned_without_saying_so() {
458 assert_eq!(kind("0xffffffff", Std::C23), IntKind::UInt);
461 assert_eq!(kind("0x7fffffff", Std::C23), IntKind::Int);
462 assert_eq!(kind("0x80000000", Std::C23), IntKind::UInt);
463 assert_eq!(kind("0x100000000", Std::C23), IntKind::Long);
464 assert_eq!(kind("0xffffffffffffffff", Std::C23), IntKind::ULong);
465 assert_eq!(kind("0777", Std::C23), IntKind::Int);
466 assert_eq!(kind("0b1010", Std::C23), IntKind::Int);
467 assert!(c23("0xffffffff").expect("a constant").remarks.is_none());
469 }
470
471 #[test]
472 fn c89_has_unsigned_long_in_the_decimal_list_and_no_long_long_in_any() {
473 assert_eq!(kind("18446744073709551615", Std::C89), IntKind::ULong);
476 assert_eq!(kind("18446744073709551615", Std::C99), IntKind::Int128);
477 let old = integer("18446744073709551615", Std::C89, &linux()).expect("a C89 constant");
478 assert!(old.remarks.has(Remarks::UNSIGNED));
479 let long_long = integer("1ll", Std::C89, &linux()).expect("an extension");
481 assert!(long_long.remarks.has(Remarks::LONG_LONG));
482 assert_eq!(kind("1ll", Std::C89), IntKind::LongLong);
483 assert!(integer("1ll", Std::C99, &linux()).expect("standard").remarks.is_none());
484 }
485
486 #[test]
487 fn a_suffix_narrows_the_list_it_does_not_pick_the_type() {
488 assert_eq!(kind("1u", Std::C23), IntKind::UInt);
489 assert_eq!(kind("1l", Std::C23), IntKind::Long);
490 assert_eq!(kind("1ul", Std::C23), IntKind::ULong);
491 assert_eq!(kind("1ll", Std::C23), IntKind::LongLong);
492 assert_eq!(kind("1llu", Std::C23), IntKind::ULongLong);
493 assert_eq!(kind("4294967296u", Std::C23), IntKind::ULong);
496 assert_eq!(kind("0xffffffffu", Std::C23), IntKind::UInt);
497 }
498
499 #[test]
500 fn the_letters_of_a_suffix_may_be_in_either_case_but_not_both() {
501 for text in ["1u", "1U", "1l", "1L", "1ll", "1LL", "1ul", "1lu", "1uL", "1LLU", "1llu"] {
502 assert!(c23(text).is_ok(), "{text} is a constant in both compilers");
503 }
504 for text in ["1lL", "1Ll", "1uu", "1lul", "1z", "1uz", "1f", "1x", "1_000"] {
505 assert_eq!(c23(text), Err(IntError::InvalidSuffix), "{text} is not");
506 }
507 }
508
509 #[test]
510 fn a_bit_int_constant_has_the_narrowest_type_that_holds_it() {
511 let cases = [
513 ("0wb", true, 2),
514 ("1wb", true, 2),
515 ("3wb", true, 3),
516 ("42wb", true, 7),
517 ("255wb", true, 9),
518 ("0uwb", false, 1),
519 ("1uwb", false, 1),
520 ("255uwb", false, 8),
521 ("256uwb", false, 9),
522 ("0xffffffffffffffffuwb", false, 64),
523 ];
524 for (text, signed, width) in cases {
525 let constant = c23(text).expect("a _BitInt constant");
526 assert_eq!(
527 constant.ty,
528 IntConstantType::BitInt { signed, width },
529 "{text} is the wrong width"
530 );
531 }
532 for text in ["1uwb", "1wbu", "1UWB", "1WBu", "1uWB"] {
534 assert!(c23(text).is_ok(), "{text} is a constant in clang");
535 }
536 for text in ["1wB", "1Wb", "1lwb", "1wbl", "1wbwb"] {
537 assert_eq!(c23(text), Err(IntError::InvalidSuffix), "{text} is not");
538 }
539 let older = integer("1wb", Std::C17, &linux()).expect("clang accepts it everywhere");
541 assert!(older.remarks.has(Remarks::BIT_INT));
542 }
543
544 #[test]
545 fn a_binary_constant_is_an_extension_before_c23() {
546 assert!(c23("0b1").expect("standard in C23").remarks.is_none());
547 let older = integer("0b1", Std::C17, &linux()).expect("both compilers accept it");
548 assert!(older.remarks.has(Remarks::BINARY));
549 }
550
551 #[test]
552 fn an_octal_constant_names_the_digit_that_is_not_one() {
553 assert_eq!(c23("08"), Err(IntError::InvalidOctalDigit));
554 assert_eq!(c23("0778"), Err(IntError::InvalidOctalDigit));
555 assert_eq!(c23("09"), Err(IntError::InvalidOctalDigit));
556 assert_eq!(c23("9").expect("decimal").value, 9);
558 }
559
560 #[test]
561 fn a_prefix_with_no_digits_after_it_is_not_a_constant() {
562 assert_eq!(c23("0x"), Err(IntError::NoDigits));
563 assert_eq!(c23("0b"), Err(IntError::NoDigits));
564 }
565
566 #[test]
567 fn a_constant_larger_than_any_type_is_refused_rather_than_wrapped() {
568 assert_eq!(c23("340282366920938463463374607431768211456"), Err(IntError::TooLarge));
572 assert_eq!(c23("0x100000000000000000000000000000000"), Err(IntError::TooLarge));
573 assert_eq!(c23("170141183460469231731687303715884105728"), Err(IntError::TooLarge));
576 assert_eq!(kind("0x80000000000000000000000000000000", Std::C23), IntKind::UInt128);
578 assert_eq!(kind("0xffffffffffffffffffffffffffffffff", Std::C23), IntKind::UInt128);
579 }
580
581 #[test]
582 fn a_floating_constant_is_handed_back_rather_than_refused() {
583 for text in ["1.0", ".5", "1.", "1e5", "1E-5", "1e", "0x1p3", "0x1.8p+1", "1.5e3"] {
584 assert_eq!(c23(text), Err(IntError::Floating), "{text} belongs to the other path");
585 }
586 assert_eq!(c23("08e5"), Err(IntError::Floating));
589 assert_eq!(c23("0xe5").expect("hex digits").value, 0xe5);
592 assert_eq!(c23("1f"), Err(IntError::InvalidSuffix));
593 }
594
595 #[test]
596 fn the_type_comes_from_the_target_and_not_from_the_host() {
597 let windows =
600 TargetInfo::new("x86_64-pc-windows-msvc".parse::<Triple>().expect("a known triple"));
601 let on_windows = integer("4294967295", Std::C23, &windows).expect("a constant");
602 assert_eq!(on_windows.ty, IntConstantType::Standard(IntKind::LongLong));
603 assert_eq!(kind("4294967295", Std::C23), IntKind::Long);
604 }
605}