v2 / vlib / v / gen / js / auto_eq_methods.v
336 lines · 318 sloc · 13.42 KB · 99f141f741b643327a2628963d95998c862c7ed2
Raw
1module js
2
3import v.ast
4import strings
5import arrays
6
7fn (mut g JsGen) gen_sumtype_equality_fn(left_type ast.Type) string {
8 left := g.unwrap(left_type)
9 ptr_styp := g.styp(left.typ.set_nr_muls(0))
10 if ptr_styp in g.sumtype_fn_definitions {
11 return ptr_styp
12 }
13 g.sumtype_fn_definitions << ptr_styp
14 info := left.sym.sumtype_info()
15 mut fn_builder := strings.new_builder(512)
16 defer {
17 g.definitions.writeln(fn_builder.str())
18 }
19 fn_builder.writeln('function ${ptr_styp}_sumtype_eq(a,b) {')
20 fn_builder.writeln('\tlet aProto = Object.getPrototypeOf(a);')
21 fn_builder.writeln('\tlet bProto = Object.getPrototypeOf(b);')
22 fn_builder.writeln('\tif (aProto !== bProto) { return new bool(false); }')
23 mut variants := []Type{}
24 for typ in info.variants {
25 variant := g.unwrap(typ)
26 if variant.unaliased_sym.info is ast.SumType {
27 variants << g.unwrap_sum_type(typ)
28 } else {
29 variants << variant
30 }
31 }
32 variants = arrays.distinct(variants)
33 for variant in variants {
34 typ := variant.typ
35 fn_builder.writeln('\tif (aProto == ${g.js_name(variant.unaliased_sym.name)}.prototype) {')
36 if variant.sym.kind == .string {
37 fn_builder.writeln('\t\treturn new bool(a.str == b.str);')
38 } else if variant.sym.kind == .sum_type && !typ.is_ptr() {
39 eq_fn := g.gen_sumtype_equality_fn(typ)
40 fn_builder.writeln('\t\treturn ${eq_fn}_sumtype_eq(a,b);')
41 } else if variant.sym.kind == .struct && !typ.is_ptr() {
42 eq_fn := g.gen_struct_equality_fn(typ)
43 fn_builder.writeln('\t\treturn ${eq_fn}_struct_eq(a,b);')
44 } else if variant.sym.kind == .array && !typ.is_ptr() {
45 eq_fn := g.gen_array_equality_fn(typ)
46 fn_builder.writeln('\t\treturn ${eq_fn}_arr_eq(a,b);')
47 } else if variant.sym.kind == .array_fixed && !typ.is_ptr() {
48 eq_fn := g.gen_fixed_array_equality_fn(typ)
49 fn_builder.writeln('\t\treturn ${eq_fn}_arr_eq(a,b);')
50 } else if variant.sym.kind == .map && !typ.is_ptr() {
51 eq_fn := g.gen_map_equality_fn(typ)
52 fn_builder.writeln('\t\treturn ${eq_fn}_map_eq(a,b);')
53 } else if variant.sym.kind == .alias && !typ.is_ptr() {
54 eq_fn := g.gen_alias_equality_fn(typ)
55 fn_builder.writeln('\t\treturn ${eq_fn}_alias_eq(a,b);')
56 } else if variant.sym.kind == .function {
57 fn_builder.writeln('\t\treturn new bool(a == b);')
58 } else {
59 fn_builder.writeln('\t\treturn new bool(vEq(a,b));')
60 }
61 fn_builder.writeln('\t}')
62 }
63 fn_builder.writeln('\treturn new bool(false);')
64 fn_builder.writeln('}')
65
66 return ptr_styp
67}
68
69fn (mut g JsGen) gen_struct_equality_fn(left_type ast.Type) string {
70 left := g.unwrap(left_type)
71 ptr_styp := g.styp(left.typ.set_nr_muls(0))
72 fn_name := ptr_styp.replace('struct ', '')
73 if fn_name in g.struct_fn_definitions {
74 return fn_name
75 }
76 g.struct_fn_definitions << fn_name
77 info := left.sym.struct_info()
78 mut fn_builder := strings.new_builder(512)
79 defer {
80 g.definitions.writeln(fn_builder.str())
81 }
82 fn_builder.writeln('function ${fn_name}_struct_eq(a,b) {')
83
84 // overloaded
85 if left.sym.has_method('==') {
86 fn_builder.writeln('\treturn ${fn_name}__eq(a, b);')
87 fn_builder.writeln('}')
88 return fn_name
89 }
90
91 fn_builder.write_string('\treturn new bool(')
92 if info.fields.len > 0 {
93 for i, field in info.fields {
94 if i > 0 {
95 fn_builder.write_string('\n\t\t&& ')
96 }
97 field_type := g.unwrap(field.typ)
98 field_name := g.js_name(field.name)
99 if field_type.sym.kind == .string {
100 fn_builder.write_string('a.${field_name}.str == b.${field_name}.str')
101 } else if field_type.sym.kind == .sum_type && !field.typ.is_ptr() {
102 eq_fn := g.gen_sumtype_equality_fn(field.typ)
103 fn_builder.write_string('${eq_fn}_sumtype_eq(a.${field_name}, b.${field_name})')
104 } else if field_type.sym.kind == .struct && !field.typ.is_ptr() {
105 eq_fn := g.gen_struct_equality_fn(field.typ)
106 fn_builder.write_string('${eq_fn}_struct_eq(a.${field_name}, b.${field_name})')
107 } else if field_type.sym.kind == .array && !field.typ.is_ptr() {
108 eq_fn := g.gen_array_equality_fn(field.typ)
109 fn_builder.write_string('${eq_fn}_arr_eq(a.${field_name}, b.${field_name})')
110 } else if field_type.sym.kind == .array_fixed && !field.typ.is_ptr() {
111 eq_fn := g.gen_fixed_array_equality_fn(field.typ)
112 fn_builder.write_string('${eq_fn}_arr_eq(a.${field_name}, b.${field_name})')
113 } else if field_type.sym.kind == .map && !field.typ.is_ptr() {
114 eq_fn := g.gen_map_equality_fn(field.typ)
115 fn_builder.write_string('${eq_fn}_map_eq(a.${field_name}, b.${field_name})')
116 } else if field_type.sym.kind == .alias && !field.typ.is_ptr() {
117 eq_fn := g.gen_alias_equality_fn(field.typ)
118 fn_builder.write_string('${eq_fn}_alias_eq(a.${field_name}, b.${field_name})')
119 } else if field_type.sym.kind == .function {
120 fn_builder.write_string('a.${field_name} == b.${field_name}')
121 } else {
122 // fallback to vEq for JS types or primitives.
123 fn_builder.write_string('vEq(a.${field_name},b.${field_name})')
124 }
125 }
126 } else {
127 fn_builder.write_string('true')
128 }
129 fn_builder.writeln(');')
130 fn_builder.writeln('}')
131 return fn_name
132}
133
134fn (mut g JsGen) gen_alias_equality_fn(left_type ast.Type) string {
135 left := g.unwrap(left_type)
136 ptr_styp := g.styp(left.typ.set_nr_muls(0))
137 if ptr_styp in g.alias_fn_definitions {
138 return ptr_styp
139 }
140 g.alias_fn_definitions << ptr_styp
141 info := left.sym.info as ast.Alias
142
143 mut fn_builder := strings.new_builder(512)
144 defer {
145 g.definitions.writeln(fn_builder.str())
146 }
147 fn_builder.writeln('function ${ptr_styp}_alias_eq(a,b) {')
148 sym := g.table.sym(info.parent_type)
149 if sym.kind == .string {
150 fn_builder.writeln('\treturn new bool(a.str == b.str);')
151 } else if sym.kind == .sum_type && !left.typ.is_ptr() {
152 eq_fn := g.gen_sumtype_equality_fn(info.parent_type)
153 fn_builder.writeln('\treturn ${eq_fn}_sumtype_eq(a, b);')
154 } else if sym.kind == .struct && !left.typ.is_ptr() {
155 eq_fn := g.gen_struct_equality_fn(info.parent_type)
156 fn_builder.writeln('\treturn ${eq_fn}_struct_eq(a, b);')
157 } else if sym.kind == .array && !left.typ.is_ptr() {
158 eq_fn := g.gen_array_equality_fn(info.parent_type)
159 fn_builder.writeln('\treturn ${eq_fn}_arr_eq(a, b);')
160 } else if sym.kind == .array_fixed && !left.typ.is_ptr() {
161 eq_fn := g.gen_fixed_array_equality_fn(info.parent_type)
162 fn_builder.writeln('\treturn ${eq_fn}_arr_eq(a, b);')
163 } else if sym.kind == .map && !left.typ.is_ptr() {
164 eq_fn := g.gen_map_equality_fn(info.parent_type)
165 fn_builder.writeln('\treturn ${eq_fn}_map_eq(a, b);')
166 } else if sym.kind == .function {
167 fn_builder.writeln('\treturn new bool(a == b);')
168 } else {
169 fn_builder.writeln('\treturn new bool(vEq(a,b));')
170 }
171 fn_builder.writeln('}')
172
173 return ptr_styp
174}
175
176fn (mut g JsGen) gen_array_equality_fn(left_type ast.Type) string {
177 left := g.unwrap(left_type)
178 ptr_styp := g.styp(left.typ.set_nr_muls(0))
179 if ptr_styp in g.array_fn_definitions {
180 return ptr_styp
181 }
182 g.array_fn_definitions << ptr_styp
183 elem := g.unwrap(left.sym.array_info().elem_type)
184
185 mut fn_builder := strings.new_builder(512)
186 defer {
187 g.definitions.writeln(fn_builder.str())
188 }
189 fn_builder.writeln('function ${ptr_styp}_arr_eq(a,b) {')
190 fn_builder.writeln('\tif (a.len.valueOf() != b.len.valueOf()) {')
191 fn_builder.writeln('\t\treturn new bool(false);')
192 fn_builder.writeln('\t}')
193 fn_builder.writeln('\tfor (let i = 0; i < a.len; ++i) {')
194 // compare every pair of elements of the two arrays
195 if elem.sym.kind == .string {
196 fn_builder.writeln('\t\tif (a.arr.get(new int(i)).str != b.arr.get(new int(i)).str) {')
197 } else if elem.sym.kind == .sum_type && !elem.typ.is_ptr() {
198 eq_fn := g.gen_sumtype_equality_fn(elem.typ)
199 fn_builder.writeln('\t\tif (!${eq_fn}_sumtype_eq(a.arr.get(new int(i)),b.arr.get(new int(i))).val) {')
200 } else if elem.sym.kind == .struct && !elem.typ.is_ptr() {
201 eq_fn := g.gen_struct_equality_fn(elem.typ)
202 fn_builder.writeln('\t\tif (!${eq_fn}_struct_eq(a.arr.get(new int(i)),b.arr.get(new int(i))).val) {')
203 } else if elem.sym.kind == .array && !elem.typ.is_ptr() {
204 eq_fn := g.gen_array_equality_fn(elem.typ)
205 fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(a.arr.get(new int(i)),b.arr.get(new int(i))).val) {')
206 } else if elem.sym.kind == .array_fixed && !elem.typ.is_ptr() {
207 eq_fn := g.gen_fixed_array_equality_fn(elem.typ)
208 fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(a.arr.get(new int(i)),b.arr.get(new int(i))).val) {')
209 } else if elem.sym.kind == .map && !elem.typ.is_ptr() {
210 eq_fn := g.gen_map_equality_fn(elem.typ)
211 fn_builder.writeln('\t\tif (!${eq_fn}_map_eq(a.arr.get(new int(i)),b.arr.get(new int(i))).val) {')
212 } else if elem.sym.kind == .alias && !elem.typ.is_ptr() {
213 eq_fn := g.gen_alias_equality_fn(elem.typ)
214 fn_builder.writeln('\t\tif (!${eq_fn}_alias_eq(a.arr.get(new int(i)),b.arr.get(new int(i))).val) {')
215 } else if elem.sym.kind == .function {
216 fn_builder.writeln('\t\tif (a.arr.get(new int(i)) != b.arr.get(new int(i))) {')
217 } else {
218 fn_builder.writeln('\t\tif (!vEq(a.arr.get(new int(i)),b.arr.get(new int(i)))) {')
219 }
220 fn_builder.writeln('\t\t\treturn new bool(false);')
221 fn_builder.writeln('\t\t}')
222 fn_builder.writeln('\t}')
223 fn_builder.writeln('\treturn new bool(true);')
224 fn_builder.writeln('}')
225
226 return ptr_styp
227}
228
229fn (mut g JsGen) gen_fixed_array_equality_fn(left_type ast.Type) string {
230 left := g.unwrap(left_type)
231 ptr_styp := g.styp(left.typ.set_nr_muls(0))
232 if ptr_styp in g.array_fn_definitions {
233 return ptr_styp
234 }
235 g.array_fn_definitions << ptr_styp
236 elem_info := left.sym.array_fixed_info()
237 elem := g.unwrap(elem_info.elem_type)
238 size := elem_info.size
239
240 mut fn_builder := strings.new_builder(512)
241 defer {
242 g.definitions.writeln(fn_builder.str())
243 }
244 fn_builder.writeln('function ${ptr_styp}_arr_eq(a,b) {')
245 fn_builder.writeln('\tfor (let i = 0; i < ${size}; ++i) {')
246 // compare every pair of elements of the two fixed arrays
247 if elem.sym.kind == .string {
248 fn_builder.writeln('\t\tif (a.arr.get(new int(i)).str != b.arr.get(new int(i)).str) {')
249 } else if elem.sym.kind == .sum_type && !elem.typ.is_ptr() {
250 eq_fn := g.gen_sumtype_equality_fn(elem.typ)
251 fn_builder.writeln('\t\tif (!${eq_fn}_sumtype_eq(a.arr.get(new int(i)), b.arr.get(new int(i))).val) {')
252 } else if elem.sym.kind == .struct && !elem.typ.is_ptr() {
253 eq_fn := g.gen_struct_equality_fn(elem.typ)
254 fn_builder.writeln('\t\tif (!${eq_fn}_struct_eq(a.arr.get(new int(i)), b.arr.get(new int(i))).val) {')
255 } else if elem.sym.kind == .array && !elem.typ.is_ptr() {
256 eq_fn := g.gen_array_equality_fn(elem.typ)
257 fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(a.arr.get(new int(i)), b.arr.get(new int(i))).val) {')
258 } else if elem.sym.kind == .array_fixed && !elem.typ.is_ptr() {
259 eq_fn := g.gen_fixed_array_equality_fn(elem.typ)
260 fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(a.arr.get(new int(i)), b.arr.get(new int(i))).val) {')
261 } else if elem.sym.kind == .map && !elem.typ.is_ptr() {
262 eq_fn := g.gen_map_equality_fn(elem.typ)
263 fn_builder.writeln('\t\tif (!${eq_fn}_map_eq(a.arr.get(new int(i)), b.arr.get(new int(i))).val) {')
264 } else if elem.sym.kind == .alias && !elem.typ.is_ptr() {
265 eq_fn := g.gen_alias_equality_fn(elem.typ)
266 fn_builder.writeln('\t\tif (!${eq_fn}_alias_eq(a.arr.get(new int(i)), b.arr.get(new int(i))).val) {')
267 } else if elem.sym.kind == .function {
268 fn_builder.writeln('\t\tif (a.arr.get(new int(i)) != b.arr.get(new int(i))) {')
269 } else {
270 fn_builder.writeln('\t\tif (!vEq(a.arr.get(new int(i)),b.arr.get(new int(i)))) {')
271 }
272 fn_builder.writeln('\t\t\treturn new bool(false);')
273 fn_builder.writeln('\t\t}')
274 fn_builder.writeln('\t}')
275 fn_builder.writeln('\treturn new bool(true);')
276 fn_builder.writeln('}')
277
278 return ptr_styp
279}
280
281fn (mut g JsGen) gen_map_equality_fn(left_type ast.Type) string {
282 left := g.unwrap(left_type)
283 ptr_styp := g.styp(left.typ.set_nr_muls(0))
284 if ptr_styp in g.map_fn_definitions {
285 return ptr_styp
286 }
287 g.map_fn_definitions << ptr_styp
288 value := g.unwrap(left.sym.map_info().value_type)
289
290 mut fn_builder := strings.new_builder(512)
291 defer {
292 g.definitions.writeln(fn_builder.str())
293 }
294 fn_builder.writeln('function ${ptr_styp}_map_eq(a,b) {')
295 fn_builder.writeln('\tif (Object.keys(a.map).length != Object.keys(b.map).length) {')
296 fn_builder.writeln('\t\treturn new bool(false);')
297 fn_builder.writeln('\t}')
298 fn_builder.writeln('\tlet keys = Object.keys(a.map);')
299 fn_builder.writeln('\tfor (let i = 0;i < keys.length;i++) {')
300 fn_builder.writeln('\t\tlet key = keys[i]; let value = a.map[key];')
301 fn_builder.writeln('\t\tif (!(key in b.map)) { return new bool(false); }')
302 fn_builder.writeln('\t\tlet x = value.val; let y = b.map[key].val;')
303 kind := g.table.type_kind(value.typ)
304 if kind == .string {
305 fn_builder.writeln('\t\tif (x.str != y.str) {')
306 } else if kind == .sum_type {
307 eq_fn := g.gen_sumtype_equality_fn(value.typ)
308 fn_builder.writeln('\t\tif (!${eq_fn}_sumtype_eq(x,y).val) {')
309 } else if kind == .struct {
310 eq_fn := g.gen_struct_equality_fn(value.typ)
311 fn_builder.writeln('\t\tif (!${eq_fn}_struct_eq(x,y).val) {')
312 } else if kind == .array {
313 eq_fn := g.gen_array_equality_fn(value.typ)
314 fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(x,y).val) {')
315 } else if kind == .array_fixed {
316 eq_fn := g.gen_fixed_array_equality_fn(value.typ)
317 fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(x,y).val) {')
318 } else if kind == .map {
319 eq_fn := g.gen_map_equality_fn(value.typ)
320 fn_builder.writeln('\t\tif (!${eq_fn}_map_eq(x,y).val) {')
321 } else if kind == .alias {
322 eq_fn := g.gen_alias_equality_fn(value.typ)
323 fn_builder.writeln('\t\tif (!${eq_fn}_alias_eq(x,y).val) {')
324 } else if kind == .function {
325 fn_builder.writeln('\t\tif (x !== y) {')
326 } else {
327 fn_builder.writeln('\t\tif (!vEq(x,y)) {')
328 }
329 fn_builder.writeln('\t\t\treturn new bool(false);')
330 fn_builder.writeln('\t\t}')
331 fn_builder.writeln('\t}')
332 fn_builder.writeln('\treturn new bool(true);')
333 fn_builder.writeln('}')
334
335 return ptr_styp
336}
337