use std::fmt;
use super::{CharClassItem, Grammar, GrammarExpr, GrammarFormat, GrammarRule, RuleKind};
const MAX_SAFE_INTEGER: u64 = (1 << 53) - 1;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct ExprBuilder;
impl ExprBuilder {
#[must_use]
pub const fn empty(self) -> GrammarExpr {
GrammarExpr::Empty
}
#[must_use]
pub fn term(self, value: impl Into<String>) -> GrammarExpr {
GrammarExpr::terminal(value)
}
#[must_use]
pub fn terminal(self, value: impl Into<String>) -> GrammarExpr {
GrammarExpr::terminal(value)
}
#[must_use]
pub fn terminal_insensitive(self, value: impl Into<String>) -> GrammarExpr {
GrammarExpr::terminal_insensitive(value)
}
#[must_use]
pub const fn char(self, value: char) -> GrammarExpr {
GrammarExpr::CharRange(value, value)
}
#[must_use]
pub const fn char_range(self, start: char, end: char) -> GrammarExpr {
GrammarExpr::CharRange(start, end)
}
#[must_use]
pub fn char_class<I>(self, negated: bool, items: I) -> GrammarExpr
where
I: IntoIterator<Item = CharClassItem>,
{
GrammarExpr::char_class(negated, items)
}
#[must_use]
pub const fn any(self) -> GrammarExpr {
GrammarExpr::AnyChar
}
#[must_use]
pub fn nt(self, value: impl Into<String>) -> GrammarExpr {
GrammarExpr::non_terminal(value)
}
#[must_use]
pub fn non_terminal(self, value: impl Into<String>) -> GrammarExpr {
GrammarExpr::non_terminal(value)
}
#[must_use]
pub fn choice<I>(self, ordered: bool, alternatives: I) -> GrammarExpr
where
I: IntoIterator<Item = GrammarExpr>,
{
GrammarExpr::choice(ordered, alternatives)
}
#[must_use]
pub fn choice_ordered<I>(self, alternatives: I) -> GrammarExpr
where
I: IntoIterator<Item = GrammarExpr>,
{
GrammarExpr::choice(true, alternatives)
}
#[must_use]
pub fn choice_unordered<I>(self, alternatives: I) -> GrammarExpr
where
I: IntoIterator<Item = GrammarExpr>,
{
GrammarExpr::choice(false, alternatives)
}
#[must_use]
pub fn seq<I>(self, items: I) -> GrammarExpr
where
I: IntoIterator<Item = GrammarExpr>,
{
GrammarExpr::sequence(items)
}
#[must_use]
pub fn opt(self, expr: GrammarExpr) -> GrammarExpr {
GrammarExpr::optional(expr)
}
#[must_use]
pub fn rep0(self, expr: GrammarExpr) -> GrammarExpr {
GrammarExpr::zero_or_more(expr)
}
#[must_use]
pub fn rep1(self, expr: GrammarExpr) -> GrammarExpr {
GrammarExpr::one_or_more(expr)
}
#[must_use]
pub fn repeat(self, expr: GrammarExpr, min: usize, max: Option<usize>) -> GrammarExpr {
GrammarExpr::repeat(expr, min, max)
}
#[must_use]
pub fn and(self, expr: GrammarExpr) -> GrammarExpr {
GrammarExpr::and(expr)
}
#[must_use]
pub fn not(self, expr: GrammarExpr) -> GrammarExpr {
GrammarExpr::not(expr)
}
#[must_use]
pub fn capture(self, label: Option<impl Into<String>>, expr: GrammarExpr) -> GrammarExpr {
match label {
Some(label) => GrammarExpr::capture(label, expr),
None => GrammarExpr::capture_unlabeled(expr),
}
}
#[must_use]
pub fn capture_unlabeled(self, expr: GrammarExpr) -> GrammarExpr {
GrammarExpr::capture_unlabeled(expr)
}
}
#[must_use]
pub fn sequence(items: Vec<GrammarExpr>) -> GrammarExpr {
let mut flattened = Vec::with_capacity(items.len());
for item in items {
match item {
GrammarExpr::Empty => {}
GrammarExpr::Sequence(nested) => flattened.extend(nested),
item => flattened.push(item),
}
}
match flattened.len() {
0 => GrammarExpr::Empty,
1 => flattened.remove(0),
_ => GrammarExpr::Sequence(flattened),
}
}
#[must_use]
pub fn choice(alternatives: Vec<GrammarExpr>, ordered: bool) -> GrammarExpr {
let mut flattened = Vec::with_capacity(alternatives.len());
for alternative in alternatives {
match alternative {
GrammarExpr::Choice {
ordered: nested_ordered,
alternatives: nested,
} if nested_ordered == ordered => flattened.extend(nested),
alternative => flattened.push(alternative),
}
}
match flattened.len() {
0 => GrammarExpr::Empty,
1 => flattened.remove(0),
_ => GrammarExpr::Choice {
ordered,
alternatives: flattened,
},
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct RepetitionBoundsError {
pub min: u64,
pub max: Option<u64>,
}
impl fmt::Display for RepetitionBoundsError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
let max = self.max.map_or_else(String::new, |max| max.to_string());
write!(formatter, "invalid repetition bounds {}..{max}", self.min)
}
}
impl std::error::Error for RepetitionBoundsError {}
pub fn canonical_repeat(
expr: GrammarExpr,
min: u64,
max: Option<u64>,
) -> Result<GrammarExpr, RepetitionBoundsError> {
let invalid = RepetitionBoundsError { min, max };
if min > MAX_SAFE_INTEGER || max.is_some_and(|max| max > MAX_SAFE_INTEGER || max < min) {
return Err(invalid);
}
let bound = |value: u64| usize::try_from(value).map_err(|_| invalid);
Ok(match (min, max) {
(0, None) => GrammarExpr::zero_or_more(expr),
(1, None) => GrammarExpr::one_or_more(expr),
(0, Some(1)) => GrammarExpr::optional(expr),
(min, max) => GrammarExpr::repeat(expr, bound(min)?, max.map(bound).transpose()?),
})
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct GrammarBuilder {
grammar: Grammar,
}
impl GrammarBuilder {
#[must_use]
pub const fn new() -> Self {
Self {
grammar: Grammar::new(),
}
}
#[must_use]
pub const fn source_format(mut self, source_format: GrammarFormat) -> Self {
self.grammar.source_format = Some(source_format);
self
}
#[must_use]
pub fn start(mut self, start: impl Into<String>) -> Self {
self.grammar.start = Some(start.into());
self
}
#[must_use]
pub fn rule(mut self, name: impl Into<String>, expr: GrammarExpr) -> Self {
self.grammar.rules.push(GrammarRule::new(name, expr));
self
}
#[must_use]
pub fn grammar_rule(mut self, rule: GrammarRule) -> Self {
self.grammar.rules.push(rule);
self
}
#[must_use]
pub fn rule_with_kind(
mut self,
name: impl Into<String>,
expr: GrammarExpr,
kind: RuleKind,
) -> Self {
self.grammar
.rules
.push(GrammarRule::new(name, expr).with_kind(kind));
self
}
#[must_use]
pub fn build(self) -> Grammar {
self.grammar
}
}