Skip to main content

oak_hlsl/parser/
mod.rs

1/// Element type definitions for the HLSL parser.
2pub mod element_type;
3pub use element_type::HlslElementType;
4
5use crate::{language::HlslLanguage, lexer::HlslLexer};
6use oak_core::{
7    parser::{ParseCache, ParseOutput, Parser, ParserState, parse_with_lexer},
8    source::{Source, TextEdit},
9};
10
11pub(crate) type State<'a, S> = ParserState<'a, HlslLanguage, S>;
12
13/// HLSL syntax parser.
14pub struct HlslParser<'config> {
15    pub(crate) config: &'config HlslLanguage,
16}
17
18impl<'config> HlslParser<'config> {
19    /// Creates a new HLSL parser with the given language configuration.
20    pub fn new(config: &'config HlslLanguage) -> Self {
21        Self { config }
22    }
23}
24
25impl<'config> Parser<HlslLanguage> for HlslParser<'config> {
26    fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<HlslLanguage>) -> ParseOutput<'a, HlslLanguage> {
27        let lexer = HlslLexer::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::HlslTokenType::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, HlslElementType::Root))
46        })
47    }
48}
49
50impl<'config> HlslParser<'config> {
51    fn skip_trivia<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
52        while state.at(crate::lexer::token_type::HlslTokenType::Whitespace) || state.at(crate::lexer::token_type::HlslTokenType::Newline) || state.at(crate::lexer::token_type::HlslTokenType::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.peek_kind() {
59            Some(k) => {
60                let val = k as u8;
61                // Basic types are from Bool (42) to Double4x4 (92)
62                (val >= 42 && val <= 92) || k == crate::lexer::token_type::HlslTokenType::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::HlslTokenType::Struct).ok();
71        self.skip_trivia(state);
72
73        if state.at(crate::lexer::token_type::HlslTokenType::Identifier) {
74            state.bump();
75        }
76        self.skip_trivia(state);
77
78        if state.at(crate::lexer::token_type::HlslTokenType::LeftBrace) {
79            state.bump();
80            while state.not_at_end() && !state.at(crate::lexer::token_type::HlslTokenType::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::HlslTokenType::RightBrace) {
90                state.bump();
91            }
92        }
93
94        if state.at(crate::lexer::token_type::HlslTokenType::Semicolon) {
95            state.bump();
96        }
97
98        state.finish_at(cp, HlslElementType::StructDeclaration);
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::HlslTokenType::Identifier) {
110            state.bump();
111        }
112        self.skip_trivia(state);
113
114        if state.at(crate::lexer::token_type::HlslTokenType::LeftParen) {
115            // function
116            self.parse_parameter_list(state);
117            self.skip_trivia(state);
118
119            // semantic
120            if state.at(crate::lexer::token_type::HlslTokenType::Colon) {
121                state.bump();
122                self.skip_trivia(state);
123                if state.at(crate::lexer::token_type::HlslTokenType::Identifier) {
124                    state.bump();
125                }
126            }
127            self.skip_trivia(state);
128
129            if state.at(crate::lexer::token_type::HlslTokenType::LeftBrace) {
130                self.parse_block(state);
131            }
132            else if state.at(crate::lexer::token_type::HlslTokenType::Semicolon) {
133                state.bump();
134            }
135            state.finish_at(cp, HlslElementType::FunctionDeclaration);
136        }
137        else {
138            // variable
139            while state.not_at_end() && !state.at(crate::lexer::token_type::HlslTokenType::Semicolon) {
140                state.bump();
141            }
142            if state.at(crate::lexer::token_type::HlslTokenType::Semicolon) {
143                state.bump();
144            }
145            state.finish_at(cp, HlslElementType::VariableDeclaration);
146        }
147    }
148
149    fn parse_variable_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
150        let cp = state.checkpoint();
151        state.bump(); // type
152        self.skip_trivia(state);
153        if state.at(crate::lexer::token_type::HlslTokenType::Identifier) {
154            state.bump();
155        }
156        self.skip_trivia(state);
157        if state.at(crate::lexer::token_type::HlslTokenType::Semicolon) {
158            state.bump();
159        }
160        state.finish_at(cp, HlslElementType::VariableDeclaration);
161    }
162
163    fn parse_parameter_list<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
164        let cp = state.checkpoint();
165        state.expect(crate::lexer::token_type::HlslTokenType::LeftParen).ok();
166        self.skip_trivia(state);
167
168        while state.not_at_end() && !state.at(crate::lexer::token_type::HlslTokenType::RightParen) {
169            self.parse_parameter(state);
170            self.skip_trivia(state);
171            if state.at(crate::lexer::token_type::HlslTokenType::Comma) {
172                state.bump();
173                self.skip_trivia(state);
174            }
175        }
176
177        if state.at(crate::lexer::token_type::HlslTokenType::RightParen) {
178            state.bump();
179        }
180        state.finish_at(cp, HlslElementType::ParameterList);
181    }
182
183    fn parse_parameter<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
184        let cp = state.checkpoint();
185        if self.is_at_type(state) {
186            state.bump(); // type
187            self.skip_trivia(state);
188        }
189        if state.at(crate::lexer::token_type::HlslTokenType::Identifier) {
190            state.bump(); // name
191        }
192        state.finish_at(cp, HlslElementType::Parameter);
193    }
194
195    fn parse_block<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
196        let cp = state.checkpoint();
197        state.expect(crate::lexer::token_type::HlslTokenType::LeftBrace).ok();
198        self.skip_trivia(state);
199
200        while state.not_at_end() && !state.at(crate::lexer::token_type::HlslTokenType::RightBrace) {
201            self.parse_statement(state);
202            self.skip_trivia(state);
203        }
204
205        if state.at(crate::lexer::token_type::HlslTokenType::RightBrace) {
206            state.bump();
207        }
208        state.finish_at(cp, HlslElementType::Block);
209    }
210
211    fn parse_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
212        let cp = state.checkpoint();
213        if state.at(crate::lexer::token_type::HlslTokenType::LeftBrace) {
214            self.parse_block(state);
215        }
216        else {
217            while state.not_at_end() && !state.at(crate::lexer::token_type::HlslTokenType::Semicolon) && !state.at(crate::lexer::token_type::HlslTokenType::RightBrace) {
218                state.bump();
219            }
220            if state.at(crate::lexer::token_type::HlslTokenType::Semicolon) {
221                state.bump();
222            }
223        }
224        state.finish_at(cp, HlslElementType::Statement);
225    }
226}