Skip to content

Commit

Permalink
add(core) Context::can_feed() for LR, GLR parser
Browse files Browse the repository at this point in the history
    - bump lr version to 3.3.0
  • Loading branch information
ehwan committed Oct 23, 2024
1 parent 3ebe8d7 commit ec20ff8
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 14 deletions.
4 changes: 2 additions & 2 deletions example/glr/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ fn main() {

let input = "1+2*3+4";
for ch in input.chars() {
println!("feed: {}", ch);
println!("feed: {}, possible: {}", ch, c.can_feed(&p, &ch));
match c.feed(&p, ch, &mut ()) {
Ok(_) => {
println!("nodes: {}", c.len_paths());
Expand Down Expand Up @@ -41,7 +41,7 @@ fn main() {
let input = "1+2**3+4";
let mut c = parser::EContext::new();
for ch in input.chars() {
println!("feed: {}", ch);
println!("feed: {}, can_feed(): {}", ch, c.can_feed(&p, &ch));
match c.feed(&p, ch, &mut ()) {
Ok(_) => {
println!("nodes: {}", c.len_paths());
Expand Down
8 changes: 4 additions & 4 deletions rusty_lr/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rusty_lr"
version = "3.2.2"
version = "3.3.0"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "GLR, LR(1) and LALR(1) parser generator with custom reduce action"
Expand All @@ -10,9 +10,9 @@ keywords = ["parser", "bison", "lr", "glr", "compiler"]
categories = ["parsing", "compilers", "parser-implementations"]

[dependencies]
rusty_lr_core = { version = "3.3.4", path = "../rusty_lr_core" }
rusty_lr_derive = { version = "2.3.1", path = "../rusty_lr_derive", optional = true }
rusty_lr_buildscript = { version = "0.21.1", path = "../rusty_lr_buildscript", optional = true }
rusty_lr_core = { version = "3.4.0", path = "../rusty_lr_core" }
rusty_lr_derive = { version = "2.4.0", path = "../rusty_lr_derive", optional = true }
rusty_lr_buildscript = { version = "0.22.0", path = "../rusty_lr_buildscript", optional = true }

[features]
default = ["derive"]
Expand Down
6 changes: 3 additions & 3 deletions rusty_lr_buildscript/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rusty_lr_buildscript"
version = "0.21.1"
version = "0.22.0"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "buildscipt tools for rusty_lr"
Expand All @@ -11,8 +11,8 @@ categories = ["parsing"]


[dependencies]
rusty_lr_parser = { version = "3.24.2", path = "../rusty_lr_parser" }
rusty_lr_core = { version = "3.3.4", path = "../rusty_lr_core", features = [
rusty_lr_parser = { version = "3.25.0", path = "../rusty_lr_parser" }
rusty_lr_core = { version = "3.4.0", path = "../rusty_lr_core", features = [
"builder",
] }
codespan-reporting = "0.11"
Expand Down
2 changes: 1 addition & 1 deletion rusty_lr_core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rusty_lr_core"
version = "3.3.4"
version = "3.4.0"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "core library for rusty_lr"
Expand Down
70 changes: 70 additions & 0 deletions rusty_lr_core/src/glr/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,76 @@ impl<Data: NodeData> Context<Data> {
super::feed(parser, self, term, userdata)
}

/// Check if `term` can be feeded to current state.
/// This does not check for reduce action error.
///
/// This does not change the state of the context.
pub fn can_feed<P: Parser<Term = Data::Term, NonTerm = Data::NonTerm>>(
&self,
parser: &P,
term: &P::Term,
) -> bool
where
P::Term: Hash + Eq,
P::NonTerm: Hash + Eq,
{
let mut nodes = self.current_nodes.clone();
let mut nodes_pong: HashMap<usize, Vec<Rc<Node<Data>>>> = HashMap::default();

loop {
if nodes.is_empty() {
break;
}

nodes_pong.clear();
for (state, nodes) in nodes.drain() {
let state = &parser.get_states()[state];
if state.shift_goto_term(term).is_some() {
return true;
}

if let Some(reduce_rules) = state.reduce(term) {
for reduce_rule in reduce_rules {
let reduce_rule = &parser.get_rules()[*reduce_rule];
let reduce_len = reduce_rule.rule.len();

for p in nodes.iter() {
let mut parent = Rc::clone(p);
for _ in 0..reduce_len {
parent = Rc::clone(parent.parent.as_ref().unwrap());
}
if let Some(nonterm_shift_state) = parser.get_states()[parent.state]
.shift_goto_nonterm(&reduce_rule.name)
{
if parser.get_states()[nonterm_shift_state]
.shift_goto_term(term)
.is_some()
{
return true;
}

let nonterm_node = Rc::new(Node {
parent: Some(parent),
state: nonterm_shift_state,
data: None,
#[cfg(feature = "tree")]
tree: None,
});
nodes_pong
.entry(nonterm_shift_state)
.or_default()
.push(nonterm_node);
}
}
}
}
}
std::mem::swap(&mut nodes, &mut nodes_pong);
}

false
}

/// Search for the shortest path that can be accepted and represented as CurrentState -> Terms^N -> Tails.
/// Where Terms is set of terminals `terms`, and Tails is a sequence of terminals `tails`.
/// Returns true if there is a alive path.
Expand Down
41 changes: 41 additions & 0 deletions rusty_lr_core/src/lr/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,47 @@ impl<S: Stack> Context<S> {
super::feed(parser, self, term, userdata)
}

/// Check if `term` can be feeded to current state.
/// This does not check for reduce action error.
///
/// This does not change the state of the context.
pub fn can_feed<P: Parser<Term = S::Term, NonTerm = S::NonTerm>>(
&self,
parser: &P,
term: &S::Term,
) -> bool
where
S::Term: Hash + Eq,
S::NonTerm: Hash + Eq,
{
if parser.get_states()[*self.state_stack.last().unwrap()]
.shift_goto_term(term)
.is_some()
{
return true;
}

let mut state_stack = self.state_stack.clone();
while let Some(reduce_rule) = parser.get_states()[*state_stack.last().unwrap()].reduce(term)
{
let rule = &parser.get_rules()[reduce_rule];
let new_len = state_stack.len() - rule.rule.len();
state_stack.truncate(new_len);

if let Some(next_state) =
parser.get_states()[*state_stack.last().unwrap()].shift_goto_nonterm(&rule.name)
{
state_stack.push(next_state);
} else {
return false;
}
}

parser.get_states()[*state_stack.last().unwrap()]
.shift_goto_term(term)
.is_some()
}

#[cfg(feature = "error")]
/// Get backtrace information for current state.
/// What current state is trying to parse, and where it comes from.
Expand Down
4 changes: 2 additions & 2 deletions rusty_lr_derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rusty_lr_derive"
version = "2.3.1"
version = "2.4.0"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "proc-macro definitions for rusty_lr"
Expand All @@ -14,7 +14,7 @@ proc-macro = true

[dependencies]
proc-macro2 = "1.0.86"
rusty_lr_parser = { version = "3.24.2", path = "../rusty_lr_parser" }
rusty_lr_parser = { version = "3.25.0", path = "../rusty_lr_parser" }


[features]
Expand Down
4 changes: 2 additions & 2 deletions rusty_lr_parser/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rusty_lr_parser"
version = "3.24.2"
version = "3.25.0"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "macro line parser for rusty_lr"
Expand All @@ -12,7 +12,7 @@ categories = ["parsing"]
[dependencies]
proc-macro2 = "1.0.86"
quote = "1.0"
rusty_lr_core = { version = "3.3.4", path = "../rusty_lr_core", features = [
rusty_lr_core = { version = "3.4.0", path = "../rusty_lr_core", features = [
"builder",
] }

Expand Down

0 comments on commit ec20ff8

Please sign in to comment.