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