Merge pull request #249 from ehuss/int-radix
0.5: Support hex/oct/bin integers.
This commit is contained in:
commit
9fe48c3282
63
src/de.rs
63
src/de.rs
|
@ -871,7 +871,14 @@ impl<'a> Deserializer<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn number(&mut self, Span { start, end}: Span, s: &'a str) -> Result<Value<'a>, Error> {
|
fn number(&mut self, Span { start, end}: Span, s: &'a str) -> Result<Value<'a>, Error> {
|
||||||
if s.contains('e') || s.contains('E') {
|
let to_integer = |f| Value { e: E::Integer(f), start: start, end: end };
|
||||||
|
if s.starts_with("0x") {
|
||||||
|
self.integer(&s[2..], 16).map(to_integer)
|
||||||
|
} else if s.starts_with("0o") {
|
||||||
|
self.integer(&s[2..], 8).map(to_integer)
|
||||||
|
} else if s.starts_with("0b") {
|
||||||
|
self.integer(&s[2..], 2).map(to_integer)
|
||||||
|
} else if s.contains('e') || s.contains('E') {
|
||||||
self.float(s, None).map(|f| Value { e: E::Float(f), start: start, end: end })
|
self.float(s, None).map(|f| Value { e: E::Float(f), start: start, end: end })
|
||||||
} else if self.eat(Token::Period)? {
|
} else if self.eat(Token::Period)? {
|
||||||
let at = self.tokens.current();
|
let at = self.tokens.current();
|
||||||
|
@ -892,7 +899,7 @@ impl<'a> Deserializer<'a> {
|
||||||
} else if s == "-nan" {
|
} else if s == "-nan" {
|
||||||
Ok(Value { e: E::Float(-f64::NAN), start: start, end: end })
|
Ok(Value { e: E::Float(-f64::NAN), start: start, end: end })
|
||||||
} else {
|
} else {
|
||||||
self.integer(s).map(|f| Value { e: E::Integer(f), start: start, end: end })
|
self.integer(s, 10).map(to_integer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -906,22 +913,25 @@ impl<'a> Deserializer<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn integer(&self, s: &'a str) -> Result<i64, Error> {
|
fn integer(&self, s: &'a str, radix: u32) -> Result<i64, Error> {
|
||||||
let (prefix, suffix) = self.parse_integer(s, true, false)?;
|
let allow_sign = radix == 10;
|
||||||
|
let allow_leading_zeros = radix != 10;
|
||||||
|
let (prefix, suffix) = self.parse_integer(s, allow_sign, allow_leading_zeros, radix)?;
|
||||||
let start = self.tokens.substr_offset(s);
|
let start = self.tokens.substr_offset(s);
|
||||||
if suffix != "" {
|
if suffix != "" {
|
||||||
return Err(self.error(start, ErrorKind::NumberInvalid))
|
return Err(self.error(start, ErrorKind::NumberInvalid))
|
||||||
}
|
}
|
||||||
prefix.replace("_", "").trim_left_matches('+').parse().map_err(|_e| {
|
i64::from_str_radix(&prefix.replace("_", "").trim_left_matches('+'), radix)
|
||||||
self.error(start, ErrorKind::NumberInvalid)
|
.map_err(|_e| self.error(start, ErrorKind::NumberInvalid))
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_integer(&self,
|
fn parse_integer(
|
||||||
|
&self,
|
||||||
s: &'a str,
|
s: &'a str,
|
||||||
allow_sign: bool,
|
allow_sign: bool,
|
||||||
allow_leading_zeros: bool)
|
allow_leading_zeros: bool,
|
||||||
-> Result<(&'a str, &'a str), Error> {
|
radix: u32,
|
||||||
|
) -> Result<(&'a str, &'a str), Error> {
|
||||||
let start = self.tokens.substr_offset(s);
|
let start = self.tokens.substr_offset(s);
|
||||||
|
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
|
@ -934,21 +944,20 @@ impl<'a> Deserializer<'a> {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
match c {
|
if c == '0' && first {
|
||||||
'0' if first => first_zero = true,
|
first_zero = true;
|
||||||
'0' ... '9' if !first && first_zero && !allow_leading_zeros => {
|
} else if c.to_digit(radix).is_some() {
|
||||||
return Err(self.error(at, ErrorKind::NumberInvalid))
|
if !first && first_zero && !allow_leading_zeros {
|
||||||
|
return Err(self.error(at, ErrorKind::NumberInvalid));
|
||||||
}
|
}
|
||||||
'0' ... '9' => underscore = false,
|
underscore = false;
|
||||||
'_' if first => {
|
} else if c == '_' && first {
|
||||||
return Err(self.error(at, ErrorKind::NumberInvalid))
|
return Err(self.error(at, ErrorKind::NumberInvalid));
|
||||||
}
|
} else if c == '_' && !underscore {
|
||||||
'_' if !underscore => underscore = true,
|
underscore = true;
|
||||||
_ => {
|
} else {
|
||||||
end = i;
|
end = i;
|
||||||
break
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
|
@ -960,7 +969,7 @@ impl<'a> Deserializer<'a> {
|
||||||
|
|
||||||
fn float(&mut self, s: &'a str, after_decimal: Option<&'a str>)
|
fn float(&mut self, s: &'a str, after_decimal: Option<&'a str>)
|
||||||
-> Result<f64, Error> {
|
-> Result<f64, Error> {
|
||||||
let (integral, mut suffix) = self.parse_integer(s, true, false)?;
|
let (integral, mut suffix) = self.parse_integer(s, true, false, 10)?;
|
||||||
let start = self.tokens.substr_offset(integral);
|
let start = self.tokens.substr_offset(integral);
|
||||||
|
|
||||||
let mut fraction = None;
|
let mut fraction = None;
|
||||||
|
@ -968,7 +977,7 @@ impl<'a> Deserializer<'a> {
|
||||||
if suffix != "" {
|
if suffix != "" {
|
||||||
return Err(self.error(start, ErrorKind::NumberInvalid))
|
return Err(self.error(start, ErrorKind::NumberInvalid))
|
||||||
}
|
}
|
||||||
let (a, b) = self.parse_integer(after, false, true)?;
|
let (a, b) = self.parse_integer(after, false, true, 10)?;
|
||||||
fraction = Some(a);
|
fraction = Some(a);
|
||||||
suffix = b;
|
suffix = b;
|
||||||
}
|
}
|
||||||
|
@ -979,12 +988,12 @@ impl<'a> Deserializer<'a> {
|
||||||
self.eat(Token::Plus)?;
|
self.eat(Token::Plus)?;
|
||||||
match self.next()? {
|
match self.next()? {
|
||||||
Some((_, Token::Keylike(s))) => {
|
Some((_, Token::Keylike(s))) => {
|
||||||
self.parse_integer(s, false, false)?
|
self.parse_integer(s, false, false, 10)?
|
||||||
}
|
}
|
||||||
_ => return Err(self.error(start, ErrorKind::NumberInvalid)),
|
_ => return Err(self.error(start, ErrorKind::NumberInvalid)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.parse_integer(&suffix[1..], true, false)?
|
self.parse_integer(&suffix[1..], true, false, 10)?
|
||||||
};
|
};
|
||||||
if b != "" {
|
if b != "" {
|
||||||
return Err(self.error(start, ErrorKind::NumberInvalid))
|
return Err(self.error(start, ErrorKind::NumberInvalid))
|
||||||
|
|
|
@ -11,6 +11,10 @@ fn bad() {
|
||||||
bad("a = 1_");
|
bad("a = 1_");
|
||||||
bad("''");
|
bad("''");
|
||||||
bad("a = 9e99999");
|
bad("a = 9e99999");
|
||||||
|
|
||||||
bad("a = \"\u{7f}\"");
|
bad("a = \"\u{7f}\"");
|
||||||
bad("a = '\u{7f}'");
|
bad("a = '\u{7f}'");
|
||||||
|
|
||||||
|
bad("a = -0x1");
|
||||||
|
bad("a = 0x-1");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
{
|
{
|
||||||
"answer": {"type": "integer", "value": "42"},
|
"answer": {"type": "integer", "value": "42"},
|
||||||
"neganswer": {"type": "integer", "value": "-42"},
|
"neganswer": {"type": "integer", "value": "-42"},
|
||||||
|
|
||||||
"neg_zero": {"type": "integer", "value": "0"},
|
"neg_zero": {"type": "integer", "value": "0"},
|
||||||
"pos_zero": {"type": "integer", "value": "0"}
|
"pos_zero": {"type": "integer", "value": "0"},
|
||||||
|
|
||||||
|
"hex1": {"type": "integer", "value": "3735928559"},
|
||||||
|
"hex2": {"type": "integer", "value": "3735928559"},
|
||||||
|
"hex3": {"type": "integer", "value": "3735928559"},
|
||||||
|
"oct1": {"type": "integer", "value": "342391"},
|
||||||
|
"oct2": {"type": "integer", "value": "493"},
|
||||||
|
"bin1": {"type": "integer", "value": "214"}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,18 @@
|
||||||
answer = 42
|
answer = 42
|
||||||
neganswer = -42
|
neganswer = -42
|
||||||
|
|
||||||
neg_zero = -0
|
neg_zero = -0
|
||||||
pos_zero = +0
|
pos_zero = +0
|
||||||
|
|
||||||
|
# hexadecimal with prefix `0x`
|
||||||
|
hex1 = 0xDEADBEEF
|
||||||
|
hex2 = 0xdeadbeef
|
||||||
|
hex3 = 0xdead_beef
|
||||||
|
|
||||||
|
# octal with prefix `0o`
|
||||||
|
oct1 = 0o01234567
|
||||||
|
oct2 = 0o755 # useful for Unix file permissions
|
||||||
|
|
||||||
|
# binary with prefix `0b`
|
||||||
|
bin1 = 0b11010110
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue