Skip to main content

oak_c/builder/
mod.rs

1#![doc = include_str!("readme.md")]
2use crate::{CParser, ast::*, language::CLanguage, lexer::CTokenType, parser::CElementType};
3use core::range::Range;
4use oak_core::{Builder, BuilderCache, GreenNode, OakDiagnostics, OakError, Parser, RedNode, RedTree, SourceText, TextEdit, builder::BuildOutput, source::Source};
5
6/// AST builder for the C language.
7#[derive(Clone, Copy)]
8pub struct CBuilder<'config> {
9    /// Language configuration.
10    config: &'config CLanguage,
11}
12
13impl<'config> CBuilder<'config> {
14    /// Creates a new `CBuilder` with the given language configuration.
15    pub fn new(config: &'config CLanguage) -> Self {
16        Self { config }
17    }
18}
19
20impl<'config> Builder<CLanguage> for CBuilder<'config> {
21    /// Builds the C AST from the green tree.
22    fn build<'a, S: Source + ?Sized>(&self, source: &S, edits: &[TextEdit], _cache: &'a mut impl BuilderCache<CLanguage>) -> BuildOutput<CLanguage> {
23        // Parse source code to get green tree.
24        let parser = CParser::new(self.config);
25
26        // TODO: Real incremental build should use BuilderCache.
27        let mut cache = oak_core::parser::session::ParseSession::<CLanguage>::default();
28        let parse_result = parser.parse(source, edits, &mut cache);
29
30        // Check if parsing succeeded.
31        match parse_result.result {
32            Ok(green_tree) => {
33                // Build AST.
34                let source_text = SourceText::new(source.get_text_in((0..source.length()).into()).into_owned());
35                match self.build_root(green_tree, &source_text) {
36                    Ok(ast_root) => OakDiagnostics { result: Ok(ast_root), diagnostics: parse_result.diagnostics },
37                    Err(build_error) => {
38                        let mut diagnostics = parse_result.diagnostics;
39                        diagnostics.push(build_error.clone());
40                        OakDiagnostics { result: Err(build_error), diagnostics }
41                    }
42                }
43            }
44            Err(parse_error) => OakDiagnostics { result: Err(parse_error), diagnostics: parse_result.diagnostics },
45        }
46    }
47}
48
49impl<'config> CBuilder<'config> {
50    /// Builds the AST root from the green tree.
51    pub(crate) fn build_root<'a>(&self, green_tree: &'a GreenNode<'a, CLanguage>, source: &SourceText) -> Result<CRoot, OakError> {
52        let root_node = RedNode::new(green_tree, 0);
53        let mut external_declarations = Vec::new();
54
55        for child in root_node.children() {
56            if let RedTree::Node(n) = child {
57                match n.green.kind {
58                    CElementType::FunctionDefinition => external_declarations.push(ExternalDeclaration::FunctionDefinition(self.build_function_definition(n, source)?)),
59                    CElementType::DeclarationStatement => external_declarations.push(ExternalDeclaration::Declaration(self.build_declaration(n, source)?)),
60                    _ => {}
61                }
62            }
63        }
64
65        Ok(CRoot { translation_unit: TranslationUnit { external_declarations, span: root_node.span() }, span: root_node.span() })
66    }
67
68    /// Builds a function definition from a red node.
69    fn build_function_definition(&self, node: RedNode<CLanguage>, source: &SourceText) -> Result<FunctionDefinition, OakError> {
70        let mut declaration_specifiers = Vec::new();
71        let mut declarator = None;
72        let mut compound_statement = None;
73
74        for child in node.children() {
75            match child {
76                RedTree::Node(n) => match n.green.kind {
77                    CElementType::CompoundStatement => compound_statement = Some(self.build_compound_statement(n, source)?),
78                    _ => {}
79                },
80                RedTree::Leaf(t) => match t.kind {
81                    CTokenType::Int => declaration_specifiers.push(DeclarationSpecifier::TypeSpecifier(TypeSpecifier::Int { span: t.span.clone() })),
82                    CTokenType::Void => declaration_specifiers.push(DeclarationSpecifier::TypeSpecifier(TypeSpecifier::Void { span: t.span.clone() })),
83                    CTokenType::Identifier => {
84                        let name = text(source, t.span.clone());
85                        declarator = Some(Declarator { pointer: None, direct_declarator: DirectDeclarator::Identifier(name, t.span.clone()), span: t.span.clone() })
86                    }
87                    _ => {}
88                },
89                _ => {}
90            }
91        }
92
93        Ok(FunctionDefinition {
94            declaration_specifiers,
95            declarator: declarator.unwrap_or_else(|| Declarator { pointer: None, direct_declarator: DirectDeclarator::Identifier("main".to_string(), (0..0).into()), span: (0..0).into() }),
96            compound_statement: compound_statement.unwrap_or_else(|| CompoundStatement { block_items: vec![], span: (0..0).into() }),
97            span: node.span(),
98        })
99    }
100
101    fn build_declaration(&self, node: RedNode<CLanguage>, source: &SourceText) -> Result<Declaration, OakError> {
102        Ok(Declaration { declaration_specifiers: vec![], init_declarators: vec![], span: node.span() })
103    }
104
105    fn build_compound_statement(&self, node: RedNode<CLanguage>, source: &SourceText) -> Result<CompoundStatement, OakError> {
106        let mut block_items = Vec::new();
107
108        for child in node.children() {
109            if let RedTree::Node(n) = child {
110                match n.green.kind {
111                    CElementType::ReturnStatement => block_items.push(BlockItem::Statement(Statement::Jump(self.build_return_statement(n, source)?))),
112                    CElementType::ExpressionStatement => {
113                        if let Some(expr) = self.build_expression(n, source)? {
114                            block_items.push(BlockItem::Statement(Statement::Expression(ExpressionStatement { expression: Some(expr), span: n.span() })))
115                        }
116                    }
117                    _ => {}
118                }
119            }
120        }
121
122        Ok(CompoundStatement { block_items, span: node.span() })
123    }
124
125    fn build_return_statement(&self, node: RedNode<CLanguage>, source: &SourceText) -> Result<JumpStatement, OakError> {
126        let mut expression = None;
127        for child in node.children() {
128            match child {
129                RedTree::Node(n) => {
130                    if n.green.kind == CElementType::ExpressionStatement {
131                        expression = self.build_expression(n, source)?
132                    }
133                }
134                RedTree::Leaf(t) => {
135                    if t.kind == CTokenType::IntegerLiteral {
136                        let val = text(source, t.span.clone());
137                        let int_val = val.parse::<i64>().unwrap_or(0);
138                        expression = Some(Expression { kind: Box::new(ExpressionKind::Constant(Constant::Integer(int_val, t.span.clone()), t.span.clone())), span: t.span.clone() })
139                    }
140                }
141                _ => {}
142            }
143        }
144        Ok(JumpStatement::Return(expression, node.span()))
145    }
146
147    fn build_expression(&self, node: RedNode<CLanguage>, source: &SourceText) -> Result<Option<Expression>, OakError> {
148        for child in node.children() {
149            match child {
150                RedTree::Leaf(t) => match t.kind {
151                    CTokenType::IntegerLiteral => {
152                        let val = text(source, t.span.clone());
153                        let int_val = val.parse::<i64>().unwrap_or(0);
154                        return Ok(Some(Expression { kind: Box::new(ExpressionKind::Constant(Constant::Integer(int_val, t.span.clone()), t.span.clone())), span: t.span.clone() }));
155                    }
156                    CTokenType::Identifier => {
157                        let name = text(source, t.span.clone());
158                        return Ok(Some(Expression { kind: Box::new(ExpressionKind::Identifier(name, t.span.clone())), span: t.span.clone() }));
159                    }
160                    _ => {}
161                },
162                RedTree::Node(n) => {
163                    // 递归处理表达式子节点
164                    if let Some(expr) = self.build_expression(n, source)? {
165                        return Ok(Some(expr));
166                    }
167                }
168                _ => {}
169            }
170        }
171        Ok(None)
172    }
173}
174
175fn text(source: &SourceText, span: core::range::Range<usize>) -> String {
176    source.get_text_in(span).to_string()
177}