Skip to main content

oak_wat/parser/
mod.rs

1/// Element type definitions.
2pub mod element_type;
3
4use crate::{
5    language::WatLanguage,
6    lexer::{WatLexer, token_type::WatTokenType},
7    parser::element_type::WatElementType,
8};
9use oak_core::{
10    TextEdit,
11    parser::{ParseCache, ParseOutput, Parser, ParserState, parse_with_lexer},
12    source::Source,
13};
14
15pub(crate) type State<'a, S> = ParserState<'a, WatLanguage, S>;
16
17/// Parser for the WebAssembly Text (WAT) language.
18pub struct WatParser<'config> {
19    pub(crate) config: &'config WatLanguage,
20}
21
22impl<'config> WatParser<'config> {
23    /// Creates a new instance of the WAT parser.
24    pub fn new(config: &'config WatLanguage) -> Self {
25        Self { config }
26    }
27
28    /// Parses a WAT item starting with a left parenthesis.
29    fn parse_item<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
30        let cp = state.checkpoint();
31        state.expect(WatTokenType::LeftParen).ok();
32
33        if state.at(WatTokenType::ModuleKw) {
34            state.bump();
35            while state.not_at_end() && !state.at(WatTokenType::RightParen) {
36                if state.at(WatTokenType::LeftParen) {
37                    self.parse_item(state);
38                }
39                else {
40                    state.bump();
41                }
42            }
43            state.expect(WatTokenType::RightParen).ok();
44            state.finish_at(cp, WatElementType::Module);
45        }
46        else if state.at(WatTokenType::FuncKw) {
47            state.bump();
48            while state.not_at_end() && !state.at(WatTokenType::RightParen) {
49                if state.at(WatTokenType::LeftParen) {
50                    self.parse_item(state);
51                }
52                else {
53                    state.bump();
54                }
55            }
56            state.expect(WatTokenType::RightParen).ok();
57            state.finish_at(cp, WatElementType::Func);
58        }
59        else if state.at(WatTokenType::ParamKw) {
60            state.bump();
61            while state.not_at_end() && !state.at(WatTokenType::RightParen) {
62                state.bump();
63            }
64            state.expect(WatTokenType::RightParen).ok();
65            state.finish_at(cp, WatElementType::Param);
66        }
67        else if state.at(WatTokenType::ResultKw) {
68            state.bump();
69            while state.not_at_end() && !state.at(WatTokenType::RightParen) {
70                state.bump();
71            }
72            state.expect(WatTokenType::RightParen).ok();
73            state.finish_at(cp, WatElementType::Result);
74        }
75        else if state.at(WatTokenType::LocalKw) {
76            state.bump();
77            while state.not_at_end() && !state.at(WatTokenType::RightParen) {
78                state.bump();
79            }
80            state.expect(WatTokenType::RightParen).ok();
81            state.finish_at(cp, WatElementType::Local);
82        }
83        else if state.at(WatTokenType::ExportKw) {
84            state.bump();
85            while state.not_at_end() && !state.at(WatTokenType::RightParen) {
86                state.bump();
87            }
88            state.expect(WatTokenType::RightParen).ok();
89            state.finish_at(cp, WatElementType::Export);
90        }
91        else if state.at(WatTokenType::ImportKw) {
92            state.bump();
93            while state.not_at_end() && !state.at(WatTokenType::RightParen) {
94                state.bump();
95            }
96            state.expect(WatTokenType::RightParen).ok();
97            state.finish_at(cp, WatElementType::Import);
98        }
99        else if state.at(WatTokenType::TypeKw) {
100            state.bump();
101            while state.not_at_end() && !state.at(WatTokenType::RightParen) {
102                state.bump();
103            }
104            state.expect(WatTokenType::RightParen).ok();
105            state.finish_at(cp, WatElementType::Type);
106        }
107        else if state.at(WatTokenType::TableKw) {
108            state.bump();
109            while state.not_at_end() && !state.at(WatTokenType::RightParen) {
110                if state.at(WatTokenType::LeftParen) {
111                    self.parse_item(state);
112                }
113                else {
114                    state.bump();
115                }
116            }
117            state.expect(WatTokenType::RightParen).ok();
118            state.finish_at(cp, WatElementType::Table);
119        }
120        else if state.at(WatTokenType::MemoryKw) {
121            state.bump();
122            while state.not_at_end() && !state.at(WatTokenType::RightParen) {
123                if state.at(WatTokenType::LeftParen) {
124                    self.parse_item(state);
125                }
126                else {
127                    state.bump();
128                }
129            }
130            state.expect(WatTokenType::RightParen).ok();
131            state.finish_at(cp, WatElementType::Memory);
132        }
133        else if state.at(WatTokenType::GlobalKw) {
134            state.bump();
135            while state.not_at_end() && !state.at(WatTokenType::RightParen) {
136                state.bump();
137            }
138            state.expect(WatTokenType::RightParen).ok();
139            state.finish_at(cp, WatElementType::Global);
140        }
141        else {
142            // Check if it's an instruction with result (e.g. (i32.add (local.get 0) (local.get 1)))
143            let is_instr = state.peek_kind().map_or(false, |k| {
144                let kind_val = k as u8;
145                kind_val >= WatTokenType::LocalGetKw as u8 && kind_val <= WatTokenType::I64RemUKw as u8
146            });
147
148            state.bump();
149            while state.not_at_end() && !state.at(WatTokenType::RightParen) {
150                if state.at(WatTokenType::LeftParen) {
151                    self.parse_item(state);
152                }
153                else {
154                    state.bump();
155                }
156            }
157            state.expect(WatTokenType::RightParen).ok();
158
159            if is_instr {
160                state.finish_at(cp, WatElementType::Instruction);
161            }
162            else {
163                state.finish_at(cp, WatElementType::Item);
164            }
165        }
166    }
167}
168
169impl<'config> Parser<WatLanguage> for WatParser<'config> {
170    fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<WatLanguage>) -> ParseOutput<'a, WatLanguage> {
171        let lexer = WatLexer::new(&self.config);
172        parse_with_lexer(&lexer, text, edits, cache, |state| {
173            let cp = state.checkpoint();
174
175            while state.not_at_end() {
176                if state.at(WatTokenType::LeftParen) {
177                    self.parse_item(state);
178                }
179                else {
180                    state.bump();
181                }
182            }
183            Ok(state.finish_at(cp, WatElementType::Root))
184        })
185    }
186}