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::Unary { op, expr, .. } => {
655 self.write("(");
656 self.write(match op {
657 UnaryOp::Plus => "+",
658 UnaryOp::Minus => "-",
659 UnaryOp::Not => "!",
660 UnaryOp::BitNot => "~",
661 UnaryOp::PreInc => "++",
662 UnaryOp::PreDec => "--",
663 UnaryOp::ErrorSuppress => "@",
664 UnaryOp::Reference => "&",
665 });
666 self.write(" ");
667 self.visit_expr(expr);
668 self.write(")");
669 }
670 Expr::PostInc { var, .. } => {
671 self.write("(post-inc ");
672 self.visit_expr(var);
673 self.write(")");
674 }
675 Expr::PostDec { var, .. } => {
676 self.write("(post-dec ");
677 self.visit_expr(var);
678 self.write(")");
679 }
680 Expr::AssignOp { var, op, expr, .. } => {
681 self.write("(assign-op ");
682 self.write(match op {
683 AssignOp::Plus => "+=",
684 AssignOp::Minus => "-=",
685 AssignOp::Mul => "*=",
686 AssignOp::Div => "/=",
687 AssignOp::Mod => "%=",
688 AssignOp::Concat => ".=",
689 AssignOp::BitAnd => "&=",
690 AssignOp::BitOr => "|=",
691 AssignOp::BitXor => "^=",
692 AssignOp::ShiftLeft => "<<=",
693 AssignOp::ShiftRight => ">>=",
694 AssignOp::Pow => "**=",
695 AssignOp::Coalesce => "??=",
696 });
697 self.write(" ");
698 self.visit_expr(var);
699 self.write(" ");
700 self.visit_expr(expr);
701 self.write(")");
702 }
703 Expr::AssignRef { var, expr, .. } => {
704 self.write("(assign-ref ");
705 self.visit_expr(var);
706 self.write(" ");
707 self.visit_expr(expr);
708 self.write(")");
709 }
710 Expr::Call { func, args, .. } => {
711 self.write("(call ");
712 self.visit_expr(func);
713 self.write(" (args");
714 for arg in *args {
715 self.write(" ");
716 self.visit_arg(arg);
717 }
718 self.write("))");
719 }
720 Expr::MethodCall {
721 target,
722 method,
723 args,
724 ..
725 } => {
726 self.write("(method-call ");
727 self.visit_expr(target);
728 self.write("->");
729 self.visit_expr(method);
730 self.write(" (args");
731 for arg in *args {
732 self.write(" ");
733 self.visit_arg(arg);
734 }
735 self.write("))");
736 }
737 Expr::StaticCall {
738 class,
739 method,
740 args,
741 ..
742 } => {
743 self.write("(static-call ");
744 self.visit_expr(class);
745 self.write("::");
746 self.visit_expr(method);
747 self.write(" (args");
748 for arg in *args {
749 self.write(" ");
750 self.visit_arg(arg);
751 }
752 self.write("))");
753 }
754 Expr::Array { items, .. } => {
755 self.write("(array");
756 for item in *items {
757 self.write(" ");
758 self.visit_array_item(item);
759 }
760 self.write(")");
761 }
762 Expr::ArrayDimFetch { array, dim, .. } => {
763 self.write("(array-dim-fetch ");
764 self.visit_expr(array);
765 if let Some(dim) = dim {
766 self.write(" ");
767 self.visit_expr(dim);
768 }
769 self.write(")");
770 }
771 Expr::PropertyFetch {
772 target, property, ..
773 } => {
774 self.write("(property-fetch ");
775 self.visit_expr(target);
776 self.write("->");
777 self.visit_expr(property);
778 self.write(")");
779 }
780 Expr::ClassConstFetch {
781 class, constant, ..
782 } => {
783 self.write("(class-const-fetch ");
784 self.visit_expr(class);
785 self.write("::");
786 self.visit_expr(constant);
787 self.write(")");
788 }
789 Expr::New { class, args, .. } => {
790 self.write("(new ");
791 self.visit_expr(class);
792 self.write(" (args");
793 for arg in *args {
794 self.write(" ");
795 self.visit_arg(arg);
796 }
797 self.write("))");
798 }
799 Expr::Clone { expr, .. } => {
800 self.write("(clone ");
801 self.visit_expr(expr);
802 self.write(")");
803 }
804 Expr::Ternary {
805 condition,
806 if_true,
807 if_false,
808 ..
809 } => {
810 self.write("(ternary ");
811 self.visit_expr(condition);
812 self.write(" ");
813 if let Some(t) = if_true {
814 self.visit_expr(t);
815 } else {
816 self.write("?");
817 }
818 self.write(" ");
819 self.visit_expr(if_false);
820 self.write(")");
821 }
822 Expr::Match {
823 condition, arms, ..
824 } => {
825 self.write("(match ");
826 self.visit_expr(condition);
827 self.indent += 1;
828 for arm in *arms {
829 self.newline();
830 self.visit_match_arm(arm);
831 }
832 self.indent -= 1;
833 self.write(")");
834 }
835 Expr::Closure {
836 attributes,
837 is_static,
838 by_ref,
839 params,
840 return_type,
841 body,
842 uses,
843 ..
844 } => {
845 self.write("(closure");
846 for attr in *attributes {
847 self.write(" ");
848 self.visit_attribute_group(attr);
849 }
850 if *is_static {
851 self.write(" static");
852 }
853 if *by_ref {
854 self.write(" &");
855 }
856 self.write(" (params");
857 for param in *params {
858 self.write(" ");
859 self.visit_param(param);
860 }
861 self.write(")");
862 if !uses.is_empty() {
863 self.write(" (uses");
864 for u in *uses {
865 self.write(" ");
866 self.visit_closure_use(u);
867 }
868 self.write(")");
869 }
870 if let Some(rt) = return_type {
871 self.write(" (return-type ");
872 self.visit_type(rt);
873 self.write(")");
874 }
875 self.indent += 1;
876 self.newline();
877 self.write("(body");
878 self.indent += 1;
879 for stmt in *body {
880 self.newline();
881 self.visit_stmt(stmt);
882 }
883 self.indent -= 1;
884 self.write("))");
885 self.indent -= 1;
886 }
887 Expr::ArrowFunction {
888 attributes,
889 is_static,
890 by_ref,
891 params,
892 return_type,
893 expr,
894 ..
895 } => {
896 self.write("(arrow-function");
897 for attr in *attributes {
898 self.write(" ");
899 self.visit_attribute_group(attr);
900 }
901 if *is_static {
902 self.write(" static");
903 }
904 if *by_ref {
905 self.write(" &");
906 }
907 self.write(" (params");
908 for param in *params {
909 self.write(" ");
910 self.visit_param(param);
911 }
912 self.write(")");
913 if let Some(rt) = return_type {
914 self.write(" (return-type ");
915 self.visit_type(rt);
916 self.write(")");
917 }
918 self.write(" => ");
919 self.visit_expr(expr);
920 self.write(")");
921 }
922 Expr::Empty { expr, .. } => {
923 self.write("(empty ");
924 self.visit_expr(expr);
925 self.write(")");
926 }
927 Expr::Isset { vars, .. } => {
928 self.write("(isset");
929 for var in *vars {
930 self.write(" ");
931 self.visit_expr(var);
932 }
933 self.write(")");
934 }
935 Expr::Eval { expr, .. } => {
936 self.write("(eval ");
937 self.visit_expr(expr);
938 self.write(")");
939 }
940 Expr::Die { expr, .. } => {
941 self.write("(die");
942 if let Some(expr) = expr {
943 self.write(" ");
944 self.visit_expr(expr);
945 }
946 self.write(")");
947 }
948 Expr::Exit { expr, .. } => {
949 self.write("(exit");
950 if let Some(expr) = expr {
951 self.write(" ");
952 self.visit_expr(expr);
953 }
954 self.write(")");
955 }
956 Expr::Cast { kind, expr, .. } => {
957 self.write("(cast ");
958 self.write(match kind {
959 CastKind::Int => "int",
960 CastKind::Bool => "bool",
961 CastKind::Float => "float",
962 CastKind::String => "string",
963 CastKind::Array => "array",
964 CastKind::Object => "object",
965 CastKind::Unset => "unset",
966 CastKind::Void => "void",
967 });
968 self.write(" ");
969 self.visit_expr(expr);
970 self.write(")");
971 }
972 Expr::Yield {
973 key, value, from, ..
974 } => {
975 self.write("(yield");
976 if *from {
977 self.write("-from");
978 }
979 if let Some(key) = key {
980 self.write(" ");
981 self.visit_expr(key);
982 self.write(" =>");
983 }
984 if let Some(value) = value {
985 self.write(" ");
986 self.visit_expr(value);
987 }
988 self.write(")");
989 }
990 Expr::Print { expr, .. } => {
991 self.write("(print ");
992 self.visit_expr(expr);
993 self.write(")");
994 }
995 Expr::Include { kind, expr, .. } => {
996 self.write("(");
997 self.write(match kind {
998 IncludeKind::Include => "include",
999 IncludeKind::IncludeOnce => "include_once",
1000 IncludeKind::Require => "require",
1001 IncludeKind::RequireOnce => "require_once",
1002 });
1003 self.write(" ");
1004 self.visit_expr(expr);
1005 self.write(")");
1006 }
1007 Expr::ShellExec { parts, .. } => {
1008 self.write("(shell-exec");
1009 for part in *parts {
1010 self.write(" ");
1011 self.visit_expr(part);
1012 }
1013 self.write(")");
1014 }
1015 Expr::InterpolatedString { parts, .. } => {
1016 self.write("(interpolated-string");
1017 for part in *parts {
1018 self.write(" ");
1019 self.visit_expr(part);
1020 }
1021 self.write(")");
1022 }
1023 Expr::MagicConst { kind, .. } => {
1024 self.write("(magic-const ");
1025 self.write(match kind {
1026 MagicConstKind::Line => "__LINE__",
1027 MagicConstKind::File => "__FILE__",
1028 MagicConstKind::Dir => "__DIR__",
1029 MagicConstKind::Function => "__FUNCTION__",
1030 MagicConstKind::Class => "__CLASS__",
1031 MagicConstKind::Trait => "__TRAIT__",
1032 MagicConstKind::Method => "__METHOD__",
1033 MagicConstKind::Namespace => "__NAMESPACE__",
1034 MagicConstKind::Property => "__PROPERTY__",
1035 });
1036 self.write(")");
1037 }
1038 Expr::Boolean { value, .. } => {
1039 self.write(if *value { "(true)" } else { "(false)" });
1040 }
1041 Expr::Null { .. } => self.write("(null)"),
1042 Expr::Float { value, .. } => {
1043 self.write("(float ");
1044 self.write(&String::from_utf8_lossy(value));
1045 self.write(")");
1046 }
1047 Expr::AnonymousClass {
1048 attributes,
1049 modifiers,
1050 args,
1051 extends,
1052 implements,
1053 members,
1054 ..
1055 } => {
1056 self.write("(anonymous-class");
1057 for attr in *attributes {
1058 self.write(" ");
1059 self.visit_attribute_group(attr);
1060 }
1061 for modifier in *modifiers {
1062 self.write(" ");
1063 self.write(&String::from_utf8_lossy(modifier.text(self.source)));
1064 }
1065 if !args.is_empty() {
1066 self.write(" (args");
1067 for arg in *args {
1068 self.write(" ");
1069 self.visit_arg(arg);
1070 }
1071 self.write(")");
1072 }
1073 if let Some(extends) = extends {
1074 self.write(" (extends ");
1075 self.visit_name(extends);
1076 self.write(")");
1077 }
1078 if !implements.is_empty() {
1079 self.write(" (implements");
1080 for iface in *implements {
1081 self.write(" ");
1082 self.visit_name(iface);
1083 }
1084 self.write(")");
1085 }
1086 self.indent += 1;
1087 self.newline();
1088 self.write("(members");
1089 self.indent += 1;
1090 for member in *members {
1091 self.newline();
1092 self.visit_class_member(member);
1093 }
1094 self.indent -= 1;
1095 self.write("))");
1096 self.indent -= 1;
1097 self.write(")");
1098 }
1099 Expr::NullsafePropertyFetch {
1100 target, property, ..
1101 } => {
1102 self.write("(nullsafe-property-fetch ");
1103 self.visit_expr(target);
1104 self.write("?->");
1105 self.visit_expr(property);
1106 self.write(")");
1107 }
1108 Expr::NullsafeMethodCall {
1109 target,
1110 method,
1111 args,
1112 ..
1113 } => {
1114 self.write("(nullsafe-method-call ");
1115 self.visit_expr(target);
1116 self.write("?->");
1117 self.visit_expr(method);
1118 self.write(" (args");
1119 for arg in *args {
1120 self.write(" ");
1121 self.visit_arg(arg);
1122 }
1123 self.write("))");
1124 }
1125 Expr::VariadicPlaceholder { .. } => self.write("(...)"),
1126 Expr::Error { .. } => self.write("(error)"),
1127 }
1128 }
1129
1130 fn visit_name(&mut self, name: &Name<'ast>) {
1131 for (i, part) in name.parts.iter().enumerate() {
1132 if i > 0 {
1133 self.write("\\");
1134 }
1135 self.write(&String::from_utf8_lossy(part.text(self.source)));
1136 }
1137 }
1138
1139 fn visit_case(&mut self, case: &'ast Case<'ast>) {
1140 self.write("(case");
1141 if let Some(cond) = case.condition {
1142 self.write(" ");
1143 self.visit_expr(cond);
1144 } else {
1145 self.write(" default");
1146 }
1147 self.indent += 1;
1148 for stmt in case.body {
1149 self.newline();
1150 self.visit_stmt(stmt);
1151 }
1152 self.indent -= 1;
1153 self.write(")");
1154 }
1155
1156 fn visit_catch(&mut self, catch: &'ast Catch<'ast>) {
1157 self.write("(catch (");
1158 for (i, ty) in catch.types.iter().enumerate() {
1159 if i > 0 {
1160 self.write("|");
1161 }
1162 self.visit_name(ty);
1163 }
1164 self.write(")");
1165 if let Some(var) = catch.var {
1166 self.write(" ");
1167 self.write(&String::from_utf8_lossy(var.text(self.source)));
1168 }
1169 self.indent += 1;
1170 for stmt in catch.body {
1171 self.newline();
1172 self.visit_stmt(stmt);
1173 }
1174 self.indent -= 1;
1175 self.write(")");
1176 }
1177
1178 fn visit_param(&mut self, param: &'ast Param<'ast>) {
1179 self.write("(");
1180 for attr in param.attributes {
1181 self.write(" ");
1182 self.visit_attribute_group(attr);
1183 }
1184 for modifier in param.modifiers {
1185 self.write(" ");
1186 self.write(&String::from_utf8_lossy(modifier.text(self.source)));
1187 }
1188 if let Some(ty) = param.ty {
1189 self.write(" ");
1190 self.visit_type(ty);
1191 self.write(" ");
1192 }
1193 if param.variadic {
1194 self.write("...");
1195 }
1196 if param.by_ref {
1197 self.write("&");
1198 }
1199 self.write(&String::from_utf8_lossy(param.name.text(self.source)));
1200 if let Some(default) = param.default {
1201 self.write(" = ");
1202 self.visit_expr(default);
1203 }
1204 if let Some(hooks) = param.hooks {
1205 self.write(" (hooks");
1206 for hook in hooks {
1207 self.write(" ");
1208 self.visit_property_hook(hook);
1209 }
1210 self.write(")");
1211 }
1212 self.write(")");
1213 }
1214
1215 fn visit_type(&mut self, ty: &'ast Type<'ast>) {
1216 match ty {
1217 Type::Simple(t) => self.write(&String::from_utf8_lossy(t.text(self.source))),
1218 Type::Name(n) => self.visit_name(n),
1219 Type::Union(types) => {
1220 self.write("(union");
1221 for t in *types {
1222 self.write(" ");
1223 self.visit_type(t);
1224 }
1225 self.write(")");
1226 }
1227 Type::Intersection(types) => {
1228 self.write("(intersection");
1229 for t in *types {
1230 self.write(" ");
1231 self.visit_type(t);
1232 }
1233 self.write(")");
1234 }
1235 Type::Nullable(t) => {
1236 self.write("?");
1237 self.visit_type(t);
1238 }
1239 }
1240 }
1241
1242 fn visit_class_member(&mut self, member: &'ast ClassMember<'ast>) {
1243 match member {
1244 ClassMember::Property {
1245 attributes,
1246 modifiers,
1247 ty,
1248 entries,
1249 ..
1250 } => {
1251 self.write("(property");
1252 for attr in *attributes {
1253 self.write(" ");
1254 self.visit_attribute_group(attr);
1255 }
1256 for modifier in *modifiers {
1257 self.write(" ");
1258 self.write(&String::from_utf8_lossy(modifier.text(self.source)));
1259 }
1260 if let Some(ty) = ty {
1261 self.write(" ");
1262 self.visit_type(ty);
1263 }
1264 for entry in *entries {
1265 self.write(" ");
1266 self.visit_property_entry(entry);
1267 }
1268 self.write(")");
1269 }
1270 ClassMember::Method {
1271 attributes,
1272 modifiers,
1273 name,
1274 params,
1275 return_type,
1276 body,
1277 ..
1278 } => {
1279 self.write("(method");
1280 for attr in *attributes {
1281 self.write(" ");
1282 self.visit_attribute_group(attr);
1283 }
1284 for modifier in *modifiers {
1285 self.write(" ");
1286 self.write(&String::from_utf8_lossy(modifier.text(self.source)));
1287 }
1288 self.write(" \"");
1289 self.write(&String::from_utf8_lossy(name.text(self.source)));
1290 self.write("\"");
1291 self.write(" (params");
1292 for param in *params {
1293 self.write(" ");
1294 self.visit_param(param);
1295 }
1296 self.write(")");
1297 if let Some(rt) = return_type {
1298 self.write(" (return-type ");
1299 self.visit_type(rt);
1300 self.write(")");
1301 }
1302 self.indent += 1;
1303 self.newline();
1304 self.write("(body");
1305 self.indent += 1;
1306 for stmt in *body {
1307 self.newline();
1308 self.visit_stmt(stmt);
1309 }
1310 self.indent -= 1;
1311 self.write("))");
1312 self.indent -= 1;
1313 }
1314 ClassMember::Const {
1315 attributes,
1316 modifiers,
1317 ty,
1318 consts,
1319 ..
1320 } => {
1321 self.write("(const");
1322 for attr in *attributes {
1323 self.write(" ");
1324 self.visit_attribute_group(attr);
1325 }
1326 for modifier in *modifiers {
1327 self.write(" ");
1328 self.write(&String::from_utf8_lossy(modifier.text(self.source)));
1329 }
1330 if let Some(ty) = ty {
1331 self.write(" ");
1332 self.visit_type(ty);
1333 }
1334 for c in *consts {
1335 self.write(" ");
1336 self.visit_class_const(c);
1337 }
1338 self.write(")");
1339 }
1340 ClassMember::TraitUse {
1341 attributes,
1342 traits,
1343 adaptations,
1344 ..
1345 } => {
1346 self.write("(trait-use");
1347 for attr in *attributes {
1348 self.write(" ");
1349 self.visit_attribute_group(attr);
1350 }
1351 for t in *traits {
1352 self.write(" ");
1353 self.visit_name(t);
1354 }
1355 if !adaptations.is_empty() {
1356 self.write(" (adaptations");
1357 for a in *adaptations {
1358 self.write(" ");
1359 self.visit_trait_adaptation(a);
1360 }
1361 self.write(")");
1362 }
1363 self.write(")");
1364 }
1365 ClassMember::Case {
1366 attributes,
1367 name,
1368 value,
1369 ..
1370 } => {
1371 self.write("(enum-case");
1372 for attr in *attributes {
1373 self.write(" ");
1374 self.visit_attribute_group(attr);
1375 }
1376 self.write(" \"");
1377 self.write(&String::from_utf8_lossy(name.text(self.source)));
1378 self.write("\"");
1379 if let Some(v) = value {
1380 self.write(" = ");
1381 self.visit_expr(v);
1382 }
1383 self.write(")");
1384 }
1385 ClassMember::PropertyHook {
1386 attributes,
1387 modifiers,
1388 ty,
1389 name,
1390 default,
1391 hooks,
1392 ..
1393 } => {
1394 self.write("(property-hook-def");
1395 for attr in *attributes {
1396 self.write(" ");
1397 self.visit_attribute_group(attr);
1398 }
1399 for modifier in *modifiers {
1400 self.write(" ");
1401 self.write(&String::from_utf8_lossy(modifier.text(self.source)));
1402 }
1403 if let Some(ty) = ty {
1404 self.write(" ");
1405 self.visit_type(ty);
1406 }
1407 self.write(" ");
1408 self.write(&String::from_utf8_lossy(name.text(self.source)));
1409 if let Some(default) = default {
1410 self.write(" = ");
1411 self.visit_expr(default);
1412 }
1413 if !hooks.is_empty() {
1414 self.indent += 1;
1415 self.newline();
1416 self.write("(hooks");
1417 self.indent += 1;
1418 for hook in *hooks {
1419 self.newline();
1420 self.visit_property_hook(hook);
1421 }
1422 self.indent -= 1;
1423 self.write(")");
1424 self.indent -= 1;
1425 }
1426 self.write(")");
1427 }
1428 }
1429 }
1430
1431 fn visit_arg(&mut self, arg: &'ast Arg<'ast>) {
1432 if let Some(name) = arg.name {
1433 self.write(&String::from_utf8_lossy(name.text(self.source)));
1434 self.write(": ");
1435 }
1436 if arg.unpack {
1437 self.write("...");
1438 }
1439 self.visit_expr(arg.value);
1440 }
1441
1442 fn visit_array_item(&mut self, item: &'ast ArrayItem<'ast>) {
1443 self.write("(");
1444 if let Some(key) = item.key {
1445 self.visit_expr(key);
1446 self.write(" => ");
1447 }
1448 if item.by_ref {
1449 self.write("&");
1450 }
1451 if item.unpack {
1452 self.write("...");
1453 }
1454 self.visit_expr(item.value);
1455 self.write(")");
1456 }
1457
1458 fn visit_match_arm(&mut self, arm: &'ast MatchArm<'ast>) {
1459 self.write("(arm");
1460 if let Some(conds) = arm.conditions {
1461 self.write(" (conds");
1462 for cond in conds {
1463 self.write(" ");
1464 self.visit_expr(cond);
1465 }
1466 self.write(")");
1467 } else {
1468 self.write(" default");
1469 }
1470 self.write(" => ");
1471 self.visit_expr(arm.body);
1472 self.write(")");
1473 }
1474
1475 fn visit_closure_use(&mut self, u: &'ast ClosureUse<'ast>) {
1476 if u.by_ref {
1477 self.write("&");
1478 }
1479 self.write(&String::from_utf8_lossy(u.var.text(self.source)));
1480 }
1481
1482 fn visit_trait_adaptation(&mut self, adaptation: &'ast TraitAdaptation<'ast>) {
1483 match adaptation {
1484 TraitAdaptation::Precedence {
1485 method, insteadof, ..
1486 } => {
1487 self.write("(precedence ");
1488 self.visit_trait_method_ref(method);
1489 self.write(" insteadof");
1490 for n in *insteadof {
1491 self.write(" ");
1492 self.visit_name(n);
1493 }
1494 self.write(")");
1495 }
1496 TraitAdaptation::Alias {
1497 method,
1498 alias,
1499 visibility,
1500 ..
1501 } => {
1502 self.write("(alias ");
1503 self.visit_trait_method_ref(method);
1504 self.write(" as");
1505 if let Some(vis) = visibility {
1506 self.write(" ");
1507 self.write(&String::from_utf8_lossy(vis.text(self.source)));
1508 }
1509 if let Some(alias) = alias {
1510 self.write(" \"");
1511 self.write(&String::from_utf8_lossy(alias.text(self.source)));
1512 self.write("\"");
1513 }
1514 self.write(")");
1515 }
1516 }
1517 }
1518
1519 fn visit_trait_method_ref(&mut self, method: &'ast TraitMethodRef<'ast>) {
1520 if let Some(trait_name) = method.trait_name {
1521 self.visit_name(&trait_name);
1522 self.write("::");
1523 }
1524 self.write(&String::from_utf8_lossy(method.method.text(self.source)));
1525 }
1526
1527 fn visit_attribute_group(&mut self, group: &'ast AttributeGroup<'ast>) {
1528 self.write("(attribute-group");
1529 for attr in group.attributes {
1530 self.write(" ");
1531 self.visit_attribute(attr);
1532 }
1533 self.write(")");
1534 }
1535
1536 fn visit_attribute(&mut self, attribute: &'ast Attribute<'ast>) {
1537 self.write("(attribute ");
1538 self.visit_name(&attribute.name);
1539 if !attribute.args.is_empty() {
1540 self.write(" (args");
1541 for arg in attribute.args {
1542 self.write(" ");
1543 self.visit_arg(arg);
1544 }
1545 self.write(")");
1546 }
1547 self.write(")");
1548 }
1549
1550 fn visit_static_var(&mut self, var: &'ast StaticVar<'ast>) {
1551 self.visit_expr(var.var);
1552 if let Some(default) = var.default {
1553 self.write(" = ");
1554 self.visit_expr(default);
1555 }
1556 }
1557
1558 fn visit_use_item(&mut self, use_item: &'ast UseItem<'ast>) {
1559 match use_item.kind {
1560 UseKind::Normal => {}
1561 UseKind::Function => self.write("function "),
1562 UseKind::Const => self.write("const "),
1563 }
1564 self.visit_name(&use_item.name);
1565 if let Some(alias) = use_item.alias {
1566 self.write(" as ");
1567 self.write(&String::from_utf8_lossy(alias.text(self.source)));
1568 }
1569 }
1570
1571 fn visit_class_const(&mut self, c: &'ast ClassConst<'ast>) {
1572 self.write(&String::from_utf8_lossy(c.name.text(self.source)));
1573 self.write(" = ");
1574 self.visit_expr(c.value);
1575 }
1576
1577 fn visit_declare_item(&mut self, declare: &'ast DeclareItem<'ast>) {
1578 self.write(&String::from_utf8_lossy(declare.key.text(self.source)));
1579 self.write("=");
1580 self.visit_expr(declare.value);
1581 }
1582
1583 fn visit_property_entry(&mut self, entry: &'ast PropertyEntry<'ast>) {
1584 self.write(&String::from_utf8_lossy(entry.name.text(self.source)));
1585 if let Some(default) = entry.default {
1586 self.write(" = ");
1587 self.visit_expr(default);
1588 }
1589 }
1590
1591 fn visit_parse_error(&mut self, error: &'ast ParseError) {
1592 self.write("(parse-error \"");
1593 self.write(error.message);
1594 self.write("\")");
1595 }
1596
1597 fn visit_property_hook(&mut self, hook: &'ast PropertyHook<'ast>) {
1598 self.write("(hook");
1599 for attr in hook.attributes {
1600 self.write(" ");
1601 self.visit_attribute_group(attr);
1602 }
1603 for modifier in hook.modifiers {
1604 self.write(" ");
1605 self.write(&String::from_utf8_lossy(modifier.text(self.source)));
1606 }
1607 if hook.by_ref {
1608 self.write(" &");
1609 }
1610 self.write(" ");
1611 self.write(&String::from_utf8_lossy(hook.name.text(self.source)));
1612
1613 if !hook.params.is_empty() {
1614 self.write(" (params");
1615 for param in hook.params {
1616 self.write(" ");
1617 self.visit_param(param);
1618 }
1619 self.write(")");
1620 }
1621
1622 self.write(" ");
1623 self.visit_property_hook_body(&hook.body);
1624 self.write(")");
1625 }
1626
1627 fn visit_property_hook_body(&mut self, body: &'ast PropertyHookBody<'ast>) {
1628 match body {
1629 PropertyHookBody::None => self.write("(none)"),
1630 PropertyHookBody::Expr(expr) => {
1631 self.write(" => ");
1632 self.visit_expr(expr);
1633 }
1634 PropertyHookBody::Statements(stmts) => {
1635 self.indent += 1;
1636 self.newline();
1637 self.write("(body");
1638 self.indent += 1;
1639 for stmt in *stmts {
1640 self.newline();
1641 self.visit_stmt(stmt);
1642 }
1643 self.indent -= 1;
1644 self.write(")");
1645 self.indent -= 1;
1646 }
1647 }
1648 }
1649}