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