Audit string parsing, fixing a few bugs here and there

Closes #51
This commit is contained in:
Alex Crichton 2015-01-15 15:23:37 -08:00
parent 5f2c7b4986
commit f4b2045de0

View file

@ -305,7 +305,7 @@ impl<'a> Parser<'a> {
} }
loop { loop {
while self.newline() { ret.push('\n') } while multiline && self.newline() { ret.push('\n') }
match self.cur.next() { match self.cur.next() {
Some((_, '"')) => { Some((_, '"')) => {
if multiline { if multiline {
@ -321,15 +321,11 @@ impl<'a> Parser<'a> {
} }
} }
Some((pos, ch)) if ch < '\u{1f}' => { Some((pos, ch)) if ch < '\u{1f}' => {
let mut escaped = String::new();
for c in ch.escape_default() {
escaped.push(c);
}
self.errors.push(ParserError { self.errors.push(ParserError {
lo: pos, lo: pos,
hi: pos + 1, hi: pos + 1,
desc: format!("control character `{}` must be escaped", desc: format!("control character `{}` must be escaped",
escaped) ch.escape_default().collect::<String>())
}); });
} }
Some((_, ch)) => ret.push(ch), Some((_, ch)) => ret.push(ch),
@ -372,9 +368,7 @@ impl<'a> Parser<'a> {
Some(n) => { Some(n) => {
match char::from_u32(n) { match char::from_u32(n) {
Some(c) => { Some(c) => {
for _ in range(0, len) { me.cur.by_ref().skip(len - 1).next();
me.cur.next();
}
return Some(c) return Some(c)
} }
None => { None => {
@ -400,16 +394,12 @@ impl<'a> Parser<'a> {
None None
} }
Some((pos, ch)) => { Some((pos, ch)) => {
let mut escaped = String::new();
for c in ch.escape_default() {
escaped.push(c);
}
let next_pos = me.next_pos(); let next_pos = me.next_pos();
me.errors.push(ParserError { me.errors.push(ParserError {
lo: pos, lo: pos,
hi: next_pos, hi: next_pos,
desc: format!("unknown string escape: `{}`", desc: format!("unknown string escape: `{}`",
escaped), ch.escape_default().collect::<String>()),
}); });
None None
} }
@ -431,13 +421,25 @@ impl<'a> Parser<'a> {
let mut ret = String::new(); let mut ret = String::new();
// detect multiline literals // detect multiline literals
if self.eat('\'') {
if self.eat('\'') { if self.eat('\'') {
multiline = true; multiline = true;
if !self.expect('\'') { return None }
self.newline(); self.newline();
} else {
return Some(Value::String(ret)) // empty
}
} }
loop { loop {
if !multiline && self.newline() {
let next = self.next_pos();
self.errors.push(ParserError {
lo: start,
hi: next,
desc: format!("literal strings cannot contain newlines"),
});
return None
}
match self.cur.next() { match self.cur.next() {
Some((_, '\'')) => { Some((_, '\'')) => {
if multiline { if multiline {
@ -945,6 +947,17 @@ trimmed in raw strings.
let mut p = Parser::new("foo = '''\r'''"); let mut p = Parser::new("foo = '''\r'''");
let table = Table(p.parse().unwrap()); let table = Table(p.parse().unwrap());
assert_eq!(table.lookup("foo").and_then(|k| k.as_str()), Some("\r")); assert_eq!(table.lookup("foo").and_then(|k| k.as_str()), Some("\r"));
let mut p = Parser::new("foo = '\r'");
let table = Table(p.parse().unwrap());
assert_eq!(table.lookup("foo").and_then(|k| k.as_str()), Some("\r"));
}
#[test]
fn blank_literal_string() {
let mut p = Parser::new("foo = ''");
let table = Table(p.parse().unwrap());
assert_eq!(table.lookup("foo").and_then(|k| k.as_str()), Some(""));
} }
#[test] #[test]
@ -964,4 +977,10 @@ trimmed in raw strings.
assert_eq!(table.lookup("foo").and_then(|k| k.as_str()), Some("")); assert_eq!(table.lookup("foo").and_then(|k| k.as_str()), Some(""));
assert_eq!(table.lookup("bar").and_then(|k| k.as_str()), Some("a")); assert_eq!(table.lookup("bar").and_then(|k| k.as_str()), Some("a"));
} }
#[test]
fn string_no_newline() {
assert!(Parser::new("a = \"\n\"").parse().is_none());
assert!(Parser::new("a = '\n'").parse().is_none());
}
} }