From 5aee09a5518fbff972683644cd99ab07a5674016 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Mon, 19 Sep 2016 21:43:34 +1000 Subject: [PATCH] Don't return None from Source::location when byte is at end of file Since spans are exclusive they may refer to indexes one past the end. --- base/src/source.rs | 33 +++++++++++++++++++++++++++++---- tests/error.rs | 15 +++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 tests/error.rs diff --git a/base/src/source.rs b/base/src/source.rs index 800c1f66e5..5100ddc3d2 100644 --- a/base/src/source.rs +++ b/base/src/source.rs @@ -65,18 +65,32 @@ impl<'a> Source<'a> { let line_index = self.line_number_at_byte(byte); self.line(line_index).and_then(|(line_byte, line)| { - for (col, (next_byte, _)) in line.char_indices().enumerate() { + let mut column_index = Column::from(0); + + for (i, (next_byte, _)) in line.char_indices().enumerate() { + column_index = Column::from(i); + let curr_byte = line_byte + BytePos::from(next_byte); if curr_byte == byte { return Some(Location { - line: Line::from(line_index), - column: Column::from(col), + line: line_index, + column: column_index, absolute: byte, }); } } - None + + // Handle the case where `byte` is equal to the source's length + if byte == line_byte + BytePos::from(line.len()) { + Some(Location { + line: line_index, + column: column_index, + absolute: byte, + }) + } else { + None + } }) } } @@ -157,4 +171,15 @@ mod tests { assert_eq!(source.location(BytePos::from(400)), None); } + + #[test] + fn source_location_end_of_source() { + let source = test_source(); + assert_eq!(source.location(BytePos::from(source.src.len())), + Some(Location { + line: Line::from(5), + column: Column::from(0), + absolute: BytePos::from(source.src.len()), + })); + } } diff --git a/tests/error.rs b/tests/error.rs new file mode 100644 index 0000000000..decf0e51ac --- /dev/null +++ b/tests/error.rs @@ -0,0 +1,15 @@ +extern crate env_logger; +extern crate gluon; + +mod support; + +use gluon::Compiler; + +#[test] +fn dont_panic_when_error_span_is_at_eof() { + let _ = ::env_logger::init(); + let vm = support::make_vm(); + let text = r#"abc"#; + let result = Compiler::new().load_script(&vm, "test", text); + assert!(result.is_err()); +}