1#![doc = include_str!("readme.md")]
2
3use crate::{ast::*, language::VbNetLanguage, lexer::token_type::VbNetTokenType, parser::element_type::VbNetElementType};
4use oak_core::{
5 builder::Builder,
6 parser::Parser,
7 source::Source,
8 tree::{GreenNode, GreenTree},
9};
10
11pub struct VbNetBuilder<'config> {
13 config: &'config VbNetLanguage,
14}
15
16impl<'config> VbNetBuilder<'config> {
17 pub fn new(config: &'config VbNetLanguage) -> Self {
19 Self { config }
20 }
21}
22
23impl<'config> Builder<VbNetLanguage> for VbNetBuilder<'config> {
24 fn build<'a, S: Source + ?Sized>(&self, source: &'a S, edits: &[oak_core::TextEdit], cache: &'a mut impl oak_core::builder::BuilderCache<VbNetLanguage>) -> oak_core::builder::BuildOutput<VbNetLanguage> {
25 let parser = crate::parser::VbNetParser::new(self.config);
26 let parse_output = parser.parse(source, edits, cache);
27
28 match parse_output.result {
29 Ok(green_node) => {
30 let ast = self.build_ast(&green_node, source);
31 oak_core::errors::OakDiagnostics { result: Ok(ast), diagnostics: parse_output.diagnostics }
32 }
33 Err(err) => oak_core::errors::OakDiagnostics { result: Err(err), diagnostics: parse_output.diagnostics },
34 }
35 }
36}
37
38impl<'config> VbNetBuilder<'config> {
39 fn build_ast<'a, S: Source + ?Sized>(&self, node: &GreenNode<'a, VbNetLanguage>, source: &'a S) -> VbNetRoot {
40 let mut items = Vec::new();
41 self.build_items(node, source, &mut items);
42 VbNetRoot { items }
43 }
44
45 fn build_items<'a, S: Source + ?Sized>(&self, node: &GreenNode<'a, VbNetLanguage>, source: &'a S, items: &mut Vec<Item>) {
46 for child in node.children() {
47 match child {
48 GreenTree::Node(child_node) => {
49 match child_node.kind() {
50 VbNetElementType::Namespace => {
51 if let Some(namespace) = self.build_namespace(child_node, source) {
52 items.push(Item::Namespace(namespace));
53 }
54 }
55 VbNetElementType::Imports => {
56 if let Some(imports) = self.build_imports(child_node, source) {
57 items.push(Item::Imports(imports));
58 }
59 }
60 VbNetElementType::Class => {
61 if let Some(class) = self.build_class(child_node, source) {
62 items.push(Item::Class(class));
63 }
64 }
65 VbNetElementType::Function => {
66 if let Some(function) = self.build_function(child_node, source) {
67 items.push(Item::Function(function));
68 }
69 }
70 VbNetElementType::Sub => {
71 if let Some(sub) = self.build_sub(child_node, source) {
72 items.push(Item::Sub(sub));
73 }
74 }
75 VbNetElementType::Property => {
76 if let Some(property) = self.build_property(child_node, source) {
77 items.push(Item::Property(property));
78 }
79 }
80 VbNetElementType::Dim => {
81 if let Some(variable) = self.build_variable(child_node, source) {
82 items.push(Item::Variable(variable));
83 }
84 }
85 _ => {
86 self.build_items(child_node, source, items);
88 }
89 }
90 }
91 GreenTree::Leaf(_) => {
92 }
94 }
95 }
96 }
97
98 fn build_namespace<'a, S: Source + ?Sized>(&self, node: &GreenNode<'a, VbNetLanguage>, source: &'a S) -> Option<NamespaceDeclaration> {
99 let mut name = String::new();
100 let mut items = Vec::new();
101 let span = (0..node.text_len() as usize).into();
102 let mut current_offset = 0;
103
104 for child in node.children() {
105 match child {
106 GreenTree::Leaf(leaf) => {
107 if leaf.kind() == VbNetTokenType::Identifier {
108 let leaf_start = current_offset;
109 let leaf_end = current_offset + leaf.length() as usize;
110 name = source.get_text_in((leaf_start..leaf_end).into()).to_string();
111 }
112 }
113 GreenTree::Node(child_node) => {
114 self.build_items(child_node, source, &mut items);
115 }
116 }
117 current_offset += child.len() as usize;
118 }
119
120 Some(NamespaceDeclaration { name, items, span })
121 }
122
123 fn build_imports<'a, S: Source + ?Sized>(&self, node: &GreenNode<'a, VbNetLanguage>, source: &'a S) -> Option<ImportsDirective> {
124 let mut path = String::new();
125 let span = (0..node.text_len() as usize).into();
126 let mut current_offset = 0;
127 let mut found_imports = false;
128
129 for child in node.children() {
130 match child {
131 GreenTree::Leaf(leaf) => {
132 if leaf.kind() == VbNetTokenType::Imports {
133 found_imports = true;
134 }
135 else if found_imports && leaf.kind() == VbNetTokenType::Identifier {
136 if !path.is_empty() {
137 path.push('.');
138 }
139 let leaf_start = current_offset;
140 let leaf_end = current_offset + leaf.length() as usize;
141 path.push_str(&source.get_text_in((leaf_start..leaf_end).into()));
142 }
143 else if found_imports && leaf.kind() == VbNetTokenType::Dot {
144 path.push('.');
145 }
146 }
147 GreenTree::Node(_) => {}
148 }
149 current_offset += child.len() as usize;
150 }
151
152 Some(ImportsDirective { path, alias: None, span })
153 }
154
155 fn build_class<'a, S: Source + ?Sized>(&self, node: &GreenNode<'a, VbNetLanguage>, source: &'a S) -> Option<ClassDeclaration> {
156 let mut name = String::new();
157 let mut attributes = Vec::new();
158 let mut modifiers = Vec::new();
159 let mut base_types = Vec::new();
160 let mut members = Vec::new();
161 let span = (0..node.text_len() as usize).into();
162 let mut current_offset = 0;
163 let mut skipped_class = false;
164
165 for child in node.children() {
166 match child {
167 GreenTree::Leaf(leaf) => match leaf.kind() {
168 VbNetTokenType::Class => {
169 skipped_class = true;
170 }
171 VbNetTokenType::Identifier if skipped_class => {
172 if name.is_empty() {
173 let leaf_start = current_offset;
174 let leaf_end = current_offset + leaf.length() as usize;
175 name = source.get_text_in((leaf_start..leaf_end).into()).to_string();
176 }
177 }
178 VbNetTokenType::Public | VbNetTokenType::Private | VbNetTokenType::Protected | VbNetTokenType::Friend | VbNetTokenType::Shared | VbNetTokenType::MustInherit | VbNetTokenType::NotInheritable | VbNetTokenType::Partial => {
179 let leaf_start = current_offset;
180 let leaf_end = current_offset + leaf.length() as usize;
181 modifiers.push(source.get_text_in((leaf_start..leaf_end).into()).to_string());
182 }
183 _ => {}
184 },
185 GreenTree::Node(child_node) => {
186 self.build_members(child_node, source, &mut members);
187 }
188 }
189 current_offset += child.len() as usize;
190 }
191
192 Some(ClassDeclaration { name, attributes, modifiers, base_types, members, span })
193 }
194
195 fn build_function<'a, S: Source + ?Sized>(&self, node: &GreenNode<'a, VbNetLanguage>, source: &'a S) -> Option<FunctionDeclaration> {
196 let mut name = String::new();
197 let mut attributes = Vec::new();
198 let mut modifiers = Vec::new();
199 let mut return_type = String::new();
200 let mut parameters = Vec::new();
201 let mut body = None;
202 let span = (0..node.text_len() as usize).into();
203 let mut current_offset = 0;
204 let mut skipped_function = false;
205
206 for child in node.children() {
207 match child {
208 GreenTree::Leaf(leaf) => match leaf.kind() {
209 VbNetTokenType::Function => {
210 skipped_function = true;
211 }
212 VbNetTokenType::Identifier if skipped_function => {
213 if name.is_empty() {
214 let leaf_start = current_offset;
215 let leaf_end = current_offset + leaf.length() as usize;
216 name = source.get_text_in((leaf_start..leaf_end).into()).to_string();
217 }
218 }
219 VbNetTokenType::Public
220 | VbNetTokenType::Private
221 | VbNetTokenType::Protected
222 | VbNetTokenType::Friend
223 | VbNetTokenType::Shared
224 | VbNetTokenType::Overrides
225 | VbNetTokenType::Overloads
226 | VbNetTokenType::Overridable
227 | VbNetTokenType::NotOverridable
228 | VbNetTokenType::MustOverride
229 | VbNetTokenType::ReadOnly
230 | VbNetTokenType::WriteOnly
231 | VbNetTokenType::Static
232 | VbNetTokenType::Partial
233 | VbNetTokenType::Async => {
234 let leaf_start = current_offset;
235 let leaf_end = current_offset + leaf.length() as usize;
236 modifiers.push(source.get_text_in((leaf_start..leaf_end).into()).to_string());
237 }
238 _ => {}
239 },
240 GreenTree::Node(child_node) => {
241 if child_node.kind() == VbNetElementType::Statement {
242 let mut statements = Vec::new();
243 self.build_statements(child_node, source, &mut statements);
244 body = Some(statements);
245 }
246 }
247 }
248 current_offset += child.len() as usize;
249 }
250
251 Some(FunctionDeclaration { name, attributes, modifiers, return_type, parameters, body, span })
252 }
253
254 fn build_sub<'a, S: Source + ?Sized>(&self, node: &GreenNode<'a, VbNetLanguage>, source: &'a S) -> Option<SubDeclaration> {
255 let mut name = String::new();
256 let mut attributes = Vec::new();
257 let mut modifiers = Vec::new();
258 let mut parameters = Vec::new();
259 let mut body = None;
260 let span = (0..node.text_len() as usize).into();
261 let mut current_offset = 0;
262 let mut skipped_sub = false;
263
264 for child in node.children() {
265 match child {
266 GreenTree::Leaf(leaf) => match leaf.kind() {
267 VbNetTokenType::Sub => {
268 skipped_sub = true;
269 }
270 VbNetTokenType::Identifier if skipped_sub => {
271 if name.is_empty() {
272 let leaf_start = current_offset;
273 let leaf_end = current_offset + leaf.length() as usize;
274 name = source.get_text_in((leaf_start..leaf_end).into()).to_string();
275 }
276 }
277 VbNetTokenType::Public
278 | VbNetTokenType::Private
279 | VbNetTokenType::Protected
280 | VbNetTokenType::Friend
281 | VbNetTokenType::Shared
282 | VbNetTokenType::Overrides
283 | VbNetTokenType::Overloads
284 | VbNetTokenType::Overridable
285 | VbNetTokenType::NotOverridable
286 | VbNetTokenType::MustOverride
287 | VbNetTokenType::Static
288 | VbNetTokenType::Partial
289 | VbNetTokenType::Async => {
290 let leaf_start = current_offset;
291 let leaf_end = current_offset + leaf.length() as usize;
292 modifiers.push(source.get_text_in((leaf_start..leaf_end).into()).to_string());
293 }
294 _ => {}
295 },
296 GreenTree::Node(child_node) => {
297 if child_node.kind() == VbNetElementType::Statement {
298 let mut statements = Vec::new();
299 self.build_statements(child_node, source, &mut statements);
300 body = Some(statements);
301 }
302 }
303 }
304 current_offset += child.len() as usize;
305 }
306
307 Some(SubDeclaration { name, attributes, modifiers, parameters, body, span })
308 }
309
310 fn build_property<'a, S: Source + ?Sized>(&self, node: &GreenNode<'a, VbNetLanguage>, source: &'a S) -> Option<PropertyDeclaration> {
311 let mut name = String::new();
312 let mut attributes = Vec::new();
313 let mut property_type = String::new();
314 let mut modifiers = Vec::new();
315 let mut get_accessor = None;
316 let mut set_accessor = None;
317 let span = (0..node.text_len() as usize).into();
318 let mut current_offset = 0;
319 let mut skipped_property = false;
320
321 for child in node.children() {
322 match child {
323 GreenTree::Leaf(leaf) => match leaf.kind() {
324 VbNetTokenType::Property => {
325 skipped_property = true;
326 }
327 VbNetTokenType::Identifier if skipped_property => {
328 if name.is_empty() {
329 let leaf_start = current_offset;
330 let leaf_end = current_offset + leaf.length() as usize;
331 name = source.get_text_in((leaf_start..leaf_end).into()).to_string();
332 }
333 }
334 VbNetTokenType::Public
335 | VbNetTokenType::Private
336 | VbNetTokenType::Protected
337 | VbNetTokenType::Friend
338 | VbNetTokenType::Shared
339 | VbNetTokenType::Overrides
340 | VbNetTokenType::Overloads
341 | VbNetTokenType::Overridable
342 | VbNetTokenType::NotOverridable
343 | VbNetTokenType::MustOverride
344 | VbNetTokenType::ReadOnly
345 | VbNetTokenType::WriteOnly
346 | VbNetTokenType::Static
347 | VbNetTokenType::Partial => {
348 let leaf_start = current_offset;
349 let leaf_end = current_offset + leaf.length() as usize;
350 modifiers.push(source.get_text_in((leaf_start..leaf_end).into()).to_string());
351 }
352 _ => {}
353 },
354 GreenTree::Node(_) => {
355 }
357 }
358 current_offset += child.len() as usize;
359 }
360
361 Some(PropertyDeclaration { name, attributes, property_type, modifiers, get_accessor, set_accessor, span })
362 }
363
364 fn build_variable<'a, S: Source + ?Sized>(&self, node: &GreenNode<'a, VbNetLanguage>, source: &'a S) -> Option<VariableDeclaration> {
365 let mut name = String::new();
366 let mut attributes = Vec::new();
367 let mut variable_type = String::new();
368 let mut modifiers = Vec::new();
369 let mut initializer = None;
370 let span = (0..node.text_len() as usize).into();
371 let mut current_offset = 0;
372 let mut skipped_dim = false;
373
374 for child in node.children() {
375 match child {
376 GreenTree::Leaf(leaf) => {
377 if leaf.kind() == VbNetTokenType::Dim {
378 skipped_dim = true;
379 }
380 if leaf.kind() == VbNetTokenType::Identifier && name.is_empty() && skipped_dim {
381 let leaf_start = current_offset;
382 let leaf_end = current_offset + leaf.length() as usize;
383 name = source.get_text_in((leaf_start..leaf_end).into()).to_string();
384 }
385 }
386 GreenTree::Node(child_node) => {
387 if child_node.kind() == VbNetElementType::Expression {
388 if let Some(expr) = self.build_expression(child_node, source) {
389 initializer = Some(expr);
390 }
391 }
392 }
393 }
394 current_offset += child.len() as usize;
395 }
396
397 Some(VariableDeclaration { name, attributes, variable_type, modifiers, initializer, span })
398 }
399
400 fn build_members<'a, S: Source + ?Sized>(&self, node: &GreenNode<'a, VbNetLanguage>, source: &'a S, members: &mut Vec<Member>) {
401 for child in node.children() {
402 match child {
403 GreenTree::Node(child_node) => match child_node.kind() {
404 VbNetElementType::Function => {
405 if let Some(function) = self.build_function(child_node, source) {
406 members.push(Member::Function(function));
407 }
408 }
409 VbNetElementType::Sub => {
410 if let Some(sub) = self.build_sub(child_node, source) {
411 members.push(Member::Sub(sub));
412 }
413 }
414 VbNetElementType::Property => {
415 if let Some(property) = self.build_property(child_node, source) {
416 members.push(Member::Property(property));
417 }
418 }
419 VbNetElementType::Dim => {
420 if let Some(variable) = self.build_variable(child_node, source) {
421 members.push(Member::Variable(variable));
422 }
423 }
424 _ => {
425 self.build_members(child_node, source, members);
426 }
427 },
428 GreenTree::Leaf(_) => {}
429 }
430 }
431 }
432
433 fn build_statements<'a, S: Source + ?Sized>(&self, node: &GreenNode<'a, VbNetLanguage>, source: &'a S, statements: &mut Vec<Statement>) {
434 for child in node.children() {
435 match child {
436 GreenTree::Node(child_node) => {
437 match child_node.kind() {
438 VbNetElementType::Expression => {
439 if let Some(expr) = self.build_expression(child_node, source) {
440 statements.push(Statement::Expression(expr));
441 }
442 }
443 VbNetElementType::Return => {
444 let mut return_expr = None;
445 for grandchild in child_node.children() {
446 if let GreenTree::Node(grandchild_node) = grandchild {
447 if grandchild_node.kind() == VbNetElementType::Expression {
448 return_expr = self.build_expression(grandchild_node, source);
449 }
450 }
451 }
452 statements.push(Statement::Return(return_expr));
453 }
454 VbNetElementType::If => {
455 }
457 VbNetElementType::For => {
458 }
460 VbNetElementType::While => {
461 }
463 VbNetElementType::DoWhile => {
464 }
466 VbNetElementType::SelectCase => {
467 }
469 VbNetElementType::Try => {
470 }
472 VbNetElementType::Exit => {
473 }
475 VbNetElementType::Continue => {
476 }
478 VbNetElementType::Throw => {
479 }
481 VbNetElementType::With => {
482 }
484 VbNetElementType::Dim => {
485 if let Some(variable) = self.build_variable(child_node, source) {
486 statements.push(Statement::Dim(variable));
487 }
488 }
489 VbNetElementType::Const => {
490 }
492 _ => {
493 self.build_statements(child_node, source, statements);
494 }
495 }
496 }
497 GreenTree::Leaf(_) => {}
498 }
499 }
500 }
501
502 fn build_expression<'a, S: Source + ?Sized>(&self, node: &GreenNode<'a, VbNetLanguage>, source: &'a S) -> Option<Expression> {
503 let mut current_offset = 0;
504 for child in node.children() {
505 match child {
506 GreenTree::Leaf(leaf) => {
507 match leaf.kind() {
508 VbNetTokenType::Identifier => {
509 let leaf_start = current_offset;
510 let leaf_end = current_offset + leaf.length() as usize;
511 return Some(Expression::Identifier(source.get_text_in((leaf_start..leaf_end).into()).to_string()));
512 }
513 VbNetTokenType::IntegerLiteral => {
514 let leaf_start = current_offset;
515 let leaf_end = current_offset + leaf.length() as usize;
516 if let Ok(value) = source.get_text_in((leaf_start..leaf_end).into()).parse::<i64>() {
517 return Some(Expression::Literal(Literal::Integer(value)));
518 }
519 }
520 VbNetTokenType::FloatLiteral => {
521 let leaf_start = current_offset;
522 let leaf_end = current_offset + leaf.length() as usize;
523 if let Ok(value) = source.get_text_in((leaf_start..leaf_end).into()).parse::<f64>() {
524 return Some(Expression::Literal(Literal::Double(value)));
525 }
526 }
527 VbNetTokenType::StringLiteral => {
528 let leaf_start = current_offset;
529 let leaf_end = current_offset + leaf.length() as usize;
530 let text = source.get_text_in((leaf_start..leaf_end).into());
531 let value = text.trim_matches('"').replace("\"", "\"");
533 return Some(Expression::Literal(Literal::String(value)));
534 }
535 VbNetTokenType::BooleanLiteral => {
536 let leaf_start = current_offset;
537 let leaf_end = current_offset + leaf.length() as usize;
538 let text = source.get_text_in((leaf_start..leaf_end).into()).to_lowercase();
539 if text == "true" {
540 return Some(Expression::Literal(Literal::Boolean(true)));
541 }
542 else if text == "false" {
543 return Some(Expression::Literal(Literal::Boolean(false)));
544 }
545 }
546 VbNetTokenType::NothingLiteral => {
547 return Some(Expression::Literal(Literal::Nothing));
548 }
549 VbNetTokenType::Me => {
550 return Some(Expression::Me);
551 }
552 VbNetTokenType::MyBase => {
553 return Some(Expression::MyBase);
554 }
555 VbNetTokenType::MyClass => {
556 return Some(Expression::MyClass);
557 }
558 _ => {}
559 }
560 }
561 GreenTree::Node(child_node) => {
562 if child_node.kind() == VbNetElementType::ParenthesizedExpression {
563 for grandchild in child_node.children() {
565 if let GreenTree::Node(grandchild_node) = grandchild {
566 if let Some(expr) = self.build_expression(grandchild_node, source) {
567 return Some(Expression::Parenthesized(Box::new(expr)));
568 }
569 }
570 }
571 }
572 else {
573 if let Some(expr) = self.build_expression(child_node, source) {
574 return Some(expr);
575 }
576 }
577 }
578 }
579 current_offset += child.len() as usize;
580 }
581 None
582 }
583}