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]>
bors[bot] 2021-01-22
parent f9725ba · parent f36cf51 · commit 8b03b1a
-rw-r--r--lib/ungrammar/Cargo.toml2
-rw-r--r--lib/ungrammar/README.md3
-rw-r--r--lib/ungrammar/src/error.rs2
-rw-r--r--lib/ungrammar/src/lib.rs50
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>),
}