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