lisette_semantics/pattern_analysis/
witness.rs1use super::NormalizedPattern;
2use super::types::INTERFACE_UNKNOWN_TAG;
3use syntax::ast::Literal;
4
5pub fn format_witness(pattern: &NormalizedPattern) -> String {
6 match pattern {
7 NormalizedPattern::Wildcard => "_".to_string(),
8
9 NormalizedPattern::Literal(_) => unreachable!("literals cannot be witnesses"),
12
13 NormalizedPattern::Constructor {
14 type_name,
15 tag,
16 args,
17 } => {
18 if type_name.starts_with("Slice") {
19 return format_slice_pattern(pattern);
20 }
21
22 if type_name.starts_with("Tuple") {
23 let formatted_args = args
24 .iter()
25 .map(format_witness)
26 .collect::<Vec<_>>()
27 .join(", ");
28 return format!("({})", formatted_args);
29 }
30
31 let display_tag = strip_module_prefix(tag);
32
33 if display_tag == "__value_enum_unknown__" || display_tag == INTERFACE_UNKNOWN_TAG {
34 return "_".to_string();
35 }
36
37 if args.is_empty() {
38 display_tag
39 } else {
40 let formatted_args = args
41 .iter()
42 .map(format_witness)
43 .collect::<Vec<_>>()
44 .join(", ");
45 format!("{}({})", display_tag, formatted_args)
46 }
47 }
48 }
49}
50
51pub fn format_pattern(pattern: &NormalizedPattern) -> String {
55 match pattern {
56 NormalizedPattern::Wildcard => "_".to_string(),
57
58 NormalizedPattern::Literal(lit) => format_literal(lit),
60
61 NormalizedPattern::Constructor {
62 type_name,
63 tag,
64 args,
65 } => {
66 if type_name.starts_with("Slice") {
67 return format_slice_pattern_for_display(pattern);
68 }
69
70 if type_name.starts_with("Tuple") {
71 let formatted_args = args
72 .iter()
73 .map(format_pattern)
74 .collect::<Vec<_>>()
75 .join(", ");
76 return format!("({})", formatted_args);
77 }
78
79 let display_tag = strip_module_prefix(tag);
80
81 if display_tag == "__value_enum_unknown__" || display_tag == INTERFACE_UNKNOWN_TAG {
82 return "_".to_string();
83 }
84
85 if args.is_empty() {
86 display_tag
87 } else {
88 let formatted_args = args
89 .iter()
90 .map(format_pattern)
91 .collect::<Vec<_>>()
92 .join(", ");
93 format!("{}({})", display_tag, formatted_args)
94 }
95 }
96 }
97}
98
99fn format_literal(lit: &Literal) -> String {
100 match lit {
101 Literal::Integer { text, value } => text.as_ref().unwrap_or(&value.to_string()).clone(),
102 Literal::Float { text, value } => text.as_ref().unwrap_or(&value.to_string()).clone(),
103 Literal::Imaginary(val) => format!("{}i", val),
104 Literal::Boolean(b) => b.to_string(),
105 Literal::String(s) => format!("\"{}\"", s),
106 Literal::Char(c) => format!("'{}'", c),
107 Literal::FormatString(_) => "f\"...\"".to_string(),
108 Literal::Slice(_) => "[...]".to_string(),
109 }
110}
111
112fn strip_module_prefix(tag: &str) -> String {
113 let parts: Vec<&str> = tag.split('.').collect();
114 if parts.len() >= 2 {
115 parts[1..].join(".")
116 } else {
117 tag.to_string()
118 }
119}
120
121fn format_slice_pattern(pattern: &NormalizedPattern) -> String {
122 let mut elements = Vec::new();
123 let mut current = pattern;
124 let mut ends_with_rest = false;
125
126 loop {
127 match current {
128 NormalizedPattern::Constructor { tag, .. } if tag == "EmptySlice" => {
129 break;
130 }
131 NormalizedPattern::Constructor { tag, args, .. } if tag == "NonEmptySlice" => {
132 if args.len() >= 2 {
133 elements.push(format_witness(&args[0]));
134 current = &args[1];
135 } else {
136 break;
137 }
138 }
139 NormalizedPattern::Wildcard => {
140 ends_with_rest = true;
141 break;
142 }
143 _ => {
144 elements.push(format_witness(current));
145 break;
146 }
147 }
148 }
149
150 if ends_with_rest {
151 elements.push("..".to_string());
152 }
153
154 format!("[{}]", elements.join(", "))
155}
156
157fn format_slice_pattern_for_display(pattern: &NormalizedPattern) -> String {
158 let mut elements = Vec::new();
159 let mut current = pattern;
160 let mut ends_with_rest = false;
161
162 loop {
163 match current {
164 NormalizedPattern::Constructor { tag, .. } if tag == "EmptySlice" => {
165 break;
166 }
167 NormalizedPattern::Constructor { tag, args, .. } if tag == "NonEmptySlice" => {
168 if args.len() >= 2 {
169 elements.push(format_pattern(&args[0]));
170 current = &args[1];
171 } else {
172 break;
173 }
174 }
175 NormalizedPattern::Wildcard => {
176 ends_with_rest = true;
177 break;
178 }
179 _ => {
180 elements.push(format_pattern(current));
181 break;
182 }
183 }
184 }
185
186 if ends_with_rest {
187 elements.push("..".to_string());
188 }
189
190 format!("[{}]", elements.join(", "))
191}