150 lines
4.4 KiB
Rust
150 lines
4.4 KiB
Rust
use crate::{
|
|
AsGrammar, GbnfComplex, GbnfField, GbnfFieldType, GbnfLimit, GbnfPrimitive, GbnfRule,
|
|
GbnfRuleLevel, GbnfToken,
|
|
};
|
|
use itertools::Itertools;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct LimitedGbnfComplex<'a> {
|
|
pub complex: &'a GbnfComplex,
|
|
pub limit: &'a GbnfLimit,
|
|
}
|
|
|
|
impl AsGrammar for LimitedGbnfComplex<'_> {
|
|
fn rule(&self, token: &str) -> GbnfRule {
|
|
let mut main_rule = self.complex.rule_for_self(token, Some(self.limit));
|
|
let field_rules = self.complex.rules_for_fields(Some(self.limit));
|
|
main_rule.dependents = field_rules;
|
|
main_rule.dependents.push(GbnfRule::space());
|
|
main_rule
|
|
}
|
|
|
|
fn base_type_token(&self) -> GbnfToken {
|
|
GbnfToken::new(format!("{}Limit", self.complex.base_type_token()))
|
|
}
|
|
|
|
fn with_limit<'a>(&'a self, _: Option<&'a GbnfLimit>) -> impl AsGrammar + 'a {
|
|
self.clone()
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct LimitedGbnfPrimitive<'a> {
|
|
primitive: GbnfPrimitive,
|
|
values: &'a [String],
|
|
}
|
|
|
|
impl LimitedGbnfPrimitive<'_> {
|
|
pub fn new(limit: &GbnfLimit) -> Option<LimitedGbnfPrimitive> {
|
|
if let GbnfLimit::Simple(primitive, values) = limit {
|
|
Some(LimitedGbnfPrimitive {
|
|
primitive: *primitive,
|
|
values,
|
|
})
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
impl AsGrammar for LimitedGbnfPrimitive<'_> {
|
|
fn rule(&self, token: &str) -> GbnfRule {
|
|
let values = self
|
|
.values
|
|
.into_iter()
|
|
.map(|v| {
|
|
if self.primitive == GbnfPrimitive::String {
|
|
format!(r#""\"{}\"""#, v)
|
|
} else {
|
|
format!(r#""{}""#, v)
|
|
}
|
|
})
|
|
.join(" | ");
|
|
|
|
GbnfRule::new(token.into(), values, GbnfRuleLevel::Leaf)
|
|
}
|
|
|
|
fn base_type_token(&self) -> GbnfToken {
|
|
GbnfToken::new(format!("{}Limit", self.primitive.base_type_token()))
|
|
}
|
|
|
|
fn with_limit<'a>(&'a self, _: Option<&'a GbnfLimit>) -> impl AsGrammar + 'a {
|
|
self.clone()
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct LimitedGbnfField<'a> {
|
|
pub field: &'a GbnfField,
|
|
pub limit: &'a GbnfLimit,
|
|
}
|
|
|
|
macro_rules! wrap_in_limit {
|
|
($field:expr, $limit:expr, $token:expr) => {
|
|
$field.with_limit($limit).rule($token)
|
|
};
|
|
}
|
|
|
|
impl AsGrammar for LimitedGbnfField<'_> {
|
|
fn rule(&self, token: &str) -> GbnfRule {
|
|
// This is always the limit for this specific field.
|
|
let limit = Some(self.limit);
|
|
|
|
match &self.field.field_type {
|
|
GbnfFieldType::Complex(f) => wrap_in_limit!(f, limit, token),
|
|
GbnfFieldType::Primitive(f) => wrap_in_limit!(f, limit, token),
|
|
GbnfFieldType::OptionalComplex(f) => wrap_in_limit!(f, limit, token).to_optional(),
|
|
GbnfFieldType::OptionalPrimitive(f) => wrap_in_limit!(f, limit, token).to_optional(),
|
|
GbnfFieldType::ComplexList(f) => wrap_in_limit!(f, limit, token).to_list(),
|
|
GbnfFieldType::PrimitiveList(f) => wrap_in_limit!(f, limit, token).to_list(),
|
|
}
|
|
}
|
|
|
|
fn base_type_token(&self) -> GbnfToken {
|
|
let token = match &self.field.field_type {
|
|
GbnfFieldType::Primitive(f) => f.base_type_token(),
|
|
GbnfFieldType::Complex(f) => f.base_type_token(),
|
|
GbnfFieldType::OptionalPrimitive(f) => f.base_type_token(),
|
|
GbnfFieldType::OptionalComplex(f) => f.base_type_token(),
|
|
GbnfFieldType::PrimitiveList(f) => f.base_type_token(),
|
|
GbnfFieldType::ComplexList(f) => f.base_type_token(),
|
|
};
|
|
|
|
GbnfToken::new(format!("{}{}Limit", self.field.field_name, token))
|
|
}
|
|
|
|
fn with_limit<'a>(&'a self, _: Option<&'a GbnfLimit>) -> impl AsGrammar + 'a {
|
|
self.clone()
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct Limited<'a, T, L>(pub &'a T, pub Option<L>)
|
|
where
|
|
T: AsGrammar + Clone,
|
|
L: AsGrammar + Clone;
|
|
|
|
impl<T, L> AsGrammar for Limited<'_, T, L>
|
|
where
|
|
T: AsGrammar + Clone,
|
|
L: AsGrammar + Clone,
|
|
{
|
|
fn rule(&self, token: &str) -> GbnfRule {
|
|
self.1
|
|
.as_ref()
|
|
.map(|l| l.rule(token))
|
|
.unwrap_or_else(|| self.0.rule(token))
|
|
}
|
|
|
|
fn base_type_token(&self) -> GbnfToken {
|
|
self.1
|
|
.as_ref()
|
|
.map(|l| l.base_type_token())
|
|
.unwrap_or_else(|| self.0.base_type_token())
|
|
}
|
|
|
|
fn with_limit<'a>(&'a self, _: Option<&'a GbnfLimit>) -> impl AsGrammar + 'a {
|
|
self.clone()
|
|
}
|
|
}
|