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