Skip to main content

oak_gsgl/parser/
mod.rs

1/// Element type definitions.
2pub mod element_type;
3
4use crate::language::GsglLanguage;
5use oak_core::{
6    parser::{ParseCache, ParseOutput, Parser, ParserState, parse_with_lexer},
7    source::{Source, TextEdit},
8};
9
10pub(crate) type State<'a, S> = ParserState<'a, GsglLanguage, S>;
11
12/// Parser for the GSGL language.
13pub struct GsglParser {
14    /// The language configuration.
15    pub(crate) config: GsglLanguage,
16}
17
18impl GsglParser {
19    /// Creates a new `GsglParser`.
20    pub fn new(config: GsglLanguage) -> Self {
21        Self { config }
22    }
23}
24
25impl Parser<GsglLanguage> for GsglParser {
26    fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<GsglLanguage>) -> ParseOutput<'a, GsglLanguage> {
27        let lexer = crate::lexer::GsglLexer::new(&self.config);
28        parse_with_lexer(&lexer, text, edits, cache, |state| {
29            let checkpoint = state.checkpoint();
30
31            while state.not_at_end() {
32                self.skip_trivia(state);
33                if state.at(crate::lexer::token_type::GsglTokenType::Struct) {
34                    self.parse_struct(state);
35                }
36                else if self.is_at_type(state) {
37                    self.parse_declaration_or_function(state);
38                }
39                else {
40                    state.advance();
41                }
42                self.skip_trivia(state);
43            }
44
45            Ok(state.finish_at(checkpoint, crate::parser::element_type::GsglElementType::Root))
46        })
47    }
48}
49
50impl GsglParser {
51    fn skip_trivia<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
52        while state.at(crate::lexer::token_type::GsglTokenType::Whitespace) || state.at(crate::lexer::token_type::GsglTokenType::Newline) || state.at(crate::lexer::token_type::GsglTokenType::Comment) {
53            state.bump();
54        }
55    }
56
57    fn is_at_type<'a, S: Source + ?Sized>(&self, state: &State<'a, S>) -> bool {
58        match state.current().map(|t| t.kind) {
59            Some(k) => {
60                let val = k as u8;
61                // Basic types are from Float (84) to Void (107)
62                (val >= 84 && val <= 107) || k == crate::lexer::token_type::GsglTokenType::Identifier
63            }
64            None => false,
65        }
66    }
67
68    fn parse_struct<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
69        let cp = state.checkpoint();
70        state.expect(crate::lexer::token_type::GsglTokenType::Struct).ok();
71        self.skip_trivia(state);
72
73        if state.at(crate::lexer::token_type::GsglTokenType::Identifier) {
74            state.bump();
75        }
76        self.skip_trivia(state);
77
78        if state.at(crate::lexer::token_type::GsglTokenType::LeftBrace) {
79            state.bump();
80            while state.not_at_end() && !state.at(crate::lexer::token_type::GsglTokenType::RightBrace) {
81                if self.is_at_type(state) {
82                    self.parse_variable_declaration(state);
83                }
84                else {
85                    state.advance();
86                }
87                self.skip_trivia(state);
88            }
89            if state.at(crate::lexer::token_type::GsglTokenType::RightBrace) {
90                state.bump();
91            }
92        }
93
94        if state.at(crate::lexer::token_type::GsglTokenType::Semicolon) {
95            state.bump();
96        }
97
98        state.finish_at(cp, crate::parser::element_type::GsglElementType::StructDecl);
99    }
100
101    fn parse_declaration_or_function<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
102        let cp = state.checkpoint();
103
104        // type
105        state.bump();
106        self.skip_trivia(state);
107
108        // name
109        if state.at(crate::lexer::token_type::GsglTokenType::Identifier) {
110            state.bump();
111        }
112        self.skip_trivia(state);
113
114        if state.at(crate::lexer::token_type::GsglTokenType::LeftParen) {
115            // function
116            self.parse_parameter_list(state);
117            self.skip_trivia(state);
118
119            if state.at(crate::lexer::token_type::GsglTokenType::LeftBrace) {
120                self.parse_block(state);
121            }
122            else if state.at(crate::lexer::token_type::GsglTokenType::Semicolon) {
123                state.bump();
124            }
125            state.finish_at(cp, crate::parser::element_type::GsglElementType::FunctionDecl);
126        }
127        else {
128            // variable
129            while state.not_at_end() && !state.at(crate::lexer::token_type::GsglTokenType::Semicolon) {
130                state.bump();
131            }
132            if state.at(crate::lexer::token_type::GsglTokenType::Semicolon) {
133                state.bump();
134            }
135            state.finish_at(cp, crate::parser::element_type::GsglElementType::VariableDecl);
136        }
137    }
138
139    fn parse_variable_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
140        let cp = state.checkpoint();
141        state.bump(); // type
142        self.skip_trivia(state);
143        if state.at(crate::lexer::token_type::GsglTokenType::Identifier) {
144            state.bump();
145        }
146        self.skip_trivia(state);
147        if state.at(crate::lexer::token_type::GsglTokenType::Semicolon) {
148            state.bump();
149        }
150        state.finish_at(cp, crate::parser::element_type::GsglElementType::VariableDecl);
151    }
152
153    fn parse_parameter_list<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
154        state.expect(crate::lexer::token_type::GsglTokenType::LeftParen).ok();
155        self.skip_trivia(state);
156
157        while state.not_at_end() && !state.at(crate::lexer::token_type::GsglTokenType::RightParen) {
158            self.parse_parameter(state);
159            self.skip_trivia(state);
160            if state.at(crate::lexer::token_type::GsglTokenType::Comma) {
161                state.bump();
162                self.skip_trivia(state);
163            }
164        }
165
166        if state.at(crate::lexer::token_type::GsglTokenType::RightParen) {
167            state.bump();
168        }
169    }
170
171    fn parse_parameter<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
172        let cp = state.checkpoint();
173        if self.is_at_type(state) {
174            state.bump(); // type
175            self.skip_trivia(state);
176        }
177        if state.at(crate::lexer::token_type::GsglTokenType::Identifier) {
178            state.bump(); // name
179        }
180        state.finish_at(cp, crate::parser::element_type::GsglElementType::Parameter);
181    }
182
183    fn parse_block<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
184        let cp = state.checkpoint();
185        state.expect(crate::lexer::token_type::GsglTokenType::LeftBrace).ok();
186        self.skip_trivia(state);
187
188        while state.not_at_end() && !state.at(crate::lexer::token_type::GsglTokenType::RightBrace) {
189            self.parse_statement(state);
190            self.skip_trivia(state);
191        }
192
193        if state.at(crate::lexer::token_type::GsglTokenType::RightBrace) {
194            state.bump();
195        }
196        state.finish_at(cp, crate::parser::element_type::GsglElementType::Block);
197    }
198
199    fn parse_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
200        let cp = state.checkpoint();
201        if state.at(crate::lexer::token_type::GsglTokenType::LeftBrace) {
202            self.parse_block(state);
203        }
204        else {
205            while state.not_at_end() && !state.at(crate::lexer::token_type::GsglTokenType::Semicolon) && !state.at(crate::lexer::token_type::GsglTokenType::RightBrace) {
206                state.bump();
207            }
208            if state.at(crate::lexer::token_type::GsglTokenType::Semicolon) {
209                state.bump();
210            }
211        }
212        state.finish_at(cp, crate::parser::element_type::GsglElementType::Statement);
213    }
214}