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