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