1use std::collections::BTreeMap;
32
33use super::element::{GrammarElement, GrammarRule, GreType};
34use super::error::GrammarError;
35use super::utf8::{byte_at, decode_char};
36
37pub const MAX_REPETITION_THRESHOLD: u64 = 2000;
40
41pub trait GrammarVocab {
47 fn tokenize_special(&self, text: &str) -> Vec<u32>;
50}
51
52#[derive(Debug, Clone, Default, PartialEq, Eq)]
54pub struct ParsedGrammar {
55 pub rules: Vec<GrammarRule>,
58 pub symbol_ids: BTreeMap<String, u32>,
61}
62
63impl ParsedGrammar {
64 pub fn symbol_id(&self, name: &str) -> Option<u32> {
67 self.symbol_ids.get(name).copied()
68 }
69
70 pub fn symbol_name(&self, rule_id: u32) -> Option<&str> {
72 self.symbol_ids
73 .iter()
74 .find(|(_, &v)| v == rule_id)
75 .map(|(k, _)| k.as_str())
76 }
77}
78
79pub fn parse(src: &str) -> Result<ParsedGrammar, GrammarError> {
82 parse_with_vocab(src, None)
83}
84
85pub fn parse_with_vocab(
87 src: &str,
88 vocab: Option<&dyn GrammarVocab>,
89) -> Result<ParsedGrammar, GrammarError> {
90 let mut p = Parser {
91 src: src.as_bytes(),
92 pos: 0,
93 vocab,
94 out: ParsedGrammar::default(),
95 };
96 p.parse_all()?;
97 Ok(p.out)
98}
99
100struct Parser<'a> {
101 src: &'a [u8],
102 pos: usize,
103 vocab: Option<&'a dyn GrammarVocab>,
104 out: ParsedGrammar,
105}
106
107impl<'a> Parser<'a> {
108 #[inline]
109 fn at(&self, i: usize) -> u8 {
110 byte_at(self.src, i)
111 }
112
113 #[inline]
114 fn cur(&self) -> u8 {
115 self.at(self.pos)
116 }
117
118 fn err(&self, expected: impl Into<String>) -> GrammarError {
119 GrammarError::syntax(expected, self.src, self.pos)
120 }
121
122 fn err_at(&self, expected: impl Into<String>, offset: usize) -> GrammarError {
123 GrammarError::syntax(expected, self.src, offset)
124 }
125
126 fn is_digit_char(c: u8) -> bool {
129 c.is_ascii_digit()
130 }
131
132 fn is_word_char(c: u8) -> bool {
133 c.is_ascii_alphabetic() || c == b'-' || Self::is_digit_char(c)
134 }
135
136 fn parse_space(&mut self, newline_ok: bool) {
143 loop {
144 let c = self.cur();
145 if c == b' ' || c == b'\t' {
146 self.pos += 1;
147 } else if c == b'#' {
148 while self.cur() != 0 && self.cur() != b'\r' && self.cur() != b'\n' {
149 self.pos += 1;
150 }
151 } else if newline_ok && (c == b'\r' || c == b'\n') {
152 self.pos += 1;
153 } else {
154 return;
155 }
156 }
157 }
158
159 fn parse_name(&self) -> Result<usize, GrammarError> {
162 let mut end = self.pos;
163 while Self::is_word_char(self.at(end)) {
164 end += 1;
165 }
166 if end == self.pos {
167 return Err(self.err("expecting name"));
168 }
169 Ok(end)
170 }
171
172 fn parse_int_end(&self) -> Result<usize, GrammarError> {
174 let mut end = self.pos;
175 while Self::is_digit_char(self.at(end)) {
176 end += 1;
177 }
178 if end == self.pos {
179 return Err(self.err("expecting integer"));
180 }
181 Ok(end)
182 }
183
184 fn parse_u64(&mut self) -> Result<u64, GrammarError> {
186 let end = self.parse_int_end()?;
187 let text = std::str::from_utf8(&self.src[self.pos..end])
188 .map_err(|_| self.err("expecting integer"))?;
189 let value: u64 = text
190 .parse()
191 .map_err(|_| self.err_at("integer is too large", self.pos))?;
192 self.pos = end;
193 Ok(value)
194 }
195
196 fn parse_hex(&mut self, size: usize) -> Result<u32, GrammarError> {
198 let start = self.pos;
199 let end = start + size;
200 let mut value: u32 = 0;
201 let mut p = start;
202 while p < end && self.at(p) != 0 {
203 let c = self.at(p);
204 let digit = match c {
205 b'a'..=b'f' => c - b'a' + 10,
206 b'A'..=b'F' => c - b'A' + 10,
207 b'0'..=b'9' => c - b'0',
208 _ => break,
209 };
210 value = (value << 4) + digit as u32;
211 p += 1;
212 }
213 if p != end {
214 self.pos = p;
215 return Err(self.err_at(format!("expecting {size} hex chars"), start));
216 }
217 self.pos = p;
218 Ok(value)
219 }
220
221 fn parse_char(&mut self) -> Result<u32, GrammarError> {
223 if self.cur() == b'\\' {
224 let start = self.pos;
225 let next = self.at(self.pos + 1);
226 return match next {
227 b'x' => {
228 self.pos += 2;
229 self.parse_hex(2)
230 }
231 b'u' => {
232 self.pos += 2;
233 self.parse_hex(4)
234 }
235 b'U' => {
236 self.pos += 2;
237 self.parse_hex(8)
238 }
239 b't' => {
240 self.pos += 2;
241 Ok(u32::from(b'\t'))
242 }
243 b'r' => {
244 self.pos += 2;
245 Ok(u32::from(b'\r'))
246 }
247 b'n' => {
248 self.pos += 2;
249 Ok(u32::from(b'\n'))
250 }
251 b'\\' | b'"' | b'[' | b']' => {
252 self.pos += 2;
253 Ok(u32::from(next))
254 }
255 _ => Err(self.err_at("unknown escape", start)),
256 };
257 }
258 if self.cur() != 0 {
259 let (value, next) = decode_char(self.src, self.pos);
260 self.pos = next;
261 return Ok(value);
262 }
263 Err(self.err("unexpected end of input"))
264 }
265
266 fn parse_token(&mut self) -> Result<u32, GrammarError> {
268 let start = self.pos;
269 if self.cur() != b'<' {
270 return Err(self.err("expecting '<'"));
271 }
272 self.pos += 1;
273
274 if self.cur() == b'[' {
275 self.pos += 1;
276 let id = self.parse_u64()?;
277 let id = u32::try_from(id).map_err(|_| self.err_at("token id is too large", start))?;
278 if self.cur() != b']' {
279 return Err(self.err("expecting ']'"));
280 }
281 self.pos += 1;
282 if self.cur() != b'>' {
283 return Err(self.err("expecting '>'"));
284 }
285 self.pos += 1;
286 return Ok(id);
287 }
288
289 while self.cur() != 0 && self.cur() != b'>' {
290 self.pos += 1;
291 }
292 if self.cur() != b'>' {
293 return Err(self.err("expecting '>'"));
294 }
295 self.pos += 1;
296
297 let text = std::str::from_utf8(&self.src[start..self.pos])
298 .map_err(|_| self.err_at("token name is not valid UTF-8", start))?
299 .to_string();
300
301 let Some(vocab) = self.vocab else {
302 return Err(GrammarError::TokenNeedsVocabulary {
303 token: text,
304 offset: start,
305 });
306 };
307 let ids = vocab.tokenize_special(&text);
308 if ids.len() != 1 {
309 return Err(GrammarError::TokenNotSingle {
310 token: text,
311 n_tokens: ids.len(),
312 });
313 }
314 Ok(ids[0])
315 }
316
317 fn get_symbol_id(&mut self, name: &str) -> u32 {
322 let next_id = self.out.symbol_ids.len() as u32;
323 *self
324 .out
325 .symbol_ids
326 .entry(name.to_string())
327 .or_insert(next_id)
328 }
329
330 fn generate_symbol_id(&mut self, base_name: &str) -> u32 {
332 let next_id = self.out.symbol_ids.len() as u32;
333 self.out
334 .symbol_ids
335 .insert(format!("{base_name}_{next_id}"), next_id);
336 next_id
337 }
338
339 fn add_rule(&mut self, rule_id: u32, rule: GrammarRule) {
342 let idx = rule_id as usize;
343 if self.out.rules.len() <= idx {
344 self.out.rules.resize(idx + 1, GrammarRule::new());
345 }
346 self.out.rules[idx] = rule;
347 }
348
349 fn parse_alternates(
353 &mut self,
354 rule_name: &str,
355 rule_id: u32,
356 is_nested: bool,
357 ) -> Result<(), GrammarError> {
358 let mut rule = GrammarRule::new();
359 self.parse_sequence(rule_name, &mut rule, is_nested)?;
360 while self.cur() == b'|' {
361 rule.push(GrammarElement::new(GreType::Alt, 0));
362 self.pos += 1;
363 self.parse_space(true);
364 self.parse_sequence(rule_name, &mut rule, is_nested)?;
365 }
366 rule.push(GrammarElement::new(GreType::End, 0));
367 self.add_rule(rule_id, rule);
368 Ok(())
369 }
370
371 fn handle_repetitions(
374 &mut self,
375 rule: &mut GrammarRule,
376 rule_name: &str,
377 last_sym_start: usize,
378 n_prev_rules: &mut u64,
379 min_times: u64,
380 max_times: Option<u64>,
381 ) -> Result<(), GrammarError> {
382 let no_max = max_times.is_none();
383 if last_sym_start == rule.len() {
384 return Err(self.err("expecting preceding item to */+/?/{"));
385 }
386
387 let prev_rule: GrammarRule = rule[last_sym_start..].to_vec();
388
389 let mut total_rules: u64 = 1;
391 match max_times {
392 Some(max) if max > 0 => total_rules = max,
393 _ => {
394 if min_times > 0 {
395 total_rules = min_times;
396 }
397 }
398 }
399
400 let product = n_prev_rules.saturating_mul(total_rules);
401 if product >= MAX_REPETITION_THRESHOLD {
402 return Err(GrammarError::RepetitionTooLarge {
403 requested: product,
404 limit: MAX_REPETITION_THRESHOLD,
405 offset: self.pos,
406 });
407 }
408
409 if min_times == 0 {
410 rule.truncate(last_sym_start);
411 } else {
412 for _ in 1..min_times {
413 rule.extend_from_slice(&prev_rule);
414 }
415 }
416
417 let mut last_rec_rule_id: u32 = 0;
418 let n_opt = match max_times {
422 None => 1,
423 Some(max) => max.saturating_sub(min_times),
424 };
425
426 let mut rec_rule = prev_rule.clone();
427 for i in 0..n_opt {
428 rec_rule.truncate(prev_rule.len());
429 let rec_rule_id = self.generate_symbol_id(rule_name);
430 if i > 0 || no_max {
431 rec_rule.push(GrammarElement::new(
432 GreType::RuleRef,
433 if no_max {
434 rec_rule_id
435 } else {
436 last_rec_rule_id
437 },
438 ));
439 }
440 rec_rule.push(GrammarElement::new(GreType::Alt, 0));
441 rec_rule.push(GrammarElement::new(GreType::End, 0));
442 self.add_rule(rec_rule_id, rec_rule.clone());
443 last_rec_rule_id = rec_rule_id;
444 }
445 if n_opt > 0 {
446 rule.push(GrammarElement::new(GreType::RuleRef, last_rec_rule_id));
447 }
448 *n_prev_rules = product;
452 Ok(())
453 }
454
455 fn parse_sequence(
457 &mut self,
458 rule_name: &str,
459 rule: &mut GrammarRule,
460 is_nested: bool,
461 ) -> Result<(), GrammarError> {
462 let mut last_sym_start = rule.len();
463 let mut n_prev_rules: u64 = 1;
464
465 while self.cur() != 0 {
466 match self.cur() {
467 b'"' => {
468 self.pos += 1;
470 last_sym_start = rule.len();
471 n_prev_rules = 1;
472 while self.cur() != b'"' {
473 if self.cur() == 0 {
474 return Err(self.err("unexpected end of input"));
475 }
476 let value = self.parse_char()?;
477 rule.push(GrammarElement::new(GreType::Char, value));
478 }
479 self.pos += 1;
480 self.parse_space(is_nested);
481 }
482 b'[' => {
483 self.pos += 1;
485 let mut start_type = GreType::Char;
486 if self.cur() == b'^' {
487 self.pos += 1;
488 start_type = GreType::CharNot;
489 }
490 last_sym_start = rule.len();
491 n_prev_rules = 1;
492 while self.cur() != b']' {
493 if self.cur() == 0 {
494 return Err(self.err("unexpected end of input"));
495 }
496 let value = self.parse_char()?;
497 let gtype = if last_sym_start < rule.len() {
502 GreType::CharAlt
503 } else {
504 start_type
505 };
506 rule.push(GrammarElement::new(gtype, value));
507 if self.at(self.pos) == b'-' && self.at(self.pos + 1) != b']' {
508 if self.at(self.pos + 1) == 0 {
509 return Err(self.err("unexpected end of input"));
510 }
511 self.pos += 1;
512 let endchar = self.parse_char()?;
513 rule.push(GrammarElement::new(GreType::CharRngUpper, endchar));
514 }
515 }
516 self.pos += 1;
517 self.parse_space(is_nested);
518 }
519 b'<' | b'!' => {
520 let mut gtype = GreType::Token;
522 if self.cur() == b'!' {
523 gtype = GreType::TokenNot;
524 self.pos += 1;
525 }
526 let token_id = self.parse_token()?;
527 last_sym_start = rule.len();
528 n_prev_rules = 1;
529 rule.push(GrammarElement::new(gtype, token_id));
530 self.parse_space(is_nested);
531 }
532 c if Self::is_word_char(c) => {
533 let name_end = self.parse_name()?;
535 let name = std::str::from_utf8(&self.src[self.pos..name_end])
536 .map_err(|_| self.err("rule name is not valid UTF-8"))?
537 .to_string();
538 let ref_rule_id = self.get_symbol_id(&name);
539 self.pos = name_end;
540 self.parse_space(is_nested);
541 last_sym_start = rule.len();
542 n_prev_rules = 1;
543 rule.push(GrammarElement::new(GreType::RuleRef, ref_rule_id));
544 }
545 b'(' => {
546 self.pos += 1;
549 self.parse_space(true);
550 let n_rules_before = self.out.symbol_ids.len() as u64;
551 let sub_rule_id = self.generate_symbol_id(rule_name);
552 self.parse_alternates(rule_name, sub_rule_id, true)?;
553 n_prev_rules = (self.out.symbol_ids.len() as u64 - n_rules_before).max(1);
554 last_sym_start = rule.len();
555 rule.push(GrammarElement::new(GreType::RuleRef, sub_rule_id));
556 if self.cur() != b')' {
557 return Err(self.err("expecting ')'"));
558 }
559 self.pos += 1;
560 self.parse_space(is_nested);
561 }
562 b'.' => {
563 last_sym_start = rule.len();
564 n_prev_rules = 1;
565 rule.push(GrammarElement::new(GreType::CharAny, 0));
566 self.pos += 1;
567 self.parse_space(is_nested);
568 }
569 b'*' => {
570 self.pos += 1;
571 self.parse_space(is_nested);
572 self.handle_repetitions(
573 rule,
574 rule_name,
575 last_sym_start,
576 &mut n_prev_rules,
577 0,
578 None,
579 )?;
580 }
581 b'+' => {
582 self.pos += 1;
583 self.parse_space(is_nested);
584 self.handle_repetitions(
585 rule,
586 rule_name,
587 last_sym_start,
588 &mut n_prev_rules,
589 1,
590 None,
591 )?;
592 }
593 b'?' => {
594 self.pos += 1;
595 self.parse_space(is_nested);
596 self.handle_repetitions(
597 rule,
598 rule_name,
599 last_sym_start,
600 &mut n_prev_rules,
601 0,
602 Some(1),
603 )?;
604 }
605 b'{' => {
606 self.pos += 1;
607 self.parse_space(is_nested);
608
609 if !Self::is_digit_char(self.cur()) {
610 return Err(self.err("expecting an int"));
611 }
612 let min_times = self.parse_u64()?;
613 self.parse_space(is_nested);
614
615 let mut max_times: Option<u64> = None;
616
617 if self.cur() == b'}' {
618 max_times = Some(min_times);
619 self.pos += 1;
620 self.parse_space(is_nested);
621 } else if self.cur() == b',' {
622 self.pos += 1;
623 self.parse_space(is_nested);
624
625 if Self::is_digit_char(self.cur()) {
626 max_times = Some(self.parse_u64()?);
627 self.parse_space(is_nested);
628 }
629
630 if self.cur() != b'}' {
631 return Err(self.err("expecting '}'"));
632 }
633 self.pos += 1;
634 self.parse_space(is_nested);
635 } else {
636 return Err(self.err("expecting ','"));
637 }
638 if min_times > MAX_REPETITION_THRESHOLD
639 || max_times.is_some_and(|m| m > MAX_REPETITION_THRESHOLD)
640 {
641 return Err(GrammarError::RepetitionTooLarge {
642 requested: max_times.unwrap_or(min_times),
643 limit: MAX_REPETITION_THRESHOLD,
644 offset: self.pos,
645 });
646 }
647 self.handle_repetitions(
648 rule,
649 rule_name,
650 last_sym_start,
651 &mut n_prev_rules,
652 min_times,
653 max_times,
654 )?;
655 }
656 _ => break,
657 }
658 }
659 Ok(())
660 }
661
662 fn parse_rule(&mut self) -> Result<(), GrammarError> {
664 let name_end = self.parse_name()?;
665 let name = std::str::from_utf8(&self.src[self.pos..name_end])
666 .map_err(|_| self.err("rule name is not valid UTF-8"))?
667 .to_string();
668 self.pos = name_end;
669 self.parse_space(false);
670 let rule_id = self.get_symbol_id(&name);
671
672 if !(self.cur() == b':' && self.at(self.pos + 1) == b':' && self.at(self.pos + 2) == b'=') {
673 return Err(self.err("expecting ::="));
674 }
675 self.pos += 3;
676 self.parse_space(true);
677
678 self.parse_alternates(&name, rule_id, false)?;
679
680 if self.cur() == b'\r' {
681 self.pos += if self.at(self.pos + 1) == b'\n' { 2 } else { 1 };
682 } else if self.cur() == b'\n' {
683 self.pos += 1;
684 } else if self.cur() != 0 {
685 return Err(self.err("expecting newline or end"));
686 }
687 self.parse_space(true);
688 Ok(())
689 }
690
691 fn parse_all(&mut self) -> Result<(), GrammarError> {
693 self.parse_space(true);
694 while self.cur() != 0 {
695 self.parse_rule()?;
696 }
697
698 for id in 0..self.out.rules.len() {
703 if self.out.rules[id].is_empty() {
704 return Err(self.undefined(id as u32));
705 }
706 }
707 for rule in &self.out.rules {
708 for elem in rule {
709 if elem.gtype == GreType::RuleRef {
710 let idx = elem.value as usize;
711 if idx >= self.out.rules.len() || self.out.rules[idx].is_empty() {
712 return Err(self.undefined(elem.value));
713 }
714 }
715 }
716 }
717 Ok(())
718 }
719
720 fn undefined(&self, rule_id: u32) -> GrammarError {
721 GrammarError::UndefinedRule {
722 name: self
723 .out
724 .symbol_name(rule_id)
725 .unwrap_or("<unnamed>")
726 .to_string(),
727 rule_id,
728 }
729 }
730}