sort.ha (3216B)
1 // SPDX-License-Identifier: GPL-3.0-only 2 // (c) Hare authors <https://harelang.org> 3 4 use hare::ast; 5 use sort; 6 use strings; 7 8 // Sorts declarations by: 9 // - removing unexported declarations, 10 // - setting the "exported" field of all remaining declarations to false, so the 11 // "export" keyword isn't unparsed, 12 // - moving undocumented declarations to the end, 13 // - sorting by identifier, 14 // - removing the initializer from globals and the body from functions, 15 // - ensuring that only one member is present in each declaration: 16 // "let x: int, y: int;" becomes two declarations: "let x: int; let y: int;". 17 export fn sort_decls(decls: []ast::decl) summary = { 18 let sorted = summary { ... }; 19 20 for (let decl .. decls) { 21 if (!decl.exported) { 22 continue; 23 }; 24 25 match (decl.decl) { 26 case let f: ast::decl_func => 27 append(sorted.funcs, ast::decl { 28 exported = false, 29 start = decl.start, 30 end = decl.end, 31 decl = ast::decl_func { 32 symbol = f.symbol, 33 ident = f.ident, 34 prototype = f.prototype, 35 body = null, 36 attrs = f.attrs, 37 }, 38 docs = decl.docs, 39 }); 40 case let types: []ast::decl_type => 41 for (let t .. types) { 42 let bucket = &sorted.types; 43 if (t._type.flags & ast::type_flag::ERROR == ast::type_flag::ERROR) { 44 bucket = &sorted.errors; 45 }; 46 append(bucket, ast::decl { 47 exported = false, 48 start = decl.start, 49 end = decl.end, 50 decl = alloc([t]), 51 docs = decl.docs, 52 }); 53 }; 54 case let consts: []ast::decl_const => 55 for (let c .. consts) { 56 append(sorted.constants, ast::decl { 57 exported = false, 58 start = decl.start, 59 end = decl.end, 60 decl = alloc([c]), 61 docs = decl.docs, 62 }); 63 }; 64 case let globals: []ast::decl_global => 65 for (let g .. globals) { 66 append(sorted.globals, ast::decl { 67 exported = false, 68 start = decl.start, 69 end = decl.end, 70 decl = alloc([ast::decl_global { 71 is_const = g.is_const, 72 is_threadlocal = g.is_threadlocal, 73 symbol = g.symbol, 74 ident = g.ident, 75 _type = g._type, 76 init = null, 77 }]), 78 docs = decl.docs, 79 }); 80 }; 81 case ast::assert_expr => void; 82 }; 83 }; 84 85 sort::sort(sorted.constants, size(ast::decl), &decl_cmp); 86 sort::sort(sorted.errors, size(ast::decl), &decl_cmp); 87 sort::sort(sorted.types, size(ast::decl), &decl_cmp); 88 sort::sort(sorted.globals, size(ast::decl), &decl_cmp); 89 sort::sort(sorted.funcs, size(ast::decl), &decl_cmp); 90 return sorted; 91 }; 92 93 fn decl_cmp(a: const *opaque, b: const *opaque) int = { 94 const a = a: const *ast::decl; 95 const b = b: const *ast::decl; 96 if (a.docs == "" && b.docs != "") { 97 return 1; 98 } else if (a.docs != "" && b.docs == "") { 99 return -1; 100 }; 101 const id_a = decl_ident(a), id_b = decl_ident(b); 102 return strings::compare(id_a[len(id_a) - 1], id_b[len(id_b) - 1]); 103 }; 104 105 fn decl_ident(decl: *ast::decl) ast::ident = { 106 match (decl.decl) { 107 case let f: ast::decl_func => 108 return f.ident; 109 case let t: []ast::decl_type => 110 assert(len(t) == 1); 111 return t[0].ident; 112 case let c: []ast::decl_const => 113 assert(len(c) == 1); 114 return c[0].ident; 115 case let g: []ast::decl_global => 116 assert(len(g) == 1); 117 return g[0].ident; 118 case ast::assert_expr => abort(); 119 }; 120 };