use std::fmt;
use std::io::Read;
use decoder::{decode, DecodedMap};
use errors::{Result, Error};
#[derive(PartialEq, Copy, Clone)]
pub struct RawToken {
pub dst_line: u32,
pub dst_col: u32,
pub src_line: u32,
pub src_col: u32,
pub src_id: u32,
pub name_id: u32,
}
pub struct Token<'a> {
raw: &'a RawToken,
i: &'a SourceMap,
}
impl<'a> Token<'a> {
pub fn get_dst_line(&self) -> u32 {
self.raw.dst_line
}
pub fn get_dst_col(&self) -> u32 {
self.raw.dst_col
}
pub fn get_dst(&self) -> (u32, u32) {
(self.get_dst_line(), self.get_dst_col())
}
pub fn get_src_line(&self) -> u32 {
self.raw.src_line
}
pub fn get_src_col(&self) -> u32 {
self.raw.src_col
}
pub fn get_src(&self) -> (u32, u32) {
(self.get_src_line(), self.get_src_col())
}
pub fn get_source(&self) -> &str {
if self.raw.src_id == !0 {
""
} else {
&self.i.sources[self.raw.src_id as usize][..]
}
}
pub fn get_name(&self) -> Option<&str> {
if self.raw.name_id == !0 {
None
} else {
Some(&self.i.names[self.raw.name_id as usize][..])
}
}
pub fn has_name(&self) -> bool {
self.get_name().is_some()
}
pub fn to_tuple(&self) -> (&str, u32, u32, Option<&str>) {
(
self.get_source(),
self.get_src_line(),
self.get_src_col(),
self.get_name()
)
}
pub fn get_raw_token(&self) -> RawToken {
*self.raw
}
}
pub struct TokenIter<'a> {
i: &'a SourceMap,
next_idx: u32,
}
impl<'a> Iterator for TokenIter<'a> {
type Item = Token<'a>;
fn next(&mut self) -> Option<Token<'a>> {
self.i.get_token(self.next_idx).map(|tok| {
self.next_idx += 1;
tok
})
}
}
impl<'a> fmt::Debug for Token<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "<Token {}>", self)
}
}
impl<'a> fmt::Display for Token<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}:{}:{}{}",
self.get_source(),
self.get_src_line(),
self.get_src_col(),
self.get_name().map(|x| format!(" name={}", x))
.unwrap_or("".into()))
}
}
pub struct SourceMapSection {
offset: (u32, u32),
url: Option<String>,
map: Option<Box<SourceMap>>,
}
pub struct SourceMapSectionIter<'a> {
i: &'a SourceMapIndex,
next_idx: u32,
}
impl<'a> Iterator for SourceMapSectionIter<'a> {
type Item = &'a SourceMapSection;
fn next(&mut self) -> Option<&'a SourceMapSection> {
self.i.get_section(self.next_idx).map(|sec| {
self.next_idx += 1;
sec
})
}
}
pub struct SourceMapIndex {
version: u32,
file: Option<String>,
sections: Vec<SourceMapSection>,
}
pub struct SourceMap {
version: u32,
file: Option<String>,
tokens: Vec<RawToken>,
index: Vec<(u32, u32, u32)>,
names: Vec<String>,
sources: Vec<String>,
sources_content: Vec<Option<String>>,
}
impl SourceMap {
pub fn from_reader<R: Read>(rdr: R) -> Result<SourceMap> {
match try!(decode(rdr)) {
DecodedMap::Regular(sm) => Ok(sm),
DecodedMap::Index(_) => Err(Error::IndexedSourcemap),
}
}
pub fn new(version: u32, file: Option<String>, tokens: Vec<RawToken>,
index: Vec<(u32, u32, u32)>, names: Vec<String>,
sources: Vec<String>,
sources_content: Option<Vec<Option<String>>>) -> SourceMap {
SourceMap {
version: version,
file: file,
tokens: tokens,
index: index,
names: names,
sources: sources,
sources_content: sources_content.unwrap_or(vec![]),
}
}
pub fn get_version(&self) -> u32 {
self.version
}
pub fn get_file(&self) -> Option<&str> {
self.file.as_ref().map(|x| &x[..])
}
pub fn get_token<'a>(&'a self, idx: u32) -> Option<Token<'a>> {
self.tokens.get(idx as usize).map(|raw| {
Token { raw: raw, i: self }
})
}
pub fn get_token_count(&self) -> u32 {
self.tokens.len() as u32
}
pub fn tokens<'a>(&'a self) -> TokenIter<'a> {
TokenIter { i: self, next_idx: 0 }
}
pub fn lookup_token<'a>(&'a self, line: u32, col: u32) -> Option<Token<'a>> {
let mut low = 0;
let mut high = self.index.len();
while low < high {
let mid = (low + high) / 2;
if (line, col, 0) < self.index[mid as usize] {
high = mid;
} else {
low = mid + 1;
}
}
if low > 0 {
self.get_token(self.index[low as usize].2)
} else {
None
}
}
pub fn get_source_count(&self) -> u32 {
self.sources.len() as u32
}
pub fn get_source(&self, idx: u32) -> Option<&str> {
self.sources.get(idx as usize).map(|x| &x[..])
}
pub fn get_source_contents(&self, idx: u32) -> Option<&str> {
self.sources_content.get(idx as usize)
.and_then(|bucket| bucket.as_ref()).map(|x| &**x)
}
pub fn get_name_count(&self) -> u32 {
self.names.len() as u32
}
pub fn get_name(&self, idx: u32) -> Option<&str> {
self.names.get(idx as usize).map(|x| &x[..])
}
}
impl SourceMapIndex {
pub fn from_reader<R: Read>(rdr: R) -> Result<SourceMapIndex> {
match try!(decode(rdr)) {
DecodedMap::Regular(_) => Err(Error::RegularSourcemap),
DecodedMap::Index(smi) => Ok(smi),
}
}
pub fn new(version: u32, file: Option<String>,
sections: Vec<SourceMapSection>) -> SourceMapIndex {
SourceMapIndex {
version: version,
file: file,
sections: sections,
}
}
pub fn get_version(&self) -> u32 {
self.version
}
pub fn get_file(&self) -> Option<&str> {
self.file.as_ref().map(|x| &x[..])
}
pub fn get_section_count(&self) -> u32 {
self.sections.len() as u32
}
pub fn get_section(&self, idx: u32) -> Option<&SourceMapSection> {
self.sections.get(idx as usize)
}
pub fn get_section_mut(&mut self, idx: u32) -> Option<&mut SourceMapSection> {
self.sections.get_mut(idx as usize)
}
pub fn sections<'a>(&'a self) -> SourceMapSectionIter<'a> {
SourceMapSectionIter {
i: self,
next_idx: 0
}
}
pub fn lookup_token<'a>(&'a self, line: u32, col: u32) -> Option<Token<'a>> {
for section in self.sections() {
let (off_line, off_col) = section.get_offset();
if off_line < line || off_col < col {
continue;
}
if let Some(map) = section.get_sourcemap() {
if let Some(tok) = map.lookup_token(line - off_line, col - off_col) {
return Some(tok);
}
}
}
None
}
}
impl SourceMapSection {
pub fn new(offset: (u32, u32), url: Option<String>, map: Option<SourceMap>) -> SourceMapSection {
SourceMapSection {
offset: offset,
url: url,
map: map.map(|x| Box::new(x)),
}
}
pub fn get_offset_line(&self) -> u32 {
self.offset.0
}
pub fn get_offset_col(&self) -> u32 {
self.offset.1
}
pub fn get_offset(&self) -> (u32, u32) {
self.offset
}
pub fn get_url(&self) -> Option<&str> {
self.url.as_ref().map(|x| &**x)
}
pub fn get_sourcemap(&self) -> Option<&SourceMap> {
self.map.as_ref().map(|x| &**x)
}
pub fn set_sourcemap(&mut self, sm: SourceMap) {
self.map = Some(Box::new(sm));
}
}