Skip to main content

oak_go/builder/
mod.rs

1//! Go 语言构建器
2
3use 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
16/// Go 语言构建器
17pub 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                        // 处理 import ( ... )
95                        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                                // 处理 else if
202                                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                // 支持多重赋值
244                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                                // 递归提取
255                                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                // 如果没有值(如变量声明),填充默认值
276                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                // 可能是表达式语句
286                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                        // 处理 var ( ... )
455                        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                        // 处理 const ( ... )
492                        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                        // 处理 type ( ... )
528                        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}