1use crate::{ast::*, language::CSharpLanguage, lexer::token_type::CSharpTokenType, parser::CSharpElementType};
2use core::range::Range;
3use oak_core::{
4 GreenNode, Parser, TokenType,
5 builder::{BuildOutput, Builder, BuilderCache},
6 source::{Source, TextEdit},
7 tree::red_tree::{RedNode, RedTree},
8};
9
10pub struct CSharpBuilder<'config> {
11 language: &'config CSharpLanguage,
12}
13
14impl<'config> CSharpBuilder<'config> {
15 pub fn new(language: &'config CSharpLanguage) -> Self {
16 Self { language }
17 }
18
19 fn build_root(&self, green: &GreenNode<CSharpLanguage>, source: &str) -> CSharpRoot {
20 let red = RedNode::new(green, 0);
21 let mut items = Vec::new();
22
23 for child in red.children() {
24 if let RedTree::Node(node) = child {
25 if let Some(item) = self.build_item(node, source) {
26 items.push(item);
27 }
28 }
29 }
30
31 CSharpRoot { items }
32 }
33
34 fn build_item(&self, node: RedNode<CSharpLanguage>, source: &str) -> Option<Item> {
35 match node.green.kind {
36 CSharpElementType::NamespaceDeclaration => Some(Item::Namespace(self.build_namespace(node, source))),
37 CSharpElementType::UsingDirective => Some(Item::Using(self.build_using(node, source))),
38 CSharpElementType::ClassDeclaration => Some(Item::Class(self.build_class(node, source))),
39 CSharpElementType::InterfaceDeclaration => Some(Item::Interface(self.build_interface(node, source))),
40 CSharpElementType::StructDeclaration => Some(Item::Struct(self.build_struct(node, source))),
41 CSharpElementType::EnumDeclaration => Some(Item::Enum(self.build_enum(node, source))),
42 CSharpElementType::RecordDeclaration => Some(Item::Record(self.build_record(node, source))),
43 CSharpElementType::DelegateDeclaration => Some(Item::Delegate(self.build_delegate(node, source))),
44 _ => None,
45 }
46 }
47
48 fn get_text<'a>(&self, span: Range<usize>, source: &'a str) -> &'a str {
49 let start = span.start;
50 let end = span.end;
51 if start > source.len() || end > source.len() || start > end {
52 return "";
53 }
54 &source[start..end]
55 }
56
57 fn extract_identifier(&self, node: RedNode<CSharpLanguage>, source: &str) -> String {
58 for child in node.children() {
59 match child {
60 RedTree::Leaf(leaf) => {
61 if leaf.kind == CSharpTokenType::Identifier {
62 return self.get_text(leaf.span, source).trim().to_string();
63 }
64 }
65 RedTree::Node(sub_node) => {
66 if sub_node.kind::<CSharpElementType>() == CSharpElementType::IdentifierName {
67 return self.get_text(sub_node.span(), source).trim().to_string();
68 }
69 let id = self.extract_identifier(sub_node, source);
70 if !id.is_empty() {
71 return id;
72 }
73 }
74 }
75 }
76 String::new()
77 }
78
79 fn extract_attributes(&self, node: RedNode<CSharpLanguage>, source: &str) -> Vec<Attribute> {
80 let mut attributes = Vec::new();
81 for child in node.children() {
82 if let RedTree::Node(sub_node) = child {
83 if sub_node.green.kind == CSharpElementType::AttributeList {
84 for attr_child in sub_node.children() {
85 if let RedTree::Node(attr_node) = attr_child {
86 if attr_node.green.kind == CSharpElementType::Attribute {
87 let name = self.extract_identifier(attr_node.clone(), source);
88 let mut arguments = Vec::new();
89 attributes.push(Attribute { name, arguments })
91 }
92 }
93 }
94 }
95 }
96 }
97 attributes
98 }
99
100 fn build_namespace(&self, node: RedNode<CSharpLanguage>, source: &str) -> NamespaceDeclaration {
101 let name = self.extract_identifier(node.clone(), source);
102 let attributes = self.extract_attributes(node.clone(), source);
103 let mut items = Vec::new();
104
105 for child in node.children() {
106 if let RedTree::Node(sub_node) = child {
107 if let Some(item) = self.build_item(sub_node, source) {
108 items.push(item)
109 }
110 }
111 }
112
113 NamespaceDeclaration { name, attributes, items, span: node.span() }
114 }
115
116 fn build_using(&self, node: RedNode<CSharpLanguage>, source: &str) -> UsingDirective {
117 let path = self.extract_identifier(node.clone(), source);
118 let is_static = self.get_text(node.span(), source).contains("static");
119 let is_global = self.get_text(node.span(), source).contains("global");
120 UsingDirective {
121 path,
122 is_static,
123 alias: None, is_global,
125 span: node.span(),
126 }
127 }
128
129 fn build_class(&self, node: RedNode<CSharpLanguage>, source: &str) -> ClassDeclaration {
130 let name = self.extract_identifier(node.clone(), source);
131 let mut members = Vec::new();
132 let modifiers = self.extract_modifiers(node.clone(), source);
133 let attributes = self.extract_attributes(node.clone(), source);
134
135 for child in node.children() {
136 if let RedTree::Node(sub_node) = child {
137 self.collect_members(sub_node, source, &mut members)
138 }
139 }
140
141 ClassDeclaration { name, attributes, modifiers, base_types: Vec::new(), type_parameters: Vec::new(), constraints: Vec::new(), members, span: node.span() }
142 }
143
144 fn build_interface(&self, node: RedNode<CSharpLanguage>, source: &str) -> InterfaceDeclaration {
145 let name = self.extract_identifier(node.clone(), source);
146 let modifiers = self.extract_modifiers(node.clone(), source);
147 let attributes = self.extract_attributes(node.clone(), source);
148 let mut members = Vec::new();
149 for child in node.children() {
150 if let RedTree::Node(sub_node) = child {
151 self.collect_members(sub_node, source, &mut members)
152 }
153 }
154 InterfaceDeclaration { name, attributes, modifiers, members, type_parameters: Vec::new(), span: node.span() }
155 }
156
157 fn build_struct(&self, node: RedNode<CSharpLanguage>, source: &str) -> StructDeclaration {
158 let name = self.extract_identifier(node.clone(), source);
159 let modifiers = self.extract_modifiers(node.clone(), source);
160 let attributes = self.extract_attributes(node.clone(), source);
161 let mut members = Vec::new();
162 for child in node.children() {
163 if let RedTree::Node(sub_node) = child {
164 self.collect_members(sub_node, source, &mut members)
165 }
166 }
167 StructDeclaration { name, attributes, modifiers, members, type_parameters: Vec::new(), span: node.span() }
168 }
169
170 fn build_enum(&self, node: RedNode<CSharpLanguage>, source: &str) -> EnumDeclaration {
171 let name = self.extract_identifier(node.clone(), source);
172 let modifiers = self.extract_modifiers(node.clone(), source);
173 let attributes = self.extract_attributes(node.clone(), source);
174 let mut members = Vec::new();
175 for child in node.children() {
177 if let RedTree::Node(sub_node) = child {
178 if sub_node.kind::<CSharpElementType>() == CSharpElementType::IdentifierName {
179 members.push(EnumMember { name: self.get_text(sub_node.span(), source).to_string(), attributes: Vec::new(), value: None })
180 }
181 }
182 }
183 EnumDeclaration { name, attributes, modifiers, members, span: node.span() }
184 }
185
186 fn build_record(&self, node: RedNode<CSharpLanguage>, source: &str) -> RecordDeclaration {
187 let name = self.extract_identifier(node.clone(), source);
188 let modifiers = self.extract_modifiers(node.clone(), source);
189 let attributes = self.extract_attributes(node.clone(), source);
190 let mut members = Vec::new();
191 for child in node.children() {
192 if let RedTree::Node(sub_node) = child {
193 self.collect_members(sub_node, source, &mut members)
194 }
195 }
196 RecordDeclaration { name, attributes, modifiers, members, type_parameters: Vec::new(), span: node.span() }
197 }
198
199 fn build_delegate(&self, node: RedNode<CSharpLanguage>, source: &str) -> DelegateDeclaration {
200 let name = self.extract_identifier(node.clone(), source);
201 let modifiers = self.extract_modifiers(node.clone(), source);
202 let attributes = self.extract_attributes(node.clone(), source);
203 DelegateDeclaration { name, attributes, modifiers, return_type: "void".to_string(), type_parameters: Vec::new(), parameters: Vec::new(), span: node.span() }
204 }
205
206 fn extract_modifiers(&self, node: RedNode<CSharpLanguage>, source: &str) -> Vec<String> {
207 let mut modifiers = Vec::new();
208 for child in node.children() {
209 if let RedTree::Leaf(leaf) = child {
210 if leaf.kind.is_keyword() {
211 let text = self.get_text(leaf.span, source).trim();
212 match text {
213 "public" | "private" | "protected" | "internal" | "static" | "readonly" | "abstract" | "virtual" | "override" | "async" | "volatile" | "sealed" | "extern" | "partial" | "new" | "unsafe" => modifiers.push(text.to_string()),
214 _ => {}
215 }
216 }
217 }
218 }
219 modifiers
220 }
221
222 fn collect_members(&self, node: RedNode<CSharpLanguage>, source: &str, members: &mut Vec<Member>) {
223 match node.green.kind {
224 CSharpElementType::MethodDeclaration => members.push(Member::Method(self.build_method(node, source))),
225 CSharpElementType::FieldDeclaration => members.push(Member::Field(self.build_field(node, source))),
226 CSharpElementType::PropertyDeclaration => members.push(Member::Property(self.build_property(node, source))),
227 CSharpElementType::IndexerDeclaration => members.push(Member::Indexer(self.build_indexer(node, source))),
228 CSharpElementType::EventDeclaration => members.push(Member::Event(self.build_event(node, source))),
229 _ => {
230 for child in node.children() {
231 if let RedTree::Node(sub_node) = child {
232 self.collect_members(sub_node, source, members)
233 }
234 }
235 }
236 }
237 }
238
239 fn build_method(&self, node: RedNode<CSharpLanguage>, source: &str) -> MethodDeclaration {
240 let name = self.extract_identifier(node.clone(), source);
241 let modifiers = self.extract_modifiers(node.clone(), source);
242 let attributes = self.extract_attributes(node.clone(), source);
243 let is_async = modifiers.contains(&"async".to_string());
244
245 MethodDeclaration {
246 name,
247 attributes,
248 modifiers,
249 return_type: "void".to_string(), type_parameters: Vec::new(), parameters: Vec::new(), body: self.build_body(node.clone(), source),
253 is_async,
254 span: node.span(),
255 }
256 }
257
258 fn build_field(&self, node: RedNode<CSharpLanguage>, source: &str) -> FieldDeclaration {
259 let name = self.extract_identifier(node.clone(), source);
260 let attributes = self.extract_attributes(node.clone(), source);
261 FieldDeclaration {
262 name,
263 attributes,
264 r#type: "object".to_string(), modifiers: self.extract_modifiers(node, source),
266 initializer: None, span: Range::default(),
268 }
269 }
270
271 fn build_property(&self, node: RedNode<CSharpLanguage>, source: &str) -> PropertyDeclaration {
272 let name = self.extract_identifier(node.clone(), source);
273 let attributes = self.extract_attributes(node.clone(), source);
274 PropertyDeclaration {
275 name,
276 attributes,
277 r#type: "object".to_string(), modifiers: self.extract_modifiers(node, source),
279 get_accessor: None, set_accessor: None, span: node.span(),
282 }
283 }
284
285 fn build_indexer(&self, node: RedNode<CSharpLanguage>, source: &str) -> IndexerDeclaration {
286 let attributes = self.extract_attributes(node.clone(), source);
287 IndexerDeclaration {
288 attributes,
289 r#type: "object".to_string(), parameters: Vec::new(), get_accessor: None, set_accessor: None, span: node.span(),
294 }
295 }
296
297 fn build_event(&self, node: RedNode<CSharpLanguage>, source: &str) -> EventDeclaration {
298 let name = self.extract_identifier(node.clone(), source);
299 let attributes = self.extract_attributes(node.clone(), source);
300 EventDeclaration {
301 name,
302 attributes,
303 r#type: "object".to_string(), modifiers: self.extract_modifiers(node, source),
305 span: node.span(),
306 }
307 }
308
309 fn build_body(&self, node: RedNode<CSharpLanguage>, source: &str) -> Option<Vec<Statement>> {
310 for child in node.children() {
311 if let RedTree::Node(sub_node) = child {
312 if sub_node.green.kind == CSharpElementType::Block {
313 let mut statements = Vec::new();
314 for grandchild in sub_node.children() {
315 if let RedTree::Node(grandchild_node) = grandchild {
316 if let Some(stmt) = self.build_statement(grandchild_node, source) {
317 statements.push(stmt)
318 }
319 }
320 }
321 return Some(statements);
322 }
323 }
324 }
325 None
326 }
327
328 fn build_statement(&self, node: RedNode<CSharpLanguage>, source: &str) -> Option<Statement> {
329 match node.green.kind {
330 CSharpElementType::ExpressionStatement => {
331 for child in node.children() {
332 if let RedTree::Node(sub_node) = child {
333 if let Some(expr) = self.build_expression(sub_node, source) {
334 return Some(Statement::Expression(expr));
335 }
336 }
337 }
338 None
339 }
340 CSharpElementType::ReturnStatement => {
341 for child in node.children() {
342 if let RedTree::Node(sub_node) = child {
343 if let Some(expr) = self.build_expression(sub_node, source) {
344 return Some(Statement::Return(Some(expr)));
345 }
346 }
347 }
348 Some(Statement::Return(None))
349 }
350 CSharpElementType::Block => {
351 let mut statements = Vec::new();
352 for child in node.children() {
353 if let RedTree::Node(sub_node) = child {
354 if let Some(stmt) = self.build_statement(sub_node, source) {
355 statements.push(stmt)
356 }
357 }
358 }
359 Some(Statement::Block(statements))
360 }
361 CSharpElementType::IfStatement => {
362 Some(Statement::If { condition: Expression::Literal(Literal::Boolean(true)), then_branch: Box::new(Statement::Block(Vec::new())), else_branch: None })
364 }
365 CSharpElementType::BreakStatement => Some(Statement::Break),
366 CSharpElementType::ContinueStatement => Some(Statement::Continue),
367 _ => None,
368 }
369 }
370
371 fn build_expression(&self, node: RedNode<CSharpLanguage>, source: &str) -> Option<Expression> {
372 match node.green.kind {
373 CSharpElementType::LiteralExpression => {
374 let text = self.get_text(node.span(), source).trim();
375 if text == "true" {
376 Some(Expression::Literal(Literal::Boolean(true)))
377 }
378 else if text == "false" {
379 Some(Expression::Literal(Literal::Boolean(false)))
380 }
381 else if text == "null" {
382 Some(Expression::Literal(Literal::Null))
383 }
384 else if let Ok(n) = text.parse::<i64>() {
385 Some(Expression::Literal(Literal::Integer(n)))
386 }
387 else {
388 Some(Expression::Literal(Literal::String(text.to_string())))
389 }
390 }
391 CSharpElementType::IdentifierName => Some(Expression::Identifier(self.get_text(node.span(), source).trim().to_string())),
392 CSharpElementType::AwaitExpression => {
393 for child in node.children() {
394 if let RedTree::Node(sub_node) = child {
395 if let Some(expr) = self.build_expression(sub_node, source) {
396 return Some(Expression::Await(Box::new(expr)));
397 }
398 }
399 }
400 None
401 }
402 _ => None,
403 }
404 }
405}
406
407impl<'config> Builder<CSharpLanguage> for CSharpBuilder<'config> {
408 fn build<'a, S: Source + ?Sized>(&self, source: &'a S, edits: &[TextEdit], cache: &'a mut impl BuilderCache<CSharpLanguage>) -> BuildOutput<CSharpLanguage> {
409 let mut session = oak_core::parser::ParseSession::<CSharpLanguage>::default();
410 let parser = crate::parser::CSharpParser::new(self.language);
411 let output = parser.parse(source, edits, &mut session);
412
413 let mut result = Err(oak_core::OakError::custom_error("Build failed"));
414 if let Ok(green) = &output.result {
415 let root = self.build_root(green, source.get_text_in((0..source.length()).into()).as_ref());
416 result = Ok(root)
417 }
418
419 oak_core::errors::OakDiagnostics { result, diagnostics: output.diagnostics }
420 }
421}