diff --git a/tools/pdl/Android.bp b/tools/pdl/Android.bp index 50f4ceae399d75d214fad0b8c367faac6683e547..b1cbcd4aaf5c87deb40c73d4449c210d146fd08b 100644 --- a/tools/pdl/Android.bp +++ b/tools/pdl/Android.bp @@ -8,11 +8,9 @@ package { default_applicable_licenses: ["system_bt_license"], } -rust_binary_host { - name: "pdl", - srcs: [ - "src/main.rs", - ], +rust_defaults { + name: "pdl_defaults", + srcs: ["src/main.rs"], rustlibs: [ "libpest", "libserde", @@ -24,3 +22,14 @@ rust_binary_host { "libpest_derive", ], } + +rust_binary_host { + name: "pdl", + defaults: ["pdl_defaults"], +} + +rust_test_host { + name: "pdl_inline_tests", + defaults: ["pdl_defaults"], + test_suites: ["general-tests"], +} diff --git a/tools/pdl/src/ast.rs b/tools/pdl/src/ast.rs index e25b01a207b5c16f563a20e49d6d73d7d5355271..01ce05c6453b0c345b69973b1c5c7a7dd01662b0 100644 --- a/tools/pdl/src/ast.rs +++ b/tools/pdl/src/ast.rs @@ -14,8 +14,11 @@ pub type SourceDatabase = files::SimpleFiles<String, String>; #[derive(Debug, Copy, Clone, Serialize, PartialEq, Eq, PartialOrd, Ord)] pub struct SourceLocation { + /// Byte offset into the file (counted from zero). pub offset: usize, + /// Line number (counted from zero). pub line: usize, + /// Column number (counted from zero) pub column: usize, } @@ -176,13 +179,20 @@ pub trait Named<'d> { } impl SourceLocation { + /// Construct a new source location. + /// + /// The `line_starts` indicates the byte offsets where new lines + /// start in the file. The first element should thus be `0` since + /// every file has at least one line starting at offset `0`. pub fn new(offset: usize, line_starts: &[usize]) -> SourceLocation { + let mut loc = SourceLocation { offset, line: 0, column: offset }; for (line, start) in line_starts.iter().enumerate() { - if *start <= offset { - return SourceLocation { offset, line, column: offset - start }; + if *start > offset { + break; } + loc = SourceLocation { offset, line, column: offset - start }; } - unreachable!() + loc } } @@ -299,3 +309,39 @@ impl<'d> Named<'d> for Decl { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn source_location_new() { + let line_starts = &[0, 20, 80, 120, 150]; + assert_eq!( + SourceLocation::new(0, line_starts), + SourceLocation { offset: 0, line: 0, column: 0 } + ); + assert_eq!( + SourceLocation::new(10, line_starts), + SourceLocation { offset: 10, line: 0, column: 10 } + ); + assert_eq!( + SourceLocation::new(50, line_starts), + SourceLocation { offset: 50, line: 1, column: 30 } + ); + assert_eq!( + SourceLocation::new(100, line_starts), + SourceLocation { offset: 100, line: 2, column: 20 } + ); + assert_eq!( + SourceLocation::new(1000, line_starts), + SourceLocation { offset: 1000, line: 4, column: 850 } + ); + } + + #[test] + fn source_location_new_no_crash_with_empty_line_starts() { + let loc = SourceLocation::new(100, &[]); + assert_eq!(loc, SourceLocation { offset: 100, line: 0, column: 100 }); + } +}