Skip to main content

oak_msil/parser/
mod.rs

1/// MSIL element type definition.
2pub mod element_type;
3
4use crate::{
5    language::MsilLanguage,
6    lexer::{MsilLexer, token_type::MsilTokenType},
7};
8use oak_core::{
9    TextEdit,
10    parser::{ParseCache, Parser, ParserState, parse_with_lexer},
11    source::Source,
12};
13
14pub(crate) type State<'a, S> = ParserState<'a, MsilLanguage, S>;
15
16/// MSIL language parser.
17pub struct MsilParser<'config> {
18    pub(crate) config: &'config MsilLanguage,
19}
20
21impl<'config> MsilParser<'config> {
22    /// Creates a new MSIL parser.
23    pub fn new(config: &'config MsilLanguage) -> Self {
24        Self { config }
25    }
26
27    fn skip_trivia<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
28        while let Some(kind) = state.peek_kind() {
29            if kind == MsilTokenType::Whitespace || kind == MsilTokenType::CommentToken {
30                state.bump();
31            }
32            else {
33                break;
34            }
35        }
36    }
37
38    fn parse_assembly<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
39        let cp = state.checkpoint();
40        state.bump(); // .assembly
41        self.skip_trivia(state);
42
43        let is_extern = if state.at(MsilTokenType::ExternKeyword) {
44            state.bump(); // extern
45            self.skip_trivia(state);
46            true
47        }
48        else {
49            false
50        };
51
52        if state.at(MsilTokenType::IdentifierToken) {
53            let id_cp = state.checkpoint();
54            state.bump();
55            state.finish_at(id_cp, crate::parser::element_type::MsilElementType::Identifier);
56            self.skip_trivia(state);
57        }
58
59        if state.at(MsilTokenType::LeftBrace) {
60            state.bump();
61            while state.not_at_end() && !state.at(MsilTokenType::RightBrace) {
62                state.bump();
63            }
64            if state.at(MsilTokenType::RightBrace) {
65                state.bump();
66            }
67        }
68
69        if is_extern {
70            state.finish_at(cp, crate::parser::element_type::MsilElementType::AssemblyExtern);
71        }
72        else {
73            state.finish_at(cp, crate::parser::element_type::MsilElementType::Assembly);
74        }
75    }
76
77    fn parse_module<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
78        let cp = state.checkpoint();
79        state.bump(); // .module
80        self.skip_trivia(state);
81        while state.not_at_end() && !state.at(MsilTokenType::Semicolon) && !state.at(MsilTokenType::Eof) {
82            if state.at(MsilTokenType::IdentifierToken) {
83                let id_cp = state.checkpoint();
84                state.bump();
85                state.finish_at(id_cp, crate::parser::element_type::MsilElementType::Identifier);
86                self.skip_trivia(state);
87            }
88            else {
89                state.bump();
90            }
91        }
92        state.finish_at(cp, crate::parser::element_type::MsilElementType::Module);
93    }
94
95    fn parse_class<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
96        let cp = state.checkpoint();
97        state.bump(); // .class
98        self.skip_trivia(state);
99
100        // Skip modifiers
101        while state.at(MsilTokenType::PublicKeyword) || state.at(MsilTokenType::PrivateKeyword) || state.at(MsilTokenType::StaticKeyword) || state.at(MsilTokenType::Keyword) {
102            state.bump();
103            self.skip_trivia(state);
104        }
105
106        if state.at(MsilTokenType::IdentifierToken) {
107            let id_cp = state.checkpoint();
108            state.bump();
109            state.finish_at(id_cp, crate::parser::element_type::MsilElementType::Identifier);
110            self.skip_trivia(state);
111        }
112
113        // Handle extends
114        if (state.at(MsilTokenType::IdentifierToken) || state.at(MsilTokenType::Keyword)) && state.peek_text().as_deref() == Some("extends") {
115            state.bump();
116            self.skip_trivia(state);
117            while state.not_at_end() && !state.at(MsilTokenType::LeftBrace) {
118                state.bump();
119            }
120        }
121
122        if state.at(MsilTokenType::LeftBrace) {
123            state.bump();
124            while state.not_at_end() && !state.at(MsilTokenType::RightBrace) {
125                self.skip_trivia(state);
126                if !state.not_at_end() || state.at(MsilTokenType::RightBrace) {
127                    break;
128                }
129
130                if state.at(MsilTokenType::MethodKeyword) {
131                    self.parse_method(state);
132                }
133                else {
134                    state.bump();
135                }
136            }
137            if state.at(MsilTokenType::RightBrace) {
138                state.bump();
139            }
140        }
141
142        state.finish_at(cp, crate::parser::element_type::MsilElementType::Class);
143    }
144
145    fn parse_method<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
146        let cp = state.checkpoint();
147        state.bump(); // .method
148        self.skip_trivia(state);
149
150        // Parse method modifiers
151        while state.not_at_end() && !state.at(MsilTokenType::LeftBrace) {
152            if state.at(MsilTokenType::PublicKeyword) || state.at(MsilTokenType::PrivateKeyword) || state.at(MsilTokenType::StaticKeyword) || state.at(MsilTokenType::Keyword) {
153                state.bump();
154                self.skip_trivia(state);
155            }
156            else if state.at(MsilTokenType::IdentifierToken) {
157                let id_cp = state.checkpoint();
158                state.bump();
159                state.finish_at(id_cp, crate::parser::element_type::MsilElementType::Identifier);
160                self.skip_trivia(state);
161            }
162            else if state.at(MsilTokenType::LeftParen) {
163                // Parse method parameters
164                state.bump();
165                self.skip_trivia(state);
166                while state.not_at_end() && !state.at(MsilTokenType::RightParen) {
167                    if state.at(MsilTokenType::IdentifierToken) {
168                        let id_cp = state.checkpoint();
169                        state.bump();
170                        state.finish_at(id_cp, crate::parser::element_type::MsilElementType::Identifier);
171                        self.skip_trivia(state);
172                    }
173                    else if state.at(MsilTokenType::Comma) {
174                        state.bump();
175                        self.skip_trivia(state);
176                    }
177                    else {
178                        state.bump();
179                    }
180                }
181                if state.at(MsilTokenType::RightParen) {
182                    state.bump();
183                    self.skip_trivia(state);
184                }
185            }
186            else {
187                state.bump();
188            }
189        }
190
191        if state.at(MsilTokenType::LeftBrace) {
192            state.bump();
193            while state.not_at_end() && !state.at(MsilTokenType::RightBrace) {
194                self.skip_trivia(state);
195                if !state.not_at_end() || state.at(MsilTokenType::RightBrace) {
196                    break;
197                }
198
199                // Parse method body elements
200                if state.at(MsilTokenType::IdentifierToken) {
201                    let peeked = state.peek_text();
202                    let text = peeked.as_deref().unwrap_or("");
203                    if text.starts_with(".") {
204                        // Parse directives like .maxstack, .locals, etc.
205                        let dir_cp = state.checkpoint();
206                        state.bump();
207                        self.skip_trivia(state);
208                        while state.not_at_end() && !state.at(MsilTokenType::Semicolon) && !state.at(MsilTokenType::LeftBrace) && !state.at(MsilTokenType::RightBrace) {
209                            state.bump();
210                        }
211                        if state.at(MsilTokenType::Semicolon) {
212                            state.bump();
213                        }
214                        state.finish_at(dir_cp, crate::parser::element_type::MsilElementType::Directive);
215                    }
216                    else if text.starts_with("IL_") {
217                        // Parse instruction labels
218                        let label_cp = state.checkpoint();
219                        state.bump();
220                        if state.at(MsilTokenType::Colon) {
221                            state.bump();
222                        }
223                        state.finish_at(label_cp, crate::parser::element_type::MsilElementType::Label);
224                    }
225                    else {
226                        // Parse instructions
227                        let inst_cp = state.checkpoint();
228                        state.bump();
229                        self.skip_trivia(state);
230                        // Parse instruction operands
231                        while state.not_at_end() && !state.at(MsilTokenType::Semicolon) && !state.at(MsilTokenType::RightBrace) {
232                            if state.at(MsilTokenType::IdentifierToken) || state.at(MsilTokenType::NumberToken) || state.at(MsilTokenType::StringToken) || state.at(MsilTokenType::LeftBracket) {
233                                state.bump();
234                            }
235                            else {
236                                break;
237                            }
238                            self.skip_trivia(state);
239                        }
240                        state.finish_at(inst_cp, crate::parser::element_type::MsilElementType::Instruction);
241                    }
242                }
243                else {
244                    state.bump();
245                }
246            }
247            if state.at(MsilTokenType::RightBrace) {
248                state.bump();
249            }
250        }
251
252        state.finish_at(cp, crate::parser::element_type::MsilElementType::Method);
253    }
254}
255
256impl<'config> Parser<MsilLanguage> for MsilParser<'config> {
257    fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<MsilLanguage>) -> oak_core::ParseOutput<'a, MsilLanguage> {
258        let lexer = MsilLexer::new(self.config);
259        parse_with_lexer(&lexer, text, edits, cache, |state| {
260            let cp = state.checkpoint();
261            while state.not_at_end() {
262                self.skip_trivia(state);
263                if !state.not_at_end() {
264                    break;
265                }
266
267                if state.at(MsilTokenType::AssemblyKeyword) {
268                    self.parse_assembly(state);
269                }
270                else if state.at(MsilTokenType::ModuleKeyword) {
271                    self.parse_module(state);
272                }
273                else if state.at(MsilTokenType::ClassKeyword) {
274                    self.parse_class(state);
275                }
276                else {
277                    state.bump();
278                }
279            }
280            Ok(state.finish_at(cp, crate::parser::element_type::MsilElementType::Root))
281        })
282    }
283}