php_parser/ast/
sexpr.rs

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}