| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862 |
- // SPDX-License-Identifier: Apache-2.0 OR MIT
- #[cfg(feature = "parsing")]
- use crate::lookahead;
- #[cfg(feature = "parsing")]
- use crate::parse::{Parse, Parser};
- use crate::{Error, Result};
- use proc_macro2::{Ident, Literal, Span};
- #[cfg(feature = "parsing")]
- use proc_macro2::{TokenStream, TokenTree};
- use std::ffi::{CStr, CString};
- use std::fmt::{self, Display};
- #[cfg(feature = "extra-traits")]
- use std::hash::{Hash, Hasher};
- use std::str::{self, FromStr};
- ast_enum_of_structs! {
- /// A Rust literal such as a string or integer or boolean.
- ///
- /// # Syntax tree enum
- ///
- /// This type is a [syntax tree enum].
- ///
- /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums
- #[non_exhaustive]
- pub enum Lit {
- /// A UTF-8 string literal: `"foo"`.
- Str(LitStr),
- /// A byte string literal: `b"foo"`.
- ByteStr(LitByteStr),
- /// A nul-terminated C-string literal: `c"foo"`.
- CStr(LitCStr),
- /// A byte literal: `b'f'`.
- Byte(LitByte),
- /// A character literal: `'a'`.
- Char(LitChar),
- /// An integer literal: `1` or `1u16`.
- Int(LitInt),
- /// A floating point literal: `1f64` or `1.0e10f64`.
- ///
- /// Must be finite. May not be infinite or NaN.
- Float(LitFloat),
- /// A boolean literal: `true` or `false`.
- Bool(LitBool),
- /// A raw token literal not interpreted by Syn.
- Verbatim(Literal),
- }
- }
- ast_struct! {
- /// A UTF-8 string literal: `"foo"`.
- pub struct LitStr {
- repr: Box<LitRepr>,
- }
- }
- ast_struct! {
- /// A byte string literal: `b"foo"`.
- pub struct LitByteStr {
- repr: Box<LitRepr>,
- }
- }
- ast_struct! {
- /// A nul-terminated C-string literal: `c"foo"`.
- pub struct LitCStr {
- repr: Box<LitRepr>,
- }
- }
- ast_struct! {
- /// A byte literal: `b'f'`.
- pub struct LitByte {
- repr: Box<LitRepr>,
- }
- }
- ast_struct! {
- /// A character literal: `'a'`.
- pub struct LitChar {
- repr: Box<LitRepr>,
- }
- }
- struct LitRepr {
- token: Literal,
- suffix: Box<str>,
- }
- ast_struct! {
- /// An integer literal: `1` or `1u16`.
- pub struct LitInt {
- repr: Box<LitIntRepr>,
- }
- }
- struct LitIntRepr {
- token: Literal,
- digits: Box<str>,
- suffix: Box<str>,
- }
- ast_struct! {
- /// A floating point literal: `1f64` or `1.0e10f64`.
- ///
- /// Must be finite. May not be infinite or NaN.
- pub struct LitFloat {
- repr: Box<LitFloatRepr>,
- }
- }
- struct LitFloatRepr {
- token: Literal,
- digits: Box<str>,
- suffix: Box<str>,
- }
- ast_struct! {
- /// A boolean literal: `true` or `false`.
- pub struct LitBool {
- pub value: bool,
- pub span: Span,
- }
- }
- impl LitStr {
- pub fn new(value: &str, span: Span) -> Self {
- let mut token = Literal::string(value);
- token.set_span(span);
- LitStr {
- repr: Box::new(LitRepr {
- token,
- suffix: Box::<str>::default(),
- }),
- }
- }
- pub fn value(&self) -> String {
- let repr = self.repr.token.to_string();
- let (value, _suffix) = value::parse_lit_str(&repr);
- String::from(value)
- }
- /// Parse a syntax tree node from the content of this string literal.
- ///
- /// All spans in the syntax tree will point to the span of this `LitStr`.
- ///
- /// # Example
- ///
- /// ```
- /// use syn::{Attribute, Error, Expr, Lit, Meta, Path, Result};
- ///
- /// // Parses the path from an attribute that looks like:
- /// //
- /// // #[path = "a::b::c"]
- /// //
- /// // or returns `None` if the input is some other attribute.
- /// fn get_path(attr: &Attribute) -> Result<Option<Path>> {
- /// if !attr.path().is_ident("path") {
- /// return Ok(None);
- /// }
- ///
- /// if let Meta::NameValue(meta) = &attr.meta {
- /// if let Expr::Lit(expr) = &meta.value {
- /// if let Lit::Str(lit_str) = &expr.lit {
- /// return lit_str.parse().map(Some);
- /// }
- /// }
- /// }
- ///
- /// let message = "expected #[path = \"...\"]";
- /// Err(Error::new_spanned(attr, message))
- /// }
- /// ```
- #[cfg(feature = "parsing")]
- #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
- pub fn parse<T: Parse>(&self) -> Result<T> {
- self.parse_with(T::parse)
- }
- /// Invoke parser on the content of this string literal.
- ///
- /// All spans in the syntax tree will point to the span of this `LitStr`.
- ///
- /// # Example
- ///
- /// ```
- /// # use proc_macro2::Span;
- /// # use syn::{LitStr, Result};
- /// #
- /// # fn main() -> Result<()> {
- /// # let lit_str = LitStr::new("a::b::c", Span::call_site());
- /// #
- /// # const IGNORE: &str = stringify! {
- /// let lit_str: LitStr = /* ... */;
- /// # };
- ///
- /// // Parse a string literal like "a::b::c" into a Path, not allowing
- /// // generic arguments on any of the path segments.
- /// let basic_path = lit_str.parse_with(syn::Path::parse_mod_style)?;
- /// #
- /// # Ok(())
- /// # }
- /// ```
- #[cfg(feature = "parsing")]
- #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
- pub fn parse_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
- use proc_macro2::Group;
- // Token stream with every span replaced by the given one.
- fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
- stream
- .into_iter()
- .map(|token| respan_token_tree(token, span))
- .collect()
- }
- // Token tree with every span replaced by the given one.
- fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
- match &mut token {
- TokenTree::Group(g) => {
- let stream = respan_token_stream(g.stream(), span);
- *g = Group::new(g.delimiter(), stream);
- g.set_span(span);
- }
- other => other.set_span(span),
- }
- token
- }
- // Parse string literal into a token stream with every span equal to the
- // original literal's span.
- let span = self.span();
- let mut tokens = TokenStream::from_str(&self.value())?;
- tokens = respan_token_stream(tokens, span);
- let result = crate::parse::parse_scoped(parser, span, tokens)?;
- let suffix = self.suffix();
- if !suffix.is_empty() {
- return Err(Error::new(
- self.span(),
- format!("unexpected suffix `{}` on string literal", suffix),
- ));
- }
- Ok(result)
- }
- pub fn span(&self) -> Span {
- self.repr.token.span()
- }
- pub fn set_span(&mut self, span: Span) {
- self.repr.token.set_span(span);
- }
- pub fn suffix(&self) -> &str {
- &self.repr.suffix
- }
- pub fn token(&self) -> Literal {
- self.repr.token.clone()
- }
- }
- impl LitByteStr {
- pub fn new(value: &[u8], span: Span) -> Self {
- let mut token = Literal::byte_string(value);
- token.set_span(span);
- LitByteStr {
- repr: Box::new(LitRepr {
- token,
- suffix: Box::<str>::default(),
- }),
- }
- }
- pub fn value(&self) -> Vec<u8> {
- let repr = self.repr.token.to_string();
- let (value, _suffix) = value::parse_lit_byte_str(&repr);
- value
- }
- pub fn span(&self) -> Span {
- self.repr.token.span()
- }
- pub fn set_span(&mut self, span: Span) {
- self.repr.token.set_span(span);
- }
- pub fn suffix(&self) -> &str {
- &self.repr.suffix
- }
- pub fn token(&self) -> Literal {
- self.repr.token.clone()
- }
- }
- impl LitCStr {
- pub fn new(value: &CStr, span: Span) -> Self {
- let mut token = Literal::c_string(value);
- token.set_span(span);
- LitCStr {
- repr: Box::new(LitRepr {
- token,
- suffix: Box::<str>::default(),
- }),
- }
- }
- pub fn value(&self) -> CString {
- let repr = self.repr.token.to_string();
- let (value, _suffix) = value::parse_lit_c_str(&repr);
- value
- }
- pub fn span(&self) -> Span {
- self.repr.token.span()
- }
- pub fn set_span(&mut self, span: Span) {
- self.repr.token.set_span(span);
- }
- pub fn suffix(&self) -> &str {
- &self.repr.suffix
- }
- pub fn token(&self) -> Literal {
- self.repr.token.clone()
- }
- }
- impl LitByte {
- pub fn new(value: u8, span: Span) -> Self {
- let mut token = Literal::u8_suffixed(value);
- token.set_span(span);
- LitByte {
- repr: Box::new(LitRepr {
- token,
- suffix: Box::<str>::default(),
- }),
- }
- }
- pub fn value(&self) -> u8 {
- let repr = self.repr.token.to_string();
- let (value, _suffix) = value::parse_lit_byte(&repr);
- value
- }
- pub fn span(&self) -> Span {
- self.repr.token.span()
- }
- pub fn set_span(&mut self, span: Span) {
- self.repr.token.set_span(span);
- }
- pub fn suffix(&self) -> &str {
- &self.repr.suffix
- }
- pub fn token(&self) -> Literal {
- self.repr.token.clone()
- }
- }
- impl LitChar {
- pub fn new(value: char, span: Span) -> Self {
- let mut token = Literal::character(value);
- token.set_span(span);
- LitChar {
- repr: Box::new(LitRepr {
- token,
- suffix: Box::<str>::default(),
- }),
- }
- }
- pub fn value(&self) -> char {
- let repr = self.repr.token.to_string();
- let (value, _suffix) = value::parse_lit_char(&repr);
- value
- }
- pub fn span(&self) -> Span {
- self.repr.token.span()
- }
- pub fn set_span(&mut self, span: Span) {
- self.repr.token.set_span(span);
- }
- pub fn suffix(&self) -> &str {
- &self.repr.suffix
- }
- pub fn token(&self) -> Literal {
- self.repr.token.clone()
- }
- }
- impl LitInt {
- pub fn new(repr: &str, span: Span) -> Self {
- let (digits, suffix) = match value::parse_lit_int(repr) {
- Some(parse) => parse,
- None => panic!("not an integer literal: `{}`", repr),
- };
- let mut token: Literal = repr.parse().unwrap();
- token.set_span(span);
- LitInt {
- repr: Box::new(LitIntRepr {
- token,
- digits,
- suffix,
- }),
- }
- }
- pub fn base10_digits(&self) -> &str {
- &self.repr.digits
- }
- /// Parses the literal into a selected number type.
- ///
- /// This is equivalent to `lit.base10_digits().parse()` except that the
- /// resulting errors will be correctly spanned to point to the literal token
- /// in the macro input.
- ///
- /// ```
- /// use syn::LitInt;
- /// use syn::parse::{Parse, ParseStream, Result};
- ///
- /// struct Port {
- /// value: u16,
- /// }
- ///
- /// impl Parse for Port {
- /// fn parse(input: ParseStream) -> Result<Self> {
- /// let lit: LitInt = input.parse()?;
- /// let value = lit.base10_parse::<u16>()?;
- /// Ok(Port { value })
- /// }
- /// }
- /// ```
- pub fn base10_parse<N>(&self) -> Result<N>
- where
- N: FromStr,
- N::Err: Display,
- {
- self.base10_digits()
- .parse()
- .map_err(|err| Error::new(self.span(), err))
- }
- pub fn suffix(&self) -> &str {
- &self.repr.suffix
- }
- pub fn span(&self) -> Span {
- self.repr.token.span()
- }
- pub fn set_span(&mut self, span: Span) {
- self.repr.token.set_span(span);
- }
- pub fn token(&self) -> Literal {
- self.repr.token.clone()
- }
- }
- impl From<Literal> for LitInt {
- fn from(token: Literal) -> Self {
- let repr = token.to_string();
- if let Some((digits, suffix)) = value::parse_lit_int(&repr) {
- LitInt {
- repr: Box::new(LitIntRepr {
- token,
- digits,
- suffix,
- }),
- }
- } else {
- panic!("not an integer literal: `{}`", repr);
- }
- }
- }
- impl Display for LitInt {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- self.repr.token.fmt(formatter)
- }
- }
- impl LitFloat {
- pub fn new(repr: &str, span: Span) -> Self {
- let (digits, suffix) = match value::parse_lit_float(repr) {
- Some(parse) => parse,
- None => panic!("not a float literal: `{}`", repr),
- };
- let mut token: Literal = repr.parse().unwrap();
- token.set_span(span);
- LitFloat {
- repr: Box::new(LitFloatRepr {
- token,
- digits,
- suffix,
- }),
- }
- }
- pub fn base10_digits(&self) -> &str {
- &self.repr.digits
- }
- pub fn base10_parse<N>(&self) -> Result<N>
- where
- N: FromStr,
- N::Err: Display,
- {
- self.base10_digits()
- .parse()
- .map_err(|err| Error::new(self.span(), err))
- }
- pub fn suffix(&self) -> &str {
- &self.repr.suffix
- }
- pub fn span(&self) -> Span {
- self.repr.token.span()
- }
- pub fn set_span(&mut self, span: Span) {
- self.repr.token.set_span(span);
- }
- pub fn token(&self) -> Literal {
- self.repr.token.clone()
- }
- }
- impl From<Literal> for LitFloat {
- fn from(token: Literal) -> Self {
- let repr = token.to_string();
- if let Some((digits, suffix)) = value::parse_lit_float(&repr) {
- LitFloat {
- repr: Box::new(LitFloatRepr {
- token,
- digits,
- suffix,
- }),
- }
- } else {
- panic!("not a float literal: `{}`", repr);
- }
- }
- }
- impl Display for LitFloat {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- self.repr.token.fmt(formatter)
- }
- }
- impl LitBool {
- pub fn new(value: bool, span: Span) -> Self {
- LitBool { value, span }
- }
- pub fn value(&self) -> bool {
- self.value
- }
- pub fn span(&self) -> Span {
- self.span
- }
- pub fn set_span(&mut self, span: Span) {
- self.span = span;
- }
- pub fn token(&self) -> Ident {
- let s = if self.value { "true" } else { "false" };
- Ident::new(s, self.span)
- }
- }
- #[cfg(feature = "extra-traits")]
- mod debug_impls {
- use crate::lit::{LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitInt, LitStr};
- use std::fmt::{self, Debug};
- #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
- impl Debug for LitStr {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- self.debug(formatter, "LitStr")
- }
- }
- impl LitStr {
- pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
- formatter
- .debug_struct(name)
- .field("token", &format_args!("{}", self.repr.token))
- .finish()
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
- impl Debug for LitByteStr {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- self.debug(formatter, "LitByteStr")
- }
- }
- impl LitByteStr {
- pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
- formatter
- .debug_struct(name)
- .field("token", &format_args!("{}", self.repr.token))
- .finish()
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
- impl Debug for LitCStr {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- self.debug(formatter, "LitCStr")
- }
- }
- impl LitCStr {
- pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
- formatter
- .debug_struct(name)
- .field("token", &format_args!("{}", self.repr.token))
- .finish()
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
- impl Debug for LitByte {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- self.debug(formatter, "LitByte")
- }
- }
- impl LitByte {
- pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
- formatter
- .debug_struct(name)
- .field("token", &format_args!("{}", self.repr.token))
- .finish()
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
- impl Debug for LitChar {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- self.debug(formatter, "LitChar")
- }
- }
- impl LitChar {
- pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
- formatter
- .debug_struct(name)
- .field("token", &format_args!("{}", self.repr.token))
- .finish()
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
- impl Debug for LitInt {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- self.debug(formatter, "LitInt")
- }
- }
- impl LitInt {
- pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
- formatter
- .debug_struct(name)
- .field("token", &format_args!("{}", self.repr.token))
- .finish()
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
- impl Debug for LitFloat {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- self.debug(formatter, "LitFloat")
- }
- }
- impl LitFloat {
- pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
- formatter
- .debug_struct(name)
- .field("token", &format_args!("{}", self.repr.token))
- .finish()
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
- impl Debug for LitBool {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- self.debug(formatter, "LitBool")
- }
- }
- impl LitBool {
- pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
- formatter
- .debug_struct(name)
- .field("value", &self.value)
- .finish()
- }
- }
- }
- #[cfg(feature = "clone-impls")]
- #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
- impl Clone for LitRepr {
- fn clone(&self) -> Self {
- LitRepr {
- token: self.token.clone(),
- suffix: self.suffix.clone(),
- }
- }
- }
- #[cfg(feature = "clone-impls")]
- #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
- impl Clone for LitIntRepr {
- fn clone(&self) -> Self {
- LitIntRepr {
- token: self.token.clone(),
- digits: self.digits.clone(),
- suffix: self.suffix.clone(),
- }
- }
- }
- #[cfg(feature = "clone-impls")]
- #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
- impl Clone for LitFloatRepr {
- fn clone(&self) -> Self {
- LitFloatRepr {
- token: self.token.clone(),
- digits: self.digits.clone(),
- suffix: self.suffix.clone(),
- }
- }
- }
- macro_rules! lit_extra_traits {
- ($ty:ident) => {
- #[cfg(feature = "clone-impls")]
- #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
- impl Clone for $ty {
- fn clone(&self) -> Self {
- $ty {
- repr: self.repr.clone(),
- }
- }
- }
- #[cfg(feature = "extra-traits")]
- #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
- impl PartialEq for $ty {
- fn eq(&self, other: &Self) -> bool {
- self.repr.token.to_string() == other.repr.token.to_string()
- }
- }
- #[cfg(feature = "extra-traits")]
- #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
- impl Hash for $ty {
- fn hash<H>(&self, state: &mut H)
- where
- H: Hasher,
- {
- self.repr.token.to_string().hash(state);
- }
- }
- #[cfg(feature = "parsing")]
- pub_if_not_doc! {
- #[doc(hidden)]
- #[allow(non_snake_case)]
- pub fn $ty(marker: lookahead::TokenMarker) -> $ty {
- match marker {}
- }
- }
- };
- }
- lit_extra_traits!(LitStr);
- lit_extra_traits!(LitByteStr);
- lit_extra_traits!(LitCStr);
- lit_extra_traits!(LitByte);
- lit_extra_traits!(LitChar);
- lit_extra_traits!(LitInt);
- lit_extra_traits!(LitFloat);
- #[cfg(feature = "parsing")]
- pub_if_not_doc! {
- #[doc(hidden)]
- #[allow(non_snake_case)]
- pub fn LitBool(marker: lookahead::TokenMarker) -> LitBool {
- match marker {}
- }
- }
- /// The style of a string literal, either plain quoted or a raw string like
- /// `r##"data"##`.
- #[doc(hidden)] // https://github.com/dtolnay/syn/issues/1566
- pub enum StrStyle {
- /// An ordinary string like `"data"`.
- Cooked,
- /// A raw string like `r##"data"##`.
- ///
- /// The unsigned integer is the number of `#` symbols used.
- Raw(usize),
- }
- #[cfg(feature = "parsing")]
- pub_if_not_doc! {
- #[doc(hidden)]
- #[allow(non_snake_case)]
- pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
- match marker {}
- }
- }
- #[cfg(feature = "parsing")]
- pub(crate) mod parsing {
- use crate::buffer::Cursor;
- use crate::error::Result;
- use crate::lit::{
- value, Lit, LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitFloatRepr, LitInt,
- LitIntRepr, LitStr,
- };
- use crate::parse::{Parse, ParseStream, Unexpected};
- use crate::token::{self, Token};
- use proc_macro2::{Literal, Punct, Span};
- use std::cell::Cell;
- use std::rc::Rc;
- #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
- impl Parse for Lit {
- fn parse(input: ParseStream) -> Result<Self> {
- input.step(|cursor| {
- if let Some((lit, rest)) = cursor.literal() {
- return Ok((Lit::new(lit), rest));
- }
- if let Some((ident, rest)) = cursor.ident() {
- let value = ident == "true";
- if value || ident == "false" {
- let lit_bool = LitBool {
- value,
- span: ident.span(),
- };
- return Ok((Lit::Bool(lit_bool), rest));
- }
- }
- if let Some((punct, rest)) = cursor.punct() {
- if punct.as_char() == '-' {
- if let Some((lit, rest)) = parse_negative_lit(punct, rest) {
- return Ok((lit, rest));
- }
- }
- }
- Err(cursor.error("expected literal"))
- })
- }
- }
- fn parse_negative_lit(neg: Punct, cursor: Cursor) -> Option<(Lit, Cursor)> {
- let (lit, rest) = cursor.literal()?;
- let mut span = neg.span();
- span = span.join(lit.span()).unwrap_or(span);
- let mut repr = lit.to_string();
- repr.insert(0, '-');
- if let Some((digits, suffix)) = value::parse_lit_int(&repr) {
- let mut token: Literal = repr.parse().unwrap();
- token.set_span(span);
- return Some((
- Lit::Int(LitInt {
- repr: Box::new(LitIntRepr {
- token,
- digits,
- suffix,
- }),
- }),
- rest,
- ));
- }
- let (digits, suffix) = value::parse_lit_float(&repr)?;
- let mut token: Literal = repr.parse().unwrap();
- token.set_span(span);
- Some((
- Lit::Float(LitFloat {
- repr: Box::new(LitFloatRepr {
- token,
- digits,
- suffix,
- }),
- }),
- rest,
- ))
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
- impl Parse for LitStr {
- fn parse(input: ParseStream) -> Result<Self> {
- let head = input.fork();
- match input.parse() {
- Ok(Lit::Str(lit)) => Ok(lit),
- _ => Err(head.error("expected string literal")),
- }
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
- impl Parse for LitByteStr {
- fn parse(input: ParseStream) -> Result<Self> {
- let head = input.fork();
- match input.parse() {
- Ok(Lit::ByteStr(lit)) => Ok(lit),
- _ => Err(head.error("expected byte string literal")),
- }
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
- impl Parse for LitCStr {
- fn parse(input: ParseStream) -> Result<Self> {
- let head = input.fork();
- match input.parse() {
- Ok(Lit::CStr(lit)) => Ok(lit),
- _ => Err(head.error("expected C string literal")),
- }
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
- impl Parse for LitByte {
- fn parse(input: ParseStream) -> Result<Self> {
- let head = input.fork();
- match input.parse() {
- Ok(Lit::Byte(lit)) => Ok(lit),
- _ => Err(head.error("expected byte literal")),
- }
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
- impl Parse for LitChar {
- fn parse(input: ParseStream) -> Result<Self> {
- let head = input.fork();
- match input.parse() {
- Ok(Lit::Char(lit)) => Ok(lit),
- _ => Err(head.error("expected character literal")),
- }
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
- impl Parse for LitInt {
- fn parse(input: ParseStream) -> Result<Self> {
- let head = input.fork();
- match input.parse() {
- Ok(Lit::Int(lit)) => Ok(lit),
- _ => Err(head.error("expected integer literal")),
- }
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
- impl Parse for LitFloat {
- fn parse(input: ParseStream) -> Result<Self> {
- let head = input.fork();
- match input.parse() {
- Ok(Lit::Float(lit)) => Ok(lit),
- _ => Err(head.error("expected floating point literal")),
- }
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
- impl Parse for LitBool {
- fn parse(input: ParseStream) -> Result<Self> {
- let head = input.fork();
- match input.parse() {
- Ok(Lit::Bool(lit)) => Ok(lit),
- _ => Err(head.error("expected boolean literal")),
- }
- }
- }
- fn peek_impl(cursor: Cursor, peek: fn(ParseStream) -> bool) -> bool {
- let scope = Span::call_site();
- let unexpected = Rc::new(Cell::new(Unexpected::None));
- let buffer = crate::parse::new_parse_buffer(scope, cursor, unexpected);
- peek(&buffer)
- }
- macro_rules! impl_token {
- ($display:literal $name:ty) => {
- impl Token for $name {
- fn peek(cursor: Cursor) -> bool {
- fn peek(input: ParseStream) -> bool {
- <$name as Parse>::parse(input).is_ok()
- }
- peek_impl(cursor, peek)
- }
- fn display() -> &'static str {
- $display
- }
- }
- impl token::private::Sealed for $name {}
- };
- }
- impl_token!("literal" Lit);
- impl_token!("string literal" LitStr);
- impl_token!("byte string literal" LitByteStr);
- impl_token!("C-string literal" LitCStr);
- impl_token!("byte literal" LitByte);
- impl_token!("character literal" LitChar);
- impl_token!("integer literal" LitInt);
- impl_token!("floating point literal" LitFloat);
- impl_token!("boolean literal" LitBool);
- }
- #[cfg(feature = "printing")]
- mod printing {
- use crate::lit::{LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitInt, LitStr};
- use proc_macro2::TokenStream;
- use quote::{ToTokens, TokenStreamExt};
- #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
- impl ToTokens for LitStr {
- fn to_tokens(&self, tokens: &mut TokenStream) {
- self.repr.token.to_tokens(tokens);
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
- impl ToTokens for LitByteStr {
- fn to_tokens(&self, tokens: &mut TokenStream) {
- self.repr.token.to_tokens(tokens);
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
- impl ToTokens for LitCStr {
- fn to_tokens(&self, tokens: &mut TokenStream) {
- self.repr.token.to_tokens(tokens);
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
- impl ToTokens for LitByte {
- fn to_tokens(&self, tokens: &mut TokenStream) {
- self.repr.token.to_tokens(tokens);
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
- impl ToTokens for LitChar {
- fn to_tokens(&self, tokens: &mut TokenStream) {
- self.repr.token.to_tokens(tokens);
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
- impl ToTokens for LitInt {
- fn to_tokens(&self, tokens: &mut TokenStream) {
- self.repr.token.to_tokens(tokens);
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
- impl ToTokens for LitFloat {
- fn to_tokens(&self, tokens: &mut TokenStream) {
- self.repr.token.to_tokens(tokens);
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
- impl ToTokens for LitBool {
- fn to_tokens(&self, tokens: &mut TokenStream) {
- tokens.append(self.token());
- }
- }
- }
- mod value {
- use crate::bigint::BigInt;
- use crate::lit::{
- Lit, LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitFloatRepr, LitInt,
- LitIntRepr, LitRepr, LitStr,
- };
- use proc_macro2::{Literal, Span};
- use std::ascii;
- use std::char;
- use std::ffi::CString;
- use std::ops::{Index, RangeFrom};
- impl Lit {
- /// Interpret a Syn literal from a proc-macro2 literal.
- pub fn new(token: Literal) -> Self {
- let repr = token.to_string();
- match byte(&repr, 0) {
- // "...", r"...", r#"..."#
- b'"' | b'r' => {
- let (_, suffix) = parse_lit_str(&repr);
- return Lit::Str(LitStr {
- repr: Box::new(LitRepr { token, suffix }),
- });
- }
- b'b' => match byte(&repr, 1) {
- // b"...", br"...", br#"...#"
- b'"' | b'r' => {
- let (_, suffix) = parse_lit_byte_str(&repr);
- return Lit::ByteStr(LitByteStr {
- repr: Box::new(LitRepr { token, suffix }),
- });
- }
- // b'...'
- b'\'' => {
- let (_, suffix) = parse_lit_byte(&repr);
- return Lit::Byte(LitByte {
- repr: Box::new(LitRepr { token, suffix }),
- });
- }
- _ => {}
- },
- // c"...", cr"...", cr#"..."#
- b'c' => {
- let (_, suffix) = parse_lit_c_str(&repr);
- return Lit::CStr(LitCStr {
- repr: Box::new(LitRepr { token, suffix }),
- });
- }
- // '...'
- b'\'' => {
- let (_, suffix) = parse_lit_char(&repr);
- return Lit::Char(LitChar {
- repr: Box::new(LitRepr { token, suffix }),
- });
- }
- b'0'..=b'9' | b'-' => {
- // 0, 123, 0xFF, 0o77, 0b11
- if let Some((digits, suffix)) = parse_lit_int(&repr) {
- return Lit::Int(LitInt {
- repr: Box::new(LitIntRepr {
- token,
- digits,
- suffix,
- }),
- });
- }
- // 1.0, 1e-1, 1e+1
- if let Some((digits, suffix)) = parse_lit_float(&repr) {
- return Lit::Float(LitFloat {
- repr: Box::new(LitFloatRepr {
- token,
- digits,
- suffix,
- }),
- });
- }
- }
- // true, false
- b't' | b'f' => {
- if repr == "true" || repr == "false" {
- return Lit::Bool(LitBool {
- value: repr == "true",
- span: token.span(),
- });
- }
- }
- b'(' if repr == "(/*ERROR*/)" => return Lit::Verbatim(token),
- _ => {}
- }
- panic!("unrecognized literal: `{}`", repr);
- }
- pub fn suffix(&self) -> &str {
- match self {
- Lit::Str(lit) => lit.suffix(),
- Lit::ByteStr(lit) => lit.suffix(),
- Lit::CStr(lit) => lit.suffix(),
- Lit::Byte(lit) => lit.suffix(),
- Lit::Char(lit) => lit.suffix(),
- Lit::Int(lit) => lit.suffix(),
- Lit::Float(lit) => lit.suffix(),
- Lit::Bool(_) | Lit::Verbatim(_) => "",
- }
- }
- pub fn span(&self) -> Span {
- match self {
- Lit::Str(lit) => lit.span(),
- Lit::ByteStr(lit) => lit.span(),
- Lit::CStr(lit) => lit.span(),
- Lit::Byte(lit) => lit.span(),
- Lit::Char(lit) => lit.span(),
- Lit::Int(lit) => lit.span(),
- Lit::Float(lit) => lit.span(),
- Lit::Bool(lit) => lit.span,
- Lit::Verbatim(lit) => lit.span(),
- }
- }
- pub fn set_span(&mut self, span: Span) {
- match self {
- Lit::Str(lit) => lit.set_span(span),
- Lit::ByteStr(lit) => lit.set_span(span),
- Lit::CStr(lit) => lit.set_span(span),
- Lit::Byte(lit) => lit.set_span(span),
- Lit::Char(lit) => lit.set_span(span),
- Lit::Int(lit) => lit.set_span(span),
- Lit::Float(lit) => lit.set_span(span),
- Lit::Bool(lit) => lit.span = span,
- Lit::Verbatim(lit) => lit.set_span(span),
- }
- }
- }
- /// Get the byte at offset idx, or a default of `b'\0'` if we're looking
- /// past the end of the input buffer.
- pub(crate) fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
- let s = s.as_ref();
- if idx < s.len() {
- s[idx]
- } else {
- 0
- }
- }
- fn next_chr(s: &str) -> char {
- s.chars().next().unwrap_or('\0')
- }
- // Returns (content, suffix).
- pub(crate) fn parse_lit_str(s: &str) -> (Box<str>, Box<str>) {
- match byte(s, 0) {
- b'"' => parse_lit_str_cooked(s),
- b'r' => parse_lit_str_raw(s),
- _ => unreachable!(),
- }
- }
- fn parse_lit_str_cooked(mut s: &str) -> (Box<str>, Box<str>) {
- assert_eq!(byte(s, 0), b'"');
- s = &s[1..];
- let mut content = String::new();
- 'outer: loop {
- let ch = match byte(s, 0) {
- b'"' => break,
- b'\\' => {
- let b = byte(s, 1);
- s = &s[2..];
- match b {
- b'x' => {
- let (byte, rest) = backslash_x(s);
- s = rest;
- assert!(byte <= 0x7F, "invalid \\x byte in string literal");
- char::from_u32(u32::from(byte)).unwrap()
- }
- b'u' => {
- let (ch, rest) = backslash_u(s);
- s = rest;
- ch
- }
- b'n' => '\n',
- b'r' => '\r',
- b't' => '\t',
- b'\\' => '\\',
- b'0' => '\0',
- b'\'' => '\'',
- b'"' => '"',
- b'\r' | b'\n' => loop {
- let b = byte(s, 0);
- match b {
- b' ' | b'\t' | b'\n' | b'\r' => s = &s[1..],
- _ => continue 'outer,
- }
- },
- b => panic!(
- "unexpected byte '{}' after \\ character in string literal",
- ascii::escape_default(b),
- ),
- }
- }
- b'\r' => {
- assert_eq!(byte(s, 1), b'\n', "bare CR not allowed in string");
- s = &s[2..];
- '\n'
- }
- _ => {
- let ch = next_chr(s);
- s = &s[ch.len_utf8()..];
- ch
- }
- };
- content.push(ch);
- }
- assert!(s.starts_with('"'));
- let content = content.into_boxed_str();
- let suffix = s[1..].to_owned().into_boxed_str();
- (content, suffix)
- }
- fn parse_lit_str_raw(mut s: &str) -> (Box<str>, Box<str>) {
- assert_eq!(byte(s, 0), b'r');
- s = &s[1..];
- let mut pounds = 0;
- while byte(s, pounds) == b'#' {
- pounds += 1;
- }
- assert_eq!(byte(s, pounds), b'"');
- let close = s.rfind('"').unwrap();
- for end in s[close + 1..close + 1 + pounds].bytes() {
- assert_eq!(end, b'#');
- }
- let content = s[pounds + 1..close].to_owned().into_boxed_str();
- let suffix = s[close + 1 + pounds..].to_owned().into_boxed_str();
- (content, suffix)
- }
- // Returns (content, suffix).
- pub(crate) fn parse_lit_byte_str(s: &str) -> (Vec<u8>, Box<str>) {
- assert_eq!(byte(s, 0), b'b');
- match byte(s, 1) {
- b'"' => parse_lit_byte_str_cooked(s),
- b'r' => parse_lit_byte_str_raw(s),
- _ => unreachable!(),
- }
- }
- fn parse_lit_byte_str_cooked(mut s: &str) -> (Vec<u8>, Box<str>) {
- assert_eq!(byte(s, 0), b'b');
- assert_eq!(byte(s, 1), b'"');
- s = &s[2..];
- // We're going to want to have slices which don't respect codepoint boundaries.
- let mut v = s.as_bytes();
- let mut out = Vec::new();
- 'outer: loop {
- let byte = match byte(v, 0) {
- b'"' => break,
- b'\\' => {
- let b = byte(v, 1);
- v = &v[2..];
- match b {
- b'x' => {
- let (b, rest) = backslash_x(v);
- v = rest;
- b
- }
- b'n' => b'\n',
- b'r' => b'\r',
- b't' => b'\t',
- b'\\' => b'\\',
- b'0' => b'\0',
- b'\'' => b'\'',
- b'"' => b'"',
- b'\r' | b'\n' => loop {
- let byte = byte(v, 0);
- if matches!(byte, b' ' | b'\t' | b'\n' | b'\r') {
- v = &v[1..];
- } else {
- continue 'outer;
- }
- },
- b => panic!(
- "unexpected byte '{}' after \\ character in byte-string literal",
- ascii::escape_default(b),
- ),
- }
- }
- b'\r' => {
- assert_eq!(byte(v, 1), b'\n', "bare CR not allowed in string");
- v = &v[2..];
- b'\n'
- }
- b => {
- v = &v[1..];
- b
- }
- };
- out.push(byte);
- }
- assert_eq!(byte(v, 0), b'"');
- let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str();
- (out, suffix)
- }
- fn parse_lit_byte_str_raw(s: &str) -> (Vec<u8>, Box<str>) {
- assert_eq!(byte(s, 0), b'b');
- let (value, suffix) = parse_lit_str_raw(&s[1..]);
- (String::from(value).into_bytes(), suffix)
- }
- // Returns (content, suffix).
- pub(crate) fn parse_lit_c_str(s: &str) -> (CString, Box<str>) {
- assert_eq!(byte(s, 0), b'c');
- match byte(s, 1) {
- b'"' => parse_lit_c_str_cooked(s),
- b'r' => parse_lit_c_str_raw(s),
- _ => unreachable!(),
- }
- }
- fn parse_lit_c_str_cooked(mut s: &str) -> (CString, Box<str>) {
- assert_eq!(byte(s, 0), b'c');
- assert_eq!(byte(s, 1), b'"');
- s = &s[2..];
- // We're going to want to have slices which don't respect codepoint boundaries.
- let mut v = s.as_bytes();
- let mut out = Vec::new();
- 'outer: loop {
- let byte = match byte(v, 0) {
- b'"' => break,
- b'\\' => {
- let b = byte(v, 1);
- v = &v[2..];
- match b {
- b'x' => {
- let (b, rest) = backslash_x(v);
- assert!(b != 0, "\\x00 is not allowed in C-string literal");
- v = rest;
- b
- }
- b'u' => {
- let (ch, rest) = backslash_u(v);
- assert!(ch != '\0', "\\u{{0}} is not allowed in C-string literal");
- v = rest;
- out.extend_from_slice(ch.encode_utf8(&mut [0u8; 4]).as_bytes());
- continue 'outer;
- }
- b'n' => b'\n',
- b'r' => b'\r',
- b't' => b'\t',
- b'\\' => b'\\',
- b'\'' => b'\'',
- b'"' => b'"',
- b'\r' | b'\n' => loop {
- let byte = byte(v, 0);
- if matches!(byte, b' ' | b'\t' | b'\n' | b'\r') {
- v = &v[1..];
- } else {
- continue 'outer;
- }
- },
- b => panic!(
- "unexpected byte '{}' after \\ character in byte literal",
- ascii::escape_default(b),
- ),
- }
- }
- b'\r' => {
- assert_eq!(byte(v, 1), b'\n', "bare CR not allowed in string");
- v = &v[2..];
- b'\n'
- }
- b => {
- v = &v[1..];
- b
- }
- };
- out.push(byte);
- }
- assert_eq!(byte(v, 0), b'"');
- let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str();
- (CString::new(out).unwrap(), suffix)
- }
- fn parse_lit_c_str_raw(s: &str) -> (CString, Box<str>) {
- assert_eq!(byte(s, 0), b'c');
- let (value, suffix) = parse_lit_str_raw(&s[1..]);
- (CString::new(String::from(value)).unwrap(), suffix)
- }
- // Returns (value, suffix).
- pub(crate) fn parse_lit_byte(s: &str) -> (u8, Box<str>) {
- assert_eq!(byte(s, 0), b'b');
- assert_eq!(byte(s, 1), b'\'');
- // We're going to want to have slices which don't respect codepoint boundaries.
- let mut v = &s.as_bytes()[2..];
- let b = match byte(v, 0) {
- b'\\' => {
- let b = byte(v, 1);
- v = &v[2..];
- match b {
- b'x' => {
- let (b, rest) = backslash_x(v);
- v = rest;
- b
- }
- b'n' => b'\n',
- b'r' => b'\r',
- b't' => b'\t',
- b'\\' => b'\\',
- b'0' => b'\0',
- b'\'' => b'\'',
- b'"' => b'"',
- b => panic!(
- "unexpected byte '{}' after \\ character in byte literal",
- ascii::escape_default(b),
- ),
- }
- }
- b => {
- v = &v[1..];
- b
- }
- };
- assert_eq!(byte(v, 0), b'\'');
- let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str();
- (b, suffix)
- }
- // Returns (value, suffix).
- pub(crate) fn parse_lit_char(mut s: &str) -> (char, Box<str>) {
- assert_eq!(byte(s, 0), b'\'');
- s = &s[1..];
- let ch = match byte(s, 0) {
- b'\\' => {
- let b = byte(s, 1);
- s = &s[2..];
- match b {
- b'x' => {
- let (byte, rest) = backslash_x(s);
- s = rest;
- assert!(byte <= 0x7F, "invalid \\x byte in character literal");
- char::from_u32(u32::from(byte)).unwrap()
- }
- b'u' => {
- let (ch, rest) = backslash_u(s);
- s = rest;
- ch
- }
- b'n' => '\n',
- b'r' => '\r',
- b't' => '\t',
- b'\\' => '\\',
- b'0' => '\0',
- b'\'' => '\'',
- b'"' => '"',
- b => panic!(
- "unexpected byte '{}' after \\ character in character literal",
- ascii::escape_default(b),
- ),
- }
- }
- _ => {
- let ch = next_chr(s);
- s = &s[ch.len_utf8()..];
- ch
- }
- };
- assert_eq!(byte(s, 0), b'\'');
- let suffix = s[1..].to_owned().into_boxed_str();
- (ch, suffix)
- }
- fn backslash_x<S>(s: &S) -> (u8, &S)
- where
- S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
- {
- let mut ch = 0;
- let b0 = byte(s, 0);
- let b1 = byte(s, 1);
- ch += 0x10
- * match b0 {
- b'0'..=b'9' => b0 - b'0',
- b'a'..=b'f' => 10 + (b0 - b'a'),
- b'A'..=b'F' => 10 + (b0 - b'A'),
- _ => panic!("unexpected non-hex character after \\x"),
- };
- ch += match b1 {
- b'0'..=b'9' => b1 - b'0',
- b'a'..=b'f' => 10 + (b1 - b'a'),
- b'A'..=b'F' => 10 + (b1 - b'A'),
- _ => panic!("unexpected non-hex character after \\x"),
- };
- (ch, &s[2..])
- }
- fn backslash_u<S>(mut s: &S) -> (char, &S)
- where
- S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
- {
- if byte(s, 0) != b'{' {
- panic!("{}", "expected { after \\u");
- }
- s = &s[1..];
- let mut ch = 0;
- let mut digits = 0;
- loop {
- let b = byte(s, 0);
- let digit = match b {
- b'0'..=b'9' => b - b'0',
- b'a'..=b'f' => 10 + b - b'a',
- b'A'..=b'F' => 10 + b - b'A',
- b'_' if digits > 0 => {
- s = &s[1..];
- continue;
- }
- b'}' if digits == 0 => panic!("invalid empty unicode escape"),
- b'}' => break,
- _ => panic!("unexpected non-hex character after \\u"),
- };
- if digits == 6 {
- panic!("overlong unicode escape (must have at most 6 hex digits)");
- }
- ch *= 0x10;
- ch += u32::from(digit);
- digits += 1;
- s = &s[1..];
- }
- assert!(byte(s, 0) == b'}');
- s = &s[1..];
- if let Some(ch) = char::from_u32(ch) {
- (ch, s)
- } else {
- panic!("character code {:x} is not a valid unicode character", ch);
- }
- }
- // Returns base 10 digits and suffix.
- pub(crate) fn parse_lit_int(mut s: &str) -> Option<(Box<str>, Box<str>)> {
- let negative = byte(s, 0) == b'-';
- if negative {
- s = &s[1..];
- }
- let base = match (byte(s, 0), byte(s, 1)) {
- (b'0', b'x') => {
- s = &s[2..];
- 16
- }
- (b'0', b'o') => {
- s = &s[2..];
- 8
- }
- (b'0', b'b') => {
- s = &s[2..];
- 2
- }
- (b'0'..=b'9', _) => 10,
- _ => return None,
- };
- let mut value = BigInt::new();
- let mut has_digit = false;
- 'outer: loop {
- let b = byte(s, 0);
- let digit = match b {
- b'0'..=b'9' => b - b'0',
- b'a'..=b'f' if base > 10 => b - b'a' + 10,
- b'A'..=b'F' if base > 10 => b - b'A' + 10,
- b'_' => {
- s = &s[1..];
- continue;
- }
- // If looking at a floating point literal, we don't want to
- // consider it an integer.
- b'.' if base == 10 => return None,
- b'e' | b'E' if base == 10 => {
- let mut has_exp = false;
- for (i, b) in s[1..].bytes().enumerate() {
- match b {
- b'_' => {}
- b'-' | b'+' => return None,
- b'0'..=b'9' => has_exp = true,
- _ => {
- let suffix = &s[1 + i..];
- if has_exp && crate::ident::xid_ok(suffix) {
- return None;
- } else {
- break 'outer;
- }
- }
- }
- }
- if has_exp {
- return None;
- } else {
- break;
- }
- }
- _ => break,
- };
- if digit >= base {
- return None;
- }
- has_digit = true;
- value *= base;
- value += digit;
- s = &s[1..];
- }
- if !has_digit {
- return None;
- }
- let suffix = s;
- if suffix.is_empty() || crate::ident::xid_ok(suffix) {
- let mut repr = value.to_string();
- if negative {
- repr.insert(0, '-');
- }
- Some((repr.into_boxed_str(), suffix.to_owned().into_boxed_str()))
- } else {
- None
- }
- }
- // Returns base 10 digits and suffix.
- pub(crate) fn parse_lit_float(input: &str) -> Option<(Box<str>, Box<str>)> {
- // Rust's floating point literals are very similar to the ones parsed by
- // the standard library, except that rust's literals can contain
- // ignorable underscores. Let's remove those underscores.
- let mut bytes = input.to_owned().into_bytes();
- let start = (*bytes.first()? == b'-') as usize;
- match bytes.get(start)? {
- b'0'..=b'9' => {}
- _ => return None,
- }
- let mut read = start;
- let mut write = start;
- let mut has_dot = false;
- let mut has_e = false;
- let mut has_sign = false;
- let mut has_exponent = false;
- while read < bytes.len() {
- match bytes[read] {
- b'_' => {
- // Don't increase write
- read += 1;
- continue;
- }
- b'0'..=b'9' => {
- if has_e {
- has_exponent = true;
- }
- bytes[write] = bytes[read];
- }
- b'.' => {
- if has_e || has_dot {
- return None;
- }
- has_dot = true;
- bytes[write] = b'.';
- }
- b'e' | b'E' => {
- match bytes[read + 1..]
- .iter()
- .find(|b| **b != b'_')
- .unwrap_or(&b'\0')
- {
- b'-' | b'+' | b'0'..=b'9' => {}
- _ => break,
- }
- if has_e {
- if has_exponent {
- break;
- } else {
- return None;
- }
- }
- has_e = true;
- bytes[write] = b'e';
- }
- b'-' | b'+' => {
- if has_sign || has_exponent || !has_e {
- return None;
- }
- has_sign = true;
- if bytes[read] == b'-' {
- bytes[write] = bytes[read];
- } else {
- // Omit '+'
- read += 1;
- continue;
- }
- }
- _ => break,
- }
- read += 1;
- write += 1;
- }
- if has_e && !has_exponent {
- return None;
- }
- let mut digits = String::from_utf8(bytes).unwrap();
- let suffix = digits.split_off(read);
- digits.truncate(write);
- if suffix.is_empty() || crate::ident::xid_ok(&suffix) {
- Some((digits.into_boxed_str(), suffix.into_boxed_str()))
- } else {
- None
- }
- }
- }
|