luaur_analysis/functions/
to_string_human.rs1use crate::enums::pack_field::PackField;
3use crate::enums::type_field::TypeField;
4use crate::enums::variant::Variant;
5use crate::functions::to_human_readable_index::to_human_readable_index;
6use crate::records::path::Path;
7use crate::type_aliases::component::Component;
8use alloc::string::String;
9use core::fmt::Write as _;
10
11#[derive(Clone, Copy, PartialEq, Eq)]
12enum State {
13 Initial,
14 Normal,
15 Property,
16 PendingIs,
17 PendingAs,
18 PendingWhich,
19}
20
21pub fn to_string_human(path: &Path) -> String {
22 let mut result = String::new();
23 let mut state = State::Initial;
24 let mut last = false;
25
26 let mut count: usize = 0;
27
28 for component in &path.components {
29 count += 1;
30 if count == path.components.len() {
31 last = true;
32 }
33
34 match component {
35 Component::Property(c) => {
36 if state == State::PendingIs {
37 result.push_str(", ");
38 }
39
40 match state {
41 State::Initial | State::PendingIs => {
42 if c.is_read {
43 result.push_str("accessing `");
44 } else {
45 result.push_str("writing to `");
46 }
47 }
48 State::Property => {
49 result.push('.');
52 }
53 _ => {}
54 }
55
56 result.push_str(&c.name);
57
58 state = State::Property;
59 }
60 Component::Index(c) => {
61 if state == State::Initial && !last {
62 result.push_str("in ");
63 } else if state == State::PendingIs {
64 result.push_str(" has ");
65 } else if state == State::Property {
66 result.push_str("` has ");
67 }
68
69 let _ = write!(result, "the {}", to_human_readable_index(c.index));
70
71 match c.variant {
72 Variant::Pack => result.push_str(" entry in the type pack"),
73 Variant::Union => result.push_str(" component of the union"),
74 Variant::Intersection => result.push_str(" component of the intersection"),
75 }
76
77 if state == State::PendingWhich {
78 result.push_str(" which");
79 }
80
81 if state == State::PendingIs || state == State::Property {
82 state = State::PendingAs;
83 } else {
84 state = State::PendingIs;
85 }
86 }
87 Component::TypeField(c) => {
88 if state == State::Initial && !last {
89 result.push_str("in ");
90 } else if state == State::PendingIs {
91 result.push_str(", ");
92 } else if state == State::Property {
93 result.push_str("` has ");
94 }
95
96 match c {
97 TypeField::Table => {
98 result.push_str("the table portion");
99 if state == State::Property {
100 state = State::PendingAs;
101 } else {
102 state = State::PendingIs;
103 }
104 }
105 TypeField::Metatable => {
106 result.push_str("the metatable portion");
107 if state == State::Property {
108 state = State::PendingAs;
109 } else {
110 state = State::PendingIs;
111 }
112 }
113 TypeField::LowerBound => {
114 result.push_str("the lower bound of ");
115 state = State::Normal;
116 }
117 TypeField::UpperBound => {
118 result.push_str("the upper bound of ");
119 state = State::Normal;
120 }
121 TypeField::IndexLookup => {
122 result.push_str("the index type");
123 if state == State::Property {
124 state = State::PendingAs;
125 } else {
126 state = State::PendingIs;
127 }
128 }
129 TypeField::IndexResult => {
130 result.push_str("the result of indexing");
131 if state == State::Property {
132 state = State::PendingAs;
133 } else {
134 state = State::PendingIs;
135 }
136 }
137 TypeField::Negated => {
138 result.push_str("the negation ");
139 state = State::Normal;
140 }
141 TypeField::Variadic => {
142 result.push_str("the variadic ");
143 state = State::Normal;
144 }
145 }
146 }
147 Component::PackField(c) => {
148 if state == State::PendingIs {
149 result.push_str(", ");
150 } else if state == State::Property {
151 result.push_str("`, ");
152 }
153
154 match c {
155 PackField::Arguments => {
156 if state == State::Initial {
157 result.push_str("it ");
158 } else if state == State::PendingIs {
159 result.push_str("the function ");
160 }
161 result.push_str("takes");
162 }
163 PackField::Returns => {
164 if state == State::Initial {
165 result.push_str("it ");
166 } else if state == State::PendingIs {
167 result.push_str("the function ");
168 }
169 result.push_str("returns");
170 }
171 PackField::Tail => {
172 if state == State::Initial {
173 result.push_str("it has ");
174 }
175 result.push_str("a tail of");
176 }
177 }
178
179 if state == State::PendingIs {
180 result.push(' ');
181 state = State::PendingWhich;
182 } else {
183 result.push(' ');
184 state = State::Normal;
185 }
186 }
187 Component::PackSlice(c) => {
188 let _ = write!(
189 result,
190 "the portion of the type pack starting at index {} to the end",
191 c.start_index
192 );
193 }
194 Component::Reduction(_c) => {
195 if state == State::Initial {
196 result.push_str("it ");
197 }
198 result.push_str("reduces to ");
199 state = State::Normal;
200 }
201 Component::GenericPackMapping(_c) => {
202 result.push_str("is a generic pack mapped to ");
203 }
204 }
205 }
206
207 match state {
208 State::Property => {
209 result.push_str("` results in ");
210 }
211 State::PendingWhich => {
212 result.push_str("is ");
214 }
215 State::PendingIs => {
216 result.push_str(" is ");
217 }
218 State::PendingAs => {
219 result.push_str(" as ");
220 }
221 _ => {}
222 }
223
224 result
225}