1use super::{span::Span, tokenizer::Token};
2use crate::syntax_error::SyntaxError;
3use serde::{Deserialize, Serialize};
4use std::collections::BTreeMap;
5
6#[derive(Debug, Serialize, Deserialize)]
7pub struct Document {
8 pub span: Span,
9 pub executable: Option<String>,
10 pub elements: Vec<Expression>,
11}
12
13#[derive(Debug, Serialize, Deserialize)]
14pub struct Variable {
15 pub span: Span,
16 pub comment: Box<Option<Expression>>,
17 pub name: String,
18 pub variable_type: Option<String>,
19 pub options_variable_type: Option<BTreeMap<String, Option<Expression>>>,
20 pub default_value: Box<Option<Expression>>,
21 pub nullable: bool,
22}
23
24#[derive(Debug, Serialize, Deserialize)]
25pub struct CommentBlock {
26 pub span: Span,
27 pub raw: Vec<String>,
28}
29
30#[derive(Debug, Serialize, Deserialize)]
31pub struct DefaultValue {
32 pub span: Span,
33 pub value: String,
34}
35
36#[derive(Debug, Serialize, Deserialize)]
37pub struct OptionValue {
38 pub span: Span,
39 pub value: String,
40}
41
42#[derive(Debug, Serialize, Deserialize)]
44pub enum Expression {
45 Document(Document),
46 CommentBlock(CommentBlock),
47 Variable(Variable),
48 DefaultValue(DefaultValue),
49 OptionValue(OptionValue),
50}
51
52impl Expression {
53 fn to_span(&self) -> Span {
54 match self {
55 Expression::Document(Document { span, .. }) => span.clone(),
56 Expression::CommentBlock(CommentBlock { span, .. }) => span.clone(),
57 Expression::Variable(Variable { span, .. }) => span.clone(),
58 Expression::DefaultValue(DefaultValue { span, .. }) => span.clone(),
59 Expression::OptionValue(OptionValue { span, .. }) => span.clone(),
60 }
61 }
62
63 pub fn as_variable(&self) -> Option<&Variable> {
64 if let Self::Variable(v) = self {
65 Some(v)
66 } else {
67 None
68 }
69 }
70
71 pub fn as_document(&self) -> Option<&Document> {
72 if let Self::Document(v) = self {
73 Some(v)
74 } else {
75 None
76 }
77 }
78
79 pub fn as_default_value(&self) -> Option<&DefaultValue> {
80 if let Self::DefaultValue(v) = self {
81 Some(v)
82 } else {
83 None
84 }
85 }
86}
87
88#[derive(Debug, Clone)]
89struct Cursor<T>
90where
91 T: AsRef<Vec<Token>>,
92{
93 index: usize,
94 items: T,
95}
96
97impl<T> Cursor<T>
98where
99 T: AsRef<Vec<Token>>,
100{
101 fn new(items: T) -> Self {
102 Self { index: 0, items }
103 }
104
105 fn assert_current_kind<S: ToString, const U: usize>(
106 &self,
107 kinds: [S; U],
108 ) -> Result<&Token, SyntaxError> {
109 let kinds_str = kinds.map(|k| k.to_string());
110 if let Some(token) = self.select_current() {
111 if kinds_str.contains(&token.kind) {
112 Ok(token)
113 } else {
114 do yeet SyntaxError::new(
115 format!("Unexpected token {}", token.kind),
116 token.span.clone(),
117 )
118 }
119 } else {
120 do yeet SyntaxError::new(
121 "Unexpected token",
122 Span {
123 start: self.index,
124 end: self.index + 1,
125 },
126 )
127 }
128 }
129
130 fn forward_some_kind<S: ToString, const Z: usize>(&mut self, kinds: [S; Z]) {
131 let kinds_str = kinds.map(|k| k.to_string());
132 while let Some(token) = self.select_current() {
133 if kinds_str.contains(&token.kind) {
134 self.forward(1);
135 continue;
136 }
137 break;
138 }
139 }
140
141 fn select_current(&self) -> Option<&Token> {
142 self.items.as_ref().get(self.index)
143 }
144
145 fn select_next(&self) -> Option<&Token> {
146 self.items.as_ref().get(self.index + 1)
147 }
148
149 fn select_nexts(&self, steps: usize) -> Option<&Token> {
150 self.items.as_ref().get(self.index + steps)
151 }
152
153 fn select_prev(&self) -> Option<&Token> {
154 self.items.as_ref().get(self.index - 1)
155 }
156
157 fn next(&mut self) -> Option<&Token> {
158 self.forward(1);
159 self.select_prev()
160 }
161
162 fn forward(&mut self, steps: usize) {
163 self.index = self.index + steps;
164 }
165}
166
167pub struct AST {}
168
169impl AST {
170 pub fn parse(tokens: Vec<Token>) -> Result<Expression, SyntaxError> {
171 let mut executable: Option<String> = None;
172 let ref mut token_cursor = Cursor::new(tokens);
173 let mut span_start: usize = 0;
174 let mut span_end: usize = 0;
175
176 if let Some(token) = token_cursor.select_current() {
177 if token.kind == "comment" && token.raw.starts_with("#!") {
178 span_start = token.span.start;
179 span_end = token.span.end;
180 executable = Some(token.raw.to_string());
181 token_cursor.forward(1);
182 }
183 }
184
185 let elements = Self::parse_expressions_list(token_cursor)?;
186
187 if let Some(expression) = elements.last() {
188 span_end = expression.to_span().end;
189 }
190
191 Ok(Expression::Document(Document {
192 executable,
193 elements,
194 span: Span {
195 start: span_start,
196 end: span_end,
197 },
198 }))
199 }
200
201 fn parse_expressions_list(
202 tokens_cursor: &mut Cursor<Vec<Token>>,
203 ) -> Result<Vec<Expression>, SyntaxError> {
204 let mut vec: Vec<Expression> = vec![];
205
206 while let Some(token) = tokens_cursor.select_current() {
207 if token.kind == "newline" || token.kind == "space" {
208 tokens_cursor.forward(1);
209 continue;
210 }
211 if token.kind == "comment" {
212 vec.push(Self::parse_block_comment(tokens_cursor)?);
213 continue;
214 }
215 if token.kind == "keyword" {
216 vec.push(Self::parse_variable(tokens_cursor, None)?);
217 continue;
218 }
219 do yeet SyntaxError::new("Unexpected type", token.span.clone())
220 }
221
222 Ok(vec)
223 }
224
225 fn parse_block_comment(
226 tokens_cursor: &mut Cursor<Vec<Token>>,
227 ) -> Result<Expression, SyntaxError> {
228 let span_start = tokens_cursor.select_current().unwrap().span.start;
229 let mut span_end = tokens_cursor.select_current().unwrap().span.end;
230 let mut raw: Vec<String> = vec![];
231
232 while let Some(token) = tokens_cursor.select_current() {
233 if token.kind == "space" {
234 tokens_cursor.forward(1);
235 continue;
236 }
237
238 if token.kind != "comment" {
239 break;
240 }
241
242 raw.push(token.raw.to_string());
243 span_end = token.span.end;
244
245 if let Some(token) = tokens_cursor.select_next() {
246 if token.kind == "newline" {
247 tokens_cursor.forward(1);
248 }
249 }
250
251 tokens_cursor.forward(1);
252 }
253
254 let comment = Expression::CommentBlock(CommentBlock {
255 span: Span {
256 start: span_start,
257 end: span_end,
258 },
259 raw,
260 });
261
262 if let Some(token) = tokens_cursor.select_current() {
263 if token.kind == "keyword" {
264 return Ok(Self::parse_variable(tokens_cursor, Some(comment))?);
265 }
266 }
267
268 Ok(comment)
269 }
270
271 fn parse_variable(
272 tokens_cursor: &mut Cursor<Vec<Token>>,
273 comment: Option<Expression>,
274 ) -> Result<Expression, SyntaxError> {
275 tokens_cursor.assert_current_kind(["keyword"])?;
277
278 let name: String = tokens_cursor.select_current().unwrap().raw.to_string();
279 let span_start: usize = tokens_cursor.select_current().unwrap().span.start;
280 let mut span_end: usize = tokens_cursor.select_current().unwrap().span.end;
281 let mut variable_type: Option<String> = None;
282 let mut options_variable_type: Option<BTreeMap<String, Option<Expression>>> = None;
283 let mut default_value: Option<Expression> = None;
284 let mut nullable: bool = false;
285 tokens_cursor.forward(1);
286
287 tokens_cursor.forward_some_kind(["space"]);
288
289 if tokens_cursor.assert_current_kind(["colon"]).is_ok() {
290 tokens_cursor.forward(1);
291 tokens_cursor.forward_some_kind(["space"]);
292 tokens_cursor.assert_current_kind(["keyword"])?;
293 let variable_type_token = tokens_cursor.select_current().unwrap();
294 variable_type = Some(variable_type_token.raw.to_string());
295 span_end = variable_type_token.span.end;
296 tokens_cursor.forward(1);
297 tokens_cursor.forward_some_kind(["space"]);
298
299 if tokens_cursor.assert_current_kind(["less_than"]).is_ok() {
300 tokens_cursor.forward(1);
301 tokens_cursor.forward_some_kind(["space", "newline"]);
302
303 let mut options: BTreeMap<String, Option<Expression>> = Default::default();
304
305 while tokens_cursor.assert_current_kind(["keyword"]).is_ok() {
306 let option_key = tokens_cursor.select_current().unwrap().raw.to_string();
307 tokens_cursor.forward(1);
308 tokens_cursor.forward_some_kind(["space", "newline"]);
309 if tokens_cursor.assert_current_kind(["equal"]).is_ok() {
310 tokens_cursor.assert_current_kind(["equal"])?;
311 tokens_cursor.forward(1);
312 tokens_cursor.forward_some_kind(["space"]);
313 let value_expression = Self::parse_items_option_value(tokens_cursor)?;
314 options.insert(option_key, Some(value_expression));
315 tokens_cursor.forward_some_kind(["space", "newline"]);
316 } else {
317 options.insert(option_key, None);
318 }
319 }
320
321 let greater_than = tokens_cursor.assert_current_kind(["greater_than"])?;
322 span_end = greater_than.span.end;
323 tokens_cursor.forward(1);
324
325 options_variable_type = Some(options);
326
327 tokens_cursor.forward_some_kind(["space"]);
328 }
329
330 if let Ok(token) = tokens_cursor.assert_current_kind(["question_mark"]) {
331 span_end = token.span.end;
332 tokens_cursor.forward(1);
333 nullable = true;
334 }
335 }
336
337 if tokens_cursor.assert_current_kind(["equal"]).is_ok() {
338 tokens_cursor.forward(1);
339 tokens_cursor.forward_some_kind(["space"]);
340 let default_value_expression = Self::parse_items_default_value(tokens_cursor)?;
341 span_end = default_value_expression.to_span().end;
342 default_value = Some(default_value_expression);
343 }
344
345 Ok(Expression::Variable(Variable {
346 span: Span {
347 start: span_start,
348 end: span_end,
349 },
350 comment: Box::new(comment),
351 name: name,
352 variable_type,
353 options_variable_type,
354 default_value: Box::new(default_value),
355 nullable,
356 }))
357 }
358
359 fn parse_items_default_value(
360 tokens_cursor: &mut Cursor<Vec<Token>>,
361 ) -> Result<Expression, SyntaxError> {
362 match tokens_cursor.select_current() {
363 Some(token) if token.kind == "string" => {
364 Ok(Self::parse_items_default_value_string(tokens_cursor)?)
365 }
366 Some(token) if token.kind == "number" => {
367 Ok(Self::parse_items_default_value_number(tokens_cursor)?)
368 }
369 Some(token) => do yeet SyntaxError::new("Unexpected token", token.span.clone()),
370 _ => {
371 do yeet SyntaxError::new(
372 "Unexpected token",
373 Span {
374 start: tokens_cursor.index,
375 end: tokens_cursor.index + 1,
376 },
377 )
378 }
379 }
380 }
381
382 fn parse_items_default_value_string(
383 tokens_cursor: &mut Cursor<Vec<Token>>,
384 ) -> Result<Expression, SyntaxError> {
385 let token = tokens_cursor.select_current().unwrap();
386 let a = Expression::DefaultValue(DefaultValue {
387 span: token.span.clone(),
388 value: token.raw.to_string(),
389 });
390 tokens_cursor.forward(1);
391 return Ok(a);
392 }
393
394 fn parse_items_default_value_number(
395 tokens_cursor: &mut Cursor<Vec<Token>>,
396 ) -> Result<Expression, SyntaxError> {
397 let token = tokens_cursor.select_current().unwrap();
398 let a = Expression::DefaultValue(DefaultValue {
399 span: token.span.clone(),
400 value: token.raw.to_string(),
401 });
402 tokens_cursor.forward(1);
403 return Ok(a);
404 }
405
406 fn parse_items_option_value(
407 tokens_cursor: &mut Cursor<Vec<Token>>,
408 ) -> Result<Expression, SyntaxError> {
409 match tokens_cursor.select_current() {
410 Some(token) if token.kind == "string" => {
411 Ok(Self::parse_items_option_value_string(tokens_cursor)?)
412 }
413 Some(token) if token.kind == "number" => {
414 Ok(Self::parse_items_option_value_number(tokens_cursor)?)
415 }
416 Some(token) => do yeet SyntaxError::new("Unexpected token", token.span.clone()),
417 _ => {
418 do yeet SyntaxError::new(
419 "Unexpected token",
420 Span {
421 start: tokens_cursor.index,
422 end: tokens_cursor.index + 1,
423 },
424 )
425 }
426 }
427 }
428
429 fn parse_items_option_value_string(
430 tokens_cursor: &mut Cursor<Vec<Token>>,
431 ) -> Result<Expression, SyntaxError> {
432 let token = tokens_cursor.select_current().unwrap();
433 let a = Expression::OptionValue(OptionValue {
434 span: token.span.clone(),
435 value: token.raw.to_string(),
436 });
437 tokens_cursor.forward(1);
438 return Ok(a);
439 }
440
441 fn parse_items_option_value_number(
442 tokens_cursor: &mut Cursor<Vec<Token>>,
443 ) -> Result<Expression, SyntaxError> {
444 let token = tokens_cursor.select_current().unwrap();
445 let a = Expression::OptionValue(OptionValue {
446 span: token.span.clone(),
447 value: token.raw.to_string(),
448 });
449 tokens_cursor.forward(1);
450 return Ok(a);
451 }
452}