blob: e8e1c9daf0d3c10b41975ee6b64982e9714b5c08 [file] [edit]
//! Rust parser based on the Reference grammar.
use std::ops::Range;
use std::str::FromStr;
pub mod coverage;
pub mod lexer;
mod parser;
pub mod tree;
#[derive(Clone, Debug)]
pub struct ParseError {
pub byte_offset: usize,
pub message: String,
}
impl ParseError {
pub fn display(&self, src: &str) -> String {
let s = &src[self.byte_offset..];
match s.char_indices().nth(100) {
Some((i, _)) => format!("{} at `{}…`", self.message, &s[..i]),
None => format!("{} at `{s}`", self.message),
}
}
}
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug, Eq)]
pub enum Edition {
Edition2015,
Edition2018,
Edition2021,
Edition2024,
}
impl FromStr for Edition {
type Err = ();
fn from_str(s: &str) -> Result<Self, ()> {
match s {
"2015" => Ok(Edition::Edition2015),
"2018" => Ok(Edition::Edition2018),
"2021" => Ok(Edition::Edition2021),
"2024" => Ok(Edition::Edition2024),
_ => Err(()),
}
}
}
/// A parsed section of source corresponding to some grammar expression.
#[derive(Clone, Debug, Default)]
pub struct Node {
pub name: String,
/// Range in bytes of the original source that this node covers.
pub range: Range<usize>,
pub children: Nodes,
}
impl Node {
pub fn new(name: String, range: Range<usize>) -> Node {
Node {
name,
range,
children: Nodes::default(),
}
}
/// Returns a new `Node` with the given children.
fn with_children(name: String, start: usize, children: Nodes) -> Node {
let range = if children.0.is_empty() {
Range { start, end: start }
} else {
Range {
start: children.0.first().unwrap().range.start,
end: children.0.last().unwrap().range.end,
}
};
Node {
name,
range,
children,
}
}
/// Length in bytes of this node.
fn byte_len(&self) -> usize {
self.range.end - self.range.start
}
}
/// Abstraction over a sequence of nodes.
#[derive(Clone, Debug, Default)]
pub struct Nodes(pub Vec<Node>);
impl Nodes {
fn new(name: String, range: Range<usize>) -> Nodes {
let node = Node {
name,
range,
children: Nodes::default(),
};
Nodes(vec![node])
}
/// Converts this `Nodes` to one with a single `Node`.
fn wrap(self, name: String, start: usize) -> Nodes {
Nodes(vec![Node::with_children(name.to_string(), start, self)])
}
fn extend(&mut self, other: Nodes) {
self.0.extend(other.0)
}
fn byte_len(&self) -> usize {
if self.0.is_empty() {
0
} else {
self.0.last().unwrap().range.end - self.0.first().unwrap().range.start
}
}
}