1pub mod element_type;
3
4use crate::{
5 language::ScssLanguage,
6 lexer::{ScssLexer, token_type::ScssTokenType},
7 parser::element_type::ScssElementType,
8};
9use oak_core::{
10 errors::OakError,
11 parser::{ParseCache, ParseOutput, Parser, ParserState, parse_with_lexer},
12 source::{Source, TextEdit},
13};
14
15pub(crate) type State<'a, S> = ParserState<'a, ScssLanguage, S>;
16
17pub struct ScssParser<'config> {
19 pub(crate) config: &'config ScssLanguage,
20}
21
22impl<'config> ScssParser<'config> {
23 pub fn new(config: &'config ScssLanguage) -> Self {
25 Self { config }
26 }
27
28 fn parse_node<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
29 match state.peek_kind() {
30 Some(ScssTokenType::Dollar) => self.parse_variable_declaration(state),
31 Some(ScssTokenType::At) => self.parse_at_rule(state),
32 Some(ScssTokenType::Identifier) | Some(ScssTokenType::Dot) | Some(ScssTokenType::Hash) | Some(ScssTokenType::Star) => self.parse_rule(state),
33 Some(ScssTokenType::Comment) => {
34 let cp = state.checkpoint();
35 state.bump();
36 state.finish_at(cp, ScssElementType::Comment);
37 Ok(())
38 }
39 _ => {
40 state.advance();
41 Ok(())
42 }
43 }
44 }
45
46 fn parse_at_rule<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
47 let cp = state.checkpoint();
48 state.expect(ScssTokenType::At)?;
49
50 if let Some(ScssTokenType::Identifier) = state.peek_kind() {
51 let name = state.peek_text().map(|s| s.into_owned());
52 state.bump();
53
54 match name.as_deref() {
55 Some("mixin") => self.parse_mixin(state, cp),
56 Some("include") => self.parse_include(state, cp),
57 Some("function") => self.parse_function(state, cp),
58 Some("return") => self.parse_return(state, cp),
59 Some("import") => self.parse_import(state, cp),
60 Some("if") => self.parse_if(state, cp),
61 Some("for") => self.parse_for(state, cp),
62 Some("each") => self.parse_each(state, cp),
63 Some("while") => self.parse_while(state, cp),
64 _ => {
65 while state.not_at_end() && !state.at(ScssTokenType::Semicolon) && !state.at(ScssTokenType::LeftBrace) {
67 state.advance();
68 }
69 if state.at(ScssTokenType::LeftBrace) {
70 self.parse_block(state)?;
71 }
72 else {
73 state.eat(ScssTokenType::Semicolon);
74 }
75 state.finish_at(cp, ScssElementType::RuleSet);
76 Ok(())
77 }
78 }
79 }
80 else {
81 state.finish_at(cp, ScssElementType::Error);
82 Ok(())
83 }
84 }
85
86 fn parse_mixin<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, cp: (usize, usize)) -> Result<(), OakError> {
87 state.expect(ScssTokenType::Identifier)?;
88 if state.at(ScssTokenType::LeftParen) {
89 self.parse_parameters(state)?;
90 }
91 self.parse_block(state)?;
92 state.finish_at(cp, ScssElementType::MixinDeclaration);
93 Ok(())
94 }
95
96 fn parse_include<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, cp: (usize, usize)) -> Result<(), OakError> {
97 state.expect(ScssTokenType::Identifier)?;
98 if state.at(ScssTokenType::LeftParen) {
99 self.parse_arguments(state)?;
100 }
101 if state.at(ScssTokenType::LeftBrace) {
102 self.parse_block(state)?;
103 }
104 else {
105 state.eat(ScssTokenType::Semicolon);
106 }
107 state.finish_at(cp, ScssElementType::IncludeStatement);
108 Ok(())
109 }
110
111 fn parse_function<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, cp: (usize, usize)) -> Result<(), OakError> {
112 state.expect(ScssTokenType::Identifier)?;
113 self.parse_parameters(state)?;
114 self.parse_block(state)?;
115 state.finish_at(cp, ScssElementType::FunctionDeclaration);
116 Ok(())
117 }
118
119 fn parse_import<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, cp: (usize, usize)) -> Result<(), OakError> {
120 while state.not_at_end() && !state.at(ScssTokenType::Semicolon) {
121 state.advance();
122 }
123 state.eat(ScssTokenType::Semicolon);
124 state.finish_at(cp, ScssElementType::ImportStatement);
125 Ok(())
126 }
127
128 fn parse_if<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, cp: (usize, usize)) -> Result<(), OakError> {
129 while state.not_at_end() && !state.at(ScssTokenType::LeftBrace) {
130 state.advance();
131 }
132 self.parse_block(state)?;
133 state.finish_at(cp, ScssElementType::IfStatement);
135 Ok(())
136 }
137
138 fn parse_for<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, cp: (usize, usize)) -> Result<(), OakError> {
139 while state.not_at_end() && !state.at(ScssTokenType::LeftBrace) {
140 state.advance();
141 }
142 self.parse_block(state)?;
143 state.finish_at(cp, ScssElementType::ForStatement);
144 Ok(())
145 }
146
147 fn parse_each<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, cp: (usize, usize)) -> Result<(), OakError> {
148 while state.not_at_end() && !state.at(ScssTokenType::LeftBrace) {
149 state.advance();
150 }
151 self.parse_block(state)?;
152 state.finish_at(cp, ScssElementType::EachStatement);
153 Ok(())
154 }
155
156 fn parse_while<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, cp: (usize, usize)) -> Result<(), OakError> {
157 while state.not_at_end() && !state.at(ScssTokenType::LeftBrace) {
158 state.advance();
159 }
160 self.parse_block(state)?;
161 state.finish_at(cp, ScssElementType::WhileStatement);
162 Ok(())
163 }
164
165 fn parse_parameters<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
166 state.expect(ScssTokenType::LeftParen)?;
167 while state.not_at_end() && !state.at(ScssTokenType::RightParen) {
168 state.advance();
169 }
170 state.expect(ScssTokenType::RightParen)?;
171 Ok(())
172 }
173
174 fn parse_arguments<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
175 state.expect(ScssTokenType::LeftParen)?;
176 while state.not_at_end() && !state.at(ScssTokenType::RightParen) {
177 state.advance();
178 }
179 state.expect(ScssTokenType::RightParen)?;
180 Ok(())
181 }
182
183 fn parse_block<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
184 let cp = state.checkpoint();
185 state.expect(ScssTokenType::LeftBrace)?;
186 while state.not_at_end() && !state.at(ScssTokenType::RightBrace) {
187 if state.at(ScssTokenType::Identifier) && self.is_declaration(state) {
188 self.parse_declaration(state)?;
189 }
190 else {
191 self.parse_node(state)?;
192 }
193 }
194 state.expect(ScssTokenType::RightBrace)?;
195 state.finish_at(cp, ScssElementType::Block);
196 Ok(())
197 }
198
199 fn is_declaration<'a, S: Source + ?Sized>(&self, state: &State<'a, S>) -> bool {
200 state.peek_kind_at(1) == Some(ScssTokenType::Colon)
202 }
203
204 fn parse_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
205 let cp = state.checkpoint();
206 let prop_cp = state.checkpoint();
207 state.expect(ScssTokenType::Identifier)?;
208 state.finish_at(prop_cp, ScssElementType::Property);
209
210 state.expect(ScssTokenType::Colon)?;
211
212 let val_cp = state.checkpoint();
213 while state.not_at_end() && !state.at(ScssTokenType::Semicolon) && !state.at(ScssTokenType::RightBrace) {
214 state.advance();
215 }
216 state.finish_at(val_cp, ScssElementType::ValueNode);
217
218 state.eat(ScssTokenType::Semicolon);
219 state.finish_at(cp, ScssElementType::Declaration);
220 Ok(())
221 }
222
223 fn parse_variable_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
224 let cp = state.checkpoint();
225 state.expect(ScssTokenType::Dollar)?;
226 state.expect(ScssTokenType::Identifier)?;
227 state.expect(ScssTokenType::Colon)?;
228 while state.not_at_end() && !state.at(ScssTokenType::Semicolon) {
229 state.advance();
230 }
231 state.eat(ScssTokenType::Semicolon);
232 state.finish_at(cp, ScssElementType::VariableDeclaration);
233 Ok(())
234 }
235
236 fn parse_return<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, cp: (usize, usize)) -> Result<(), OakError> {
237 let val_cp = state.checkpoint();
238 while state.not_at_end() && !state.at(ScssTokenType::Semicolon) {
239 state.advance();
240 }
241 state.finish_at(val_cp, ScssElementType::ValueNode);
242 state.eat(ScssTokenType::Semicolon);
243 state.finish_at(cp, ScssElementType::ReturnStatement);
244 Ok(())
245 }
246
247 fn parse_rule<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
248 let cp = state.checkpoint();
249 let sel_cp = state.checkpoint();
251 while state.not_at_end() && !state.at(ScssTokenType::LeftBrace) {
252 state.advance();
253 }
254 state.finish_at(sel_cp, ScssElementType::Selector);
255
256 if state.at(ScssTokenType::LeftBrace) {
257 self.parse_block(state)?;
258 }
259
260 state.finish_at(cp, ScssElementType::RuleSet);
261 Ok(())
262 }
263}
264
265impl<'config> Parser<ScssLanguage> for ScssParser<'config> {
266 fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<ScssLanguage>) -> ParseOutput<'a, ScssLanguage> {
267 let lexer = ScssLexer::new(&self.config);
268 parse_with_lexer(&lexer, text, edits, cache, |state| {
269 let checkpoint = state.checkpoint();
270
271 while state.not_at_end() {
272 self.parse_node(state)?;
273 }
274
275 Ok(state.finish_at(checkpoint, ScssElementType::SourceFile))
276 })
277 }
278}