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