1use crate::ast::visitor::Visitor;
2use crate::ast::*;
3
4pub struct SExprFormatter<'a> {
5 output: String,
6 indent: usize,
7 source: &'a [u8],
8}
9
10impl<'a> SExprFormatter<'a> {
11 pub fn new(source: &'a [u8]) -> Self {
12 Self {
13 output: String::new(),
14 indent: 0,
15 source,
16 }
17 }
18
19 pub fn finish(self) -> String {
20 self.output
21 }
22
23 fn write(&mut self, s: &str) {
24 self.output.push_str(s);
25 }
26
27 fn newline(&mut self) {
28 self.output.push('\n');
29 for _ in 0..self.indent {
30 self.output.push_str(" ");
31 }
32 }
33}
34
35impl<'a, 'ast> Visitor<'ast> for SExprFormatter<'a> {
36 fn visit_program(&mut self, program: &'ast Program<'ast>) {
37 self.write("(program");
38 self.indent += 1;
39 for stmt in program.statements {
40 self.newline();
41 self.visit_stmt(stmt);
42 }
43 for error in program.errors {
44 self.newline();
45 self.visit_parse_error(error);
46 }
47 self.indent -= 1;
48 self.write(")");
49 }
50
51 fn visit_stmt(&mut self, stmt: StmtId<'ast>) {
52 match stmt {
53 Stmt::Block { statements, .. } => {
54 self.write("(block");
55 self.indent += 1;
56 for stmt in *statements {
57 self.newline();
58 self.visit_stmt(stmt);
59 }
60 self.indent -= 1;
61 self.write(")");
62 }
63 Stmt::If {
64 condition,
65 then_block,
66 else_block,
67 ..
68 } => {
69 self.write("(if ");
70 self.visit_expr(condition);
71 self.indent += 1;
72 self.newline();
73 self.write("(then");
74 self.indent += 1;
75 for stmt in *then_block {
76 self.newline();
77 self.visit_stmt(stmt);
78 }
79 self.indent -= 1;
80 self.write(")");
81 if let Some(else_block) = else_block {
82 self.newline();
83 self.write("(else");
84 self.indent += 1;
85 for stmt in *else_block {
86 self.newline();
87 self.visit_stmt(stmt);
88 }
89 self.indent -= 1;
90 self.write(")");
91 }
92 self.indent -= 1;
93 self.write(")");
94 }
95 Stmt::While {
96 condition, body, ..
97 } => {
98 self.write("(while ");
99 self.visit_expr(condition);
100 self.indent += 1;
101 self.newline();
102 self.write("(body");
103 self.indent += 1;
104 for stmt in *body {
105 self.newline();
106 self.visit_stmt(stmt);
107 }
108 self.indent -= 1;
109 self.write("))");
110 self.indent -= 1;
111 }
112 Stmt::Echo { exprs, .. } => {
113 self.write("(echo");
114 for expr in *exprs {
115 self.write(" ");
116 self.visit_expr(expr);
117 }
118 self.write(")");
119 }
120 Stmt::Expression { expr, .. } => {
121 self.visit_expr(expr);
122 }
123 Stmt::DoWhile {
124 body, condition, ..
125 } => {
126 self.write("(do-while ");
127 self.visit_expr(condition);
128 self.indent += 1;
129 self.newline();
130 self.write("(body");
131 self.indent += 1;
132 for stmt in *body {
133 self.newline();
134 self.visit_stmt(stmt);
135 }
136 self.indent -= 1;
137 self.write("))");
138 self.indent -= 1;
139 }
140 Stmt::For {
141 init,
142 condition,
143 loop_expr,
144 body,
145 ..
146 } => {
147 self.write("(for");
148 self.indent += 1;
149 self.newline();
150 self.write("(init");
151 for expr in *init {
152 self.write(" ");
153 self.visit_expr(expr);
154 }
155 self.write(")");
156 self.newline();
157 self.write("(cond");
158 for expr in *condition {
159 self.write(" ");
160 self.visit_expr(expr);
161 }
162 self.write(")");
163 self.newline();
164 self.write("(loop");
165 for expr in *loop_expr {
166 self.write(" ");
167 self.visit_expr(expr);
168 }
169 self.write(")");
170 self.newline();
171 self.write("(body");
172 self.indent += 1;
173 for stmt in *body {
174 self.newline();
175 self.visit_stmt(stmt);
176 }
177 self.indent -= 1;
178 self.write("))");
179 self.indent -= 1;
180 }
181 Stmt::Foreach {
182 expr,
183 key_var,
184 value_var,
185 body,
186 ..
187 } => {
188 self.write("(foreach ");
189 self.visit_expr(expr);
190 self.write(" ");
191 if let Some(key) = key_var {
192 self.visit_expr(key);
193 self.write(" ");
194 }
195 self.visit_expr(value_var);
196 self.indent += 1;
197 self.newline();
198 self.write("(body");
199 self.indent += 1;
200 for stmt in *body {
201 self.newline();
202 self.visit_stmt(stmt);
203 }
204 self.indent -= 1;
205 self.write("))");
206 self.indent -= 1;
207 }
208 Stmt::Return { expr, .. } => {
209 self.write("(return");
210 if let Some(expr) = expr {
211 self.write(" ");
212 self.visit_expr(expr);
213 }
214 self.write(")");
215 }
216 Stmt::Break { level, .. } => {
217 self.write("(break");
218 if let Some(level) = level {
219 self.write(" ");
220 self.visit_expr(level);
221 }
222 self.write(")");
223 }
224 Stmt::Continue { level, .. } => {
225 self.write("(continue");
226 if let Some(level) = level {
227 self.write(" ");
228 self.visit_expr(level);
229 }
230 self.write(")");
231 }
232 Stmt::Switch {
233 condition, cases, ..
234 } => {
235 self.write("(switch ");
236 self.visit_expr(condition);
237 self.indent += 1;
238 for case in *cases {
239 self.newline();
240 self.visit_case(case);
241 }
242 self.indent -= 1;
243 self.write(")");
244 }
245 Stmt::Try {
246 body,
247 catches,
248 finally,
249 ..
250 } => {
251 self.write("(try");
252 self.indent += 1;
253 self.newline();
254 self.write("(body");
255 self.indent += 1;
256 for stmt in *body {
257 self.newline();
258 self.visit_stmt(stmt);
259 }
260 self.indent -= 1;
261 self.write(")");
262 for catch in *catches {
263 self.newline();
264 self.visit_catch(catch);
265 }
266 if let Some(finally) = finally {
267 self.newline();
268 self.write("(finally");
269 self.indent += 1;
270 for stmt in *finally {
271 self.newline();
272 self.visit_stmt(stmt);
273 }
274 self.indent -= 1;
275 self.write(")");
276 }
277 self.indent -= 1;
278 self.write(")");
279 }
280 Stmt::Throw { expr, .. } => {
281 self.write("(throw ");
282 self.visit_expr(expr);
283 self.write(")");
284 }
285 Stmt::Function {
286 attributes,
287 name,
288 params,
289 return_type,
290 body,
291 by_ref,
292 ..
293 } => {
294 self.write("(function");
295 for attr in *attributes {
296 self.write(" ");
297 self.visit_attribute_group(attr);
298 }
299 if *by_ref {
300 self.write(" &");
301 }
302 self.write(" \"");
303 self.write(&String::from_utf8_lossy(name.text(self.source)));
304 self.write("\"");
305 self.write(" (params");
306 for param in *params {
307 self.write(" ");
308 self.visit_param(param);
309 }
310 self.write(")");
311 if let Some(rt) = return_type {
312 self.write(" (return-type ");
313 self.visit_type(rt);
314 self.write(")");
315 }
316 self.indent += 1;
317 self.newline();
318 self.write("(body");
319 self.indent += 1;
320 for stmt in *body {
321 self.newline();
322 self.visit_stmt(stmt);
323 }
324 self.indent -= 1;
325 self.write("))");
326 self.indent -= 1;
327 }
328 Stmt::Class {
329 attributes,
330 modifiers,
331 name,
332 extends,
333 implements,
334 members,
335 ..
336 } => {
337 self.write("(class");
338 for attr in *attributes {
339 self.write(" ");
340 self.visit_attribute_group(attr);
341 }
342 for modifier in *modifiers {
343 self.write(" ");
344 self.write(&String::from_utf8_lossy(modifier.text(self.source)));
345 }
346 self.write(" \"");
347 self.write(&String::from_utf8_lossy(name.text(self.source)));
348 self.write("\"");
349 if let Some(extends) = extends {
350 self.write(" (extends ");
351 self.visit_name(extends);
352 self.write(")");
353 }
354 if !implements.is_empty() {
355 self.write(" (implements");
356 for iface in *implements {
357 self.write(" ");
358 self.visit_name(iface);
359 }
360 self.write(")");
361 }
362 self.indent += 1;
363 self.newline();
364 self.write("(members");
365 self.indent += 1;
366 for member in *members {
367 self.newline();
368 self.visit_class_member(member);
369 }
370 self.indent -= 1;
371 self.write("))");
372 self.indent -= 1;
373 }
374 Stmt::Interface {
375 attributes,
376 name,
377 extends,
378 members,
379 ..
380 } => {
381 self.write("(interface");
382 for attr in *attributes {
383 self.write(" ");
384 self.visit_attribute_group(attr);
385 }
386 self.write(" \"");
387 self.write(&String::from_utf8_lossy(name.text(self.source)));
388 self.write("\"");
389 if !extends.is_empty() {
390 self.write(" (extends");
391 for iface in *extends {
392 self.write(" ");
393 self.visit_name(iface);
394 }
395 self.write(")");
396 }
397 self.indent += 1;
398 self.newline();
399 self.write("(members");
400 self.indent += 1;
401 for member in *members {
402 self.newline();
403 self.visit_class_member(member);
404 }
405 self.indent -= 1;
406 self.write("))");
407 self.indent -= 1;
408 }
409 Stmt::Trait {
410 attributes,
411 name,
412 members,
413 ..
414 } => {
415 self.write("(trait");
416 for attr in *attributes {
417 self.write(" ");
418 self.visit_attribute_group(attr);
419 }
420 self.write(" \"");
421 self.write(&String::from_utf8_lossy(name.text(self.source)));
422 self.write("\"");
423 self.indent += 1;
424 self.newline();
425 self.write("(members");
426 self.indent += 1;
427 for member in *members {
428 self.newline();
429 self.visit_class_member(member);
430 }
431 self.indent -= 1;
432 self.write("))");
433 self.indent -= 1;
434 }
435 Stmt::Enum {
436 attributes,
437 name,
438 backed_type,
439 implements,
440 members,
441 ..
442 } => {
443 self.write("(enum");
444 for attr in *attributes {
445 self.write(" ");
446 self.visit_attribute_group(attr);
447 }
448 self.write(" \"");
449 self.write(&String::from_utf8_lossy(name.text(self.source)));
450 self.write("\"");
451 if let Some(backed_type) = backed_type {
452 self.write(" : ");
453 self.visit_type(backed_type);
454 }
455 if !implements.is_empty() {
456 self.write(" (implements");
457 for iface in *implements {
458 self.write(" ");
459 self.visit_name(iface);
460 }
461 self.write(")");
462 }
463 self.indent += 1;
464 self.newline();
465 self.write("(members");
466 self.indent += 1;
467 for member in *members {
468 self.newline();
469 self.visit_class_member(member);
470 }
471 self.indent -= 1;
472 self.write("))");
473 self.indent -= 1;
474 }
475 Stmt::Namespace { name, body, .. } => {
476 self.write("(namespace");
477 if let Some(name) = name {
478 self.write(" ");
479 self.visit_name(name);
480 }
481 if let Some(body) = body {
482 self.indent += 1;
483 self.newline();
484 self.write("(body");
485 self.indent += 1;
486 for stmt in *body {
487 self.newline();
488 self.visit_stmt(stmt);
489 }
490 self.indent -= 1;
491 self.write("))");
492 self.indent -= 1;
493 }
494 self.write(")");
495 }
496 Stmt::Use { uses, .. } => {
497 self.write("(use");
498 for use_item in *uses {
499 self.write(" ");
500 self.visit_use_item(use_item);
501 }
502 self.write(")");
503 }
504 Stmt::Global { vars, .. } => {
505 self.write("(global");
506 for var in *vars {
507 self.write(" ");
508 self.visit_expr(var);
509 }
510 self.write(")");
511 }
512 Stmt::Static { vars, .. } => {
513 self.write("(static");
514 for var in *vars {
515 self.write(" ");
516 self.visit_static_var(var);
517 }
518 self.write(")");
519 }
520 Stmt::Unset { vars, .. } => {
521 self.write("(unset");
522 for var in *vars {
523 self.write(" ");
524 self.visit_expr(var);
525 }
526 self.write(")");
527 }
528 Stmt::Goto { label, .. } => {
529 self.write("(goto \"");
530 self.write(&String::from_utf8_lossy(label.text(self.source)));
531 self.write("\")");
532 }
533 Stmt::Label { name, .. } => {
534 self.write("(label \"");
535 self.write(&String::from_utf8_lossy(name.text(self.source)));
536 self.write("\")");
537 }
538 Stmt::HaltCompiler { .. } => self.write("(halt-compiler)"),
539 Stmt::Declare { declares, body, .. } => {
540 self.write("(declare");
541 for declare in *declares {
542 self.write(" ");
543 self.visit_declare_item(declare);
544 }
545 self.indent += 1;
546 self.newline();
547 self.write("(body");
548 self.indent += 1;
549 for stmt in *body {
550 self.newline();
551 self.visit_stmt(stmt);
552 }
553 self.indent -= 1;
554 self.write("))");
555 self.indent -= 1;
556 self.write(")");
557 }
558 Stmt::Const {
559 attributes, consts, ..
560 } => {
561 self.write("(const");
562 for attr in *attributes {
563 self.write(" ");
564 self.visit_attribute_group(attr);
565 }
566 for c in *consts {
567 self.write(" ");
568 self.visit_class_const(c);
569 }
570 self.write(")");
571 }
572 Stmt::InlineHtml { value, .. } => {
573 self.write("(inline-html \"");
574 self.write(&String::from_utf8_lossy(value));
575 self.write("\")");
576 }
577 Stmt::Error { .. } => self.write("(error)"),
578 Stmt::Nop { .. } => self.write("(nop)"),
579 }
580 }
581
582 fn visit_expr(&mut self, expr: ExprId<'ast>) {
583 match expr {
584 Expr::Assign { var, expr, .. } => {
585 self.write("(assign ");
586 self.visit_expr(var);
587 self.write(" ");
588 self.visit_expr(expr);
589 self.write(")");
590 }
591 Expr::Integer { value, .. } => {
592 self.write("(integer ");
593 self.write(&String::from_utf8_lossy(value));
594 self.write(")");
595 }
596 Expr::String { value, .. } => {
597 self.write("(string \"");
598 self.write(
599 &String::from_utf8_lossy(value)
600 .replace("\\", "\\\\")
601 .replace("\"", "\\\"")
602 .replace("\n", "\\n")
603 .replace("\r", "\\r")
604 .replace("\t", "\\t"),
605 );
606 self.write("\")");
607 }
608 Expr::Binary {
609 left, op, right, ..
610 } => {
611 self.write("(");
612 self.write(match op {
613 BinaryOp::Plus => "+",
614 BinaryOp::Minus => "-",
615 BinaryOp::Mul => "*",
616 BinaryOp::Div => "/",
617 BinaryOp::Mod => "%",
618 BinaryOp::Concat => ".",
619 BinaryOp::Eq => "=",
620 BinaryOp::EqEq => "==",
621 BinaryOp::EqEqEq => "===",
622 BinaryOp::NotEq => "!=",
623 BinaryOp::NotEqEq => "!==",
624 BinaryOp::Lt => "<",
625 BinaryOp::LtEq => "<=",
626 BinaryOp::Gt => ">",
627 BinaryOp::GtEq => ">=",
628 BinaryOp::And => "&&",
629 BinaryOp::Or => "||",
630 BinaryOp::BitAnd => "&",
631 BinaryOp::BitOr => "|",
632 BinaryOp::BitXor => "^",
633 BinaryOp::Coalesce => "??",
634 BinaryOp::Spaceship => "<=>",
635 BinaryOp::Pow => "**",
636 BinaryOp::ShiftLeft => "<<",
637 BinaryOp::ShiftRight => ">>",
638 BinaryOp::LogicalAnd => "and",
639 BinaryOp::LogicalOr => "or",
640 BinaryOp::LogicalXor => "xor",
641 BinaryOp::Instanceof => "instanceof",
642 });
643 self.write(" ");
644 self.visit_expr(left);
645 self.write(" ");
646 self.visit_expr(right);
647 self.write(")");
648 }
649 Expr::Variable { name, .. } => {
650 self.write("(variable \"");
651 self.write(&String::from_utf8_lossy(name.as_str(self.source)));
652 self.write("\")");
653 }
654 Expr::IndirectVariable { name, .. } => {
655 self.write("(indirect-variable ");
656 self.visit_expr(name);
657 self.write(")");
658 }
659 Expr::Unary { op, expr, .. } => {
660 self.write("(");
661 self.write(match op {
662 UnaryOp::Plus => "+",
663 UnaryOp::Minus => "-",
664 UnaryOp::Not => "!",
665 UnaryOp::BitNot => "~",
666 UnaryOp::PreInc => "++",
667 UnaryOp::PreDec => "--",
668 UnaryOp::ErrorSuppress => "@",
669 UnaryOp::Reference => "&",
670 });
671 self.write(" ");
672 self.visit_expr(expr);
673 self.write(")");
674 }
675 Expr::PostInc { var, .. } => {
676 self.write("(post-inc ");
677 self.visit_expr(var);
678 self.write(")");
679 }
680 Expr::PostDec { var, .. } => {
681 self.write("(post-dec ");
682 self.visit_expr(var);
683 self.write(")");
684 }
685 Expr::AssignOp { var, op, expr, .. } => {
686 self.write("(assign-op ");
687 self.write(match op {
688 AssignOp::Plus => "+=",
689 AssignOp::Minus => "-=",
690 AssignOp::Mul => "*=",
691 AssignOp::Div => "/=",
692 AssignOp::Mod => "%=",
693 AssignOp::Concat => ".=",
694 AssignOp::BitAnd => "&=",
695 AssignOp::BitOr => "|=",
696 AssignOp::BitXor => "^=",
697 AssignOp::ShiftLeft => "<<=",
698 AssignOp::ShiftRight => ">>=",
699 AssignOp::Pow => "**=",
700 AssignOp::Coalesce => "??=",
701 });
702 self.write(" ");
703 self.visit_expr(var);
704 self.write(" ");
705 self.visit_expr(expr);
706 self.write(")");
707 }
708 Expr::AssignRef { var, expr, .. } => {
709 self.write("(assign-ref ");
710 self.visit_expr(var);
711 self.write(" ");
712 self.visit_expr(expr);
713 self.write(")");
714 }
715 Expr::Call { func, args, .. } => {
716 self.write("(call ");
717 self.visit_expr(func);
718 self.write(" (args");
719 for arg in *args {
720 self.write(" ");
721 self.visit_arg(arg);
722 }
723 self.write("))");
724 }
725 Expr::MethodCall {
726 target,
727 method,
728 args,
729 ..
730 } => {
731 self.write("(method-call ");
732 self.visit_expr(target);
733 self.write("->");
734 self.visit_expr(method);
735 self.write(" (args");
736 for arg in *args {
737 self.write(" ");
738 self.visit_arg(arg);
739 }
740 self.write("))");
741 }
742 Expr::StaticCall {
743 class,
744 method,
745 args,
746 ..
747 } => {
748 self.write("(static-call ");
749 self.visit_expr(class);
750 self.write("::");
751 self.visit_expr(method);
752 self.write(" (args");
753 for arg in *args {
754 self.write(" ");
755 self.visit_arg(arg);
756 }
757 self.write("))");
758 }
759 Expr::Array { items, .. } => {
760 self.write("(array");
761 for item in *items {
762 self.write(" ");
763 self.visit_array_item(item);
764 }
765 self.write(")");
766 }
767 Expr::ArrayDimFetch { array, dim, .. } => {
768 self.write("(array-dim-fetch ");
769 self.visit_expr(array);
770 if let Some(dim) = dim {
771 self.write(" ");
772 self.visit_expr(dim);
773 }
774 self.write(")");
775 }
776 Expr::PropertyFetch {
777 target, property, ..
778 } => {
779 self.write("(property-fetch ");
780 self.visit_expr(target);
781 self.write("->");
782 self.visit_expr(property);
783 self.write(")");
784 }
785 Expr::ClassConstFetch {
786 class, constant, ..
787 } => {
788 self.write("(class-const-fetch ");
789 self.visit_expr(class);
790 self.write("::");
791 self.visit_expr(constant);
792 self.write(")");
793 }
794 Expr::New { class, args, .. } => {
795 self.write("(new ");
796 self.visit_expr(class);
797 self.write(" (args");
798 for arg in *args {
799 self.write(" ");
800 self.visit_arg(arg);
801 }
802 self.write("))");
803 }
804 Expr::Clone { expr, .. } => {
805 self.write("(clone ");
806 self.visit_expr(expr);
807 self.write(")");
808 }
809 Expr::Ternary {
810 condition,
811 if_true,
812 if_false,
813 ..
814 } => {
815 self.write("(ternary ");
816 self.visit_expr(condition);
817 self.write(" ");
818 if let Some(t) = if_true {
819 self.visit_expr(t);
820 } else {
821 self.write("?");
822 }
823 self.write(" ");
824 self.visit_expr(if_false);
825 self.write(")");
826 }
827 Expr::Match {
828 condition, arms, ..
829 } => {
830 self.write("(match ");
831 self.visit_expr(condition);
832 self.indent += 1;
833 for arm in *arms {
834 self.newline();
835 self.visit_match_arm(arm);
836 }
837 self.indent -= 1;
838 self.write(")");
839 }
840 Expr::Closure {
841 attributes,
842 is_static,
843 by_ref,
844 params,
845 return_type,
846 body,
847 uses,
848 ..
849 } => {
850 self.write("(closure");
851 for attr in *attributes {
852 self.write(" ");
853 self.visit_attribute_group(attr);
854 }
855 if *is_static {
856 self.write(" static");
857 }
858 if *by_ref {
859 self.write(" &");
860 }
861 self.write(" (params");
862 for param in *params {
863 self.write(" ");
864 self.visit_param(param);
865 }
866 self.write(")");
867 if !uses.is_empty() {
868 self.write(" (uses");
869 for u in *uses {
870 self.write(" ");
871 self.visit_closure_use(u);
872 }
873 self.write(")");
874 }
875 if let Some(rt) = return_type {
876 self.write(" (return-type ");
877 self.visit_type(rt);
878 self.write(")");
879 }
880 self.indent += 1;
881 self.newline();
882 self.write("(body");
883 self.indent += 1;
884 for stmt in *body {
885 self.newline();
886 self.visit_stmt(stmt);
887 }
888 self.indent -= 1;
889 self.write("))");
890 self.indent -= 1;
891 }
892 Expr::ArrowFunction {
893 attributes,
894 is_static,
895 by_ref,
896 params,
897 return_type,
898 expr,
899 ..
900 } => {
901 self.write("(arrow-function");
902 for attr in *attributes {
903 self.write(" ");
904 self.visit_attribute_group(attr);
905 }
906 if *is_static {
907 self.write(" static");
908 }
909 if *by_ref {
910 self.write(" &");
911 }
912 self.write(" (params");
913 for param in *params {
914 self.write(" ");
915 self.visit_param(param);
916 }
917 self.write(")");
918 if let Some(rt) = return_type {
919 self.write(" (return-type ");
920 self.visit_type(rt);
921 self.write(")");
922 }
923 self.write(" => ");
924 self.visit_expr(expr);
925 self.write(")");
926 }
927 Expr::Empty { expr, .. } => {
928 self.write("(empty ");
929 self.visit_expr(expr);
930 self.write(")");
931 }
932 Expr::Isset { vars, .. } => {
933 self.write("(isset");
934 for var in *vars {
935 self.write(" ");
936 self.visit_expr(var);
937 }
938 self.write(")");
939 }
940 Expr::Eval { expr, .. } => {
941 self.write("(eval ");
942 self.visit_expr(expr);
943 self.write(")");
944 }
945 Expr::Die { expr, .. } => {
946 self.write("(die");
947 if let Some(expr) = expr {
948 self.write(" ");
949 self.visit_expr(expr);
950 }
951 self.write(")");
952 }
953 Expr::Exit { expr, .. } => {
954 self.write("(exit");
955 if let Some(expr) = expr {
956 self.write(" ");
957 self.visit_expr(expr);
958 }
959 self.write(")");
960 }
961 Expr::Cast { kind, expr, .. } => {
962 self.write("(cast ");
963 self.write(match kind {
964 CastKind::Int => "int",
965 CastKind::Bool => "bool",
966 CastKind::Float => "float",
967 CastKind::String => "string",
968 CastKind::Array => "array",
969 CastKind::Object => "object",
970 CastKind::Unset => "unset",
971 CastKind::Void => "void",
972 });
973 self.write(" ");
974 self.visit_expr(expr);
975 self.write(")");
976 }
977 Expr::Yield {
978 key, value, from, ..
979 } => {
980 self.write("(yield");
981 if *from {
982 self.write("-from");
983 }
984 if let Some(key) = key {
985 self.write(" ");
986 self.visit_expr(key);
987 self.write(" =>");
988 }
989 if let Some(value) = value {
990 self.write(" ");
991 self.visit_expr(value);
992 }
993 self.write(")");
994 }
995 Expr::Print { expr, .. } => {
996 self.write("(print ");
997 self.visit_expr(expr);
998 self.write(")");
999 }
1000 Expr::Include { kind, expr, .. } => {
1001 self.write("(");
1002 self.write(match kind {
1003 IncludeKind::Include => "include",
1004 IncludeKind::IncludeOnce => "include_once",
1005 IncludeKind::Require => "require",
1006 IncludeKind::RequireOnce => "require_once",
1007 });
1008 self.write(" ");
1009 self.visit_expr(expr);
1010 self.write(")");
1011 }
1012 Expr::ShellExec { parts, .. } => {
1013 self.write("(shell-exec");
1014 for part in *parts {
1015 self.write(" ");
1016 self.visit_expr(part);
1017 }
1018 self.write(")");
1019 }
1020 Expr::InterpolatedString { parts, .. } => {
1021 self.write("(interpolated-string");
1022 for part in *parts {
1023 self.write(" ");
1024 self.visit_expr(part);
1025 }
1026 self.write(")");
1027 }
1028 Expr::MagicConst { kind, .. } => {
1029 self.write("(magic-const ");
1030 self.write(match kind {
1031 MagicConstKind::Line => "__LINE__",
1032 MagicConstKind::File => "__FILE__",
1033 MagicConstKind::Dir => "__DIR__",
1034 MagicConstKind::Function => "__FUNCTION__",
1035 MagicConstKind::Class => "__CLASS__",
1036 MagicConstKind::Trait => "__TRAIT__",
1037 MagicConstKind::Method => "__METHOD__",
1038 MagicConstKind::Namespace => "__NAMESPACE__",
1039 MagicConstKind::Property => "__PROPERTY__",
1040 });
1041 self.write(")");
1042 }
1043 Expr::Boolean { value, .. } => {
1044 self.write(if *value { "(true)" } else { "(false)" });
1045 }
1046 Expr::Null { .. } => self.write("(null)"),
1047 Expr::Float { value, .. } => {
1048 self.write("(float ");
1049 self.write(&String::from_utf8_lossy(value));
1050 self.write(")");
1051 }
1052 Expr::AnonymousClass {
1053 attributes,
1054 modifiers,
1055 args,
1056 extends,
1057 implements,
1058 members,
1059 ..
1060 } => {
1061 self.write("(anonymous-class");
1062 for attr in *attributes {
1063 self.write(" ");
1064 self.visit_attribute_group(attr);
1065 }
1066 for modifier in *modifiers {
1067 self.write(" ");
1068 self.write(&String::from_utf8_lossy(modifier.text(self.source)));
1069 }
1070 if !args.is_empty() {
1071 self.write(" (args");
1072 for arg in *args {
1073 self.write(" ");
1074 self.visit_arg(arg);
1075 }
1076 self.write(")");
1077 }
1078 if let Some(extends) = extends {
1079 self.write(" (extends ");
1080 self.visit_name(extends);
1081 self.write(")");
1082 }
1083 if !implements.is_empty() {
1084 self.write(" (implements");
1085 for iface in *implements {
1086 self.write(" ");
1087 self.visit_name(iface);
1088 }
1089 self.write(")");
1090 }
1091 self.indent += 1;
1092 self.newline();
1093 self.write("(members");
1094 self.indent += 1;
1095 for member in *members {
1096 self.newline();
1097 self.visit_class_member(member);
1098 }
1099 self.indent -= 1;
1100 self.write("))");
1101 self.indent -= 1;
1102 self.write(")");
1103 }
1104 Expr::NullsafePropertyFetch {
1105 target, property, ..
1106 } => {
1107 self.write("(nullsafe-property-fetch ");
1108 self.visit_expr(target);
1109 self.write("?->");
1110 self.visit_expr(property);
1111 self.write(")");
1112 }
1113 Expr::NullsafeMethodCall {
1114 target,
1115 method,
1116 args,
1117 ..
1118 } => {
1119 self.write("(nullsafe-method-call ");
1120 self.visit_expr(target);
1121 self.write("?->");
1122 self.visit_expr(method);
1123 self.write(" (args");
1124 for arg in *args {
1125 self.write(" ");
1126 self.visit_arg(arg);
1127 }
1128 self.write("))");
1129 }
1130 Expr::VariadicPlaceholder { .. } => self.write("(...)"),
1131 Expr::Error { .. } => self.write("(error)"),
1132 }
1133 }
1134
1135 fn visit_name(&mut self, name: &Name<'ast>) {
1136 for (i, part) in name.parts.iter().enumerate() {
1137 if i > 0 {
1138 self.write("\\");
1139 }
1140 self.write(&String::from_utf8_lossy(part.text(self.source)));
1141 }
1142 }
1143
1144 fn visit_case(&mut self, case: &'ast Case<'ast>) {
1145 self.write("(case");
1146 if let Some(cond) = case.condition {
1147 self.write(" ");
1148 self.visit_expr(cond);
1149 } else {
1150 self.write(" default");
1151 }
1152 self.indent += 1;
1153 for stmt in case.body {
1154 self.newline();
1155 self.visit_stmt(stmt);
1156 }
1157 self.indent -= 1;
1158 self.write(")");
1159 }
1160
1161 fn visit_catch(&mut self, catch: &'ast Catch<'ast>) {
1162 self.write("(catch (");
1163 for (i, ty) in catch.types.iter().enumerate() {
1164 if i > 0 {
1165 self.write("|");
1166 }
1167 self.visit_name(ty);
1168 }
1169 self.write(")");
1170 if let Some(var) = catch.var {
1171 self.write(" ");
1172 self.write(&String::from_utf8_lossy(var.text(self.source)));
1173 }
1174 self.indent += 1;
1175 for stmt in catch.body {
1176 self.newline();
1177 self.visit_stmt(stmt);
1178 }
1179 self.indent -= 1;
1180 self.write(")");
1181 }
1182
1183 fn visit_param(&mut self, param: &'ast Param<'ast>) {
1184 self.write("(");
1185 for attr in param.attributes {
1186 self.write(" ");
1187 self.visit_attribute_group(attr);
1188 }
1189 for modifier in param.modifiers {
1190 self.write(" ");
1191 self.write(&String::from_utf8_lossy(modifier.text(self.source)));
1192 }
1193 if let Some(ty) = param.ty {
1194 self.write(" ");
1195 self.visit_type(ty);
1196 self.write(" ");
1197 }
1198 if param.variadic {
1199 self.write("...");
1200 }
1201 if param.by_ref {
1202 self.write("&");
1203 }
1204 self.write(&String::from_utf8_lossy(param.name.text(self.source)));
1205 if let Some(default) = param.default {
1206 self.write(" = ");
1207 self.visit_expr(default);
1208 }
1209 if let Some(hooks) = param.hooks {
1210 self.write(" (hooks");
1211 for hook in hooks {
1212 self.write(" ");
1213 self.visit_property_hook(hook);
1214 }
1215 self.write(")");
1216 }
1217 self.write(")");
1218 }
1219
1220 fn visit_type(&mut self, ty: &'ast Type<'ast>) {
1221 match ty {
1222 Type::Simple(t) => self.write(&String::from_utf8_lossy(t.text(self.source))),
1223 Type::Name(n) => self.visit_name(n),
1224 Type::Union(types) => {
1225 self.write("(union");
1226 for t in *types {
1227 self.write(" ");
1228 self.visit_type(t);
1229 }
1230 self.write(")");
1231 }
1232 Type::Intersection(types) => {
1233 self.write("(intersection");
1234 for t in *types {
1235 self.write(" ");
1236 self.visit_type(t);
1237 }
1238 self.write(")");
1239 }
1240 Type::Nullable(t) => {
1241 self.write("?");
1242 self.visit_type(t);
1243 }
1244 }
1245 }
1246
1247 fn visit_class_member(&mut self, member: &'ast ClassMember<'ast>) {
1248 match member {
1249 ClassMember::Property {
1250 attributes,
1251 modifiers,
1252 ty,
1253 entries,
1254 ..
1255 } => {
1256 self.write("(property");
1257 for attr in *attributes {
1258 self.write(" ");
1259 self.visit_attribute_group(attr);
1260 }
1261 for modifier in *modifiers {
1262 self.write(" ");
1263 self.write(&String::from_utf8_lossy(modifier.text(self.source)));
1264 }
1265 if let Some(ty) = ty {
1266 self.write(" ");
1267 self.visit_type(ty);
1268 }
1269 for entry in *entries {
1270 self.write(" ");
1271 self.visit_property_entry(entry);
1272 }
1273 self.write(")");
1274 }
1275 ClassMember::Method {
1276 attributes,
1277 modifiers,
1278 name,
1279 params,
1280 return_type,
1281 body,
1282 ..
1283 } => {
1284 self.write("(method");
1285 for attr in *attributes {
1286 self.write(" ");
1287 self.visit_attribute_group(attr);
1288 }
1289 for modifier in *modifiers {
1290 self.write(" ");
1291 self.write(&String::from_utf8_lossy(modifier.text(self.source)));
1292 }
1293 self.write(" \"");
1294 self.write(&String::from_utf8_lossy(name.text(self.source)));
1295 self.write("\"");
1296 self.write(" (params");
1297 for param in *params {
1298 self.write(" ");
1299 self.visit_param(param);
1300 }
1301 self.write(")");
1302 if let Some(rt) = return_type {
1303 self.write(" (return-type ");
1304 self.visit_type(rt);
1305 self.write(")");
1306 }
1307 self.indent += 1;
1308 self.newline();
1309 self.write("(body");
1310 self.indent += 1;
1311 for stmt in *body {
1312 self.newline();
1313 self.visit_stmt(stmt);
1314 }
1315 self.indent -= 1;
1316 self.write("))");
1317 self.indent -= 1;
1318 }
1319 ClassMember::Const {
1320 attributes,
1321 modifiers,
1322 ty,
1323 consts,
1324 ..
1325 } => {
1326 self.write("(const");
1327 for attr in *attributes {
1328 self.write(" ");
1329 self.visit_attribute_group(attr);
1330 }
1331 for modifier in *modifiers {
1332 self.write(" ");
1333 self.write(&String::from_utf8_lossy(modifier.text(self.source)));
1334 }
1335 if let Some(ty) = ty {
1336 self.write(" ");
1337 self.visit_type(ty);
1338 }
1339 for c in *consts {
1340 self.write(" ");
1341 self.visit_class_const(c);
1342 }
1343 self.write(")");
1344 }
1345 ClassMember::TraitUse {
1346 attributes,
1347 traits,
1348 adaptations,
1349 ..
1350 } => {
1351 self.write("(trait-use");
1352 for attr in *attributes {
1353 self.write(" ");
1354 self.visit_attribute_group(attr);
1355 }
1356 for t in *traits {
1357 self.write(" ");
1358 self.visit_name(t);
1359 }
1360 if !adaptations.is_empty() {
1361 self.write(" (adaptations");
1362 for a in *adaptations {
1363 self.write(" ");
1364 self.visit_trait_adaptation(a);
1365 }
1366 self.write(")");
1367 }
1368 self.write(")");
1369 }
1370 ClassMember::Case {
1371 attributes,
1372 name,
1373 value,
1374 ..
1375 } => {
1376 self.write("(enum-case");
1377 for attr in *attributes {
1378 self.write(" ");
1379 self.visit_attribute_group(attr);
1380 }
1381 self.write(" \"");
1382 self.write(&String::from_utf8_lossy(name.text(self.source)));
1383 self.write("\"");
1384 if let Some(v) = value {
1385 self.write(" = ");
1386 self.visit_expr(v);
1387 }
1388 self.write(")");
1389 }
1390 ClassMember::PropertyHook {
1391 attributes,
1392 modifiers,
1393 ty,
1394 name,
1395 default,
1396 hooks,
1397 ..
1398 } => {
1399 self.write("(property-hook-def");
1400 for attr in *attributes {
1401 self.write(" ");
1402 self.visit_attribute_group(attr);
1403 }
1404 for modifier in *modifiers {
1405 self.write(" ");
1406 self.write(&String::from_utf8_lossy(modifier.text(self.source)));
1407 }
1408 if let Some(ty) = ty {
1409 self.write(" ");
1410 self.visit_type(ty);
1411 }
1412 self.write(" ");
1413 self.write(&String::from_utf8_lossy(name.text(self.source)));
1414 if let Some(default) = default {
1415 self.write(" = ");
1416 self.visit_expr(default);
1417 }
1418 if !hooks.is_empty() {
1419 self.indent += 1;
1420 self.newline();
1421 self.write("(hooks");
1422 self.indent += 1;
1423 for hook in *hooks {
1424 self.newline();
1425 self.visit_property_hook(hook);
1426 }
1427 self.indent -= 1;
1428 self.write(")");
1429 self.indent -= 1;
1430 }
1431 self.write(")");
1432 }
1433 }
1434 }
1435
1436 fn visit_arg(&mut self, arg: &'ast Arg<'ast>) {
1437 if let Some(name) = arg.name {
1438 self.write(&String::from_utf8_lossy(name.text(self.source)));
1439 self.write(": ");
1440 }
1441 if arg.unpack {
1442 self.write("...");
1443 }
1444 self.visit_expr(arg.value);
1445 }
1446
1447 fn visit_array_item(&mut self, item: &'ast ArrayItem<'ast>) {
1448 self.write("(");
1449 if let Some(key) = item.key {
1450 self.visit_expr(key);
1451 self.write(" => ");
1452 }
1453 if item.by_ref {
1454 self.write("&");
1455 }
1456 if item.unpack {
1457 self.write("...");
1458 }
1459 self.visit_expr(item.value);
1460 self.write(")");
1461 }
1462
1463 fn visit_match_arm(&mut self, arm: &'ast MatchArm<'ast>) {
1464 self.write("(arm");
1465 if let Some(conds) = arm.conditions {
1466 self.write(" (conds");
1467 for cond in conds {
1468 self.write(" ");
1469 self.visit_expr(cond);
1470 }
1471 self.write(")");
1472 } else {
1473 self.write(" default");
1474 }
1475 self.write(" => ");
1476 self.visit_expr(arm.body);
1477 self.write(")");
1478 }
1479
1480 fn visit_closure_use(&mut self, u: &'ast ClosureUse<'ast>) {
1481 if u.by_ref {
1482 self.write("&");
1483 }
1484 self.write(&String::from_utf8_lossy(u.var.text(self.source)));
1485 }
1486
1487 fn visit_trait_adaptation(&mut self, adaptation: &'ast TraitAdaptation<'ast>) {
1488 match adaptation {
1489 TraitAdaptation::Precedence {
1490 method, insteadof, ..
1491 } => {
1492 self.write("(precedence ");
1493 self.visit_trait_method_ref(method);
1494 self.write(" insteadof");
1495 for n in *insteadof {
1496 self.write(" ");
1497 self.visit_name(n);
1498 }
1499 self.write(")");
1500 }
1501 TraitAdaptation::Alias {
1502 method,
1503 alias,
1504 visibility,
1505 ..
1506 } => {
1507 self.write("(alias ");
1508 self.visit_trait_method_ref(method);
1509 self.write(" as");
1510 if let Some(vis) = visibility {
1511 self.write(" ");
1512 self.write(&String::from_utf8_lossy(vis.text(self.source)));
1513 }
1514 if let Some(alias) = alias {
1515 self.write(" \"");
1516 self.write(&String::from_utf8_lossy(alias.text(self.source)));
1517 self.write("\"");
1518 }
1519 self.write(")");
1520 }
1521 }
1522 }
1523
1524 fn visit_trait_method_ref(&mut self, method: &'ast TraitMethodRef<'ast>) {
1525 if let Some(trait_name) = method.trait_name {
1526 self.visit_name(&trait_name);
1527 self.write("::");
1528 }
1529 self.write(&String::from_utf8_lossy(method.method.text(self.source)));
1530 }
1531
1532 fn visit_attribute_group(&mut self, group: &'ast AttributeGroup<'ast>) {
1533 self.write("(attribute-group");
1534 for attr in group.attributes {
1535 self.write(" ");
1536 self.visit_attribute(attr);
1537 }
1538 self.write(")");
1539 }
1540
1541 fn visit_attribute(&mut self, attribute: &'ast Attribute<'ast>) {
1542 self.write("(attribute ");
1543 self.visit_name(&attribute.name);
1544 if !attribute.args.is_empty() {
1545 self.write(" (args");
1546 for arg in attribute.args {
1547 self.write(" ");
1548 self.visit_arg(arg);
1549 }
1550 self.write(")");
1551 }
1552 self.write(")");
1553 }
1554
1555 fn visit_static_var(&mut self, var: &'ast StaticVar<'ast>) {
1556 self.visit_expr(var.var);
1557 if let Some(default) = var.default {
1558 self.write(" = ");
1559 self.visit_expr(default);
1560 }
1561 }
1562
1563 fn visit_use_item(&mut self, use_item: &'ast UseItem<'ast>) {
1564 match use_item.kind {
1565 UseKind::Normal => {}
1566 UseKind::Function => self.write("function "),
1567 UseKind::Const => self.write("const "),
1568 }
1569 self.visit_name(&use_item.name);
1570 if let Some(alias) = use_item.alias {
1571 self.write(" as ");
1572 self.write(&String::from_utf8_lossy(alias.text(self.source)));
1573 }
1574 }
1575
1576 fn visit_class_const(&mut self, c: &'ast ClassConst<'ast>) {
1577 self.write(&String::from_utf8_lossy(c.name.text(self.source)));
1578 self.write(" = ");
1579 self.visit_expr(c.value);
1580 }
1581
1582 fn visit_declare_item(&mut self, declare: &'ast DeclareItem<'ast>) {
1583 self.write(&String::from_utf8_lossy(declare.key.text(self.source)));
1584 self.write("=");
1585 self.visit_expr(declare.value);
1586 }
1587
1588 fn visit_property_entry(&mut self, entry: &'ast PropertyEntry<'ast>) {
1589 self.write(&String::from_utf8_lossy(entry.name.text(self.source)));
1590 if let Some(default) = entry.default {
1591 self.write(" = ");
1592 self.visit_expr(default);
1593 }
1594 }
1595
1596 fn visit_parse_error(&mut self, error: &'ast ParseError) {
1597 self.write("(parse-error \"");
1598 self.write(error.message);
1599 self.write("\")");
1600 }
1601
1602 fn visit_property_hook(&mut self, hook: &'ast PropertyHook<'ast>) {
1603 self.write("(hook");
1604 for attr in hook.attributes {
1605 self.write(" ");
1606 self.visit_attribute_group(attr);
1607 }
1608 for modifier in hook.modifiers {
1609 self.write(" ");
1610 self.write(&String::from_utf8_lossy(modifier.text(self.source)));
1611 }
1612 if hook.by_ref {
1613 self.write(" &");
1614 }
1615 self.write(" ");
1616 self.write(&String::from_utf8_lossy(hook.name.text(self.source)));
1617
1618 if !hook.params.is_empty() {
1619 self.write(" (params");
1620 for param in hook.params {
1621 self.write(" ");
1622 self.visit_param(param);
1623 }
1624 self.write(")");
1625 }
1626
1627 self.write(" ");
1628 self.visit_property_hook_body(&hook.body);
1629 self.write(")");
1630 }
1631
1632 fn visit_property_hook_body(&mut self, body: &'ast PropertyHookBody<'ast>) {
1633 match body {
1634 PropertyHookBody::None => self.write("(none)"),
1635 PropertyHookBody::Expr(expr) => {
1636 self.write(" => ");
1637 self.visit_expr(expr);
1638 }
1639 PropertyHookBody::Statements(stmts) => {
1640 self.indent += 1;
1641 self.newline();
1642 self.write("(body");
1643 self.indent += 1;
1644 for stmt in *stmts {
1645 self.newline();
1646 self.visit_stmt(stmt);
1647 }
1648 self.indent -= 1;
1649 self.write(")");
1650 self.indent -= 1;
1651 }
1652 }
1653 }
1654}