Skip to main content

oak_json/builder/
mod.rs

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