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#[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}