1use crate::{
4 ast::{self, Declaration, GoRoot},
5 language::GoLanguage,
6 lexer::{GoLexer, token_type::GoTokenType},
7 parser::{GoParser, element_type::GoElementType},
8};
9use oak_core::{
10 Builder, BuilderCache, GreenNode, Lexer, OakDiagnostics, OakError, ParseSession, Parser, SourceText, TextEdit, TokenType,
11 builder::BuildOutput,
12 source::Source,
13 tree::{RedNode, RedTree},
14};
15
16mod build_signatures;
17
18pub struct GoBuilder<'config> {
20 pub(crate) config: &'config GoLanguage,
21}
22
23impl<'config> Builder<GoLanguage> for GoBuilder<'config> {
24 fn build<'a, S: Source + ?Sized>(&self, text: &S, edits: &[TextEdit], cache: &'a mut impl BuilderCache<GoLanguage>) -> BuildOutput<GoLanguage> {
25 let parser = GoParser::new(self.config);
26 let cache_ptr = cache as *mut _;
27 let output = parser.parse(text, edits, unsafe { &mut *cache_ptr });
28 let result = output.result.map(|green| {
29 let source = SourceText::new(text.get_text_in((0..text.length()).into()).into_owned());
30 self.build_root(green, &source, unsafe { &mut *cache_ptr })
31 });
32 OakDiagnostics { result, diagnostics: output.diagnostics }
33 }
34}
35
36impl<'config> GoBuilder<'config> {
37 pub fn new(config: &'config GoLanguage) -> Self {
38 Self { config }
39 }
40
41 fn build_root<'a>(&self, green: &'a GreenNode<'a, GoLanguage>, source: &SourceText, cache: &mut impl BuilderCache<GoLanguage>) -> GoRoot {
42 if let Some(cached) = cache.get_typed_node::<std::sync::Arc<GoRoot>>(green) {
43 return (*cached).clone();
44 }
45
46 let red = RedNode::new(green, 0);
47 let mut package = None;
48 let mut imports = vec![];
49 let mut declarations = vec![];
50
51 for child in red.children() {
52 if let RedTree::Node(node) = child {
53 match node.green.kind {
54 GoElementType::PackageClause => {
55 package = self.extract_package(node, source);
56 }
57 GoElementType::ImportDeclaration => {
58 imports.extend(self.extract_imports(node, source));
59 }
60 GoElementType::FunctionDeclaration => {
61 if let Ok(func) = self.extract_function(node, source, cache) {
62 declarations.push(Declaration::Function(func));
63 }
64 }
65 GoElementType::VariableDeclaration => {
66 if let Ok(vars) = self.extract_variables(node, source, cache) {
67 declarations.extend(vars);
68 }
69 }
70 GoElementType::ConstDeclaration => {
71 if let Ok(consts) = self.extract_consts(node, source, cache) {
72 declarations.extend(consts);
73 }
74 }
75 GoElementType::TypeDeclaration => {
76 if let Ok(types) = self.extract_types(node, source, cache) {
77 declarations.extend(types);
78 }
79 }
80 _ => {}
81 }
82 }
83 }
84
85 let root = GoRoot { package, imports, declarations };
86 root
88 }
89
90 fn extract_package(&self, node: RedNode<GoLanguage>, source: &SourceText) -> Option<String> {
91 for child in node.children() {
92 if let RedTree::Leaf(leaf) = child {
93 if leaf.kind == GoTokenType::Identifier {
94 return Some(source.get_text_in(leaf.span).trim().to_string());
95 }
96 }
97 }
98 None
99 }
100
101 fn extract_imports(&self, node: RedNode<GoLanguage>, source: &SourceText) -> Vec<ast::Import> {
102 let mut imports = vec![];
103 for child in node.children() {
104 if let RedTree::Node(n) = child {
105 match n.green.kind {
106 GoElementType::ImportSpec => {
107 let mut path = String::new();
108 let mut alias = None;
109 for spec_child in n.children() {
110 match spec_child {
111 RedTree::Leaf(leaf) if leaf.kind == GoTokenType::Identifier => {
112 alias = Some(source.get_text_in(leaf.span).trim().to_string());
113 }
114 RedTree::Leaf(leaf) if leaf.kind == GoTokenType::StringLiteral => {
115 path = source.get_text_in(leaf.span).trim_matches('"').to_string();
116 }
117 _ => {}
118 }
119 }
120 imports.push(ast::Import { path, alias, span: n.span() });
121 }
122 _ => {
123 imports.extend(self.extract_imports(n, source));
125 }
126 }
127 }
128 }
129 imports
130 }
131
132 fn extract_block(&self, node: RedNode<GoLanguage>, source: &SourceText) -> Result<ast::Block, OakError> {
133 let mut statements = vec![];
134 let span = node.span();
135
136 for child in node.children() {
137 if let RedTree::Node(n) = child {
138 if let Some(stmt) = self.extract_statement(n, source)? {
139 statements.push(stmt);
140 }
141 }
142 }
143
144 Ok(ast::Block { statements, span })
145 }
146
147 fn extract_statement(&self, node: RedNode<GoLanguage>, source: &SourceText) -> Result<Option<ast::Statement>, OakError> {
148 match node.green.kind {
149 GoElementType::ReturnStatement => {
150 let mut values = vec![];
151 for child in node.children() {
152 if let RedTree::Node(n) = child {
153 values.push(self.extract_expression(n, source)?);
154 }
155 }
156 Ok(Some(ast::Statement::Return { values, span: node.span() }))
157 }
158 GoElementType::IfStatement => {
159 let mut condition = ast::Expression::Literal { value: "true".to_string(), span: node.span() };
160 let mut then_block = ast::Block { statements: vec![], span: node.span() };
161 let mut else_block = None;
162
163 for child in node.children() {
164 if let RedTree::Node(n) = child {
165 match n.green.kind {
166 GoElementType::BinaryExpression | GoElementType::CallExpression | GoElementType::Identifier => {
167 condition = self.extract_expression(n, source)?;
168 }
169 GoElementType::Block => {
170 if then_block.statements.is_empty() {
171 then_block = self.extract_block(n, source)?;
172 }
173 else {
174 else_block = Some(self.extract_block(n, source)?);
175 }
176 }
177 GoElementType::IfStatement => {
178 let inner_if = self.extract_statement(n, source)?;
180 if let Some(ast::Statement::If { condition, then_block, else_block: inner_else, span }) = inner_if {
181 else_block = Some(ast::Block { statements: vec![ast::Statement::If { condition, then_block, else_block: inner_else, span }], span });
182 }
183 }
184 _ => {}
185 }
186 }
187 }
188 Ok(Some(ast::Statement::If { condition, then_block, else_block, span: node.span() }))
189 }
190 GoElementType::ForStatement => {
191 let mut init = None;
192 let mut condition = None;
193 let mut post = None;
194 let mut body = ast::Block { statements: vec![], span: node.span() };
195
196 for child in node.children() {
197 if let RedTree::Node(n) = child {
198 match n.green.kind {
199 GoElementType::ShortVarDecl | GoElementType::AssignmentStatement | GoElementType::VariableDeclaration => {
200 if init.is_none() {
201 init = self.extract_statement(n, source)?.map(Box::new);
202 }
203 else {
204 post = self.extract_statement(n, source)?.map(Box::new);
205 }
206 }
207 GoElementType::BinaryExpression | GoElementType::CallExpression | GoElementType::Identifier => {
208 condition = Some(self.extract_expression(n, source)?);
209 }
210 GoElementType::Block => {
211 body = self.extract_block(n, source)?;
212 }
213 _ => {}
214 }
215 }
216 }
217 Ok(Some(ast::Statement::For { init, condition, post, body, span: node.span() }))
218 }
219 GoElementType::AssignmentStatement | GoElementType::ShortVarDecl | GoElementType::VariableDeclaration | GoElementType::VariableSpec => {
220 let mut targets = vec![];
222 let mut values = vec![];
223
224 for child in node.children() {
225 match child {
226 RedTree::Leaf(leaf) if leaf.kind == GoTokenType::Identifier => {
227 targets.push(source.get_text_in(leaf.span).trim().to_string());
228 }
229 RedTree::Node(n) => {
230 if n.green.kind == GoElementType::VariableSpec || n.green.kind == GoElementType::VariableDeclaration {
231 if let Some(ast::Statement::Assignment { targets: t, values: v, .. }) = self.extract_statement(n, source)? {
233 targets.extend(t);
234 values.extend(v);
235 }
236 }
237 else if n.green.kind != GoElementType::Identifier && !n.green.kind.is_keyword() {
238 values.push(self.extract_expression(n, source)?);
239 }
240 else if n.green.kind == GoElementType::Identifier {
241 targets.push(source.get_text_in(n.span()).trim().to_string());
242 }
243 }
244 _ => {}
245 }
246 }
247
248 if targets.is_empty() {
249 return Ok(None);
250 }
251
252 if values.is_empty() {
254 for _ in &targets {
255 values.push(ast::Expression::Literal { value: "0".to_string(), span: node.span() });
256 }
257 }
258
259 Ok(Some(ast::Statement::Assignment { targets, values, span: node.span() }))
260 }
261 _ => {
262 if let Ok(expr) = self.extract_expression(node, source) { Ok(Some(ast::Statement::Expression(expr))) } else { Ok(None) }
264 }
265 }
266 }
267
268 fn extract_expression(&self, node: RedNode<GoLanguage>, source: &SourceText) -> Result<ast::Expression, OakError> {
269 self.extract_expression_internal(RedTree::Node(node), source)
270 }
271
272 fn extract_expression_internal(&self, tree: RedTree<GoLanguage>, source: &SourceText) -> Result<ast::Expression, OakError> {
273 match tree {
274 RedTree::Leaf(leaf) => {
275 if leaf.kind == GoTokenType::Identifier {
276 let name = source.get_text_in(leaf.span).trim().to_string();
277 if name.is_empty() {
278 return Err(OakError::parse_error("Empty identifier leaf"));
279 }
280 Ok(ast::Expression::Identifier { name, span: leaf.span })
281 }
282 else if leaf.kind == GoTokenType::IntLiteral || leaf.kind == GoTokenType::StringLiteral || leaf.kind == GoTokenType::BoolLiteral {
283 Ok(ast::Expression::Literal { value: source.get_text_in(leaf.span).to_string(), span: leaf.span })
284 }
285 else {
286 Err(OakError::parse_error(format!("Unexpected leaf in expression: {:?}", leaf.kind)))
287 }
288 }
289 RedTree::Node(node) => match node.green.kind {
290 GoElementType::Identifier => {
291 let mut name = String::new();
292 for child in node.children() {
293 match child {
294 RedTree::Leaf(leaf) if leaf.kind == GoTokenType::Identifier => {
295 name = source.get_text_in(leaf.span).trim().to_string();
296 if !name.is_empty() {
297 break;
298 }
299 }
300 RedTree::Node(n) => {
301 println!("DEBUG: Identifier node has a Node child: kind={:?}, span={:?}", n.green.kind, n.span());
302 }
303 _ => {}
304 }
305 }
306 if name.is_empty() {
307 name = source.get_text_in(node.span()).trim().to_string();
308 }
309 if name.is_empty() {
310 println!("DEBUG: Final empty identifier node details:");
311 println!(" Node kind: {:?}", node.green.kind);
312 println!(" Node span: {:?}", node.span());
313 println!(" Children count: {}", node.children().count());
314 for (i, child) in node.children().enumerate() {
315 match child {
316 RedTree::Node(n) => println!(" child {}: Node kind={:?}, span={:?}", i, n.green.kind, n.span()),
317 RedTree::Leaf(l) => println!(" child {}: Leaf kind={:?}, span={:?}, text={:?}", i, l.kind, l.span, source.get_text_in(l.span)),
318 }
319 }
320 return Err(OakError::parse_error(format!("Empty identifier at {:?}", node.span())));
321 }
322 Ok(ast::Expression::Identifier { name, span: node.span() })
323 }
324 GoElementType::IntLiteral | GoElementType::StringLiteral | GoElementType::BoolLiteral => Ok(ast::Expression::Literal { value: source.get_text_in(node.span()).trim().to_string(), span: node.span() }),
325 GoElementType::BinaryExpression => {
326 let mut left = None;
327 let mut op = String::new();
328 let mut right = None;
329
330 for child in node.children() {
331 match child {
332 RedTree::Node(n) => {
333 if left.is_none() {
334 left = Some(Box::new(self.extract_expression(n, source)?));
335 }
336 else {
337 right = Some(Box::new(self.extract_expression(n, source)?));
338 }
339 }
340 RedTree::Leaf(leaf) => {
341 if leaf.kind == GoTokenType::Identifier {
342 if left.is_none() {
343 left = Some(Box::new(ast::Expression::Identifier { name: source.get_text_in(leaf.span).trim().to_string(), span: leaf.span }));
344 }
345 else {
346 right = Some(Box::new(ast::Expression::Identifier { name: source.get_text_in(leaf.span).trim().to_string(), span: leaf.span }));
347 }
348 }
349 else if TokenType::role(&leaf.kind) == oak_core::UniversalTokenRole::Operator {
350 op = source.get_text_in(leaf.span).to_string();
351 }
352 }
353 }
354 }
355
356 if let (Some(left), Some(right)) = (left, right) { Ok(ast::Expression::Binary { left, op, right, span: node.span() }) } else { Ok(ast::Expression::Literal { value: source.get_text_in(node.span()).to_string(), span: node.span() }) }
357 }
358 GoElementType::CallExpression => {
359 let mut func = None;
360 let mut args = vec![];
361
362 for child in node.children() {
363 match child {
364 RedTree::Node(n) => {
365 if func.is_none() {
366 func = Some(Box::new(self.extract_expression(n, source)?));
367 }
368 else if n.green.kind == GoElementType::ExpressionList {
369 for list_child in n.children() {
370 if let RedTree::Node(ln) = list_child {
371 args.push(self.extract_expression(ln, source)?);
372 }
373 else if let RedTree::Leaf(leaf) = list_child {
374 if let Ok(expr) = self.extract_expression_internal(RedTree::Leaf(leaf), source) {
375 args.push(expr);
376 }
377 }
378 }
379 }
380 else {
381 args.push(self.extract_expression(n, source)?);
382 }
383 }
384 RedTree::Leaf(leaf) if leaf.kind == GoTokenType::Identifier => {
385 if func.is_none() {
386 func = Some(Box::new(ast::Expression::Identifier { name: source.get_text_in(leaf.span).trim().to_string(), span: leaf.span }));
387 }
388 else {
389 args.push(ast::Expression::Identifier { name: source.get_text_in(leaf.span).trim().to_string(), span: leaf.span });
390 }
391 }
392 _ => {}
393 }
394 }
395
396 if let Some(func) = func { Ok(ast::Expression::Call { func, args, span: node.span() }) } else { Ok(ast::Expression::Literal { value: source.get_text_in(node.span()).to_string(), span: node.span() }) }
397 }
398 _ => Ok(ast::Expression::Literal { value: source.get_text_in(node.span()).to_string(), span: node.span() }),
399 },
400 }
401 }
402
403 fn extract_variables(&self, node: RedNode<GoLanguage>, source: &SourceText, cache: &mut impl BuilderCache<GoLanguage>) -> Result<Vec<Declaration>, OakError> {
404 if let Some(cached) = cache.get_typed_node::<Vec<Declaration>>(&node.green) {
405 return Ok(cached);
406 }
407 let mut vars = vec![];
408 for child in node.children() {
409 if let RedTree::Node(n) = child {
410 match n.green.kind {
411 GoElementType::VariableSpec => {
412 let mut name = String::new();
413 let mut var_type = None;
414 let mut value = None;
415 for spec_child in n.children() {
416 match spec_child {
417 RedTree::Leaf(leaf) if leaf.kind == GoTokenType::Identifier => {
418 if name.is_empty() {
419 name = source.get_text_in(leaf.span).trim().to_string();
420 }
421 else if var_type.is_none() {
422 var_type = Some(source.get_text_in(leaf.span).trim().to_string());
423 }
424 }
425 RedTree::Node(en) => {
426 value = Some(self.extract_expression(en, source)?);
427 }
428 _ => {}
429 }
430 }
431 vars.push(Declaration::Variable(ast::Variable { name, var_type, value, span: n.span() }));
432 }
433 _ => {
434 vars.extend(self.extract_variables(n, source, cache)?);
436 }
437 }
438 }
439 }
440 cache.set_typed_node(&node.green, std::sync::Arc::new(vars.clone()));
441 Ok(vars)
442 }
443
444 fn extract_consts(&self, node: RedNode<GoLanguage>, source: &SourceText, cache: &mut impl BuilderCache<GoLanguage>) -> Result<Vec<Declaration>, OakError> {
445 if let Some(cached) = cache.get_typed_node::<Vec<Declaration>>(&node.green) {
446 return Ok(cached);
447 }
448 let mut consts = vec![];
449 for child in node.children() {
450 if let RedTree::Node(n) = child {
451 match n.green.kind {
452 GoElementType::ConstSpec => {
453 let mut name = String::new();
454 let mut const_type = None;
455 let mut value = ast::Expression::Literal { value: "0".to_string(), span: n.span() };
456 for spec_child in n.children() {
457 match spec_child {
458 RedTree::Leaf(leaf) if leaf.kind == GoTokenType::Identifier => {
459 if name.is_empty() {
460 name = source.get_text_in(leaf.span).trim().to_string();
461 }
462 else if const_type.is_none() {
463 const_type = Some(source.get_text_in(leaf.span).trim().to_string());
464 }
465 }
466 RedTree::Node(en) => {
467 value = self.extract_expression(en, source)?;
468 }
469 _ => {}
470 }
471 }
472 consts.push(Declaration::Const(ast::Const { name, const_type, value, span: n.span() }));
473 }
474 _ => {
475 consts.extend(self.extract_consts(n, source, cache)?);
477 }
478 }
479 }
480 }
481 cache.set_typed_node(&node.green, std::sync::Arc::new(consts.clone()));
482 Ok(consts)
483 }
484
485 fn extract_types(&self, node: RedNode<GoLanguage>, source: &SourceText, cache: &mut impl BuilderCache<GoLanguage>) -> Result<Vec<Declaration>, OakError> {
486 if let Some(cached) = cache.get_typed_node::<Vec<Declaration>>(&node.green) {
487 return Ok(cached);
488 }
489 let mut types = vec![];
490 for child in node.children() {
491 if let RedTree::Node(n) = child {
492 match n.green.kind {
493 GoElementType::TypeSpec => {
494 let mut name = String::new();
495 let mut definition = String::new();
496 for spec_child in n.children() {
497 match spec_child {
498 RedTree::Leaf(leaf) if leaf.kind == GoTokenType::Identifier => {
499 if name.is_empty() {
500 name = source.get_text_in(leaf.span).trim().to_string();
501 }
502 else {
503 definition = source.get_text_in(leaf.span).trim().to_string();
504 }
505 }
506 RedTree::Node(tn) => {
507 definition = source.get_text_in(tn.span()).to_string();
508 }
509 _ => {}
510 }
511 }
512 types.push(Declaration::Type(ast::TypeDecl { name, definition, span: n.span() }));
513 }
514 _ => {
515 types.extend(self.extract_types(n, source, cache)?);
517 }
518 }
519 }
520 }
521 cache.set_typed_node(&node.green, std::sync::Arc::new(types.clone()));
522 Ok(types)
523 }
524}