Skip to main content

squawk_syntax/
body.rs

1use std::marker::PhantomData;
2
3use rowan::{GreenNode, TextRange};
4
5use crate::{
6    SyntaxNode, ast, ast::AstNode, decoded_text::DecodedText, syntax_error::SyntaxError, validation,
7};
8
9pub struct Body<T> {
10    green: GreenNode,
11    errors: Vec<SyntaxError>,
12    decoded: DecodedText,
13    _ty: PhantomData<fn() -> T>,
14}
15
16pub trait BodyLanguage: AstNode {
17    const LANGUAGE: &'static str;
18
19    fn parse_text(text: &str) -> (GreenNode, Vec<SyntaxError>);
20
21    fn is_language(language: Option<ast::LanguageName>) -> bool {
22        language.is_some_and(|language| language.name == Self::LANGUAGE)
23    }
24}
25
26impl<T: BodyLanguage> Body<T> {
27    pub const LANGUAGE: &'static str = T::LANGUAGE;
28
29    pub(crate) fn parse(decoded: DecodedText) -> Self {
30        let (green, errors) = T::parse_text(decoded.text());
31        let errors = errors
32            .into_iter()
33            .map(|error| {
34                let range = decoded.source_range(error.range());
35                error.with_range(range)
36            })
37            .collect();
38
39        Self {
40            green,
41            errors,
42            decoded,
43            _ty: PhantomData,
44        }
45    }
46
47    pub(crate) fn from_options(options: ast::FuncOptionList) -> Option<Self> {
48        let mut matches = false;
49        let mut body = None;
50
51        for option in options.options() {
52            match option {
53                ast::FuncOption::LanguageFuncOption(option) => {
54                    matches = T::is_language(option.language_name());
55                }
56                ast::FuncOption::AsFuncOption(option) => {
57                    if let Some(ast::AsFuncTarget::AsDefinition(definition)) =
58                        option.as_func_target()
59                    {
60                        body = definition.literal();
61                    }
62                }
63                _ => (),
64            }
65        }
66
67        matches.then_some(())?;
68        Some(Self::parse(body?.decoded_value()?))
69    }
70
71    pub fn syntax(&self) -> SyntaxNode {
72        SyntaxNode::new_root(self.green.clone())
73    }
74
75    pub fn tree(&self) -> T {
76        T::cast(self.syntax()).expect("root is always the body's node")
77    }
78
79    pub fn text(&self) -> &str {
80        self.decoded.text()
81    }
82
83    pub fn source_range(&self, range: TextRange) -> TextRange {
84        self.decoded.source_range(range)
85    }
86
87    pub fn errors(&self) -> Vec<SyntaxError> {
88        let mut validation_errors = vec![];
89        validation::validate(&self.syntax(), &mut validation_errors);
90
91        let mut errors = self.errors.clone();
92        errors.extend(validation_errors.into_iter().map(|error| {
93            let range = self.decoded.source_range(error.range());
94            error.with_range(range)
95        }));
96        errors.sort_by_key(|error| error.range().start());
97        errors
98    }
99}