diff options
Diffstat (limited to 'src/libsyntax/parse')
| -rw-r--r-- | src/libsyntax/parse/lexer/mod.rs | 68 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 3 | ||||
| -rw-r--r-- | src/libsyntax/parse/token.rs | 11 |
3 files changed, 78 insertions, 4 deletions
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index f7eac0b323f..7e4cb195cea 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -650,10 +650,13 @@ impl<'a> StringReader<'a> { /// token, and updates the interner fn next_token_inner(&mut self) -> token::Token { let c = self.curr; - if ident_start(c) && !self.nextch_is('"') && !self.nextch_is('#') { + if ident_start(c) && match (c.unwrap(), self.nextch()) { // Note: r as in r" or r#" is part of a raw string literal, - // not an identifier, and is handled further down. - + // b as in b' is part of a byte literal. + // They are not identifiers, and are handled further down. + ('r', Some('"')) | ('r', Some('#')) | ('b', Some('\'')) => false, + _ => true + } { let start = self.last_pos; while ident_continue(self.curr) { self.bump(); @@ -854,6 +857,65 @@ impl<'a> StringReader<'a> { self.bump(); // advance curr past token return token::LIT_CHAR(c2); } + 'b' => { + self.bump(); + assert!(self.curr_is('\''), "Should have been a token::IDENT"); + self.bump(); + let start = self.last_pos; + + // the eof will be picked up by the final `'` check below + let mut c2 = self.curr.unwrap_or('\x00'); + self.bump(); + + match c2 { + '\\' => { + // '\X' for some X must be a character constant: + let escaped = self.curr; + let escaped_pos = self.last_pos; + self.bump(); + match escaped { + None => {} + Some(e) => { + c2 = match e { + 'n' => '\n', + 'r' => '\r', + 't' => '\t', + '\\' => '\\', + '\'' => '\'', + '"' => '"', + '0' => '\x00', + 'x' => self.scan_numeric_escape(2u, '\''), + c2 => { + self.err_span_char(escaped_pos, self.last_pos, + "unknown byte escape", c2); + c2 + } + } + } + } + } + '\t' | '\n' | '\r' | '\'' => { + self.err_span_char( start, self.last_pos, + "byte constant must be escaped", c2); + } + _ if c2 > '\x7F' => { + self.err_span_char( start, self.last_pos, + "byte constant must be ASCII. \ + Use a \\xHH escape for a non-ASCII byte", c2); + } + _ => {} + } + if !self.curr_is('\'') { + self.fatal_span_verbose( + // Byte offsetting here is okay because the + // character before position `start` are an + // ascii single quote and ascii 'b'. + start - BytePos(2), self.last_pos, + "unterminated byte constant".to_string()); + } + self.bump(); // advance curr past token + return token::LIT_BYTE(c2 as u8); + } '"' => { let mut accum_str = String::new(); let start_bpos = self.last_pos; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index bbe0680ef14..0bd47ede214 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -33,7 +33,7 @@ use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod}; use ast::{Ident, NormalFn, Inherited, Item, Item_, ItemStatic}; use ast::{ItemEnum, ItemFn, ItemForeignMod, ItemImpl}; use ast::{ItemMac, ItemMod, ItemStruct, ItemTrait, ItemTy, Lit, Lit_}; -use ast::{LitBool, LitFloat, LitFloatUnsuffixed, LitInt, LitChar}; +use ast::{LitBool, LitFloat, LitFloatUnsuffixed, LitInt, LitChar, LitByte}; use ast::{LitIntUnsuffixed, LitNil, LitStr, LitUint, Local, LocalLet}; use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, Matcher, MatchNonterminal}; use ast::{MatchSeq, MatchTok, Method, MutTy, BiMul, Mutability}; @@ -1512,6 +1512,7 @@ impl<'a> Parser<'a> { // matches token_lit = LIT_INT | ... pub fn lit_from_token(&mut self, tok: &token::Token) -> Lit_ { match *tok { + token::LIT_BYTE(i) => LitByte(i), token::LIT_CHAR(i) => LitChar(i), token::LIT_INT(i, it) => LitInt(i, it), token::LIT_UINT(u, ut) => LitUint(u, ut), diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index a4a022708d9..b8f13624a32 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -78,6 +78,7 @@ pub enum Token { DOLLAR, /* Literals */ + LIT_BYTE(u8), LIT_CHAR(char), LIT_INT(i64, ast::IntTy), LIT_UINT(u64, ast::UintTy), @@ -193,6 +194,14 @@ pub fn to_str(t: &Token) -> String { DOLLAR => "$".to_string(), /* Literals */ + LIT_BYTE(b) => { + let mut res = String::from_str("b'"); + (b as char).escape_default(|c| { + res.push_char(c); + }); + res.push_char('\''); + res + } LIT_CHAR(c) => { let mut res = String::from_str("'"); c.escape_default(|c| { @@ -273,6 +282,7 @@ pub fn can_begin_expr(t: &Token) -> bool { IDENT(_, _) => true, UNDERSCORE => true, TILDE => true, + LIT_BYTE(_) => true, LIT_CHAR(_) => true, LIT_INT(_, _) => true, LIT_UINT(_, _) => true, @@ -311,6 +321,7 @@ pub fn close_delimiter_for(t: &Token) -> Option<Token> { pub fn is_lit(t: &Token) -> bool { match *t { + LIT_BYTE(_) => true, LIT_CHAR(_) => true, LIT_INT(_, _) => true, LIT_UINT(_, _) => true, |
