1pub mod element_type;
3
4use crate::{
5 language::NixLanguage,
6 lexer::{NixLexer, token_type::NixTokenType},
7};
8use oak_core::{
9 parser::{ParseCache, ParseOutput, Parser, ParserState, parse_with_lexer},
10 source::{Source, TextEdit},
11};
12
13pub(crate) type State<'a, S> = ParserState<'a, NixLanguage, S>;
14
15pub struct NixParser<'a> {
17 pub language: &'a NixLanguage,
19}
20
21impl<'a> NixParser<'a> {
22 pub fn new(language: &'a NixLanguage) -> Self {
24 Self { language }
25 }
26
27 fn parse_expr<'b, S: Source + ?Sized>(&self, state: &mut State<'b, S>) {
28 match state.peek_kind() {
29 Some(NixTokenType::LeftBrace) => self.parse_set(state),
30 Some(NixTokenType::LeftBracket) => self.parse_list(state),
31 Some(NixTokenType::Let) => self.parse_let_in(state),
32 Some(NixTokenType::If) => self.parse_if_then_else(state),
33 Some(NixTokenType::Identifier) => {
34 state.bump();
35 if state.at(NixTokenType::Colon) {
36 state.bump();
38 self.parse_expr(state)
39 }
40 }
41 _ => state.bump(),
42 }
43 }
44
45 fn parse_set<'b, S: Source + ?Sized>(&self, state: &mut State<'b, S>) {
46 let cp = state.checkpoint();
47 state.expect(NixTokenType::LeftBrace).ok();
48 while state.not_at_end() && !state.at(NixTokenType::RightBrace) {
49 self.parse_binding(state)
50 }
51 state.expect(NixTokenType::RightBrace).ok();
52 state.finish_at(cp, crate::parser::element_type::NixElementType::Set);
53 }
54
55 fn parse_list<'b, S: Source + ?Sized>(&self, state: &mut State<'b, S>) {
56 let cp = state.checkpoint();
57 state.expect(NixTokenType::LeftBracket).ok();
58 while state.not_at_end() && !state.at(NixTokenType::RightBracket) {
59 self.parse_expr(state)
60 }
61 state.expect(NixTokenType::RightBracket).ok();
62 state.finish_at(cp, crate::parser::element_type::NixElementType::List);
63 }
64
65 fn parse_let_in<'b, S: Source + ?Sized>(&self, state: &mut State<'b, S>) {
66 let cp = state.checkpoint();
67 state.expect(NixTokenType::Let).ok();
68 while state.not_at_end() && !state.at(NixTokenType::In) {
69 self.parse_binding(state)
70 }
71 if state.at(NixTokenType::In) {
72 state.bump();
73 self.parse_expr(state)
74 }
75 state.finish_at(cp, crate::parser::element_type::NixElementType::LetIn);
76 }
77
78 fn parse_if_then_else<'b, S: Source + ?Sized>(&self, state: &mut State<'b, S>) {
79 let cp = state.checkpoint();
80 state.expect(NixTokenType::If).ok();
81 self.parse_expr(state);
82 if state.at(NixTokenType::Then) {
83 state.bump();
84 self.parse_expr(state)
85 }
86 if state.at(NixTokenType::Else) {
87 state.bump();
88 self.parse_expr(state)
89 }
90 state.finish_at(cp, crate::parser::element_type::NixElementType::IfThenElse);
91 }
92
93 fn parse_binding<'b, S: Source + ?Sized>(&self, state: &mut State<'b, S>) {
94 let cp = state.checkpoint();
95 state.expect(NixTokenType::Identifier).ok();
96 if state.at(NixTokenType::Assign) {
97 state.bump();
98 self.parse_expr(state);
99 state.expect(NixTokenType::Semicolon).ok();
100 }
101 state.finish_at(cp, crate::parser::element_type::NixElementType::Binding);
102 }
103}
104
105impl<'config> Parser<NixLanguage> for NixParser<'config> {
106 fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<NixLanguage>) -> ParseOutput<'a, NixLanguage> {
107 let lexer = NixLexer::new(self.language);
108 parse_with_lexer(&lexer, text, edits, cache, |state| {
109 let cp = state.checkpoint();
110
111 while state.not_at_end() {
112 self.parse_expr(state);
113 }
114
115 Ok(state.finish_at(cp, crate::parser::element_type::NixElementType::Root))
116 })
117 }
118}