use super::{Expression, Grammar};
use crate::TokenKind;
impl<T> Grammar<T> {
pub(super) fn validate(&self) -> Result<(), String> {
for (_, expression) in &self.rules {
self.check_references(expression)?;
}
let mut nullable = vec![false; self.rules.len()];
loop {
let mut changed = false;
for (index, (_, expression)) in self.rules.iter().enumerate() {
if !nullable[index] && self.nullable(expression, &nullable) {
nullable[index] = true;
changed = true;
}
}
if !changed {
break;
}
}
let mut edges = Vec::new();
for (_, expression) in &self.rules {
self.check_repetition(expression, &nullable)?;
let mut next = Vec::new();
self.leading_rules(expression, &nullable, &mut next);
edges.push(next);
}
let mut visiting = vec![false; self.rules.len()];
let mut visited = vec![false; self.rules.len()];
for root in 0..self.rules.len() {
if cycle(root, &edges, &mut visiting, &mut visited) {
return Err(format!(
"left recursion in PEG rule: {}",
self.rules[root].0
));
}
}
Ok(())
}
fn check_references(&self, expression: &Expression<T>) -> Result<(), String> {
match expression {
Expression::Rule(name) if !self.names.contains_key(name) => {
Err(format!("unknown PEG rule: {name}"))
}
Expression::Choice(items) | Expression::Sequence(items) => {
for item in items {
self.check_references(item)?;
}
Ok(())
}
Expression::Optional(item)
| Expression::Repeat(item)
| Expression::Ahead(item, _)
| Expression::Not(item, _) => self.check_references(item),
_ => Ok(()),
}
}
fn nullable(&self, expression: &Expression<T>, nullable: &[bool]) -> bool {
match expression {
Expression::Rule(name) => nullable[self.names[name]],
Expression::Sequence(items) => items.iter().all(|item| self.nullable(item, nullable)),
Expression::Choice(items) => items.iter().any(|item| self.nullable(item, nullable)),
Expression::Optional(_)
| Expression::Repeat(_)
| Expression::Ahead(_, _)
| Expression::Not(_, _) => true,
Expression::Native { nullable, .. } => *nullable,
Expression::Token(TokenKind::End, _) => true,
_ => false,
}
}
fn check_repetition(
&self,
expression: &Expression<T>,
nullable: &[bool],
) -> Result<(), String> {
match expression {
Expression::Repeat(item) if self.nullable(item, nullable) => {
Err("nullable PEG repetition".into())
}
Expression::Choice(items) | Expression::Sequence(items) => {
for item in items {
self.check_repetition(item, nullable)?;
}
Ok(())
}
Expression::Optional(item)
| Expression::Repeat(item)
| Expression::Ahead(item, _)
| Expression::Not(item, _) => self.check_repetition(item, nullable),
_ => Ok(()),
}
}
fn leading_rules(&self, expression: &Expression<T>, nullable: &[bool], edges: &mut Vec<usize>) {
match expression {
Expression::Rule(name) => edges.push(self.names[name]),
Expression::Sequence(items) => {
for item in items {
self.leading_rules(item, nullable, edges);
if !self.nullable(item, nullable) {
break;
}
}
}
Expression::Choice(items) => {
for item in items {
self.leading_rules(item, nullable, edges);
}
}
Expression::Optional(item)
| Expression::Repeat(item)
| Expression::Ahead(item, _)
| Expression::Not(item, _) => {
self.leading_rules(item, nullable, edges);
}
_ => (),
}
}
}
fn cycle(node: usize, edges: &[Vec<usize>], visiting: &mut [bool], visited: &mut [bool]) -> bool {
if visiting[node] {
return true;
}
if visited[node] {
return false;
}
visiting[node] = true;
for child in &edges[node] {
if cycle(*child, edges, visiting, visited) {
return true;
}
}
visiting[node] = false;
visited[node] = true;
false
}