Skip to content

Commit bc54601

Browse files
committed
rewrite visitor architecture to support arbitrary visitor lifetime
1 parent fa24927 commit bc54601

File tree

12 files changed

+49
-66
lines changed

12 files changed

+49
-66
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "antlr-rust"
3-
version = "0.2.0-dev.1"
3+
version = "0.2.0-dev.2"
44
authors = ["Konstantin Anisimov <rrevenantt@gmail.com>"]
55
homepage = "https://github.com/rrevenantt/antlr4rust"
66
repository = "https://github.com/rrevenantt/antlr4rust"

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# antlr4rust
2-
[![docs](https://docs.rs/antlr-rust/badge.svg)](https://docs.rs/antlr-rust)
3-
[![Crate](https://img.shields.io/crates/v/antlr_rust.svg)](https://crates.io/crates/antlr_rust)
2+
[![Crate](https://flat.badgen.net/crates/v/antlr-rust)](https://crates.io/crates/antlr_rust)
3+
[![docs](https://flat.badgen.net/badge/docs.rs/v0.2.0-dev.2)](https://docs.rs/antlr-rust/0.2.0-dev.2)
44

55
[ANTLR4](https://github.com/antlr/antlr4) runtime for Rust programming language.
66

src/char_stream.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ use crate::utils::Sealed;
1515
pub trait CharStream<Data>: IntStream {
1616
/// Returns underlying data piece, either slice or owned copy.
1717
/// Panics if provided indexes are invalid
18+
/// Called by parser only on token intervals.
19+
/// This fact can be used by custom implementations
1820
fn get_text(&self, a: isize, b: isize) -> Data;
1921
fn get_text_from_interval(&self, i: &Interval) -> Data { self.get_text(i.a, i.b) }
2022
}

src/diagnostic_error_listener.rs

Lines changed: 0 additions & 20 deletions
This file was deleted.

src/lib.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#![warn(missing_docs)] // warn if there is missing docs
1515
#![warn(missing_debug_implementations)]
1616
#![warn(trivial_numeric_casts)]
17+
1718
//! # Antlr4 runtime
1819
//!
1920
//! **This is pre-release version.**
@@ -58,18 +59,16 @@
5859
//! If you need to generate owned versions of parse tree or you want simpler usage,
5960
//! you can opt out zero-copy by requiring `'input` to be static. In this case it is easier to also use
6061
//! types that contains "owned" in their name or constructor function like `OwningTokenFactory`
61-
//! or `InputStream::new_owned()`
62+
//! or `InputStream::new_owned()`.
6263
//!
6364
//! ### Visitors and Listeners
6465
//!
65-
//! Currently visitors and listeners must outlive `'input`.
66-
//! In practice this means that visitor has either `'static` or `'input` lifetime.
67-
//! Thus you can retrieve references to parsed data from syntax tree to save in listener/visitor
68-
//! (as example you can see visitor test). This should cover 99% of usecases.
66+
//! Parse listeners must outlive 'input because they have to be stored inside of the parser.
67+
//! It still allows to retrieve borrowed data from parse tree which should be enough to cover 99% use cases.
68+
//!
69+
//! `ParseTreeWalker` can accept listeners with arbitrary lifetime.
6970
//!
70-
//! You can try to give visitor outside references but in this case
71-
//! if those references do not outlive `'input` you will get very confusing error messages,
72-
//! so this is not recommended.
71+
//! Visitors also can have arbitrary lifetime
7372
//!
7473
//! ### Downcasting
7574
//!

src/parser_rule_context.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use crate::token::Token;
2121
use crate::token_factory::{CommonTokenFactory, TokenFactory};
2222
use crate::tree::{
2323
ErrorNode, ParseTree, ParseTreeListener, ParseTreeVisitor, TerminalNode, Tree, Visitable,
24+
VisitableDyn,
2425
};
2526
use better_any::{Tid, TidAble, TidExt};
2627

@@ -131,7 +132,7 @@ pub trait RuleContextExt<'input>: ParserRuleContext<'input> {
131132
fn accept_children<V>(&self, visitor: &mut V)
132133
where
133134
V: ParseTreeVisitor<'input, Self::Ctx> + ?Sized,
134-
<Self::Ctx as ParserNodeType<'input>>::Type: Visitable<V>;
135+
<Self::Ctx as ParserNodeType<'input>>::Type: VisitableDyn<V>;
135136
}
136137

137138
impl<'input, T: ParserRuleContext<'input> + ?Sized + 'input> RuleContextExt<'input> for T {
@@ -177,9 +178,10 @@ impl<'input, T: ParserRuleContext<'input> + ?Sized + 'input> RuleContextExt<'inp
177178
fn accept_children<V>(&self, visitor: &mut V)
178179
where
179180
V: ParseTreeVisitor<'input, Self::Ctx> + ?Sized,
180-
<Self::Ctx as ParserNodeType<'input>>::Type: Visitable<V>,
181+
<Self::Ctx as ParserNodeType<'input>>::Type: VisitableDyn<V>,
181182
{
182-
self.get_children().for_each(|child| child.accept(visitor))
183+
self.get_children()
184+
.for_each(|child| child.accept_dyn(visitor))
183185
}
184186
}
185187

src/tree.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -221,24 +221,23 @@ pub trait ParseTreeVisitor<'input, Node: ParserNodeType<'input>>:
221221
fn visit_children(&mut self, node: &Node::Type) { self.visit_children_inner(node) }
222222
}
223223

224-
/// How visitor is supposed to visit children
224+
/// Workaround for default recursive children visiting
225225
///
226-
/// Default implementation visits children recursively
227-
/// To override it you would need to enable specialization feature
228-
///
229-
/// It is already implemented for visitors that are bound by `'input`.
226+
/// Already blanket implemented for all visitors.
227+
/// To override it you would need to implement `ParseTreeVisitor::visit_children`
230228
pub trait VisitChildren<'input, Node: ParserNodeType<'input>> {
231229
fn visit_children_inner(&mut self, node: &Node::Type);
232230
}
233231

234232
impl<'input, Node, T> VisitChildren<'input, Node> for T
235233
where
236234
Node: ParserNodeType<'input>,
237-
T: ParseTreeVisitor<'input, Node>,
238-
for<'a> &'a mut Self: CoerceUnsized<&'a mut Node::Visitor>,
239-
Node::Type: Visitable<Node::Visitor>,
235+
T: ParseTreeVisitor<'input, Node> + ?Sized,
236+
// for<'a> &'a mut Self: CoerceUnsized<&'a mut Node::Visitor>,
237+
Node::Type: VisitableDyn<T>,
240238
{
241-
default fn visit_children_inner(&mut self, node: &Node::Type) { node.accept_children(self) }
239+
#[inline(always)]
240+
fn visit_children_inner(&mut self, node: &Node::Type) { node.accept_children(self) }
242241
}
243242

244243
pub trait Visitable<Vis: ?Sized> {
@@ -247,6 +246,12 @@ pub trait Visitable<Vis: ?Sized> {
247246
}
248247
}
249248

249+
pub trait VisitableDyn<Vis: ?Sized> {
250+
fn accept_dyn(&self, visitor: &mut Vis) {
251+
unreachable!("should have been properly implemented by generated context when reachable")
252+
}
253+
}
254+
250255
pub trait ParseTreeListener<'input, Node: ParserNodeType<'input>> {
251256
fn visit_terminal(&mut self, _node: &TerminalNode<'input, Node>) {}
252257
fn visit_error_node(&mut self, _node: &ErrorNode<'input, Node>) {}
@@ -279,9 +284,6 @@ where
279284
T: ParseTreeListener<'input, Node> + 'a + ?Sized,
280285
Node::Type: Listenable<T>,
281286
{
282-
// #[doc(hidden)]
283-
// pub fn new() -> Self{ Self(PhantomData) }
284-
285287
pub fn walk<Listener, Ctx>(mut listener: Box<Listener>, t: &Ctx) -> Box<Listener>
286288
where
287289
for<'x> &'x mut Listener: CoerceUnsized<&'x mut T>,

tests/gen/csvparser.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,7 @@ use antlr_rust::token::{OwningToken, Token, TOKEN_EOF};
2222
use antlr_rust::token_factory::{CommonTokenFactory, TokenAware, TokenFactory};
2323
use antlr_rust::token_source::TokenSource;
2424
use antlr_rust::token_stream::TokenStream;
25-
use antlr_rust::tree::{
26-
ErrorNode, LeafNode, Listenable, ParseTree, ParseTreeListener, ParseTreeVisitor,
27-
ParseTreeWalker, TerminalNode, Visitable,
28-
};
25+
use antlr_rust::tree::*;
2926
use antlr_rust::vocabulary::{Vocabulary, VocabularyImpl};
3027
use antlr_rust::PredictionContextCache;
3128

@@ -147,6 +144,15 @@ pub trait CSVParserContext<'input>:
147144
{
148145
}
149146

147+
impl<'input, 'x, T> VisitableDyn<T> for dyn CSVParserContext<'input> + 'input
148+
where
149+
T: CSVVisitor<'input> + 'x,
150+
{
151+
fn accept_dyn(&self, visitor: &mut T) {
152+
self.accept(visitor as &mut (dyn CSVVisitor<'input> + 'x))
153+
}
154+
}
155+
150156
impl<'input> CSVParserContext<'input> for TerminalNode<'input, CSVParserContextType> {}
151157
impl<'input> CSVParserContext<'input> for ErrorNode<'input, CSVParserContextType> {}
152158

tests/gen/labelsparser.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,7 @@ use antlr_rust::token::{OwningToken, Token, TOKEN_EOF};
2222
use antlr_rust::token_factory::{CommonTokenFactory, TokenAware, TokenFactory};
2323
use antlr_rust::token_source::TokenSource;
2424
use antlr_rust::token_stream::TokenStream;
25-
use antlr_rust::tree::{
26-
ErrorNode, LeafNode, Listenable, ParseTree, ParseTreeListener, ParseTreeVisitor,
27-
ParseTreeWalker, TerminalNode, Visitable,
28-
};
25+
use antlr_rust::tree::*;
2926
use antlr_rust::vocabulary::{Vocabulary, VocabularyImpl};
3027
use antlr_rust::PredictionContextCache;
3128
use antlr_rust::{TidAble, TidExt};

tests/gen/referencetoatnparser.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,7 @@ use antlr_rust::token::{OwningToken, Token, TOKEN_EOF};
2222
use antlr_rust::token_factory::{CommonTokenFactory, TokenAware, TokenFactory};
2323
use antlr_rust::token_source::TokenSource;
2424
use antlr_rust::token_stream::TokenStream;
25-
use antlr_rust::tree::{
26-
ErrorNode, LeafNode, Listenable, ParseTree, ParseTreeListener, ParseTreeVisitor,
27-
ParseTreeWalker, TerminalNode, Visitable,
28-
};
25+
use antlr_rust::tree::*;
2926
use antlr_rust::vocabulary::{Vocabulary, VocabularyImpl};
3027
use antlr_rust::PredictionContextCache;
3128
use antlr_rust::{TidAble, TidExt};

0 commit comments

Comments
 (0)