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}