1#![doc = include_str!("readme.md")]
2use crate::{CParser, ast::*, language::CLanguage, lexer::CTokenType, parser::CElementType};
3use oak_core::{Builder, BuilderCache, GreenNode, OakDiagnostics, OakError, Parser, RedNode, RedTree, SourceText, TextEdit, builder::BuildOutput, source::Source};
4
5mod build_type_system;
6
7#[derive(Clone, Copy)]
9pub struct CBuilder<'config> {
10 config: &'config CLanguage,
12}
13
14impl<'config> CBuilder<'config> {
15 pub fn new(config: &'config CLanguage) -> Self {
17 Self { config }
18 }
19}
20
21impl<'config> Builder<CLanguage> for CBuilder<'config> {
22 fn build<'a, S: Source + ?Sized>(&self, source: &S, edits: &[TextEdit], cache: &'a mut impl BuilderCache<CLanguage>) -> BuildOutput<CLanguage> {
24 let parser = CParser::new(self.config);
26
27 let parse_result = parser.parse(source, edits, cache);
29
30 match parse_result.result {
32 Ok(green_tree) => {
33 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 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 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 CElementType::Declarator => {
79 }
82 _ => {}
83 },
84 RedTree::Leaf(t) => match t.kind {
85 CTokenType::Int => declaration_specifiers.push(DeclarationSpecifier::TypeSpecifier(TypeSpecifier::Int { span: t.span.clone() })),
86 CTokenType::Void => declaration_specifiers.push(DeclarationSpecifier::TypeSpecifier(TypeSpecifier::Void { span: t.span.clone() })),
87 CTokenType::Identifier => {
88 let name = text(source, t.span.clone());
89 if declarator.is_none() {
90 declarator = Some(Declarator { pointer: None, direct_declarator: DirectDeclarator::Identifier(name, t.span.clone()), span: t.span.clone() })
91 }
92 }
93 _ => {}
94 },
95 }
96 }
97
98 let final_declarator = declarator.unwrap_or_else(|| Declarator { pointer: None, direct_declarator: DirectDeclarator::Identifier("main".to_string(), (0..0).into()), span: (0..0).into() });
99
100 let _canonical_type = self.build_type(&declaration_specifiers, &final_declarator, source);
102
103 Ok(FunctionDefinition { declaration_specifiers, declarator: final_declarator, compound_statement: compound_statement.unwrap_or_else(|| CompoundStatement { block_items: vec![], span: (0..0).into() }), span: node.span() })
104 }
105
106 fn build_declaration(&self, node: RedNode<CLanguage>, _source: &SourceText) -> Result<Declaration, OakError> {
108 Ok(Declaration { declaration_specifiers: vec![], init_declarators: vec![], span: node.span() })
109 }
110
111 fn build_compound_statement(&self, node: RedNode<CLanguage>, source: &SourceText) -> Result<CompoundStatement, OakError> {
112 let mut block_items = Vec::new();
113
114 self.collect_block_items(node, source, &mut block_items)?;
115
116 Ok(CompoundStatement { block_items, span: node.span() })
117 }
118
119 fn collect_block_items(&self, node: RedNode<CLanguage>, source: &SourceText, out: &mut Vec<BlockItem>) -> Result<(), OakError> {
120 for child in node.children() {
121 if let RedTree::Node(n) = child {
122 match n.green.kind {
123 CElementType::ReturnStatement => out.push(BlockItem::Statement(Statement::Jump(self.build_return_statement(n, source)?))),
124 CElementType::IfStatement => out.push(BlockItem::Statement(Statement::Selection(self.build_if_statement(n, source)?))),
125 CElementType::CompoundStatement => out.push(BlockItem::Statement(Statement::Compound(self.build_compound_statement(n, source)?))),
126 CElementType::ExpressionStatement => {
127 if let Some(expr) = self.build_expression(n, source)? {
128 out.push(BlockItem::Statement(Statement::Expression(ExpressionStatement { expression: Some(expr), span: n.span() })))
129 }
130 }
131 _ => self.collect_block_items(n, source, out)?,
132 }
133 }
134 }
135 Ok(())
136 }
137
138 fn build_if_statement(&self, node: RedNode<CLanguage>, source: &SourceText) -> Result<SelectionStatement, OakError> {
139 let mut condition = None;
140 let mut then_statement = None;
141 let mut else_statement = None;
142
143 fn scan<'config>(builder: &CBuilder<'config>, node: &RedNode<CLanguage>, source: &SourceText, condition: &mut Option<Expression>, then_statement: &mut Option<Statement>, else_statement: &mut Option<Statement>) -> Result<(), OakError> {
144 for child in node.children() {
145 if let RedTree::Node(n) = child {
146 match n.green.kind {
147 CElementType::ExpressionStatement => {
148 if condition.is_none() {
149 *condition = builder.build_expression(n.clone(), source)?;
150 }
151 }
152 CElementType::CompoundStatement => {
153 let stmt = Statement::Compound(builder.build_compound_statement(n.clone(), source)?);
154 if then_statement.is_none() {
155 *then_statement = Some(stmt);
156 }
157 else if else_statement.is_none() {
158 *else_statement = Some(stmt);
159 }
160 }
161 CElementType::IfStatement => {
162 let stmt = Statement::Selection(builder.build_if_statement(n.clone(), source)?);
163 if then_statement.is_none() {
164 *then_statement = Some(stmt);
165 }
166 else if else_statement.is_none() {
167 *else_statement = Some(stmt);
168 }
169 }
170 _ => {}
171 }
172 if condition.is_none() {
173 *condition = builder.build_expression(n.clone(), source)?;
174 }
175 scan(builder, &n, source, condition, then_statement, else_statement)?;
176 }
177 }
178 Ok(())
179 }
180
181 scan(self, &node, source, &mut condition, &mut then_statement, &mut else_statement)?;
182
183 Ok(SelectionStatement::If {
184 condition: condition.unwrap_or(Expression { kind: Box::new(ExpressionKind::Constant(Constant::Integer(0, node.span()), node.span())), span: node.span() }),
185 then_statement: Box::new(then_statement.unwrap_or_else(|| Statement::Compound(CompoundStatement { block_items: vec![], span: node.span() }))),
186 else_statement: else_statement.map(Box::new),
187 span: node.span(),
188 })
189 }
190
191 fn build_return_statement(&self, node: RedNode<CLanguage>, source: &SourceText) -> Result<JumpStatement, OakError> {
192 let mut expression = None;
193 for child in node.children() {
194 match child {
195 RedTree::Node(n) => {
196 if expression.is_none() {
197 expression = self.build_expression(n, source)?
198 }
199 }
200 RedTree::Leaf(t) => {
201 if t.kind == CTokenType::IntConstant {
202 let val = text(source, t.span.clone());
203 let int_val = val.parse::<i64>().unwrap_or(0);
204 expression = Some(Expression { kind: Box::new(ExpressionKind::Constant(Constant::Integer(int_val, t.span.clone()), t.span.clone())), span: t.span.clone() })
205 }
206 }
207 }
208 }
209 Ok(JumpStatement::Return(expression, node.span()))
210 }
211
212 fn build_expression(&self, node: RedNode<CLanguage>, source: &SourceText) -> Result<Option<Expression>, OakError> {
213 for child in node.children() {
214 match child {
215 RedTree::Leaf(t) => match t.kind {
216 CTokenType::IntConstant => {
217 let val = text(source, t.span.clone());
218 let int_val = val.parse::<i64>().unwrap_or(0);
219 return Ok(Some(Expression { kind: Box::new(ExpressionKind::Constant(Constant::Integer(int_val, t.span.clone()), t.span.clone())), span: t.span.clone() }));
220 }
221 CTokenType::Identifier => {
222 let name = text(source, t.span.clone());
223 return Ok(Some(Expression { kind: Box::new(ExpressionKind::Identifier(name, t.span.clone())), span: t.span.clone() }));
224 }
225 _ => {}
226 },
227 RedTree::Node(n) => {
228 if let Some(expr) = self.build_expression(n, source)? {
230 return Ok(Some(expr));
231 }
232 }
233 }
234 }
235 Ok(None)
236 }
237}
238
239fn text(source: &SourceText, span: core::range::Range<usize>) -> String {
240 source.get_text_in(span).to_string()
241}