Skip to content

Commit

Permalink
make tracking for better error details optional (fixes #1009)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomtau committed Apr 30, 2024
1 parent f60b518 commit 4b2534d
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 49 deletions.
8 changes: 4 additions & 4 deletions debugger/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "pest_debugger"
description = "pest grammar debugger"
version = "2.7.9"
version = "2.7.10"
edition = "2021"
authors = [
"Dragoș Tiselice <[email protected]>",
Expand All @@ -17,9 +17,9 @@ readme = "_README.md"
rust-version = "1.61"

[dependencies]
pest = { path = "../pest", version = "2.7.9" }
pest_meta = { path = "../meta", version = "2.7.9" }
pest_vm = { path = "../vm", version = "2.7.9" }
pest = { path = "../pest", version = "2.7.10" }
pest_meta = { path = "../meta", version = "2.7.10" }
pest_vm = { path = "../vm", version = "2.7.10" }
reqwest = { version = "= 0.11.13", default-features = false, features = [
"blocking",
"json",
Expand Down
6 changes: 3 additions & 3 deletions derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "pest_derive"
description = "pest's derive macro"
version = "2.7.9"
version = "2.7.10"
edition = "2021"
authors = ["Dragoș Tiselice <[email protected]>"]
homepage = "https://pest.rs/"
Expand All @@ -25,5 +25,5 @@ grammar-extras = ["pest_generator/grammar-extras"]

[dependencies]
# for tests, included transitively anyway
pest = { path = "../pest", version = "2.7.9", default-features = false }
pest_generator = { path = "../generator", version = "2.7.9", default-features = false }
pest = { path = "../pest", version = "2.7.10", default-features = false }
pest_generator = { path = "../generator", version = "2.7.10", default-features = false }
6 changes: 3 additions & 3 deletions generator/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "pest_generator"
description = "pest code generator"
version = "2.7.9"
version = "2.7.10"
edition = "2021"
authors = ["Dragoș Tiselice <[email protected]>"]
homepage = "https://pest.rs/"
Expand All @@ -22,8 +22,8 @@ grammar-extras = ["pest_meta/grammar-extras"]
export-internal = []

[dependencies]
pest = { path = "../pest", version = "2.7.9", default-features = false }
pest_meta = { path = "../meta", version = "2.7.9" }
pest = { path = "../pest", version = "2.7.10", default-features = false }
pest_meta = { path = "../meta", version = "2.7.10" }
proc-macro2 = "1.0"
quote = "1.0"
syn = "2.0"
6 changes: 3 additions & 3 deletions grammars/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "pest_grammars"
description = "pest popular grammar implementations"
version = "2.7.9"
version = "2.7.10"
edition = "2021"
authors = ["Dragoș Tiselice <[email protected]>"]
homepage = "https://pest.rs/"
Expand All @@ -14,8 +14,8 @@ readme = "_README.md"
rust-version = "1.61"

[dependencies]
pest = { path = "../pest", version = "2.7.9" }
pest_derive = { path = "../derive", version = "2.7.9" }
pest = { path = "../pest", version = "2.7.10" }
pest_derive = { path = "../derive", version = "2.7.10" }

[dev-dependencies]
criterion = "0.5"
Expand Down
2 changes: 2 additions & 0 deletions grammars/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,8 @@ mod tests {

#[test]
fn sql_parse_attempts_error() {
pest::set_error_detail(true);

fn is_whitespace(string: String) -> bool {
string == "\r\n"
|| (string.len() == 1 && string.chars().next().unwrap().is_whitespace())
Expand Down
4 changes: 2 additions & 2 deletions meta/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "pest_meta"
description = "pest meta language parser and validator"
version = "2.7.9"
version = "2.7.10"
edition = "2021"
authors = ["Dragoș Tiselice <[email protected]>"]
homepage = "https://pest.rs/"
Expand All @@ -22,7 +22,7 @@ include = [
rust-version = "1.61"

[dependencies]
pest = { path = "../pest", version = "2.7.9" }
pest = { path = "../pest", version = "2.7.10" }
once_cell = "1.8.0"

[build-dependencies]
Expand Down
2 changes: 1 addition & 1 deletion pest/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "pest"
description = "The Elegant Parser"
version = "2.7.9"
version = "2.7.10"
edition = "2021"
authors = ["Dragoș Tiselice <[email protected]>"]
homepage = "https://pest.rs/"
Expand Down
3 changes: 2 additions & 1 deletion pest/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,8 @@ extern crate std;

pub use crate::parser::Parser;
pub use crate::parser_state::{
set_call_limit, state, Atomicity, Lookahead, MatchDir, ParseResult, ParserState,
set_call_limit, set_error_detail, state, Atomicity, Lookahead, MatchDir, ParseResult,
ParserState,
};
pub use crate::position::Position;
pub use crate::span::{merge_spans, Lines, LinesSpan, Span};
Expand Down
96 changes: 67 additions & 29 deletions pest/src/parser_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use alloc::vec::Vec;
use core::fmt::{Debug, Display, Formatter};
use core::num::NonZeroUsize;
use core::ops::Range;
use core::sync::atomic::{AtomicUsize, Ordering};
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};

use crate::error::{Error, ErrorVariant};
use crate::iterators::pairs::new;
Expand Down Expand Up @@ -103,6 +103,22 @@ pub fn set_call_limit(limit: Option<NonZeroUsize>) {
CALL_LIMIT.store(limit.map(|f| f.get()).unwrap_or(0), Ordering::Relaxed);
}

static ERROR_DETAIL: AtomicBool = AtomicBool::new(false);

/// Sets whether information for more error details
/// should be collected. This is useful for debugging
/// parser errors (as it leads to more comphrensive
/// error messages), but it has a higher performance cost.
/// (hence, it's off by default)
///
/// # Arguments
///
/// * `enabled` - Whether to enable the collection for
/// more error details.
pub fn set_error_detail(enabled: bool) {
ERROR_DETAIL.store(enabled, Ordering::Relaxed);
}

#[derive(Debug)]
struct CallLimitTracker {
current_call_limit: Option<(usize, usize)>,
Expand Down Expand Up @@ -204,6 +220,8 @@ impl Display for ParsingToken {
/// The intuition is such rules will be most likely the query user initially wanted to write.
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct ParseAttempts<R> {
/// Indicates whether the parsing attempts are tracked.
enabled: bool,
/// Vec of rule calls sequences awaiting tokens at the same `max_position`.
/// If there are several stacks in vec, it means all those rule stacks are "equal"
/// because their attempts occurred on the same position.
Expand All @@ -227,6 +245,7 @@ impl<R: RuleType> ParseAttempts<R> {
expected_tokens: Vec::with_capacity(EXPECTED_TOKENS_INITIAL_CAPACITY),
unexpected_tokens: Vec::with_capacity(EXPECTED_TOKENS_INITIAL_CAPACITY),
max_position: 0,
enabled: ERROR_DETAIL.load(Ordering::Relaxed),
}
}

Expand Down Expand Up @@ -461,11 +480,18 @@ where
}
};

Err(Error::new_from_pos_with_parsing_attempts(
variant,
Position::new_internal(input, state.attempt_pos),
state.parse_attempts.clone(),
))
if state.parse_attempts.enabled {
Err(Error::new_from_pos_with_parsing_attempts(
variant,
Position::new_internal(input, state.attempt_pos),
state.parse_attempts.clone(),
))
} else {
Err(Error::new_from_pos(
variant,
Position::new_internal(input, state.attempt_pos),
))
}
}
}
}
Expand Down Expand Up @@ -675,7 +701,9 @@ impl<'i, R: RuleType> ParserState<'i, R> {
// Note, that we need to count positive parsing results too, because we can fail in
// optional rule call inside which may lie the farthest
// parsed token.
try_add_rule_to_stack(&mut new_state);
if new_state.parse_attempts.enabled {
try_add_rule_to_stack(&mut new_state);
}
Ok(new_state)
}
Err(mut new_state) => {
Expand All @@ -687,7 +715,9 @@ impl<'i, R: RuleType> ParserState<'i, R> {
neg_attempts_index,
attempts,
);
try_add_rule_to_stack(&mut new_state);
if new_state.parse_attempts.enabled {
try_add_rule_to_stack(&mut new_state);
}
}

if new_state.lookahead == Lookahead::None
Expand Down Expand Up @@ -981,13 +1011,15 @@ impl<'i, R: RuleType> ParserState<'i, R> {
where
F: FnOnce(char) -> bool,
{
let token = ParsingToken::BuiltInRule;
let start_position = self.position.pos();
if self.position.match_char_by(f) {
self.handle_token_parse_result(start_position, token, true);
let succeeded = self.position.match_char_by(f);
if self.parse_attempts.enabled {
let token = ParsingToken::BuiltInRule;
self.handle_token_parse_result(start_position, token, succeeded);
}
if succeeded {
Ok(self)
} else {
self.handle_token_parse_result(start_position, token, false);
Err(self)
}
}
Expand Down Expand Up @@ -1016,15 +1048,17 @@ impl<'i, R: RuleType> ParserState<'i, R> {
/// ```
#[inline]
pub fn match_string(mut self: Box<Self>, string: &str) -> ParseResult<Box<Self>> {
let token = ParsingToken::Sensitive {
token: String::from(string),
};
let start_position = self.position.pos();
if self.position.match_string(string) {
self.handle_token_parse_result(start_position, token, true);
let succeeded = self.position.match_string(string);
if self.parse_attempts.enabled {
let token = ParsingToken::Sensitive {
token: String::from(string),
};
self.handle_token_parse_result(start_position, token, succeeded);
}
if succeeded {
Ok(self)
} else {
self.handle_token_parse_result(start_position, token, false);
Err(self)
}
}
Expand Down Expand Up @@ -1053,15 +1087,17 @@ impl<'i, R: RuleType> ParserState<'i, R> {
/// ```
#[inline]
pub fn match_insensitive(mut self: Box<Self>, string: &str) -> ParseResult<Box<Self>> {
let token = ParsingToken::Insensitive {
token: String::from(string),
};
let start_position = self.position().pos();
if self.position.match_insensitive(string) {
self.handle_token_parse_result(start_position, token, true);
let start_position: usize = self.position().pos();
let succeeded = self.position.match_insensitive(string);
if self.parse_attempts.enabled {
let token = ParsingToken::Insensitive {
token: String::from(string),
};
self.handle_token_parse_result(start_position, token, succeeded);
}
if succeeded {
Ok(self)
} else {
self.handle_token_parse_result(start_position, token, false);
Err(self)
}
}
Expand Down Expand Up @@ -1093,16 +1129,18 @@ impl<'i, R: RuleType> ParserState<'i, R> {
/// ```
#[inline]
pub fn match_range(mut self: Box<Self>, range: Range<char>) -> ParseResult<Box<Self>> {
let start_position = self.position().pos();
let token = ParsingToken::Range {
start: range.start,
end: range.end,
};
let start_position = self.position().pos();
if self.position.match_range(range) {
self.handle_token_parse_result(start_position, token, true);
let succeeded = self.position.match_range(range);
if self.parse_attempts.enabled {
self.handle_token_parse_result(start_position, token, succeeded);
}
if succeeded {
Ok(self)
} else {
self.handle_token_parse_result(start_position, token, false);
Err(self)
}
}
Expand Down
6 changes: 3 additions & 3 deletions vm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "pest_vm"
description = "pest grammar virtual machine"
version = "2.7.9"
version = "2.7.10"
edition = "2021"
authors = ["Dragoș Tiselice <[email protected]>"]
homepage = "https://pest.rs/"
Expand All @@ -14,8 +14,8 @@ readme = "_README.md"
rust-version = "1.61"

[dependencies]
pest = { path = "../pest", version = "2.7.9" }
pest_meta = { path = "../meta", version = "2.7.9" }
pest = { path = "../pest", version = "2.7.10" }
pest_meta = { path = "../meta", version = "2.7.10" }

[features]
grammar-extras = ["pest_meta/grammar-extras"]

0 comments on commit 4b2534d

Please sign in to comment.