Unnamed repository; edit this file 'description' to name the repository.
Merge rust-analyzer/ungrammar#25
25: Derive more traits for Node and Token r=azdavis a=azdavis
- Derive Hash for Node and Token
- I'd like to be able to use these types as keys for a HashMap
- Derive PartialOrd and Ord as well
- I don't particularly need these but perhaps if someone wanted to put them into a BTreeMap it might be handy
- Add an iterator for tokens of a grammar
- Write docs
- Enforce some lints
Co-authored-by: Ariel Davis <[email protected]>
| -rw-r--r-- | lib/ungrammar/Cargo.toml | 2 | ||||
| -rw-r--r-- | lib/ungrammar/README.md | 3 | ||||
| -rw-r--r-- | lib/ungrammar/src/error.rs | 2 | ||||
| -rw-r--r-- | lib/ungrammar/src/lib.rs | 50 |
4 files changed, 52 insertions, 5 deletions
diff --git a/lib/ungrammar/Cargo.toml b/lib/ungrammar/Cargo.toml index bf4a6fa0ab..539abe6ee3 100644 --- a/lib/ungrammar/Cargo.toml +++ b/lib/ungrammar/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "ungrammar" description = "A DSL for describing concrete syntax trees" -version = "1.9.3" +version = "1.10.0" license = "MIT OR Apache-2.0" repository = "https://github.com/matklad/ungrammar" authors = ["Aleksey Kladov <[email protected]>"] diff --git a/lib/ungrammar/README.md b/lib/ungrammar/README.md index ea47622f22..b5a3f48ab3 100644 --- a/lib/ungrammar/README.md +++ b/lib/ungrammar/README.md @@ -1,5 +1,6 @@ # ungrammar -A DLS for specifying concrete syntax tree. See this [introductory post](https://rust-analyzer.github.io/blog/2020/10/24/introducing-ungrammar.html). +A DSL for specifying concrete syntax trees. See this +[introductory post](https://rust-analyzer.github.io/blog/2020/10/24/introducing-ungrammar.html). See [./rust.ungram](./rust.ungram) for an example. diff --git a/lib/ungrammar/src/error.rs b/lib/ungrammar/src/error.rs index a7a62d0cc0..6cc86f52f9 100644 --- a/lib/ungrammar/src/error.rs +++ b/lib/ungrammar/src/error.rs @@ -3,8 +3,10 @@ use std::fmt; use crate::lexer::Location; +/// A type alias for std's Result with the Error as our error type. pub type Result<T, E = Error> = std::result::Result<T, E>; +/// An error encountered when parsing a Grammar. #[derive(Debug)] pub struct Error { pub(crate) message: String, diff --git a/lib/ungrammar/src/lib.rs b/lib/ungrammar/src/lib.rs index 2d51dcc5d2..7aa0ce9c88 100644 --- a/lib/ungrammar/src/lib.rs +++ b/lib/ungrammar/src/lib.rs @@ -6,6 +6,11 @@ //! See this //! [introductory post](https://rust-analyzer.github.io/blog/2020/10/24/introducing-ungrammar.html) //! for details. + +#![deny(missing_debug_implementations)] +#![deny(missing_docs)] +#![deny(rust_2018_idioms)] + mod error; mod lexer; mod parser; @@ -14,16 +19,27 @@ use std::{ops, str::FromStr}; pub use error::{Error, Result}; +/// Returns a Rust grammar. pub fn rust_grammar() -> Grammar { let src = include_str!("../rust.ungram"); src.parse().unwrap() } -#[derive(Eq, PartialEq, Debug, Copy, Clone)] +/// A node, like `A = 'b' | 'c'`. +/// +/// Indexing into a [`Grammar`] with a [`Node`] returns a reference to a +/// [`NodeData`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Node(usize); -#[derive(Eq, PartialEq, Debug, Copy, Clone)] + +/// A token, denoted with single quotes, like `'+'` or `'struct'`. +/// +/// Indexing into a [`Grammar`] with a [`Token`] returns a reference to a +/// [`TokenData`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Token(usize); +/// An Ungrammar grammar. #[derive(Default, Debug)] pub struct Grammar { nodes: Vec<NodeData>, @@ -39,9 +55,15 @@ impl FromStr for Grammar { } impl Grammar { + /// Returns an iterator over all nodes in the grammar. pub fn iter(&self) -> impl Iterator<Item = Node> + '_ { (0..self.nodes.len()).map(Node) } + + /// Returns an iterator over all tokens in the grammar. + pub fn tokens(&self) -> impl Iterator<Item = Token> + '_ { + (0..self.tokens.len()).map(Token) + } } impl ops::Index<Node> for Grammar { @@ -58,25 +80,47 @@ impl ops::Index<Token> for Grammar { } } +/// Data about a node. #[derive(Debug)] pub struct NodeData { + /// The name of the node. + /// + /// In the rule `A = 'b' | 'c'`, this is `"A"`. pub name: String, + /// The rule for this node. + /// + /// In the rule `A = 'b' | 'c'`, this represents `'b' | 'c'`. pub rule: Rule, } +/// Data about a token. #[derive(Debug)] pub struct TokenData { + /// The name of the token. pub name: String, } +/// A production rule. #[derive(Debug, Eq, PartialEq)] pub enum Rule { - Labeled { label: String, rule: Box<Rule> }, + /// A labeled rule, like `a:B` (`"a"` is the label, `B` is the rule). + Labeled { + /// The label. + label: String, + /// The rule. + rule: Box<Rule>, + }, + /// A node, like `A`. Node(Node), + /// A token, like `'struct'`. Token(Token), + /// A sequence of rules, like `'while' '(' Expr ')' Stmt`. Seq(Vec<Rule>), + /// An alternative between many rules, like `'+' | '-' | '*' | '/'`. Alt(Vec<Rule>), + /// An optional rule, like `A?`. Opt(Box<Rule>), + /// A repeated rule, like `A*`. Rep(Box<Rule>), } |