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