diff --git a/Cargo.lock b/Cargo.lock index 3a15dd56..84685ba4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -82,9 +82,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" [[package]] name = "arbitrary" @@ -980,9 +980,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -1257,18 +1257,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", diff --git a/cli/benches/benchmark.rs b/cli/benches/benchmark.rs index f7700dd7..0712facc 100644 --- a/cli/benches/benchmark.rs +++ b/cli/benches/benchmark.rs @@ -5,7 +5,7 @@ use std::path::{Path, PathBuf}; use std::time::Instant; use std::{env, fs, str, usize}; use tree_sitter::{Language, Parser, Query}; -use tree_sitter_loader::Loader; +use tree_sitter_loader::{CompileConfig, Loader}; include!("../src/tests/helpers/dirs.rs"); @@ -210,9 +210,9 @@ fn parse(path: &Path, max_path_length: usize, mut action: impl FnMut(&[u8])) -> } fn get_language(path: &Path) -> Language { - let src_dir = GRAMMARS_DIR.join(path).join("src"); + let src_path = GRAMMARS_DIR.join(path).join("src"); TEST_LOADER - .load_language_at_path(&src_dir, &[&src_dir], None) - .with_context(|| format!("Failed to load language at path {src_dir:?}")) + .load_language_at_path(CompileConfig::new(&src_path, None, None)) + .with_context(|| format!("Failed to load language at path {src_path:?}")) .unwrap() } diff --git a/cli/loader/src/lib.rs b/cli/loader/src/lib.rs index 9556bc99..9c1d8dfc 100644 --- a/cli/loader/src/lib.rs +++ b/cli/loader/src/lib.rs @@ -78,12 +78,6 @@ impl Config { } } -#[cfg(unix)] -const DYLIB_EXTENSION: &str = "so"; - -#[cfg(windows)] -const DYLIB_EXTENSION: &str = "dll"; - const BUILD_TARGET: &str = env!("BUILD_TARGET"); pub struct LanguageConfiguration<'a> { @@ -106,7 +100,7 @@ pub struct LanguageConfiguration<'a> { } pub struct Loader { - parser_lib_path: PathBuf, + pub parser_lib_path: PathBuf, languages_by_id: Vec<(PathBuf, OnceCell, Option>)>, language_configurations: Vec>, language_configuration_ids_by_file_type: HashMap>, @@ -120,6 +114,36 @@ pub struct Loader { wasm_store: Mutex>, } +pub struct CompileConfig<'a> { + pub src_path: &'a Path, + pub header_paths: Vec<&'a Path>, + pub parser_path: PathBuf, + pub scanner_path: Option, + pub external_files: Option<&'a [PathBuf]>, + pub output_path: Option, + pub flags: &'a [&'a str], + pub name: String, +} + +impl<'a> CompileConfig<'a> { + pub fn new( + src_path: &'a Path, + externals: Option<&'a [PathBuf]>, + output_path: Option, + ) -> CompileConfig<'a> { + Self { + src_path, + header_paths: vec![src_path], + parser_path: src_path.join("parser.c"), + scanner_path: None, + external_files: externals, + output_path, + flags: &["TREE_SITTER_REUSE_ALLOCATOR", "TREE_SITTER_INTERNAL_BUILD"], + name: String::new(), + } + } +} + unsafe impl Send for Loader {} unsafe impl Sync for Loader {} @@ -353,18 +377,29 @@ impl Loader { language .get_or_try_init(|| { let src_path = path.join("src"); - self.load_language_at_path(&src_path, &[&src_path], externals.as_deref()) + self.load_language_at_path(CompileConfig::new( + &src_path, + externals.as_deref(), + None, + )) }) .cloned() } - pub fn load_language_at_path( + pub fn compile_parser_at_path( &self, - src_path: &Path, - header_paths: &[&Path], - external_files: Option<&[PathBuf]>, - ) -> Result { - let grammar_path = src_path.join("grammar.json"); + grammar_path: &Path, + output_path: PathBuf, + flags: &[&str], + ) -> Result<()> { + let src_path = grammar_path.join("src"); + let mut config = CompileConfig::new(&src_path, None, Some(output_path)); + config.flags = flags; + self.load_language_at_path(config).map(|_| ()) + } + + pub fn load_language_at_path(&self, mut config: CompileConfig) -> Result { + let grammar_path = config.src_path.join("grammar.json"); #[derive(Deserialize)] struct GrammarJSON { @@ -375,85 +410,90 @@ impl Loader { let grammar_json: GrammarJSON = serde_json::from_reader(BufReader::new(&mut grammar_file)) .with_context(|| "Failed to parse grammar.json")?; - self.load_language_at_path_with_name( - src_path, - header_paths, - &grammar_json.name, - external_files, - ) + config.name = grammar_json.name; + + self.load_language_at_path_with_name(config) } - pub fn load_language_at_path_with_name( - &self, - src_path: &Path, - header_paths: &[&Path], - name: &str, - external_files: Option<&[PathBuf]>, - ) -> Result { - let mut lib_name = name.to_string(); - let language_fn_name = format!("tree_sitter_{}", replace_dashes_with_underscores(name)); + pub fn load_language_at_path_with_name(&self, mut config: CompileConfig) -> Result { + let mut lib_name = config.name.to_string(); + let language_fn_name = format!( + "tree_sitter_{}", + replace_dashes_with_underscores(&config.name) + ); if self.debug_build { lib_name.push_str(".debug._"); } - fs::create_dir_all(&self.parser_lib_path)?; + if config.output_path.is_none() { + fs::create_dir_all(&self.parser_lib_path)?; + } - let mut library_path = self.parser_lib_path.join(lib_name); - library_path.set_extension(DYLIB_EXTENSION); + let mut recompile = config.output_path.is_some(); // if specified, always recompile - let parser_path = src_path.join("parser.c"); - let scanner_path = self.get_scanner_path(src_path); + let output_path = config.output_path.unwrap_or_else(|| { + let mut path = self.parser_lib_path.join(lib_name); + path.set_extension(env::consts::DLL_EXTENSION); + #[cfg(feature = "wasm")] + if self.wasm_store.lock().unwrap().is_some() { + path.set_extension("wasm"); + } + path + }); + config.output_path = Some(output_path.clone()); + + let parser_path = config.src_path.join("parser.c"); + config.scanner_path = self.get_scanner_path(config.src_path); let mut paths_to_check = vec![parser_path.clone()]; - if let Some(scanner_path) = scanner_path.as_ref() { + if let Some(scanner_path) = config.scanner_path.as_ref() { paths_to_check.push(scanner_path.clone()); } paths_to_check.extend( - external_files + config + .external_files .unwrap_or_default() .iter() - .map(|p| src_path.join(p)), + .map(|p| config.src_path.join(p)), ); - #[cfg(feature = "wasm")] - if self.wasm_store.lock().unwrap().is_some() { - library_path.set_extension("wasm"); + if !recompile { + recompile = needs_recompile(&output_path, &paths_to_check) + .with_context(|| "Failed to compare source and binary timestamps")?; } - let mut recompile = needs_recompile(&library_path, &paths_to_check) - .with_context(|| "Failed to compare source and binary timestamps")?; - #[cfg(feature = "wasm")] if let Some(wasm_store) = self.wasm_store.lock().unwrap().as_mut() { if recompile { self.compile_parser_to_wasm( - name, - src_path, - scanner_path + &config.name, + config.src_path, + config + .scanner_path .as_ref() - .and_then(|p| p.strip_prefix(src_path).ok()), - &library_path, + .and_then(|p| p.strip_prefix(config.src_path).ok()), + &output_path, false, )?; } - let wasm_bytes = fs::read(&library_path)?; - return Ok(wasm_store.load_language(name, &wasm_bytes)?); + let wasm_bytes = fs::read(&output_path)?; + return Ok(wasm_store.load_language(&config.name, &wasm_bytes)?); } let lock_path = if env::var("CROSS_RUNNER").is_ok() { PathBuf::from("/tmp") .join("tree-sitter") .join("lock") - .join(format!("{name}.lock")) + .join(format!("{}.lock", config.name)) } else { dirs::cache_dir() .ok_or_else(|| anyhow!("Cannot determine cache directory"))? .join("tree-sitter") .join("lock") - .join(format!("{name}.lock")) + .join(format!("{}.lock", config.name)) }; if let Ok(lock_file) = fs::OpenOptions::new().write(true).open(&lock_path) { @@ -488,22 +528,15 @@ impl Loader { .open(&lock_path)?; lock_file.lock_exclusive()?; - self.compile_parser_to_dylib( - header_paths, - &parser_path, - scanner_path.as_deref(), - &library_path, - &lock_file, - &lock_path, - )?; + self.compile_parser_to_dylib(&config, &lock_file, &lock_path)?; - if scanner_path.is_some() { - self.check_external_scanner(name, &library_path)?; + if config.scanner_path.is_some() { + self.check_external_scanner(&config.name, &output_path)?; } } - let library = unsafe { Library::new(&library_path) } - .with_context(|| format!("Error opening dynamic library {library_path:?}"))?; + let library = unsafe { Library::new(&output_path) } + .with_context(|| format!("Error opening dynamic library {output_path:?}"))?; let language = unsafe { let language_fn = library .get:: Language>>(language_fn_name.as_bytes()) @@ -516,32 +549,30 @@ impl Loader { fn compile_parser_to_dylib( &self, - header_paths: &[&Path], - parser_path: &Path, - scanner_path: Option<&Path>, - library_path: &Path, + config: &CompileConfig, lock_file: &fs::File, lock_path: &Path, ) -> Result<(), Error> { - let mut config = cc::Build::new(); - config - .cpp(true) + let mut cc = cc::Build::new(); + cc.cpp(true) .opt_level(2) .cargo_metadata(false) .cargo_warnings(false) .target(BUILD_TARGET) .host(BUILD_TARGET) .flag_if_supported("-Werror=implicit-function-declaration"); - let compiler = config.get_compiler(); + let compiler = cc.get_compiler(); let mut command = Command::new(compiler.path()); for (key, value) in compiler.env() { command.env(key, value); } + let output_path = config.output_path.as_ref().unwrap(); + if compiler.is_like_msvc() { command.args(["/nologo", "/LD"]); - for path in header_paths { + for path in &config.header_paths { command.arg(format!("/I{}", path.to_string_lossy())); } @@ -550,9 +581,9 @@ impl Loader { } else { command.arg("/O2"); } - command.arg(parser_path); + command.arg(&config.parser_path); - if let Some(scanner_path) = scanner_path.as_ref() { + if let Some(scanner_path) = config.scanner_path.as_ref() { if scanner_path.extension() != Some("c".as_ref()) { eprintln!("Warning: Using a C++ scanner is now deprecated. Please migrate your scanner code to C, as C++ support will be removed in the near future."); } @@ -561,16 +592,16 @@ impl Loader { } command .arg("/link") - .arg(format!("/out:{}", library_path.to_str().unwrap())); + .arg(format!("/out:{}", output_path.to_str().unwrap())); } else { command .arg("-shared") .arg("-fno-exceptions") .arg("-g") .arg("-o") - .arg(library_path); + .arg(output_path); - for path in header_paths { + for path in &config.header_paths { command.arg(format!("-I{}", path.to_string_lossy())); } @@ -584,7 +615,7 @@ impl Loader { command.arg("-O2"); } - if let Some(scanner_path) = scanner_path.as_ref() { + if let Some(scanner_path) = config.scanner_path.as_ref() { if scanner_path.extension() == Some("c".as_ref()) { command.arg("-xc").arg("-std=c11").arg(scanner_path); } else { @@ -592,7 +623,7 @@ impl Loader { command.arg(scanner_path); } } - command.arg("-xc").arg(parser_path); + command.arg("-xc").arg(&config.parser_path); } // For conditional compilation of external scanner code when @@ -967,7 +998,6 @@ impl Loader { .map(|path| { let path = parser_path.join(path); // prevent p being above/outside of parser_path - if path.starts_with(parser_path) { Ok(path) } else { diff --git a/cli/src/generate/templates/package.json b/cli/src/generate/templates/package.json index fe67099b..39b5f71c 100644 --- a/cli/src/generate/templates/package.json +++ b/cli/src/generate/templates/package.json @@ -40,7 +40,7 @@ "install": "node-gyp-build", "prebuildify": "prebuildify --napi --strip", "build": "tree-sitter generate --no-bindings", - "build-wasm": "tree-sitter build-wasm", + "build-wasm": "tree-sitter build --wasm", "test": "tree-sitter test", "parse": "tree-sitter parse" }, diff --git a/cli/src/main.rs b/cli/src/main.rs index c46d38d7..0337ead0 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -27,12 +27,12 @@ const DEFAULT_GENERATE_ABI_VERSION: usize = 14; enum Commands { InitConfig(InitConfig), Generate(Generate), + Build(Build), Parse(Parse), Test(Test), Query(Query), Highlight(Highlight), Tags(Tags), - BuildWasm(BuildWasm), Playground(Playground), DumpLanguages(DumpLanguages), } @@ -91,6 +91,30 @@ struct Generate { pub js_runtime: Option, } +#[derive(Args)] +#[command(about = "Compile a parser", alias = "b")] +struct Build { + #[arg(short, long, help = "Build a WASM module instead of a dynamic library")] + pub wasm: bool, + #[arg( + short, + long, + help = "Run emscripten via docker even if it is installed locally (only if building a WASM module with --wasm)" + )] + pub docker: bool, + #[arg(short, long, help = "The path to output the compiled file")] + pub output: Option, + #[arg(index = 1, num_args = 1, help = "The path to the grammar directory")] + pub path: Option, + #[arg(long, help = "Make the parser reuse the same allocator as the library")] + pub reuse_allocator: bool, + #[arg( + long, + help = "Build the parser with `TREE_SITTER_INTERNAL_BUILD` defined" + )] + pub internal_build: bool, +} + #[derive(Args)] #[command(about = "Parse files", alias = "p")] struct Parse { @@ -298,18 +322,6 @@ struct Tags { pub config_path: Option, } -#[derive(Args)] -#[command(about = "Compile a parser to WASM", alias = "bw")] -struct BuildWasm { - #[arg( - long, - help = "Run emscripten via docker even if it is installed locally" - )] - pub docker: bool, - #[arg(index = 1, num_args = 1.., help = "The path to output the wasm file")] - pub path: Option, -} - #[derive(Args)] #[command( about = "Start local playground for a parser in the browser", @@ -428,6 +440,64 @@ fn run() -> Result<()> { } } + Commands::Build(build_options) => { + if build_options.wasm { + let grammar_path = + current_dir.join(build_options.path.as_deref().unwrap_or_default()); + let (output_dir, output_path) = if let Some(ref path) = build_options.output { + (current_dir.clone(), Some(current_dir.join(path))) + } else { + (loader.parser_lib_path.clone(), None) + }; + wasm::compile_language_to_wasm( + &loader, + &grammar_path, + &output_dir, + output_path, + build_options.docker, + )?; + } else { + let grammar_path = + current_dir.join(build_options.path.as_deref().unwrap_or_default()); + let output_path = if let Some(ref path) = build_options.output { + let path = Path::new(path); + if path.is_absolute() { + path.to_path_buf() + } else { + current_dir.join(path) + } + } else { + let file_name = grammar_path + .file_stem() + .unwrap() + .to_str() + .unwrap() + .strip_prefix("tree-sitter-") + .unwrap_or("parser"); + current_dir + .join(file_name) + .with_extension(env::consts::DLL_EXTENSION) + }; + + let flags: &[&str] = + match (build_options.reuse_allocator, build_options.internal_build) { + (true, true) => { + &["TREE_SITTER_REUSE_ALLOCATOR", "TREE_SITTER_INTERNAL_BUILD"] + } + (true, false) => &["TREE_SITTER_REUSE_ALLOCATOR"], + (false, true) => &["TREE_SITTER_INTERNAL_BUILD"], + (false, false) => &[""], + }; + + let config = Config::load(None)?; + let loader_config = config.get()?; + loader.find_all_languages(&loader_config).unwrap(); + loader + .compile_parser_at_path(&grammar_path, output_path, flags) + .unwrap(); + } + } + Commands::Parse(parse_options) => { let config = Config::load(parse_options.config_path)?; let output = if parse_options.output_dot { @@ -770,16 +840,6 @@ fn run() -> Result<()> { )?; } - Commands::BuildWasm(wasm_options) => { - let grammar_path = current_dir.join(wasm_options.path.unwrap_or_default()); - wasm::compile_language_to_wasm( - &loader, - &grammar_path, - ¤t_dir, - wasm_options.docker, - )?; - } - Commands::Playground(playground_options) => { let open_in_browser = !playground_options.quiet; let grammar_path = playground_options diff --git a/cli/src/tests/helpers/fixtures.rs b/cli/src/tests/helpers/fixtures.rs index bad016c4..a3cecb63 100644 --- a/cli/src/tests/helpers/fixtures.rs +++ b/cli/src/tests/helpers/fixtures.rs @@ -4,7 +4,7 @@ use std::path::{Path, PathBuf}; use std::{env, fs}; use tree_sitter::Language; use tree_sitter_highlight::HighlightConfiguration; -use tree_sitter_loader::Loader; +use tree_sitter_loader::{CompileConfig, Loader}; use tree_sitter_tags::TagsConfiguration; include!("./dirs.rs"); @@ -32,13 +32,10 @@ pub fn scratch_dir() -> &'static Path { } pub fn get_language(name: &str) -> Language { - TEST_LOADER - .load_language_at_path( - &GRAMMARS_DIR.join(name).join("src"), - &[&HEADER_DIR, &GRAMMARS_DIR.join(name).join("src")], - None, - ) - .unwrap() + let src_dir = GRAMMARS_DIR.join(name).join("src"); + let mut config = CompileConfig::new(&src_dir, None, None); + config.header_paths.push(&HEADER_DIR); + TEST_LOADER.load_language_at_path(config).unwrap() } pub fn get_language_queries_path(language_name: &str) -> PathBuf { @@ -141,7 +138,9 @@ pub fn get_test_language(name: &str, parser_code: &str, path: Option<&Path>) -> vec![parser_path] }; - TEST_LOADER - .load_language_at_path_with_name(&src_dir, &[&HEADER_DIR], name, Some(&paths_to_check)) - .unwrap() + let mut config = CompileConfig::new(&src_dir, Some(&paths_to_check), None); + config.header_paths = vec![&HEADER_DIR]; + config.name = name.to_string(); + + TEST_LOADER.load_language_at_path_with_name(config).unwrap() } diff --git a/cli/src/wasm.rs b/cli/src/wasm.rs index 11dbb5c5..affd7663 100644 --- a/cli/src/wasm.rs +++ b/cli/src/wasm.rs @@ -1,6 +1,9 @@ use super::generate::parse_grammar::GrammarJSON; use anyhow::{anyhow, Context, Result}; -use std::{fs, path::Path}; +use std::{ + fs, + path::{Path, PathBuf}, +}; use tree_sitter::wasm_stdlib_symbols; use tree_sitter_loader::Loader; use wasmparser::Parser; @@ -11,7 +14,7 @@ pub fn load_language_wasm_file(language_dir: &Path) -> Result<(String, Vec)> .unwrap(); let wasm_filename = format!("tree-sitter-{grammar_name}.wasm"); let contents = fs::read(language_dir.join(&wasm_filename)).with_context(|| { - format!("Failed to read {wasm_filename}. Run `tree-sitter build-wasm` first.",) + format!("Failed to read {wasm_filename}. Run `tree-sitter build --wasm` first.",) })?; Ok((grammar_name, contents)) } @@ -30,10 +33,12 @@ pub fn compile_language_to_wasm( loader: &Loader, language_dir: &Path, output_dir: &Path, + output_file: Option, force_docker: bool, ) -> Result<()> { let grammar_name = get_grammar_name(language_dir)?; - let output_filename = output_dir.join(format!("tree-sitter-{grammar_name}.wasm")); + let output_filename = + output_file.unwrap_or_else(|| output_dir.join(format!("tree-sitter-{grammar_name}.wasm"))); let src_path = language_dir.join("src"); let scanner_path = loader.get_scanner_path(&src_path); loader.compile_parser_to_wasm( diff --git a/docs/section-3-creating-parsers.md b/docs/section-3-creating-parsers.md index 3e1745c8..471f2067 100644 --- a/docs/section-3-creating-parsers.md +++ b/docs/section-3-creating-parsers.md @@ -148,6 +148,24 @@ The first time you run `tree-sitter generate`, it will also generate a few other If there is an ambiguity or *local ambiguity* in your grammar, Tree-sitter will detect it during parser generation, and it will exit with a `Unresolved conflict` error message. See below for more information on these errors. +### Command: `build` + +The `build` command compiles your parser into a dynamically-loadable library, either as a shared object (`.so`, `.dylib`, or `.dll`) or as a WASM module. + +You can specify whether to compile it as a wasm module with the `--wasm`/`-w` flag, and you can opt in to use docker or podman to supply emscripten with the `--docker`/`-d` flag. This removes the need to install emscripten on your machine locally. + +You can specify where to output the shared object file (native or WASM) with the `--output`/`-o` flag, which accepts either an absolute path or relative path. Note that if you don't supply this flag, the CLI will attempt to figure out what the language name is based on the parent directory (so building in `tree-sitter-javascript` will resolve to `javascript`) to use for the output file. If it can't figure it out, it will default to `parser`, thus generating `parser.so` or `parser.wasm` in the current working directory. + +Lastly, you can also specify a path to the actual grammar directory, in case you are not currently in one. This is done by providing a path as the first *positional* argument. + +Example: + +```sh +tree-sitter build --wasm --output ./build/parser.wasm tree-sitter-javascript +``` + +Notice how the `tree-sitter-javascript` argument is the first positional argument. + ### Command: `test` The `tree-sitter test` command allows you to easily test that your parser is working correctly. diff --git a/lib/binding_web/README.md b/lib/binding_web/README.md index f9f621a6..ce5def96 100644 --- a/lib/binding_web/README.md +++ b/lib/binding_web/README.md @@ -131,7 +131,7 @@ npm install --save-dev tree-sitter-cli tree-sitter-javascript Then just use tree-sitter cli tool to generate the `.wasm`. ```sh -npx tree-sitter build-wasm node_modules/tree-sitter-javascript +npx tree-sitter build --wasm node_modules/tree-sitter-javascript ``` If everything is fine, file `tree-sitter-javascript.wasm` should be generated in current directory. diff --git a/lib/binding_web/test/helper.js b/lib/binding_web/test/helper.js index 5ceba02d..2847f5ab 100644 --- a/lib/binding_web/test/helper.js +++ b/lib/binding_web/test/helper.js @@ -7,7 +7,7 @@ function languageURL(name) { module.exports = Parser.init().then(async () => ({ Parser, languageURL, - EmbeddedTemplate: await Parser.Language.load(languageURL('embedded_template')), + EmbeddedTemplate: await Parser.Language.load(languageURL('embedded-template')), HTML: await Parser.Language.load(languageURL('html')), JavaScript: await Parser.Language.load(languageURL('javascript')), JSON: await Parser.Language.load(languageURL('json')), diff --git a/script/generate-fixtures b/script/generate-fixtures index 5c0f74f5..b5d95f1d 100755 --- a/script/generate-fixtures +++ b/script/generate-fixtures @@ -30,4 +30,4 @@ while read -r grammar_file; do cd "$grammar_dir" "$tree_sitter" generate src/grammar.json --no-bindings --abi=latest ) -done <<< "$grammar_files" +done <<<"$grammar_files" diff --git a/script/generate-fixtures-wasm b/script/generate-fixtures-wasm index 4bba56ae..eba74701 100755 --- a/script/generate-fixtures-wasm +++ b/script/generate-fixtures-wasm @@ -21,7 +21,7 @@ fi filter_grammar_name=$1 grammars_dir=${root_dir}/test/fixtures/grammars -grammar_files=$(find $grammars_dir -name grammar.js | grep -v node_modules) +grammar_files=$(find "$grammars_dir" -name grammar.js | grep -v node_modules) while read -r grammar_file; do grammar_dir=$(dirname "$grammar_file") @@ -32,7 +32,5 @@ while read -r grammar_file; do fi echo "Compiling ${grammar_name} parser to wasm" - "$tree_sitter" build-wasm $build_wasm_args $grammar_dir -done <<< "$grammar_files" - -mv tree-sitter-*.wasm target/release/ + "$tree_sitter" build --wasm $build_wasm_args -o target/release/tree-sitter-"${grammar_name}".wasm "$grammar_dir" +done <<<"$grammar_files"