Skip to content

Commit

Permalink
add tree features for debug purpose
Browse files Browse the repository at this point in the history
  - bump version to 2.6.0
  - add Context::to_tree_list for LR, GLR parser
  - fix MultiplePathError to unit struct, use tree feature instead
  • Loading branch information
ehwan committed Aug 29, 2024
1 parent c1366b2 commit 9679314
Show file tree
Hide file tree
Showing 24 changed files with 793 additions and 372 deletions.
109 changes: 109 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ For huge and complex grammars, it is recommended to use the [buildscipt](#integr
#### `features` in `Cargo.toml`
- `build` : Enable buildscript tools.
- `fxhash` : In parser table, replace `std::collections::HashMap` with `FxHashMap` from [`rustc-hash`](https://github.com/rust-lang/rustc-hash).
- `tree` : Enable automatic Tree construction.
This feature should be used on debug purpose only, since it will consume much more memory and time.

### Example
```rust
Expand Down Expand Up @@ -125,6 +127,7 @@ println!("userdata: {}", userdata);
- [Proc-macro](#proc-macro)
- [Integrating with `build.rs`](#integrating-with-buildrs)
- [Start Parsing](#start-parsing)
- [Syntax Tree](#syntax-tree)
- [GLR Parser](#glr-parser)
- [Syntax](#syntax)

Expand Down Expand Up @@ -234,6 +237,112 @@ for token in input_sequence {
let start_symbol_value = context.accept();
```

## Syntax Tree
With the `tree` feature, `feed()` function will automatically construct the parse tree.
By calling `context.to_tree_list()`,
you can get current syntax tree. Simply print the tree list with `Display` or `Debug` will give you the pretty-printed tree.

```rust
let parser = Parser::new();
let mut context = parser.begin();
/// feed tokens...
println!( "{:?}", context.to_tree_list() ); // print tree list with `Debug` trait
println!( "{}", context.to_tree_list() ); // print tree list with `Display` trait
```

```
TreeList
├─A
│ └─M
│ └─P
│ └─Number
│ ├─WS0
│ │ └─_space_Star1
│ │ └─_space_Plus0
│ │ ├─_space_Plus0
│ │ │ └─' '
│ │ └─' '
│ ├─_Digit_Plus3
│ │ └─Digit
│ │ └─_TerminalSet2
│ │ └─'1'
│ └─WS0
│ └─_space_Star1
│ └─_space_Plus0
│ └─' '
├─'+'
├─M
│ └─P
│ └─Number
│ ├─WS0
│ │ └─_space_Star1
│ │ └─_space_Plus0
│ │ ├─_space_Plus0
│ │ │ └─' '
│ │ └─' '
│ ├─_Digit_Plus3
│ │ ├─_Digit_Plus3
│ │ │ └─Digit
│ │ │ └─_TerminalSet2
│ │ │ └─'2'
│ │ └─Digit
│ │ └─_TerminalSet2
│ │ └─'0'
│ └─WS0
│ └─_space_Star1
│ └─_space_Plus0
│ └─' '
├─'*'
├─WS0
│ └─_space_Star1
│ └─_space_Plus0
│ ├─_space_Plus0
│ │ ├─_space_Plus0
│ │ │ └─' '
│ │ └─' '
│ └─' '
├─'('
├─E
│ └─A
│ ├─A
│ │ └─M
│ │ └─P
│ │ └─Number
│ │ ├─WS0
│ │ │ └─_space_Star1
│ │ ├─_Digit_Plus3
│ │ │ └─Digit
│ │ │ └─_TerminalSet2
│ │ │ └─'3'
│ │ └─WS0
│ │ └─_space_Star1
│ │ └─_space_Plus0
│ │ └─' '
│ ├─'+'
│ └─A
│ └─M
│ └─P
│ └─Number
│ ├─WS0
│ │ └─_space_Star1
│ │ └─_space_Plus0
│ │ └─' '
│ ├─_Digit_Plus3
│ │ └─Digit
│ │ └─_TerminalSet2
│ │ └─'4'
│ └─WS0
│ └─_space_Star1
│ └─_space_Plus0
│ └─' '
├─')'
├─_space_Plus0
│ ├─_space_Plus0
│ │ └─' '
│ └─' '
└─' '
```

## GLR Parser
The GLR (Generalized LR parser) can be generated by `%glr;` directive in the grammar.
```
Expand Down
2 changes: 1 addition & 1 deletion example/calculator_u8/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ version = "0.1.0"
edition = "2021"

[dependencies]
rusty_lr = { path = "../../rusty_lr", features = ["fxhash"] }
rusty_lr = { path = "../../rusty_lr", features = ["fxhash", "tree"] }
1 change: 1 addition & 0 deletions example/calculator_u8/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ fn main() {
}
}
}
println!("{:?}", context.to_tree_list());
parser.feed(&mut context, 0 as char, &mut userdata).unwrap(); // feed EOF

let result = context.accept(); // get value of start 'E'
Expand Down
2 changes: 1 addition & 1 deletion example/glr/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ version = "0.1.0"
edition = "2021"

[dependencies]
rusty_lr = { path = "../../rusty_lr", features = ["fxhash"] }
rusty_lr = { path = "../../rusty_lr", features = ["fxhash", "tree"] }
6 changes: 4 additions & 2 deletions example/glr/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ fn main() {
match p.feed(&mut c, ch) {
Ok(_) => {
println!("nodes: {}", c.current_nodes.len());
c.backtrace(8, &p);
for tree_stream in c.to_tree_lists().into_iter() {
println!("{}", tree_stream);
}
}
Err(e) => {
println!("Error: {}", e);
Expand All @@ -29,7 +31,7 @@ fn main() {
}
}

let result = match c.accept(&p) {
let result = match c.accept() {
Ok(n) => n,
Err(e) => {
println!("Error: {}", e);
Expand Down
13 changes: 9 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 = "2.5.5"
version = "2.6.0"
edition = "2021"
license = "MIT"
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 = "2.9.0"
rusty_lr_derive = "1.17.0"
rusty_lr_buildscript = { version = "0.12.0", optional = true }
rusty_lr_core = "2.10.0"
rusty_lr_derive = "1.18.0"
rusty_lr_buildscript = { version = "0.13.0", optional = true }
# rusty_lr_core = { path = "../rusty_lr_core" }
# rusty_lr_derive = { path = "../rusty_lr_derive" }
# rusty_lr_buildscript = { path = "../rusty_lr_buildscript", optional = true }
Expand All @@ -22,6 +22,11 @@ default = []
fxhash = ["rusty_lr_core/fxhash"]
builder = ["rusty_lr_core/builder"]
build = ["dep:rusty_lr_buildscript"]
tree = [
"rusty_lr_core/tree",
"rusty_lr_derive/tree",
"rusty_lr_buildscript/tree",
]
# default = ["core", "derive"]
# core = ["rusty_lr_core"]
# derive = ["rusty_lr_derive"]
108 changes: 108 additions & 0 deletions rusty_lr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
//! #### `features` in `Cargo.toml`
//! - `build` : Enable buildscript tools.
//! - `fxhash` : In parser table, replace `std::collections::HashMap` with `FxHashMap` from [`rustc-hash`](https://github.com/rust-lang/rustc-hash).
//! - `tree` : Enable automatic Tree construction.
//! This feature should be used on debug purpose only, since it will consume much more memory and time.
//!
//! ## Features
//! - pure Rust implementation
Expand Down Expand Up @@ -126,6 +128,112 @@
//! ```
//!
//!
//! ## Syntax Tree
//! With the `tree` feature, `feed()` function will automatically construct the parse tree.
//! By calling `context.to_tree_list()`,
//! you can get current syntax tree. Simply print the tree list with `Display` or `Debug` will give you the pretty-printed tree.
//!
//! ```rust
//! let parser = Parser::new();
//! let mut context = parser.begin();
//! /// feed tokens...
//! println!( "{:?}", context.to_tree_list() ); // print tree list with `Debug` trait
//! println!( "{}", context.to_tree_list() ); // print tree list with `Display` trait
//! ```
//!
//! ```text
//! TreeList
//! ├─A
//! │ └─M
//! │ └─P
//! │ └─Number
//! │ ├─WS0
//! │ │ └─_space_Star1
//! │ │ └─_space_Plus0
//! │ │ ├─_space_Plus0
//! │ │ │ └─' '
//! │ │ └─' '
//! │ ├─_Digit_Plus3
//! │ │ └─Digit
//! │ │ └─_TerminalSet2
//! │ │ └─'1'
//! │ └─WS0
//! │ └─_space_Star1
//! │ └─_space_Plus0
//! │ └─' '
//! ├─'+'
//! ├─M
//! │ └─P
//! │ └─Number
//! │ ├─WS0
//! │ │ └─_space_Star1
//! │ │ └─_space_Plus0
//! │ │ ├─_space_Plus0
//! │ │ │ └─' '
//! │ │ └─' '
//! │ ├─_Digit_Plus3
//! │ │ ├─_Digit_Plus3
//! │ │ │ └─Digit
//! │ │ │ └─_TerminalSet2
//! │ │ │ └─'2'
//! │ │ └─Digit
//! │ │ └─_TerminalSet2
//! │ │ └─'0'
//! │ └─WS0
//! │ └─_space_Star1
//! │ └─_space_Plus0
//! │ └─' '
//! ├─'*'
//! ├─WS0
//! │ └─_space_Star1
//! │ └─_space_Plus0
//! │ ├─_space_Plus0
//! │ │ ├─_space_Plus0
//! │ │ │ └─' '
//! │ │ └─' '
//! │ └─' '
//! ├─'('
//! ├─E
//! │ └─A
//! │ ├─A
//! │ │ └─M
//! │ │ └─P
//! │ │ └─Number
//! │ │ ├─WS0
//! │ │ │ └─_space_Star1
//! │ │ ├─_Digit_Plus3
//! │ │ │ └─Digit
//! │ │ │ └─_TerminalSet2
//! │ │ │ └─'3'
//! │ │ └─WS0
//! │ │ └─_space_Star1
//! │ │ └─_space_Plus0
//! │ │ └─' '
//! │ ├─'+'
//! │ └─A
//! │ └─M
//! │ └─P
//! │ └─Number
//! │ ├─WS0
//! │ │ └─_space_Star1
//! │ │ └─_space_Plus0
//! │ │ └─' '
//! │ ├─_Digit_Plus3
//! │ │ └─Digit
//! │ │ └─_TerminalSet2
//! │ │ └─'4'
//! │ └─WS0
//! │ └─_space_Star1
//! │ └─_space_Plus0
//! │ └─' '
//! ├─')'
//! ├─_space_Plus0
//! │ ├─_space_Plus0
//! │ │ └─' '
//! │ └─' '
//! └─' '
//! ```
//!
//!
//! ## GLR Parser
//! The GLR (Generalized LR parser) can be generated by `%glr;` directive in the grammar.
Expand Down
10 changes: 7 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.12.0"
version = "0.13.0"
edition = "2021"
license = "MIT"
description = "buildscipt tools for rusty_lr"
Expand All @@ -14,7 +14,11 @@ categories = ["parsing"]
proc-macro2 = { version = "1.0.86", features = ["span-locations"] }
quote = "1.0"
# rusty_lr_parser = { path = "../rusty_lr_parser" }
rusty_lr_parser = "3.15.0"
rusty_lr_parser = "3.16.0"
# rusty_lr_core = { path = "../rusty_lr_core", features = ["fxhash", "builder"] }
rusty_lr_core = { version = "2.9.0", features = ["fxhash", "builder"] }
rusty_lr_core = { version = "2.10.0", features = ["fxhash", "builder"] }
codespan-reporting = "0.11"

[features]
default = []
tree = ["rusty_lr_parser/tree", "rusty_lr_core/tree"]
3 changes: 2 additions & 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 = "2.9.1"
version = "2.10.0"
edition = "2021"
license = "MIT"
description = "core library for rusty_lr"
Expand All @@ -17,3 +17,4 @@ default = []
# use `rustc-hash` crate for hash map
fxhash = ["dep:rustc-hash"]
builder = []
tree = []
Loading

0 comments on commit 9679314

Please sign in to comment.