1use crate::{kind::NginxSyntaxKind, language::NginxLanguage, lexer::NginxLexer};
2use oak_core::{
3 GreenNode, OakError,
4 parser::{ParseCache, ParseOutput, Parser, ParserState},
5 source::{Source, TextEdit},
6};
7
8pub struct NginxParser<'a> {
9 pub language: &'a NginxLanguage,
10}
11
12impl<'a> NginxParser<'a> {
13 pub fn new(language: &'a NginxLanguage) -> Self {
14 Self { language }
15 }
16
17 fn parse_directive<'b, S: Source + ?Sized>(&self, state: &mut ParserState<'b, NginxLanguage, S>) {
18 if state.at(NginxSyntaxKind::CommentToken) {
19 let checkpoint = state.checkpoint();
20 state.bump();
21 state.finish_at(checkpoint, NginxSyntaxKind::Comment.into());
22 return;
23 }
24
25 let is_block_directive = matches!(state.peek_kind(), Some(NginxSyntaxKind::HttpKeyword | NginxSyntaxKind::ServerKeyword | NginxSyntaxKind::LocationKeyword | NginxSyntaxKind::EventsKeyword | NginxSyntaxKind::UpstreamKeyword));
26
27 if is_block_directive {
28 self.parse_block(state);
29 }
30 else {
31 let checkpoint = state.checkpoint();
32 state.bump(); while state.not_at_end() && !state.at(NginxSyntaxKind::Semicolon) && !state.at(NginxSyntaxKind::LeftBrace) {
34 let p_checkpoint = state.checkpoint();
35 state.bump();
36 state.finish_at(p_checkpoint, NginxSyntaxKind::Parameter.into());
37 }
38 if state.at(NginxSyntaxKind::Semicolon) {
39 state.bump();
40 }
41 state.finish_at(checkpoint, NginxSyntaxKind::Directive.into());
42 }
43 }
44
45 fn parse_block<'b, S: Source + ?Sized>(&self, state: &mut ParserState<'b, NginxLanguage, S>) {
46 let checkpoint = state.checkpoint();
47 state.bump(); while state.not_at_end() && !state.at(NginxSyntaxKind::LeftBrace) {
51 let p_checkpoint = state.checkpoint();
52 state.bump();
53 state.finish_at(p_checkpoint, NginxSyntaxKind::Parameter.into());
54 }
55
56 if state.at(NginxSyntaxKind::LeftBrace) {
57 state.bump();
58 while state.not_at_end() && !state.at(NginxSyntaxKind::RightBrace) {
59 self.parse_directive(state);
60 }
61 if state.at(NginxSyntaxKind::RightBrace) {
62 state.bump();
63 }
64 }
65 state.finish_at(checkpoint, NginxSyntaxKind::Block.into());
66 }
67
68 fn parse_root_internal<'b, S: Source + ?Sized>(&self, state: &mut ParserState<'b, NginxLanguage, S>) -> Result<&'b GreenNode<'b, NginxLanguage>, OakError> {
69 let checkpoint = state.checkpoint();
70 while state.not_at_end() {
71 self.parse_directive(state);
72 }
73
74 Ok(state.finish_at(checkpoint, NginxSyntaxKind::Root.into()))
75 }
76}
77
78impl<'a> Parser<NginxLanguage> for NginxParser<'a> {
79 fn parse<'b, S: Source + ?Sized>(&self, text: &'b S, edits: &[TextEdit], cache: &'b mut impl ParseCache<NginxLanguage>) -> ParseOutput<'b, NginxLanguage> {
80 let lexer = NginxLexer::new(self.language);
81 oak_core::parser::parse_with_lexer(&lexer, text, edits, cache, |state| self.parse_root_internal(state))
82 }
83}