1#![forbid(unsafe_code)]
2use std::fmt::Write;
14
15pub type NodeId = String;
17
18pub type Rank = String;
20
21pub type SlotName = String;
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub struct Span {
27 pub start: usize,
28 pub end: usize,
29}
30
31#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct Meta {
34 pub id: NodeId,
35 pub rank: Option<Rank>,
36 pub anchor: Option<NodeId>,
37 pub slot: Option<SlotName>,
38 pub span: Option<Span>,
39}
40
41impl Meta {
42 pub fn without_span(&self) -> Self {
44 let mut meta = self.clone();
45 meta.span = None;
46 meta
47 }
48}
49
50#[derive(Debug, Clone, PartialEq, Eq)]
52pub struct File {
53 pub items: Vec<Item>,
54}
55
56impl File {
57 pub fn without_spans(&self) -> Self {
59 let mut file = self.clone();
60 file.clear_spans();
61 file
62 }
63
64 pub fn clear_spans(&mut self) {
66 for item in &mut self.items {
67 item.clear_spans();
68 }
69 }
70
71 pub fn to_json_pretty(&self) -> String {
73 let mut out = String::new();
74 write_file_json(self, &mut out, 0);
75 out.push('\n');
76 out
77 }
78}
79
80#[derive(Debug, Clone, PartialEq, Eq)]
82pub enum Item {
83 Mod(ItemMod),
84 Use(ItemUse),
85 Struct(ItemStruct),
86 Enum(ItemEnum),
87 Fn(ItemFn),
88 Doc(DocNode),
89 Comment(CommentNode),
90}
91
92impl Item {
93 pub fn meta(&self) -> &Meta {
95 match self {
96 Self::Mod(node) => &node.meta,
97 Self::Use(node) => &node.meta,
98 Self::Struct(node) => &node.meta,
99 Self::Enum(node) => &node.meta,
100 Self::Fn(node) => &node.meta,
101 Self::Doc(node) => &node.meta,
102 Self::Comment(node) => &node.meta,
103 }
104 }
105
106 pub fn meta_mut(&mut self) -> &mut Meta {
108 match self {
109 Self::Mod(node) => &mut node.meta,
110 Self::Use(node) => &mut node.meta,
111 Self::Struct(node) => &mut node.meta,
112 Self::Enum(node) => &mut node.meta,
113 Self::Fn(node) => &mut node.meta,
114 Self::Doc(node) => &mut node.meta,
115 Self::Comment(node) => &mut node.meta,
116 }
117 }
118
119 pub fn clear_spans(&mut self) {
121 self.meta_mut().span = None;
122 match self {
123 Self::Mod(node) => {
124 for item in &mut node.items {
125 item.clear_spans();
126 }
127 }
128 Self::Use(_) => {}
129 Self::Struct(node) => {
130 for field in &mut node.fields {
131 field.clear_spans();
132 }
133 }
134 Self::Enum(node) => {
135 for variant in &mut node.variants {
136 variant.clear_spans();
137 }
138 }
139 Self::Fn(node) => {
140 for param in &mut node.params {
141 param.clear_spans();
142 }
143 if let Some(ret_ty) = &mut node.ret_ty {
144 ret_ty.clear_spans();
145 }
146 node.body.clear_spans();
147 }
148 Self::Doc(_) => {}
149 Self::Comment(_) => {}
150 }
151 }
152}
153
154#[derive(Debug, Clone, PartialEq, Eq)]
156pub struct ItemMod {
157 pub meta: Meta,
158 pub name: String,
159 pub items: Vec<Item>,
160}
161
162#[derive(Debug, Clone, PartialEq, Eq)]
164pub struct ItemUse {
165 pub meta: Meta,
167 pub tree: UseTree,
169}
170
171#[derive(Debug, Clone, PartialEq, Eq)]
173pub enum UseTree {
174 Name(UseName),
176 Path(UsePathTree),
178 Group(UseGroup),
180 Glob(UseGlob),
182}
183
184#[derive(Debug, Clone, PartialEq, Eq)]
186pub struct UseName {
187 pub name: String,
189}
190
191#[derive(Debug, Clone, PartialEq, Eq)]
193pub struct UsePathTree {
194 pub prefix: String,
196 pub tree: Box<UseTree>,
198}
199
200#[derive(Debug, Clone, PartialEq, Eq)]
202pub struct UseGroup {
203 pub items: Vec<UseTree>,
205}
206
207#[derive(Debug, Clone, PartialEq, Eq)]
209pub struct UseGlob;
210
211#[derive(Debug, Clone, PartialEq, Eq)]
213pub struct ItemStruct {
214 pub meta: Meta,
215 pub name: String,
216 pub fields: Vec<Field>,
217}
218
219#[derive(Debug, Clone, PartialEq, Eq)]
221pub struct ItemEnum {
222 pub meta: Meta,
223 pub name: String,
224 pub variants: Vec<Variant>,
225}
226
227#[derive(Debug, Clone, PartialEq, Eq)]
229pub struct ItemFn {
230 pub meta: Meta,
231 pub name: String,
232 pub params: Vec<Param>,
233 pub ret_ty: Option<Type>,
234 pub body: Block,
235}
236
237#[derive(Debug, Clone, PartialEq, Eq)]
239pub struct Field {
240 pub meta: Meta,
241 pub name: String,
242 pub ty: Type,
243}
244
245impl Field {
246 pub fn clear_spans(&mut self) {
248 self.meta.span = None;
249 self.ty.clear_spans();
250 }
251}
252
253#[derive(Debug, Clone, PartialEq, Eq)]
255pub struct Variant {
256 pub meta: Meta,
257 pub name: String,
258}
259
260impl Variant {
261 pub fn clear_spans(&mut self) {
263 self.meta.span = None;
264 }
265}
266
267#[derive(Debug, Clone, PartialEq, Eq)]
269pub struct Param {
270 pub meta: Meta,
271 pub name: String,
272 pub ty: Type,
273}
274
275impl Param {
276 pub fn clear_spans(&mut self) {
278 self.meta.span = None;
279 self.ty.clear_spans();
280 }
281}
282
283#[derive(Debug, Clone, PartialEq, Eq)]
285pub struct Block {
286 pub meta: Option<Meta>,
287 pub stmts: Vec<Stmt>,
288}
289
290impl Block {
291 pub fn clear_spans(&mut self) {
293 if let Some(meta) = &mut self.meta {
294 meta.span = None;
295 }
296 for stmt in &mut self.stmts {
297 stmt.clear_spans();
298 }
299 }
300}
301
302#[derive(Debug, Clone, PartialEq, Eq)]
304pub enum Stmt {
305 Let(StmtLet),
306 Expr(StmtExpr),
307 Item(Item),
308 Doc(DocNode),
309 Comment(CommentNode),
310}
311
312impl Stmt {
313 pub fn meta(&self) -> Option<&Meta> {
315 match self {
316 Self::Let(node) => Some(&node.meta),
317 Self::Expr(node) => Some(&node.meta),
318 Self::Item(node) => Some(node.meta()),
319 Self::Doc(node) => Some(&node.meta),
320 Self::Comment(node) => Some(&node.meta),
321 }
322 }
323
324 pub fn clear_spans(&mut self) {
326 match self {
327 Self::Let(node) => node.clear_spans(),
328 Self::Expr(node) => node.clear_spans(),
329 Self::Item(node) => node.clear_spans(),
330 Self::Doc(node) => node.meta.span = None,
331 Self::Comment(node) => node.meta.span = None,
332 }
333 }
334}
335
336#[derive(Debug, Clone, PartialEq, Eq)]
338pub struct StmtLet {
339 pub meta: Meta,
340 pub pat: Pattern,
341 pub value: Expr,
342}
343
344impl StmtLet {
345 pub fn clear_spans(&mut self) {
347 self.meta.span = None;
348 self.pat.clear_spans();
349 self.value.clear_spans();
350 }
351}
352
353#[derive(Debug, Clone, PartialEq, Eq)]
355pub struct StmtExpr {
356 pub meta: Meta,
358 pub expr: Expr,
360 pub has_semi: bool,
362}
363
364impl StmtExpr {
365 pub fn clear_spans(&mut self) {
367 self.meta.span = None;
368 self.expr.clear_spans();
369 }
370}
371
372#[derive(Debug, Clone, PartialEq, Eq)]
374pub enum Expr {
375 Path(ExprPath),
376 Lit(ExprLit),
377 Group(ExprGroup),
378 Binary(ExprBinary),
379 Unary(ExprUnary),
380 Call(ExprCall),
381 Match(ExprMatch),
382 Block(Block),
383}
384
385impl Expr {
386 pub fn meta(&self) -> Option<&Meta> {
388 match self {
389 Self::Path(node) => node.meta.as_ref(),
390 Self::Lit(node) => node.meta.as_ref(),
391 Self::Group(node) => node.meta.as_ref(),
392 Self::Binary(node) => node.meta.as_ref(),
393 Self::Unary(node) => node.meta.as_ref(),
394 Self::Call(node) => node.meta.as_ref(),
395 Self::Match(node) => node.meta.as_ref(),
396 Self::Block(node) => node.meta.as_ref(),
397 }
398 }
399
400 pub fn meta_mut(&mut self) -> Option<&mut Meta> {
402 match self {
403 Self::Path(node) => node.meta.as_mut(),
404 Self::Lit(node) => node.meta.as_mut(),
405 Self::Group(node) => node.meta.as_mut(),
406 Self::Binary(node) => node.meta.as_mut(),
407 Self::Unary(node) => node.meta.as_mut(),
408 Self::Call(node) => node.meta.as_mut(),
409 Self::Match(node) => node.meta.as_mut(),
410 Self::Block(node) => node.meta.as_mut(),
411 }
412 }
413
414 pub fn clear_spans(&mut self) {
416 if let Some(meta) = self.meta_mut() {
417 meta.span = None;
418 }
419 match self {
420 Self::Path(_) => {}
421 Self::Lit(_) => {}
422 Self::Group(node) => {
423 node.expr.clear_spans();
424 }
425 Self::Binary(node) => {
426 node.lhs.clear_spans();
427 node.rhs.clear_spans();
428 }
429 Self::Unary(node) => {
430 node.expr.clear_spans();
431 }
432 Self::Call(node) => {
433 node.callee.clear_spans();
434 for arg in &mut node.args {
435 arg.clear_spans();
436 }
437 }
438 Self::Match(node) => {
439 node.scrutinee.clear_spans();
440 for arm in &mut node.arms {
441 arm.clear_spans();
442 }
443 }
444 Self::Block(node) => node.clear_spans(),
445 }
446 }
447}
448
449#[derive(Debug, Clone, PartialEq, Eq)]
451pub struct ExprPath {
452 pub meta: Option<Meta>,
453 pub path: Path,
454}
455
456#[derive(Debug, Clone, PartialEq, Eq)]
458pub struct ExprLit {
459 pub meta: Option<Meta>,
460 pub value: Literal,
461}
462
463#[derive(Debug, Clone, PartialEq, Eq)]
465pub struct ExprGroup {
466 pub meta: Option<Meta>,
468 pub expr: Box<Expr>,
470}
471
472#[derive(Debug, Clone, PartialEq, Eq)]
474pub struct ExprBinary {
475 pub meta: Option<Meta>,
476 pub lhs: Box<Expr>,
477 pub op: BinaryOp,
478 pub rhs: Box<Expr>,
479}
480
481#[derive(Debug, Clone, PartialEq, Eq)]
483pub struct ExprUnary {
484 pub meta: Option<Meta>,
485 pub op: UnaryOp,
486 pub expr: Box<Expr>,
487}
488
489#[derive(Debug, Clone, PartialEq, Eq)]
491pub struct ExprCall {
492 pub meta: Option<Meta>,
493 pub callee: Box<Expr>,
494 pub args: Vec<Expr>,
495}
496
497#[derive(Debug, Clone, PartialEq, Eq)]
499pub struct ExprMatch {
500 pub meta: Option<Meta>,
501 pub scrutinee: Box<Expr>,
502 pub arms: Vec<MatchArm>,
503}
504
505#[derive(Debug, Clone, PartialEq, Eq)]
507pub struct MatchArm {
508 pub meta: Meta,
509 pub pat: Pattern,
510 pub guard: Option<Expr>,
511 pub body: Expr,
512}
513
514impl MatchArm {
515 pub fn clear_spans(&mut self) {
517 self.meta.span = None;
518 self.pat.clear_spans();
519 if let Some(guard) = &mut self.guard {
520 guard.clear_spans();
521 }
522 self.body.clear_spans();
523 }
524}
525
526#[derive(Debug, Clone, PartialEq, Eq)]
528pub enum Pattern {
529 Ident(PatIdent),
530 Wild(PatWild),
531}
532
533impl Pattern {
534 pub fn meta(&self) -> Option<&Meta> {
536 match self {
537 Self::Ident(node) => node.meta.as_ref(),
538 Self::Wild(node) => node.meta.as_ref(),
539 }
540 }
541
542 pub fn clear_spans(&mut self) {
544 match self {
545 Self::Ident(node) => {
546 if let Some(meta) = &mut node.meta {
547 meta.span = None;
548 }
549 }
550 Self::Wild(node) => {
551 if let Some(meta) = &mut node.meta {
552 meta.span = None;
553 }
554 }
555 }
556 }
557}
558
559#[derive(Debug, Clone, PartialEq, Eq)]
561pub struct PatIdent {
562 pub meta: Option<Meta>,
563 pub name: String,
564}
565
566#[derive(Debug, Clone, PartialEq, Eq)]
568pub struct PatWild {
569 pub meta: Option<Meta>,
570}
571
572#[derive(Debug, Clone, PartialEq, Eq)]
574pub enum Type {
575 Path(TypePath),
576}
577
578impl Type {
579 pub fn meta(&self) -> &Meta {
581 match self {
582 Self::Path(node) => &node.meta,
583 }
584 }
585
586 pub fn clear_spans(&mut self) {
588 match self {
589 Self::Path(node) => node.meta.span = None,
590 }
591 }
592}
593
594#[derive(Debug, Clone, PartialEq, Eq)]
596pub struct TypePath {
597 pub meta: Meta,
598 pub path: Path,
599}
600
601#[derive(Debug, Clone, PartialEq, Eq)]
603pub struct Path {
604 pub segments: Vec<String>,
605}
606
607#[derive(Debug, Clone, PartialEq, Eq)]
609pub enum Literal {
610 Int(i64),
611 Str(String),
612}
613
614#[derive(Debug, Clone, Copy, PartialEq, Eq)]
616pub enum BinaryOp {
617 Add,
618 Sub,
619 Lt,
620}
621
622#[derive(Debug, Clone, Copy, PartialEq, Eq)]
624pub enum UnaryOp {
625 Neg,
626}
627
628#[derive(Debug, Clone, PartialEq, Eq)]
630pub struct DocNode {
631 pub meta: Meta,
632 pub text: String,
633}
634
635#[derive(Debug, Clone, PartialEq, Eq)]
637pub struct CommentNode {
638 pub meta: Meta,
639 pub text: String,
640}
641
642fn write_indent(out: &mut String, level: usize) {
643 for _ in 0..level {
644 out.push_str(" ");
645 }
646}
647
648fn write_json_string(value: &str, out: &mut String) {
649 out.push('"');
650 for ch in value.chars() {
651 match ch {
652 '"' => out.push_str("\\\""),
653 '\\' => out.push_str("\\\\"),
654 '\n' => out.push_str("\\n"),
655 '\r' => out.push_str("\\r"),
656 '\t' => out.push_str("\\t"),
657 _ => out.push(ch),
658 }
659 }
660 out.push('"');
661}
662
663fn write_json_meta(meta: &Meta, out: &mut String, level: usize) {
664 out.push_str("{\n");
665 write_indent(out, level + 1);
666 out.push_str("\"id\": ");
667 write_json_string(&meta.id, out);
668 out.push_str(",\n");
669 write_indent(out, level + 1);
670 out.push_str("\"rank\": ");
671 match &meta.rank {
672 Some(rank) => write_json_string(rank, out),
673 None => out.push_str("null"),
674 }
675 out.push_str(",\n");
676 write_indent(out, level + 1);
677 out.push_str("\"anchor\": ");
678 match &meta.anchor {
679 Some(anchor) => write_json_string(anchor, out),
680 None => out.push_str("null"),
681 }
682 out.push_str(",\n");
683 write_indent(out, level + 1);
684 out.push_str("\"slot\": ");
685 match &meta.slot {
686 Some(slot) => write_json_string(slot, out),
687 None => out.push_str("null"),
688 }
689 out.push_str(",\n");
690 write_indent(out, level + 1);
691 out.push_str("\"span\": ");
692 match meta.span {
693 Some(span) => {
694 out.push_str("{\n");
695 write_indent(out, level + 2);
696 let _ = write!(out, "\"start\": {},\n", span.start);
697 write_indent(out, level + 2);
698 let _ = write!(out, "\"end\": {}\n", span.end);
699 write_indent(out, level + 1);
700 out.push('}');
701 }
702 None => out.push_str("null"),
703 }
704 out.push('\n');
705 write_indent(out, level);
706 out.push('}');
707}
708
709fn write_json_path(path: &Path, out: &mut String, level: usize) {
710 out.push_str("{\n");
711 write_indent(out, level + 1);
712 out.push_str("\"segments\": [");
713 for (index, segment) in path.segments.iter().enumerate() {
714 if index > 0 {
715 out.push_str(", ");
716 }
717 write_json_string(segment, out);
718 }
719 out.push_str("]\n");
720 write_indent(out, level);
721 out.push('}');
722}
723
724fn write_json_use_tree(tree: &UseTree, out: &mut String, level: usize) {
725 match tree {
726 UseTree::Name(node) => {
727 out.push_str("{\n");
728 write_indent(out, level + 1);
729 out.push_str("\"kind\": \"Name\",\n");
730 write_indent(out, level + 1);
731 out.push_str("\"name\": ");
732 write_json_string(&node.name, out);
733 out.push('\n');
734 write_indent(out, level);
735 out.push('}');
736 }
737 UseTree::Path(node) => {
738 out.push_str("{\n");
739 write_indent(out, level + 1);
740 out.push_str("\"kind\": \"Path\",\n");
741 write_indent(out, level + 1);
742 out.push_str("\"prefix\": ");
743 write_json_string(&node.prefix, out);
744 out.push_str(",\n");
745 write_indent(out, level + 1);
746 out.push_str("\"tree\": ");
747 write_json_use_tree(&node.tree, out, level + 1);
748 out.push('\n');
749 write_indent(out, level);
750 out.push('}');
751 }
752 UseTree::Group(node) => {
753 out.push_str("{\n");
754 write_indent(out, level + 1);
755 out.push_str("\"kind\": \"Group\",\n");
756 write_indent(out, level + 1);
757 out.push_str("\"items\": [\n");
758 for (index, item) in node.items.iter().enumerate() {
759 if index > 0 {
760 out.push_str(",\n");
761 }
762 write_indent(out, level + 2);
763 write_json_use_tree(item, out, level + 2);
764 }
765 out.push('\n');
766 write_indent(out, level + 1);
767 out.push_str("]\n");
768 write_indent(out, level);
769 out.push('}');
770 }
771 UseTree::Glob(_) => {
772 out.push_str("{\n");
773 write_indent(out, level + 1);
774 out.push_str("\"kind\": \"Glob\"\n");
775 write_indent(out, level);
776 out.push('}');
777 }
778 }
779}
780
781fn write_json_literal(literal: &Literal, out: &mut String, level: usize) {
782 out.push_str("{\n");
783 match literal {
784 Literal::Int(value) => {
785 write_indent(out, level + 1);
786 out.push_str("\"kind\": \"Int\",\n");
787 write_indent(out, level + 1);
788 let _ = write!(out, "\"value\": {}\n", value);
789 }
790 Literal::Str(value) => {
791 write_indent(out, level + 1);
792 out.push_str("\"kind\": \"Str\",\n");
793 write_indent(out, level + 1);
794 out.push_str("\"value\": ");
795 write_json_string(value, out);
796 out.push('\n');
797 }
798 }
799 write_indent(out, level);
800 out.push('}');
801}
802
803fn write_json_type(ty: &Type, out: &mut String, level: usize) {
804 match ty {
805 Type::Path(node) => {
806 out.push_str("{\n");
807 write_indent(out, level + 1);
808 out.push_str("\"kind\": \"Path\",\n");
809 write_indent(out, level + 1);
810 out.push_str("\"meta\": ");
811 write_json_meta(&node.meta, out, level + 1);
812 out.push_str(",\n");
813 write_indent(out, level + 1);
814 out.push_str("\"path\": ");
815 write_json_path(&node.path, out, level + 1);
816 out.push('\n');
817 write_indent(out, level);
818 out.push('}');
819 }
820 }
821}
822
823fn write_json_pattern(pattern: &Pattern, out: &mut String, level: usize) {
824 match pattern {
825 Pattern::Ident(node) => {
826 out.push_str("{\n");
827 write_indent(out, level + 1);
828 out.push_str("\"kind\": \"Ident\",\n");
829 write_indent(out, level + 1);
830 out.push_str("\"meta\": ");
831 match &node.meta {
832 Some(meta) => write_json_meta(meta, out, level + 1),
833 None => out.push_str("null"),
834 }
835 out.push_str(",\n");
836 write_indent(out, level + 1);
837 out.push_str("\"name\": ");
838 write_json_string(&node.name, out);
839 out.push('\n');
840 write_indent(out, level);
841 out.push('}');
842 }
843 Pattern::Wild(node) => {
844 out.push_str("{\n");
845 write_indent(out, level + 1);
846 out.push_str("\"kind\": \"Wild\",\n");
847 write_indent(out, level + 1);
848 out.push_str("\"meta\": ");
849 match &node.meta {
850 Some(meta) => write_json_meta(meta, out, level + 1),
851 None => out.push_str("null"),
852 }
853 out.push('\n');
854 write_indent(out, level);
855 out.push('}');
856 }
857 }
858}
859
860fn write_json_expr(expr: &Expr, out: &mut String, level: usize) {
861 match expr {
862 Expr::Path(node) => {
863 out.push_str("{\n");
864 write_indent(out, level + 1);
865 out.push_str("\"kind\": \"Path\",\n");
866 write_indent(out, level + 1);
867 out.push_str("\"meta\": ");
868 match &node.meta {
869 Some(meta) => write_json_meta(meta, out, level + 1),
870 None => out.push_str("null"),
871 }
872 out.push_str(",\n");
873 write_indent(out, level + 1);
874 out.push_str("\"path\": ");
875 write_json_path(&node.path, out, level + 1);
876 out.push('\n');
877 write_indent(out, level);
878 out.push('}');
879 }
880 Expr::Lit(node) => {
881 out.push_str("{\n");
882 write_indent(out, level + 1);
883 out.push_str("\"kind\": \"Lit\",\n");
884 write_indent(out, level + 1);
885 out.push_str("\"meta\": ");
886 match &node.meta {
887 Some(meta) => write_json_meta(meta, out, level + 1),
888 None => out.push_str("null"),
889 }
890 out.push_str(",\n");
891 write_indent(out, level + 1);
892 out.push_str("\"value\": ");
893 write_json_literal(&node.value, out, level + 1);
894 out.push('\n');
895 write_indent(out, level);
896 out.push('}');
897 }
898 Expr::Group(node) => {
899 out.push_str("{\n");
900 write_indent(out, level + 1);
901 out.push_str("\"kind\": \"Group\",\n");
902 write_indent(out, level + 1);
903 out.push_str("\"meta\": ");
904 match &node.meta {
905 Some(meta) => write_json_meta(meta, out, level + 1),
906 None => out.push_str("null"),
907 }
908 out.push_str(",\n");
909 write_indent(out, level + 1);
910 out.push_str("\"expr\": ");
911 write_json_expr(&node.expr, out, level + 1);
912 out.push('\n');
913 write_indent(out, level);
914 out.push('}');
915 }
916 Expr::Binary(node) => {
917 out.push_str("{\n");
918 write_indent(out, level + 1);
919 out.push_str("\"kind\": \"Binary\",\n");
920 write_indent(out, level + 1);
921 out.push_str("\"meta\": ");
922 match &node.meta {
923 Some(meta) => write_json_meta(meta, out, level + 1),
924 None => out.push_str("null"),
925 }
926 out.push_str(",\n");
927 write_indent(out, level + 1);
928 out.push_str("\"lhs\": ");
929 write_json_expr(&node.lhs, out, level + 1);
930 out.push_str(",\n");
931 write_indent(out, level + 1);
932 out.push_str("\"op\": ");
933 write_json_string(
934 match node.op {
935 BinaryOp::Add => "Add",
936 BinaryOp::Sub => "Sub",
937 BinaryOp::Lt => "Lt",
938 },
939 out,
940 );
941 out.push_str(",\n");
942 write_indent(out, level + 1);
943 out.push_str("\"rhs\": ");
944 write_json_expr(&node.rhs, out, level + 1);
945 out.push('\n');
946 write_indent(out, level);
947 out.push('}');
948 }
949 Expr::Unary(node) => {
950 out.push_str("{\n");
951 write_indent(out, level + 1);
952 out.push_str("\"kind\": \"Unary\",\n");
953 write_indent(out, level + 1);
954 out.push_str("\"meta\": ");
955 match &node.meta {
956 Some(meta) => write_json_meta(meta, out, level + 1),
957 None => out.push_str("null"),
958 }
959 out.push_str(",\n");
960 write_indent(out, level + 1);
961 out.push_str("\"op\": ");
962 write_json_string("Neg", out);
963 out.push_str(",\n");
964 write_indent(out, level + 1);
965 out.push_str("\"expr\": ");
966 write_json_expr(&node.expr, out, level + 1);
967 out.push('\n');
968 write_indent(out, level);
969 out.push('}');
970 }
971 Expr::Call(node) => {
972 out.push_str("{\n");
973 write_indent(out, level + 1);
974 out.push_str("\"kind\": \"Call\",\n");
975 write_indent(out, level + 1);
976 out.push_str("\"meta\": ");
977 match &node.meta {
978 Some(meta) => write_json_meta(meta, out, level + 1),
979 None => out.push_str("null"),
980 }
981 out.push_str(",\n");
982 write_indent(out, level + 1);
983 out.push_str("\"callee\": ");
984 write_json_expr(&node.callee, out, level + 1);
985 out.push_str(",\n");
986 write_indent(out, level + 1);
987 out.push_str("\"args\": [\n");
988 for (index, arg) in node.args.iter().enumerate() {
989 if index > 0 {
990 out.push_str(",\n");
991 }
992 write_indent(out, level + 2);
993 write_json_expr(arg, out, level + 2);
994 }
995 out.push('\n');
996 write_indent(out, level + 1);
997 out.push_str("]\n");
998 write_indent(out, level);
999 out.push('}');
1000 }
1001 Expr::Match(node) => {
1002 out.push_str("{\n");
1003 write_indent(out, level + 1);
1004 out.push_str("\"kind\": \"Match\",\n");
1005 write_indent(out, level + 1);
1006 out.push_str("\"meta\": ");
1007 match &node.meta {
1008 Some(meta) => write_json_meta(meta, out, level + 1),
1009 None => out.push_str("null"),
1010 }
1011 out.push_str(",\n");
1012 write_indent(out, level + 1);
1013 out.push_str("\"scrutinee\": ");
1014 write_json_expr(&node.scrutinee, out, level + 1);
1015 out.push_str(",\n");
1016 write_indent(out, level + 1);
1017 out.push_str("\"arms\": [\n");
1018 for (index, arm) in node.arms.iter().enumerate() {
1019 if index > 0 {
1020 out.push_str(",\n");
1021 }
1022 write_indent(out, level + 2);
1023 write_json_match_arm(arm, out, level + 2);
1024 }
1025 out.push('\n');
1026 write_indent(out, level + 1);
1027 out.push_str("]\n");
1028 write_indent(out, level);
1029 out.push('}');
1030 }
1031 Expr::Block(node) => write_json_block(node, out, level),
1032 }
1033}
1034
1035fn write_json_match_arm(arm: &MatchArm, out: &mut String, level: usize) {
1036 out.push_str("{\n");
1037 write_indent(out, level + 1);
1038 out.push_str("\"meta\": ");
1039 write_json_meta(&arm.meta, out, level + 1);
1040 out.push_str(",\n");
1041 write_indent(out, level + 1);
1042 out.push_str("\"pat\": ");
1043 write_json_pattern(&arm.pat, out, level + 1);
1044 out.push_str(",\n");
1045 write_indent(out, level + 1);
1046 out.push_str("\"guard\": ");
1047 match &arm.guard {
1048 Some(guard) => write_json_expr(guard, out, level + 1),
1049 None => out.push_str("null"),
1050 }
1051 out.push_str(",\n");
1052 write_indent(out, level + 1);
1053 out.push_str("\"body\": ");
1054 write_json_expr(&arm.body, out, level + 1);
1055 out.push('\n');
1056 write_indent(out, level);
1057 out.push('}');
1058}
1059
1060fn write_json_block(block: &Block, out: &mut String, level: usize) {
1061 out.push_str("{\n");
1062 write_indent(out, level + 1);
1063 out.push_str("\"kind\": \"Block\",\n");
1064 write_indent(out, level + 1);
1065 out.push_str("\"meta\": ");
1066 match &block.meta {
1067 Some(meta) => write_json_meta(meta, out, level + 1),
1068 None => out.push_str("null"),
1069 }
1070 out.push_str(",\n");
1071 write_indent(out, level + 1);
1072 out.push_str("\"stmts\": [\n");
1073 for (index, stmt) in block.stmts.iter().enumerate() {
1074 if index > 0 {
1075 out.push_str(",\n");
1076 }
1077 write_indent(out, level + 2);
1078 write_json_stmt(stmt, out, level + 2);
1079 }
1080 out.push('\n');
1081 write_indent(out, level + 1);
1082 out.push_str("]\n");
1083 write_indent(out, level);
1084 out.push('}');
1085}
1086
1087fn write_json_stmt(stmt: &Stmt, out: &mut String, level: usize) {
1088 match stmt {
1089 Stmt::Let(node) => {
1090 out.push_str("{\n");
1091 write_indent(out, level + 1);
1092 out.push_str("\"kind\": \"Let\",\n");
1093 write_indent(out, level + 1);
1094 out.push_str("\"meta\": ");
1095 write_json_meta(&node.meta, out, level + 1);
1096 out.push_str(",\n");
1097 write_indent(out, level + 1);
1098 out.push_str("\"pat\": ");
1099 write_json_pattern(&node.pat, out, level + 1);
1100 out.push_str(",\n");
1101 write_indent(out, level + 1);
1102 out.push_str("\"value\": ");
1103 write_json_expr(&node.value, out, level + 1);
1104 out.push('\n');
1105 write_indent(out, level);
1106 out.push('}');
1107 }
1108 Stmt::Expr(node) => {
1109 out.push_str("{\n");
1110 write_indent(out, level + 1);
1111 out.push_str("\"kind\": \"Expr\",\n");
1112 write_indent(out, level + 1);
1113 out.push_str("\"meta\": ");
1114 write_json_meta(&node.meta, out, level + 1);
1115 out.push_str(",\n");
1116 write_indent(out, level + 1);
1117 let _ = write!(out, "\"has_semi\": {},\n", node.has_semi);
1118 write_indent(out, level + 1);
1119 out.push_str("\"expr\": ");
1120 write_json_expr(&node.expr, out, level + 1);
1121 out.push('\n');
1122 write_indent(out, level);
1123 out.push('}');
1124 }
1125 Stmt::Item(node) => {
1126 out.push_str("{\n");
1127 write_indent(out, level + 1);
1128 out.push_str("\"kind\": \"Item\",\n");
1129 write_indent(out, level + 1);
1130 out.push_str("\"item\": ");
1131 write_json_item(node, out, level + 1);
1132 out.push('\n');
1133 write_indent(out, level);
1134 out.push('}');
1135 }
1136 Stmt::Doc(node) => {
1137 out.push_str("{\n");
1138 write_indent(out, level + 1);
1139 out.push_str("\"kind\": \"Doc\",\n");
1140 write_indent(out, level + 1);
1141 out.push_str("\"meta\": ");
1142 write_json_meta(&node.meta, out, level + 1);
1143 out.push_str(",\n");
1144 write_indent(out, level + 1);
1145 out.push_str("\"text\": ");
1146 write_json_string(&node.text, out);
1147 out.push('\n');
1148 write_indent(out, level);
1149 out.push('}');
1150 }
1151 Stmt::Comment(node) => {
1152 out.push_str("{\n");
1153 write_indent(out, level + 1);
1154 out.push_str("\"kind\": \"Comment\",\n");
1155 write_indent(out, level + 1);
1156 out.push_str("\"meta\": ");
1157 write_json_meta(&node.meta, out, level + 1);
1158 out.push_str(",\n");
1159 write_indent(out, level + 1);
1160 out.push_str("\"text\": ");
1161 write_json_string(&node.text, out);
1162 out.push('\n');
1163 write_indent(out, level);
1164 out.push('}');
1165 }
1166 }
1167}
1168
1169fn write_json_item(item: &Item, out: &mut String, level: usize) {
1170 match item {
1171 Item::Mod(node) => {
1172 out.push_str("{\n");
1173 write_indent(out, level + 1);
1174 out.push_str("\"kind\": \"Mod\",\n");
1175 write_indent(out, level + 1);
1176 out.push_str("\"meta\": ");
1177 write_json_meta(&node.meta, out, level + 1);
1178 out.push_str(",\n");
1179 write_indent(out, level + 1);
1180 out.push_str("\"name\": ");
1181 write_json_string(&node.name, out);
1182 out.push_str(",\n");
1183 write_indent(out, level + 1);
1184 out.push_str("\"items\": [\n");
1185 for (index, child) in node.items.iter().enumerate() {
1186 if index > 0 {
1187 out.push_str(",\n");
1188 }
1189 write_indent(out, level + 2);
1190 write_json_item(child, out, level + 2);
1191 }
1192 out.push('\n');
1193 write_indent(out, level + 1);
1194 out.push_str("]\n");
1195 write_indent(out, level);
1196 out.push('}');
1197 }
1198 Item::Use(node) => {
1199 out.push_str("{\n");
1200 write_indent(out, level + 1);
1201 out.push_str("\"kind\": \"Use\",\n");
1202 write_indent(out, level + 1);
1203 out.push_str("\"meta\": ");
1204 write_json_meta(&node.meta, out, level + 1);
1205 out.push_str(",\n");
1206 write_indent(out, level + 1);
1207 out.push_str("\"tree\": ");
1208 write_json_use_tree(&node.tree, out, level + 1);
1209 out.push('\n');
1210 write_indent(out, level);
1211 out.push('}');
1212 }
1213 Item::Struct(node) => {
1214 out.push_str("{\n");
1215 write_indent(out, level + 1);
1216 out.push_str("\"kind\": \"Struct\",\n");
1217 write_indent(out, level + 1);
1218 out.push_str("\"meta\": ");
1219 write_json_meta(&node.meta, out, level + 1);
1220 out.push_str(",\n");
1221 write_indent(out, level + 1);
1222 out.push_str("\"name\": ");
1223 write_json_string(&node.name, out);
1224 out.push_str(",\n");
1225 write_indent(out, level + 1);
1226 out.push_str("\"fields\": [\n");
1227 for (index, field) in node.fields.iter().enumerate() {
1228 if index > 0 {
1229 out.push_str(",\n");
1230 }
1231 write_indent(out, level + 2);
1232 out.push_str("{\n");
1233 write_indent(out, level + 3);
1234 out.push_str("\"meta\": ");
1235 write_json_meta(&field.meta, out, level + 3);
1236 out.push_str(",\n");
1237 write_indent(out, level + 3);
1238 out.push_str("\"name\": ");
1239 write_json_string(&field.name, out);
1240 out.push_str(",\n");
1241 write_indent(out, level + 3);
1242 out.push_str("\"ty\": ");
1243 write_json_type(&field.ty, out, level + 3);
1244 out.push('\n');
1245 write_indent(out, level + 2);
1246 out.push('}');
1247 }
1248 out.push('\n');
1249 write_indent(out, level + 1);
1250 out.push_str("]\n");
1251 write_indent(out, level);
1252 out.push('}');
1253 }
1254 Item::Enum(node) => {
1255 out.push_str("{\n");
1256 write_indent(out, level + 1);
1257 out.push_str("\"kind\": \"Enum\",\n");
1258 write_indent(out, level + 1);
1259 out.push_str("\"meta\": ");
1260 write_json_meta(&node.meta, out, level + 1);
1261 out.push_str(",\n");
1262 write_indent(out, level + 1);
1263 out.push_str("\"name\": ");
1264 write_json_string(&node.name, out);
1265 out.push_str(",\n");
1266 write_indent(out, level + 1);
1267 out.push_str("\"variants\": [\n");
1268 for (index, variant) in node.variants.iter().enumerate() {
1269 if index > 0 {
1270 out.push_str(",\n");
1271 }
1272 write_indent(out, level + 2);
1273 out.push_str("{\n");
1274 write_indent(out, level + 3);
1275 out.push_str("\"meta\": ");
1276 write_json_meta(&variant.meta, out, level + 3);
1277 out.push_str(",\n");
1278 write_indent(out, level + 3);
1279 out.push_str("\"name\": ");
1280 write_json_string(&variant.name, out);
1281 out.push('\n');
1282 write_indent(out, level + 2);
1283 out.push('}');
1284 }
1285 out.push('\n');
1286 write_indent(out, level + 1);
1287 out.push_str("]\n");
1288 write_indent(out, level);
1289 out.push('}');
1290 }
1291 Item::Fn(node) => {
1292 out.push_str("{\n");
1293 write_indent(out, level + 1);
1294 out.push_str("\"kind\": \"Fn\",\n");
1295 write_indent(out, level + 1);
1296 out.push_str("\"meta\": ");
1297 write_json_meta(&node.meta, out, level + 1);
1298 out.push_str(",\n");
1299 write_indent(out, level + 1);
1300 out.push_str("\"name\": ");
1301 write_json_string(&node.name, out);
1302 out.push_str(",\n");
1303 write_indent(out, level + 1);
1304 out.push_str("\"params\": [\n");
1305 for (index, param) in node.params.iter().enumerate() {
1306 if index > 0 {
1307 out.push_str(",\n");
1308 }
1309 write_indent(out, level + 2);
1310 out.push_str("{\n");
1311 write_indent(out, level + 3);
1312 out.push_str("\"meta\": ");
1313 write_json_meta(¶m.meta, out, level + 3);
1314 out.push_str(",\n");
1315 write_indent(out, level + 3);
1316 out.push_str("\"name\": ");
1317 write_json_string(¶m.name, out);
1318 out.push_str(",\n");
1319 write_indent(out, level + 3);
1320 out.push_str("\"ty\": ");
1321 write_json_type(¶m.ty, out, level + 3);
1322 out.push('\n');
1323 write_indent(out, level + 2);
1324 out.push('}');
1325 }
1326 out.push('\n');
1327 write_indent(out, level + 1);
1328 out.push_str("],\n");
1329 write_indent(out, level + 1);
1330 out.push_str("\"ret_ty\": ");
1331 match &node.ret_ty {
1332 Some(ret_ty) => write_json_type(ret_ty, out, level + 1),
1333 None => out.push_str("null"),
1334 }
1335 out.push_str(",\n");
1336 write_indent(out, level + 1);
1337 out.push_str("\"body\": ");
1338 write_json_block(&node.body, out, level + 1);
1339 out.push('\n');
1340 write_indent(out, level);
1341 out.push('}');
1342 }
1343 Item::Doc(node) => {
1344 out.push_str("{\n");
1345 write_indent(out, level + 1);
1346 out.push_str("\"kind\": \"Doc\",\n");
1347 write_indent(out, level + 1);
1348 out.push_str("\"meta\": ");
1349 write_json_meta(&node.meta, out, level + 1);
1350 out.push_str(",\n");
1351 write_indent(out, level + 1);
1352 out.push_str("\"text\": ");
1353 write_json_string(&node.text, out);
1354 out.push('\n');
1355 write_indent(out, level);
1356 out.push('}');
1357 }
1358 Item::Comment(node) => {
1359 out.push_str("{\n");
1360 write_indent(out, level + 1);
1361 out.push_str("\"kind\": \"Comment\",\n");
1362 write_indent(out, level + 1);
1363 out.push_str("\"meta\": ");
1364 write_json_meta(&node.meta, out, level + 1);
1365 out.push_str(",\n");
1366 write_indent(out, level + 1);
1367 out.push_str("\"text\": ");
1368 write_json_string(&node.text, out);
1369 out.push('\n');
1370 write_indent(out, level);
1371 out.push('}');
1372 }
1373 }
1374}
1375
1376fn write_file_json(file: &File, out: &mut String, level: usize) {
1377 out.push_str("{\n");
1378 write_indent(out, level + 1);
1379 out.push_str("\"items\": [\n");
1380 for (index, item) in file.items.iter().enumerate() {
1381 if index > 0 {
1382 out.push_str(",\n");
1383 }
1384 write_indent(out, level + 2);
1385 write_json_item(item, out, level + 2);
1386 }
1387 out.push('\n');
1388 write_indent(out, level + 1);
1389 out.push_str("]\n");
1390 write_indent(out, level);
1391 out.push('}');
1392}