1pub mod element_type;
3
4use crate::{
5 language::NginxLanguage,
6 lexer::{NginxLexer, token_type::NginxTokenType},
7};
8use oak_core::{
9 GreenNode, OakError,
10 parser::{ParseCache, ParseOutput, Parser, ParserState},
11 source::{Source, TextEdit},
12};
13
14pub struct NginxParser<'a> {
16 pub language: &'a NginxLanguage,
18}
19
20impl<'a> NginxParser<'a> {
21 pub fn new(language: &'a NginxLanguage) -> Self {
23 Self { language }
24 }
25
26 fn parse_directive<'b, S: Source + ?Sized>(&self, state: &mut ParserState<'b, NginxLanguage, S>) {
27 if state.at(NginxTokenType::CommentToken) {
28 let checkpoint = state.checkpoint();
29 state.bump();
30 state.finish_at(checkpoint, crate::parser::element_type::NginxElementType::Comment);
31 return;
32 }
33
34 let is_block_directive = matches!(state.peek_kind(), Some(NginxTokenType::HttpKeyword | NginxTokenType::ServerKeyword | NginxTokenType::LocationKeyword | NginxTokenType::EventsKeyword | NginxTokenType::UpstreamKeyword));
35
36 if is_block_directive {
37 self.parse_block(state);
38 }
39 else {
40 let checkpoint = state.checkpoint();
41 state.bump(); while state.not_at_end() && !state.at(NginxTokenType::Semicolon) && !state.at(NginxTokenType::LeftBrace) {
43 let p_checkpoint = state.checkpoint();
44 state.bump();
45 state.finish_at(p_checkpoint, crate::parser::element_type::NginxElementType::Parameter);
46 }
47 if state.at(NginxTokenType::Semicolon) {
48 state.bump();
49 }
50 state.finish_at(checkpoint, crate::parser::element_type::NginxElementType::Directive);
51 }
52 }
53
54 fn parse_block<'b, S: Source + ?Sized>(&self, state: &mut ParserState<'b, NginxLanguage, S>) {
55 let checkpoint = state.checkpoint();
56 state.bump(); while state.not_at_end() && !state.at(NginxTokenType::LeftBrace) {
60 let p_checkpoint = state.checkpoint();
61 state.bump();
62 state.finish_at(p_checkpoint, crate::parser::element_type::NginxElementType::Parameter);
63 }
64
65 if state.at(NginxTokenType::LeftBrace) {
66 state.bump();
67 while state.not_at_end() && !state.at(NginxTokenType::RightBrace) {
68 self.parse_directive(state);
69 }
70 if state.at(NginxTokenType::RightBrace) {
71 state.bump();
72 }
73 }
74 state.finish_at(checkpoint, crate::parser::element_type::NginxElementType::Block);
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| {
82 let checkpoint = state.checkpoint();
83 while state.not_at_end() {
84 self.parse_directive(state);
85 }
86
87 Ok(state.finish_at(checkpoint, crate::parser::element_type::NginxElementType::Root))
88 })
89 }
90}