Skip to content

Commit 5f7806f

Browse files
committed
feat: add option to disable parse state optimizations
1 parent a9bce7c commit 5f7806f

File tree

6 files changed

+40
-1
lines changed

6 files changed

+40
-1
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/cli/src/main.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use tree_sitter_cli::{
3232
wasm,
3333
};
3434
use tree_sitter_config::Config;
35+
use tree_sitter_generate::OptLevel;
3536
use tree_sitter_highlight::Highlighter;
3637
use tree_sitter_loader::{self as loader, Bindings, TreeSitterJSON};
3738
use tree_sitter_tags::TagsContext;
@@ -162,6 +163,11 @@ struct Generate {
162163
/// The name or path of the JavaScript runtime to use for generating parsers, specify `native`
163164
/// to use the native `QuickJS` runtime
164165
pub js_runtime: Option<String>,
166+
167+
/// Disable optimizations when generating the parser. Currently, this only affects
168+
/// the merging of compatible parse states.
169+
#[arg(long)]
170+
pub disable_optimizations: bool,
165171
}
166172

167173
#[derive(Args)]
@@ -868,6 +874,11 @@ impl Generate {
868874
self.report_states_for_rule.as_deref(),
869875
self.js_runtime.as_deref(),
870876
self.emit != GenerationEmit::Json,
877+
if self.disable_optimizations {
878+
OptLevel::empty()
879+
} else {
880+
OptLevel::default()
881+
},
871882
) {
872883
if self.json {
873884
eprintln!("{}", serde_json::to_string_pretty(&err)?);

crates/generate/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ qjs-rt = ["load", "rquickjs", "pathdiff"]
2626

2727
[dependencies]
2828
anyhow.workspace = true
29+
bitflags = "2.9.4"
2930
dunce = "1.0.5"
3031
indexmap.workspace = true
3132
indoc.workspace = true

crates/generate/src/build_tables.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use crate::{
2727
node_types::VariableInfo,
2828
rules::{AliasMap, Symbol, SymbolType, TokenSet},
2929
tables::{LexTable, ParseAction, ParseTable, ParseTableEntry},
30+
OptLevel,
3031
};
3132

3233
pub struct Tables {
@@ -43,6 +44,7 @@ pub fn build_tables(
4344
variable_info: &[VariableInfo],
4445
inlines: &InlinedProductionMap,
4546
report_symbol_name: Option<&str>,
47+
optimizations: OptLevel,
4648
) -> BuildTableResult<Tables> {
4749
let item_set_builder = ParseItemSetBuilder::new(syntax_grammar, lexical_grammar, inlines);
4850
let following_tokens =
@@ -78,6 +80,7 @@ pub fn build_tables(
7880
simple_aliases,
7981
&token_conflict_map,
8082
&keywords,
83+
optimizations,
8184
);
8285
let lex_tables = build_lex_table(
8386
&mut parse_table,

crates/generate/src/build_tables/minimize_parse_table.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::{
1111
grammars::{LexicalGrammar, SyntaxGrammar, VariableType},
1212
rules::{AliasMap, Symbol, TokenSet},
1313
tables::{GotoAction, ParseAction, ParseState, ParseStateId, ParseTable, ParseTableEntry},
14+
OptLevel,
1415
};
1516

1617
pub fn minimize_parse_table(
@@ -20,6 +21,7 @@ pub fn minimize_parse_table(
2021
simple_aliases: &AliasMap,
2122
token_conflict_map: &TokenConflictMap,
2223
keywords: &TokenSet,
24+
optimizations: OptLevel,
2325
) {
2426
let mut minimizer = Minimizer {
2527
parse_table,
@@ -29,7 +31,9 @@ pub fn minimize_parse_table(
2931
keywords,
3032
simple_aliases,
3133
};
32-
minimizer.merge_compatible_states();
34+
if optimizations.contains(OptLevel::MergeStates) {
35+
minimizer.merge_compatible_states();
36+
}
3337
minimizer.remove_unit_reductions();
3438
minimizer.remove_unused_states();
3539
minimizer.reorder_states_by_descending_size();

crates/generate/src/generate.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::{
88
};
99

1010
use anyhow::Result;
11+
use bitflags::bitflags;
1112
use log::warn;
1213
use node_types::VariableInfo;
1314
use regex::{Regex, RegexBuilder};
@@ -191,6 +192,19 @@ impl From<rquickjs::Error> for JSError {
191192
}
192193
}
193194

195+
bitflags! {
196+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
197+
pub struct OptLevel: u32 {
198+
const MergeStates = 1 << 0;
199+
}
200+
}
201+
202+
impl Default for OptLevel {
203+
fn default() -> Self {
204+
Self::MergeStates
205+
}
206+
}
207+
194208
#[cfg(feature = "load")]
195209
#[allow(clippy::too_many_arguments)]
196210
pub fn generate_parser_in_directory<T, U, V>(
@@ -201,6 +215,7 @@ pub fn generate_parser_in_directory<T, U, V>(
201215
report_symbol_name: Option<&str>,
202216
js_runtime: Option<&str>,
203217
generate_parser: bool,
218+
optimizations: OptLevel,
204219
) -> GenerateResult<()>
205220
where
206221
T: Into<PathBuf>,
@@ -278,6 +293,7 @@ where
278293
abi_version,
279294
semantic_version.map(|v| (v.major as u8, v.minor as u8, v.patch as u8)),
280295
report_symbol_name,
296+
optimizations,
281297
)?;
282298

283299
write_file(&src_path.join("parser.c"), c_code)?;
@@ -301,6 +317,7 @@ pub fn generate_parser_for_grammar(
301317
LANGUAGE_VERSION,
302318
semantic_version,
303319
None,
320+
OptLevel::empty(),
304321
)?;
305322
Ok((input_grammar.name, parser.c_code))
306323
}
@@ -334,6 +351,7 @@ fn generate_parser_for_grammar_with_opts(
334351
abi_version: usize,
335352
semantic_version: Option<(u8, u8, u8)>,
336353
report_symbol_name: Option<&str>,
354+
optimizations: OptLevel,
337355
) -> GenerateResult<GeneratedParser> {
338356
let JSONOutput {
339357
syntax_grammar,
@@ -353,6 +371,7 @@ fn generate_parser_for_grammar_with_opts(
353371
&variable_info,
354372
&inlines,
355373
report_symbol_name,
374+
optimizations,
356375
)?;
357376
let c_code = render_c_code(
358377
&input_grammar.name,

0 commit comments

Comments
 (0)