How are negative int/float literals handled during lexing/parsing?


#1

I’m trying to read the compiler code (mostly because I’m curious) and right now I’m trying to understand the handling of negative integer/float literals.

In token.rs we have:

pub enum Lit {
    ...
    Integer(ast::Name),
    Float(ast::Name),
    ...
}

So at this stage these literals are still just (interned) strings. In lexer/mod.rs we can see that the lexer doesn’t consume any plus/minus sign, so the above tokens don’t contain them.

In ast.rs we have:

pub enum Expr_ {
    ...
    /// A literal (For example: `1u8`, `"foo"`)
    ExprLit(P<Lit>),
    ...
}

pub enum Lit_ {
    ...
    /// An integer literal (`1u8`)
    LitInt(u64, LitIntType),
    /// A float literal (`1f64` or `1E10f64`)
    LitFloat(InternedString, FloatTy),
    /// A float literal without a suffix (`1.0 or 1.0E10`)
    LitFloatUnsuffixed(InternedString),
    ...
}

pub enum Sign {
    Minus,
    Plus
}

pub enum LitIntType {
    SignedIntLit(IntTy, Sign),
    UnsignedIntLit(UintTy),
    UnsuffixedIntLit(Sign)
}

I’d expect that somewhere in the code we’d construct e.g. an SignedIntLit with a Minus in it, but I cannot find a single place that does this after looking for all uses of ast::Minus ast::SignedIntLit, etc.

So my question is, since the sign isn’t lexed together with the literal, how is it eventually added to the literal that’s stored in in e.g. ast::LitInt?


#2

I have a PR that removes all the signs from the ast: https://github.com/rust-lang/rust/pull/30508

In the AST a “literal” like -5 is actually ExprUnary(UnOp::Neg, LitInt(5, UnsuffixedIntLit(Plus))). After my change it will be ExprUnary(UnOp::Neg, LitInt(5, UnsuffixedIntLit)).


#3

So it’s unused. That explains why I couldn’t find a use site. :smile:

Does this mean that when we emit constants to LLVM we somehow have to spot a ExprUnary(UnOp::Neg, Lit…) to emit a negative literal, or is this handled in some other way?


#4

yes. that code resides in rustc_trans/trans/consts.rs. But the future is MIR. Not sure how MIR does it.


#5

FYI, rustc can dump AST after parsing:

const X: i32 = -123456i32;

