Skip to content

Commit

Permalink
use parking_lot, allow BaseRuleContext to use in parsers, some refact…
Browse files Browse the repository at this point in the history
…oring
  • Loading branch information
rrevenantt committed Dec 15, 2020
1 parent 15de67b commit 3517a58
Show file tree
Hide file tree
Showing 22 changed files with 145 additions and 139 deletions.
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ keywords = ["ANTLR","ANTLR4","parsing","runtime"]
categories = ["parsing"]
exclude = ["build.rs"]

[features]
test = []
default = []

[dependencies]
lazy_static = "^1.4"
uuid = "=0.8.*"
Expand All @@ -23,6 +27,7 @@ once_cell = "^1.2"
#backtrace = "=0.3"
typed-arena = "^2.0"
better_any = "=0.1"
parking_lot = "0.11"

[lib]

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ there are quite some differences because Rust is not an OOP language and is much
Also in Rust target `TokenFactory` is the way to specify token type. As example you can see [CSV](grammars/CSV.g4) test grammar.
- All rule context variables (rule argument or rule return) should implement `Default + Clone`.

### Benchmarks

### Unsafe
Currently, unsafe is used only for downcasting (through separate crate)
and to update data inside Rc via `get_mut_unchecked`(returned mutable reference is used immediately and not stored anywhere)
Expand Down
2 changes: 1 addition & 1 deletion src/atn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ impl ATN {
}

pub(crate) fn add_state(&mut self, state: Box<dyn ATNState>) {
assert_eq!(state.get_state_number(), self.states.len());
debug_assert_eq!(state.get_state_number(), self.states.len());
self.states.push(state)
}

Expand Down
21 changes: 11 additions & 10 deletions src/dfa.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use std::collections::HashMap;
use std::convert::TryFrom;
use std::ops::Deref;
use std::sync::{Arc, RwLock};
use std::sync::Arc;

use crate::atn::ATN;
use crate::atn_config_set::ATNConfigSet;
use crate::atn_state::{ATNDecisionState, ATNState, ATNStateRef, ATNStateType};
use crate::dfa_serializer::DFASerializer;
use crate::dfa_state::{DFAState, DFAStateRef};
use crate::vocabulary::Vocabulary;
use parking_lot::RwLock;

