1use crate::{RegexLanguage, RegexSyntaxKind, lexer::RegexLexer};
2use oak_core::{
3 GreenNode, Source, TextEdit,
4 parser::{Associativity, ParseCache, ParseOutput, Parser, ParserState, Pratt, PrattParser, binary},
5};
6
7pub(crate) type State<'a, S> = ParserState<'a, RegexLanguage, S>;
8
9#[allow(missing_docs)]
10pub struct RegexParser<'config> {
11 pub(crate) config: &'config RegexLanguage,
13}
14
15impl<'config> RegexParser<'config> {
16 pub fn new(config: &'config RegexLanguage) -> Self {
17 Self { config }
18 }
19}
20
21impl<'config> Pratt<RegexLanguage> for RegexParser<'config> {
22 fn primary<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, RegexLanguage> {
23 use RegexSyntaxKind::*;
24 let cp = state.checkpoint();
25 match state.peek_kind() {
26 Some(Character) => {
27 state.bump();
28 state.finish_at(cp, RegexPattern.into())
29 }
30 Some(Dot) => {
31 state.bump();
32 state.finish_at(cp, RegexPattern.into())
33 }
34 Some(LParen) => {
35 state.bump();
36 PrattParser::parse(state, 0, self);
37 state.expect(RParen).ok();
38 state.finish_at(cp, RegexPattern.into())
39 }
40 Some(LBrack) => {
41 state.bump();
42 while state.not_at_end() && !state.at(RBrack) {
43 state.advance();
44 }
45 state.expect(RBrack).ok();
46 state.finish_at(cp, RegexPattern.into())
47 }
48 _ => {
49 state.bump();
50 state.finish_at(cp, Error.into())
51 }
52 }
53 }
54
55 fn prefix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, RegexLanguage> {
56 use RegexSyntaxKind::*;
57 match state.peek_kind() {
58 Some(Hat) | Some(Dollar) => {
59 let cp = state.checkpoint();
60 state.bump();
61 state.finish_at(cp, RegexPattern.into())
62 }
63 Some(Backslash) => {
64 let cp = state.checkpoint();
65 state.bump();
66 state.advance();
67 state.finish_at(cp, RegexPattern.into())
68 }
69 _ => self.primary(state),
70 }
71 }
72
73 fn infix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, left: &'a GreenNode<'a, RegexLanguage>, min_precedence: u8) -> Option<&'a GreenNode<'a, RegexLanguage>> {
74 use RegexSyntaxKind::*;
75 let kind = state.peek_kind()?;
76
77 let (prec, assoc) = match kind {
78 Pipe => (1, Associativity::Left),
79 Question | Star | Plus => (10, Associativity::Right),
80 _ => return None,
81 };
82
83 if prec < min_precedence {
84 return None;
85 }
86
87 match kind {
88 Pipe => Some(binary(state, left, Pipe, prec, assoc, RegexPattern.into(), |s, p| PrattParser::parse(s, p, self))),
89 Question | Star | Plus => {
90 let cp = state.checkpoint();
91 state.push_child(left);
92 state.bump();
93 Some(state.finish_at(cp, RegexPattern.into()))
94 }
95 _ => None,
96 }
97 }
98}
99
100impl<'config> Parser<RegexLanguage> for RegexParser<'config> {
101 fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<RegexLanguage>) -> ParseOutput<'a, RegexLanguage> {
102 let lexer = RegexLexer::new(&self.config);
103 oak_core::parser::parse_with_lexer(&lexer, text, edits, cache, |state| {
104 let checkpoint = state.checkpoint();
105 while state.not_at_end() {
106 PrattParser::parse(state, 0, self);
107 }
108 Ok(state.finish_at(checkpoint, RegexSyntaxKind::RegexPattern.into()))
109 })
110 }
111}