Skip to main content

oak_json/builder/
mod.rs

1use crate::{
2    JsonLanguage,
3    ast::{JsonArray, JsonBoolean, JsonField, JsonNull, JsonNumber, JsonObject, JsonRoot, JsonString, JsonValueNode},
4    lexer::JsonLexer,
5    parser::JsonParser,
6};
7use oak_core::{Builder, BuilderCache, GreenNode, Lexer, OakDiagnostics, OakError, Parser, SourceText, TextEdit, parser::session::ParseSession, source::Source};
8
9/// AST builder for JSON.
10#[derive(Clone)]
11pub struct JsonBuilder<'config> {
12    config: &'config JsonLanguage,
13}
14
15impl<'config> JsonBuilder<'config> {
16    /// Creates a new JSON builder.
17    pub fn new(config: &'config JsonLanguage) -> Self {
18        Self { config }
19    }
20}
21
22impl<'config> Builder<JsonLanguage> for JsonBuilder<'config> {
23    fn build<'a, S: Source + ?Sized>(&self, source: &S, edits: &[TextEdit], _cache: &'a mut impl BuilderCache<JsonLanguage>) -> OakDiagnostics<JsonRoot> {
24        let parser = JsonParser::new(self.config);
25        let lexer = JsonLexer::new(self.config);
26
27        let mut cache = ParseSession::<JsonLanguage>::default();
28        lexer.lex(source, edits, &mut cache);
29        let parse_result = parser.parse(source, edits, &mut cache);
30        let OakDiagnostics { result, diagnostics } = parse_result;
31
32        match result {
33            Ok(green_tree) => {
34                let text = source.get_text_in((0..source.length()).into());
35                let source_text = SourceText::new(text.into_owned());
36                match self.build_root(&green_tree, &source_text) {
37                    Ok(ast_root) => OakDiagnostics { result: Ok(ast_root), diagnostics },
38                    Err(build_error) => {
39                        let mut diagnostics = diagnostics;
40                        diagnostics.push(build_error.clone());
41                        OakDiagnostics { result: Err(build_error), diagnostics }
42                    }
43                }
44            }
45            Err(parse_error) => OakDiagnostics { result: Err(parse_error), diagnostics },
46        }
47    }
48}
49
50impl<'config> JsonBuilder<'config> {
51    fn build_root<'a>(&self, green_tree: &GreenNode<'a, JsonLanguage>, source: &SourceText) -> Result<JsonRoot, OakError> {
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(JsonRoot { value })
59    }
60
61    fn build_value<'a>(&self, node: &GreenNode<'a, JsonLanguage>, offset: usize, source: &SourceText) -> Result<JsonValueNode, OakError> {
62        use crate::parser::element_type::JsonElementType;
63        let span: oak_core::Range<usize> = (offset..offset + node.byte_length as usize).into();
64
65        match node.kind {
66            JsonElementType::Object => {
67                let mut fields = Vec::new();
68                let mut current_offset = offset;
69                for child in node.children {
70                    match child {
71                        oak_core::GreenTree::Node(n) => {
72                            if n.kind == JsonElementType::ObjectEntry {
73                                fields.push(self.build_field(n, current_offset, source)?);
74                            }
75                            current_offset += n.byte_length as usize;
76                        }
77                        oak_core::GreenTree::Leaf(l) => {
78                            current_offset += l.length as usize;
79                        }
80                    }
81                }
82                Ok(JsonValueNode::Object(JsonObject { fields, span }))
83            }
84            JsonElementType::Array => {
85                let mut elements = Vec::new();
86                let mut current_offset = offset;
87                for child in node.children {
88                    match child {
89                        oak_core::GreenTree::Node(n) => {
90                            match n.kind {
91                                JsonElementType::ArrayElement | JsonElementType::Value | JsonElementType::Object | JsonElementType::Array | JsonElementType::String | JsonElementType::Number | JsonElementType::Boolean | JsonElementType::Null => {
92                                    elements.push(self.build_value(n, current_offset, source)?);
93                                }
94                                _ => {}
95                            }
96                            current_offset += n.byte_length as usize;
97                        }
98                        oak_core::GreenTree::Leaf(l) => {
99                            current_offset += l.length as usize;
100                        }
101                    }
102                }
103                Ok(JsonValueNode::Array(JsonArray { elements, span }))
104            }
105            JsonElementType::String => {
106                let text = source.get_text_in(span.clone());
107                let value = text.trim_matches('"').to_string();
108                Ok(JsonValueNode::String(JsonString { value, span }))
109            }
110            JsonElementType::Number => {
111                let text = source.get_text_in(span.clone());
112                let value = text.parse::<f64>().map_err(|_| OakError::syntax_error(format!("Invalid number: {}", text), span.start, None))?;
113                Ok(JsonValueNode::Number(JsonNumber { value, span }))
114            }
115            JsonElementType::Boolean => {
116                let text = source.get_text_in(span.clone());
117                let value = text == "true";
118                Ok(JsonValueNode::Boolean(JsonBoolean { value, span }))
119            }
120            JsonElementType::Null => Ok(JsonValueNode::Null(JsonNull { span })),
121            JsonElementType::Value | JsonElementType::ArrayElement | JsonElementType::Root => {
122                let mut current_offset = offset;
123                for child in node.children {
124                    if let oak_core::GreenTree::Node(n) = child {
125                        return self.build_value(n, current_offset, source);
126                    }
127                    else if let oak_core::GreenTree::Leaf(l) = child {
128                        current_offset += l.length as usize;
129                    }
130                }
131                Err(OakError::unexpected_eof(span.start, None))
132            }
133            _ => Err(OakError::syntax_error(format!("Unexpected node kind: {:?}", node.kind), span.start, None)),
134        }
135    }
136
137    fn build_field<'a>(&self, node: &GreenNode<'a, JsonLanguage>, offset: usize, source: &SourceText) -> Result<JsonField, OakError> {
138        use crate::{lexer::token_type::JsonTokenType, parser::element_type::JsonElementType};
139        let span: oak_core::Range<usize> = (offset..offset + node.byte_length as usize).into();
140        let mut name = None;
141        let mut value = None;
142        let mut seen_colon = false;
143        let mut current_offset = offset;
144
145        for child in node.children {
146            match child {
147                oak_core::GreenTree::Node(n) => {
148                    if !seen_colon {
149                        if n.kind == JsonElementType::String {
150                            let s_span: oak_core::Range<usize> = (current_offset..current_offset + n.byte_length as usize).into();
151                            let text = source.get_text_in(s_span.clone());
152                            name = Some(JsonString { value: text.trim_matches('"').to_string(), span: s_span });
153                        }
154                    }
155                    else if value.is_none() {
156                        match n.kind {
157                            JsonElementType::Value | JsonElementType::Object | JsonElementType::Array | JsonElementType::String | JsonElementType::Number | JsonElementType::Boolean | JsonElementType::Null => {
158                                value = Some(self.build_value(n, current_offset, source)?);
159                            }
160                            _ => {}
161                        }
162                    }
163                    current_offset += n.byte_length as usize;
164                }
165                oak_core::GreenTree::Leaf(l) => {
166                    if l.kind == JsonTokenType::Colon {
167                        seen_colon = true;
168                    }
169                    current_offset += l.length as usize;
170                }
171            }
172        }
173
174        Ok(JsonField { name: name.ok_or_else(|| OakError::syntax_error("Missing field name", offset, None))?, value: value.ok_or_else(|| OakError::syntax_error("Missing field value", offset, None))?, span })
175    }
176}