A few days and an RFC draft later (and many excellent comments from @rkruppe poking holes in it!) , I’d like to propose an alternative to the i__ and f__ for feedback.
Introduce two lang items (note that the names are strawmen; they clash with the traits I’ve defined above!)
#[lang = "int_literal"]
struct IntLit(str);
impl IntLit {
/// Creates a new IntLit from a string,
/// checking to make sure it's syntactically valid!
const fn new<'a>(&'a str) -> &'a IntLit { .. }
/// The literal, exactly like it appears in
/// source code.
const fn verbatim(&self) -> &str { self.0 }
/// The canonicalized for of the literal, with
/// extraneous '0' and '_' characters removed,
/// and converted to base 10.
///
/// assert_eq!(IntLit::new("9001").canonical(), "9001")
/// assert_eq!(IntLit::new("0x00_ff_ff").canonical(), "65535")
const fn canonical(&self) -> &str { .. }
}
#[lang = "float_literal"]
struct FloatLit(str);
impl FloatLit {
/// Creates a new IntLit from a string,
/// checking to make sure it's syntactically valid!
const fn new<'a>(&'a str) -> &'a FloatLit { .. }
/// The literal, exactly like it appears in
/// source code.
const fn verbatim(&self) -> &str { self.0 }
/// The canonicalized for of the literal, with
/// extraneous '0', '_', and '.' characters removed, and
/// with the exponent removed if the exponent is 0. The
/// 'e' in the exponent is also lowecased.
///
/// assert_eq!(IntLit::new("42.42").canonical(), "42.42")
/// assert_eq!(IntLit::new("1.").canonical(), "1")
/// assert_eq!(IntLit::new("0.2").canonical(), ".2")
///
/// assert_eq!(IntLit::new("10e100").canonical(), "10e100")
/// assert_eq!(IntLit::new("10E-5").canonical(), "10e-5")
/// assert_eq!(IntLit::new("1e0").canonical(), "1")
const fn canonical(&self) -> &str { .. }
// the following are optional convenience methods for
// splitting a float literal. it is not clear if we will
// be including these or not
/// The decimal part of this literal.
const fn decimal_part(&self) -> &str { .. }
/// The integral part of this literal, if it exists.
const fn decimal_part(&self) -> Option<&str> { .. }
/// The fractional part of this literal, if it exists.
const fn fractional_part(&self) -> Option<&str> { .. }
/// The exponent of this literal, if it exists.
const fn exponent(&self) -> Option<&str> { .. }
}
Alternatively, we could imagine something like
// imagine for simplicity that you can have multiple DSTs in the same
// struct... we'll just store the metadata at the top
struct FloatLit {
integral_part: [u8],
fractional_part: [u8],
negative_exponent: bool,
exponent: [u8],
}
where the byte arrays represent the parsed components in the target endianess, i.e.
12.34e56
// produces
FloatLit {
integral_part: transmute(12),
fractional_part: transmute(34),
negative_exponent: false,
exponent: transmute(56),
}