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