///Helper trait for scope management and temporary values not living long enough
pub(crate) trait ScopeExt: Sized {
Expand Down Expand Up @@ -63,7 +64,7 @@ impl DFA {
};

// to indicate null
dfa.states.write().unwrap().push(DFAState::new_dfastate(
dfa.states.write().push(DFAState::new_dfastate(
usize::max_value(),
Box::new(ATNConfigSet::new_base_atnconfig_set(true)),
));
Expand All @@ -78,15 +79,15 @@ impl DFA {
{
dfa.is_precedence_dfa = true;
let mut precedence_state = DFAState::new_dfastate(
dfa.states.read().unwrap().len(),
dfa.states.read().len(),
Box::new(ATNConfigSet::new_base_atnconfig_set(true)),
);
precedence_state.edges = vec![];
precedence_state.is_accept_state = false;
precedence_state.requires_full_context = false;

dfa.s0 = RwLock::new(Some(precedence_state.state_number));
dfa.states.write().unwrap().push(precedence_state)
dfa.states.write().push(precedence_state)
}
dfa
}
Expand All @@ -96,8 +97,8 @@ impl DFA {
panic!("dfa is supposed to be precedence here");
}

self.s0.read().unwrap().and_then(|s0| {
self.states.read().unwrap()[s0]
self.s0.read().and_then(|s0| {
self.states.read()[s0]
.edges
.get(_precedence as usize)
.copied()
Expand All @@ -118,8 +119,8 @@ impl DFA {
}
let precedence = precedence as usize;

if let Some(x) = self.s0.write().unwrap().deref() {
self.states.write().unwrap()[*x].edges.apply(|edges| {
if let Some(x) = self.s0.write().deref() {
self.states.write()[*x].edges.apply(|edges| {
if edges.len() <= precedence {
edges.resize(precedence + 1, 0);
}
Expand All @@ -137,7 +138,7 @@ impl DFA {
fn num_states(&self) -> isize { unimplemented!() }

pub fn to_string(&self, vocabulary: &dyn Vocabulary) -> String {
if self.s0.read().unwrap().is_none() {
if self.s0.read().is_none() {
return String::new();
}

Expand All @@ -150,7 +151,7 @@ impl DFA {
}

pub fn to_lexer_string(&self) -> String {
if self.s0.read().unwrap().is_none() {
if self.s0.read().is_none() {
return String::new();
}
format!(
Expand Down
2 changes: 1 addition & 1 deletion src/dfa_serializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub struct DFASerializer<'a, 'b> {

impl Display for DFASerializer<'_, '_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let dfa = self.dfa.states.read().unwrap();
let dfa = self.dfa.states.read();
for source in dfa.iter() {
for (i, edge) in source.edges.iter().copied().enumerate() {
if edge != 0 && edge != ERROR_DFA_STATE_REF {
Expand Down
20 changes: 9 additions & 11 deletions src/error_strategy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,14 @@ use std::any::Any;
/// The interface for defining strategies to deal with syntax errors encountered
/// during a parse by ANTLR-generated parsers. We distinguish between three
/// different kinds of errors:
/// <ul>
/// <li>The parser could not figure out which path to take in the ATN (none of
/// the available alternatives could possibly match)</li>
/// <li>The current input does not match what we were looking for</li>
/// <li>A predicate evaluated to false</li>
/// </ul>
/// - The parser could not figure out which path to take in the ATN (none of
/// the available alternatives could possibly match)
/// - The current input does not match what we were looking for
/// - A predicate evaluated to false
///
/// Implementations of this interface report syntax errors by calling [`Parser.notifyErrorListeners`]
/// Implementations of this interface should report syntax errors by calling [`Parser.notifyErrorListeners`]
///
/// [`Parser.notifyErrorListeners`]: todo
/// [`Parser.notifyErrorListeners`]: crate::parser::Parser::notifyErrorListeners
pub trait ErrorStrategy<'a, T: Parser<'a>>: Tid<'a> {
fn reset(&mut self, recognizer: &mut T);
fn recover_inline(
Expand Down Expand Up @@ -534,7 +532,7 @@ impl<'input, Ctx: ParserNodeType<'input>> BailErrorStrategy<'input, Ctx> {
ctx = ctx.get_parent()?
}
};
return ANTLRError::FallThrough(Box::new(ParseCancelledError(e.clone())));
return ANTLRError::FallThrough(Rc::new(ParseCancelledError(e.clone())));
}
}

Expand All @@ -557,7 +555,7 @@ impl<'a, T: Parser<'a>> ErrorStrategy<'a, T> for BailErrorStrategy<'a, T::Node>
#[inline(always)]
fn reset(&mut self, recognizer: &mut T) { self.0.reset(recognizer) }

#[inline(always)]
#[cold]
fn recover_inline(
&mut self,
recognizer: &mut T,
Expand All @@ -567,7 +565,7 @@ impl<'a, T: Parser<'a>> ErrorStrategy<'a, T> for BailErrorStrategy<'a, T::Node>
Err(self.process_error(recognizer, &err))
}

#[inline(always)]
#[cold]
fn recover(&mut self, recognizer: &mut T, e: &ANTLRError) -> Result<(), ANTLRError> {
Err(self.process_error(recognizer, &e))
}
Expand Down
36 changes: 18 additions & 18 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::transition::PredicateTransition;
use crate::transition::TransitionType::TRANSITION_PREDICATE;

/// Main ANTLR4 Rust runtime error
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum ANTLRError {
/// Returned from Lexer when it fails to find matching token type for current input
///
Expand Down Expand Up @@ -48,29 +48,29 @@ pub enum ANTLRError {

/// Unrecoverable error. Indicates that error should not be processed by parser
/// and it should abort parsing and immediately return to caller
FallThrough(Box<dyn Error>),
FallThrough(Rc<dyn Error>),

/// Potentially recoverable error.
/// Used to allow user to emit his own errors from parser actions or from custom error strategy.
/// Parser will try to recover with provided `ErrorStrategy`
OtherError(Box<dyn Error>),
OtherError(Rc<dyn Error>),
}

impl Clone for ANTLRError {
fn clone(&self) -> Self {
match self {
ANTLRError::LexerNoAltError { start_index } => ANTLRError::LexerNoAltError {
start_index: *start_index,
},
ANTLRError::NoAltError(e) => ANTLRError::NoAltError(e.clone()),
ANTLRError::InputMismatchError(e) => ANTLRError::InputMismatchError(e.clone()),
ANTLRError::PredicateError(e) => ANTLRError::PredicateError(e.clone()),
ANTLRError::IllegalStateError(e) => ANTLRError::IllegalStateError(e.clone()),
ANTLRError::FallThrough(_) => panic!("clone not supported"),
ANTLRError::OtherError(_) => panic!("clone not supported"),
}
}
}
// impl Clone for ANTLRError {
// fn clone(&self) -> Self {
// match self {
// ANTLRError::LexerNoAltError { start_index } => ANTLRError::LexerNoAltError {
// start_index: *start_index,
// },
// ANTLRError::NoAltError(e) => ANTLRError::NoAltError(e.clone()),
// ANTLRError::InputMismatchError(e) => ANTLRError::InputMismatchError(e.clone()),
// ANTLRError::PredicateError(e) => ANTLRError::PredicateError(e.clone()),
// ANTLRError::IllegalStateError(e) => ANTLRError::IllegalStateError(e.clone()),
// ANTLRError::FallThrough(_) => panic!("clone not supported"),
// ANTLRError::OtherError(_) => panic!("clone not supported"),
// }
// }
// }

impl Display for ANTLRError {
fn fmt(&self, _f: &mut Formatter<'_>) -> fmt::Result { <Self as Debug>::fmt(self, _f) }
Expand Down
17 changes: 7 additions & 10 deletions src/lexer_atn_simulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ impl ILexerATNSimulator for LexerATNSimulator {
.get(mode)
.ok_or_else(|| ANTLRError::IllegalStateError("invalid mode".into()))?;

let s0 = dfa.s0.read().unwrap().as_ref().copied();
let s0 = dfa.s0.read().as_ref().copied();
match s0 {
None => self.match_atn(lexer),
Some(s0) => self.exec_atn(s0, lexer),
Expand Down Expand Up @@ -175,9 +175,9 @@ impl LexerATNSimulator {
let _supress_edge = s0_closure.has_semantic_context();
s0_closure.set_has_semantic_context(false);

let next_state = self.add_dfastate(&mut self.get_dfa().states.write().unwrap(), s0_closure);
let next_state = self.add_dfastate(&mut self.get_dfa().states.write(), s0_closure);
if !_supress_edge {
*self.get_dfa().s0.write().unwrap() = Some(next_state);
*self.get_dfa().s0.write() = Some(next_state);
}

self.exec_atn(next_state, lexer)
Expand Down Expand Up @@ -219,7 +219,7 @@ impl LexerATNSimulator {

s = target;
}
let _last = self.get_dfa().states.read().unwrap().get(s).unwrap();
// let _last = self.get_dfa().states.read().get(s).unwrap();

self.fail_or_accept(symbol, lexer)
}
Expand All @@ -232,7 +232,6 @@ impl LexerATNSimulator {
self.get_dfa()
.states
.read()
.unwrap()
.get(_s)
.unwrap()
.edges
Expand All @@ -250,7 +249,7 @@ impl LexerATNSimulator {
_t: isize,
lexer: &mut impl Lexer<'input>,
) -> DFAStateRef {
let states = self.get_dfa().states.read().unwrap();
let states = self.get_dfa().states.read();

let mut reach = ATNConfigSet::new_ordered();
self.get_reachable_config_set(
Expand All @@ -264,7 +263,7 @@ impl LexerATNSimulator {
// println!(" --- target computed {:?}", reach.configs.iter().map(|it|it.get_state()).collect::<Vec<_>>());

drop(states);
let mut states = self.get_dfa().states.write().unwrap();
let mut states = self.get_dfa().states.write();
if reach.is_empty() {
if !reach.has_semantic_context() {
self.add_dfaedge(states.get_mut(_s).unwrap(), _t, ERROR_DFA_STATE_REF);
Expand Down Expand Up @@ -351,7 +350,7 @@ impl LexerATNSimulator {
if let Some(state) = self.prev_accept.dfa_state {
// let lexer_action_executor;
let prediction = {
let dfa_state_prediction = &mut self.get_dfa().states.write().unwrap()[state];
let dfa_state_prediction = &self.get_dfa().states.read()[state];
// println!("accepted, prediction = {}, on dfastate {}", dfa_state_prediction.prediction, dfa_state_prediction.state_number);
// lexer_action_executor = dfa_state_prediction.lexer_action_executor.clone();
// let recog = self.recog.clone();
Expand Down Expand Up @@ -602,7 +601,6 @@ impl LexerATNSimulator {
.get_dfa()
.states
.read()
.unwrap()
.get(dfa_state)
.unwrap()
.is_accept_state
Expand Down Expand Up @@ -664,7 +662,6 @@ impl LexerATNSimulator {
let dfastate_index = *dfa
.states_map
.write()
.unwrap()
.entry(key)
.or_insert_with(|| {
dfastate.state_number = states.deref().len();
Expand Down
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#![feature(get_mut_unchecked)]
#![feature(specialization)]
#![feature(coerce_unsized)]
#![feature(unsize)]
#![feature(associated_type_defaults)]
#![warn(rust_2018_idioms)]
#![warn(missing_docs)] // warn if there is missing docs
Expand Down
24 changes: 13 additions & 11 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::borrow::Borrow;
use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::iter::from_fn;
use std::marker::{PhantomData, Unsize};
use std::marker::PhantomData;
use std::mem;
use std::ops::{CoerceUnsized, Deref, DerefMut};
use std::rc::Rc;
Expand Down Expand Up @@ -430,21 +430,27 @@ where
///
/// ### Example for listener usage:
/// todo
pub fn add_parse_listener<L: Unsize<T>>(&mut self, listener: Box<L>) -> ListenerId<L> {
pub fn add_parse_listener<L>(&mut self, listener: Box<L>) -> ListenerId<L>
where
Box<L>: CoerceUnsized<Box<T>>,
{
let id = ListenerId::new(&listener);
self.parse_listeners.push(listener);
id
}

/// Removes parse listener with corresponding `listener_id`, casts it back to user type and returns it to the caller.
/// `listener_id` is returned when listener is added via `add_parse_listener`
pub fn remove_parse_listener<L: Unsize<T>>(&mut self, listener_id: ListenerId<L>) -> Box<L> {
pub fn remove_parse_listener<L>(&mut self, listener_id: ListenerId<L>) -> Box<L>
where
Box<L>: CoerceUnsized<Box<T>>,
{
let index = self
.parse_listeners
.iter()
.position(|it| ListenerId::new(it).actual_id == listener_id.actual_id)
.expect("listener not found");
listener_id.into_listener(self.parse_listeners.remove(index))
unsafe { listener_id.into_listener(self.parse_listeners.remove(index)) }
}

/// Removes all added parse listeners without returning them
Expand Down Expand Up @@ -612,7 +618,7 @@ where
let mut seen_one = false;
for dfa in self.interp.decision_to_dfa() {
// because s0 is saved in dfa for Rust version
if dfa.states.read().unwrap().len() > 1 + (dfa.is_precedence_dfa() as usize) {
if dfa.states.read().len() > 1 + (dfa.is_precedence_dfa() as usize) {
if seen_one {
println!()
}
Expand Down Expand Up @@ -655,11 +661,7 @@ impl<T: ?Sized> ListenerId<T> {
}

impl<T> ListenerId<T> {
fn into_listener<U>(self, boxed: Box<U>) -> Box<T>
where
U: ?Sized,
T: Unsize<U>,
{
unsafe { Box::from_raw(Box::into_raw(boxed) as *mut T) }
unsafe fn into_listener<U: ?Sized>(self, boxed: Box<U>) -> Box<T> {
Box::from_raw(Box::into_raw(boxed) as *mut T)
}
}
Loading

0 comments on commit 3517a58

Please sign in to comment.