From 5e20a29b4fdc8a2d442d1093681b396dcb4b816b Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Tue, 7 Jan 2020 11:18:04 +0000 Subject: Add structopt dependency in version 0.3.7 This patch series replaces argparse with structopt in the argument handling code. As a first step, we need structopt as a dependency. Import subrepo structopt/:structopt at efbdda4753592e27bc430fb01f7b9650b2f3174d Import subrepo bitflags/:bitflags at 30668016aca6bd3b02c766e8347e0b4080d4c296 Import subrepo clap/:clap at 784524f7eb193e35f81082cc69454c8c21b948f7 Import subrepo heck/:heck at 093d56fbf001e1506e56dbfa38631d99b1066df1 Import subrepo proc-macro-error/:proc-macro-error at 6c4cfe79a622c5de8ae68557993542be46eacae2 Import subrepo proc-macro2/:proc-macro2 at d5d48eddca4566e5438e8a2cbed4a74e049544de Import subrepo quote/:quote at 727436c6c137b20f0f34dde5d8fda2679b9747ad Import subrepo rustversion/:rustversion at 0c5663313516263059ce9059ef81fc7a1cf655ca Import subrepo syn-mid/:syn-mid at 5d3d85414a9e6674e1857ec22a87b96e04a6851a Import subrepo syn/:syn at e87c27e87f6f4ef8919d0372bdb056d53ef0d8f3 Import subrepo textwrap/:textwrap at abcd618beae3f74841032aa5b53c1086b0a57ca2 Import subrepo unicode-segmentation/:unicode-segmentation at 637c9874c4fe0c205ff27787faf150a40295c6c3 Import subrepo unicode-width/:unicode-width at 3033826f8bf05e82724140a981d5941e48fce393 Import subrepo unicode-xid/:unicode-xid at 4baae9fffb156ba229665b972a9cd5991787ceb7 --- syn/examples/dump-syntax/src/main.rs | 149 +++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 syn/examples/dump-syntax/src/main.rs (limited to 'syn/examples/dump-syntax/src/main.rs') diff --git a/syn/examples/dump-syntax/src/main.rs b/syn/examples/dump-syntax/src/main.rs new file mode 100644 index 0000000..240b7a2 --- /dev/null +++ b/syn/examples/dump-syntax/src/main.rs @@ -0,0 +1,149 @@ +//! Parse a Rust source file into a `syn::File` and print out a debug +//! representation of the syntax tree. +//! +//! Use the following command from this directory to test this program by +//! running it on its own source code: +//! +//! cargo run -- src/main.rs +//! +//! The output will begin with: +//! +//! File { +//! shebang: None, +//! attrs: [ +//! Attribute { +//! pound_token: Pound, +//! style: Inner( +//! ... +//! } + +use std::borrow::Cow; +use std::env; +use std::ffi::OsStr; +use std::fmt::{self, Display}; +use std::fs; +use std::io::{self, Write}; +use std::path::{Path, PathBuf}; +use std::process; + +use colored::Colorize; + +enum Error { + IncorrectUsage, + ReadFile(io::Error), + ParseFile { + error: syn::Error, + filepath: PathBuf, + source_code: String, + }, +} + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::Error::*; + + match self { + IncorrectUsage => write!(f, "Usage: dump-syntax path/to/filename.rs"), + ReadFile(error) => write!(f, "Unable to read file: {}", error), + ParseFile { + error, + filepath, + source_code, + } => render_location(f, error, filepath, source_code), + } + } +} + +fn main() { + if let Err(error) = try_main() { + let _ = writeln!(io::stderr(), "{}", error); + process::exit(1); + } +} + +fn try_main() -> Result<(), Error> { + let mut args = env::args_os(); + let _ = args.next(); // executable name + + let filepath = match (args.next(), args.next()) { + (Some(arg), None) => PathBuf::from(arg), + _ => return Err(Error::IncorrectUsage), + }; + + let code = fs::read_to_string(&filepath).map_err(Error::ReadFile)?; + let syntax = syn::parse_file(&code).map_err({ + |error| Error::ParseFile { + error, + filepath, + source_code: code, + } + })?; + println!("{:#?}", syntax); + + Ok(()) +} + +// Render a rustc-style error message, including colors. +// +// error: Syn unable to parse file +// --> main.rs:40:17 +// | +// 40 | fn fmt(&self formatter: &mut fmt::Formatter) -> fmt::Result { +// | ^^^^^^^^^ expected `,` +// +fn render_location( + formatter: &mut fmt::Formatter, + err: &syn::Error, + filepath: &Path, + code: &str, +) -> fmt::Result { + let start = err.span().start(); + let mut end = err.span().end(); + + if start.line == end.line && start.column == end.column { + return render_fallback(formatter, err); + } + + let code_line = match code.lines().nth(start.line - 1) { + Some(line) => line, + None => return render_fallback(formatter, err), + }; + + if end.line > start.line { + end.line = start.line; + end.column = code_line.len(); + } + + let filename = filepath + .file_name() + .map(OsStr::to_string_lossy) + .unwrap_or(Cow::Borrowed("main.rs")); + + write!( + formatter, + "\n\ + {error}{header}\n\ + {indent}{arrow} {filename}:{linenum}:{colnum}\n\ + {indent} {pipe}\n\ + {label} {pipe} {code}\n\ + {indent} {pipe} {offset}{underline} {message}\n\ + ", + error = "error".red().bold(), + header = ": Syn unable to parse file".bold(), + indent = " ".repeat(start.line.to_string().len()), + arrow = "-->".blue().bold(), + filename = filename, + linenum = start.line, + colnum = start.column, + pipe = "|".blue().bold(), + label = start.line.to_string().blue().bold(), + code = code_line.trim_end(), + offset = " ".repeat(start.column), + underline = "^".repeat(end.column - start.column).red().bold(), + message = err.to_string().red(), + ) +} + +fn render_fallback(formatter: &mut fmt::Formatter, err: &syn::Error) -> fmt::Result { + write!(formatter, "Unable to parse file: {}", err) +} -- cgit v1.2.1