1use crate::ast::{
4 ExampleDecl, Expr, Grammar, GrammarItem, ImportDecl, RuleDecl, TokenBody, TokenDecl,
5};
6use crate::diagnostic::{Diagnostic, DiagnosticKind};
7use crate::error::RantlrError;
8use crate::lexer::{lex, LexerError};
9use crate::span::Span;
10use crate::token::{BuiltinType, Keyword, Token, TokenKind};
11
12pub fn parse(source: &str) -> Result<Grammar, RantlrError> {
14 let tokens = lex(source).map_err(|e| match e {
15 LexerError::Diagnostic(diag) => RantlrError::from_diagnostic(source, diag),
16 })?;
17 Parser::new(source, tokens).parse_grammar()
18}
19
20struct Parser<'src> {
21 source: &'src str,
22 tokens: Vec<Token>,
23 pos: usize,
24}
25
26impl<'src> Parser<'src> {
27 fn new(source: &'src str, tokens: Vec<Token>) -> Self {
28 Self {
29 source,
30 tokens,
31 pos: 0,
32 }
33 }
34
35 fn parse_grammar(mut self) -> Result<Grammar, RantlrError> {
36 let start = self.peek().span;
37 self.expect_keyword(Keyword::Grammar)?;
38 let (name, name_span) = self.expect_ident("grammar name")?;
39 self.expect_semi()?;
40
41 let mut items = Vec::new();
42 while !self.at_eof() {
43 items.push(self.parse_item()?);
44 }
45
46 let end = self.prev_span();
47 Ok(Grammar {
48 name,
49 name_span,
50 items,
51 span: start.merge(end),
52 })
53 }
54
55 fn parse_item(&mut self) -> Result<GrammarItem, RantlrError> {
56 match &self.peek().kind {
57 TokenKind::Keyword(Keyword::Token) => Ok(GrammarItem::Token(self.parse_token_decl()?)),
58 TokenKind::Keyword(Keyword::Rule) => Ok(GrammarItem::Rule(self.parse_rule_decl()?)),
59 TokenKind::Keyword(Keyword::Example) => {
60 Ok(GrammarItem::Example(self.parse_example_decl()?))
61 }
62 TokenKind::Keyword(Keyword::Import) => {
63 Ok(GrammarItem::Import(self.parse_import_decl()?))
64 }
65 _ => Err(self.unexpected(
66 "expected `token`, `rule`, `example`, or `import`",
67 )),
68 }
69 }
70
71 fn parse_token_decl(&mut self) -> Result<TokenDecl, RantlrError> {
72 let start = self.peek().span;
73 self.expect_keyword(Keyword::Token)?;
74 let (name, name_span) = self.expect_ident("token name")?;
75 self.expect_kind(TokenKind::Eq, "`=`")?;
76
77 let body = match &self.peek().kind {
78 TokenKind::Builtin(b) => {
79 let b = *b;
80 self.bump();
81 TokenBody::Builtin(b)
82 }
83 TokenKind::String(s) => {
84 let s = s.clone();
85 self.bump();
86 TokenBody::Literal(s)
87 }
88 TokenKind::Ident(name) => {
89 let span = self.peek().span;
92 let name = name.clone();
93 if let Some(b) = BuiltinType::from_ident(&name) {
94 self.bump();
95 TokenBody::Builtin(b)
96 } else {
97 return Err(self.err_at(
98 span,
99 format!("expected a built-in type or string literal, found `{name}`"),
100 Some(
101 "built-ins: Number, Identifier, QuotedString, Email, Url, DateTime",
102 ),
103 ));
104 }
105 }
106 _ => {
107 return Err(self.unexpected(
108 "expected a built-in type (e.g. Number or Identifier) or a string literal",
109 ));
110 }
111 };
112
113 let skip = if self.eat_kind(&TokenKind::Arrow) {
114 self.expect_keyword(Keyword::Skip)?;
115 true
116 } else {
117 false
118 };
119
120 self.expect_semi()?;
121 let end = self.prev_span();
122 Ok(TokenDecl {
123 name,
124 name_span,
125 body,
126 skip,
127 span: start.merge(end),
128 })
129 }
130
131 fn parse_rule_decl(&mut self) -> Result<RuleDecl, RantlrError> {
132 let start = self.peek().span;
133 self.expect_keyword(Keyword::Rule)?;
134 let (name, name_span) = self.expect_ident("rule name")?;
135 self.expect_kind(TokenKind::LBrace, "`{`")?;
136 let body = self.parse_expr()?;
137 self.expect_kind(TokenKind::RBrace, "`}`")?;
138 let end = self.prev_span();
139 Ok(RuleDecl {
140 name,
141 name_span,
142 body,
143 span: start.merge(end),
144 })
145 }
146
147 fn parse_example_decl(&mut self) -> Result<ExampleDecl, RantlrError> {
148 let start = self.peek().span;
149 self.expect_keyword(Keyword::Example)?;
150
151 let label = if let TokenKind::String(s) = &self.peek().kind {
152 let s = s.clone();
153 self.bump();
154 Some(s)
155 } else {
156 None
157 };
158
159 self.expect_kind(TokenKind::LBrace, "`{`")?;
160 self.expect_keyword(Keyword::Input)?;
161 self.expect_kind(TokenKind::Colon, "`:`")?;
162
163 let input = match &self.peek().kind {
164 TokenKind::RawString(s) | TokenKind::String(s) => {
165 let s = s.clone();
166 self.bump();
167 s
168 }
169 _ => {
170 return Err(self.unexpected(
171 "expected example input as a string or raw string (`...`)",
172 ));
173 }
174 };
175
176 let expect = if self.eat_keyword(Keyword::Expect) {
177 self.expect_kind(TokenKind::Colon, "`:`")?;
178 let (name, _) = self.expect_ident("expected rule name")?;
179 Some(name)
180 } else {
181 None
182 };
183
184 self.expect_kind(TokenKind::RBrace, "`}`")?;
185 let end = self.prev_span();
186 Ok(ExampleDecl {
187 label,
188 input,
189 expect,
190 span: start.merge(end),
191 })
192 }
193
194 fn parse_import_decl(&mut self) -> Result<ImportDecl, RantlrError> {
195 let start = self.peek().span;
196 self.expect_keyword(Keyword::Import)?;
197 let path = match &self.peek().kind {
198 TokenKind::String(s) => {
199 let s = s.clone();
200 self.bump();
201 s
202 }
203 _ => return Err(self.unexpected("expected a string path after `import`")),
204 };
205 self.expect_semi()?;
206 let end = self.prev_span();
207 Ok(ImportDecl {
208 path,
209 span: start.merge(end),
210 })
211 }
212
213 fn parse_expr(&mut self) -> Result<Expr, RantlrError> {
221 self.parse_alt()
222 }
223
224 fn parse_alt(&mut self) -> Result<Expr, RantlrError> {
225 let mut alts = vec![self.parse_seq()?];
226 while self.eat_kind(&TokenKind::Pipe) {
227 alts.push(self.parse_seq()?);
228 }
229 Ok(Expr::alt(alts))
230 }
231
232 fn parse_seq(&mut self) -> Result<Expr, RantlrError> {
233 let mut items = Vec::new();
234 while self.at_atom_start() {
235 items.push(self.parse_atom()?);
236 }
237 if items.is_empty() {
238 return Err(self.unexpected(
239 "expected an expression (match, repeat, optional, name, string, or group)",
240 ));
241 }
242 Ok(Expr::seq(items))
243 }
244
245 fn parse_atom(&mut self) -> Result<Expr, RantlrError> {
246 match &self.peek().kind {
247 TokenKind::Keyword(Keyword::Match) => self.parse_match(),
248 TokenKind::Keyword(Keyword::Repeat) => self.parse_repeat(),
249 TokenKind::Keyword(Keyword::Optional) => self.parse_optional(),
250 _ => self.parse_primary(),
251 }
252 }
253
254 fn parse_match(&mut self) -> Result<Expr, RantlrError> {
255 self.expect_keyword(Keyword::Match)?;
256 let mut arms = vec![self.parse_primary()?];
260 while self.eat_kind(&TokenKind::Pipe) {
261 if !self.at_primary_start() {
262 return Err(self.unexpected("expected a match arm after `|`"));
263 }
264 arms.push(self.parse_primary()?);
265 }
266 Ok(Expr::Match { arms })
267 }
268
269 fn parse_repeat(&mut self) -> Result<Expr, RantlrError> {
270 self.expect_keyword(Keyword::Repeat)?;
271
272 let (min, max) = if self.eat_kind(&TokenKind::LParen) {
273 let min = match &self.peek().kind {
274 TokenKind::Integer(n) => {
275 let n = *n;
276 self.bump();
277 Some(n)
278 }
279 TokenKind::DotDot => None,
280 _ => {
281 return Err(self.unexpected(
282 "expected a lower bound integer or `..` in repeat(...)",
283 ));
284 }
285 };
286 self.expect_kind(TokenKind::DotDot, "`..`")?;
287 let max = if let TokenKind::Integer(n) = &self.peek().kind {
288 let n = *n;
289 self.bump();
290 Some(n)
291 } else {
292 None
293 };
294 self.expect_kind(TokenKind::RParen, "`)`")?;
295 (min.or(Some(0)), max)
296 } else {
297 (None, None)
298 };
299
300 self.expect_kind(TokenKind::LBrace, "`{`")?;
301 let body = self.parse_expr()?;
302 self.expect_kind(TokenKind::RBrace, "`}`")?;
303
304 Ok(Expr::Repeat {
305 min,
306 max,
307 body: Box::new(body),
308 })
309 }
310
311 fn parse_optional(&mut self) -> Result<Expr, RantlrError> {
312 self.expect_keyword(Keyword::Optional)?;
313 self.expect_kind(TokenKind::LBrace, "`{`")?;
314 let body = self.parse_expr()?;
315 self.expect_kind(TokenKind::RBrace, "`}`")?;
316 Ok(Expr::Optional {
317 body: Box::new(body),
318 })
319 }
320
321 fn parse_primary(&mut self) -> Result<Expr, RantlrError> {
322 let tok = self.peek().clone();
323 match tok.kind {
324 TokenKind::Ident(name) => {
325 self.bump();
326 Ok(Expr::Ref {
327 name,
328 span: tok.span,
329 })
330 }
331 TokenKind::Builtin(b) => {
332 self.bump();
335 Ok(Expr::Ref {
336 name: b.as_str().to_string(),
337 span: tok.span,
338 })
339 }
340 TokenKind::String(value) => {
341 self.bump();
342 Ok(Expr::Literal {
343 value,
344 span: tok.span,
345 })
346 }
347 TokenKind::LParen => {
348 self.bump();
349 let body = self.parse_expr()?;
350 self.expect_kind(TokenKind::RParen, "`)`")?;
351 Ok(Expr::Group {
352 body: Box::new(body),
353 })
354 }
355 _ => Err(self.unexpected("expected a name, string, or `(...)` group")),
356 }
357 }
358
359 fn at_atom_start(&self) -> bool {
362 matches!(
363 &self.peek().kind,
364 TokenKind::Keyword(Keyword::Match)
365 | TokenKind::Keyword(Keyword::Repeat)
366 | TokenKind::Keyword(Keyword::Optional)
367 | TokenKind::Ident(_)
368 | TokenKind::Builtin(_)
369 | TokenKind::String(_)
370 | TokenKind::LParen
371 )
372 }
373
374 fn at_primary_start(&self) -> bool {
375 matches!(
376 &self.peek().kind,
377 TokenKind::Ident(_)
378 | TokenKind::Builtin(_)
379 | TokenKind::String(_)
380 | TokenKind::LParen
381 )
382 }
383
384 fn at_eof(&self) -> bool {
385 self.peek().kind.is_eof()
386 }
387
388 fn peek(&self) -> &Token {
389 &self.tokens[self.pos.min(self.tokens.len().saturating_sub(1))]
390 }
391
392 fn prev_span(&self) -> Span {
393 if self.pos == 0 {
394 Span::default()
395 } else {
396 self.tokens[self.pos - 1].span
397 }
398 }
399
400 fn bump(&mut self) {
401 if !self.peek().kind.is_eof() {
402 self.pos += 1;
403 }
404 }
405
406 fn eat_kind(&mut self, kind: &TokenKind) -> bool {
407 let matched = match (kind, &self.peek().kind) {
408 (TokenKind::LBrace, TokenKind::LBrace)
409 | (TokenKind::RBrace, TokenKind::RBrace)
410 | (TokenKind::LParen, TokenKind::LParen)
411 | (TokenKind::RParen, TokenKind::RParen)
412 | (TokenKind::LBracket, TokenKind::LBracket)
413 | (TokenKind::RBracket, TokenKind::RBracket)
414 | (TokenKind::Pipe, TokenKind::Pipe)
415 | (TokenKind::Comma, TokenKind::Comma)
416 | (TokenKind::Semi, TokenKind::Semi)
417 | (TokenKind::Colon, TokenKind::Colon)
418 | (TokenKind::Eq, TokenKind::Eq)
419 | (TokenKind::DotDot, TokenKind::DotDot)
420 | (TokenKind::Arrow, TokenKind::Arrow)
421 | (TokenKind::Eof, TokenKind::Eof) => true,
422 _ => false,
423 };
424 if matched {
425 self.bump();
426 }
427 matched
428 }
429
430 fn eat_keyword(&mut self, kw: Keyword) -> bool {
431 if matches!(&self.peek().kind, TokenKind::Keyword(k) if *k == kw) {
432 self.bump();
433 true
434 } else {
435 false
436 }
437 }
438
439 fn expect_keyword(&mut self, kw: Keyword) -> Result<(), RantlrError> {
440 if self.eat_keyword(kw) {
441 Ok(())
442 } else {
443 Err(self.unexpected(&format!("expected keyword `{}`", kw.as_str())))
444 }
445 }
446
447 fn expect_kind(&mut self, kind: TokenKind, label: &str) -> Result<(), RantlrError> {
448 if self.eat_kind(&kind) {
449 Ok(())
450 } else {
451 Err(self.unexpected(&format!("expected {label}")))
452 }
453 }
454
455 fn expect_semi(&mut self) -> Result<(), RantlrError> {
456 self.expect_kind(TokenKind::Semi, "`;`")
457 }
458
459 fn expect_ident(&mut self, what: &str) -> Result<(String, Span), RantlrError> {
460 match &self.peek().kind {
461 TokenKind::Ident(name) => {
462 let name = name.clone();
463 let span = self.peek().span;
464 self.bump();
465 Ok((name, span))
466 }
467 TokenKind::Builtin(b) => {
469 let span = self.peek().span;
471 Err(self.err_at(
472 span,
473 format!(
474 "expected {what}, found built-in type `{}`",
475 b.as_str()
476 ),
477 Some("built-in types are used on the right-hand side of `token Name = ...`"),
478 ))
479 }
480 _ => Err(self.unexpected(&format!("expected {what}"))),
481 }
482 }
483
484 fn unexpected(&self, message: &str) -> RantlrError {
485 let tok = self.peek();
486 let found = describe_token(&tok.kind);
487 self.err_at(
488 tok.span,
489 format!("{message}, found {found}"),
490 None,
491 )
492 }
493
494 fn err_at(
495 &self,
496 span: Span,
497 message: impl Into<String>,
498 help: Option<&str>,
499 ) -> RantlrError {
500 let mut diag = Diagnostic::error(DiagnosticKind::ParseError, message, span);
501 if let Some(help) = help {
502 diag = diag.with_help(help);
503 }
504 RantlrError::from_diagnostic(self.source, diag)
505 }
506}
507
508fn describe_token(kind: &TokenKind) -> String {
509 match kind {
510 TokenKind::Eof => "end of file".into(),
511 TokenKind::Keyword(k) => format!("`{}`", k.as_str()),
512 TokenKind::Builtin(b) => format!("built-in `{}`", b.as_str()),
513 TokenKind::Ident(s) => format!("identifier `{s}`"),
514 TokenKind::String(s) => format!("string {s:?}"),
515 TokenKind::RawString(s) => format!("raw string {s:?}"),
516 TokenKind::Integer(n) => format!("integer `{n}`"),
517 TokenKind::LBrace => "`{`".into(),
518 TokenKind::RBrace => "`}`".into(),
519 TokenKind::LParen => "`(`".into(),
520 TokenKind::RParen => "`)`".into(),
521 TokenKind::LBracket => "`[`".into(),
522 TokenKind::RBracket => "`]`".into(),
523 TokenKind::Pipe => "`|`".into(),
524 TokenKind::Comma => "`,`".into(),
525 TokenKind::Semi => "`;`".into(),
526 TokenKind::Colon => "`:`".into(),
527 TokenKind::Eq => "`=`".into(),
528 TokenKind::DotDot => "`..`".into(),
529 TokenKind::Arrow => "`->`".into(),
530 }
531}
532
533#[cfg(test)]
534mod tests {
535 use super::*;
536 use crate::ast::{GrammarItem, TokenBody};
537 use crate::token::BuiltinType;
538
539 #[test]
540 fn parses_calculator_example() {
541 let src = include_str!("../testdata/calculator.gr");
542 let g = parse(src).expect("parse calculator.gr");
543 assert_eq!(g.name, "Calculator");
544
545 let rules: Vec<_> = g
546 .items
547 .iter()
548 .filter_map(|i| match i {
549 GrammarItem::Rule(r) => Some(r.name.as_str()),
550 _ => None,
551 })
552 .collect();
553 assert_eq!(rules, ["prog", "expr", "term", "factor"]);
554
555 let tokens: Vec<_> = g
556 .items
557 .iter()
558 .filter_map(|i| match i {
559 GrammarItem::Token(t) => Some((t.name.as_str(), t.skip, &t.body)),
560 _ => None,
561 })
562 .collect();
563 assert!(matches!(
564 tokens[0],
565 ("Num", false, TokenBody::Builtin(BuiltinType::Number))
566 ));
567 assert!(tokens.iter().any(|(n, skip, _)| *n == "Ws" && *skip));
568
569 let examples = g
570 .items
571 .iter()
572 .filter(|i| matches!(i, GrammarItem::Example(_)))
573 .count();
574 assert_eq!(examples, 2);
575 }
576
577 #[test]
578 fn parses_match_repeat_optional() {
579 let src = r#"
580 grammar Mini;
581 token N = Number;
582 rule items {
583 optional { item }
584 repeat(0..) { "," item }
585 }
586 rule item {
587 match N | "x" | ("(" N ")")
588 }
589 "#;
590 let g = parse(src).expect("parse");
591 let rule = g
592 .items
593 .iter()
594 .find_map(|i| match i {
595 GrammarItem::Rule(r) if r.name == "items" => Some(r),
596 _ => None,
597 })
598 .unwrap();
599
600 match &rule.body {
601 Expr::Seq { items } => {
602 assert!(matches!(items[0], Expr::Optional { .. }));
603 assert!(matches!(
604 items[1],
605 Expr::Repeat {
606 min: Some(0),
607 max: None,
608 ..
609 }
610 ));
611 }
612 other => panic!("expected Seq, got {other:?}"),
613 }
614 }
615
616 #[test]
617 fn parse_error_includes_snippet() {
618 let src = "grammar X;\nrule bad {\n";
619 let err = parse(src).unwrap_err();
620 assert_eq!(err.kind, crate::error::ErrorKind::Parse);
621 assert!(err.snippet.contains("|"));
622 assert!(err.snippet.contains("^"));
623 assert!(err.line >= 2);
624 }
625}