File: sort.ha

package info (click to toggle)
hare 0.26.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 7,352 kB
  • sloc: asm: 1,374; makefile: 123; sh: 117; lisp: 101
file content (107 lines) | stat: -rw-r--r-- 2,835 bytes parent folder | download
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();
	};
};