$ rustc -Z ast-json c.rs
{“module”:{“inner”:{“lo”:0,“hi”:26},“items”:[{“ident”:"",“attrs”:[{“node”:{“id”:{"_field0":921},“style”:“Outer”,“value”:{“node”:{“variant”:“MetaWord”,“fields”:[“prelude_import”]},“span”:{“lo”:0,“hi”:0}},“is_sugared_doc”:false},“span”:{“lo”:0,“hi”:0}}],“id”:2,“node”:{“variant”:“ItemUse”,“fields”:[{“node”:{“variant”:“ViewPathGlob”,“fields”:[{“span”:{“lo”:0,“hi”:0},“global”:false,“segments”:[{“identifier”:“std”,“parameters”:{“variant”:“AngleBracketed”,“fields”:[{“lifetimes”:[],“types”:[],“bindings”:[]}]}},{“identifier”:“prelude”,“parameters”:{“variant”:“AngleBracketed”,“fields”:[{“lifetimes”:[],“types”:[],“bindings”:[]}]}},{“identifier”:“v1”,“parameters”:{“variant”:“AngleBracketed”,“fields”:[{“lifetimes”:[],“types”:[],“bindings”:[]}]}}]}]},“span”:{“lo”:0,“hi”:0}}]},“vis”:“Inherited”,“span”:{“lo”:0,“hi”:0}},{“ident”:“std”,“attrs”:[{“node”:{“id”:{"_field0":0},“style”:“Outer”,“value”:{“node”:{“variant”:“MetaWord”,“fields”:[“macro_use”]},“span”:{“lo”:0,“hi”:0}},“is_sugared_doc”:false},“span”:{“lo”:0,“hi”:0}}],“id”:3,“node”:{“variant”:“ItemExternCrate”,“fields”:[“std”]},“vis”:“Inherited”,“span”:{“lo”:0,“hi”:0}},{“ident”:“X”,“attrs”:[],“id”:4,“node”:{“variant”:“ItemConst”,“fields”:[{“id”:5,“node”:{“variant”:“TyPath”,“fields”:[null,{“span”:{“lo”:9,“hi”:12},“global”:false,“segments”:[{“identifier”:“i32”,“parameters”:{“variant”:“AngleBracketed”,“fields”:[{“lifetimes”:[],“types”:[],“bindings”:[]}]}}]}]},“span”:{“lo”:9,“hi”:12}},{“id”:6,“node”:{“variant”:“ExprUnary”,“fields”:[“UnNeg”,{“id”:7,“node”:{“variant”:“ExprLit”,“fields”:[{“node”:{“variant”:“LitInt”,“fields”:[123456,{“variant”:“SignedIntLit”,“fields”:[“TyI32”,“Plus”]}]},“span”:{“lo”:16,“hi”:25}}]},“span”:{“lo”:16,“hi”:25},“attrs”:null}]},“span”:{“lo”:15,“hi”:25},“attrs”:null}]},“vis”:“Inherited”,“span”:{“lo”:0,“hi”:26}}]},“attrs”:[],“config”:[{“node”:{“variant”:“MetaNameValue”,“fields”:[“target_os”,{“node”:{“variant”:“LitStr”,“fields”:[“linux”,“CookedStr”]},“span”:{“lo”:0,“hi”:0}}]},“span”:{“lo”:0,“hi”:0}},{“node”:{“variant”:“MetaNameValue”,“fields”:[“target_family”,{“node”:{“variant”:“LitStr”,“fields”:[“unix”,“CookedStr”]},“span”:{“lo”:0,“hi”:0}}]},“span”:{“lo”:0,“hi”:0}},{“node”:{“variant”:“MetaNameValue”,“fields”:[“target_arch”,{“node”:{“variant”:“LitStr”,“fields”:[“x86_64”,“CookedStr”]},“span”:{“lo”:0,“hi”:0}}]},“span”:{“lo”:0,“hi”:0}},{“node”:{“variant”:“MetaNameValue”,“fields”:[“target_endian”,{“node”:{“variant”:“LitStr”,“fields”:[“little”,“CookedStr”]},“span”:{“lo”:0,“hi”:0}}]},“span”:{“lo”:0,“hi”:0}},{“node”:{“variant”:“MetaNameValue”,“fields”:[“target_pointer_width”,{“node”:{“variant”:“LitStr”,“fields”:[“64”,“CookedStr”]},“span”:{“lo”:0,“hi”:0}}]},“span”:{“lo”:0,“hi”:0}},{“node”:{“variant”:“MetaNameValue”,“fields”:[“target_env”,{“node”:{“variant”:“LitStr”,“fields”:[“gnu”,“CookedStr”]},“span”:{“lo”:0,“hi”:0}}]},“span”:{“lo”:0,“hi”:0}},{“node”:{“variant”:“MetaNameValue”,“fields”:[“target_vendor”,{“node”:{“variant”:“LitStr”,“fields”:[“unknown”,“CookedStr”]},“span”:{“lo”:0,“hi”:0}}]},“span”:{“lo”:0,“hi”:0}},{“node”:{“variant”:“MetaWord”,“fields”:[“unix”]},“span”:{“lo”:0,“hi”:0}},{“node”:{“variant”:“MetaWord”,“fields”:[“target_thread_local”]},“span”:{“lo”:0,“hi”:0}},{“node”:{“variant”:“MetaWord”,“fields”:[“debug_assertions”]},“span”:{“lo”:0,“hi”:0}},{“node”:{“variant”:“MetaNameValue”,“fields”:[“target_feature”,{“node”:{“variant”:“LitStr”,“fields”:[“sse”,“CookedStr”]},“span”:{“lo”:0,“hi”:0}}]},“span”:{“lo”:0,“hi”:0}},{“node”:{“variant”:“MetaNameValue”,“fields”:[“target_feature”,{“node”:{“variant”:“LitStr”,“fields”:[“sse2”,“CookedStr”]},“span”:{“lo”:0,“hi”:0}}]},“span”:{“lo”:0,“hi”:0}}],“span”:{“lo”:0,“hi”:25},“exported_macros”:[]}

$ rustc --version
rustc 1.8.0-dev (5d6e8fced 2016-01-26)