1mod lexer;
2
3use lexer::{Lexer, Token, TokenKind};
4
5use super::{parse_error, unsupported_error, GrammarImportError};
6use crate::grammar::{CharClassItem, Grammar, GrammarExpr, GrammarFormat, GrammarRule, RuleKind};
7
8const FORMAT: GrammarFormat = GrammarFormat::Antlr;
9
10pub fn import_antlr(text: &str) -> Result<Grammar, GrammarImportError> {
23 Parser::new(Lexer::new(text).tokenize()?).parse_grammar()
24}
25
26#[derive(Clone, Debug)]
27struct Parser {
28 tokens: Vec<Token>,
29 cursor: usize,
30 pending_comments: Vec<String>,
31}
32
33impl Parser {
34 const fn new(tokens: Vec<Token>) -> Self {
35 Self {
36 tokens,
37 cursor: 0,
38 pending_comments: Vec::new(),
39 }
40 }
41
42 fn parse_grammar(&mut self) -> Result<Grammar, GrammarImportError> {
43 let mut grammar = Grammar::new().with_source_format(FORMAT);
44 while !self.is_end() {
45 self.collect_comments();
46 if self.is_end() {
47 break;
48 }
49 if self.parse_header()? || self.parse_skipped_directive()? {
50 continue;
51 }
52 grammar.add_rule(self.parse_rule()?);
53 }
54
55 let Some(start) = grammar
56 .rules()
57 .iter()
58 .find(|rule| rule.kind() == RuleKind::Normal)
59 .or_else(|| grammar.rules().first())
60 .map(|rule| rule.name.clone())
61 else {
62 return Err(parse_error(FORMAT, "ANTLR grammar does not contain rules"));
63 };
64 grammar.set_start(start);
65 Ok(grammar)
66 }
67
68 fn parse_header(&mut self) -> Result<bool, GrammarImportError> {
69 let matched = if self.check_keyword("grammar") {
70 self.advance();
71 true
72 } else if (self.check_keyword("lexer") || self.check_keyword("parser"))
73 && self.check_next_keyword("grammar")
74 {
75 self.advance();
76 self.advance();
77 true
78 } else {
79 false
80 };
81
82 if !matched {
83 return Ok(false);
84 }
85 self.expect_ident("grammar name")?;
86 self.expect_semicolon()?;
87 self.pending_comments.clear();
88 Ok(true)
89 }
90
91 fn parse_skipped_directive(&mut self) -> Result<bool, GrammarImportError> {
92 if self.check_any_keyword(&["options", "tokens", "channels"]) {
93 self.advance();
94 if matches!(self.peek_kind(), Some(TokenKind::Action(_))) {
95 self.advance();
96 self.try_consume_semicolon();
97 self.pending_comments.clear();
98 return Ok(true);
99 }
100 self.skip_until_semicolon()?;
101 self.pending_comments.clear();
102 return Ok(true);
103 }
104
105 if self.check_any_keyword(&["import", "mode"]) {
106 self.advance();
107 self.skip_until_semicolon()?;
108 self.pending_comments.clear();
109 return Ok(true);
110 }
111
112 Ok(false)
113 }
114
115 fn parse_rule(&mut self) -> Result<GrammarRule, GrammarImportError> {
116 let comments = std::mem::take(&mut self.pending_comments);
117 let fragment = self.try_consume_keyword("fragment");
118 let name = self.expect_ident("rule name")?;
119 self.reject_rule_prelude()?;
120 self.expect_colon()?;
121
122 let mut notes = Vec::new();
123 let expr = self.parse_choice(&mut notes)?;
124 let command = if self.try_consume_arrow() {
125 Some(self.parse_lexer_command()?)
126 } else {
127 None
128 };
129 self.expect_semicolon()?;
130
131 let kind = if fragment {
132 RuleKind::Silent
133 } else if name.chars().next().is_some_and(char::is_uppercase) {
134 RuleKind::Token
135 } else {
136 RuleKind::Normal
137 };
138
139 let mut rule = GrammarRule::new(name, expr).with_kind(kind);
140 if let Some(doc) = rule_doc(comments, notes, command) {
141 rule = rule.with_doc(doc);
142 }
143 Ok(rule)
144 }
145
146 fn reject_rule_prelude(&self) -> Result<(), GrammarImportError> {
147 if self.check_colon() {
148 return Ok(());
149 }
150 if let Some(keyword) = self.peek().and_then(Token::ident) {
151 if matches!(keyword, "locals" | "returns" | "throws" | "options") {
152 return Err(unsupported_error(FORMAT, format!("rule prelude {keyword}")));
153 }
154 }
155 if matches!(self.peek_kind(), Some(TokenKind::CharSet(_))) {
156 return Err(unsupported_error(FORMAT, "rule arguments"));
157 }
158 Err(self.expected("':' before rule body"))
159 }
160
161 fn parse_choice(&mut self, notes: &mut Vec<String>) -> Result<GrammarExpr, GrammarImportError> {
162 let mut alternatives = Vec::new();
163 push_choice_alternative(&mut alternatives, self.parse_sequence(notes)?);
164 while self.try_consume_pipe() {
165 push_choice_alternative(&mut alternatives, self.parse_sequence(notes)?);
166 }
167 Ok(finish_choice(alternatives))
168 }
169
170 fn parse_sequence(
171 &mut self,
172 notes: &mut Vec<String>,
173 ) -> Result<GrammarExpr, GrammarImportError> {
174 let mut items = Vec::new();
175 loop {
176 self.skip_inline_comments();
177 if self.is_sequence_end() {
178 break;
179 }
180 push_sequence_item(&mut items, self.parse_element(notes)?);
181 }
182 Ok(finish_sequence(items))
183 }
184
185 fn parse_element(
186 &mut self,
187 notes: &mut Vec<String>,
188 ) -> Result<GrammarExpr, GrammarImportError> {
189 self.skip_inline_comments();
190 if matches!(self.peek_kind(), Some(TokenKind::Action(_))) {
191 return Ok(self.parse_action(notes));
192 }
193
194 if let Some(label) = self.label_ahead() {
195 self.advance();
196 self.advance();
197 let expr = self.parse_prefixed(notes)?;
198 return Ok(GrammarExpr::capture(label, expr));
199 }
200
201 self.parse_prefixed(notes)
202 }
203
204 fn parse_prefixed(
205 &mut self,
206 notes: &mut Vec<String>,
207 ) -> Result<GrammarExpr, GrammarImportError> {
208 self.skip_inline_comments();
209 let expr = if self.try_consume_tilde() {
210 negate_expr(self.parse_atom(notes)?)
211 } else {
212 self.parse_atom(notes)?
213 };
214 self.parse_suffixes(expr)
215 }
216
217 fn parse_atom(&mut self, notes: &mut Vec<String>) -> Result<GrammarExpr, GrammarImportError> {
218 self.skip_inline_comments();
219 let Some(token) = self.peek().cloned() else {
220 return Err(self.expected("expression element"));
221 };
222
223 match token.kind {
224 TokenKind::Ident(name) => {
225 self.advance();
226 Ok(GrammarExpr::NonTerminal(name))
227 }
228 TokenKind::String(value) => {
229 self.advance();
230 if self.try_consume_range() {
231 let end = self.expect_string("range end")?;
232 let start = single_char(&value, "range start", token.offset)?;
233 let end = single_char(&end, "range end", token.offset)?;
234 if start > end {
235 return Err(error_at(token.offset, "literal range start exceeds end"));
236 }
237 Ok(GrammarExpr::CharRange(start, end))
238 } else {
239 Ok(GrammarExpr::Terminal(value))
240 }
241 }
242 TokenKind::CharSet(content) => {
243 self.advance();
244 lower_char_set(&content, token.offset)
245 }
246 TokenKind::Dot => {
247 self.advance();
248 Ok(GrammarExpr::AnyChar)
249 }
250 TokenKind::LParen => {
251 self.advance();
252 let expr = self.parse_choice(notes)?;
253 self.expect_rparen()?;
254 Ok(expr)
255 }
256 TokenKind::Action(_) => Ok(self.parse_action(notes)),
257 _ => Err(self.expected("expression element")),
258 }
259 }
260
261 fn parse_action(&mut self, notes: &mut Vec<String>) -> GrammarExpr {
262 self.advance();
263 if self.try_consume_question() {
264 notes.push("dropped predicate".to_string());
265 } else {
266 notes.push("dropped action".to_string());
267 }
268 GrammarExpr::Empty
269 }
270
271 fn parse_suffixes(&mut self, mut expr: GrammarExpr) -> Result<GrammarExpr, GrammarImportError> {
272 loop {
273 let Some(suffix) = self.consume_suffix() else {
274 return Ok(expr);
275 };
276 expr = match suffix {
277 Suffix::Optional => GrammarExpr::optional(expr),
278 Suffix::ZeroOrMore => GrammarExpr::zero_or_more(expr),
279 Suffix::OneOrMore => GrammarExpr::one_or_more(expr),
280 };
281 if self.try_consume_question() {
282 expr = GrammarExpr::capture("non_greedy", expr);
283 }
284 }
285 }
286
287 fn parse_lexer_command(&mut self) -> Result<String, GrammarImportError> {
288 let mut tokens = Vec::new();
289 while !self.is_end() && !self.check_semicolon() {
290 if matches!(self.peek_kind(), Some(TokenKind::Comment(_))) {
291 self.advance();
292 } else {
293 tokens.push(self.advance().clone());
294 }
295 }
296 if tokens.is_empty() {
297 return Err(self.expected("lexer command"));
298 }
299 Ok(format_command(&tokens))
300 }
301
302 fn skip_until_semicolon(&mut self) -> Result<(), GrammarImportError> {
303 while !self.is_end() {
304 if self.try_consume_semicolon() {
305 return Ok(());
306 }
307 self.advance();
308 }
309 Err(self.expected("';' after directive"))
310 }
311
312 fn collect_comments(&mut self) {
313 while let Some(TokenKind::Comment(comment)) = self.peek_kind() {
314 self.pending_comments.push(comment.clone());
315 self.advance();
316 }
317 }
318
319 fn skip_inline_comments(&mut self) {
320 while matches!(self.peek_kind(), Some(TokenKind::Comment(_))) {
321 self.advance();
322 }
323 }
324
325 fn label_ahead(&self) -> Option<String> {
326 let label = self.peek()?.ident()?;
327 if matches!(
328 self.tokens.get(self.cursor + 1).map(|token| &token.kind),
329 Some(TokenKind::Equal | TokenKind::PlusEqual)
330 ) {
331 Some(label.to_string())
332 } else {
333 None
334 }
335 }
336
337 fn consume_suffix(&mut self) -> Option<Suffix> {
338 match self.peek_kind() {
339 Some(TokenKind::Question) => {
340 self.advance();
341 Some(Suffix::Optional)
342 }
343 Some(TokenKind::Star) => {
344 self.advance();
345 Some(Suffix::ZeroOrMore)
346 }
347 Some(TokenKind::Plus) => {
348 self.advance();
349 Some(Suffix::OneOrMore)
350 }
351 _ => None,
352 }
353 }
354
355 fn is_sequence_end(&self) -> bool {
356 self.is_end()
357 || matches!(
358 self.peek_kind(),
359 Some(TokenKind::Pipe | TokenKind::Semicolon | TokenKind::Arrow | TokenKind::RParen)
360 )
361 }
362
363 fn expect_ident(&mut self, role: &str) -> Result<String, GrammarImportError> {
364 let Some(token) = self.peek().cloned() else {
365 return Err(self.expected(role));
366 };
367 match token.kind {
368 TokenKind::Ident(value) => {
369 self.advance();
370 Ok(value)
371 }
372 _ => Err(self.expected(role)),
373 }
374 }
375
376 fn expect_string(&mut self, role: &str) -> Result<String, GrammarImportError> {
377 let Some(token) = self.peek().cloned() else {
378 return Err(self.expected(role));
379 };
380 match token.kind {
381 TokenKind::String(value) => {
382 self.advance();
383 Ok(value)
384 }
385 _ => Err(self.expected(role)),
386 }
387 }
388
389 fn expect_colon(&mut self) -> Result<(), GrammarImportError> {
390 if self.check_colon() {
391 self.advance();
392 Ok(())
393 } else {
394 Err(self.expected("':'"))
395 }
396 }
397
398 fn expect_semicolon(&mut self) -> Result<(), GrammarImportError> {
399 if self.check_semicolon() {
400 self.advance();
401 Ok(())
402 } else {
403 Err(self.expected("';'"))
404 }
405 }
406
407 fn expect_rparen(&mut self) -> Result<(), GrammarImportError> {
408 if matches!(self.peek_kind(), Some(TokenKind::RParen)) {
409 self.advance();
410 Ok(())
411 } else {
412 Err(self.expected("')'"))
413 }
414 }
415
416 fn expected(&self, expected: &str) -> GrammarImportError {
417 let offset = self.peek().map_or(0, |token| token.offset);
418 error_at(offset, format!("expected {expected}"))
419 }
420
421 fn try_consume_keyword(&mut self, keyword: &str) -> bool {
422 if self.check_keyword(keyword) {
423 self.advance();
424 true
425 } else {
426 false
427 }
428 }
429
430 fn try_consume_arrow(&mut self) -> bool {
431 if matches!(self.peek_kind(), Some(TokenKind::Arrow)) {
432 self.advance();
433 true
434 } else {
435 false
436 }
437 }
438
439 fn try_consume_pipe(&mut self) -> bool {
440 if matches!(self.peek_kind(), Some(TokenKind::Pipe)) {
441 self.advance();
442 true
443 } else {
444 false
445 }
446 }
447
448 fn try_consume_question(&mut self) -> bool {
449 if matches!(self.peek_kind(), Some(TokenKind::Question)) {
450 self.advance();
451 true
452 } else {
453 false
454 }
455 }
456
457 fn try_consume_tilde(&mut self) -> bool {
458 if matches!(self.peek_kind(), Some(TokenKind::Tilde)) {
459 self.advance();
460 true
461 } else {
462 false
463 }
464 }
465
466 fn try_consume_range(&mut self) -> bool {
467 if matches!(self.peek_kind(), Some(TokenKind::Range)) {
468 self.advance();
469 true
470 } else {
471 false
472 }
473 }
474
475 fn try_consume_semicolon(&mut self) -> bool {
476 if self.check_semicolon() {
477 self.advance();
478 true
479 } else {
480 false
481 }
482 }
483
484 fn check_keyword(&self, keyword: &str) -> bool {
485 self.peek().is_some_and(|token| token.is_keyword(keyword))
486 }
487
488 fn check_next_keyword(&self, keyword: &str) -> bool {
489 self.tokens
490 .get(self.cursor + 1)
491 .is_some_and(|token| token.is_keyword(keyword))
492 }
493
494 fn check_any_keyword(&self, keywords: &[&str]) -> bool {
495 self.peek()
496 .and_then(Token::ident)
497 .is_some_and(|value| keywords.contains(&value))
498 }
499
500 fn check_colon(&self) -> bool {
501 matches!(self.peek_kind(), Some(TokenKind::Colon))
502 }
503
504 fn check_semicolon(&self) -> bool {
505 matches!(self.peek_kind(), Some(TokenKind::Semicolon))
506 }
507
508 fn is_end(&self) -> bool {
509 self.cursor >= self.tokens.len()
510 }
511
512 fn peek(&self) -> Option<&Token> {
513 self.tokens.get(self.cursor)
514 }
515
516 fn peek_kind(&self) -> Option<&TokenKind> {
517 self.peek().map(|token| &token.kind)
518 }
519
520 fn advance(&mut self) -> &Token {
521 let token = &self.tokens[self.cursor];
522 self.cursor += 1;
523 token
524 }
525}
526
527#[derive(Clone, Copy, Debug, PartialEq, Eq)]
528enum Suffix {
529 Optional,
530 ZeroOrMore,
531 OneOrMore,
532}
533
534fn lower_char_set(content: &str, offset: usize) -> Result<GrammarExpr, GrammarImportError> {
535 let mut scanner = ClassScanner::new(content, offset);
536 let negated = scanner.try_consume('^');
537 let mut items = Vec::new();
538 while !scanner.is_end() {
539 let start = scanner.read_char()?;
540 if scanner.try_consume_range_separator() {
541 let end = scanner.read_char()?;
542 if start > end {
543 return Err(error_at(offset, "character class range start exceeds end"));
544 }
545 items.push(CharClassItem::Range(start, end));
546 } else {
547 items.push(CharClassItem::Char(start));
548 }
549 }
550 if items.is_empty() {
551 return Err(error_at(offset, "character class must not be empty"));
552 }
553 Ok(GrammarExpr::CharClass { negated, items })
554}
555
556#[derive(Clone, Debug)]
557struct ClassScanner<'text> {
558 text: &'text str,
559 cursor: usize,
560 offset: usize,
561}
562
563impl<'text> ClassScanner<'text> {
564 const fn new(text: &'text str, offset: usize) -> Self {
565 Self {
566 text,
567 cursor: 0,
568 offset,
569 }
570 }
571
572 fn read_char(&mut self) -> Result<char, GrammarImportError> {
573 let Some(character) = self.advance_char() else {
574 return Err(error_at(self.offset, "unexpected end of character class"));
575 };
576 if character == '\\' {
577 self.read_escape()
578 } else {
579 Ok(character)
580 }
581 }
582
583 fn read_escape(&mut self) -> Result<char, GrammarImportError> {
584 let Some(character) = self.advance_char() else {
585 return Err(error_at(self.offset, "unterminated character class escape"));
586 };
587 match character {
588 'n' => Ok('\n'),
589 'r' => Ok('\r'),
590 't' => Ok('\t'),
591 'b' => Ok('\u{08}'),
592 'f' => Ok('\u{0c}'),
593 '\\' | '\'' | '"' | '[' | ']' | '-' | '^' => Ok(character),
594 character => Ok(character),
595 }
596 }
597
598 fn try_consume(&mut self, expected: char) -> bool {
599 if self.peek_char() == Some(expected) {
600 self.advance_char();
601 true
602 } else {
603 false
604 }
605 }
606
607 fn try_consume_range_separator(&mut self) -> bool {
608 if self.peek_char() == Some('-') && self.has_char_after_current() {
609 self.advance_char();
610 true
611 } else {
612 false
613 }
614 }
615
616 fn has_char_after_current(&self) -> bool {
617 let mut chars = self.text[self.cursor..].chars();
618 chars.next();
619 chars.next().is_some()
620 }
621
622 const fn is_end(&self) -> bool {
623 self.cursor >= self.text.len()
624 }
625
626 fn peek_char(&self) -> Option<char> {
627 self.text[self.cursor..].chars().next()
628 }
629
630 fn advance_char(&mut self) -> Option<char> {
631 let character = self.peek_char()?;
632 self.cursor += character.len_utf8();
633 Some(character)
634 }
635}
636
637fn negate_expr(expr: GrammarExpr) -> GrammarExpr {
638 match expr {
639 GrammarExpr::CharClass {
640 negated: false,
641 items,
642 } => GrammarExpr::CharClass {
643 negated: true,
644 items,
645 },
646 expr => GrammarExpr::not(expr),
647 }
648}
649
650fn finish_sequence(items: Vec<GrammarExpr>) -> GrammarExpr {
651 match items.len() {
652 0 => GrammarExpr::Empty,
653 1 => items.into_iter().next().expect("one sequence item exists"),
654 _ => GrammarExpr::Sequence(items),
655 }
656}
657
658fn push_sequence_item(items: &mut Vec<GrammarExpr>, item: GrammarExpr) {
659 match item {
660 GrammarExpr::Empty => {}
661 GrammarExpr::Sequence(nested) => {
662 for item in nested {
663 push_sequence_item(items, item);
664 }
665 }
666 item => items.push(item),
667 }
668}
669
670fn finish_choice(alternatives: Vec<GrammarExpr>) -> GrammarExpr {
671 if alternatives.iter().all(|expr| expr == &GrammarExpr::Empty) {
672 return GrammarExpr::Empty;
673 }
674 match alternatives.len() {
675 0 => GrammarExpr::Empty,
676 1 => alternatives
677 .into_iter()
678 .next()
679 .expect("one alternative exists"),
680 _ => GrammarExpr::Choice {
681 ordered: false,
682 alternatives,
683 },
684 }
685}
686
687fn push_choice_alternative(alternatives: &mut Vec<GrammarExpr>, alternative: GrammarExpr) {
688 match alternative {
689 GrammarExpr::Choice {
690 ordered: false,
691 alternatives: nested,
692 } => alternatives.extend(nested),
693 alternative => alternatives.push(alternative),
694 }
695}
696
697fn single_char(value: &str, role: &str, offset: usize) -> Result<char, GrammarImportError> {
698 let mut chars = value.chars();
699 let Some(character) = chars.next() else {
700 return Err(error_at(
701 offset,
702 format!("{role} must contain one character"),
703 ));
704 };
705 if chars.next().is_some() {
706 return Err(error_at(
707 offset,
708 format!("{role} {value:?} must contain one character"),
709 ));
710 }
711 Ok(character)
712}
713
714fn rule_doc(comments: Vec<String>, notes: Vec<String>, command: Option<String>) -> Option<String> {
715 let mut parts = Vec::new();
716 parts.extend(comments.into_iter().filter(|comment| !comment.is_empty()));
717 parts.extend(notes);
718 parts.extend(command);
719 if parts.is_empty() {
720 None
721 } else {
722 Some(parts.join("; "))
723 }
724}
725
726fn format_command(tokens: &[Token]) -> String {
727 let mut output = "->".to_string();
728 for token in tokens {
729 match token.kind {
730 TokenKind::LParen => output.push('('),
731 TokenKind::RParen => output.push(')'),
732 TokenKind::Comma => output.push_str(", "),
733 _ => {
734 if output == "->" || (!output.ends_with('(') && !output.ends_with(", ")) {
735 output.push(' ');
736 }
737 output.push_str(&token.text());
738 }
739 }
740 }
741 output
742}
743
744fn error_at(offset: usize, message: impl Into<String>) -> GrammarImportError {
745 parse_error(FORMAT, format!("{} at byte {offset}", message.into()))
746}