Get parse command handling multiple files, add --time, --quiet flags

This commit is contained in:
Max Brunsfeld 2019-01-17 17:15:10 -08:00
parent 71357afb2f
commit cbcc61a8cf
4 changed files with 157 additions and 62 deletions

View file

@ -56,12 +56,8 @@ impl Loader {
let entry = entry?;
if let Some(parser_dir_name) = entry.file_name().to_str() {
if parser_dir_name.starts_with("tree-sitter-") {
if self
.find_language_at_path(&parser_container_dir.join(parser_dir_name))
.is_err()
{
eprintln!("Error loading {}", parser_dir_name);
}
self.find_language_at_path(&parser_container_dir.join(parser_dir_name))
.ok();
}
}
}

View file

@ -37,7 +37,12 @@ fn main() {
fn run() -> error::Result<()> {
let matches = App::new("tree-sitter")
.version(concat!(env!("CARGO_PKG_VERSION"), " (", env!("BUILD_SHA"), ")"))
.version(concat!(
env!("CARGO_PKG_VERSION"),
" (",
env!("BUILD_SHA"),
")"
))
.setting(AppSettings::SubcommandRequiredElseHelp)
.author("Max Brunsfeld <maxbrunsfeld@gmail.com>")
.about("Generates and tests parsers")
@ -57,9 +62,16 @@ fn run() -> error::Result<()> {
.subcommand(
SubCommand::with_name("parse")
.about("Parse a file")
.arg(Arg::with_name("path").index(1).required(true))
.arg(
Arg::with_name("path")
.index(1)
.multiple(true)
.required(true),
)
.arg(Arg::with_name("debug").long("debug").short("d"))
.arg(Arg::with_name("debug-graph").long("debug-graph").short("D")),
.arg(Arg::with_name("debug-graph").long("debug-graph").short("D"))
.arg(Arg::with_name("quiet").long("quiet").short("q"))
.arg(Arg::with_name("time").long("time").short("t")),
)
.subcommand(
SubCommand::with_name("test")
@ -116,12 +128,35 @@ fn run() -> error::Result<()> {
} else if let Some(matches) = matches.subcommand_matches("parse") {
let debug = matches.is_present("debug");
let debug_graph = matches.is_present("debug-graph");
let quiet = matches.is_present("quiet");
let time = matches.is_present("time");
loader.find_all_languages(&vec![home_dir.join("github")])?;
let source_path = Path::new(matches.value_of("path").unwrap());
if let Some((language, _)) = loader.language_configuration_for_file_name(source_path)? {
parse::parse_file_at_path(language, source_path, debug, debug_graph)?;
} else {
eprintln!("No language found");
let paths = matches
.values_of("path")
.unwrap()
.into_iter()
.collect::<Vec<_>>();
let max_path_length = paths.iter().map(|p| p.chars().count()).max().unwrap();
for path in paths {
let path = Path::new(path);
let language =
if let Some((l, _)) = loader.language_configuration_for_file_name(path)? {
l
} else if let Some(l) = loader.language_at_path(&current_dir)? {
l
} else {
eprintln!("No language found");
return Ok(());
};
parse::parse_file_at_path(
language,
path,
max_path_length,
quiet,
time,
debug,
debug_graph,
)?;
}
}

View file

@ -3,21 +3,25 @@ use super::util;
use std::fs;
use std::io::{self, Write};
use std::path::Path;
use std::time::Instant;
use tree_sitter::{Language, LogType, Parser};
pub fn parse_file_at_path(
language: Language,
path: &Path,
max_path_length: usize,
quiet: bool,
print_time: bool,
debug: bool,
debug_graph: bool,
) -> Result<()> {
let mut log_session = None;
let mut _log_session = None;
let mut parser = Parser::new();
parser.set_language(language)?;
let source_code = fs::read_to_string(path)?;
let source_code = fs::read(path)?;
if debug_graph {
log_session = Some(util::log_graphs(&mut parser, "log.html")?);
_log_session = Some(util::log_graphs(&mut parser, "log.html")?);
} else if debug {
parser.set_logger(Some(Box::new(|log_type, message| {
if log_type == LogType::Lex {
@ -27,64 +31,111 @@ pub fn parse_file_at_path(
})));
}
let time = Instant::now();
let tree = parser
.parse_str(&source_code, None)
.parse_utf8(&mut |byte, _| &source_code[byte..], None)
.expect("Incompatible language version");
let duration = time.elapsed();
let duration_ms = duration.as_secs() * 1000 + duration.subsec_nanos() as u64 / 1000000;
drop(log_session);
let mut cursor = tree.walk();
let stdout = io::stdout();
let mut stdout = stdout.lock();
let mut cursor = tree.walk();
let mut needs_newline = false;
let mut indent_level = 0;
let mut did_visit_children = false;
if !quiet {
let mut needs_newline = false;
let mut indent_level = 0;
let mut did_visit_children = false;
loop {
let node = cursor.node();
let is_named = node.is_named();
if did_visit_children {
if is_named {
stdout.write(b")")?;
needs_newline = true;
}
if cursor.goto_next_sibling() {
did_visit_children = false;
} else if cursor.goto_parent() {
did_visit_children = true;
indent_level -= 1;
} else {
break;
}
} else {
if is_named {
if needs_newline {
stdout.write(b"\n")?;
}
for _ in 0..indent_level {
stdout.write(b" ")?;
}
let start = node.start_position();
let end = node.end_position();
write!(
&mut stdout,
"({} [{}, {}] - [{}, {}]",
node.kind(),
start.row,
start.column,
end.row,
end.column
)?;
needs_newline = true;
}
if cursor.goto_first_child() {
did_visit_children = false;
indent_level += 1;
} else {
did_visit_children = true;
}
}
}
cursor.reset(tree.root_node());
println!("");
}
let mut first_error = None;
loop {
let node = cursor.node();
let is_named = node.is_named();
if did_visit_children {
if is_named {
stdout.write(b")")?;
needs_newline = true;
}
if cursor.goto_next_sibling() {
did_visit_children = false;
} else if cursor.goto_parent() {
did_visit_children = true;
indent_level -= 1;
} else {
if node.has_error() {
if node.is_error() || node.is_missing() {
first_error = Some(node);
break;
}
} else {
if is_named {
if needs_newline {
stdout.write(b"\n")?;
}
for _ in 0..indent_level {
stdout.write(b" ")?;
}
let start = node.start_position();
let end = node.end_position();
write!(
&mut stdout,
"({} [{}, {}] - [{}, {}]",
node.kind(),
start.row,
start.column,
end.row,
end.column
)?;
needs_newline = true;
}
if cursor.goto_first_child() {
did_visit_children = false;
indent_level += 1;
} else {
did_visit_children = true;
cursor.goto_first_child();
}
} else if !cursor.goto_next_sibling() {
if !cursor.goto_parent() {
break;
}
}
}
println!("");
if first_error.is_some() || print_time {
write!(
&mut stdout,
"{:width$}\t{} ms",
path.to_str().unwrap(),
duration_ms,
width = max_path_length
)?;
if let Some(node) = first_error {
let start = node.start_position();
let end = node.end_position();
write!(
&mut stdout,
"\t({} [{}, {}] - [{}, {}]",
node.kind(),
start.row,
start.column,
end.row,
end.column
)?;
}
write!(&mut stdout, "\n")?;
}
Ok(())
}

View file

@ -19,6 +19,7 @@ use std::marker::PhantomData;
use std::os::raw::{c_char, c_void};
use std::ptr;
use std::str;
use std::u16;
#[derive(Clone, Copy)]
#[repr(transparent)]
@ -479,6 +480,14 @@ impl<'tree> Node<'tree> {
unsafe { ffi::ts_node_has_error(self.0) }
}
pub fn is_error(&self) -> bool {
self.kind_id() == u16::MAX
}
pub fn is_missing(&self) -> bool {
unsafe { ffi::ts_node_is_missing(self.0) }
}
pub fn start_byte(&self) -> usize {
unsafe { ffi::ts_node_start_byte(self.0) as usize }
}
@ -622,6 +631,10 @@ impl<'a> TreeCursor<'a> {
Some(result as usize)
}
}
pub fn reset(&mut self, node: Node<'a>) {
unsafe { ffi::ts_tree_cursor_reset(&mut self.0, node.0) };
}
}
impl<'a> Drop for TreeCursor<'a> {