feat(generate): Support for --stage=json/parser/lib

This commit is contained in:
Antonin Delpeuch 2025-07-17 15:48:26 +02:00 committed by Will Lillis
parent d810217e63
commit 8e90799e27
2 changed files with 30 additions and 12 deletions

View file

@ -85,6 +85,17 @@ struct Init {
pub grammar_path: Option<PathBuf>,
}
#[derive(Clone, Debug, Default, ValueEnum, PartialEq, Eq)]
enum GenerationStage {
/// Generate `grammar.json` and `node-types.json`
Json,
/// Generate `parser.c` and related files
#[default]
Parser,
/// Compile to a library
Lib,
}
#[derive(Args)]
#[command(alias = "gen", alias = "g")]
struct Generate {
@ -107,8 +118,12 @@ struct Generate {
)
)]
pub abi_version: Option<String>,
/// Compile all defined languages in the current dir
#[arg(long, short = 'b')]
/// Which generation stage to end after
#[arg(long)]
#[clap(value_enum, default_value_t=GenerationStage::Parser)]
pub stage: GenerationStage,
/// Deprecated: use --stage=lib.
#[arg(long, short = 'b', conflicts_with = "stage")]
pub build: bool,
/// Compile a parser in debug mode
#[arg(long, short = '0')]
@ -133,9 +148,6 @@ struct Generate {
default_value = "node"
)]
pub js_runtime: Option<String>,
/// Only generate `grammar.json` by evaluating `grammar.js`, but do not generate `parser.c` and related files afterwards
#[arg(long)]
pub evaluate_only: bool,
}
#[derive(Args)]
@ -803,6 +815,11 @@ impl Generate {
version.parse().expect("invalid abi version flag")
}
});
if self.build {
// TODO: remove the `--build` argument in 0.27
// TODO: migrate to `warn!` once https://github.com/tree-sitter/tree-sitter/pull/4604 is merged
eprintln!("Warning: --build is deprecated, use --stage=lib instead");
}
if let Err(err) = tree_sitter_generate::generate_parser_in_directory(
current_dir,
self.output.as_deref(),
@ -810,7 +827,7 @@ impl Generate {
abi_version,
self.report_states_for_rule.as_deref(),
self.js_runtime.as_deref(),
self.evaluate_only,
self.stage != GenerationStage::Json,
) {
if self.json {
eprintln!("{}", serde_json::to_string_pretty(&err)?);
@ -821,7 +838,7 @@ impl Generate {
Err(anyhow!(err.to_string())).with_context(|| "Error when generating parser")?;
}
}
if self.build {
if self.stage == GenerationStage::Lib || self.build {
if let Some(path) = self.libdir {
loader = loader::Loader::with_parser_lib_path(path);
}

View file

@ -196,9 +196,8 @@ where
let src_path = out_path.map_or_else(|| repo_path.join("src"), |p| p.into());
let header_path = src_path.join("tree_sitter");
// Ensure that the output directories exist.
// Ensure that the output directory exists
fs::create_dir_all(&src_path)?;
fs::create_dir_all(&header_path)?;
if grammar_path.file_name().unwrap() != "grammar.json" {
fs::write(src_path.join("grammar.json"), &grammar_json).map_err(|e| {
@ -210,13 +209,14 @@ where
}
// If our job is only to generate `grammar.json` and not `parser.c`, stop here.
let input_grammar = parse_grammar(&grammar_json)?;
if !generate_parser {
let node_types_json = generate_node_types_from_grammar(&input_grammar)?.node_types_json;
write_file(&src_path.join("node-types.json"), node_types_json)?;
return Ok(());
}
// Parse and preprocess the grammar.
let input_grammar = parse_grammar(&grammar_json)?;
let semantic_version = read_grammar_version(&repo_path)?;
if semantic_version.is_none() && abi_version > ABI_VERSION_MIN {
@ -238,6 +238,7 @@ where
write_file(&src_path.join("parser.c"), c_code)?;
write_file(&src_path.join("node-types.json"), node_types_json)?;
fs::create_dir_all(&header_path)?;
write_file(&header_path.join("alloc.h"), ALLOC_HEADER)?;
write_file(&header_path.join("array.h"), ARRAY_HEADER)?;
write_file(&header_path.join("parser.h"), tree_sitter::PARSER_HEADER)?;