lib.rs
1 use std::{ 2 collections::HashMap, 3 fmt::Display, 4 ops::{Deref, DerefMut}, 5 }; 6 7 use crate::limits::convert::{Limited, LimitedGbnfComplex, LimitedGbnfField, LimitedGbnfPrimitive}; 8 use convert_case::{Case, Casing}; 9 use itertools::Itertools; 10 use serde::de::DeserializeOwned; 11 12 mod limits; 13 14 pub mod limit { 15 pub use crate::limits::definitions::*; 16 } 17 18 pub mod prelude { 19 pub use crate::gbnf_field; 20 pub use crate::gbnf_field_type; 21 pub use crate::limit; 22 pub use crate::limit::*; 23 pub use crate::AsGbnf; 24 pub use crate::AsGbnfComplex; 25 pub use crate::AsGbnfLimit; 26 pub use crate::AsGbnfPrimitive; 27 pub use crate::AsGrammar; 28 pub use crate::GbnfComplex; 29 pub use crate::GbnfField; 30 pub use crate::GbnfFieldType; 31 pub use crate::GbnfLimit; 32 pub use crate::GbnfPrimitive; 33 pub use crate::GbnfRule; 34 pub use crate::GbnfRuleLevel; 35 pub use crate::GbnfToken; 36 pub use std::collections::HashMap; 37 } 38 39 /// The GbnfLimitedField trait is capable of producing a GbnfLimitType 40 /// enum value, which itself contains either a list of allowable 41 /// values (for simple types), or a nested GbnfLimit object(for 42 /// complex types). This allows the creation of a complex nested Limit 43 /// struct which can hold the full structure of nested limits of 44 /// multiple types that derive Gbnf and have limits. 45 pub trait AsGbnfLimit { 46 fn to_gbnf_limit(self) -> GbnfLimit; 47 } 48 49 /// A type of GBNF value limit, either simple (a list of values meant 50 /// for a single field), or complex (contains nested GbnfLimit). 51 #[derive(Debug)] 52 pub enum GbnfLimit { 53 /// The primitive type, and the allowed values. 54 Simple(GbnfPrimitive, Vec<String>), 55 /// Field name -> nested limit type. 56 Complex(HashMap<&'static str, GbnfLimit>), 57 } 58 59 // Converts GBNF defintions (through the types below) into the grammar 60 // rules. 61 pub trait AsGrammar { 62 /// Create the rule itself, along with its dependent rules. 63 fn rule(&self, token: &str) -> GbnfRule; 64 65 /// The basic token for the type, or type contained within a 66 /// wrapper. A wrapper is something like GbnfField. This always 67 /// returns the token for the base type of the rule (including 68 /// option or list, for those types). 69 fn base_type_token(&self) -> GbnfToken; 70 71 /// Wraps this trait impl in a corresponding Limited GBNF rule 72 /// creator. 73 fn with_limit<'a>(&'a self, limit: Option<&'a GbnfLimit>) -> impl AsGrammar + 'a; 74 } 75 76 /// Trait for regular types to implement to convert themselves to a 77 /// GBNF value. 78 pub trait AsGbnf { 79 fn to_gbnf() -> GbnfFieldType; 80 } 81 82 pub trait AsGbnfPrimitive { 83 fn to_gbnf_primitive() -> GbnfPrimitive; 84 } 85 86 pub trait AsGbnfComplex { 87 fn to_gbnf_complex() -> GbnfComplex; 88 } 89 90 macro_rules! define_field_type { 91 ($type:ty, $gbnf_type:expr) => { 92 impl AsGbnf for $type { 93 fn to_gbnf() -> GbnfFieldType { 94 $gbnf_type 95 } 96 } 97 }; 98 } 99 100 macro_rules! define_gbnf_primitive { 101 ($type:ty, $gbnf_primitive:expr) => { 102 impl AsGbnfPrimitive for $type { 103 fn to_gbnf_primitive() -> GbnfPrimitive { 104 $gbnf_primitive 105 } 106 } 107 }; 108 } 109 110 macro_rules! define_primitive_field_type { 111 ($type:ty, $gbnf_primitive:expr) => { 112 define_gbnf_primitive!($type, $gbnf_primitive); 113 define_field_type!($type, GbnfFieldType::Primitive($gbnf_primitive)); 114 }; 115 } 116 117 #[macro_export] 118 macro_rules! gbnf_field_type { 119 ($type:ty) => { 120 <$type as AsGbnf>::to_gbnf() 121 }; 122 } 123 124 #[macro_export] 125 macro_rules! gbnf_field { 126 ($field_name:literal, $field_type:ty) => { 127 GbnfField { 128 field_name: $field_name.to_string(), 129 field_type: gbnf_field_type!($field_type), 130 limited: false, 131 } 132 }; 133 134 ($field_name:literal, $field_type: ty, $field_limit:expr) => { 135 GbnfField { 136 field_name: $field_name.to_string(), 137 field_type: gbnf_field_type!($field_type), 138 limit: $field_limit, 139 } 140 }; 141 } 142 143 // Implemented field type mappings for common rust types. 144 define_primitive_field_type!(i16, GbnfPrimitive::Number); 145 define_primitive_field_type!(u16, GbnfPrimitive::Number); 146 define_primitive_field_type!(i32, GbnfPrimitive::Number); 147 define_primitive_field_type!(u32, GbnfPrimitive::Number); 148 define_primitive_field_type!(i64, GbnfPrimitive::Number); 149 define_primitive_field_type!(u64, GbnfPrimitive::Number); 150 define_primitive_field_type!(f32, GbnfPrimitive::Number); 151 define_primitive_field_type!(f64, GbnfPrimitive::Number); 152 define_primitive_field_type!(usize, GbnfPrimitive::Number); 153 154 define_primitive_field_type!(bool, GbnfPrimitive::Boolean); 155 156 define_primitive_field_type!(String, GbnfPrimitive::String); 157 define_primitive_field_type!(char, GbnfPrimitive::String); 158 159 // Blanket implementations to cover more types 160 impl<T, const N: usize> AsGbnf for [T; N] 161 where 162 T: AsGbnf + DeserializeOwned, 163 { 164 fn to_gbnf() -> GbnfFieldType { 165 use GbnfFieldType::*; 166 match <T as AsGbnf>::to_gbnf() { 167 Primitive(primitive_type) => PrimitiveList(primitive_type), 168 OptionalPrimitive(primitive_type) => PrimitiveList(primitive_type), 169 Complex(complex_type) => ComplexList(complex_type), 170 OptionalComplex(complex_type) => ComplexList(complex_type), 171 ComplexList(_) | PrimitiveList(_) => panic!("nested lists not supported"), 172 } 173 } 174 } 175 176 impl<T> AsGbnf for Vec<T> 177 where 178 T: AsGbnf + DeserializeOwned, 179 { 180 fn to_gbnf() -> GbnfFieldType { 181 use GbnfFieldType::*; 182 match <T as AsGbnf>::to_gbnf() { 183 Primitive(primitive_type) => PrimitiveList(primitive_type), 184 OptionalPrimitive(primitive_type) => PrimitiveList(primitive_type), 185 Complex(complex_type) => ComplexList(complex_type), 186 OptionalComplex(complex_type) => ComplexList(complex_type), 187 ComplexList(_) | PrimitiveList(_) => panic!("nested lists not supported"), 188 } 189 } 190 } 191 192 impl<T> AsGbnf for Option<T> 193 where 194 T: AsGbnf + DeserializeOwned, 195 { 196 fn to_gbnf() -> GbnfFieldType { 197 use GbnfFieldType::*; 198 match <T as AsGbnf>::to_gbnf() { 199 Primitive(primitive_type) => OptionalPrimitive(primitive_type), 200 Complex(complex_type) => OptionalComplex(complex_type), 201 OptionalPrimitive(_) | OptionalComplex(_) => panic!("nested options are not allowed"), 202 _ => panic!("optional type cannot be a list"), 203 } 204 } 205 } 206 207 #[derive(Debug, Clone, Eq, Hash, PartialEq, Ord, PartialOrd)] 208 pub enum GbnfRuleLevel { 209 Root, 210 Middle, 211 Leaf, 212 } 213 214 // Actual GBNF rule itself. Holds rule text for dedup. 215 #[derive(Debug, Clone, Eq, Hash, PartialEq)] 216 pub struct GbnfRule { 217 name: GbnfToken, 218 text: String, 219 dependents: Vec<GbnfRule>, 220 level: GbnfRuleLevel, 221 } 222 223 impl GbnfRule { 224 pub fn new(token: GbnfToken, rule_text: String, level: GbnfRuleLevel) -> GbnfRule { 225 GbnfRule { 226 name: token, 227 text: rule_text, 228 dependents: vec![], 229 level, 230 } 231 } 232 233 pub fn space() -> GbnfRule { 234 GbnfRule::new( 235 GbnfToken::new("ws".to_string()), 236 r#"[ \t\n]*"#.to_string(), 237 GbnfRuleLevel::Leaf, 238 ) 239 } 240 241 /// Turn this rule into an option rule: main rule is an option type, and 242 /// dependent rule is the original rule itself. 243 pub fn to_optional(self) -> GbnfRule { 244 let option_token = self.name.option_token(); 245 let option_rule_text = format!(r#"{} | "null""#, self.name); 246 let mut option_rule = GbnfRule::new(option_token, option_rule_text, GbnfRuleLevel::Middle); 247 option_rule.dependents = vec![self]; 248 option_rule 249 } 250 251 /// Turn this rule into a list rule: main rule is a list type, and 252 /// dependent rule is the original rule itself. 253 pub fn to_list(self) -> GbnfRule { 254 let list_name = self.name.list_token(); 255 let list_rule_text = 256 r#""[]" | "[" {SPACE} {TYPE_NAME} ("," {SPACE} {TYPE_NAME})* "]""# 257 .replace("{LIST_NAME}", &list_name.0) 258 .replace("{SPACE}", &GbnfRule::space().name.0) 259 .replace("{TYPE_NAME}", &self.name.0); 260 261 let mut list_rule = GbnfRule::new(list_name, list_rule_text, GbnfRuleLevel::Middle); 262 list_rule.dependents = vec![self, GbnfRule::space()]; 263 list_rule 264 } 265 266 /// Consume this rule to produce an ordered list of rules consisting of 267 /// this rule and its dependents. The rules in the list have no 268 /// dependents. Useful for final output of a rules list. 269 fn flatten(mut self) -> Vec<GbnfRule> { 270 let dependents = self 271 .dependents 272 .drain(0..) 273 .flat_map(|rule| rule.flatten()) 274 .collect_vec(); 275 276 // Self needs to be in front to get proper rule ordering. 277 [&[self][..], &dependents[..]].concat() 278 } 279 } 280 281 /// Tokens in the GBNF rule. 282 #[repr(transparent)] 283 #[derive(Debug, Clone, Eq, Hash, PartialEq)] 284 pub struct GbnfToken(String); 285 286 impl From<&str> for GbnfToken { 287 fn from(value: &str) -> Self { 288 GbnfToken(value.to_string().to_case(Case::Camel)) 289 } 290 } 291 292 impl Display for GbnfToken { 293 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 294 write!(f, "{}", self.0) 295 } 296 } 297 298 impl Deref for GbnfToken { 299 type Target = String; 300 fn deref(&self) -> &Self::Target { 301 &self.0 302 } 303 } 304 305 impl DerefMut for GbnfToken { 306 fn deref_mut(&mut self) -> &mut Self::Target { 307 &mut self.0 308 } 309 } 310 311 impl GbnfToken { 312 pub fn new<S: AsRef<str>>(value: S) -> GbnfToken { 313 GbnfToken::from(value.as_ref()) 314 } 315 316 fn option_token(&self) -> GbnfToken { 317 GbnfToken::new(format!("{}Option", self.0)) 318 } 319 320 fn list_token(&self) -> GbnfToken { 321 GbnfToken::new(format!("{}List", self.0)) 322 } 323 } 324 325 /// Represents a primitive value in the GBNF, the simplest possible 326 /// value a type can hold. 327 #[derive(Debug, Clone, Copy, PartialEq)] 328 pub enum GbnfPrimitive { 329 String, 330 Boolean, 331 Number, 332 } 333 334 impl GbnfPrimitive { 335 pub(self) const STRING: &'static str = r#""\"" ([^"]*) "\"""#; 336 pub(self) const BOOLEAN: &'static str = r#""true" | "false""#; 337 pub(self) const NUMBER: &'static str = r#"[0-9]+ "."? [0-9]*"#; 338 } 339 340 impl AsGrammar for GbnfPrimitive { 341 /// Output the raw GBNF rule of this primitive. 342 fn rule(&self, token: &str) -> GbnfRule { 343 let rule_text = match self { 344 Self::Boolean => Self::BOOLEAN, 345 Self::Number => Self::NUMBER, 346 Self::String => Self::STRING, 347 }; 348 349 GbnfRule::new(token.into(), rule_text.to_string(), GbnfRuleLevel::Leaf) 350 } 351 352 /// Output the token name of the GBNF rule (to refer to in other 353 /// rules). 354 fn base_type_token(&self) -> GbnfToken { 355 GbnfToken::from(match self { 356 Self::Boolean => "boolean", 357 Self::Number => "number", 358 Self::String => "string", 359 }) 360 } 361 362 fn with_limit<'a>(&'a self, limit: Option<&'a GbnfLimit>) -> impl AsGrammar + 'a { 363 Limited(self, limit.and_then(|l| LimitedGbnfPrimitive::new(l))) 364 } 365 } 366 367 /// Categorize all types of fields that the generated grammar can 368 /// handle. 369 #[derive(Debug, Clone)] 370 pub enum GbnfFieldType { 371 /// A single property on the type, e.g. myField: i32 372 Primitive(GbnfPrimitive), 373 374 /// Can be a value or null. 375 OptionalPrimitive(GbnfPrimitive), 376 377 /// A list/vec of primitive types. 378 PrimitiveList(GbnfPrimitive), 379 380 /// A complex type, with its own properties. 381 Complex(GbnfComplex), 382 383 /// Can be a value or null. 384 OptionalComplex(GbnfComplex), 385 386 /// A list/vec of complex types. 387 ComplexList(GbnfComplex), 388 } 389 390 impl GbnfFieldType { 391 pub fn as_primitive(self) -> GbnfPrimitive { 392 match self { 393 GbnfFieldType::Primitive(primitive) => primitive, 394 _ => panic!("not a GBNF primitive"), 395 } 396 } 397 398 pub fn as_complex(self) -> GbnfComplex { 399 match self { 400 GbnfFieldType::Complex(complex) => complex, 401 _ => panic!("Not a GBNF complex type"), 402 } 403 } 404 } 405 406 /// Connect a property name and a field type to generate a GBNF rule. 407 #[derive(Debug, Clone)] 408 pub struct GbnfField { 409 pub field_name: String, 410 pub field_type: GbnfFieldType, 411 pub limited: bool, 412 } 413 414 impl AsGrammar for GbnfField { 415 fn base_type_token(&self) -> GbnfToken { 416 match &self.field_type { 417 GbnfFieldType::Primitive(f) => f.base_type_token(), 418 GbnfFieldType::Complex(f) => f.base_type_token(), 419 GbnfFieldType::OptionalPrimitive(f) => f.base_type_token(), 420 GbnfFieldType::OptionalComplex(f) => f.base_type_token(), 421 GbnfFieldType::PrimitiveList(f) => f.base_type_token(), 422 GbnfFieldType::ComplexList(f) => f.base_type_token(), 423 } 424 } 425 426 fn rule(&self, token: &str) -> GbnfRule { 427 match &self.field_type { 428 GbnfFieldType::Complex(f) => f.rule(token), 429 GbnfFieldType::Primitive(f) => f.rule(token), 430 GbnfFieldType::OptionalComplex(f) => f.rule(token).to_optional(), 431 GbnfFieldType::OptionalPrimitive(f) => f.rule(token).to_optional(), 432 GbnfFieldType::ComplexList(f) => f.rule(token).to_list(), 433 GbnfFieldType::PrimitiveList(f) => f.rule(token).to_list(), 434 } 435 } 436 437 fn with_limit<'a>(&'a self, limit: Option<&'a GbnfLimit>) -> impl AsGrammar + 'a { 438 Limited( 439 self, 440 limit.map(|l| LimitedGbnfField { 441 field: self, 442 limit: l, 443 }), 444 ) 445 } 446 } 447 448 /// The complex type is a direct mapping from a supported Rust struct, 449 /// and also used to generate the root of a GBNF grammar. 450 #[derive(Debug, Clone)] 451 pub struct GbnfComplex { 452 pub name: String, 453 pub fields: Vec<GbnfField>, 454 } 455 456 impl GbnfComplex { 457 pub fn to_grammar(&self, limit: Option<GbnfLimit>) -> String { 458 // The root type cannot itself be limited. 459 let mut root = GbnfRule::new( 460 GbnfToken::new("root".to_string()), 461 self.base_type_token().0, 462 GbnfRuleLevel::Root, 463 ); 464 465 let root_type_rule = if let Some(_) = limit { 466 let limited_self = self.with_limit(limit.as_ref()); 467 limited_self.rule(&root.text) 468 } else { 469 self.rule(&root.text) 470 }; 471 472 root.dependents = vec![root_type_rule]; 473 let rules = vec![root]; 474 475 // Final output: flatten all rules into one giant list of 476 // rules with no dependents, sort according to "rule level", 477 // and then deduplicate. 478 let mut grammar = rules 479 .into_iter() 480 .flat_map(|rule| rule.flatten()) 481 .sorted_by(|rule1, rule2| Ord::cmp(&rule1.level, &rule2.level)) 482 .unique() 483 .map(|rule| format!("{} ::= {}", rule.name, rule.text)) 484 .join("\n"); 485 486 grammar.push('\n'); 487 grammar 488 } 489 490 fn rule_for_field(&self, field: &GbnfField, limit: Option<&GbnfLimit>) -> GbnfRule { 491 if let Some(GbnfLimit::Complex(nested_limit)) = limit { 492 nested_limit 493 .get(field.field_name.as_str()) 494 .map(|l| { 495 // For complex type fields, we "namespace" the 496 // field type name when limiting, to prevent 497 // collisions. 498 let limited = field.with_limit(Some(l)); 499 let token = format!("{}{}", self.name, limited.base_type_token()); 500 limited.rule(&token) 501 }) 502 .unwrap_or_else(|| field.rule(&field.base_type_token())) 503 } else { 504 field.rule(&field.base_type_token()) 505 } 506 } 507 508 /// The GBNF rule for the complex type itself. 509 fn rule_for_self(&self, token: &str, limit: Option<&GbnfLimit>) -> GbnfRule { 510 let mut rule = String::new(); 511 512 rule.push_str(r#""{" "#); 513 514 let field_rules_text = self 515 .fields 516 .iter() 517 .map(|field| { 518 let field_rule = self.rule_for_field(field, limit); 519 let token = field_rule.name; 520 521 let mut text = String::new(); 522 text.push_str(&GbnfRule::space().name.0); 523 text.push_str(" "); 524 text.push_str(&format!( 525 r#""\"{}\":" {} {}"#, 526 field.field_name, 527 GbnfRule::space().name.0, 528 token, 529 )); 530 text 531 }) 532 .join(r#" "," "#); 533 534 rule.push_str(&field_rules_text); 535 rule.push_str(r#" "}""#); 536 537 GbnfRule::new(token.into(), rule, GbnfRuleLevel::Middle) 538 } 539 540 /// The rules for the fields of the complex type. 541 fn rules_for_fields(&self, limit: Option<&GbnfLimit>) -> Vec<GbnfRule> { 542 let mut rules = vec![]; 543 for field in &self.fields { 544 rules.push(self.rule_for_field(field, limit)); 545 } 546 547 rules 548 } 549 } 550 551 impl AsGrammar for GbnfComplex { 552 fn rule(&self, token: &str) -> GbnfRule { 553 let mut main_rule = self.rule_for_self(token, None); 554 let field_rules = self.rules_for_fields(None); 555 main_rule.dependents = field_rules; 556 main_rule.dependents.push(GbnfRule::space()); 557 main_rule 558 } 559 560 fn base_type_token(&self) -> GbnfToken { 561 GbnfToken::new(self.name.clone()) 562 } 563 564 fn with_limit<'a>(&'a self, limit: Option<&'a GbnfLimit>) -> impl AsGrammar + 'a { 565 Limited( 566 self, 567 limit.map(|l| LimitedGbnfComplex { 568 complex: self, 569 limit: l, 570 }), 571 ) 572 } 573 }