From edeced89121c89e8391b6956f01d7edb05339a95 Mon Sep 17 00:00:00 2001 From: TcMits Date: Tue, 8 Jul 2025 14:58:33 +0700 Subject: [PATCH] parser: use YYSTACKDEPTH --- Cargo.lock | 5 +-- vendored/sqlite3-parser/Cargo.toml | 1 + .../sqlite3-parser/third_party/lemon/lemon.c | 3 +- .../third_party/lemon/lempar.rs | 31 ++++++++++++++----- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9d9c48c69..338fbfa12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3093,9 +3093,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.14.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" @@ -3727,6 +3727,7 @@ dependencies = [ "memchr", "miette", "serde", + "smallvec", "strum", "strum_macros", ] diff --git a/vendored/sqlite3-parser/Cargo.toml b/vendored/sqlite3-parser/Cargo.toml index 6ae686f07..8161def05 100644 --- a/vendored/sqlite3-parser/Cargo.toml +++ b/vendored/sqlite3-parser/Cargo.toml @@ -34,6 +34,7 @@ miette = "7.4.0" strum = { workspace = true } strum_macros = {workspace = true } serde = { workspace = true , optional = true, features = ["derive"] } +smallvec = { version = "1.15.1", features = ["const_generics"] } [dev-dependencies] env_logger = { version = "0.11", default-features = false } diff --git a/vendored/sqlite3-parser/third_party/lemon/lemon.c b/vendored/sqlite3-parser/third_party/lemon/lemon.c index dec7efd25..2c438a52f 100644 --- a/vendored/sqlite3-parser/third_party/lemon/lemon.c +++ b/vendored/sqlite3-parser/third_party/lemon/lemon.c @@ -4519,7 +4519,8 @@ void ReportTable( if( lemp->stacksize ){ fprintf(out,"const YYSTACKDEPTH: usize = %s;\n",lemp->stacksize); lineno++; } else { - fprintf(out, "const YYSTACKDEPTH: usize = 128;\n"); lineno++; + // from sqlite: The default value is 100. A typical application will use less than about 20 levels of the stack. Developers whose applications contain SQL statements that need more than 100 LALR(1) stack entries should seriously consider refactoring their SQL as it is likely to be well beyond the ability of any human to comprehend. + fprintf(out, "const YYSTACKDEPTH: usize = 100;\n"); lineno++; } if( lemp->errsym && lemp->errsym->useCnt ){ fprintf(out,"const YYERRORSYMBOL: YYCODETYPE = %d;\n",lemp->errsym->index); lineno++; diff --git a/vendored/sqlite3-parser/third_party/lemon/lempar.rs b/vendored/sqlite3-parser/third_party/lemon/lempar.rs index a45575ba4..a3ea5143c 100644 --- a/vendored/sqlite3-parser/third_party/lemon/lempar.rs +++ b/vendored/sqlite3-parser/third_party/lemon/lempar.rs @@ -184,12 +184,13 @@ pub struct yyParser<'input> { //#[cfg(not(feature = "YYNOERRORRECOVERY"))] yyerrcnt: i32, /* Shifts left before out of the error */ %% /* A place to hold %extra_context */ - yystack: Vec>, /* The parser's stack */ + yystack: smallvec::SmallVec<[yyStackEntry<'input>; YYSTACKDEPTH]>, /* The parser's stack */ } use std::cmp::Ordering; use std::ops::Neg; impl<'input> yyParser<'input> { + #[inline] fn shift(&self, shift: i8) -> usize { assert!(shift <= 1); match shift.cmp(&0) { @@ -199,6 +200,7 @@ impl<'input> yyParser<'input> { } } + #[inline] fn yyidx_shift(&mut self, shift: i8) { match shift.cmp(&0) { Ordering::Greater => self.yyidx += shift as usize, @@ -207,12 +209,17 @@ impl<'input> yyParser<'input> { } } + #[inline] fn yy_move(&mut self, shift: i8) -> yyStackEntry<'input> { - use std::mem::take; let idx = self.shift(shift); - take(&mut self.yystack[idx]) + + // TODO: The compiler optimizes `std::mem::take` to two `memcpy` + // but `yyStackEntry` requires 168 bytes, so it is not worth it (maybe). + assert_eq!(std::mem::size_of::(), 168); + std::mem::take(&mut self.yystack[idx]) } + #[inline] fn push(&mut self, entry: yyStackEntry<'input>) { if self.yyidx == self.yystack.len() { self.yystack.push(entry); @@ -226,12 +233,14 @@ use std::ops::{Index, IndexMut}; impl<'input> Index for yyParser<'input> { type Output = yyStackEntry<'input>; + #[inline] fn index(&self, shift: i8) -> &yyStackEntry<'input> { let idx = self.shift(shift); &self.yystack[idx] } } impl<'input> IndexMut for yyParser<'input> { + #[inline] fn index_mut(&mut self, shift: i8) -> &mut yyStackEntry<'input> { let idx = self.shift(shift); &mut self.yystack[idx] @@ -261,9 +270,11 @@ static yyRuleName: [&str; YYNRULE] = [ ** of errors. Return 0 on success. */ impl yyParser<'_> { + #[inline] fn yy_grow_stack_if_needed(&mut self) -> bool { false } + #[inline] fn yy_grow_stack_for_push(&mut self) -> bool { // yystack is not prefilled with zero value like in C. if self.yyidx == self.yystack.len() { @@ -281,17 +292,15 @@ impl yyParser<'_> { pub fn new( %% /* Optional %extra_context parameter */ ) -> yyParser { - let mut p = yyParser { + yyParser { yyidx: 0, #[cfg(feature = "YYTRACKMAXSTACKDEPTH")] yyhwm: 0, - yystack: Vec::with_capacity(YYSTACKDEPTH), + yystack: smallvec::smallvec![yyStackEntry::default()], //#[cfg(not(feature = "YYNOERRORRECOVERY"))] yyerrcnt: -1, %% /* Optional %extra_context store */ - }; - p.push(yyStackEntry::default()); - p + } } } @@ -299,6 +308,7 @@ impl yyParser<'_> { ** Pop the parser's stack once. */ impl yyParser<'_> { + #[inline] fn yy_pop_parser_stack(&mut self) { use std::mem::take; let _yytos = take(&mut self.yystack[self.yyidx]); @@ -319,6 +329,7 @@ impl yyParser<'_> { */ impl yyParser<'_> { #[expect(non_snake_case)] + #[inline] pub fn ParseFinalize(&mut self) { while self.yyidx > 0 { self.yy_pop_parser_stack(); @@ -333,9 +344,11 @@ impl yyParser<'_> { #[cfg(feature = "YYTRACKMAXSTACKDEPTH")] impl yyParser<'_> { #[expect(non_snake_case)] + #[inline] pub fn ParseStackPeak(&self) -> usize { self.yyhwm } + #[inline] fn yyhwm_incr(&mut self) { if self.yyidx > self.yyhwm { self.yyhwm += 1; @@ -488,6 +501,7 @@ fn yy_find_reduce_action( impl yyParser<'_> { #[expect(non_snake_case)] #[cfg(feature = "NDEBUG")] + #[inline] fn yyTraceShift(&self, _: YYACTIONTYPE, _: &str) { } #[expect(non_snake_case)] @@ -893,6 +907,7 @@ impl<'input> yyParser<'input> { ** Return the fallback token corresponding to canonical token iToken, or ** 0 if iToken has no fallback. */ + #[inline] pub fn parse_fallback(i_token: YYCODETYPE) -> YYCODETYPE { if YYFALLBACK { return yyFallback[i_token as usize];