comprehensive/
comprehensive.rs1use syntaxfmt::{SyntaxFmt, SyntaxFormatter, syntax_fmt};
2
3trait TypeDisplay {
5 fn should_show_types(&self) -> bool;
6}
7
8struct TypeConfig {
9 show_types: bool,
10}
11
12impl TypeDisplay for TypeConfig {
13 fn should_show_types(&self) -> bool {
14 self.show_types
15 }
16}
17
18#[derive(SyntaxFmt)]
20#[syntax(bound = TypeDisplay)]
21enum Expr<'src> {
22 #[syntax(cont_with = |expr: &Expr, f: &mut SyntaxFormatter<_>| {
23 if let Expr::Literal(val) = expr {
24 write!(f, "{}", val)
25 } else {
26 Ok(())
27 }
28 })]
29 Literal(i32),
30
31 #[syntax(pre = "(", suf = ")")]
32 Binary {
33 #[syntax(suf = " ")]
34 left: Box<Expr<'src>>,
35
36 #[syntax(suf = " ")]
37 op: &'src str,
38
39 right: Box<Expr<'src>>,
40 },
41
42 Call(FunctionCall<'src>),
43}
44
45#[derive(SyntaxFmt)]
47#[syntax(bound = TypeDisplay)]
48struct FunctionCall<'src> {
49 name: &'src str,
50
51 #[syntax(pre = "(", suf = ")", delim = [", ", ", "])]
52 args: Vec<Expr<'src>>,
53}
54
55fn format_type_with_state<S: TypeDisplay>(
57 ty: &Option<&str>,
58 f: &mut SyntaxFormatter<S>
59) -> std::fmt::Result {
60 if f.state().should_show_types() {
61 if let Some(t) = ty {
62 write!(f, ": {}", t)
63 } else {
64 Ok(())
65 }
66 } else {
67 Ok(())
68 }
69}
70
71#[derive(SyntaxFmt)]
73#[syntax(bound = TypeDisplay)]
74struct Parameter<'src> {
75 name: &'src str,
76
77 #[syntax(eval = ty.is_some(), cont_with = format_type_with_state)]
78 ty: Option<&'src str>,
79}
80
81#[derive(SyntaxFmt)]
83#[syntax(bound = TypeDisplay, nl = beg)]
84enum Statement<'src> {
85 #[syntax(pre = "return ", suf = ";", eval = value.is_some())]
86 #[syntax_else(cont = "return;")]
87 Return { value: Option<Expr<'src>> },
88
89 #[syntax(suf = ";")]
90 Expr(Expr<'src>),
91}
92
93#[derive(SyntaxFmt)]
95#[syntax(pre = "{", suf = "}", bound = TypeDisplay)]
96struct Block<'src> {
97 #[syntax(nl = [cont], ind, delim = "")]
98 statements: Vec<Statement<'src>>,
99}
100
101#[derive(SyntaxFmt)]
103#[syntax(pre = "fn ", bound = TypeDisplay)]
104struct Function<'src> {
105 name: &'src str,
106
107 #[syntax(pre = "(", suf = ")", delim = [", ", ", "])]
108 params: Vec<Parameter<'src>>,
109
110 #[syntax(pre = " -> ", eval = return_type.is_some())]
111 return_type: Option<&'src str>,
112
113 #[syntax(pre = " ")]
114 body: Block<'src>,
115}
116
117fn main() {
118 let func = Function {
120 name: "calculate",
121 params: vec![
122 Parameter { name: "x", ty: Some("i32") },
123 Parameter { name: "y", ty: Some("i32") },
124 ],
125 return_type: Some("i32"),
126 body: Block {
127 statements: vec![
128 Statement::Expr(Expr::Call(FunctionCall {
129 name: "println",
130 args: vec![Expr::Literal(42)],
131 })),
132 Statement::Return {
133 value: Some(Expr::Binary {
134 left: Box::new(Expr::Literal(1)),
135 op: "+",
136 right: Box::new(Expr::Literal(2)),
137 }),
138 },
139 ],
140 },
141 };
142
143 let config = TypeConfig { show_types: true };
144
145 println!("Normal - with types:");
146 println!("{}", syntax_fmt(&func).state(&config));
147 println!();
148
149 println!("Pretty - with types:");
150 println!("{}", syntax_fmt(&func).state(&config).pretty());
151 println!();
152
153 let config_no_types = TypeConfig { show_types: false };
154
155 println!("Normal - without types:");
156 println!("{}", syntax_fmt(&func).state(&config_no_types));
157 println!();
158
159 println!("Pretty - without types:");
160 println!("{}", syntax_fmt(&func).state(&config_no_types).pretty());
161}