sort.ha (2767B)
1 // License: GPL-3.0 2 // (c) 2021 Drew DeVault <sir@cmpwn.com> 3 // (c) 2021 Ember Sawady <ecs@d2evs.net> 4 use hare::ast; 5 use sort; 6 use strings; 7 8 type summary = struct { 9 constants: []ast::decl, 10 errors: []ast::decl, 11 types: []ast::decl, 12 globals: []ast::decl, 13 funcs: []ast::decl, 14 }; 15 16 // Sorts declarations by removing unexported declarations, moving undocumented 17 // declarations to the end, sorting by identifier, and ensuring that only one 18 // member is present in each declaration (so that "let x: int = 10, y: int = 20" 19 // becomes two declarations: "let x: int = 10; let y: int = 20;"). 20 fn sort_decls(decls: []ast::decl) summary = { 21 let sorted = summary { ... }; 22 23 for (let i = 0z; i < len(decls); i += 1) { 24 let decl = decls[i]; 25 if (!decl.exported) { 26 continue; 27 }; 28 29 match (decl.decl) { 30 case let f: ast::decl_func => 31 append(sorted.funcs, decl); 32 case let t: []ast::decl_type => 33 for (let j = 0z; j < len(t); j += 1) { 34 let bucket = &sorted.types; 35 if (t[j]._type.flags & ast::type_flag::ERROR == ast::type_flag::ERROR) { 36 bucket = &sorted.errors; 37 }; 38 append(bucket, ast::decl { 39 exported = true, 40 start = decl.start, 41 end = decl.end, 42 decl = alloc([t[j]]), 43 docs = decl.docs, 44 }); 45 }; 46 case let c: []ast::decl_const => 47 for (let j = 0z; j < len(c); j += 1) { 48 append(sorted.constants, ast::decl { 49 exported = true, 50 start = decl.start, 51 end = decl.end, 52 decl = alloc([c[j]]), 53 docs = decl.docs, 54 }); 55 }; 56 case let g: []ast::decl_global => 57 for (let j = 0z; j < len(g); j += 1) { 58 append(sorted.globals, ast::decl { 59 exported = true, 60 start = decl.start, 61 end = decl.end, 62 decl = alloc([g[j]]), 63 docs = decl.docs, 64 }); 65 }; 66 }; 67 }; 68 69 sort::sort(sorted.constants, size(ast::decl), &decl_cmp); 70 sort::sort(sorted.errors, size(ast::decl), &decl_cmp); 71 sort::sort(sorted.types, size(ast::decl), &decl_cmp); 72 sort::sort(sorted.globals, size(ast::decl), &decl_cmp); 73 sort::sort(sorted.funcs, size(ast::decl), &decl_cmp); 74 return sorted; 75 }; 76 77 fn decl_cmp(a: const *void, b: const *void) int = { 78 const a = *(a: const *ast::decl); 79 const b = *(b: const *ast::decl); 80 if (a.docs == "" && b.docs != "") { 81 return 1; 82 } else if (a.docs != "" && b.docs == "") { 83 return -1; 84 }; 85 const id_a = decl_ident(a), id_b = decl_ident(b); 86 return strings::compare(id_a[len(id_a) - 1], id_b[len(id_b) - 1]); 87 }; 88 89 fn decl_ident(decl: ast::decl) ast::ident = { 90 match (decl.decl) { 91 case let f: ast::decl_func => 92 return f.ident; 93 case let t: []ast::decl_type => 94 assert(len(t) == 1); 95 return t[0].ident; 96 case let c: []ast::decl_const => 97 assert(len(c) == 1); 98 return c[0].ident; 99 case let g: []ast::decl_global => 100 assert(len(g) == 1); 101 return g[0].ident; 102 }; 103 };