1use rowan::GreenNode;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct Parse<T> {
12 green_node: GreenNode,
13 positioned_errors: Vec<crate::PositionedParseError>,
14 _ty: std::marker::PhantomData<fn() -> T>,
15}
16
17impl<T> Parse<T> {
18 pub(crate) fn new(
19 green_node: GreenNode,
20 positioned_errors: Vec<crate::PositionedParseError>,
21 ) -> Self {
22 Parse {
23 green_node,
24 positioned_errors,
25 _ty: std::marker::PhantomData,
26 }
27 }
28
29 pub fn tree(&self) -> T
32 where
33 T: rowan::ast::AstNode<Language = crate::Lang>,
34 {
35 let syntax_node = rowan::SyntaxNode::new_root_mut(self.green_node.clone());
36 T::cast(syntax_node)
37 .expect("Parse<T> always holds a green node whose root kind matches T::can_cast")
38 }
39
40 pub fn positioned_errors(&self) -> &[crate::PositionedParseError] {
42 &self.positioned_errors
43 }
44
45 pub fn errors(&self) -> Vec<String> {
47 let text = self.green_node.to_string();
48 self.positioned_errors
49 .iter()
50 .map(|e| format!("{}: {}", e.start_position(&text), e.message))
51 .collect()
52 }
53
54 pub fn to_result(self) -> Result<T, crate::YamlError>
56 where
57 T: rowan::ast::AstNode<Language = crate::Lang>,
58 {
59 if let Some(first) = self.positioned_errors.first() {
60 let pos = first.start_position(&self.green_node.to_string());
61 Err(crate::YamlError::Parse {
62 message: first.message.clone(),
63 line: Some(pos.line),
64 column: Some(pos.column),
65 })
66 } else {
67 Ok(self.tree())
68 }
69 }
70
71 pub fn has_errors(&self) -> bool {
73 !self.positioned_errors.is_empty()
74 }
75
76 pub fn ok(&self) -> bool {
78 self.positioned_errors.is_empty()
79 }
80}
81
82impl Parse<crate::YamlFile> {
83 pub fn parse_yaml(text: &str) -> Self {
85 let parsed = crate::yaml::parse(text);
86 Parse::new(parsed.green_node, parsed.positioned_errors)
87 }
88}