Skip to main content

oak_von/builder/
mod.rs

1use crate::{
2    VonLanguage,
3    ast::{VonArray, VonBoolean, VonEnum, VonField, VonNull, VonNumber, VonObject, VonRoot, VonString, VonValue},
4    lexer::{VonLexer, VonTokenType},
5    parser::{VonElementType, VonParser},
6};
7use oak_core::{Builder, BuilderCache, GreenNode, Lexer, OakDiagnostics, OakError, Parser, SourceText, TextEdit, parser::session::ParseSession, source::Source};
8
9/// A builder for VON AST and diagnostic results.
10#[derive(Clone)]
11pub struct VonBuilder<'config> {
12    config: &'config VonLanguage,
13}
14
15impl<'config> VonBuilder<'config> {
16    /// Creates a new `VonBuilder` with the given configuration.
17    pub fn new(config: &'config VonLanguage) -> Self {
18        Self { config }
19    }
20}
21
22impl<'config> Builder<VonLanguage> for VonBuilder<'config> {
23    fn build<'a, S: Source + ?Sized>(&self, source: &S, edits: &[TextEdit], _cache: &'a mut impl BuilderCache<VonLanguage>) -> OakDiagnostics<VonRoot> {
24        let parser = VonParser::new(self.config);
25        let lexer = VonLexer::new(self.config);
26
27        let mut parse_session = ParseSession::<VonLanguage>::default();
28        lexer.lex(source, edits, &mut parse_session);
29        let parse_result = parser.parse(source, edits, &mut parse_session);
30
31        match parse_result.result {
32            Ok(green_tree) => {
33                let text = source.get_text_in((0..source.length()).into());
34                let source_text = SourceText::new(text.into_owned());
35                match self.build_root(&green_tree, &source_text) {
36                    Ok(ast_root) => OakDiagnostics { result: Ok(ast_root), diagnostics: parse_result.diagnostics },
37                    Err(build_error) => {
38                        let mut diagnostics = parse_result.diagnostics;
39                        diagnostics.push(build_error.clone());
40                        OakDiagnostics { result: Err(build_error), diagnostics }
41                    }
42                }
43            }
44            Err(parse_error) => OakDiagnostics { result: Err(parse_error), diagnostics: parse_result.diagnostics },
45        }
46    }
47}
48
49impl<'config> VonBuilder<'config> {
50    fn build_root<'a>(&self, green_tree: &GreenNode<'a, VonLanguage>, source: &SourceText) -> Result<VonRoot, OakError> {
51        // eprintln!("GreenTree: {:#?}", green_tree);
52        let root_node = match green_tree.children.first() {
53            Some(oak_core::GreenTree::Node(n)) => n,
54            _ => return Err(OakError::unexpected_eof(0, None)),
55        };
56
57        let value = self.build_value(root_node, 0, source)?;
58        Ok(VonRoot { value })
59    }
60
61    fn build_value<'a>(&self, node: &GreenNode<'a, VonLanguage>, offset: usize, source: &SourceText) -> Result<VonValue, OakError> {
62        let span: oak_core::Range<usize> = (offset..offset + node.byte_length as usize).into();
63
64        match node.kind {
65            VonElementType::Object => {
66                let mut fields = Vec::new();
67                let mut current_offset = offset;
68                for child in node.children {
69                    match child {
70                        oak_core::GreenTree::Node(n) => {
71                            if n.kind == VonElementType::ObjectEntry {
72                                fields.push(self.build_field(n, current_offset, source)?);
73                            }
74                            current_offset += n.byte_length as usize;
75                        }
76                        oak_core::GreenTree::Leaf(l) => {
77                            current_offset += l.length as usize;
78                        }
79                    }
80                }
81                Ok(VonValue::Object(VonObject { fields, span }))
82            }
83            VonElementType::Array => {
84                let mut elements = Vec::new();
85                let mut current_offset = offset;
86                for child in node.children {
87                    match child {
88                        oak_core::GreenTree::Node(n) => {
89                            if n.kind == VonElementType::ArrayElement {
90                                elements.push(self.build_value(n, current_offset, source)?);
91                            }
92                            current_offset += n.byte_length as usize;
93                        }
94                        oak_core::GreenTree::Leaf(l) => {
95                            current_offset += l.length as usize;
96                        }
97                    }
98                }
99                Ok(VonValue::Array(VonArray { elements, span }))
100            }
101            VonElementType::Enum => {
102                let mut variant = None;
103                let mut payload = None;
104                let mut current_offset = offset;
105                for child in node.children {
106                    match child {
107                        oak_core::GreenTree::Node(n) => {
108                            payload = Some(Box::new(self.build_value(n, current_offset, source)?));
109                            current_offset += n.byte_length as usize;
110                        }
111                        oak_core::GreenTree::Leaf(l) => {
112                            if l.kind == VonTokenType::Identifier {
113                                let v_span: oak_core::Range<usize> = (current_offset..current_offset + l.length as usize).into();
114                                variant = Some(source.get_text_in(v_span).to_string());
115                            }
116                            current_offset += l.length as usize;
117                        }
118                    }
119                }
120                let variant = variant.ok_or_else(|| OakError::expected_token("Variant", span.start, None))?;
121                Ok(VonValue::Enum(VonEnum { variant, payload, span }))
122            }
123            VonElementType::Value | VonElementType::ArrayElement | VonElementType::Root => {
124                let mut current_offset = offset;
125                for child in node.children {
126                    if let oak_core::GreenTree::Node(n) = child {
127                        return self.build_value(n, current_offset, source);
128                    }
129                    else if let oak_core::GreenTree::Leaf(l) = child {
130                        if l.kind == VonTokenType::StringLiteral {
131                            let s_span: oak_core::Range<usize> = (current_offset..current_offset + l.length as usize).into();
132                            let mut text = source.get_text_in(s_span.clone());
133                            // Handle raw strings raw"..." or raw'...'
134                            let is_raw = text.starts_with("raw") && (text[3..].starts_with('"') || text[3..].starts_with('\''));
135                            if is_raw {
136                                match text {
137                                    std::borrow::Cow::Borrowed(s) => text = std::borrow::Cow::Borrowed(&s[3..]),
138                                    std::borrow::Cow::Owned(ref mut s) => {
139                                        s.drain(..3);
140                                    }
141                                }
142                            }
143                            // Handle symmetric quotes: find the number of consecutive quotes at the beginning
144                            let quote_char = text.chars().next().unwrap();
145                            let mut quote_count = 0;
146                            for c in text.chars() {
147                                if c == quote_char {
148                                    quote_count += 1;
149                                }
150                                else {
151                                    break;
152                                }
153                            }
154                            let value = if text.len() >= quote_count * 2 { &text[quote_count..text.len() - quote_count] } else { "" };
155                            return Ok(VonValue::String(VonString { value: value.to_string(), span: s_span }));
156                        }
157                        else if l.kind == VonTokenType::NumberLiteral {
158                            let n_span: oak_core::Range<usize> = (current_offset..current_offset + l.length as usize).into();
159                            let text = source.get_text_in(n_span.clone());
160                            // eprintln!("Parsing number: '{}' at span {:?}", text, n_span);
161                            let clean_text = text.replace('_', "");
162                            let value = clean_text.parse::<f64>().map_err(|e| {
163                                OakError::custom_error(format!(
164                                    "Numeric parse failure: text='{}', error={:?}, span={:?}, source_around='{}'",
165                                    text,
166                                    e,
167                                    n_span,
168                                    source.get_text_in(oak_core::Range::from(n_span.start.saturating_sub(10)..n_span.end.saturating_add(10)))
169                                ))
170                            })?;
171                            return Ok(VonValue::Number(VonNumber { value, span: n_span }));
172                        }
173                        else if l.kind == VonTokenType::BoolLiteral {
174                            let b_span: oak_core::Range<usize> = (current_offset..current_offset + l.length as usize).into();
175                            let text = source.get_text_in(b_span.clone());
176                            let value = text == "true";
177                            return Ok(VonValue::Boolean(VonBoolean { value, span: b_span }));
178                        }
179                        else if l.kind == VonTokenType::NullLiteral {
180                            let n_span: oak_core::Range<usize> = (current_offset..current_offset + l.length as usize).into();
181                            return Ok(VonValue::Null(VonNull { span: n_span }));
182                        }
183                        current_offset += l.length as usize;
184                    }
185                }
186                Err(OakError::unexpected_eof(span.start, None))
187            }
188            _ => Err(OakError::syntax_error(format!("Unexpected node kind: {:?}", node.kind), span.start, None)),
189        }
190    }
191
192    fn build_field<'a>(&self, node: &GreenNode<'a, VonLanguage>, offset: usize, source: &SourceText) -> Result<VonField, OakError> {
193        let span: oak_core::Range<usize> = (offset..offset + node.byte_length as usize).into();
194
195        let mut name = None;
196        let mut value = None;
197        let mut current_offset = offset;
198
199        for child in node.children {
200            match child {
201                oak_core::GreenTree::Node(n) => {
202                    if n.kind == VonElementType::Value || n.kind == VonElementType::Object || n.kind == VonElementType::Array || n.kind == VonElementType::Enum {
203                        value = Some(self.build_value(n, current_offset, source)?);
204                    }
205                    current_offset += n.byte_length as usize
206                }
207                oak_core::GreenTree::Leaf(l) => {
208                    if l.kind == VonTokenType::Identifier || l.kind == VonTokenType::StringLiteral {
209                        let b_span: oak_core::Range<usize> = (current_offset..current_offset + l.length as usize).into();
210                        let text = source.get_text_in(b_span.clone());
211                        name = Some(text.trim_matches('"').to_string());
212                    }
213                    current_offset += l.length as usize
214                }
215            }
216        }
217
218        let name = name.ok_or_else(|| OakError::expected_token("Key", span.start, None))?;
219        let value = value.ok_or_else(|| OakError::expected_token("Value", span.start, None))?;
220
221        Ok(VonField { name, value, span })
222    }
223}