cpp_synmap-0.3.0/Cargo.toml.orig01006640001750000175000000001053131616227760015007 0ustar0000000000000000[package] name = "cpp_synmap" version = "0.3.0" authors = ["Michael Layzell "] description = "Sourcemap and full crate parsing support for `cpp_syn`" readme = "README.md" license = "MIT/Apache-2.0" keywords = ["syn", "parsing", "sourcemap", "crate"] categories = ["development-tools::procedural-macro-helpers"] repository = "https://github.com/mystor/rust-cpp" documentation = "https://docs.rs/cpp_synmap" [dependencies] memchr = "1.0" cpp_syn = { version = "0.12", features = ["full", "fold"] } cpp_synom = { version = "0.12" } cpp_synmap-0.3.0/Cargo.toml0000644000000021210010216 0ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g. crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "cpp_synmap" version = "0.3.0" authors = ["Michael Layzell "] description = "Sourcemap and full crate parsing support for `cpp_syn`" documentation = "https://docs.rs/cpp_synmap" readme = "README.md" keywords = ["syn", "parsing", "sourcemap", "crate"] categories = ["development-tools::procedural-macro-helpers"] license = "MIT/Apache-2.0" repository = "https://github.com/mystor/rust-cpp" [dependencies.cpp_syn] version = "0.12" features = ["full", "fold"] [dependencies.cpp_synom] version = "0.12" [dependencies.memchr] version = "1.0" cpp_synmap-0.3.0/README.md01006640001750000175000000001120131560253070013361 0ustar0000000000000000# Synmap > NOTE: This crate currently depends on `cpp_syn` rather than `syn`, as it > requires the `Span` features which have not been landed in `syn` yet for the > majority of its features. This crate provides a `SourceMap` type which can be used to parse an entire crate and generate a complete AST. It also updates the spans in the parsed AST to be relative to the `SourceMap` rather than the bytes in the input file. With this information, the `SourceMap` provides methods to map spans to source filenames (`filename`), source text (`source_text`) and line/column numbers (`locinfo`). cpp_synmap-0.3.0/src/lib.rs01006640001750000175000000025662131616226540014032 0ustar0000000000000000//! `synmap` provides utilities for parsing multi-file crates into `syn` AST //! nodes, and resolving the spans attached to those nodes into raw source text, //! and line/column information. //! //! The primary entry point for the crate is the `SourceMap` type, which stores //! mappings from byte offsets to file information, along with cached file //! information. extern crate cpp_syn as syn; extern crate memchr; use std::fmt::{self, Write}; use std::error; use std::fs::{self, File}; use std::io::prelude::*; use std::io::{self, Error, ErrorKind}; use std::path::{Path, PathBuf}; use syn::{Attribute, Crate, Ident, Item, ItemKind, Lit, LitKind, MetaItem, Span}; use syn::fold::{self, Folder}; use std::mem; /// This constant controls the amount of padding which is created between /// consecutive files' span ranges. It is non-zero to ensure that the low byte /// offset of one file is not equal to the high byte offset of the previous /// file. const FILE_PADDING_BYTES: usize = 1; /// Information regarding the on-disk location of a span of code. /// This type is produced by `SourceMap::locinfo`. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub struct LocInfo<'a> { pub path: &'a Path, pub line: usize, pub col: usize, } impl<'a> fmt::Display for LocInfo<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}:{}:{}", self.path.display(), self.line, self.col) } } #[derive(Debug)] struct FileInfo { span: Span, path: PathBuf, src: String, lines: Vec, } /// NOTE: This produces line and column. Line is 1-indexed, column is 0-indexed fn offset_line_col(lines: &Vec, off: usize) -> (usize, usize) { match lines.binary_search(&off) { Ok(found) => (found + 1, 0), Err(idx) => (idx, off - lines[idx - 1]), } } fn lines_offsets(s: &[u8]) -> Vec { let mut lines = vec![0]; let mut prev = 0; while let Some(len) = memchr::memchr(b'\n', &s[prev..]) { prev += len + 1; lines.push(prev); } lines } /// The `SourceMap` is the primary entry point for `synmap`. It maintains a /// mapping between `Span` objects and the original source files they were /// parsed from. #[derive(Debug)] pub struct SourceMap { files: Vec, offset: usize, } impl SourceMap { /// Create a new `SourceMap` object with no files inside of it. pub fn new() -> SourceMap { SourceMap { files: Vec::new(), offset: 0, } } /// Read and parse the passed-in file path as a crate root, recursively /// parsing each of the submodules. Produces a syn `Crate` object with /// all submodules inlined. /// /// `Span` objects inside the resulting crate object are `SourceMap` /// relative, and should be interpreted by passing to the other methods on /// this type, such as `locinfo`, `source_text`, or `filename`. pub fn add_crate_root>(&mut self, path: P) -> io::Result { self.parse_canonical_file(fs::canonicalize(path)?) } /// This is an internal method which requires a canonical pathbuf as /// returned from a method like `fs::canonicalize`. fn parse_canonical_file(&mut self, path: PathBuf) -> io::Result { // Parse the crate with syn let mut source = String::new(); File::open(&path)?.read_to_string(&mut source)?; let krate = syn::parse_crate(&source).map_err(|e| Error::new(ErrorKind::InvalidData, e))?; let parent = path.parent() .ok_or(Error::new( ErrorKind::InvalidInput, "cannot parse file without parent directory", ))? .to_path_buf(); // Register the read-in file in the SourceMap let offset = self.offset; self.offset += source.len() + FILE_PADDING_BYTES; self.files.push(FileInfo { span: Span { lo: offset, hi: offset + source.len(), }, path: path, lines: lines_offsets(source.as_bytes()), src: source, }); // Walk the parsed Crate object, recursively filling in the bodies of // `mod` statements, and rewriting spans to be SourceMap-relative // instead of file-relative. let idx = self.files.len() - 1; let mut walker = Walker { idx: idx, error: None, sm: self, parent: parent, }; let krate = walker.fold_crate(krate); if let Some(err) = walker.error { return Err(err); } Ok(krate) } fn local_fileinfo(&self, mut span: Span) -> io::Result<(&FileInfo, Span)> { if span.lo > span.hi { return Err(Error::new( ErrorKind::InvalidInput, "Invalid span object with negative length", )); } for fi in &self.files { if span.lo >= fi.span.lo && span.lo <= fi.span.hi && span.hi >= fi.span.lo && span.hi <= fi.span.hi { // Remove the offset span.lo -= fi.span.lo; span.hi -= fi.span.lo; // Set the path return Ok((fi, span)); } } Err(Error::new( ErrorKind::InvalidInput, "Span is not part of any input file", )) } /// Get the filename which contains the given span. /// /// Fails if the span is invalid or spans multiple source files. pub fn filename(&self, span: Span) -> io::Result<&Path> { Ok(&self.local_fileinfo(span)?.0.path) } /// Get the source text for the passed-in span. /// /// Fails if the span is invalid or spans multiple source files. pub fn source_text(&self, span: Span) -> io::Result<&str> { let (fi, span) = self.local_fileinfo(span)?; Ok(&fi.src[span.lo..span.hi]) } /// Get a LocInfo object for the passed-in span, containing line, column, /// and file name information for the beginning and end of the span. The /// `path` field in the returned LocInfo struct will be a reference to a /// canonical path. /// /// Fails if the span is invalid or spans multiple source files. pub fn locinfo(&self, span: Span) -> io::Result { let (fi, span) = self.local_fileinfo(span)?; let (line, col) = offset_line_col(&fi.lines, span.lo); Ok(LocInfo { path: &fi.path, line: line, col: col, }) } } struct Walker<'a> { idx: usize, error: Option, sm: &'a mut SourceMap, parent: PathBuf, } impl<'a> Walker<'a> { fn read_submodule(&mut self, path: PathBuf) -> io::Result { let faux_crate = self.sm.parse_canonical_file(path)?; if faux_crate.shebang.is_some() { return Err(Error::new( ErrorKind::InvalidData, "Only the root file of a crate may contain shebangs", )); } Ok(faux_crate) } fn get_attrs_items(&mut self, attrs: &[Attribute], ident: &Ident) -> io::Result { // Determine the path of the inner module's file for attr in attrs { match attr.value { MetaItem::NameValue( ref id, Lit { node: LitKind::Str(ref s, _), .. }, ) => if id.as_ref() == "path" { let explicit = self.parent.join(&s[..]); return self.read_submodule(explicit); }, _ => {} } } let mut subdir = self.parent.join(ident.as_ref()); subdir.push("mod.rs"); if subdir.is_file() { return self.read_submodule(subdir); } let adjacent = self.parent.join(&format!("{}.rs", ident)); if adjacent.is_file() { return self.read_submodule(adjacent); } Err(Error::new( ErrorKind::NotFound, format!("No file with module definition for `mod {}`", ident), )) } } impl<'a> Folder for Walker<'a> { fn fold_item(&mut self, mut item: Item) -> Item { if self.error.is_some() { return item; // Early return to avoid extra work when erroring } match item.node { ItemKind::Mod(None) => { let (attrs, items) = match self.get_attrs_items(&item.attrs, &item.ident) { Ok(Crate { attrs, items, .. }) => (attrs, items), Err(e) => { // Get the file, line, and column information for the // mod statement we're looking at. let span = self.fold_span(item.span); let loc = match self.sm.locinfo(span) { Ok(li) => li.to_string(), Err(_) => "unknown location".to_owned(), }; let e = Error::new( ErrorKind::Other, ModParseErr { err: e, msg: format!( "Error while parsing `mod {}` \ statement at {}", item.ident, loc ), }, ); self.error = Some(e); return item; } }; item.attrs.extend_from_slice(&attrs); item.node = ItemKind::Mod(Some(items)); item } ItemKind::Mod(Some(items)) => { let mut parent = self.parent.join(item.ident.as_ref()); mem::swap(&mut self.parent, &mut parent); let items = items.into_iter().map(|item| self.fold_item(item)).collect(); mem::swap(&mut self.parent, &mut parent); item.node = ItemKind::Mod(Some(items)); item } _ => fold::noop_fold_item(self, item), } } fn fold_span(&mut self, span: Span) -> Span { let offset = self.sm.files[self.idx].span.lo; Span { lo: span.lo + offset, hi: span.hi + offset, } } } /// This is an internal error which is used to build errors when parsing an /// inner module fails. #[derive(Debug)] struct ModParseErr { err: Error, msg: String, } impl error::Error for ModParseErr { fn description(&self) -> &str { &self.msg } fn cause(&self) -> Option<&error::Error> { Some(&self.err) } } impl fmt::Display for ModParseErr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.msg, f)?; f.write_char('\n')?; fmt::Display::fmt(&self.err, f) } }