diff --git a/cli/src/main.rs b/cli/src/main.rs index dc4b5ae6..db403fea 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -54,6 +54,7 @@ fn run() -> error::Result<()> { .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")) + .arg(Arg::with_name("allow-cancellation").long("cancel")) .arg(Arg::with_name("timeout").long("timeout").takes_value(true)), ) .subcommand( @@ -134,6 +135,7 @@ fn run() -> error::Result<()> { let debug_graph = matches.is_present("debug-graph"); let quiet = matches.is_present("quiet"); let time = matches.is_present("time"); + let allow_cancellation = matches.is_present("allow-cancellation"); let timeout = matches .value_of("timeout") .map_or(0, |t| u64::from_str_radix(t, 10).unwrap()); @@ -170,6 +172,7 @@ fn run() -> error::Result<()> { timeout, debug, debug_graph, + allow_cancellation, )?; } diff --git a/cli/src/parse.rs b/cli/src/parse.rs index f4002233..b5230e77 100644 --- a/cli/src/parse.rs +++ b/cli/src/parse.rs @@ -1,9 +1,10 @@ use super::error::{Error, Result}; use super::util; -use std::fs; use std::io::{self, Write}; use std::path::Path; +use std::sync::atomic::{AtomicU32, Ordering}; use std::time::Instant; +use std::{fs, thread}; use tree_sitter::{Language, LogType, Parser}; pub fn parse_file_at_path( @@ -15,6 +16,7 @@ pub fn parse_file_at_path( timeout: u64, debug: bool, debug_graph: bool, + allow_cancellation: bool, ) -> Result { let mut _log_session = None; let mut parser = Parser::new(); @@ -22,9 +24,28 @@ pub fn parse_file_at_path( let source_code = fs::read(path) .map_err(|e| Error(format!("Error reading source file {:?}: {}", path, e)))?; + // If the `--cancel` flag was passed, then cancel the parse + // when the user types a newline. + if allow_cancellation { + let flag = Box::new(AtomicU32::new(0)); + unsafe { parser.set_cancellation_flag(Some(&flag)) }; + thread::spawn(move || { + let mut line = String::new(); + io::stdin().read_line(&mut line).unwrap(); + eprintln!("Cancelling"); + flag.store(1, Ordering::Relaxed); + }); + } + + // Set a timeout based on the `--time` flag. + parser.set_timeout_micros(timeout); + + // Render an HTML graph if `--debug-graph` was passed if debug_graph { _log_session = Some(util::log_graphs(&mut parser, "log.html")?); - } else if debug { + } + // Log to stderr if `--debug` was passed + else if debug { parser.set_logger(Some(Box::new(|log_type, message| { if log_type == LogType::Lex { io::stderr().write(b" ").unwrap(); @@ -33,7 +54,6 @@ pub fn parse_file_at_path( }))); } - parser.set_timeout_micros(timeout); let time = Instant::now(); let tree = parser.parse(&source_code, None); let duration = time.elapsed(); @@ -139,7 +159,7 @@ pub fn parse_file_at_path( write!(&mut stdout, "\n")?; } - return Ok(first_error.is_some()) + return Ok(first_error.is_some()); } else if print_time { writeln!( &mut stdout, diff --git a/lib/src/atomic.h b/lib/src/atomic.h index 51abccf8..89f40e48 100644 --- a/lib/src/atomic.h +++ b/lib/src/atomic.h @@ -22,7 +22,7 @@ static inline uint32_t atomic_dec(volatile uint32_t *p) { #else static inline uint32_t atomic_load(const volatile uint32_t *p) { - return __atomic_load_n(p, __ATOMIC_SEQ_CST); + return __atomic_load_n(p, __ATOMIC_RELAXED); } static inline uint32_t atomic_inc(volatile uint32_t *p) {