Serenity Operating System
1/*
2 * Copyright (c) 2021, Itamar S. <itamar8910@gmail.com>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include "AST.h"
8
9namespace Cpp {
10
11static void print_indent(FILE* output, int indent)
12{
13 for (int i = 0; i < indent * 2; ++i)
14 out(output, " ");
15}
16
17void ASTNode::dump(FILE* output, size_t indent) const
18{
19 print_indent(output, indent);
20 outln(output, "{}[{}:{}->{}:{}]", class_name(), start().line, start().column, end().line, end().column);
21}
22
23void TranslationUnit::dump(FILE* output, size_t indent) const
24{
25 ASTNode::dump(output, indent);
26 for (auto const& child : m_declarations) {
27 child->dump(output, indent + 1);
28 }
29}
30
31void FunctionDeclaration::dump(FILE* output, size_t indent) const
32{
33 ASTNode::dump(output, indent);
34
35 DeprecatedString qualifiers_string;
36 if (!m_qualifiers.is_empty()) {
37 print_indent(output, indent + 1);
38 outln(output, "[{}]", DeprecatedString::join(' ', m_qualifiers));
39 }
40
41 m_return_type->dump(output, indent + 1);
42 if (!m_name.is_null()) {
43 print_indent(output, indent + 1);
44 outln(output, "{}", m_name->full_name());
45 }
46 print_indent(output, indent + 1);
47 outln(output, "(");
48 for (auto const& arg : m_parameters) {
49 arg->dump(output, indent + 1);
50 }
51 print_indent(output, indent + 1);
52 outln(output, ")");
53 if (!m_definition.is_null()) {
54 m_definition->dump(output, indent + 1);
55 }
56}
57
58Vector<NonnullRefPtr<Declaration const>> FunctionDeclaration::declarations() const
59{
60 Vector<NonnullRefPtr<Declaration const>> declarations;
61 for (auto& arg : m_parameters) {
62 declarations.append(arg);
63 }
64
65 if (m_definition)
66 declarations.extend(m_definition->declarations());
67
68 return declarations;
69}
70
71void Type::dump(FILE* output, size_t indent) const
72{
73 ASTNode::dump(output, indent);
74 print_indent(output, indent + 1);
75 outln(output, "{}", to_deprecated_string());
76}
77
78DeprecatedString NamedType::to_deprecated_string() const
79{
80 DeprecatedString qualifiers_string;
81 if (!qualifiers().is_empty())
82 qualifiers_string = DeprecatedString::formatted("[{}] ", DeprecatedString::join(' ', qualifiers()));
83
84 DeprecatedString name;
85 if (is_auto())
86 name = "auto";
87 else
88 name = m_name.is_null() ? ""sv : m_name->full_name();
89
90 return DeprecatedString::formatted("{}{}", qualifiers_string, name);
91}
92
93DeprecatedString Pointer::to_deprecated_string() const
94{
95 if (!m_pointee)
96 return {};
97 StringBuilder builder;
98 builder.append(m_pointee->to_deprecated_string());
99 builder.append('*');
100 return builder.to_deprecated_string();
101}
102
103DeprecatedString Reference::to_deprecated_string() const
104{
105 if (!m_referenced_type)
106 return {};
107 StringBuilder builder;
108 builder.append(m_referenced_type->to_deprecated_string());
109 if (m_kind == Kind::Lvalue)
110 builder.append('&');
111 else
112 builder.append("&&"sv);
113 return builder.to_deprecated_string();
114}
115
116DeprecatedString FunctionType::to_deprecated_string() const
117{
118 StringBuilder builder;
119 builder.append(m_return_type->to_deprecated_string());
120 builder.append('(');
121 bool first = true;
122 for (auto& parameter : m_parameters) {
123 if (first)
124 first = false;
125 else
126 builder.append(", "sv);
127 if (parameter->type())
128 builder.append(parameter->type()->to_deprecated_string());
129 if (parameter->name() && !parameter->full_name().is_empty()) {
130 builder.append(' ');
131 builder.append(parameter->full_name());
132 }
133 }
134 builder.append(')');
135 return builder.to_deprecated_string();
136}
137
138void Parameter::dump(FILE* output, size_t indent) const
139{
140 ASTNode::dump(output, indent);
141 if (m_is_ellipsis) {
142 print_indent(output, indent + 1);
143 outln(output, "...");
144 }
145 if (!m_name.is_null()) {
146 print_indent(output, indent);
147 outln(output, "{}", m_name->full_name());
148 }
149 if (m_type)
150 m_type->dump(output, indent + 1);
151}
152
153void FunctionDefinition::dump(FILE* output, size_t indent) const
154{
155 ASTNode::dump(output, indent);
156 print_indent(output, indent);
157 outln(output, "{{");
158 for (auto const& statement : m_statements) {
159 statement->dump(output, indent + 1);
160 }
161 print_indent(output, indent);
162 outln(output, "}}");
163}
164
165Vector<NonnullRefPtr<Declaration const>> FunctionDefinition::declarations() const
166{
167 Vector<NonnullRefPtr<Declaration const>> declarations;
168 for (auto& statement : m_statements) {
169 declarations.extend(statement->declarations());
170 }
171 return declarations;
172}
173
174void VariableDeclaration::dump(FILE* output, size_t indent) const
175{
176 ASTNode::dump(output, indent);
177 if (m_type)
178 m_type->dump(output, indent + 1);
179 print_indent(output, indent + 1);
180 outln(output, "{}", full_name());
181 if (m_initial_value)
182 m_initial_value->dump(output, indent + 1);
183}
184
185void Identifier::dump(FILE* output, size_t indent) const
186{
187 ASTNode::dump(output, indent);
188 print_indent(output, indent);
189 outln(output, "{}", m_name);
190}
191
192void NumericLiteral::dump(FILE* output, size_t indent) const
193{
194 ASTNode::dump(output, indent);
195 print_indent(output, indent);
196 outln(output, "{}", m_value);
197}
198
199void BinaryExpression::dump(FILE* output, size_t indent) const
200{
201 ASTNode::dump(output, indent);
202
203 char const* op_string = nullptr;
204 switch (m_op) {
205 case BinaryOp::Addition:
206 op_string = "+";
207 break;
208 case BinaryOp::Subtraction:
209 op_string = "-";
210 break;
211 case BinaryOp::Multiplication:
212 op_string = "*";
213 break;
214 case BinaryOp::Division:
215 op_string = "/";
216 break;
217 case BinaryOp::Modulo:
218 op_string = "%";
219 break;
220 case BinaryOp::GreaterThan:
221 op_string = ">";
222 break;
223 case BinaryOp::GreaterThanEquals:
224 op_string = ">=";
225 break;
226 case BinaryOp::LessThan:
227 op_string = "<";
228 break;
229 case BinaryOp::LessThanEquals:
230 op_string = "<=";
231 break;
232 case BinaryOp::BitwiseAnd:
233 op_string = "&";
234 break;
235 case BinaryOp::BitwiseOr:
236 op_string = "|";
237 break;
238 case BinaryOp::BitwiseXor:
239 op_string = "^";
240 break;
241 case BinaryOp::LeftShift:
242 op_string = "<<";
243 break;
244 case BinaryOp::RightShift:
245 op_string = ">>";
246 break;
247 case BinaryOp::EqualsEquals:
248 op_string = "==";
249 break;
250 case BinaryOp::NotEqual:
251 op_string = "!=";
252 break;
253 case BinaryOp::LogicalOr:
254 op_string = "||";
255 break;
256 case BinaryOp::LogicalAnd:
257 op_string = "&&";
258 break;
259 case BinaryOp::Arrow:
260 op_string = "->";
261 break;
262 }
263
264 m_lhs->dump(output, indent + 1);
265 print_indent(output, indent + 1);
266 VERIFY(op_string);
267 outln(output, "{}", op_string);
268 m_rhs->dump(output, indent + 1);
269}
270
271void AssignmentExpression::dump(FILE* output, size_t indent) const
272{
273 ASTNode::dump(output, indent);
274
275 char const* op_string = nullptr;
276 switch (m_op) {
277 case AssignmentOp::Assignment:
278 op_string = "=";
279 break;
280 case AssignmentOp::AdditionAssignment:
281 op_string = "+=";
282 break;
283 case AssignmentOp::SubtractionAssignment:
284 op_string = "-=";
285 break;
286 }
287
288 m_lhs->dump(output, indent + 1);
289 print_indent(output, indent + 1);
290 VERIFY(op_string);
291 outln(output, "{}", op_string);
292 m_rhs->dump(output, indent + 1);
293}
294
295void FunctionCall::dump(FILE* output, size_t indent) const
296{
297 ASTNode::dump(output, indent);
298 m_callee->dump(output, indent + 1);
299 for (auto const& arg : m_arguments) {
300 arg->dump(output, indent + 1);
301 }
302}
303
304void StringLiteral::dump(FILE* output, size_t indent) const
305{
306 ASTNode::dump(output, indent);
307 print_indent(output, indent + 1);
308 outln(output, "{}", m_value);
309}
310
311void ReturnStatement::dump(FILE* output, size_t indent) const
312{
313 ASTNode::dump(output, indent);
314 if (m_value)
315 m_value->dump(output, indent + 1);
316}
317
318void EnumDeclaration::dump(FILE* output, size_t indent) const
319{
320 ASTNode::dump(output, indent);
321 print_indent(output, indent);
322 outln(output, "{}", full_name());
323 for (auto& entry : m_entries) {
324 print_indent(output, indent + 1);
325 outln(output, "{}", entry.name);
326 if (entry.value)
327 entry.value->dump(output, indent + 2);
328 }
329}
330
331void StructOrClassDeclaration::dump(FILE* output, size_t indent) const
332{
333 ASTNode::dump(output, indent);
334 print_indent(output, indent);
335 outln(output, "{}", full_name());
336 if (!m_baseclasses.is_empty()) {
337 print_indent(output, indent + 1);
338 outln(output, ":");
339 for (size_t i = 0; i < m_baseclasses.size(); ++i) {
340 auto& baseclass = m_baseclasses[i];
341 baseclass->dump(output, indent + 1);
342 if (i < m_baseclasses.size() - 1) {
343 print_indent(output, indent + 1);
344 outln(output, ",");
345 }
346 }
347 }
348 outln(output, "");
349 for (auto& member : m_members) {
350 member->dump(output, indent + 1);
351 }
352}
353Vector<NonnullRefPtr<Declaration const>> StructOrClassDeclaration::declarations() const
354{
355 Vector<NonnullRefPtr<Declaration const>> declarations;
356 for (auto& member : m_members)
357 declarations.append(member);
358 return declarations;
359}
360
361void UnaryExpression::dump(FILE* output, size_t indent) const
362{
363 ASTNode::dump(output, indent);
364
365 char const* op_string = nullptr;
366 switch (m_op) {
367 case UnaryOp::BitwiseNot:
368 op_string = "~";
369 break;
370 case UnaryOp::Not:
371 op_string = "!";
372 break;
373 case UnaryOp::Plus:
374 op_string = "+";
375 break;
376 case UnaryOp::Minus:
377 op_string = "-";
378 break;
379 case UnaryOp::PlusPlus:
380 op_string = "++";
381 break;
382 case UnaryOp::Address:
383 op_string = "&";
384 break;
385 default:
386 op_string = "<invalid>";
387 }
388
389 VERIFY(op_string);
390 print_indent(output, indent + 1);
391 outln(output, "{}", op_string);
392 m_lhs->dump(output, indent + 1);
393}
394
395void BooleanLiteral::dump(FILE* output, size_t indent) const
396{
397 ASTNode::dump(output, indent);
398 print_indent(output, indent + 1);
399 outln(output, "{}", m_value ? "true" : "false");
400}
401
402void Pointer::dump(FILE* output, size_t indent) const
403{
404 ASTNode::dump(output, indent);
405 if (!m_pointee.is_null()) {
406 m_pointee->dump(output, indent + 1);
407 }
408}
409
410void Reference::dump(FILE* output, size_t indent) const
411{
412 ASTNode::dump(output, indent);
413 print_indent(output, indent + 1);
414 outln(output, "{}", m_kind == Kind::Lvalue ? "&" : "&&");
415 if (!m_referenced_type.is_null()) {
416 m_referenced_type->dump(output, indent + 1);
417 }
418}
419
420void FunctionType::dump(FILE* output, size_t indent) const
421{
422 ASTNode::dump(output, indent);
423 if (m_return_type)
424 m_return_type->dump(output, indent + 1);
425 print_indent(output, indent + 1);
426 outln("(");
427 for (auto& parameter : m_parameters)
428 parameter->dump(output, indent + 2);
429 print_indent(output, indent + 1);
430 outln(")");
431}
432
433void MemberExpression::dump(FILE* output, size_t indent) const
434{
435 ASTNode::dump(output, indent);
436 m_object->dump(output, indent + 1);
437 m_property->dump(output, indent + 1);
438}
439
440void BlockStatement::dump(FILE* output, size_t indent) const
441{
442 ASTNode::dump(output, indent);
443 for (auto& statement : m_statements) {
444 statement->dump(output, indent + 1);
445 }
446}
447
448void ForStatement::dump(FILE* output, size_t indent) const
449{
450 ASTNode::dump(output, indent);
451 if (m_init)
452 m_init->dump(output, indent + 1);
453 if (m_test)
454 m_test->dump(output, indent + 1);
455 if (m_update)
456 m_update->dump(output, indent + 1);
457 if (m_body)
458 m_body->dump(output, indent + 1);
459}
460
461Vector<NonnullRefPtr<Declaration const>> Statement::declarations() const
462{
463 if (is_declaration()) {
464 Vector<NonnullRefPtr<Declaration const>> vec;
465 auto const& decl = static_cast<Declaration const&>(*this);
466 vec.empend(const_cast<Declaration&>(decl));
467 return vec;
468 }
469 return {};
470}
471
472Vector<NonnullRefPtr<Declaration const>> ForStatement::declarations() const
473{
474 Vector<NonnullRefPtr<Declaration const>> declarations;
475 if (m_init)
476 declarations.extend(m_init->declarations());
477 if (m_body)
478 declarations.extend(m_body->declarations());
479 return declarations;
480}
481
482Vector<NonnullRefPtr<Declaration const>> BlockStatement::declarations() const
483{
484 Vector<NonnullRefPtr<Declaration const>> declarations;
485 for (auto& statement : m_statements) {
486 declarations.extend(statement->declarations());
487 }
488 return declarations;
489}
490
491void IfStatement::dump(FILE* output, size_t indent) const
492{
493 ASTNode::dump(output, indent);
494 if (m_predicate) {
495 print_indent(output, indent + 1);
496 outln(output, "Predicate:");
497 m_predicate->dump(output, indent + 1);
498 }
499 if (m_then) {
500 print_indent(output, indent + 1);
501 outln(output, "Then:");
502 m_then->dump(output, indent + 1);
503 }
504 if (m_else) {
505 print_indent(output, indent + 1);
506 outln(output, "Else:");
507 m_else->dump(output, indent + 1);
508 }
509}
510
511Vector<NonnullRefPtr<Declaration const>> IfStatement::declarations() const
512{
513 Vector<NonnullRefPtr<Declaration const>> declarations;
514 if (m_predicate)
515 declarations.extend(m_predicate->declarations());
516 if (m_then)
517 declarations.extend(m_then->declarations());
518 if (m_else)
519 declarations.extend(m_else->declarations());
520 return declarations;
521}
522
523void NamespaceDeclaration::dump(FILE* output, size_t indent) const
524{
525 ASTNode::dump(output, indent);
526 print_indent(output, indent + 1);
527 outln(output, "{}", full_name());
528 for (auto& decl : m_declarations)
529 decl->dump(output, indent + 1);
530}
531
532void NullPointerLiteral::dump(FILE* output, size_t indent) const
533{
534 ASTNode::dump(output, indent);
535}
536
537void Name::dump(FILE* output, size_t indent) const
538{
539 ASTNode::dump(output, indent);
540 print_indent(output, indent);
541 outln(output, "{}", full_name());
542}
543
544StringView Name::full_name() const
545{
546 if (m_full_name.has_value())
547 return *m_full_name;
548
549 StringBuilder builder;
550 if (!m_scope.is_empty()) {
551 for (auto& scope : m_scope) {
552 builder.appendff("{}::", scope->name());
553 }
554 }
555 m_full_name = DeprecatedString::formatted("{}{}", builder.to_deprecated_string(), m_name.is_null() ? ""sv : m_name->name());
556 return *m_full_name;
557}
558
559StringView TemplatizedName::full_name() const
560{
561 if (m_full_name.has_value())
562 return *m_full_name;
563
564 StringBuilder name;
565 name.append(Name::full_name());
566 name.append('<');
567 for (auto& type : m_template_arguments) {
568 name.append(type->to_deprecated_string());
569 }
570 name.append('>');
571 m_full_name = name.to_deprecated_string();
572 return *m_full_name;
573}
574
575void CppCastExpression::dump(FILE* output, size_t indent) const
576{
577 ASTNode::dump(output, indent);
578
579 print_indent(output, indent);
580 outln(output, "{}", m_cast_type);
581
582 print_indent(output, indent + 1);
583 outln(output, "<");
584 if (m_type)
585 m_type->dump(output, indent + 1);
586 print_indent(output, indent + 1);
587 outln(output, ">");
588
589 if (m_expression)
590 m_expression->dump(output, indent + 1);
591}
592
593void SizeofExpression::dump(FILE* output, size_t indent) const
594{
595 ASTNode::dump(output, indent);
596 if (m_type)
597 m_type->dump(output, indent + 1);
598}
599
600void BracedInitList::dump(FILE* output, size_t indent) const
601{
602 ASTNode::dump(output, indent);
603 for (auto& exp : m_expressions) {
604 exp->dump(output, indent + 1);
605 }
606}
607
608void CStyleCastExpression::dump(FILE* output, size_t indent) const
609{
610 ASTNode::dump(output, indent);
611 if (m_type)
612 m_type->dump(output, indent + 1);
613 if (m_expression)
614 m_expression->dump(output, indent + 1);
615}
616
617void Constructor::dump(FILE* output, size_t indent) const
618{
619 print_indent(output, indent);
620 outln(output, "C'tor");
621 print_indent(output, indent + 1);
622 outln(output, "(");
623 for (auto const& arg : parameters()) {
624 arg->dump(output, indent + 1);
625 }
626 print_indent(output, indent + 1);
627 outln(output, ")");
628 if (definition()) {
629 definition()->dump(output, indent + 1);
630 }
631}
632
633void Destructor::dump(FILE* output, size_t indent) const
634{
635 print_indent(output, indent);
636 outln(output, "D'tor");
637 print_indent(output, indent + 1);
638 outln(output, "(");
639 for (auto const& arg : parameters()) {
640 arg->dump(output, indent + 1);
641 }
642 print_indent(output, indent + 1);
643 outln(output, ")");
644 if (definition()) {
645 definition()->dump(output, indent + 1);
646 }
647}
648
649StringView Declaration::full_name() const
650{
651 if (!m_full_name.has_value()) {
652 if (m_name)
653 m_full_name = m_name->full_name();
654 else
655 m_full_name = DeprecatedString::empty();
656 }
657
658 return *m_full_name;
659}
660
661void UsingNamespaceDeclaration::dump(FILE* output, size_t indent) const
662{
663 ASTNode::dump(output, indent);
664 print_indent(output, indent + 1);
665 outln(output, "{}", full_name());
666}
667
668}