diff --git a/Cargo.lock b/Cargo.lock index fa7712ba..464cd050 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -774,6 +774,7 @@ name = "tree-sitter-cli" version = "0.1.0" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 2eabd88f..b6226917 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -9,6 +9,7 @@ name = "tree-sitter" path = "src/main.rs" [dependencies] +cc = "1.0" ansi_term = "0.11" difference = "2.0" lazy_static = "1.2.0" diff --git a/cli/build.rs b/cli/build.rs new file mode 100644 index 00000000..e0ebd1c4 --- /dev/null +++ b/cli/build.rs @@ -0,0 +1,6 @@ +fn main() { + println!( + "cargo:rustc-env=BUILD_TARGET={}", + std::env::var("TARGET").unwrap() + ); +} diff --git a/cli/src/generate/build_tables/build_parse_table.rs b/cli/src/generate/build_tables/build_parse_table.rs index 73c9c0e2..6af85b4c 100644 --- a/cli/src/generate/build_tables/build_parse_table.rs +++ b/cli/src/generate/build_tables/build_parse_table.rs @@ -1,7 +1,9 @@ use super::item::{ParseItem, ParseItemSet, TokenSet}; use super::item_set_builder::ParseItemSetBuilder; use crate::error::{Error, Result}; -use crate::generate::grammars::{InlinedProductionMap, LexicalGrammar, SyntaxGrammar, VariableType}; +use crate::generate::grammars::{ + InlinedProductionMap, LexicalGrammar, SyntaxGrammar, VariableType, +}; use crate::generate::rules::{Alias, Associativity, Symbol, SymbolType}; use crate::generate::tables::{ AliasSequenceId, ParseAction, ParseState, ParseStateId, ParseTable, ParseTableEntry, @@ -11,6 +13,7 @@ use hashbrown::hash_map::Entry; use hashbrown::{HashMap, HashSet}; use std::collections::hash_map::DefaultHasher; use std::collections::VecDeque; +use std::u32; use std::fmt::Write; use std::hash::Hasher; @@ -94,7 +97,6 @@ impl<'a> ParseTableBuilder<'a> { )?; } - self.populate_used_symbols(); self.remove_precedences(); Ok((self.parse_table, self.following_tokens)) @@ -313,7 +315,10 @@ impl<'a> ParseTableBuilder<'a> { .first_set(&step.symbol) .contains(&conflicting_lookahead) { - conflicting_items.insert(item); + if item.variable_index != u32::MAX { + conflicting_items.insert(item); + } + let precedence = item.precedence(); if let Some(range) = &mut shift_precedence { if precedence < range.start { @@ -327,7 +332,9 @@ impl<'a> ParseTableBuilder<'a> { } } } else if lookaheads.contains(&conflicting_lookahead) { - conflicting_items.insert(item); + if item.variable_index != u32::MAX { + conflicting_items.insert(item); + } } } @@ -610,40 +617,6 @@ impl<'a> ParseTableBuilder<'a> { } } - fn populate_used_symbols(&mut self) { - let mut terminal_usages = vec![false; self.lexical_grammar.variables.len()]; - let mut non_terminal_usages = vec![false; self.syntax_grammar.variables.len()]; - let mut external_usages = vec![false; self.syntax_grammar.external_tokens.len()]; - for state in &self.parse_table.states { - for symbol in state.terminal_entries.keys() { - match symbol.kind { - SymbolType::Terminal => terminal_usages[symbol.index] = true, - SymbolType::External => external_usages[symbol.index] = true, - _ => {} - } - } - for symbol in state.nonterminal_entries.keys() { - non_terminal_usages[symbol.index] = true; - } - } - for (i, value) in external_usages.into_iter().enumerate() { - if value { - self.parse_table.symbols.push(Symbol::external(i)); - } - } - self.parse_table.symbols.push(Symbol::end()); - for (i, value) in terminal_usages.into_iter().enumerate() { - if value { - self.parse_table.symbols.push(Symbol::terminal(i)); - } - } - for (i, value) in non_terminal_usages.into_iter().enumerate() { - if value { - self.parse_table.symbols.push(Symbol::non_terminal(i)); - } - } - } - fn remove_precedences(&mut self) { for state in self.parse_table.states.iter_mut() { for (_, entry) in state.terminal_entries.iter_mut() { @@ -702,7 +675,7 @@ impl<'a> ParseTableBuilder<'a> { if variable.kind == VariableType::Named { variable.name.clone() } else { - format!("\"{}\"", &variable.name) + format!("'{}'", &variable.name) } } } diff --git a/cli/src/generate/build_tables/mod.rs b/cli/src/generate/build_tables/mod.rs index b8432fe5..52c6abac 100644 --- a/cli/src/generate/build_tables/mod.rs +++ b/cli/src/generate/build_tables/mod.rs @@ -15,7 +15,7 @@ use self::token_conflicts::TokenConflictMap; use crate::error::Result; use crate::generate::grammars::{InlinedProductionMap, LexicalGrammar, SyntaxGrammar}; use crate::generate::nfa::{CharacterSet, NfaCursor}; -use crate::generate::rules::{AliasMap, Symbol}; +use crate::generate::rules::{AliasMap, Symbol, SymbolType}; use crate::generate::tables::{LexTable, ParseAction, ParseTable, ParseTableEntry}; pub(crate) fn build_tables( @@ -45,6 +45,7 @@ pub(crate) fn build_tables( &token_conflict_map, &keywords, ); + populate_used_symbols(&mut parse_table, syntax_grammar, lexical_grammar); mark_fragile_tokens(&mut parse_table, lexical_grammar, &token_conflict_map); if minimize { minimize_parse_table( @@ -151,6 +152,44 @@ fn populate_error_state( state.terminal_entries.insert(Symbol::end(), recover_entry); } +fn populate_used_symbols( + parse_table: &mut ParseTable, + syntax_grammar: &SyntaxGrammar, + lexical_grammar: &LexicalGrammar, +) { + let mut terminal_usages = vec![false; lexical_grammar.variables.len()]; + let mut non_terminal_usages = vec![false; syntax_grammar.variables.len()]; + let mut external_usages = vec![false; syntax_grammar.external_tokens.len()]; + for state in &parse_table.states { + for symbol in state.terminal_entries.keys() { + match symbol.kind { + SymbolType::Terminal => terminal_usages[symbol.index] = true, + SymbolType::External => external_usages[symbol.index] = true, + _ => {} + } + } + for symbol in state.nonterminal_entries.keys() { + non_terminal_usages[symbol.index] = true; + } + } + for (i, value) in external_usages.into_iter().enumerate() { + if value { + parse_table.symbols.push(Symbol::external(i)); + } + } + parse_table.symbols.push(Symbol::end()); + for (i, value) in terminal_usages.into_iter().enumerate() { + if value { + parse_table.symbols.push(Symbol::terminal(i)); + } + } + for (i, value) in non_terminal_usages.into_iter().enumerate() { + if value { + parse_table.symbols.push(Symbol::non_terminal(i)); + } + } +} + fn identify_keywords( lexical_grammar: &LexicalGrammar, parse_table: &ParseTable, diff --git a/cli/src/generate/mod.rs b/cli/src/generate/mod.rs index 0899d793..5d89bbfe 100644 --- a/cli/src/generate/mod.rs +++ b/cli/src/generate/mod.rs @@ -3,6 +3,7 @@ use self::parse_grammar::parse_grammar; use self::prepare_grammar::prepare_grammar; use self::render::render_c_code; use crate::error::Result; +use regex::{Regex, RegexBuilder}; use std::fs; use std::io::Write; use std::path::PathBuf; @@ -18,7 +19,14 @@ mod render; mod rules; mod tables; -pub fn generate_parser_for_grammar( +lazy_static! { + static ref JSON_COMMENT_REGEX: Regex = RegexBuilder::new("^\\s*//.*") + .multi_line(true) + .build() + .unwrap(); +} + +pub fn generate_parser_in_directory( repo_path: &PathBuf, minimize: bool, state_ids_to_log: Vec, @@ -26,33 +34,48 @@ pub fn generate_parser_for_grammar( ) -> Result<()> { if !properties_only { let grammar_json = load_js_grammar_file(&repo_path.join("grammar.js")); - let input_grammar = parse_grammar(&grammar_json)?; - let (syntax_grammar, lexical_grammar, inlines, simple_aliases) = - prepare_grammar(&input_grammar)?; - let (parse_table, main_lex_table, keyword_lex_table, keyword_capture_token) = build_tables( - &syntax_grammar, - &lexical_grammar, - &simple_aliases, - &inlines, - minimize, - state_ids_to_log, - )?; - let c_code = render_c_code( - &input_grammar.name, - parse_table, - main_lex_table, - keyword_lex_table, - keyword_capture_token, - syntax_grammar, - lexical_grammar, - simple_aliases, - ); + let c_code = + generate_parser_for_grammar_with_opts(&grammar_json, minimize, state_ids_to_log)?; fs::write(repo_path.join("src").join("parser.c"), c_code)?; } properties::generate_property_sheets(repo_path)?; Ok(()) } +#[cfg(test)] +pub fn generate_parser_for_grammar(grammar_json: &String) -> Result { + let grammar_json = JSON_COMMENT_REGEX.replace_all(grammar_json, "\n"); + generate_parser_for_grammar_with_opts(&grammar_json, true, Vec::new()) +} + +fn generate_parser_for_grammar_with_opts( + grammar_json: &str, + minimize: bool, + state_ids_to_log: Vec, +) -> Result { + let input_grammar = parse_grammar(grammar_json)?; + let (syntax_grammar, lexical_grammar, inlines, simple_aliases) = + prepare_grammar(&input_grammar)?; + let (parse_table, main_lex_table, keyword_lex_table, keyword_capture_token) = build_tables( + &syntax_grammar, + &lexical_grammar, + &simple_aliases, + &inlines, + minimize, + state_ids_to_log, + )?; + Ok(render_c_code( + &input_grammar.name, + parse_table, + main_lex_table, + keyword_lex_table, + keyword_capture_token, + syntax_grammar, + lexical_grammar, + simple_aliases, + )) +} + fn load_js_grammar_file(grammar_path: &PathBuf) -> String { let mut node_process = Command::new("node") .stdin(Stdio::piped()) diff --git a/cli/src/loader.rs b/cli/src/loader.rs index 7dfb233b..e056bbaa 100644 --- a/cli/src/loader.rs +++ b/cli/src/loader.rs @@ -6,6 +6,7 @@ use std::io; use std::mem; use std::path::{Path, PathBuf}; use std::process::Command; +use std::time::SystemTime; use tree_sitter::{Language, PropertySheet}; const PACKAGE_JSON_PATH: &'static str = "package.json"; @@ -37,7 +38,7 @@ pub struct LanguageConfiguration { pub struct Loader { parser_lib_path: PathBuf, language_repos: Vec, - language_configuration_indices_by_file_type: HashMap>, + language_configuration_ids_by_file_type: HashMap>, } unsafe impl Send for Loader {} @@ -48,19 +49,20 @@ impl Loader { Loader { parser_lib_path, language_repos: Vec::new(), - language_configuration_indices_by_file_type: HashMap::new(), + language_configuration_ids_by_file_type: HashMap::new(), } } - pub fn find_parsers(&mut self, parser_src_paths: &Vec) -> io::Result<()> { + pub fn find_all_languages(&mut self, parser_src_paths: &Vec) -> io::Result<()> { for parser_container_dir in parser_src_paths.iter() { for entry in fs::read_dir(parser_container_dir)? { let entry = entry?; if let Some(parser_dir_name) = entry.file_name().to_str() { if parser_dir_name.starts_with("tree-sitter-") { - if self.load_language_configurations( - &parser_container_dir.join(parser_dir_name), - ).is_err() { + if self + .find_language_at_path(&parser_container_dir.join(parser_dir_name)) + .is_err() + { eprintln!("Error loading {}", parser_dir_name); } } @@ -70,90 +72,126 @@ impl Loader { Ok(()) } - pub fn language_configuration_at_path( - &mut self, - path: &Path, - ) -> io::Result> { - let repo_index = self.load_language_configurations(path)?; - self.load_language_from_repo(repo_index, 0) - } - - pub fn language_for_file_name( - &mut self, - path: &Path, - ) -> io::Result> { - let indices = path - .file_name() - .and_then(|n| n.to_str()) - .and_then(|file_name| { - self.language_configuration_indices_by_file_type - .get(file_name) - }) - .or_else(|| { - path.extension() - .and_then(|extension| extension.to_str()) - .and_then(|extension| { - self.language_configuration_indices_by_file_type - .get(extension) - }) - }); - - if let Some(indices) = indices { - // TODO use `content-regex` to pick one - for (repo_index, conf_index) in indices { - return self.load_language_from_repo(*repo_index, *conf_index); - } - } - Ok(None) - } - - fn load_language_from_repo( - &mut self, - repo_index: usize, - conf_index: usize, - ) -> io::Result> { - let repo = &self.language_repos[repo_index]; - let language = if let Some(language) = repo.language { - language - } else { - let language = self.load_language_at_path(&repo.name, &repo.path)?; - self.language_repos[repo_index].language = Some(language); - language - }; - if let Some(configuration) = self.language_repos[repo_index] - .configurations - .get(conf_index) - { - Ok(Some((language, configuration))) + pub fn language_at_path(&mut self, path: &Path) -> io::Result> { + if let Ok(id) = self.find_language_at_path(path) { + Ok(Some(self.language_configuration_for_id(id)?.0)) } else { Ok(None) } } + pub fn language_configuration_for_file_name( + &mut self, + path: &Path, + ) -> io::Result> { + let ids = path + .file_name() + .and_then(|n| n.to_str()) + .and_then(|file_name| self.language_configuration_ids_by_file_type.get(file_name)) + .or_else(|| { + path.extension() + .and_then(|extension| extension.to_str()) + .and_then(|extension| { + self.language_configuration_ids_by_file_type.get(extension) + }) + }); + if let Some(ids) = ids { + // TODO use `content-regex` to pick one + for (repo_id, configuration_id) in ids.iter().cloned() { + let (language, configurations) = self.language_configuration_for_id(repo_id)?; + return Ok(Some((language, &configurations[configuration_id]))); + } + } + Ok(None) + } + + fn language_configuration_for_id( + &mut self, + id: usize, + ) -> io::Result<(Language, &Vec)> { + let repo = &self.language_repos[id]; + let language = if let Some(language) = repo.language { + language + } else { + let language = self.load_language_at_path(&repo.name, &repo.path)?; + self.language_repos[id].language = Some(language); + language + }; + Ok((language, &self.language_repos[id].configurations)) + } + fn load_language_at_path(&self, name: &str, language_path: &Path) -> io::Result { - let parser_c_path = language_path.join(PARSER_C_PATH); + let src_path = language_path.join("src"); + let parser_c_path = src_path.join("parser.c"); + + let scanner_path; + let scanner_c_path = src_path.join("scanner.c"); + if scanner_c_path.exists() { + scanner_path = Some(scanner_c_path); + } else { + let scanner_cc_path = src_path.join("scanner.cc"); + if scanner_cc_path.exists() { + scanner_path = Some(scanner_cc_path); + } else { + scanner_path = None; + } + } + + self.load_language_from_sources(name, &src_path, &parser_c_path, &scanner_path) + } + + pub fn load_language_from_sources( + &self, + name: &str, + header_path: &Path, + parser_path: &Path, + scanner_path: &Option, + ) -> io::Result { let mut library_path = self.parser_lib_path.join(name); library_path.set_extension(DYLIB_EXTENSION); - if !library_path.exists() || was_modified_more_recently(&parser_c_path, &library_path)? { - let compiler_name = std::env::var("CXX").unwrap_or("c++".to_owned()); - let mut command = Command::new(compiler_name); - command - .arg("-shared") - .arg("-fPIC") - .arg("-I") - .arg(language_path.join("src")) - .arg("-o") - .arg(&library_path) - .arg("-xc") - .arg(parser_c_path); - let scanner_c_path = language_path.join(SCANNER_C_PATH); - let scanner_cc_path = language_path.join(SCANNER_CC_PATH); - if scanner_c_path.exists() { - command.arg("-xc").arg(scanner_c_path); - } else if scanner_cc_path.exists() { - command.arg("-xc++").arg(scanner_cc_path); + if needs_recompile(&library_path, &parser_path, &scanner_path)? { + let mut config = cc::Build::new(); + config + .opt_level(2) + .cargo_metadata(false) + .target(env!("BUILD_TARGET")) + .host(env!("BUILD_TARGET")); + let compiler = config.get_compiler(); + let compiler_path = compiler.path(); + let mut command = Command::new(compiler_path); + + if cfg!(windows) { + command + .args(&["/nologo", "/LD", "/I"]) + .arg(header_path) + .arg("/Od") + .arg(parser_path); + if let Some(scanner_path) = scanner_path.as_ref() { + command.arg(scanner_path); + } + command + .arg("/link") + .arg(format!("/out:{}", library_path.to_str().unwrap())); + } else { + command + .arg("-shared") + .arg("-fPIC") + .arg("-I") + .arg(header_path) + .arg("-o") + .arg(&library_path) + .arg("-xc") + .arg(parser_path); + if let Some(scanner_path) = scanner_path.as_ref() { + if scanner_path.extension() == Some("c".as_ref()) { + command.arg(scanner_path); + } else { + command.arg("-xc++").arg(scanner_path); + } + } } + command.output()?; } @@ -168,7 +206,7 @@ impl Loader { Ok(language) } - fn load_language_configurations<'a>(&'a mut self, parser_path: &Path) -> io::Result { + fn find_language_at_path<'a>(&'a mut self, parser_path: &Path) -> io::Result { let name = parser_path .file_name() .unwrap() @@ -218,7 +256,7 @@ impl Loader { for (i, configuration) in configurations.iter().enumerate() { for file_type in &configuration.file_types { - self.language_configuration_indices_by_file_type + self.language_configuration_ids_by_file_type .entry(file_type.to_string()) .or_insert(Vec::new()) .push((self.language_repos.len(), i)); @@ -236,6 +274,26 @@ impl Loader { } } -fn was_modified_more_recently(a: &Path, b: &Path) -> io::Result { - Ok(fs::metadata(a)?.modified()? > fs::metadata(b)?.modified()?) +fn needs_recompile( + lib_path: &Path, + parser_c_path: &Path, + scanner_path: &Option, +) -> io::Result { + if !lib_path.exists() { + return Ok(true); + } + let lib_mtime = mtime(lib_path)?; + if mtime(parser_c_path)? > lib_mtime { + return Ok(true); + } + if let Some(scanner_path) = scanner_path { + if mtime(scanner_path)? > lib_mtime { + return Ok(true); + } + } + Ok(false) +} + +fn mtime(path: &Path) -> io::Result { + Ok(fs::metadata(path)?.modified()?) } diff --git a/cli/src/main.rs b/cli/src/main.rs index 9f095668..dda4bdca 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -89,13 +89,18 @@ fn run() -> error::Result<()> { ids.filter_map(|id| usize::from_str_radix(id, 10).ok()) .collect() }); - generate::generate_parser_for_grammar(¤t_dir, minimize, state_ids_to_log, properties_only)?; + generate::generate_parser_in_directory( + ¤t_dir, + minimize, + state_ids_to_log, + properties_only, + )?; } else if let Some(matches) = matches.subcommand_matches("test") { let debug = matches.is_present("debug"); let debug_graph = matches.is_present("debug-graph"); let filter = matches.value_of("filter"); let corpus_path = current_dir.join("corpus"); - if let Some((language, _)) = loader.language_configuration_at_path(¤t_dir)? { + if let Some(language) = loader.language_at_path(¤t_dir)? { test::run_tests_at_path(language, &corpus_path, debug, debug_graph, filter)?; } else { eprintln!("No language found"); @@ -103,9 +108,9 @@ 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"); - loader.find_parsers(&vec![home_dir.join("github")])?; + 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_for_file_name(source_path)? { + 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"); diff --git a/cli/src/tests/corpuses.rs b/cli/src/tests/corpuses.rs index b70bb371..624786fc 100644 --- a/cli/src/tests/corpuses.rs +++ b/cli/src/tests/corpuses.rs @@ -1,6 +1,9 @@ use super::languages; +use crate::generate; +use crate::loader::Loader; use crate::test::{parse_tests, TestEntry}; -use std::path::PathBuf; +use std::fs; +use std::path::{Path, PathBuf}; use tree_sitter::{Language, Parser}; lazy_static! { @@ -12,20 +15,16 @@ lazy_static! { ("html", languages::html()), ("javascript", languages::javascript()), ]; + static ref ROOT_DIR: PathBuf = [env!("CARGO_MANIFEST_DIR"), ".."].iter().collect(); + static ref HEADER_DIR: PathBuf = ROOT_DIR.join("lib").join("include"); + static ref SCRATCH_DIR: PathBuf = ROOT_DIR.join("target").join("scratch"); + static ref FIXTURES_DIR: PathBuf = ROOT_DIR.join("test").join("fixtures"); } #[test] -fn test_corpus_files() { +fn test_real_language_corpus_files() { let mut parser = Parser::new(); - let grammars_dir: PathBuf = [ - env!("CARGO_MANIFEST_DIR"), - "..", - "test", - "fixtures", - "grammars", - ] - .iter() - .collect(); + let grammars_dir = FIXTURES_DIR.join("grammars"); for (name, language) in LANGUAGES.iter().cloned() { let corpus_dir = grammars_dir.join(name).join("corpus"); @@ -35,6 +34,61 @@ fn test_corpus_files() { } } +#[test] +fn test_feature_corpus_files() { + fs::create_dir_all(SCRATCH_DIR.as_path()).unwrap(); + + let mut loader = Loader::new(SCRATCH_DIR.clone()); + let mut parser = Parser::new(); + let test_grammars_dir = FIXTURES_DIR.join("test_grammars"); + + for entry in fs::read_dir(&test_grammars_dir).unwrap() { + let entry = entry.unwrap(); + let test_name = entry.file_name(); + let test_name = test_name.to_str().unwrap(); + + eprintln!("test name: {}", test_name); + let test_path = entry.path(); + let grammar_path = test_path.join("grammar.json"); + let corpus_path = test_path.join("corpus.txt"); + let error_message_path = test_path.join("expected_error.txt"); + + let grammar_json = fs::read_to_string(grammar_path).unwrap(); + let generate_result = generate::generate_parser_for_grammar(&grammar_json); + if error_message_path.exists() { + continue; + if let Err(e) = generate_result { + assert_eq!(e.0, fs::read_to_string(&error_message_path).unwrap()); + } else { + panic!( + "Expected error message but got none for test grammar '{}'", + test_name + ); + } + } else { + let c_code = generate_result.unwrap(); + let parser_c_path = SCRATCH_DIR.join(&format!("{}-parser.c", test_name)); + fs::write(&parser_c_path, c_code).unwrap(); + let scanner_path = test_path.join("scanner.c"); + let scanner_path = if scanner_path.exists() { + Some(scanner_path) + } else { + None + }; + let language = loader + .load_language_from_sources(test_name, &HEADER_DIR, &parser_c_path, &scanner_path) + .unwrap(); + } + } + + // for (name, language) in LANGUAGES.iter().cloned() { + // let corpus_dir = grammars_dir.join(name).join("corpus"); + // let test = parse_tests(&corpus_dir).unwrap(); + // parser.set_language(language).unwrap(); + // run_mutation_tests(&mut parser, test); + // } +} + fn run_mutation_tests(parser: &mut Parser, test: TestEntry) { match test { TestEntry::Example { diff --git a/cli/src/tests/parser_api.rs b/cli/src/tests/parser_api.rs index af5ba71f..e32c292b 100644 --- a/cli/src/tests/parser_api.rs +++ b/cli/src/tests/parser_api.rs @@ -1,6 +1,6 @@ use super::languages::rust; use std::thread; -use tree_sitter::{InputEdit, LogType, Parser, Point, PropertySheet, Range}; +use tree_sitter::{InputEdit, LogType, Parser, Point, PropertySheet}; #[test] fn test_basic_parsing() { diff --git a/test/fixtures/test_grammars/aliased_rules/grammar.json b/test/fixtures/test_grammars/aliased_rules/grammar.json index 391f780f..a66bfb78 100644 --- a/test/fixtures/test_grammars/aliased_rules/grammar.json +++ b/test/fixtures/test_grammars/aliased_rules/grammar.json @@ -40,7 +40,7 @@ {"type": "SYMBOL", "name": "_expression"}, {"type": "STRING", "value": "("}, {"type": "SYMBOL", "name": "_expression"}, - {"type": "STRING", "value": ")"}, + {"type": "STRING", "value": ")"} ] } }, diff --git a/test/fixtures/test_grammars/conflict_in_repeat_rule_after_external_token/grammar.json b/test/fixtures/test_grammars/conflict_in_repeat_rule_after_external_token/grammar.json index 0be2008c..d97d9c9d 100644 --- a/test/fixtures/test_grammars/conflict_in_repeat_rule_after_external_token/grammar.json +++ b/test/fixtures/test_grammars/conflict_in_repeat_rule_after_external_token/grammar.json @@ -2,7 +2,7 @@ "name": "conflict_in_repeat_rule_after_external_token", "externals": [ - {"type": "SYMBOL", "name": "_program_start"}, + {"type": "SYMBOL", "name": "_program_start"} ], "rules": { diff --git a/test/fixtures/test_grammars/external_tokens/grammar.json b/test/fixtures/test_grammars/external_tokens/grammar.json index d61a978f..e5ca6bc9 100644 --- a/test/fixtures/test_grammars/external_tokens/grammar.json +++ b/test/fixtures/test_grammars/external_tokens/grammar.json @@ -45,7 +45,7 @@ {"type": "SYMBOL", "name": "expression"}, {"type": "SYMBOL", "name": "_percent_string_end"} ] - }, + } ] }, diff --git a/test/fixtures/test_grammars/inverted_external_token/grammar.json b/test/fixtures/test_grammars/inverted_external_token/grammar.json index a43cedcc..6dee3d03 100644 --- a/test/fixtures/test_grammars/inverted_external_token/grammar.json +++ b/test/fixtures/test_grammars/inverted_external_token/grammar.json @@ -15,7 +15,7 @@ "content": { "type": "SYMBOL", "name": "statement" - }, + } }, "statement": { diff --git a/test/fixtures/test_grammars/precedence_on_subsequence/grammar.json b/test/fixtures/test_grammars/precedence_on_subsequence/grammar.json index d05db765..d992793c 100644 --- a/test/fixtures/test_grammars/precedence_on_subsequence/grammar.json +++ b/test/fixtures/test_grammars/precedence_on_subsequence/grammar.json @@ -110,7 +110,7 @@ "type": "SEQ", "members": [ {"type": "STRING", "value": "::"}, - {"type": "SYMBOL", "name": "expression"}, + {"type": "SYMBOL", "name": "expression"} ] } ] @@ -132,4 +132,4 @@ "value": "[a-zA-Z]+" } } -} \ No newline at end of file +}